[nautilus/wip/gaction: 2/2] general: Implement extensions for GAction



commit ecf73fdcc0de0175e10dd5512723a3c800e2fc33
Author: Carlos Soriano <carlos sorian89 gmail com>
Date:   Wed Jan 14 18:18:22 2015 +0100

    general: Implement extensions for GAction
    
    The last commit rework the menus and ported to GAction.
    Update the extension mechanism to that.
    
    The changes are very little. Now menu items in extensions lost
    the property 'priority' since gmenu doesn't have one, and gain
    two properties, menu_name, which is in which menu do you want the
    extension to add a menu item, it can be background or selection, and
    menu_section, which indicates in which section of the menu do you want
    to add the items of the extension.

 libnautilus-extension/nautilus-menu-item.c  |   51 ++++--
 libnautilus-extension/nautilus-menu.h       |    4 +-
 libnautilus-private/nautilus-ui-utilities.c |   18 ++-
 libnautilus-private/nautilus-ui-utilities.h |    5 +
 nautilus-sendto-extension/nautilus-nste.c   |   23 ++--
 src/nautilus-view-context-menus.xml         |   11 +-
 src/nautilus-view.c                         |  258 +++++++++++++++++++++++++++
 7 files changed, 334 insertions(+), 36 deletions(-)
---
diff --git a/libnautilus-extension/nautilus-menu-item.c b/libnautilus-extension/nautilus-menu-item.c
index dfe3e27..a76e9ca 100644
--- a/libnautilus-extension/nautilus-menu-item.c
+++ b/libnautilus-extension/nautilus-menu-item.c
@@ -37,7 +37,8 @@ enum {
        PROP_TIP,
        PROP_ICON,
        PROP_SENSITIVE,
-       PROP_PRIORITY,
+       PROP_MENU_NAME,
+       PROP_SECTION_NAME,
        PROP_MENU,
        LAST_PROP
 };
@@ -47,6 +48,8 @@ struct _NautilusMenuItemDetails {
        char *label;
        char *tip;
        char *icon;
+       char *menu_name;
+       char *section_name;
        NautilusMenu *menu;
        gboolean sensitive;
        gboolean priority;
@@ -71,7 +74,9 @@ NautilusMenuItem *
 nautilus_menu_item_new (const char *name,
                        const char *label,
                        const char *tip,
-                       const char *icon)
+                       const char *icon,
+                       const char *menu_name,
+                       const char *section_name)
 {
        NautilusMenuItem *item;
 
@@ -84,6 +89,8 @@ nautilus_menu_item_new (const char *name,
                             "label", label,
                             "tip", tip,
                             "icon", icon,
+                            "menu_name", menu_name,
+                            "section_name", section_name,
                             NULL);
 
        return item;
@@ -140,8 +147,11 @@ nautilus_menu_item_get_property (GObject *object,
        case PROP_SENSITIVE :
                g_value_set_boolean (value, item->details->sensitive);
                break;
-       case PROP_PRIORITY :
-               g_value_set_boolean (value, item->details->priority);
+       case PROP_MENU_NAME :
+               g_value_set_string (value, item->details->menu_name);
+               break;
+       case PROP_SECTION_NAME :
+               g_value_set_string (value, item->details->section_name);
                break;
        case PROP_MENU :
                g_value_set_object (value, item->details->menu);
@@ -187,9 +197,15 @@ nautilus_menu_item_set_property (GObject *object,
                item->details->sensitive = g_value_get_boolean (value);
                g_object_notify (object, "sensitive");
                break;
-       case PROP_PRIORITY :
-               item->details->priority = g_value_get_boolean (value);
-               g_object_notify (object, "priority");
+       case PROP_MENU_NAME :
+               g_free (item->details->menu_name);
+               item->details->menu_name = g_strdup (g_value_get_string (value));
+               g_object_notify (object, "menu_name");
+               break;
+       case PROP_SECTION_NAME :
+               g_free (item->details->section_name);
+               item->details->section_name = g_strdup (g_value_get_string (value));
+               g_object_notify (object, "section_name");
                break;
        case PROP_MENU :
                if (item->details->menu) {
@@ -215,6 +231,8 @@ nautilus_menu_item_finalize (GObject *object)
        g_free (item->details->label);
        g_free (item->details->tip);
        g_free (item->details->icon);
+       g_free (item->details->section_name);
+       g_free (item->details->menu_name);
        if (item->details->menu) {
                g_object_unref (item->details->menu);
        }
@@ -288,12 +306,19 @@ nautilus_menu_item_class_init (NautilusMenuItemClass *class)
                                                               TRUE,
                                                               G_PARAM_READWRITE));
        g_object_class_install_property (G_OBJECT_CLASS (class),
-                                        PROP_PRIORITY,
-                                        g_param_spec_boolean ("priority",
-                                                              "Priority",
-                                                              "Show priority text in toolbars",
-                                                              TRUE,
-                                                              G_PARAM_READWRITE));
+                                        PROP_MENU_NAME,
+                                        g_param_spec_string ("menu_name",
+                                                             "Menu name",
+                                                             "The name of the menu to for inserting the 
item. It can be 'background' or 'selection'",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (G_OBJECT_CLASS (class),
+                                        PROP_SECTION_NAME,
+                                        g_param_spec_string ("section_name",
+                                                             "Section name",
+                                                             "The name of the section to be the insertion 
point for the item",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
        g_object_class_install_property (G_OBJECT_CLASS (class),
                                         PROP_MENU,
                                         g_param_spec_object ("menu",
diff --git a/libnautilus-extension/nautilus-menu.h b/libnautilus-extension/nautilus-menu.h
index fd132be..2f9623d 100644
--- a/libnautilus-extension/nautilus-menu.h
+++ b/libnautilus-extension/nautilus-menu.h
@@ -95,7 +95,9 @@ GType             nautilus_menu_item_get_type      (void);
 NautilusMenuItem *nautilus_menu_item_new           (const char       *name,
                                                    const char       *label,
                                                    const char       *tip,
-                                                   const char       *icon);
+                                                   const char       *icon,
+                                                   const char       *menu_name,
+                                                   const char       *section_name);
 
 void              nautilus_menu_item_activate      (NautilusMenuItem *item);
 void              nautilus_menu_item_set_submenu   (NautilusMenuItem *item,
diff --git a/libnautilus-private/nautilus-ui-utilities.c b/libnautilus-private/nautilus-ui-utilities.c
index 1201c45..0dfcc52 100644
--- a/libnautilus-private/nautilus-ui-utilities.c
+++ b/libnautilus-private/nautilus-ui-utilities.c
@@ -75,37 +75,41 @@ find_gmenu_model (GMenuModel  *model,
 }
 
 /*
- * The original GMenu is modified adding to the section @section_name
+ * The original GMenu is modified adding to the section @submodel_name
  * the items in @gmenu_to_merge.
  * @gmenu_to_merge should be a list of menu items.
  */
 void
 nautilus_gmenu_merge (GMenu       *original,
                      GMenu       *gmenu_to_merge,
-                     const gchar *section_name)
+                     const gchar *submodel_name,
+                     gboolean     prepend)
 {
        gint i, n_items;
-       GMenuModel *section;
+       GMenuModel *submodel;
        GMenuItem *item;
 
        g_return_if_fail (G_IS_MENU (original));
        g_return_if_fail (G_IS_MENU (gmenu_to_merge));
 
-       section = find_gmenu_model (G_MENU_MODEL (original), section_name);
+       submodel = find_gmenu_model (G_MENU_MODEL (original), submodel_name);
 
-       g_return_if_fail (section != NULL);
+       g_return_if_fail (submodel != NULL);
 
        n_items = g_menu_model_get_n_items (G_MENU_MODEL (gmenu_to_merge));
 
        for (i = 0; i < n_items; i++) {
                item = g_menu_item_new_from_model (G_MENU_MODEL (gmenu_to_merge), i);
-               g_menu_append_item (G_MENU (section), item);
+               if (prepend)
+                       g_menu_prepend_item (G_MENU (submodel), item);
+               else
+                       g_menu_append_item (G_MENU (submodel), item);
                g_object_unref (item);
        }
 }
 
 /*
- * The GMenu @menu is modified adding to the section @section_name
+ * The GMenu @menu is modified adding to the section @submodel_name
  * the item @item.
  */
 void
diff --git a/libnautilus-private/nautilus-ui-utilities.h b/libnautilus-private/nautilus-ui-utilities.h
index f1ce5c2..5e031ff 100644
--- a/libnautilus-private/nautilus-ui-utilities.h
+++ b/libnautilus-private/nautilus-ui-utilities.h
@@ -31,6 +31,11 @@ void nautilus_gmenu_add_item_in_submodel        (GMenu             *menu,
                                                    GMenuItem         *item,
                                                    const gchar       *section_name,
                                                    gboolean           prepend);
+void
+nautilus_gmenu_merge                              (GMenu       *original,
+                                                   GMenu       *gmenu_to_merge,
+                                                   const gchar *submodel_name,
+                                                   gboolean     prepend);
 void pop_up_context_menu                           (GtkWidget         *parent,
                                                     GMenu             *menu,
                                                     GdkEventButton    *event);
diff --git a/nautilus-sendto-extension/nautilus-nste.c b/nautilus-sendto-extension/nautilus-nste.c
index 92f347e..9859d61 100644
--- a/nautilus-sendto-extension/nautilus-nste.c
+++ b/nautilus-sendto-extension/nautilus-nste.c
@@ -78,6 +78,7 @@ nautilus_nste_get_file_items (NautilusMenuProvider *provider,
        gboolean  one_item;
        NautilusMenuItem *item;
        NautilusNste *nste;
+       char *tip;
 
        nste = NAUTILUS_NSTE (provider);
        if (!nste->nst_present)
@@ -91,17 +92,17 @@ nautilus_nste_get_file_items (NautilusMenuProvider *provider,
 
        one_item = (files != NULL) && (files->next == NULL);
        if (one_item &&
-           !nautilus_file_info_is_directory ((NautilusFileInfo *)files->data)) {
-               item = nautilus_menu_item_new ("NautilusNste::sendto",
-                                              _("Email…"),
-                                              _("Send file by mail…"),
-                                              "document-send");
-       } else {
-               item = nautilus_menu_item_new ("NautilusNste::sendto",
-                                              _("Email…"),
-                                              _("Send files by mail…"),
-                                              "document-send");
-       }
+           !nautilus_file_info_is_directory ((NautilusFileInfo *)files->data))
+               tip = _("Send file by mail…");
+       else
+               tip = _("Send files by mail…");
+
+       item = nautilus_menu_item_new ("nautilus-nste-send-to",
+                                      _("Email…"),
+                                      tip,
+                                      "document-send",
+                                      "selection",
+                                      "file-actions-section");
        g_signal_connect (item,
                          "activate",
                          G_CALLBACK (sendto_callback),
diff --git a/src/nautilus-view-context-menus.xml b/src/nautilus-view-context-menus.xml
index b9b6f96..96f4518 100644
--- a/src/nautilus-view-context-menus.xml
+++ b/src/nautilus-view-context-menus.xml
@@ -48,6 +48,9 @@
         <attribute name="hidden-when">action-disabled</attribute>
       </item>
     </section>
+    <section>
+      <attribute name="id">extensions</attribute>
+    </section>
   </menu>
   <menu id="selection-menu">
     <section>
@@ -139,6 +142,7 @@
       </item>
     </section>
     <section>
+      <attribute name="id">file-actions-section</attribute>
       <item>
         <attribute name="label" translatable="yes">Move to…</attribute>
         <attribute name="action">view.move-to</attribute>
@@ -147,10 +151,6 @@
         <attribute name="label" translatable="yes">Copy to…</attribute>
         <attribute name="action">view.copy-to</attribute>
       </item>
-      <item>
-        <attribute name="label" translatable="yes">Send to…</attribute>
-        <attribute name="action">view.send-to</attribute>
-      </item>
     </section>
     <section>
       <item>
@@ -193,6 +193,9 @@
         <attribute name="action">view.properties</attribute>
       </item>
     </section>
+    <section>
+      <attribute name="id">extensions</attribute>
+    </section>
   </menu>
   <menu id="pathbar-menu">
     <section>
diff --git a/src/nautilus-view.c b/src/nautilus-view.c
index 38424f3..65699e2 100644
--- a/src/nautilus-view.c
+++ b/src/nautilus-view.c
@@ -3662,6 +3662,262 @@ get_menu_icon_for_file (NautilusFile *file,
        return pixbuf;
 }
 
+static GList *
+get_all_extension_menu_items (GtkWidget *window,
+                             GList *selection)
+{
+       GList *items;
+       GList *providers;
+       GList *l;
+       
+       providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER);
+       items = NULL;
+
+       for (l = providers; l != NULL; l = l->next) {
+               NautilusMenuProvider *provider;
+               GList *file_items;
+               
+               provider = NAUTILUS_MENU_PROVIDER (l->data);
+               file_items = nautilus_menu_provider_get_file_items (provider,
+                                                                   window,
+                                                                   selection);
+               items = g_list_concat (items, file_items);              
+       }
+
+       nautilus_module_extension_list_free (providers);
+
+       return items;
+}
+
+typedef struct 
+{
+       NautilusMenuItem *item;
+       NautilusView *view;
+       GList *selection;
+       GAction *action;
+} ExtensionActionCallbackData;
+
+
+static void
+extension_action_callback_data_free (ExtensionActionCallbackData *data)
+{
+       g_object_unref (data->item);
+       nautilus_file_list_free (data->selection);
+       
+       g_free (data);
+}
+
+static gboolean
+search_in_menu_items (GList      * items,
+                     const char *item_name)
+{
+       GList* list;
+       
+       for (list = items; list != NULL; list = list->next) {
+               NautilusMenu* menu;
+               char *name;
+               
+               g_object_get (list->data, "name", &name, NULL);
+               if (strcmp (name, item_name) == 0) {
+                       g_free (name);
+                       return TRUE;
+               }
+               g_free (name);
+
+               menu = NULL;
+               g_object_get (list->data, "menu", &menu, NULL);
+               if (menu != NULL) {
+                       gboolean ret;
+                       GList* submenus;
+
+                       submenus = nautilus_menu_get_items (menu);
+                       ret = search_in_menu_items (submenus, item_name);
+                       nautilus_menu_item_list_free (submenus);
+                       g_object_unref (menu);
+                       if (ret) {
+                               return TRUE;
+                       }
+               }
+       }
+       return FALSE;
+}
+
+static void
+extension_action_callback (GSimpleAction *action,
+                          GVariant      *state,
+                          gpointer       user_data)
+{
+       ExtensionActionCallbackData *data;
+       char *item_name;
+       gboolean is_valid;
+       GList *l;
+       GList *items;
+
+       data = user_data;
+
+       /* Make sure the selected menu item is valid for the final sniffed
+        * mime type */
+       g_object_get (data->item, "name", &item_name, NULL);
+       items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (data->view)), 
+                                             data->selection);
+       
+       is_valid = search_in_menu_items (items, item_name);
+
+       for (l = items; l != NULL; l = l->next) {
+               g_object_unref (l->data);
+       }
+       g_list_free (items);
+       
+       g_free (item_name);
+
+       if (is_valid) {
+               nautilus_menu_item_activate (data->item);
+       }
+}
+
+static void
+add_extension_action_for_files (NautilusView *view, 
+                               NautilusMenuItem *item,
+                               GList *files)
+{
+       char *name, *label, *tip, *icon;
+       gboolean sensitive;
+       GAction *action;
+       ExtensionActionCallbackData *data;
+       
+       g_object_get (G_OBJECT (item), 
+                     "name", &name, "label", &label, 
+                     "tip", &tip, "icon", &icon,
+                     "sensitive", &sensitive,
+                     NULL);
+
+       action = G_ACTION (g_simple_action_new (name, NULL));
+
+       data = g_new0 (ExtensionActionCallbackData, 1);
+       data->item = g_object_ref (item);
+       data->view = view;
+       data->selection = nautilus_file_list_copy (files);
+       data->action = action;
+
+       g_signal_connect_data (action, "activate",
+                              G_CALLBACK (extension_action_callback),
+                              data,
+                              (GClosureNotify)extension_action_callback_data_free, 0);
+               
+       g_action_map_add_action  (G_ACTION_MAP (view->details->view_action_group),
+                                 action);
+       g_simple_action_set_enabled (G_SIMPLE_ACTION (action), sensitive);
+       g_object_unref (action);
+       
+       g_free (name);
+       g_free (label);
+       g_free (tip);
+       g_free (icon);
+}
+
+static GMenu *
+add_extension_menu_items (NautilusView *view,
+                         GList        *files,
+                         GList        *menu_items,
+                         GMenuItem    *parent) 
+{
+       GList *l;
+       GMenuItem *menu_item;
+       GMenu *gmenu, *target, *children_menu;
+       char *name, *label, *tip, *icon, *menu_name, *section_name, *detailed_action_name;
+       gboolean sensitive;
+       GdkPixbuf *pixbuf;
+
+       gmenu = g_menu_new ();
+       
+       for (l = menu_items; l; l = l->next) {
+               NautilusMenuItem *item;
+               NautilusMenu *menu;
+               
+               item = NAUTILUS_MENU_ITEM (l->data);
+               
+               g_object_get (item, "menu", &menu, NULL);
+
+               g_object_get (G_OBJECT (item), 
+                             "name", &name, "label", &label, 
+                             "tip", &tip, "icon", &icon,
+                             "sensitive", &sensitive,
+                             "menu_name", &menu_name,
+                             "section_name", &section_name,
+                             NULL);
+               
+               add_extension_action_for_files (view, item, files);
+               detailed_action_name =  g_strconcat ("view.", name, NULL);
+               menu_item = g_menu_item_new (label, detailed_action_name);
+                if (menu != NULL) {
+                       GList *children;
+                       
+                       children = nautilus_menu_get_items (menu);
+                       
+                       children_menu = add_extension_menu_items (view,
+                                                                 files,
+                                                                 children,
+                                                                 menu_item);
+
+                       nautilus_menu_item_list_free (children);
+                       g_menu_item_set_submenu (menu_item, G_MENU_MODEL (children_menu));
+               }
+
+               if (icon != NULL) {
+                       pixbuf = nautilus_ui_get_menu_icon (icon, GTK_WIDGET (view));
+                       if (pixbuf != NULL) {
+                               g_menu_item_set_icon (menu_item, pixbuf);
+                               g_object_unref (pixbuf);
+                       }
+               }
+
+               g_menu_append_item (gmenu, menu_item);                                  
+       }
+
+       if (g_strcmp0(menu_name, "background") == 0)
+               target = view->details->background_menu;
+       else if (g_strcmp0(menu_name, "selection") == 0)
+               target = view->details->selection_menu;
+       else
+               goto clean_up;
+
+       if (parent) {
+               g_menu_item_set_submenu (parent, G_MENU_MODEL (gmenu));
+       } else {
+               nautilus_gmenu_merge (target,
+                                     gmenu,
+                                     section_name,
+                                     FALSE);
+       }
+clean_up:
+       g_free (name);
+       g_free (label);
+       g_free (tip);
+       g_free (icon);
+       g_free (menu_name);
+       g_free (section_name);
+
+       return gmenu;
+}
+
+static void
+update_extensions_menus (NautilusView *view)
+{
+       GList *items;
+       GList *selection;
+       
+       selection = nautilus_view_get_selection (view);
+
+       items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (view)), 
+                                             selection);
+       if (items != NULL) {
+               add_extension_menu_items (view, selection, items, NULL);
+
+               g_list_foreach (items, (GFunc) g_object_unref, NULL);
+               g_list_free (items);
+       }
+}
+
 static char *
 change_to_view_directory (NautilusView *view)
 {
@@ -5812,6 +6068,8 @@ real_update_context_menus (NautilusView *view)
 
        update_selection_menu (view);
        update_background_menu (view);
+       update_extensions_menus (view);
+
        nautilus_view_update_actions_state (view);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]