[gthumb/ext: 36/79] started work on scripts support
- From: Paolo Bacchilega <paobac src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gthumb/ext: 36/79] started work on scripts support
- Date: Sun, 2 Aug 2009 20:28:07 +0000 (UTC)
commit c70aeb59cdeab78707aeb8625a73ba6909119469
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun Jul 5 22:43:43 2009 +0200
started work on scripts support
configure.ac | 2 +
extensions/list_tools/Makefile.am | 10 +
extensions/list_tools/actions.c | 5 +-
extensions/list_tools/callbacks.c | 102 ++++-
extensions/list_tools/data/Makefile.am | 2 +
extensions/list_tools/data/ui/Makefile.am | 5 +
.../list_tools/data/ui/personalize-scripts.ui | 173 ++++++
extensions/list_tools/data/ui/script-editor.ui | 341 ++++++++++++
extensions/list_tools/dlg-personalize-scripts.c | 563 ++++++++++++++++++++
extensions/list_tools/dlg-personalize-scripts.h | 30 +
extensions/list_tools/gth-script-editor-dialog.c | 249 +++++++++
extensions/list_tools/gth-script-editor-dialog.h | 61 +++
extensions/list_tools/gth-script-file.c | 409 ++++++++++++++
extensions/list_tools/gth-script-file.h | 72 +++
extensions/list_tools/gth-script.c | 389 ++++++++++++++
extensions/list_tools/gth-script.h | 67 +++
gthumb/gth-browser-ui.h | 4 +-
gthumb/gth-filter-file.c | 4 +-
18 files changed, 2478 insertions(+), 10 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d216eb2..41941c8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -236,6 +236,8 @@ extensions/image_viewer/Makefile
extensions/image_viewer/data/Makefile
extensions/image_viewer/data/ui/Makefile
extensions/list_tools/Makefile
+extensions/list_tools/data/Makefile
+extensions/list_tools/data/ui/Makefile
extensions/search/Makefile
extensions/search/data/Makefile
extensions/search/data/ui/Makefile
diff --git a/extensions/list_tools/Makefile.am b/extensions/list_tools/Makefile.am
index f3520a2..e987e49 100644
--- a/extensions/list_tools/Makefile.am
+++ b/extensions/list_tools/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = data
+
extensiondir = $(libdir)/gthumb-2.0/extensions
extension_LTLIBRARIES = liblist_tools.la
@@ -6,6 +8,14 @@ liblist_tools_la_SOURCES = \
actions.h \
callbacks.c \
callbacks.h \
+ dlg-personalize-scripts.c \
+ dlg-personalize-scripts.h \
+ gth-script.c \
+ gth-script.h \
+ gth-script-editor-dialog.c \
+ gth-script-editor-dialog.h \
+ gth-script-file.c \
+ gth-script-file.h \
main.c
liblist_tools_la_CFLAGS = $(GTHUMB_CFLAGS) $(DISABLE_DEPRECATED) $(WARNINGS) -I$(top_srcdir) -I$(top_builddir)/gthumb
diff --git a/extensions/list_tools/actions.c b/extensions/list_tools/actions.c
index 3973897..f967f3a 100644
--- a/extensions/list_tools/actions.c
+++ b/extensions/list_tools/actions.c
@@ -24,11 +24,12 @@
#include <config.h>
#include <glib/gi18n.h>
#include <gthumb.h>
+#include "dlg-personalize-scripts.h"
void
gth_browser_action_list_tools_edit_scripts (GtkAction *action,
- GthBrowser *browser)
+ GthBrowser *browser)
{
- /* FIXME */
+ dlg_personalize_scripts (browser);
}
diff --git a/extensions/list_tools/callbacks.c b/extensions/list_tools/callbacks.c
index 1593d4e..8b7686d 100644
--- a/extensions/list_tools/callbacks.c
+++ b/extensions/list_tools/callbacks.c
@@ -26,6 +26,7 @@
#include <glib-object.h>
#include <gthumb.h>
#include "actions.h"
+#include "gth-script-file.h"
#define BROWSER_DATA_KEY "list-tools-browser-data"
@@ -35,10 +36,9 @@ static const char *fixed_ui_info =
"<ui>"
" <popup name='ListToolsPopup'>"
" <placeholder name='Tools'/>"
-" <separator/>"
" <placeholder name='Scripts'/>"
-" <separator/>"
-" <menuitem action='ListTools_EditScripts'/>"
+" <separator name='ScriptsListSeparator'/>"
+" <menuitem name='EditScripts' action='ListTools_EditScripts'/>"
" </popup>"
"</ui>";
@@ -52,18 +52,106 @@ static GtkActionEntry action_entries[] = {
typedef struct {
+ GthBrowser *browser;
GtkToolItem *tool_item;
GtkActionGroup *action_group;
+ gulong scripts_changed_id;
} BrowserData;
static void
browser_data_free (BrowserData *data)
{
+ g_signal_handler_disconnect (gth_script_file_get (), data->scripts_changed_id);
g_free (data);
}
+static void
+activate_script_menu_item (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ BrowserData *data = user_data;
+ GthScript *script;
+
+ script = gth_script_file_get_script (gth_script_file_get (), g_object_get_data (G_OBJECT (menuitem), "script_id"));
+ if (script != NULL) {
+ GList *items;
+ GList *file_list;
+ GthTask *task;
+
+ items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (data->browser)));
+ file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (data->browser)), items);
+ task = gth_script_get_task (script, file_list);
+ gth_browser_exec_task (data->browser, task);
+
+ g_object_unref (task);
+ _g_object_list_unref (file_list);
+ _gtk_tree_path_list_free (items);
+ }
+}
+
+
+static void
+update_scripts_menu (BrowserData *data)
+{
+ GtkWidget *separator1;
+ GtkWidget *separator2;
+ GtkWidget *menu;
+ GList *script_list;
+ GList *scan;
+ int pos;
+ gboolean script_present = FALSE;
+
+ separator1 = gtk_ui_manager_get_widget (gth_browser_get_ui_manager (data->browser), "/ListToolsPopup/Tools");
+ separator2 = gtk_ui_manager_get_widget (gth_browser_get_ui_manager (data->browser), "/ListToolsPopup/Scripts");
+ menu = gtk_widget_get_parent (separator1);
+ _gtk_container_remove_children (GTK_CONTAINER (menu), separator1, separator2);
+
+ script_list = gth_script_file_get_scripts (gth_script_file_get ());
+ pos = _gtk_container_get_pos (GTK_CONTAINER (menu), separator2);
+ for (scan = script_list; scan; scan = scan->next) {
+ GthScript *script = scan->data;
+ GtkWidget *menu_item;
+
+ if (! gth_script_is_visible (script))
+ continue;
+
+ menu_item = gtk_image_menu_item_new_with_label (gth_script_get_display_name (script));
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), gtk_image_new_from_stock (GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU));
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menu_item, pos++);
+
+ g_object_set_data_full (G_OBJECT (menu_item),
+ "script_id",
+ g_strdup (gth_script_get_id (script)),
+ (GDestroyNotify) g_free);
+ g_signal_connect (menu_item,
+ "activate",
+ G_CALLBACK (activate_script_menu_item),
+ data);
+
+ script_present = TRUE;
+ }
+
+ separator1 = gtk_ui_manager_get_widget (gth_browser_get_ui_manager (data->browser), "/ListToolsPopup/ScriptsListSeparator");
+ if (script_present)
+ gtk_widget_show (separator1);
+ else
+ gtk_widget_hide (separator1);
+
+ _g_object_list_unref (script_list);
+}
+
+
+static void
+scripts_changed_cb (GthScriptFile *script_file,
+ BrowserData *data)
+{
+ update_scripts_menu (data);
+}
+
+
void
list_tools__gth_browser_construct_cb (GthBrowser *browser)
{
@@ -73,7 +161,7 @@ list_tools__gth_browser_construct_cb (GthBrowser *browser)
g_return_if_fail (GTH_IS_BROWSER (browser));
data = g_new0 (BrowserData, 1);
-
+ data->browser = browser;
data->action_group = gtk_action_group_new ("List Tools Manager Actions");
gtk_action_group_set_translation_domain (data->action_group, NULL);
gtk_action_group_add_actions (data->action_group,
@@ -97,6 +185,12 @@ list_tools__gth_browser_construct_cb (GthBrowser *browser)
gtk_toolbar_insert (GTK_TOOLBAR (gth_browser_get_browser_toolbar (browser)), data->tool_item, -1);
g_object_set_data_full (G_OBJECT (browser), BROWSER_DATA_KEY, data, (GDestroyNotify) browser_data_free);
+
+ update_scripts_menu (data);
+ data->scripts_changed_id = g_signal_connect (gth_script_file_get (),
+ "changed",
+ G_CALLBACK (scripts_changed_cb),
+ data);
}
diff --git a/extensions/list_tools/data/Makefile.am b/extensions/list_tools/data/Makefile.am
new file mode 100644
index 0000000..4d5385d
--- /dev/null
+++ b/extensions/list_tools/data/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = ui
+-include $(top_srcdir)/git.mk
diff --git a/extensions/list_tools/data/ui/Makefile.am b/extensions/list_tools/data/ui/Makefile.am
new file mode 100644
index 0000000..b220c3f
--- /dev/null
+++ b/extensions/list_tools/data/ui/Makefile.am
@@ -0,0 +1,5 @@
+uidir = $(datadir)/gthumb/ui
+ui_DATA = personalize-scripts.ui script-editor.ui
+EXTRA_DIST = $(ui_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/extensions/list_tools/data/ui/personalize-scripts.ui b/extensions/list_tools/data/ui/personalize-scripts.ui
new file mode 100644
index 0000000..3b16fc2
--- /dev/null
+++ b/extensions/list_tools/data/ui/personalize-scripts.ui
@@ -0,0 +1,173 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="personalize_scripts_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Scripts</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="scripts_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Scripts:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scripts_scrolledwindow">
+ <property name="width_request">250</property>
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">etched-in</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVButtonBox" id="vbuttonbox3">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="new_button">
+ <property name="label">gtk-new</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="edit_button">
+ <property name="label">gtk-edit</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="delete_button">
+ <property name="label">gtk-remove</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="close_button">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help_button">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">close_button</action-widget>
+ <action-widget response="0">help_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/extensions/list_tools/data/ui/script-editor.ui b/extensions/list_tools/data/ui/script-editor.ui
new file mode 100644
index 0000000..6d47730
--- /dev/null
+++ b/extensions/list_tools/data/ui/script-editor.ui
@@ -0,0 +1,341 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkVBox" id="script_editor">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">name_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">_Command:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">name_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="name_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="command_entry">
+ <property name="width_request">400</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="secondary_icon_stock">gtk-help</property>
+ <property name="secondary_icon_activatable">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="secondary_icon_tooltip_text">Help</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="wait_command_checkbutton">
+ <property name="label" translatable="yes">_Wait for the command to finish</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="for_each_file_checkbutton">
+ <property name="label" translatable="yes">E_xecute the command a file at a time</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="command_help_box">
+ <child>
+ <object class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="n_rows">7</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">%U</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">%F</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">%B</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">%P</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">The file uri</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">The file path</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">The file basename</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">The parent folder path</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Special code</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Description</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="Translate only 'message' and 'default_value', keeping the underscore if possible.">%ask{ message }{ default_value }</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Ask an input value</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="Translate only 'property_name', keeping the underscore if possible.">%prop{ property_name }</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">A file property</property>
+ <attributes>
+ <attribute name="size" value="8000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/extensions/list_tools/dlg-personalize-scripts.c b/extensions/list_tools/dlg-personalize-scripts.c
new file mode 100644
index 0000000..192b5ea
--- /dev/null
+++ b/extensions/list_tools/dlg-personalize-scripts.c
@@ -0,0 +1,563 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include "dlg-personalize-scripts.h"
+#include "gth-script.h"
+#include "gth-script-editor-dialog.h"
+#include "gth-script-file.h"
+
+
+#define GET_WIDGET(name) _gtk_builder_get_widget (data->builder, (name))
+#define ORDER_CHANGED_DELAY 250
+
+
+enum {
+ COLUMN_SCRIPT,
+ COLUMN_NAME,
+ COLUMN_VISIBLE,
+ NUM_COLUMNS
+};
+
+
+typedef struct {
+ GthBrowser *browser;
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ GtkWidget *list_view;
+ GtkListStore *list_store;
+ gulong scripts_changed_id;
+ guint list_changed_id;
+} DialogData;
+
+
+static void
+destroy_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ if (data->list_changed_id != 0)
+ g_source_remove (data->list_changed_id);
+ data->list_changed_id = 0;
+
+ gth_browser_set_dialog (data->browser, "personalize_scripts", NULL);
+ g_signal_handler_disconnect (gth_script_file_get (), data->scripts_changed_id);
+
+ g_object_unref (data->builder);
+ g_free (data);
+}
+
+
+static gboolean
+list_view_row_order_changed_cb (gpointer user_data)
+{
+ DialogData *data = user_data;
+ GtkTreeModel *model = GTK_TREE_MODEL (data->list_store);
+ GtkTreeIter iter;
+
+ if (data->list_changed_id != 0)
+ g_source_remove (data->list_changed_id);
+ data->list_changed_id = 0;
+
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ GthScriptFile *script_file;
+
+ script_file = gth_script_file_get ();
+ gth_script_file_clear (script_file);
+
+ do {
+ GthScript *script;
+
+ gtk_tree_model_get (model, &iter, COLUMN_SCRIPT, &script, -1);
+ gth_script_file_add (script_file, script);
+
+ g_object_unref (script);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+
+ gth_script_file_save (script_file, NULL);
+ }
+
+ return FALSE;
+}
+
+
+static void
+row_deleted_cb (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+
+ if (data->list_changed_id != 0)
+ g_source_remove (data->list_changed_id);
+ data->list_changed_id = g_timeout_add (ORDER_CHANGED_DELAY, list_view_row_order_changed_cb, data);
+}
+
+
+static void
+row_inserted_cb (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+
+ if (data->list_changed_id != 0)
+ g_source_remove (data->list_changed_id);
+ data->list_changed_id = g_timeout_add (ORDER_CHANGED_DELAY, list_view_row_order_changed_cb, data);
+}
+
+
+static void
+set_script_list (DialogData *data,
+ GList *script_list)
+{
+ GList *scan;
+
+ g_signal_handlers_block_by_func (data->list_store, row_inserted_cb, data);
+
+ for (scan = script_list; scan; scan = scan->next) {
+ GthScript *script = scan->data;
+ GtkTreeIter iter;
+
+ gtk_list_store_append (data->list_store, &iter);
+ gtk_list_store_set (data->list_store, &iter,
+ COLUMN_SCRIPT, script,
+ COLUMN_NAME, gth_script_get_display_name (script),
+ COLUMN_VISIBLE, gth_script_is_visible (script),
+ -1);
+ }
+
+ g_signal_handlers_unblock_by_func (data->list_store, row_inserted_cb, data);
+}
+
+
+static void
+update_script_list (DialogData *data)
+{
+ GthScriptFile *script_file;
+ GList *script_list;
+
+ g_signal_handlers_block_by_func (data->list_store, row_deleted_cb, data);
+ gtk_list_store_clear (data->list_store);
+ g_signal_handlers_unblock_by_func (data->list_store, row_deleted_cb, data);
+
+ script_file = gth_script_file_get ();
+ script_list = gth_script_file_get_scripts (script_file);
+ set_script_list (data, script_list);
+
+ _g_object_list_unref (script_list);
+}
+
+
+static void
+scripts_changed_cb (GthScriptFile *script_file,
+ DialogData *data)
+{
+ update_script_list (data);
+}
+
+
+static void
+cell_renderer_toggle_toggled_cb (GtkCellRendererToggle *cell_renderer,
+ char *path,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ GtkTreePath *tpath;
+ GtkTreeIter iter;
+ gboolean visible;
+
+ tpath = gtk_tree_path_new_from_string (path);
+ if (tpath == NULL)
+ return;
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (data->list_store), &iter, tpath)) {
+ GthScript *script;
+ GthScriptFile *script_file;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (data->list_store), &iter,
+ COLUMN_SCRIPT, &script,
+ COLUMN_VISIBLE, &visible,
+ -1);
+ visible = ! visible;
+ g_object_set (script, "visible", visible, NULL);
+
+ script_file = gth_script_file_get ();
+ g_signal_handlers_block_by_func (script_file, scripts_changed_cb, data);
+ gth_script_file_add (script_file, script);
+ gth_script_file_save (script_file, NULL);
+ g_signal_handlers_unblock_by_func (script_file, scripts_changed_cb, data);
+
+ gtk_list_store_set (data->list_store, &iter,
+ COLUMN_VISIBLE, visible,
+ -1);
+
+ g_object_unref (script);
+ }
+
+ gtk_tree_path_free (tpath);
+}
+
+
+static void
+add_columns (GtkTreeView *treeview,
+ DialogData *data)
+{
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ /* the name column. */
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Script"));
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "text", COLUMN_NAME,
+ NULL);
+
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+ /* the checkbox column */
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Show"));
+
+ renderer = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (renderer,
+ "toggled",
+ G_CALLBACK (cell_renderer_toggle_toggled_cb),
+ data);
+
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "active", COLUMN_VISIBLE,
+ NULL);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+}
+
+
+static gboolean
+get_script_iter (DialogData *data,
+ GthScript *script,
+ GtkTreeIter *iter)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (data->list_store);
+ gboolean found = FALSE;
+ const char *script_id;
+
+ script_id = gth_script_get_id (script);
+ if (! gtk_tree_model_get_iter_first (model, iter))
+ return FALSE;
+
+ do {
+ GthScript *list_script;
+
+ gtk_tree_model_get (model, iter, COLUMN_SCRIPT, &list_script, -1);
+ found = g_strcmp0 (script_id, gth_script_get_id (list_script)) == 0;
+
+ g_object_unref (list_script);
+ }
+ while (! found && gtk_tree_model_iter_next (model, iter));
+
+ return found;
+}
+
+
+static void
+script_editor_dialog__response_cb (GtkDialog *dialog,
+ int response,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ GthScript *script;
+ GError *error = NULL;
+ GthScriptFile *script_file;
+ gboolean new_script;
+ GtkTreeIter iter;
+ gboolean change_list = TRUE;
+
+
+ if (response == GTK_RESPONSE_HELP) {
+ /* FIXME */
+ return;
+ }
+
+ if (response != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ return;
+ }
+
+ script = gth_script_editor_dialog_get_script (GTH_SCRIPT_EDITOR_DIALOG (dialog), &error);
+ if (script == NULL) {
+ _gtk_error_dialog_from_gerror_show (GTK_WINDOW (dialog), _("Could not save the script"), &error);
+ return;
+ }
+
+ /* update the script file */
+
+ script_file = gth_script_file_get ();
+ new_script = ! gth_script_file_has_script (script_file, script);
+
+ g_signal_handlers_block_by_func (script_file, scripts_changed_cb, data);
+ gth_script_file_add (script_file, script);
+ gth_script_file_save (script_file, NULL); /* FIXME: handle errors */
+ g_signal_handlers_unblock_by_func (script_file, scripts_changed_cb, data);
+
+ /* update the script list */
+
+ if (new_script) {
+ g_signal_handlers_block_by_func (data->list_store, row_inserted_cb, data);
+ gtk_list_store_append (data->list_store, &iter);
+ g_signal_handlers_unblock_by_func (data->list_store, row_inserted_cb, data);
+ }
+ else
+ change_list = get_script_iter (data, script, &iter);
+
+ if (change_list)
+ gtk_list_store_set (data->list_store, &iter,
+ COLUMN_SCRIPT, script,
+ COLUMN_NAME, gth_script_get_display_name (script),
+ COLUMN_VISIBLE, gth_script_is_visible (script),
+ -1);
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+
+ g_object_unref (script);
+}
+
+
+static void
+new_script_cb (GtkButton *button,
+ DialogData *data)
+{
+ GtkWidget *dialog;
+
+ dialog = gth_script_editor_dialog_new (_("New Script"), GTK_WINDOW (data->dialog));
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (script_editor_dialog__response_cb),
+ data);
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+
+static void
+edit_script_cb (GtkButton *button,
+ DialogData *data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model = GTK_TREE_MODEL (data->list_store);
+ GtkTreeIter iter;
+ GthScript *script;
+ GtkWidget *dialog;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->list_view));
+ if (! gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, COLUMN_SCRIPT, &script, -1);
+ if (script == NULL)
+ return;
+
+ dialog = gth_script_editor_dialog_new (_("Edit Script"), GTK_WINDOW (data->dialog));
+ gth_script_editor_dialog_set_script (GTH_SCRIPT_EDITOR_DIALOG (dialog), script);
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (script_editor_dialog__response_cb),
+ data);
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ gtk_window_present (GTK_WINDOW (dialog));
+
+ g_object_unref (script);
+}
+
+
+static void
+delete_script_cb (GtkButton *button,
+ DialogData *data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model = GTK_TREE_MODEL (data->list_store);
+ GtkTreeIter iter;
+ GthScript *script;
+ GthScriptFile *script_file;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->list_view));
+ if (! gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, COLUMN_SCRIPT, &script, -1);
+ if (script == NULL)
+ return;
+
+ /* update the script file */
+
+ script_file = gth_script_file_get ();
+ g_signal_handlers_block_by_func (script_file, scripts_changed_cb, data);
+ gth_script_file_remove (script_file, script);
+ gth_script_file_save (script_file, NULL);
+ g_signal_handlers_unblock_by_func (script_file, scripts_changed_cb, data);
+
+ /* update the script list */
+
+ g_signal_handlers_block_by_func (data->list_store, row_deleted_cb, data);
+ gtk_list_store_remove (data->list_store, &iter);
+ g_signal_handlers_unblock_by_func (data->list_store, row_deleted_cb, data);
+
+ g_object_unref (script);
+}
+
+
+static void
+update_sensitivity (DialogData *data)
+{
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ gboolean script_selected;
+
+ model = GTK_TREE_MODEL (data->list_store);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->list_view));
+ script_selected = gtk_tree_selection_get_selected (selection, &model, &iter);
+
+ gtk_widget_set_sensitive (GET_WIDGET ("edit_button"), script_selected);
+ gtk_widget_set_sensitive (GET_WIDGET ("delete_button"), script_selected);
+}
+
+
+static void
+list_view_selection_changed_cb (GtkTreeSelection *treeselection,
+ gpointer user_data)
+{
+ update_sensitivity ((DialogData *) user_data);
+}
+
+
+static void
+list_view_row_activated_cb (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer user_data)
+{
+ edit_script_cb (NULL, user_data);
+}
+
+
+void
+dlg_personalize_scripts (GthBrowser *browser)
+{
+ DialogData *data;
+
+ if (gth_browser_get_dialog (browser, "personalize_scripts") != NULL) {
+ gtk_window_present (GTK_WINDOW (gth_browser_get_dialog (browser, "personalize_scripts")));
+ return;
+ }
+
+ data = g_new0 (DialogData, 1);
+ data->browser = browser;
+ data->builder = _gtk_builder_new_from_file ("personalize-scripts.ui", "list_tools");
+
+ /* Get the widgets. */
+
+ data->dialog = _gtk_builder_get_widget (data->builder, "personalize_scripts_dialog");
+ gth_browser_set_dialog (browser, "personalize_scripts", data->dialog);
+ g_object_set_data (G_OBJECT (data->dialog), "dialog_data", data);
+
+ /**/
+
+ data->list_store = gtk_list_store_new (NUM_COLUMNS,
+ G_TYPE_OBJECT,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN);
+ data->list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (data->list_store));
+ g_object_unref (data->list_store);
+ gtk_tree_view_set_reorderable (GTK_TREE_VIEW (data->list_view), TRUE);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (data->list_view), TRUE);
+
+ add_columns (GTK_TREE_VIEW (data->list_view), data);
+
+ gtk_widget_show (data->list_view);
+ gtk_container_add (GTK_CONTAINER (GET_WIDGET ("scripts_scrolledwindow")), data->list_view);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (GET_WIDGET ("scripts_label")), data->list_view);
+ gtk_label_set_use_underline (GTK_LABEL (GET_WIDGET ("scripts_label")), TRUE);
+
+ update_script_list (data);
+ update_sensitivity (data);
+
+ /* Set the signals handlers. */
+
+ g_signal_connect (G_OBJECT (data->dialog),
+ "destroy",
+ G_CALLBACK (destroy_cb),
+ data);
+ g_signal_connect_swapped (G_OBJECT (GET_WIDGET ("close_button")),
+ "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ G_OBJECT (data->dialog));
+ g_signal_connect (G_OBJECT (GET_WIDGET ("new_button")),
+ "clicked",
+ G_CALLBACK (new_script_cb),
+ data);
+ g_signal_connect (G_OBJECT (GET_WIDGET ("edit_button")),
+ "clicked",
+ G_CALLBACK (edit_script_cb),
+ data);
+ g_signal_connect (G_OBJECT (GET_WIDGET ("delete_button")),
+ "clicked",
+ G_CALLBACK (delete_script_cb),
+ data);
+ g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->list_view)),
+ "changed",
+ G_CALLBACK (list_view_selection_changed_cb),
+ data);
+ g_signal_connect (GTK_TREE_VIEW (data->list_view),
+ "row-activated",
+ G_CALLBACK (list_view_row_activated_cb),
+ data);
+ g_signal_connect (data->list_store,
+ "row-deleted",
+ G_CALLBACK (row_deleted_cb),
+ data);
+ g_signal_connect (data->list_store,
+ "row-inserted",
+ G_CALLBACK (row_inserted_cb),
+ data);
+
+ data->scripts_changed_id = g_signal_connect (gth_script_file_get (),
+ "changed",
+ G_CALLBACK (scripts_changed_cb),
+ data);
+
+ /* run dialog. */
+
+ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (browser));
+ gtk_window_set_modal (GTK_WINDOW (data->dialog), FALSE);
+ gtk_widget_show (data->dialog);
+}
diff --git a/extensions/list_tools/dlg-personalize-scripts.h b/extensions/list_tools/dlg-personalize-scripts.h
new file mode 100644
index 0000000..e2fa889
--- /dev/null
+++ b/extensions/list_tools/dlg-personalize-scripts.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef DLG_PERSONALIZE_SCRIPTS_H
+#define DLG_PERSONALIZE_SCRIPTS_H
+
+#include <gthumb.h>
+
+void dlg_personalize_scripts (GthBrowser *browser);
+
+#endif /* DLG_PERSONALIZE_SCRIPTS_H */
diff --git a/extensions/list_tools/gth-script-editor-dialog.c b/extensions/list_tools/gth-script-editor-dialog.c
new file mode 100644
index 0000000..ca80738
--- /dev/null
+++ b/extensions/list_tools/gth-script-editor-dialog.c
@@ -0,0 +1,249 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include "gth-script-editor-dialog.h"
+
+
+#define GET_WIDGET(name) _gtk_builder_get_widget (self->priv->builder, (name))
+
+
+static gpointer parent_class = NULL;
+
+
+struct _GthScriptEditorDialogPrivate {
+ GtkBuilder *builder;
+ char *script_id;
+ gboolean script_visible;
+ gboolean wait_command;
+ gboolean for_each_file;
+ gboolean help_visible;
+};
+
+
+static void
+gth_script_editor_dialog_finalize (GObject *object)
+{
+ GthScriptEditorDialog *dialog;
+
+ dialog = GTH_SCRIPT_EDITOR_DIALOG (object);
+
+ if (dialog->priv != NULL) {
+ g_object_unref (dialog->priv->builder);
+ g_free (dialog->priv->script_id);
+ g_free (dialog->priv);
+ dialog->priv = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_script_editor_dialog_class_init (GthScriptEditorDialogClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ object_class = (GObjectClass*) class;
+
+ object_class->finalize = gth_script_editor_dialog_finalize;
+}
+
+
+static void
+gth_script_editor_dialog_init (GthScriptEditorDialog *dialog)
+{
+ dialog->priv = g_new0 (GthScriptEditorDialogPrivate, 1);
+ dialog->priv->help_visible = FALSE;
+}
+
+
+GType
+gth_script_editor_dialog_get_type (void)
+{
+ static GType type = 0;
+
+ if (! type) {
+ GTypeInfo type_info = {
+ sizeof (GthScriptEditorDialogClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gth_script_editor_dialog_class_init,
+ NULL,
+ NULL,
+ sizeof (GthScriptEditorDialog),
+ 0,
+ (GInstanceInitFunc) gth_script_editor_dialog_init
+ };
+
+ type = g_type_register_static (GTK_TYPE_DIALOG,
+ "GthScriptEditorDialog",
+ &type_info,
+ 0);
+ }
+
+ return type;
+}
+
+
+static void
+update_sensitivity (GthScriptEditorDialog *self)
+{
+ /* FIXME */
+}
+
+
+static void
+command_entry_icon_press_cb (GtkEntry *entry,
+ GtkEntryIconPosition icon_pos,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ GthScriptEditorDialog *self = user_data;
+
+ self->priv->help_visible = ! self->priv->help_visible;
+
+ if (self->priv->help_visible)
+ gtk_widget_show (GET_WIDGET("command_help_box"));
+ else
+ gtk_widget_hide (GET_WIDGET("command_help_box"));
+}
+
+
+static void
+gth_script_editor_dialog_construct (GthScriptEditorDialog *self,
+ const char *title,
+ GtkWindow *parent)
+{
+ GtkWidget *content;
+
+ if (title != NULL)
+ gtk_window_set_title (GTK_WINDOW (self), title);
+ if (parent != NULL)
+ gtk_window_set_transient_for (GTK_WINDOW (self), parent);
+ gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
+ gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (self)->vbox), 5);
+ gtk_container_set_border_width (GTK_CONTAINER (self), 5);
+
+ gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_SAVE, GTK_RESPONSE_OK);
+ gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_HELP, GTK_RESPONSE_HELP);
+
+ self->priv->builder = _gtk_builder_new_from_file ("script-editor.ui", "list_tools");
+
+ content = _gtk_builder_get_widget (self->priv->builder, "script_editor");
+ gtk_container_set_border_width (GTK_CONTAINER (content), 5);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (self)->vbox), content, TRUE, TRUE, 0);
+
+ g_signal_connect (GET_WIDGET ("command_entry"),
+ "icon-press",
+ G_CALLBACK (command_entry_icon_press_cb),
+ self);
+
+ /**/
+
+ gth_script_editor_dialog_set_script (self, NULL);
+}
+
+
+GtkWidget *
+gth_script_editor_dialog_new (const char *title,
+ GtkWindow *parent)
+{
+ GthScriptEditorDialog *self;
+
+ self = g_object_new (GTH_TYPE_SCRIPT_EDITOR_DIALOG, NULL);
+ gth_script_editor_dialog_construct (self, title, parent);
+
+ return (GtkWidget *) self;
+}
+
+
+static void
+_gth_script_editor_dialog_set_new_script (GthScriptEditorDialog *self)
+{
+ gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("name_entry")), "");
+ gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("command_entry")), "");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("for_each_file_checkbutton")), FALSE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("wait_command_checkbutton")), FALSE);
+}
+
+
+void
+gth_script_editor_dialog_set_script (GthScriptEditorDialog *self,
+ GthScript *script)
+{
+ g_free (self->priv->script_id);
+ self->priv->script_id = NULL;
+ self->priv->script_visible = TRUE;
+
+ _gth_script_editor_dialog_set_new_script (self);
+
+ if (script != NULL) {
+ self->priv->script_id = g_strdup (gth_script_get_id (script));
+ self->priv->script_visible = gth_script_is_visible (script);
+
+ gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("name_entry")), gth_script_get_display_name (script));
+ gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("command_entry")), gth_script_get_command (script));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("for_each_file_checkbutton")), gth_script_for_each_file (script));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("wait_command_checkbutton")), gth_script_wait_command (script));
+ }
+
+ update_sensitivity (self);
+}
+
+
+GthScript *
+gth_script_editor_dialog_get_script (GthScriptEditorDialog *self,
+ GError **error)
+{
+ GthScript *script;
+
+ script = gth_script_new ();
+ if (self->priv->script_id != NULL)
+ g_object_set (script, "id", self->priv->script_id, NULL);
+ g_object_set (script,
+ "display-name", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("name_entry"))),
+ "command", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("command_entry"))),
+ "visible", self->priv->script_visible,
+ "for-each-file", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("for_each_file_checkbutton"))),
+ "wait-command", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("wait_command_checkbutton"))),
+ NULL);
+
+ if (g_strcmp0 (gth_script_get_display_name (script), "") == 0) {
+ *error = g_error_new (GTHUMB_ERROR, 0, _("No name specified"));
+ g_object_unref (script);
+ return NULL;
+ }
+
+ if (g_strcmp0 (gth_script_get_command (script), "") == 0) {
+ *error = g_error_new (GTHUMB_ERROR, 0, _("No command specified"));
+ g_object_unref (script);
+ return NULL;
+ }
+
+ return script;
+}
diff --git a/extensions/list_tools/gth-script-editor-dialog.h b/extensions/list_tools/gth-script-editor-dialog.h
new file mode 100644
index 0000000..86929d3
--- /dev/null
+++ b/extensions/list_tools/gth-script-editor-dialog.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_SCRIPT_EDITOR_DIALOG_H
+#define GTH_SCRIPT_EDITOR_DIALOG_H
+
+#include <gtk/gtk.h>
+#include "gth-script.h"
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_SCRIPT_EDITOR_DIALOG (gth_script_editor_dialog_get_type ())
+#define GTH_SCRIPT_EDITOR_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_SCRIPT_EDITOR_DIALOG, GthScriptEditorDialog))
+#define GTH_SCRIPT_EDITOR_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_SCRIPT_EDITOR_DIALOG, GthScriptEditorDialogClass))
+#define GTH_IS_SCRIPT_EDITOR_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_SCRIPT_EDITOR_DIALOG))
+#define GTH_IS_SCRIPT_EDITOR_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_SCRIPT_EDITOR_DIALOG))
+#define GTH_SCRIPT_EDITOR_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTH_TYPE_SCRIPT_EDITOR_DIALOG, GthScriptEditorDialogClass))
+
+typedef struct _GthScriptEditorDialog GthScriptEditorDialog;
+typedef struct _GthScriptEditorDialogClass GthScriptEditorDialogClass;
+typedef struct _GthScriptEditorDialogPrivate GthScriptEditorDialogPrivate;
+
+struct _GthScriptEditorDialog {
+ GtkDialog parent_instance;
+ GthScriptEditorDialogPrivate *priv;
+};
+
+struct _GthScriptEditorDialogClass {
+ GtkDialogClass parent_class;
+};
+
+GType gth_script_editor_dialog_get_type (void);
+GtkWidget * gth_script_editor_dialog_new (const char *title,
+ GtkWindow *parent);
+void gth_script_editor_dialog_set_script (GthScriptEditorDialog *self,
+ GthScript *script);
+GthScript * gth_script_editor_dialog_get_script (GthScriptEditorDialog *self,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* GTH_SCRIPT_EDITOR_DIALOG_H */
diff --git a/extensions/list_tools/gth-script-file.c b/extensions/list_tools/gth-script-file.c
new file mode 100644
index 0000000..c4f7534
--- /dev/null
+++ b/extensions/list_tools/gth-script-file.c
@@ -0,0 +1,409 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <gthumb.h>
+#include "gth-script.h"
+#include "gth-script-file.h"
+
+
+#define SCRIPT_FORMAT "1.0"
+
+
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+
+struct _GthScriptFilePrivate
+{
+ gboolean loaded;
+ GList *items;
+};
+
+
+static gpointer parent_class = NULL;
+static guint gth_script_file_signals[LAST_SIGNAL] = { 0 };
+
+static GType gth_script_file_get_type (void);
+
+
+static void
+gth_script_file_finalize (GObject *object)
+{
+ GthScriptFile *self;
+
+ self = GTH_SCRIPT_FILE (object);
+
+ _g_object_list_unref (self->priv->items);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_script_file_class_init (GthScriptFileClass *klass)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GthScriptFilePrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->finalize = gth_script_file_finalize;
+
+ gth_script_file_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GthScriptFileClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+
+static void
+gth_script_file_init (GthScriptFile *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_SCRIPT_FILE, GthScriptFilePrivate);
+ self->priv->items = NULL;
+ self->priv->loaded = FALSE;
+}
+
+
+static GType
+gth_script_file_get_type (void)
+{
+ static GType type = 0;
+
+ if (! type) {
+ GTypeInfo type_info = {
+ sizeof (GthScriptFileClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gth_script_file_class_init,
+ NULL,
+ NULL,
+ sizeof (GthScriptFile),
+ 0,
+ (GInstanceInitFunc) gth_script_file_init
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "GthScriptFile",
+ &type_info,
+ 0);
+ }
+
+ return type;
+}
+
+
+GthScriptFile *
+gth_script_file_get (void)
+{
+ static GthScriptFile *script_file = NULL;
+
+ if (script_file == NULL)
+ script_file = g_object_new (GTH_TYPE_SCRIPT_FILE, NULL);
+
+ return script_file;
+}
+
+
+static gboolean
+gth_script_file_load_from_data (GthScriptFile *self,
+ const char *data,
+ gsize length,
+ GError **error)
+{
+ DomDocument *doc;
+ gboolean success;
+
+ doc = dom_document_new ();
+ success = dom_document_load (doc, data, length, error);
+ if (success) {
+ DomElement *scripts_node;
+ DomElement *child;
+ GList *new_items = NULL;
+
+ scripts_node = DOM_ELEMENT (doc)->first_child;
+ if ((scripts_node != NULL) && (g_strcmp0 (scripts_node->tag_name, "scripts") == 0)) {
+ for (child = scripts_node->first_child;
+ child != NULL;
+ child = child->next_sibling)
+ {
+ GthScript *script = NULL;
+
+ if (strcmp (child->tag_name, "script") == 0) {
+ script = gth_script_new ();
+ dom_domizable_load_from_element (DOM_DOMIZABLE (script), child);
+ }
+
+ if (script == NULL)
+ continue;
+
+ new_items = g_list_prepend (new_items, script);
+ }
+
+ new_items = g_list_reverse (new_items);
+ self->priv->items = g_list_concat (self->priv->items, new_items);
+ }
+ }
+ g_object_unref (doc);
+
+ return success;
+}
+
+
+static gboolean
+gth_script_file_load_from_file (GthScriptFile *self,
+ const char *filename,
+ GError **error)
+{
+ char *buffer;
+ gsize len;
+ GError *read_error;
+ gboolean retval;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ read_error = NULL;
+ g_file_get_contents (filename, &buffer, &len, &read_error);
+ if (read_error != NULL) {
+ g_propagate_error (error, read_error);
+ return FALSE;
+ }
+
+ read_error = NULL;
+ retval = gth_script_file_load_from_data (self,
+ buffer,
+ len,
+ &read_error);
+ if (read_error != NULL) {
+ g_propagate_error (error, read_error);
+ g_free (buffer);
+ return FALSE;
+ }
+
+ g_free (buffer);
+
+ return retval;
+}
+
+
+static void
+_gth_script_file_load_if_needed (GthScriptFile *self)
+{
+ char *default_script_file;
+
+ if (self->priv->loaded)
+ return;
+
+ default_script_file = gth_user_dir_get_file (GTH_DIR_CONFIG, GTHUMB_DIR, "scripts.xml", NULL);
+ gth_script_file_load_from_file (self, default_script_file, NULL);
+ self->priv->loaded = TRUE;
+
+ g_free (default_script_file);
+}
+
+
+static char *
+gth_script_file_to_data (GthScriptFile *self,
+ gsize *len,
+ GError **data_error)
+{
+ DomDocument *doc;
+ DomElement *root;
+ char *data;
+ GList *scan;
+
+ doc = dom_document_new ();
+ root = dom_document_create_element (doc, "scripts",
+ "version", SCRIPT_FORMAT,
+ NULL);
+ dom_element_append_child (DOM_ELEMENT (doc), root);
+ for (scan = self->priv->items; scan; scan = scan->next)
+ dom_element_append_child (root, dom_domizable_create_element (DOM_DOMIZABLE (scan->data), doc));
+ data = dom_document_dump (doc, len);
+
+ g_object_unref (doc);
+
+ return data;
+}
+
+
+static gboolean
+gth_script_file_to_file (GthScriptFile *self,
+ const char *filename,
+ GError **error)
+{
+ char *data;
+ GError *data_error, *write_error;
+ gsize len;
+ gboolean retval;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ data_error = NULL;
+ data = gth_script_file_to_data (self, &len, &data_error);
+ if (data_error) {
+ g_propagate_error (error, data_error);
+ return FALSE;
+ }
+
+ write_error = NULL;
+ g_file_set_contents (filename, data, len, &write_error);
+ if (write_error) {
+ g_propagate_error (error, write_error);
+ retval = FALSE;
+ }
+ else
+ retval = TRUE;
+
+ g_free (data);
+
+ return retval;
+}
+
+
+GthScript *
+gth_script_file_get_script (GthScriptFile *self,
+ const char *id)
+{
+ GList *scan;
+
+ for (scan = self->priv->items; scan; scan = scan->next) {
+ GthScript *script = scan->data;
+
+ if (g_strcmp0 (gth_script_get_id (script), id) == 0)
+ return script;
+ }
+
+ return NULL;
+}
+
+
+gboolean
+gth_script_file_save (GthScriptFile *self,
+ GError **error)
+{
+ char *default_script_file;
+ gboolean result;
+
+ _gth_script_file_load_if_needed (self);
+
+ default_script_file = gth_user_dir_get_file (GTH_DIR_CONFIG, GTHUMB_DIR, "scripts.xml", NULL);
+ result = gth_script_file_to_file (self, default_script_file, error);
+ if (result)
+ g_signal_emit (G_OBJECT (self), gth_script_file_signals[CHANGED], 0);
+
+ g_free (default_script_file);
+
+ return result;
+}
+
+
+GList *
+gth_script_file_get_scripts (GthScriptFile *self)
+{
+ GList *list;
+ GList *scan;
+
+ _gth_script_file_load_if_needed (self);
+
+ list = NULL;
+ for (scan = self->priv->items; scan; scan = scan->next)
+ list = g_list_prepend (list, gth_duplicable_duplicate (GTH_DUPLICABLE (scan->data)));
+
+ return g_list_reverse (list);
+}
+
+
+static int
+find_by_id (gconstpointer a,
+ gconstpointer b)
+{
+ GthScript *script = (GthScript *) a;
+ GthScript *script_to_find = (GthScript *) b;
+
+ return g_strcmp0 (gth_script_get_id (script), gth_script_get_id (script_to_find));
+}
+
+
+gboolean
+gth_script_file_has_script (GthScriptFile *self,
+ GthScript *script)
+{
+ return g_list_find_custom (self->priv->items, script, find_by_id) != NULL;
+}
+
+
+void
+gth_script_file_add (GthScriptFile *self,
+ GthScript *script)
+{
+ GList *link;
+
+ _gth_script_file_load_if_needed (self);
+
+ g_object_ref (script);
+
+ link = g_list_find_custom (self->priv->items, script, find_by_id);
+ if (link != NULL) {
+ g_object_unref (link->data);
+ link->data = script;
+ }
+ else
+ self->priv->items = g_list_append (self->priv->items, script);
+}
+
+
+void
+gth_script_file_remove (GthScriptFile *self,
+ GthScript *script)
+{
+ GList *link;
+
+ _gth_script_file_load_if_needed (self);
+
+ link = g_list_find_custom (self->priv->items, script, find_by_id);
+ if (link == NULL)
+ return;
+ self->priv->items = g_list_remove_link (self->priv->items, link);
+
+ _g_object_list_unref (link);
+}
+
+
+void
+gth_script_file_clear (GthScriptFile *self)
+{
+ _g_object_list_unref (self->priv->items);
+ self->priv->items = NULL;
+}
diff --git a/extensions/list_tools/gth-script-file.h b/extensions/list_tools/gth-script-file.h
new file mode 100644
index 0000000..f4790c7
--- /dev/null
+++ b/extensions/list_tools/gth-script-file.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_SCRIPT_FILE_H
+#define GTH_SCRIPT_FILE_H
+
+#include <glib.h>
+#include "gth-script.h"
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_SCRIPT_FILE (gth_script_file_get_type ())
+#define GTH_SCRIPT_FILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_SCRIPT_FILE, GthScriptFile))
+#define GTH_SCRIPT_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_SCRIPT_FILE, GthScriptFileClass))
+#define GTH_IS_SCRIPT_FILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_SCRIPT_FILE))
+#define GTH_IS_SCRIPT_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_SCRIPT_FILE))
+#define GTH_SCRIPT_FILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_SCRIPT_FILE, GthScriptFileClass))
+
+typedef struct _GthScriptFile GthScriptFile;
+typedef struct _GthScriptFilePrivate GthScriptFilePrivate;
+typedef struct _GthScriptFileClass GthScriptFileClass;
+
+
+struct _GthScriptFile
+{
+ GObject __parent;
+ GthScriptFilePrivate *priv;
+};
+
+struct _GthScriptFileClass
+{
+ GObjectClass __parent_class;
+
+ void (*changed) (GthScriptFile *self);
+};
+
+GthScriptFile * gth_script_file_get (void);
+GthScript * gth_script_file_get_script (GthScriptFile *self,
+ const char *id);
+gboolean gth_script_file_save (GthScriptFile *self,
+ GError **error);
+GList * gth_script_file_get_scripts (GthScriptFile *self);
+gboolean gth_script_file_has_script (GthScriptFile *self,
+ GthScript *script);
+void gth_script_file_add (GthScriptFile *self,
+ GthScript *script);
+void gth_script_file_remove (GthScriptFile *self,
+ GthScript *script);
+void gth_script_file_clear (GthScriptFile *self);
+
+G_END_DECLS
+
+#endif /* GTH_SCRIPT_FILE_H */
diff --git a/extensions/list_tools/gth-script.c b/extensions/list_tools/gth-script.c
new file mode 100644
index 0000000..5585727
--- /dev/null
+++ b/extensions/list_tools/gth-script.c
@@ -0,0 +1,389 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <gthumb.h>
+#include "gth-script.h"
+
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_DISPLAY_NAME,
+ PROP_COMMAND,
+ PROP_VISIBLE,
+ PROP_FOR_EACH_FILE,
+ PROP_WAIT_COMMAND
+};
+
+
+struct _GthScriptPrivate {
+ char *id;
+ char *display_name;
+ char *command;
+ gboolean visible;
+ gboolean for_each_file;
+ gboolean wait_command;
+};
+
+
+static gpointer *parent_class = NULL;
+
+
+static DomElement*
+gth_script_real_create_element (DomDomizable *base,
+ DomDocument *doc)
+{
+ GthScript *self;
+ DomElement *element;
+
+ g_return_val_if_fail (DOM_IS_DOCUMENT (doc), NULL);
+
+ self = GTH_SCRIPT (base);
+ element = dom_document_create_element (doc, "script",
+ "id", self->priv->id,
+ "display-name", self->priv->display_name,
+ "command", self->priv->command,
+ "for-each-file", self->priv->for_each_file ? "true" : "false",
+ "wait-command", self->priv->wait_command ? "true" : "false",
+ NULL);
+ if (! self->priv->visible)
+ dom_element_set_attribute (element, "display", "none");
+
+ return element;
+}
+
+
+static void
+gth_script_real_load_from_element (DomDomizable *base,
+ DomElement *element)
+{
+ GthScript *self;
+
+ g_return_if_fail (DOM_IS_ELEMENT (element));
+
+ self = GTH_SCRIPT (base);
+ g_object_set (self,
+ "id", dom_element_get_attribute (element, "id"),
+ "display-name", dom_element_get_attribute (element, "display-name"),
+ "command", dom_element_get_attribute (element, "command"),
+ "visible", (g_strcmp0 (dom_element_get_attribute (element, "display"), "none") != 0),
+ "for-each-file", (g_strcmp0 (dom_element_get_attribute (element, "for-each-file"), "true") == 0),
+ "wait-command", (g_strcmp0 (dom_element_get_attribute (element, "wait-command"), "true") == 0),
+ NULL);
+}
+
+
+GObject *
+gth_script_real_duplicate (GthDuplicable *duplicable)
+{
+ GthScript *script = GTH_SCRIPT (duplicable);
+ GthScript *new_script;
+
+ new_script = gth_script_new ();
+ g_object_set (new_script,
+ "id", script->priv->id,
+ "display-name", script->priv->display_name,
+ "command", script->priv->command,
+ "visible", script->priv->visible,
+ "for-each-file", script->priv->for_each_file,
+ "wait-command", script->priv->wait_command,
+ NULL);
+
+ return (GObject *) new_script;
+}
+
+
+static void
+gth_script_finalize (GObject *base)
+{
+ GthScript *self;
+
+ self = GTH_SCRIPT (base);
+
+ g_free (self->priv->id);
+ g_free (self->priv->display_name);
+ g_free (self->priv->command);
+
+ G_OBJECT_CLASS (parent_class)->finalize (base);
+}
+
+
+static void
+gth_script_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GthScript *self;
+
+ self = GTH_SCRIPT (object);
+
+ switch (property_id) {
+ case PROP_ID:
+ g_free (self->priv->id);
+ self->priv->id = g_value_dup_string (value);
+ if (self->priv->id == NULL)
+ self->priv->id = g_strdup ("");
+ break;
+ case PROP_DISPLAY_NAME:
+ g_free (self->priv->display_name);
+ self->priv->display_name = g_value_dup_string (value);
+ if (self->priv->display_name == NULL)
+ self->priv->display_name = g_strdup ("");
+ break;
+ case PROP_COMMAND:
+ g_free (self->priv->command);
+ self->priv->command = g_value_dup_string (value);
+ if (self->priv->command == NULL)
+ self->priv->command = g_strdup ("");
+ break;
+ case PROP_VISIBLE:
+ self->priv->visible = g_value_get_boolean (value);
+ break;
+ case PROP_FOR_EACH_FILE:
+ self->priv->for_each_file = g_value_get_boolean (value);
+ break;
+ case PROP_WAIT_COMMAND:
+ self->priv->wait_command = g_value_get_boolean (value);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void
+gth_script_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GthScript *self;
+
+ self = GTH_SCRIPT (object);
+
+ switch (property_id) {
+ case PROP_ID:
+ g_value_set_string (value, self->priv->id);
+ break;
+ case PROP_DISPLAY_NAME:
+ g_value_set_string (value, self->priv->display_name);
+ break;
+ case PROP_COMMAND:
+ g_value_set_string (value, self->priv->command);
+ break;
+ case PROP_VISIBLE:
+ g_value_set_boolean (value, self->priv->visible);
+ break;
+ case PROP_FOR_EACH_FILE:
+ g_value_set_boolean (value, self->priv->for_each_file);
+ break;
+ case PROP_WAIT_COMMAND:
+ g_value_set_boolean (value, self->priv->wait_command);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+static void
+gth_script_class_init (GthScriptClass *klass)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GthScriptPrivate));
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->set_property = gth_script_set_property;
+ object_class->get_property = gth_script_get_property;
+ object_class->finalize = gth_script_finalize;
+
+ /* properties */
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_string ("id",
+ "ID",
+ "The object id",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_NAME,
+ g_param_spec_string ("display-name",
+ "Display name",
+ "The user visible name",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_COMMAND,
+ g_param_spec_string ("command",
+ "Command",
+ "The command to execute",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_VISIBLE,
+ g_param_spec_boolean ("visible",
+ "Visible",
+ "Whether this script should be visible in the script list",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_FOR_EACH_FILE,
+ g_param_spec_boolean ("for-each-file",
+ "Each File",
+ "Whether to execute the command on file at a time",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_WAIT_COMMAND,
+ g_param_spec_boolean ("wait-command",
+ "Wait command",
+ "Whether to wait command to finish",
+ FALSE,
+ G_PARAM_READWRITE));
+}
+
+
+static void
+gth_script_dom_domizable_interface_init (DomDomizableIface *iface)
+{
+ iface->create_element = gth_script_real_create_element;
+ iface->load_from_element = gth_script_real_load_from_element;
+}
+
+
+static void
+gth_script_gth_duplicable_interface_init (GthDuplicableIface *iface)
+{
+ iface->duplicate = gth_script_real_duplicate;
+}
+
+
+static void
+gth_script_init (GthScript *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_SCRIPT, GthScriptPrivate);
+ self->priv->id = NULL;
+ self->priv->display_name = NULL;
+ self->priv->command = NULL;
+}
+
+
+GType
+gth_script_get_type (void)
+{
+ static GType type = 0;
+
+ if (! type) {
+ GTypeInfo type_info = {
+ sizeof (GthScriptClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gth_script_class_init,
+ NULL,
+ NULL,
+ sizeof (GthScript),
+ 0,
+ (GInstanceInitFunc) gth_script_init
+ };
+ static const GInterfaceInfo dom_domizable_info = {
+ (GInterfaceInitFunc) gth_script_dom_domizable_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ static const GInterfaceInfo gth_duplicable_info = {
+ (GInterfaceInitFunc) gth_script_gth_duplicable_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "GthScript",
+ &type_info,
+ 0);
+ g_type_add_interface_static (type, DOM_TYPE_DOMIZABLE, &dom_domizable_info);
+ g_type_add_interface_static (type, GTH_TYPE_DUPLICABLE, >h_duplicable_info);
+ }
+
+ return type;
+}
+
+
+GthScript*
+gth_script_new (void)
+{
+ GthScript *script;
+ char *id;
+
+ id = _g_rand_string (ID_LENGTH);
+ script = (GthScript *) g_object_new (GTH_TYPE_SCRIPT, "id", id, NULL);
+ g_free (id);
+
+ return script;
+}
+
+
+const char *
+gth_script_get_id (GthScript *script)
+{
+ return script->priv->id;
+}
+
+
+const char *
+gth_script_get_display_name (GthScript *script)
+{
+ return script->priv->display_name;
+}
+
+
+const char *
+gth_script_get_command (GthScript *script)
+{
+ return script->priv->command;
+}
+
+
+gboolean
+gth_script_is_visible (GthScript *script)
+{
+ return script->priv->visible;
+}
+
+
+gboolean
+gth_script_for_each_file (GthScript *script)
+{
+ return script->priv->for_each_file;
+}
+
+
+gboolean
+gth_script_wait_command (GthScript *script)
+{
+ return script->priv->wait_command;
+}
diff --git a/extensions/list_tools/gth-script.h b/extensions/list_tools/gth-script.h
new file mode 100644
index 0000000..b812207
--- /dev/null
+++ b/extensions/list_tools/gth-script.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_SCRIPT_H
+#define GTH_SCRIPT_H
+
+#include <glib-object.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_SCRIPT (gth_script_get_type ())
+#define GTH_SCRIPT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_SCRIPT, GthScript))
+#define GTH_SCRIPT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_SCRIPT, GthScriptClass))
+#define GTH_IS_SCRIPT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_SCRIPT))
+#define GTH_IS_SCRIPT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_SCRIPT))
+#define GTH_SCRIPT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_SCRIPT, GthScriptClass))
+
+typedef struct _GthScript GthScript;
+typedef struct _GthScriptPrivate GthScriptPrivate;
+typedef struct _GthScriptClass GthScriptClass;
+
+
+struct _GthScript
+{
+ GObject __parent;
+ GthScriptPrivate *priv;
+};
+
+struct _GthScriptClass
+{
+ GObjectClass __parent_class;
+};
+
+GType gth_script_get_type (void) G_GNUC_CONST;
+GthScript * gth_script_new (void);
+const char * gth_script_get_id (GthScript *script);
+const char * gth_script_get_display_name (GthScript *script);
+const char * gth_script_get_command (GthScript *script);
+gboolean gth_script_is_visible (GthScript *script);
+gboolean gth_script_for_each_file (GthScript *script);
+gboolean gth_script_wait_command (GthScript *script);
+GthTask * gth_script_get_task (GthScript *script,
+ GList *file_list /* GthFileData */);
+
+G_END_DECLS
+
+#endif /* GTH_SCRIPT_H */
diff --git a/gthumb/gth-browser-ui.h b/gthumb/gth-browser-ui.h
index fdbfe51..06a095d 100644
--- a/gthumb/gth-browser-ui.h
+++ b/gthumb/gth-browser-ui.h
@@ -114,10 +114,10 @@ static const char *fixed_ui_info =
" <separator/>"
" <toolitem action='View_Prev'/>"
" <toolitem action='View_Next'/>"
-" <separator/>"
+/*" <separator/>"
" <toolitem action='Edit_Metadata'/>"
" <separator/>"
-" <toolitem action='View_Fullscreen'/>"
+" <toolitem action='View_Fullscreen'/>"*/
" <separator/>"
" <placeholder name='ViewerCommands'/>"
" <separator expand='true'/>"
diff --git a/gthumb/gth-filter-file.c b/gthumb/gth-filter-file.c
index 799dd33..e761c2d 100644
--- a/gthumb/gth-filter-file.c
+++ b/gthumb/gth-filter-file.c
@@ -211,10 +211,10 @@ gth_filter_file_get_tests (GthFilterFile *filters)
{
GList *list = NULL;
GList *scan;
-
+
for (scan = filters->items; scan; scan = scan->next)
list = g_list_prepend (list, gth_duplicable_duplicate (GTH_DUPLICABLE (scan->data)));
-
+
return g_list_reverse (list);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]