diff --git a/app/menus/menus.c b/app/menus/menus.c index 460a3c778d..3b366cbe3d 100644 --- a/app/menus/menus.c +++ b/app/menus/menus.c @@ -34,6 +34,7 @@ #include "widgets/gimpactionfactory.h" #include "widgets/gimpdashboard.h" #include "widgets/gimpmenufactory.h" +#include "widgets/gimpuimanager.h" #include "dockable-menu.h" #include "image-menu.h" @@ -523,8 +524,11 @@ menus_get_image_manager_singleton (Gimp *gimp) static GimpUIManager *image_ui_manager = NULL; if (image_ui_manager == NULL) - image_ui_manager = gimp_menu_factory_get_manager (menus_get_global_menu_factory (gimp), - "", gimp); + { + image_ui_manager = gimp_menu_factory_get_manager (menus_get_global_menu_factory (gimp), + "", gimp); + image_ui_manager->store_action_paths = TRUE; + } return image_ui_manager; } diff --git a/app/widgets/gimpaction.c b/app/widgets/gimpaction.c index f042bc70ae..9c6abcdd72 100644 --- a/app/widgets/gimpaction.c +++ b/app/widgets/gimpaction.c @@ -73,6 +73,8 @@ struct _GimpActionPrivate gchar **accels; gchar **default_accels; + gchar *menu_path; + GimpRGB *color; GimpViewable *viewable; PangoEllipsizeMode ellipsize; @@ -213,6 +215,7 @@ gimp_action_init (GimpAction *action) priv->icon = NULL; priv->accels = NULL; priv->default_accels = NULL; + priv->menu_path = NULL; priv->ellipsize = PANGO_ELLIPSIZE_NONE; priv->max_width_chars = -1; priv->proxies = NULL; @@ -644,6 +647,14 @@ gimp_action_use_default_accels (GimpAction *action) return TRUE; } +const gchar * +gimp_action_get_menu_path (GimpAction *action) +{ + g_return_val_if_fail (GIMP_IS_ACTION (action), NULL); + + return GET_PRIVATE (action)->menu_path; +} + void gimp_action_activate (GimpAction *action) { @@ -1133,6 +1144,32 @@ gimp_action_set_default_accels (GimpAction *action, g_signal_emit (action, action_signals[ACCELS_CHANGED], 0, accels); } +/* This function is only meant to be run by the GimpMenuModel class. */ +void +gimp_action_set_menu_path (GimpAction *action, + const gchar *menu_path) +{ + GimpActionPrivate *priv = GET_PRIVATE (action); + gchar **paths; + + g_return_if_fail (GIMP_IS_ACTION (action)); + if (priv->menu_path != NULL) + /* There are cases where we put some actions in 2 menu paths, for instance: + * - filters-color-to-alpha in both /Layer/Transparency and /Colors + * - dialogs-histogram in both /Colors/Info and /Windows/Dockable Dialogs + * + * Anyway this is not an error, it's just how it is. Let's simply skip such + * cases silently and keep the first path as reference to show in helper + * widgets. + */ + return; + + paths = gimp_utils_break_menu_path (menu_path); + /* The 4 raw bytes are the "rightwards triangle arrowhead" unicode character. */ + priv->menu_path = g_strjoinv (" \xF0\x9F\xA2\x92 ", paths); + g_strfreev (paths); +} + /* Private functions */ @@ -1176,6 +1213,8 @@ gimp_action_private_finalize (GimpActionPrivate *priv) g_strfreev (priv->accels); g_strfreev (priv->default_accels); + g_free (priv->menu_path); + for (GList *iter = priv->proxies; iter; iter = iter->next) { /* TODO GAction: if an action associated to a proxy menu item disappears, diff --git a/app/widgets/gimpaction.h b/app/widgets/gimpaction.h index addd40ab97..4f586dab35 100644 --- a/app/widgets/gimpaction.h +++ b/app/widgets/gimpaction.h @@ -115,6 +115,8 @@ const gchar ** gimp_action_get_accels (GimpAction *action); gchar ** gimp_action_get_display_accels (GimpAction *action); gboolean gimp_action_use_default_accels (GimpAction *action); +const gchar * gimp_action_get_menu_path (GimpAction *action); + void gimp_action_activate (GimpAction *action); gint gimp_action_name_compare (GimpAction *action1, @@ -148,6 +150,8 @@ void gimp_action_set_group (GimpAction *action, GimpActionGroup *group); void gimp_action_set_default_accels (GimpAction *action, const gchar **accels); +void gimp_action_set_menu_path (GimpAction *action, + const gchar *menu_path); #endif /* __GIMP_ACTION_H__ */ diff --git a/app/widgets/gimpmenumodel.c b/app/widgets/gimpmenumodel.c index fc7b7c29f4..8ddf4082f0 100644 --- a/app/widgets/gimpmenumodel.c +++ b/app/widgets/gimpmenumodel.c @@ -653,6 +653,12 @@ gimp_menu_model_initialize (GimpMenuModel *model, action = gimp_ui_manager_find_action (model->priv->manager, NULL, action_name); + if (model->priv->manager->store_action_paths) + /* Special-case the main menu manager when constructing it as + * this is the only one which should set the menu path. + */ + gimp_action_set_menu_path (action, gimp_menu_model_get_path (model)); + g_signal_connect_object (action, "notify::visible", G_CALLBACK (gimp_menu_model_action_notify_visible), @@ -851,6 +857,9 @@ gimp_menu_model_ui_added (GimpUIManager *manager, /* TODO: add also G_MENU_ATTRIBUTE_ICON attribute? */ g_free (detailed_action_name); + if (model->priv->manager->store_action_paths) + gimp_action_set_menu_path (GIMP_ACTION (action), gimp_menu_model_get_path (model)); + if (placeholder_key) { GList *placeholder = NULL; diff --git a/app/widgets/gimpsearchpopup.c b/app/widgets/gimpsearchpopup.c index 7e82899f96..07b046850d 100644 --- a/app/widgets/gimpsearchpopup.c +++ b/app/widgets/gimpsearchpopup.c @@ -233,8 +233,9 @@ gimp_search_popup_add_result (GimpSearchPopup *popup, gchar *label; gchar *escaped_label = NULL; const gchar *icon_name; - gchar *escaped_accel = NULL; - gboolean has_shortcut = FALSE; + gchar *shortcut_helper = NULL; + const gchar *menu_path; + gchar *menu_path_helper = NULL; const gchar *tooltip; gchar *escaped_tooltip = NULL; gboolean has_tooltip = FALSE; @@ -267,11 +268,46 @@ gimp_search_popup_add_result (GimpSearchPopup *popup, accels = gimp_action_get_display_accels (action); if (accels && accels[0]) { - escaped_accel = g_markup_escape_text (accels[0], -1); - has_shortcut = TRUE; + gchar *formatted_label; + gchar *formatted_value; + + /* TRANSLATORS: a helper label indicating the shortcut for an action, + * it will be used within the generic "%s: %s" (also localized) string. + * e.g.: "shortcut: Ctrl+Alt+O" + */ + formatted_label = g_markup_printf_escaped ("%s", _("shortcut")); + formatted_value = g_markup_escape_text (accels[0], -1); + + /* TRANSLATORS: generic "title: value" label which will be used in various ways. */ + shortcut_helper = g_strdup_printf (_("%s: %s"), formatted_label, formatted_value); + + g_free (formatted_label); + g_free (formatted_value); } g_strfreev (accels); + if ((menu_path = gimp_action_get_menu_path (action)) != NULL) + { + if (strlen (menu_path) > 0) + { + gchar *formatted_label; + gchar *formatted_value; + + /* TRANSLATORS: a helper label indicating the menu path for an action, + * it will be used within the generic "%s: %s" (also localized) string. + * e.g.: "Menu: Filters > Generic" + */ + formatted_label = g_markup_printf_escaped ("%s", _("menu")); + formatted_value = g_markup_escape_text (menu_path, -1); + + /* TRANSLATORS: generic "title: value" label which will be used in various ways. */ + menu_path_helper = g_strdup_printf (_("%s: %s"), formatted_label, formatted_value); + + g_free (formatted_label); + g_free (formatted_value); + } + } + tooltip = gimp_action_get_tooltip (action); if (tooltip != NULL) { @@ -287,12 +323,18 @@ gimp_search_popup_add_result (GimpSearchPopup *popup, markup = g_strdup_printf ("%s" /* Label */ "%s%s" /* Shortcut */ + "%s%s" /* Menu path */ "%s%s" /* Tooltip */ "%s%s" /* Inactive reason */ "", escaped_label, - has_shortcut ? " | " : "", - has_shortcut ? escaped_accel : "", + + shortcut_helper ? " | " : "", + shortcut_helper ? shortcut_helper : "", + + menu_path_helper ? " | " : "", + menu_path_helper ? menu_path_helper : "", + has_tooltip ? "\n" : "", has_tooltip ? escaped_tooltip : "", escaped_reason ? "\n" : "", @@ -339,10 +381,11 @@ gimp_search_popup_add_result (GimpSearchPopup *popup, g_free (markup); g_free (action_name); g_free (label); - g_free (escaped_accel); g_free (escaped_label); g_free (escaped_tooltip); g_free (escaped_reason); + g_free (menu_path_helper); + g_free (shortcut_helper); } /************ Private Functions ****************/ diff --git a/app/widgets/gimpuimanager.c b/app/widgets/gimpuimanager.c index 8a62f8a33e..26ec546b61 100644 --- a/app/widgets/gimpuimanager.c +++ b/app/widgets/gimpuimanager.c @@ -199,9 +199,10 @@ gimp_ui_manager_class_init (GimpUIManagerClass *klass) static void gimp_ui_manager_init (GimpUIManager *manager) { - manager->name = NULL; - manager->gimp = NULL; - manager->action_groups = NULL; + manager->name = NULL; + manager->gimp = NULL; + manager->action_groups = NULL; + manager->store_action_paths = FALSE; } static void diff --git a/app/widgets/gimpuimanager.h b/app/widgets/gimpuimanager.h index 5ac107a323..68c3314f63 100644 --- a/app/widgets/gimpuimanager.h +++ b/app/widgets/gimpuimanager.h @@ -69,6 +69,11 @@ struct _GimpUIManager GList *ui_items; GList *action_groups; + + /* Special property which should be set to TRUE only for the singleton UI + * manager of the top menu bar. + */ + gboolean store_action_paths; }; struct _GimpUIManagerClass