/*
* Copyright 2012 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* Authors:
* Lars Uebernickel
*/
#include "im-phone-menu.h"
#include
#include
typedef ImMenuClass ImPhoneMenuClass;
struct _ImPhoneMenu
{
ImMenu parent;
GMenu *message_section;
GMenu *source_section;
GMenu *clear_section;
};
G_DEFINE_TYPE (ImPhoneMenu, im_phone_menu, IM_TYPE_MENU);
typedef void (*ImMenuForeachFunc) (GMenuModel *menu, gint pos);
static void
im_phone_menu_foreach_item_with_action (GMenuModel *menu,
const gchar *action,
ImMenuForeachFunc func)
{
gint n_items;
gint i;
n_items = g_menu_model_get_n_items (menu);
for (i = 0; i < n_items; i++)
{
gchar *item_action;
g_menu_model_get_item_attribute (menu, i, G_MENU_ATTRIBUTE_ACTION, "s", &item_action);
if (g_str_equal (action, item_action))
func (menu, i);
g_free (item_action);
}
}
static void
im_phone_menu_update_clear_section (ImPhoneMenu *menu)
{
gboolean is_shown;
gboolean should_be_shown;
is_shown = g_menu_model_get_n_items (G_MENU_MODEL (menu->clear_section)) > 0;
should_be_shown = (g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section)) +
g_menu_model_get_n_items (G_MENU_MODEL (menu->source_section))) > 0;
if (!is_shown && should_be_shown)
{
GMenuItem *item;
item = g_menu_item_new (_("Clear All"), "remove-all");
g_menu_item_set_attribute (item, "x-ayatana-type", "s", "org.ayatana.indicator.button");
g_menu_append_item (menu->clear_section, item);
g_object_unref (item);
}
else if (is_shown && !should_be_shown)
{
g_menu_remove (menu->clear_section, 0);
}
}
static void
im_phone_menu_constructed (GObject *object)
{
ImPhoneMenu *menu = IM_PHONE_MENU (object);
ImApplicationList *applist;
im_menu_append_section (IM_MENU (menu), G_MENU_MODEL (menu->message_section));
im_menu_append_section (IM_MENU (menu), G_MENU_MODEL (menu->source_section));
im_menu_append_section (IM_MENU (menu), G_MENU_MODEL (menu->clear_section));
applist = im_menu_get_application_list (IM_MENU (menu));
g_signal_connect_swapped (applist, "message-added", G_CALLBACK (im_phone_menu_add_message), menu);
g_signal_connect_swapped (applist, "message-removed", G_CALLBACK (im_phone_menu_remove_message), menu);
g_signal_connect_swapped (applist, "app-stopped", G_CALLBACK (im_phone_menu_remove_application), menu);
g_signal_connect_swapped (applist, "remove-all", G_CALLBACK (im_phone_menu_remove_all), menu);
G_OBJECT_CLASS (im_phone_menu_parent_class)->constructed (object);
}
static void
im_phone_menu_dispose (GObject *object)
{
ImPhoneMenu *menu = IM_PHONE_MENU (object);
g_clear_object (&menu->message_section);
g_clear_object (&menu->source_section);
g_clear_object (&menu->clear_section);
G_OBJECT_CLASS (im_phone_menu_parent_class)->dispose (object);
}
static void
im_phone_menu_finalize (GObject *object)
{
G_OBJECT_CLASS (im_phone_menu_parent_class)->finalize (object);
}
static void
im_phone_menu_class_init (ImPhoneMenuClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = im_phone_menu_constructed;
object_class->dispose = im_phone_menu_dispose;
object_class->finalize = im_phone_menu_finalize;
}
static void
im_phone_menu_init (ImPhoneMenu *menu)
{
menu->message_section = g_menu_new ();
menu->source_section = g_menu_new ();
menu->clear_section = g_menu_new ();
}
ImPhoneMenu *
im_phone_menu_new (ImApplicationList *applist, gboolean greeter)
{
g_return_val_if_fail (IM_IS_APPLICATION_LIST (applist), NULL);
return g_object_new (IM_TYPE_PHONE_MENU,
"application-list", applist,
"on-greeter", greeter,
NULL);
}
static gint64
im_phone_menu_get_message_time (GMenuModel *model,
gint i)
{
gint64 time;
g_menu_model_get_item_attribute (model, i, "x-ayatana-time", "x", &time);
return time;
}
void
im_phone_menu_add_message (ImPhoneMenu *menu,
const gchar *app_id,
GIcon *app_icon,
const gchar *id,
GVariant *serialized_icon,
const gchar *title,
const gchar *subtitle,
const gchar *body,
GVariant *actions,
gint64 time)
{
GMenuItem *item;
gchar *action_name;
gint n_messages;
gint pos;
GVariant *serialized_app_icon;
gboolean show_data;
g_return_if_fail (IM_IS_PHONE_MENU (menu));
g_return_if_fail (app_id);
show_data = im_menu_show_data(IM_MENU (menu));
action_name = g_strconcat (app_id, ".msg.", id, NULL);
item = g_menu_item_new (title, NULL);
g_menu_item_set_action_and_target_value (item, action_name, g_variant_new_boolean (TRUE));
g_menu_item_set_attribute (item, "x-ayatana-type", "s", "org.ayatana.indicator.messages.messageitem");
g_menu_item_set_attribute (item, "x-ayatana-message-id", "s", id);
if (show_data)
g_menu_item_set_attribute (item, "x-ayatana-subtitle", "s", subtitle);
if (show_data)
g_menu_item_set_attribute (item, "x-ayatana-text", "s", body);
g_menu_item_set_attribute (item, "x-ayatana-time", "x", time);
if (serialized_icon)
g_menu_item_set_attribute_value (item, "icon", serialized_icon);
if (app_icon && (serialized_app_icon = g_icon_serialize (app_icon)))
{
g_menu_item_set_attribute_value (item, "x-ayatana-app-icon", serialized_app_icon);
g_variant_unref (serialized_app_icon);
}
if (actions && show_data)
g_menu_item_set_attribute (item, "x-ayatana-message-actions", "v", actions);
n_messages = g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section));
pos = 0;
while (pos < n_messages &&
time < im_phone_menu_get_message_time (G_MENU_MODEL (menu->message_section), pos))
pos++;
g_menu_insert_item (menu->message_section, pos, item);
im_phone_menu_update_clear_section (menu);
g_free (action_name);
g_object_unref (item);
}
void
im_phone_menu_remove_message (ImPhoneMenu *menu,
const gchar *app_id,
const gchar *id)
{
gchar *action_name;
g_return_if_fail (IM_IS_PHONE_MENU (menu));
g_return_if_fail (app_id != NULL);
action_name = g_strconcat (app_id, ".msg.", id, NULL);
im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->message_section),
action_name,
(ImMenuForeachFunc) g_menu_remove);
im_phone_menu_update_clear_section (menu);
g_free (action_name);
}
void
im_phone_menu_add_source (ImPhoneMenu *menu,
const gchar *app_id,
const gchar *id,
const gchar *label,
const gchar *iconstr)
{
GMenuItem *item;
gchar *action_name;
g_return_if_fail (IM_IS_PHONE_MENU (menu));
g_return_if_fail (app_id != NULL);
action_name = g_strconcat (app_id, ".src.", id, NULL);
item = g_menu_item_new (label, NULL);
g_menu_item_set_action_and_target_value (item, action_name, g_variant_new_boolean (TRUE));
g_menu_item_set_attribute (item, "x-ayatana-type", "s", "org.ayatana.indicator.messages.sourceitem");
if (iconstr)
g_menu_item_set_attribute (item, "x-ayatana-icon", "s", iconstr);
g_menu_prepend_item (menu->source_section, item);
g_free (action_name);
g_object_unref (item);
}
void
im_phone_menu_remove_source (ImPhoneMenu *menu,
const gchar *app_id,
const gchar *id)
{
gchar *action_name;
g_return_if_fail (IM_IS_PHONE_MENU (menu));
g_return_if_fail (app_id != NULL);
action_name = g_strconcat (app_id, ".src.", id, NULL);
im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->source_section),
action_name,
(ImMenuForeachFunc) g_menu_remove);
g_free (action_name);
}
static void
im_phone_menu_remove_all_for_app (GMenu *menu,
const gchar *app_id)
{
gchar *prefix;
gint n_items;
gint i = 0;
prefix = g_strconcat (app_id, ".", NULL);
n_items = g_menu_model_get_n_items (G_MENU_MODEL (menu));
while (i < n_items)
{
gchar *action;
g_menu_model_get_item_attribute (G_MENU_MODEL (menu), i, G_MENU_ATTRIBUTE_ACTION, "s", &action);
if (g_str_has_prefix (action, prefix))
{
g_menu_remove (menu, i);
n_items--;
}
else
{
i++;
}
g_free (action);
}
g_free (prefix);
}
void
im_phone_menu_remove_application (ImPhoneMenu *menu,
const gchar *app_id)
{
g_return_if_fail (IM_IS_PHONE_MENU (menu));
g_return_if_fail (app_id != NULL);
im_phone_menu_remove_all_for_app (menu->source_section, app_id);
im_phone_menu_remove_all_for_app (menu->message_section, app_id);
im_phone_menu_update_clear_section (menu);
}
void
im_phone_menu_remove_all (ImPhoneMenu *menu)
{
g_return_if_fail (IM_IS_PHONE_MENU (menu));
while (g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section)))
g_menu_remove (menu->message_section, 0);
while (g_menu_model_get_n_items (G_MENU_MODEL (menu->source_section)))
g_menu_remove (menu->source_section, 0);
im_phone_menu_update_clear_section (menu);
}