summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorAlexander Schwinn <alexxcons@xfce.org>2020-12-24 01:27:10 +0100
committerAlexander Schwinn <alexxcons@xfce.org>2020-12-24 01:27:10 +0100
commit61dcf30a046172f644f63b84570c4ca594e44028 (patch)
tree12094bf7ff5f8d22634779cc51a2bc7b955f30d1 /plugins
parente32e5942ceb84de1127e2f400e95b303833c5709 (diff)
downloadthunar-61dcf30a046172f644f63b84570c4ca594e44028.tar.gz
Add submenus for custom actions (Issue #184)
Diffstat (limited to 'plugins')
-rw-r--r--plugins/thunar-uca/thunar-uca-editor.c7
-rw-r--r--plugins/thunar-uca/thunar-uca-editor.ui44
-rw-r--r--plugins/thunar-uca/thunar-uca-model.c35
-rw-r--r--plugins/thunar-uca/thunar-uca-model.h2
-rw-r--r--plugins/thunar-uca/thunar-uca-provider.c113
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);