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.
This commit is contained in:
Ell 2020-01-29 21:02:00 +02:00
parent a63bf32310
commit cd2adfbede
5 changed files with 343 additions and 99 deletions

View File

@ -269,6 +269,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);
@ -398,6 +405,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);
@ -915,6 +924,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)
{

View File

@ -111,6 +111,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;
@ -187,6 +189,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);

View File

@ -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,6 +91,11 @@
#include "gimpvectortool.h"
#include "gimpwarptool.h"
#include "gimp-intl.h"
#define TOOL_RC_FILE_VERSION 1
/* local function prototypes */
@ -106,6 +113,10 @@ static void gimp_tools_register (GType tool_type,
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;
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_file (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,6 +342,7 @@ gimp_tools_save (Gimp *gimp,
gboolean save_tool_options,
gboolean always_save)
{
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_file (GIMP_CONFIG (gimp->tool_info_list),
file,
"GIMP toolrc",
"end of toolrc",
NULL, NULL);
writer = gimp_config_writer_new_from_file (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_file (file, &error);
if (scanner && gimp_tools_deserialize (gimp, container, scanner))
{
gimp_scanner_unref (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_unref);
}
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));
}
}
}

View File

@ -30,6 +30,17 @@ void gimp_tools_save (Gimp *gimp,
gboolean gimp_tools_clear (Gimp *gimp,
GError **error);
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);

View File

@ -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