[gimp/gimp-2-10] app: add support for tool groups in toolrc



commit 207c6b283f1c3f37602cbcc6fee813a2937f7f0e
Author: Ell <ell_se yahoo com>
Date:   Wed Jan 29 21:02:00 2020 +0200

    app: add support for tool groups in toolrc
    
    Add a new Gimp::tool_item_list list, in addition to
    Gimp::tool_info_list.  The latter may contain arbitrary tool items,
    including tool groups, and is intended for use in the UI (namely,
    the toolbox and the preferences tool editor).
    
    In gimp-tools, use Gimp::tool_item_list for representing the UI
    tool order (while still using Gimp::tool_info_list as a flat list
    of all GimpToolInfo objects), and add support for saving and
    loading tool groups to/from toolrc.
    
    Introduce file-version tracking in toolrc, and drop its contents on
    version mismatch, or when new tools are introduced.  This is
    slightly disruptive, but merging new changes with existing toolrc
    files is non-trivial, and it doesn't happen very often.
    
    Add support for a sysconf toolrc file, which is used if there's no
    user toolrc file (i.e., on first use).  If neither file is found,
    the hard-coded flat tool order is used.  This commit doesn't
    provide a default toolrc file, but the next commits will.
    
    Make the gimp-tools serialization and deserialization functions
    public, for use in GimpToolEditor in the next commits.

 app/core/gimp.c        |  17 +++
 app/core/gimp.h        |   3 +
 app/tools/gimp-tools.c | 394 +++++++++++++++++++++++++++++++++++++------------
 app/tools/gimp-tools.h |  29 ++--
 po/POTFILES.in         |   1 +
 5 files changed, 344 insertions(+), 100 deletions(-)
---
diff --git a/app/core/gimp.c b/app/core/gimp.c
index 6192f6fea5..c838c9a369 100644
--- a/app/core/gimp.c
+++ b/app/core/gimp.c
@@ -262,6 +262,13 @@ gimp_init (Gimp *gimp)
   gimp_object_set_static_name (GIMP_OBJECT (gimp->tool_info_list),
                                "tool infos");
 
+  gimp->tool_item_list = g_object_new (GIMP_TYPE_LIST,
+                                       "children-type", GIMP_TYPE_TOOL_ITEM,
+                                       "append",        TRUE,
+                                       NULL);
+  gimp_object_set_static_name (GIMP_OBJECT (gimp->tool_item_list),
+                               "tool items");
+
   gimp->documents = gimp_document_list_new (gimp);
 
   gimp->templates = gimp_list_new (GIMP_TYPE_TEMPLATE, TRUE);
@@ -385,6 +392,8 @@ gimp_finalize (GObject *object)
       g_clear_object (&gimp->tool_info_list);
     }
 
+  g_clear_object (&gimp->tool_item_list);
+
   file_data_exit (gimp);
   xcf_exit (gimp);
 
@@ -900,6 +909,14 @@ gimp_get_tool_info_iter (Gimp *gimp)
   return GIMP_LIST (gimp->tool_info_list)->queue->head;
 }
 
+GList *
+gimp_get_tool_item_iter (Gimp *gimp)
+{
+  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
+
+  return GIMP_LIST (gimp->tool_item_list)->queue->head;
+}
+
 GimpObject *
 gimp_get_clipboard_object (Gimp *gimp)
 {
diff --git a/app/core/gimp.h b/app/core/gimp.h
index bbf5a9ee6d..7bb7a30d2f 100644
--- a/app/core/gimp.h
+++ b/app/core/gimp.h
@@ -110,6 +110,8 @@ struct _Gimp
   GimpContainer          *tool_info_list;
   GimpToolInfo           *standard_tool_info;
 
+  GimpContainer          *tool_item_list;
+
   /*  the opened and saved images in MRU order  */
   GimpContainer          *documents;
 
@@ -186,6 +188,7 @@ GList        * gimp_get_display_iter       (Gimp                *gimp);
 GList        * gimp_get_image_windows      (Gimp                *gimp);
 GList        * gimp_get_paint_info_iter    (Gimp                *gimp);
 GList        * gimp_get_tool_info_iter     (Gimp                *gimp);
+GList        * gimp_get_tool_item_iter     (Gimp                *gimp);
 
 GimpObject   * gimp_get_clipboard_object   (Gimp                *gimp);
 
diff --git a/app/tools/gimp-tools.c b/app/tools/gimp-tools.c
index 9c63d46cef..55c0b6e30c 100644
--- a/app/tools/gimp-tools.c
+++ b/app/tools/gimp-tools.c
@@ -31,7 +31,9 @@
 #include "core/gimp.h"
 #include "core/gimp-contexts.h"
 #include "core/gimp-internal-data.h"
+#include "core/gimpcontext.h"
 #include "core/gimplist.h"
+#include "core/gimptoolgroup.h"
 #include "core/gimptoolinfo.h"
 #include "core/gimptooloptions.h"
 
@@ -89,23 +91,32 @@
 #include "gimpvectortool.h"
 #include "gimpwarptool.h"
 
+#include "gimp-intl.h"
 
-/*  local function prototypes  */
 
-static void   gimp_tools_register (GType                   tool_type,
-                                   GType                   tool_options_type,
-                                   GimpToolOptionsGUIFunc  options_gui_func,
-                                   GimpContextPropMask     context_props,
-                                   const gchar            *identifier,
-                                   const gchar            *label,
-                                   const gchar            *tooltip,
-                                   const gchar            *menu_label,
-                                   const gchar            *menu_accel,
-                                   const gchar            *help_domain,
-                                   const gchar            *help_data,
-                                   const gchar            *icon_name,
-                                   gpointer                data);
+#define TOOL_RC_FILE_VERSION 1
+
 
+/*  local function prototypes  */
+
+static void   gimp_tools_register       (GType                   tool_type,
+                                         GType                   tool_options_type,
+                                         GimpToolOptionsGUIFunc  options_gui_func,
+                                         GimpContextPropMask     context_props,
+                                         const gchar            *identifier,
+                                         const gchar            *label,
+                                         const gchar            *tooltip,
+                                         const gchar            *menu_label,
+                                         const gchar            *menu_accel,
+                                         const gchar            *help_domain,
+                                         const gchar            *help_data,
+                                         const gchar            *icon_name,
+                                         gpointer                data);
+
+static void   gimp_tools_copy_structure (Gimp                   *gimp,
+                                         GimpContainer          *src_container,
+                                         GimpContainer          *dest_container,
+                                         GHashTable             *tools);
 
 /*  private variables  */
 
@@ -225,18 +236,10 @@ gimp_tools_init (Gimp *gimp)
 void
 gimp_tools_exit (Gimp *gimp)
 {
-  GList *default_order;
   GList *list;
 
   g_return_if_fail (GIMP_IS_GIMP (gimp));
 
-  default_order = g_object_get_data (G_OBJECT (gimp),
-                                     "gimp-tools-default-order");
-
-  g_list_free_full (default_order, (GDestroyNotify) g_free);
-
-  g_object_set_data (G_OBJECT (gimp), "gimp-tools-default-order", NULL);
-
   tool_manager_exit (gimp);
 
   gimp_tool_options_manager_exit (gimp);
@@ -254,70 +257,14 @@ gimp_tools_exit (Gimp *gimp)
 void
 gimp_tools_restore (Gimp *gimp)
 {
-  GimpContainer *gimp_list;
-  GimpObject    *object;
-  GFile         *file;
-  GList         *list;
-  GError        *error = NULL;
+  GimpObject *object;
+  GList      *list;
+  GError     *error = NULL;
 
   g_return_if_fail (GIMP_IS_GIMP (gimp));
 
-  gimp_list = g_object_new (GIMP_TYPE_LIST,
-                            "children-type", GIMP_TYPE_TOOL_INFO,
-                            "append",        TRUE,
-                            NULL);
-
-  file = gimp_directory_file ("toolrc", NULL);
-
-  if (gimp->be_verbose)
-    g_print ("Parsing '%s'\n", gimp_file_get_utf8_name (file));
-
-  if (gimp_config_deserialize_gfile (GIMP_CONFIG (gimp_list), file,
-                                     NULL, &error))
-    {
-      gint i = 0;
-
-      for (list = GIMP_LIST (gimp_list)->queue->head;
-           list;
-           list = g_list_next (list))
-        {
-          const gchar *name = gimp_object_get_name (list->data);
-
-          object = gimp_container_get_child_by_name (gimp->tool_info_list,
-                                                     name);
-
-          if (object)
-            {
-              GimpToolItem *tool_item = list->data;
-
-              while (! gimp_container_get_child_by_name (
-                         gimp_list,
-                         gimp_object_get_name (
-                           gimp_container_get_child_by_index (
-                             gimp->tool_info_list, i))))
-                {
-                  i++;
-                }
-
-              g_object_set (object,
-                            "visible", gimp_tool_item_is_visible (tool_item),
-                            NULL);
-
-              gimp_container_reorder (gimp->tool_info_list,
-                                      object, i++);
-            }
-        }
-    }
-  else
-    {
-      if (error->code != G_IO_ERROR_NOT_FOUND)
-        gimp_message_literal (gimp, NULL, GIMP_MESSAGE_WARNING, error->message);
-
-      g_clear_error (&error);
-    }
-
-  g_object_unref (file);
-  g_object_unref (gimp_list);
+  /* restore tool order */
+  gimp_tools_reset (gimp, gimp->tool_item_list, TRUE);
 
   /* make the generic operation tool invisible by default */
   object = gimp_container_get_child_by_name (gimp->tool_info_list,
@@ -395,7 +342,8 @@ gimp_tools_save (Gimp     *gimp,
                  gboolean  save_tool_options,
                  gboolean  always_save)
 {
-  GFile *file;
+  GimpConfigWriter *writer;
+  GFile            *file;
 
   g_return_if_fail (GIMP_IS_GIMP (gimp));
 
@@ -435,11 +383,15 @@ gimp_tools_save (Gimp     *gimp,
   if (gimp->be_verbose)
     g_print ("Writing '%s'\n", gimp_file_get_utf8_name (file));
 
-  gimp_config_serialize_to_gfile (GIMP_CONFIG (gimp->tool_info_list),
-                                  file,
-                                  "GIMP toolrc",
-                                  "end of toolrc",
-                                  NULL, NULL);
+  writer = gimp_config_writer_new_gfile (file, TRUE, "GIMP toolrc", NULL);
+
+  if (writer)
+    {
+      gimp_tools_serialize (gimp, gimp->tool_item_list, writer);
+
+      gimp_config_writer_finish (writer, "end of toolrc", NULL);
+    }
+
   g_object_unref (file);
 }
 
@@ -473,6 +425,214 @@ gimp_tools_clear (Gimp    *gimp,
   return success;
 }
 
+gboolean
+gimp_tools_serialize (Gimp             *gimp,
+                      GimpContainer    *container,
+                      GimpConfigWriter *writer)
+{
+  g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
+  g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
+
+  gimp_config_writer_open (writer, "file-version");
+  gimp_config_writer_printf (writer, "%d", TOOL_RC_FILE_VERSION);
+  gimp_config_writer_close (writer);
+
+  gimp_config_writer_linefeed (writer);
+
+  return gimp_config_serialize (GIMP_CONFIG (container), writer, NULL);
+}
+
+gboolean
+gimp_tools_deserialize (Gimp          *gimp,
+                        GimpContainer *container,
+                        GScanner      *scanner)
+{
+  enum
+  {
+    FILE_VERSION = 1
+  };
+
+  GimpContainer *src_container;
+  GTokenType     token;
+  guint          scope_id;
+  guint          old_scope_id;
+  gint           file_version = 0;
+  gboolean       result       = FALSE;
+
+  scope_id     = g_type_qname (GIMP_TYPE_TOOL_GROUP);
+  old_scope_id = g_scanner_set_scope (scanner, scope_id);
+
+  g_scanner_scope_add_symbol (scanner, scope_id,
+                              "file-version",
+                              GINT_TO_POINTER (FILE_VERSION));
+
+  token = G_TOKEN_LEFT_PAREN;
+
+  while (g_scanner_peek_next_token (scanner) == token &&
+         (token != G_TOKEN_LEFT_PAREN                 ||
+          ! file_version))
+    {
+      token = g_scanner_get_next_token (scanner);
+
+      switch (token)
+        {
+        case G_TOKEN_LEFT_PAREN:
+          token = G_TOKEN_SYMBOL;
+          break;
+
+        case G_TOKEN_SYMBOL:
+          switch (GPOINTER_TO_INT (scanner->value.v_symbol))
+            {
+            case FILE_VERSION:
+              token = G_TOKEN_INT;
+              if (gimp_scanner_parse_int (scanner, &file_version))
+                token = G_TOKEN_RIGHT_PAREN;
+              break;
+            }
+          break;
+
+        case G_TOKEN_RIGHT_PAREN:
+          token = G_TOKEN_LEFT_PAREN;
+          break;
+
+        default:
+          break;
+        }
+    }
+
+  g_scanner_set_scope (scanner, old_scope_id);
+
+  if (token != G_TOKEN_LEFT_PAREN)
+    {
+      g_scanner_get_next_token (scanner);
+      g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
+                             _("fatal parse error"), TRUE);
+
+      return FALSE;
+    }
+  else if (file_version != TOOL_RC_FILE_VERSION)
+    {
+      g_scanner_error (scanner, "wrong toolrc file format version");
+
+      return FALSE;
+    }
+
+  gimp_container_freeze (container);
+
+  g_type_class_unref (g_type_class_ref (GIMP_TYPE_TOOL_GROUP));
+
+  gimp_container_clear (container);
+
+  src_container = g_object_new (GIMP_TYPE_LIST,
+                                "children-type", GIMP_TYPE_TOOL_ITEM,
+                                "append",        TRUE,
+                                NULL);
+
+  if (gimp_config_deserialize (GIMP_CONFIG (src_container),
+                               scanner, 0, NULL))
+    {
+      GHashTable *tools;
+      GList      *list;
+
+      result = TRUE;
+
+      tools = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+      gimp_tools_copy_structure (gimp, src_container, container, tools);
+
+      for (list = gimp_get_tool_info_iter (gimp);
+           list;
+           list = g_list_next (list))
+        {
+          GimpToolInfo *tool_info = list->data;
+
+          if (! tool_info->hidden && ! g_hash_table_contains (tools, tool_info))
+            {
+              g_scanner_error (scanner, "missing tools in toolrc file");
+
+              result = FALSE;
+
+              break;
+            }
+        }
+
+      g_hash_table_unref (tools);
+    }
+
+  g_object_unref (src_container);
+
+  gimp_container_thaw (container);
+
+  return result;
+}
+
+void
+gimp_tools_reset (Gimp          *gimp,
+                  GimpContainer *container,
+                  gboolean       user_toolrc)
+{
+  GList *files = NULL;
+  GList *list;
+
+  g_return_if_fail (GIMP_IS_GIMP (gimp));
+  g_return_if_fail (GIMP_IS_CONTAINER (container));
+
+  if (user_toolrc)
+    files = g_list_prepend (files, gimp_directory_file       ("toolrc", NULL));
+  files = g_list_prepend (files, gimp_sysconf_directory_file ("toolrc", NULL));
+
+  files = g_list_reverse (files);
+
+  gimp_container_freeze (container);
+
+  gimp_container_clear (container);
+
+  for (list = files; list; list = g_list_next (list))
+    {
+      GScanner *scanner;
+      GFile    *file  = list->data;
+      GError   *error = NULL;
+
+      if (gimp->be_verbose)
+        g_print ("Parsing '%s'\n", gimp_file_get_utf8_name (file));
+
+      scanner = gimp_scanner_new_gfile (file, &error);
+
+      if (scanner && gimp_tools_deserialize (gimp, container, scanner))
+        {
+          gimp_scanner_destroy (scanner);
+
+          break;
+        }
+      else
+        {
+          if (error->code != G_IO_ERROR_NOT_FOUND)
+            {
+              gimp_message_literal (gimp, NULL,
+                                    GIMP_MESSAGE_WARNING, error->message);
+            }
+
+          g_clear_error (&error);
+
+          gimp_container_clear (container);
+        }
+
+      g_clear_pointer (&scanner, gimp_scanner_destroy);
+    }
+
+  g_list_free_full (files, g_object_unref);
+
+  if (gimp_container_is_empty (container))
+    {
+      if (gimp->be_verbose)
+        g_print ("Using default tool order\n");
+
+      gimp_tools_copy_structure (gimp, gimp->tool_info_list, container, NULL);
+    }
+
+  gimp_container_thaw (container);
+}
+
 GList *
 gimp_tools_get_default_order (Gimp *gimp)
 {
@@ -582,9 +742,9 @@ gimp_tools_register (GType                   tool_type,
 
   visible = (! g_type_is_a (tool_type, GIMP_TYPE_FILTER_TOOL));
 
-  g_object_set (tool_info, "visible", visible, NULL);
+  gimp_tool_item_set_visible (GIMP_TOOL_ITEM (tool_info), visible);
 
-  /* hack to make the operation tools always invisible */
+  /* hack to hide the operation tool entirely */
   if (tool_type == GIMP_TYPE_OPERATION_TOOL)
     tool_info->hidden = TRUE;
 
@@ -600,3 +760,55 @@ gimp_tools_register (GType                   tool_type,
   if (tool_type == GIMP_TYPE_PAINTBRUSH_TOOL)
     gimp_tool_info_set_standard (gimp, tool_info);
 }
+
+static void
+gimp_tools_copy_structure (Gimp          *gimp,
+                           GimpContainer *src_container,
+                           GimpContainer *dest_container,
+                           GHashTable    *tools)
+{
+  GList *list;
+
+  for (list = GIMP_LIST (src_container)->queue->head;
+       list;
+       list = g_list_next (list))
+    {
+      GimpToolItem *src_tool_item  = list->data;
+      GimpToolItem *dest_tool_item = NULL;
+
+      if (GIMP_IS_TOOL_GROUP (src_tool_item))
+        {
+          dest_tool_item = GIMP_TOOL_ITEM (gimp_tool_group_new ());
+
+          gimp_tools_copy_structure (
+            gimp,
+            gimp_viewable_get_children (GIMP_VIEWABLE (src_tool_item)),
+            gimp_viewable_get_children (GIMP_VIEWABLE (dest_tool_item)),
+            tools);
+
+          gimp_tool_group_set_active_tool (
+            GIMP_TOOL_GROUP (dest_tool_item),
+            gimp_tool_group_get_active_tool (GIMP_TOOL_GROUP (src_tool_item)));
+        }
+      else
+        {
+          dest_tool_item = GIMP_TOOL_ITEM (
+            gimp_get_tool_info (gimp, gimp_object_get_name (src_tool_item)));
+
+          if (dest_tool_item && GIMP_TOOL_INFO (dest_tool_item)->hidden)
+            dest_tool_item = NULL;
+          else if (tools)
+            g_hash_table_add (tools, dest_tool_item);
+        }
+
+      if (dest_tool_item)
+        {
+          gimp_tool_item_set_visible (
+            dest_tool_item,
+            gimp_tool_item_get_visible (src_tool_item));
+
+          gimp_container_add (dest_container,
+                              GIMP_OBJECT (dest_tool_item));
+        }
+    }
+}
diff --git a/app/tools/gimp-tools.h b/app/tools/gimp-tools.h
index 1a54d95cbd..d718b168c5 100644
--- a/app/tools/gimp-tools.h
+++ b/app/tools/gimp-tools.h
@@ -19,18 +19,29 @@
 #define __GIMP_TOOLS_H__
 
 
-void       gimp_tools_init              (Gimp      *gimp);
-void       gimp_tools_exit              (Gimp      *gimp);
+void       gimp_tools_init              (Gimp              *gimp);
+void       gimp_tools_exit              (Gimp              *gimp);
 
-void       gimp_tools_restore           (Gimp      *gimp);
-void       gimp_tools_save              (Gimp      *gimp,
-                                         gboolean   save_tool_options,
-                                         gboolean   always_save);
+void       gimp_tools_restore           (Gimp              *gimp);
+void       gimp_tools_save              (Gimp              *gimp,
+                                         gboolean           save_tool_options,
+                                         gboolean           always_save);
 
-gboolean   gimp_tools_clear             (Gimp      *gimp,
-                                         GError   **error);
+gboolean   gimp_tools_clear             (Gimp              *gimp,
+                                         GError           **error);
 
-GList    * gimp_tools_get_default_order (Gimp      *gimp);
+gboolean   gimp_tools_serialize         (Gimp              *gimp,
+                                         GimpContainer     *container,
+                                         GimpConfigWriter  *writer);
+gboolean   gimp_tools_deserialize       (Gimp              *gimp,
+                                         GimpContainer     *container,
+                                         GScanner          *scanner);
+
+void       gimp_tools_reset             (Gimp              *gimp,
+                                         GimpContainer     *container,
+                                         gboolean           user_toolrc);
+
+GList    * gimp_tools_get_default_order (Gimp              *gimp);
 
 
 #endif  /* __GIMP_TOOLS_H__ */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 29ce971c33..98d594c327 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -416,6 +416,7 @@ app/text/gimptextlayer-xcf.c
 app/text/gimptextlayout.c
 app/text/text-enums.c
 
+app/tools/gimp-tools.c
 app/tools/gimpairbrushtool.c
 app/tools/gimpalignoptions.c
 app/tools/gimpaligntool.c


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