diff options
author | Alexander Schwinn <alexxcons@xfce.org> | 2020-12-24 01:27:10 +0100 |
---|---|---|
committer | Alexander Schwinn <alexxcons@xfce.org> | 2020-12-24 01:27:10 +0100 |
commit | 61dcf30a046172f644f63b84570c4ca594e44028 (patch) | |
tree | 12094bf7ff5f8d22634779cc51a2bc7b955f30d1 /plugins | |
parent | e32e5942ceb84de1127e2f400e95b303833c5709 (diff) | |
download | thunar-61dcf30a046172f644f63b84570c4ca594e44028.tar.gz |
Add submenus for custom actions (Issue #184)
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/thunar-uca/thunar-uca-editor.c | 7 | ||||
-rw-r--r-- | plugins/thunar-uca/thunar-uca-editor.ui | 44 | ||||
-rw-r--r-- | plugins/thunar-uca/thunar-uca-model.c | 35 | ||||
-rw-r--r-- | plugins/thunar-uca/thunar-uca-model.h | 2 | ||||
-rw-r--r-- | plugins/thunar-uca/thunar-uca-provider.c | 113 |
5 files changed, 186 insertions, 15 deletions
diff --git a/plugins/thunar-uca/thunar-uca-editor.c b/plugins/thunar-uca/thunar-uca-editor.c index 9bc80754..5a1cd17f 100644 --- a/plugins/thunar-uca/thunar-uca-editor.c +++ b/plugins/thunar-uca/thunar-uca-editor.c @@ -63,6 +63,7 @@ struct _ThunarUcaEditor GtkWidget *notebook; GtkWidget *name_entry; + GtkWidget *sub_menu_entry; GtkWidget *description_entry; GtkWidget *icon_button; GtkWidget *command_entry; @@ -110,6 +111,7 @@ thunar_uca_editor_class_init (ThunarUcaEditorClass *klass) /* bind stuff */ gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, notebook); gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, name_entry); + gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, sub_menu_entry); gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, description_entry); gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, icon_button); gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, command_entry); @@ -573,6 +575,7 @@ thunar_uca_editor_load (ThunarUcaEditor *uca_editor, gchar *command; gchar *icon_name; gchar *name; + gchar *submenu; gchar *unique_id; gchar *accel_label = NULL; gboolean startup_notify; @@ -590,6 +593,7 @@ thunar_uca_editor_load (ThunarUcaEditor *uca_editor, THUNAR_UCA_MODEL_COLUMN_TYPES, &types, THUNAR_UCA_MODEL_COLUMN_ICON_NAME, &icon_name, THUNAR_UCA_MODEL_COLUMN_NAME, &name, + THUNAR_UCA_MODEL_COLUMN_SUB_MENU, &submenu, THUNAR_UCA_MODEL_COLUMN_STARTUP_NOTIFY, &startup_notify, THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id, -1); @@ -614,6 +618,7 @@ thunar_uca_editor_load (ThunarUcaEditor *uca_editor, gtk_entry_set_text (GTK_ENTRY (uca_editor->patterns_entry), (patterns != NULL) ? patterns : ""); gtk_entry_set_text (GTK_ENTRY (uca_editor->command_entry), (command != NULL) ? command : ""); gtk_entry_set_text (GTK_ENTRY (uca_editor->name_entry), (name != NULL) ? name : ""); + gtk_entry_set_text (GTK_ENTRY (uca_editor->sub_menu_entry), (submenu != NULL) ? submenu : ""); gtk_button_set_label (GTK_BUTTON (uca_editor->shortcut_button), (accel_label != NULL) ? accel_label : _("None")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->sn_button), startup_notify); @@ -623,6 +628,7 @@ thunar_uca_editor_load (ThunarUcaEditor *uca_editor, g_free (command); g_free (icon_name); g_free (name); + g_free (submenu); g_free (unique_id); g_free (accel_label); } @@ -660,6 +666,7 @@ thunar_uca_editor_save (ThunarUcaEditor *uca_editor, thunar_uca_model_update (uca_model, iter, gtk_entry_get_text (GTK_ENTRY (uca_editor->name_entry)), + gtk_entry_get_text (GTK_ENTRY (uca_editor->sub_menu_entry)), unique_id, gtk_entry_get_text (GTK_ENTRY (uca_editor->description_entry)), thunar_uca_editor_get_icon_name (uca_editor), diff --git a/plugins/thunar-uca/thunar-uca-editor.ui b/plugins/thunar-uca/thunar-uca-editor.ui index f6f39449..f837e16c 100644 --- a/plugins/thunar-uca/thunar-uca-editor.ui +++ b/plugins/thunar-uca/thunar-uca-editor.ui @@ -103,6 +103,36 @@ </packing> </child> <child> + <object class="GtkLabel" id="sub_menu_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">_Submenu:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">sub_menu_entry</property> + <property name="xalign">0</property> + <accessibility> + <relation type="label-for" target="sub_menu_entry"/> + </accessibility> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="sub_menu_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">The submenu in which the action will be displayed. Leave empty for no menu. Use '/' for nested menus.</property> + <property name="hexpand">True</property> + <property name="activates_default">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> <object class="GtkLabel" id="command_label"> <property name="visible">True</property> <property name="can_focus">False</property> @@ -116,7 +146,7 @@ </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">2</property> + <property name="top_attach">3</property> </packing> </child> <child> @@ -164,7 +194,7 @@ </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">2</property> + <property name="top_attach">3</property> </packing> </child> <child> @@ -177,7 +207,7 @@ </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">3</property> + <property name="top_attach">4</property> </packing> </child> <child> @@ -226,7 +256,7 @@ </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">3</property> + <property name="top_attach">4</property> </packing> </child> <child> @@ -258,7 +288,7 @@ </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">5</property> + <property name="top_attach">6</property> </packing> </child> <child> @@ -273,7 +303,7 @@ </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">5</property> + <property name="top_attach">6</property> </packing> </child> <child> @@ -290,7 +320,7 @@ </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">6</property> + <property name="top_attach">7</property> <property name="width">2</property> </packing> </child> diff --git a/plugins/thunar-uca/thunar-uca-model.c b/plugins/thunar-uca/thunar-uca-model.c index 5e24b7a7..02b4292e 100644 --- a/plugins/thunar-uca/thunar-uca-model.c +++ b/plugins/thunar-uca/thunar-uca-model.c @@ -75,6 +75,7 @@ typedef enum PARSER_ACTION, PARSER_ICON, PARSER_NAME, + PARSER_SUB_FOLDER, PARSER_UNIQUE_ID, PARSER_COMMAND, PARSER_STARTUP_NOTIFY, @@ -161,6 +162,7 @@ struct _ThunarUcaModel struct _ThunarUcaModelItem { gchar *name; + gchar *submenu; gchar *description; gchar *unique_id; gchar *icon_name; @@ -182,6 +184,7 @@ typedef struct ThunarUcaModel *model; gchar *locale; GString *name; + GString *submenu; gboolean name_use; guint name_match; GString *unique_id; @@ -312,6 +315,9 @@ thunar_uca_model_get_column_type (GtkTreeModel *tree_model, case THUNAR_UCA_MODEL_COLUMN_NAME: return G_TYPE_STRING; + case THUNAR_UCA_MODEL_COLUMN_SUB_MENU: + return G_TYPE_STRING; + case THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID: return G_TYPE_STRING; @@ -407,6 +413,10 @@ thunar_uca_model_get_value (GtkTreeModel *tree_model, g_value_set_static_string (value, item->name ? item->name : ""); break; + case THUNAR_UCA_MODEL_COLUMN_SUB_MENU: + g_value_set_static_string (value, item->submenu ? item->submenu : ""); + break; + case THUNAR_UCA_MODEL_COLUMN_DESCRIPTION: g_value_set_static_string (value, item->description); break; @@ -570,6 +580,7 @@ thunar_uca_model_load_from_file (ThunarUcaModel *uca_model, parser.model = uca_model; parser.locale = g_strdup (setlocale (LC_MESSAGES, NULL)); parser.name = g_string_new (NULL); + parser.submenu = g_string_new (NULL); parser.unique_id = g_string_new (NULL); parser.icon_name = g_string_new (NULL); parser.command = g_string_new (NULL); @@ -591,6 +602,7 @@ thunar_uca_model_load_from_file (ThunarUcaModel *uca_model, g_string_free (parser.command, TRUE); g_string_free (parser.icon_name, TRUE); g_string_free (parser.unique_id, TRUE); + g_string_free (parser.submenu, TRUE); g_string_free (parser.name, TRUE); g_free (parser.locale); xfce_stack_free (parser.stack); @@ -614,6 +626,7 @@ thunar_uca_model_item_reset (ThunarUcaModelItem *item) g_free (item->description); g_free (item->command); g_free (item->name); + g_free (item->submenu); g_free (item->unique_id); g_free (item->icon_name); @@ -665,6 +678,7 @@ start_element_handler (GMarkupParseContext *context, parser->startup_notify = FALSE; g_string_truncate (parser->icon_name, 0); g_string_truncate (parser->name, 0); + g_string_truncate (parser->submenu, 0); g_string_truncate (parser->unique_id, 0); g_string_truncate (parser->command, 0); g_string_truncate (parser->patterns, 0); @@ -705,6 +719,11 @@ start_element_handler (GMarkupParseContext *context, xfce_stack_push (parser->stack, PARSER_NAME); } + else if (strcmp (element_name, "submenu") == 0) + { + g_string_truncate (parser->submenu, 0); + xfce_stack_push (parser->stack, PARSER_SUB_FOLDER); + } else if (strcmp (element_name, "unique-id") == 0) { g_string_truncate (parser->unique_id, 0); @@ -827,6 +846,7 @@ end_element_handler (GMarkupParseContext *context, thunar_uca_model_append (parser->model, &iter); thunar_uca_model_update (parser->model, &iter, parser->name->str, + parser->submenu->str, parser->unique_id->str, parser->description->str, parser->icon_name->str, @@ -849,6 +869,11 @@ end_element_handler (GMarkupParseContext *context, goto unknown_element; break; + case PARSER_SUB_FOLDER: + if (strcmp (element_name, "submenu") != 0) + goto unknown_element; + break; + case PARSER_UNIQUE_ID: if (strcmp (element_name, "unique-id") != 0) goto unknown_element; @@ -943,6 +968,10 @@ text_handler (GMarkupParseContext *context, g_string_append_len (parser->name, text, text_len); break; + case PARSER_SUB_FOLDER: + g_string_append_len (parser->submenu, text, text_len); + break; + case PARSER_UNIQUE_ID: g_string_append_len (parser->unique_id, text, text_len); break; @@ -1302,6 +1331,7 @@ thunar_uca_model_remove (ThunarUcaModel *uca_model, * @uca_model : a #ThunarUcaModel. * @iter : the #GtkTreeIter of the item to update. * @name : the name of the item. + * @submenu : the submenu structure in which the item is placed. * @unique_id : a unique ID for the item. * @description : the description of the item. * @icon : the icon for the item. @@ -1315,6 +1345,7 @@ void thunar_uca_model_update (ThunarUcaModel *uca_model, GtkTreeIter *iter, const gchar *name, + const gchar *submenu, const gchar *unique_id, const gchar *description, const gchar *icon, @@ -1340,6 +1371,8 @@ thunar_uca_model_update (ThunarUcaModel *uca_model, /* setup the new item values */ if (G_LIKELY (name != NULL && *name != '\0')) item->name = g_strdup (name); + if (G_LIKELY (submenu != NULL && *submenu != '\0')) + item->submenu = g_strdup (submenu); if (G_LIKELY (icon != NULL && *icon != '\0')) item->icon_name = g_strdup (icon); if (G_LIKELY (command != NULL && *command != '\0')) @@ -1449,12 +1482,14 @@ thunar_uca_model_save (ThunarUcaModel *uca_model, patterns = g_strjoinv (";", item->patterns); escaped = g_markup_printf_escaped ("\t<icon>%s</icon>\n" "\t<name>%s</name>\n" + "\t<submenu>%s</submenu>\n" "\t<unique-id>%s</unique-id>\n" "\t<command>%s</command>\n" "\t<description>%s</description>\n" "\t<patterns>%s</patterns>\n", (item->icon_name != NULL) ? item->icon_name : "", (item->name != NULL) ? item->name : "", + (item->submenu != NULL) ? item->submenu : "", (item->unique_id != NULL) ? item->unique_id : "", (item->command != NULL) ? item->command : "", (item->description != NULL) ? item->description : "", diff --git a/plugins/thunar-uca/thunar-uca-model.h b/plugins/thunar-uca/thunar-uca-model.h index e662b2f2..dad95e04 100644 --- a/plugins/thunar-uca/thunar-uca-model.h +++ b/plugins/thunar-uca/thunar-uca-model.h @@ -38,6 +38,7 @@ typedef struct _ThunarUcaModel ThunarUcaModel; typedef enum { THUNAR_UCA_MODEL_COLUMN_NAME, + THUNAR_UCA_MODEL_COLUMN_SUB_MENU, THUNAR_UCA_MODEL_COLUMN_DESCRIPTION, THUNAR_UCA_MODEL_COLUMN_GICON, THUNAR_UCA_MODEL_COLUMN_ICON_NAME, @@ -90,6 +91,7 @@ void thunar_uca_model_remove (ThunarUcaModel *uca_mod void thunar_uca_model_update (ThunarUcaModel *uca_model, GtkTreeIter *iter, const gchar *name, + const gchar *submenu, const gchar *unique_id, const gchar *description, const gchar *icon, diff --git a/plugins/thunar-uca/thunar-uca-provider.c b/plugins/thunar-uca/thunar-uca-provider.c index 450616ce..288454bf 100644 --- a/plugins/thunar-uca/thunar-uca-provider.c +++ b/plugins/thunar-uca/thunar-uca-provider.c @@ -187,6 +187,51 @@ thunar_uca_provider_get_menu_items (ThunarxPreferencesProvider *preferences_prov } +/* returned menu must be freed with g_object_unref() */ +static ThunarxMenu* +find_submenu_by_name (gchar *name, GList* items) +{ + GList *lp; + GList *thunarx_menu_items; + + for (lp = g_list_first (items); lp != NULL; lp = lp->next) + { + gchar *item_name = NULL; + ThunarxMenu *item_menu = NULL; + g_object_get (G_OBJECT (lp->data), "name", &item_name, "menu", &item_menu, NULL); + + if (item_menu != NULL) + { + /* This menu is the correct menu */ + if (g_strcmp0 (item_name, name) == 0) + { + g_free (item_name); + return item_menu; + } + + /* Some other menu found .. lets check recursively if the menu we search for is inside */ + thunarx_menu_items = thunarx_menu_get_items (item_menu); + g_object_unref (item_menu); + + if (thunarx_menu_items != NULL) + { + ThunarxMenu *submenu = find_submenu_by_name (name, thunarx_menu_items); + if (submenu != NULL) + { + g_free (item_name); + return submenu; + } + thunarx_menu_item_list_free (thunarx_menu_items); + } + } + g_free (item_name); + } + + /* not found */ + return NULL; +} + + static GList* thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider, @@ -197,20 +242,26 @@ thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider, ThunarUcaProvider *uca_provider = THUNAR_UCA_PROVIDER (menu_provider); ThunarUcaContext *uca_context = NULL; GtkTreeIter iter; + ThunarxMenuItem *menu_item; ThunarxMenuItem *item; GList *items = NULL; GList *paths; GList *lp; + ThunarxMenu *submenu; + ThunarxMenu *parent_menu = NULL; paths = thunar_uca_model_match (uca_provider->model, files); + for (lp = g_list_last (paths); lp != NULL; lp = lp->prev) { - gchar *unique_id = NULL; - gchar *name = NULL; - gchar *label = NULL; - gchar *tooltip = NULL; - gchar *icon_name = NULL; - GIcon *gicon = NULL; + gchar *unique_id = NULL; + gchar *name = NULL; + gchar *sub_menu_string = NULL; + gchar **sub_menus_as_array = NULL; + gchar *label = NULL; + gchar *tooltip = NULL; + gchar *icon_name = NULL; + GIcon *gicon = NULL; /* try to lookup the tree iter for the specified tree path */ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (uca_provider->model), &iter, lp->data)) @@ -218,6 +269,7 @@ thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider, /* determine the label, tooltip and stock-id for the item */ gtk_tree_model_get (GTK_TREE_MODEL (uca_provider->model), &iter, THUNAR_UCA_MODEL_COLUMN_NAME, &label, + THUNAR_UCA_MODEL_COLUMN_SUB_MENU, &sub_menu_string, THUNAR_UCA_MODEL_COLUMN_GICON, &gicon, THUNAR_UCA_MODEL_COLUMN_DESCRIPTION, &tooltip, THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id, @@ -229,6 +281,47 @@ thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider, if (gicon != NULL) icon_name = g_icon_to_string (gicon); + /* Search or build the parent submenus, if required */ + parent_menu = NULL; + sub_menus_as_array = g_strsplit (sub_menu_string, "/", -1); + + for (int i = 0; sub_menus_as_array[i] != NULL; i++) + { + /* get the submenu path up to the iterator */ + gchar *sub_menu_path = g_strdup (sub_menus_as_array[0]); + + for (int j= 1; j<=i; j++) + sub_menu_path = g_strconcat (sub_menu_path, "/", sub_menus_as_array[j], NULL); + + /* Check if the full path already exists */ + submenu = find_submenu_by_name (sub_menu_path, items); + + if (submenu != NULL) + { + /* This submenu already exists, we can just use it as new parent */ + parent_menu = submenu; + /* no need to keep the extra reference on it */ + g_object_unref (submenu); + } + else + { + /* Not found, we create a new submenu */ + menu_item = thunarx_menu_item_new (sub_menu_path, sub_menus_as_array[i], "", "inode-directory"); + + /* Only add base-submenus to the returned list */ + if (parent_menu == NULL) + items = g_list_prepend (items, menu_item); + else + thunarx_menu_prepend_item (parent_menu, menu_item); + + /* This sublevel becomes the new parent */ + parent_menu = thunarx_menu_new (); + thunarx_menu_item_set_menu (menu_item, parent_menu); + } + g_free (sub_menu_path); + } + g_strfreev (sub_menus_as_array); + /* create the new menu item with the given parameters */ item = thunarx_menu_item_new (name, label, tooltip, icon_name); @@ -254,13 +347,17 @@ thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider, g_object_set_data (G_OBJECT (item), "action_path", g_strconcat ("<Actions>/ThunarActions/", name, NULL)); - /* add the menu item to the return list */ - items = g_list_prepend (items, item); + /* add only base menu items to the return list */ + if(parent_menu == NULL) + items = g_list_prepend (items, item); + else + thunarx_menu_prepend_item (parent_menu, item); /* cleanup */ g_free (tooltip); g_free (label); g_free (name); + g_free (sub_menu_string); g_free (icon_name); g_free (unique_id); |