[gthumb/ext: 55/79] Implemented the rename series command



commit 38d437ac2bf8d13e0d2851db231cb5d30dbfac50
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sun Jul 19 18:35:09 2009 +0200

    Implemented the rename series command

 configure.ac                                       |    3 +
 data/ui/overwrite-dialog.ui                        |  342 +++++++++++++
 extensions/Makefile.am                             |    2 +-
 extensions/file_manager/actions.c                  |   11 +-
 extensions/file_manager/actions.h                  |    1 -
 extensions/file_manager/callbacks.c                |    6 -
 extensions/list_tools/actions.c                    |    4 +-
 extensions/list_tools/actions.h                    |    2 +-
 extensions/list_tools/callbacks.c                  |    2 +-
 extensions/list_tools/gth-script-editor-dialog.c   |    4 +-
 extensions/list_tools/gth-script.c                 |   14 +-
 extensions/rename_series/Makefile.am               |   36 ++
 extensions/rename_series/actions.c                 |   43 ++
 extensions/rename_series/actions.h                 |   32 ++
 extensions/rename_series/callbacks.c               |  163 +++++++
 extensions/rename_series/callbacks.h               |   35 ++
 extensions/rename_series/data/Makefile.am          |    2 +
 extensions/rename_series/data/ui/Makefile.am       |    5 +
 extensions/rename_series/data/ui/rename-series.ui  |  514 ++++++++++++++++++++
 extensions/rename_series/dlg-rename-series.c       |  491 +++++++++++++++++++
 extensions/rename_series/dlg-rename-series.h       |   31 ++
 extensions/rename_series/gth-rename-task.c         |  308 ++++++++++++
 extensions/rename_series/gth-rename-task.h         |   57 +++
 extensions/rename_series/main.c                    |   56 +++
 .../rename_series/rename_series.extension.in.in    |   10 +
 extensions/search/gth-search-editor-dialog.c       |    4 +-
 gthumb/Makefile.am                                 |    2 +
 gthumb/dlg-extensions.c                            |   33 +-
 gthumb/gio-utils.c                                 |   61 +++-
 gthumb/gio-utils.h                                 |    7 +
 gthumb/gth-browser.c                               |   13 +-
 gthumb/gth-browser.h                               |    1 +
 gthumb/gth-edit-metadata-dialog.c                  |  102 ++--
 gthumb/gth-filter-editor-dialog.c                  |   42 +-
 gthumb/gth-overwrite-dialog.c                      |  288 +++++++++++
 gthumb/gth-overwrite-dialog.h                      |   69 +++
 gthumb/gth-progress-dialog.c                       |    4 +-
 gthumb/gtk-utils.c                                 |   34 +-
 38 files changed, 2694 insertions(+), 140 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 41941c8..6ff9387 100644
--- a/configure.ac
+++ b/configure.ac
@@ -238,6 +238,9 @@ extensions/image_viewer/data/ui/Makefile
 extensions/list_tools/Makefile
 extensions/list_tools/data/Makefile
 extensions/list_tools/data/ui/Makefile
+extensions/rename_series/Makefile
+extensions/rename_series/data/Makefile
+extensions/rename_series/data/ui/Makefile
 extensions/search/Makefile
 extensions/search/data/Makefile
 extensions/search/data/ui/Makefile
diff --git a/data/ui/overwrite-dialog.ui b/data/ui/overwrite-dialog.ui
new file mode 100644
index 0000000..0bdb162
--- /dev/null
+++ b/data/ui/overwrite-dialog.ui
@@ -0,0 +1,342 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkVBox" id="overwrite_dialog_box">
+    <property name="visible">True</property>
+    <property name="border_width">6</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">6</property>
+    <child>
+      <object class="GtkLabel" id="label124">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Overwrite the old file with the new one?</property>
+        <property name="justify">center</property>
+        <attributes>
+          <attribute name="weight" value="bold"/>
+        </attributes>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="padding">5</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="hbox46">
+        <property name="visible">True</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkVBox" id="vbox57">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkFrame" id="frame2">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <child>
+                  <object class="GtkHBox" id="hbox110">
+                    <property name="visible">True</property>
+                    <property name="border_width">6</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkFrame" id="old_image_frame">
+                        <property name="width_request">256</property>
+                        <property name="height_request">256</property>
+                        <property name="visible">True</property>
+                        <property name="label_xalign">0</property>
+                        <property name="shadow_type">none</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label137">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Old File:</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkTable" id="table15">
+                <property name="visible">True</property>
+                <property name="n_rows">3</property>
+                <property name="column_spacing">12</property>
+                <property name="row_spacing">6</property>
+                <child>
+                  <object class="GtkLabel" id="old_image_size_label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="old_image_time_label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEventBox" id="old_image_filename_eventbox">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="old_image_filename_label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="wrap">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox58">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkFrame" id="frame3">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <child>
+                  <object class="GtkHBox" id="hbox111">
+                    <property name="visible">True</property>
+                    <property name="border_width">6</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkFrame" id="new_image_frame">
+                        <property name="width_request">256</property>
+                        <property name="height_request">256</property>
+                        <property name="visible">True</property>
+                        <property name="label_xalign">0</property>
+                        <property name="shadow_type">none</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label138">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">New File:</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkTable" id="table16">
+                <property name="visible">True</property>
+                <property name="n_rows">3</property>
+                <property name="column_spacing">12</property>
+                <property name="row_spacing">6</property>
+                <child>
+                  <object class="GtkLabel" id="new_image_size_label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="new_image_time_label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEventBox" id="new_image_filename_eventbox">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="new_image_filename_label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="wrap">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</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="padding">5</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHSeparator" id="hseparator1">
+        <property name="visible">True</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="position">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkRadioButton" id="overwrite_yes_radiobutton">
+        <property name="label" translatable="yes">Over_write the old file</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="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkRadioButton" id="overwrite_no_radiobutton">
+        <property name="label" translatable="yes">Do not overwrite _the old file</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>
+        <property name="group">overwrite_yes_radiobutton</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">4</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkRadioButton" id="overwrite_all_radiobutton">
+        <property name="label" translatable="yes">Overwrite _all files</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>
+        <property name="group">overwrite_yes_radiobutton</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">5</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkRadioButton" id="overwrite_none_radiobutton">
+        <property name="label" translatable="yes">_Do not overwrite any file</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>
+        <property name="group">overwrite_yes_radiobutton</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">6</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="hbox112">
+        <property name="visible">True</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkRadioButton" id="overwrite_rename_radiobutton">
+            <property name="label" translatable="yes">_Save the new file as:</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>
+            <property name="group">overwrite_yes_radiobutton</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="overwrite_rename_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">&#x25CF;</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="position">7</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index 25caf25..96d3bab 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = catalogs comments exiv2 file_manager file_tools file_viewer image_viewer list_tools search
+SUBDIRS = catalogs comments exiv2 file_manager file_tools file_viewer image_viewer list_tools rename_series search
 
 -include $(top_srcdir)/git.mk
diff --git a/extensions/file_manager/actions.c b/extensions/file_manager/actions.c
index 2cfd948..10bce2b 100644
--- a/extensions/file_manager/actions.c
+++ b/extensions/file_manager/actions.c
@@ -333,7 +333,7 @@ gth_browser_activate_action_edit_paste (GtkAction  *action,
 
 	paste_data = g_new0 (PasteData, 1);
 	paste_data->browser = g_object_ref (browser);
-	paste_data->destination = g_object_ref (gth_browser_get_location (browser));
+	paste_data->destination = g_object_ref (gth_browser_get_location_data (browser));
 
 	gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (browser), GDK_SELECTION_CLIPBOARD),
 					GNOME_COPIED_FILES,
@@ -361,13 +361,6 @@ gth_browser_activate_action_edit_duplicate (GtkAction  *action,
 }
 
 
-void
-gth_browser_activate_action_edit_rename (GtkAction  *action,
-					 GthBrowser *browser)
-{
-}
-
-
 static void
 delete_file_permanently (GtkWindow *window,
 			 GList     *file_list)
@@ -513,7 +506,7 @@ gth_browser_activate_action_folder_open_in_file_manager (GtkAction  *action,
                             gtk_get_current_event_time (),
                             &error))
 	{
-		_gtk_error_dialog_from_gerror_run (GTK_WINDOW (browser), _("Could not open location"), &error);
+		_gtk_error_dialog_from_gerror_run (GTK_WINDOW (browser), _("Could not open the location"), &error);
 	}
 
 	g_free (uri);
diff --git a/extensions/file_manager/actions.h b/extensions/file_manager/actions.h
index efff79e..fefde72 100644
--- a/extensions/file_manager/actions.h
+++ b/extensions/file_manager/actions.h
@@ -33,7 +33,6 @@ DEFINE_ACTION(gth_browser_activate_action_edit_cut_files)
 DEFINE_ACTION(gth_browser_activate_action_edit_copy_files)
 DEFINE_ACTION(gth_browser_activate_action_edit_paste)
 DEFINE_ACTION(gth_browser_activate_action_edit_duplicate)
-DEFINE_ACTION(gth_browser_activate_action_edit_rename)
 DEFINE_ACTION(gth_browser_activate_action_edit_trash)
 DEFINE_ACTION(gth_browser_activate_action_edit_delete)
 DEFINE_ACTION(gth_browser_activate_action_folder_open_in_file_manager)
diff --git a/extensions/file_manager/callbacks.c b/extensions/file_manager/callbacks.c
index 5e7a0bb..fffdccd 100644
--- a/extensions/file_manager/callbacks.c
+++ b/extensions/file_manager/callbacks.c
@@ -37,7 +37,6 @@ static const char *vfs_ui_info =
 "    <menu name='Edit' action='EditMenu'>"
 "      <placeholder name='Folder_Actions'>"
 "        <menuitem action='Edit_Duplicate'/>"
-"        <menuitem action='Edit_Rename'/>"
 "        <separator/>"
 "        <menuitem action='Edit_Trash'/>"
 "        <menuitem action='Edit_Delete'/>"
@@ -140,10 +139,6 @@ static GtkActionEntry action_entries[] = {
 	  N_("D_uplicate"), "<control><shift>D",
 	  N_("Duplicate the selected files"),
 	  G_CALLBACK (gth_browser_activate_action_edit_duplicate) },
-	{ "Edit_Rename", NULL,
-	  N_("_Rename"), "F2",
-	  N_("Rename the selected files"),
-	  G_CALLBACK (gth_browser_activate_action_edit_rename) },
 	{ "Edit_Trash", "user-trash",
 	  N_("Mo_ve to Trash"), "Delete",
 	  N_("Move the selected files to the Trash"),
@@ -425,7 +420,6 @@ fm__gth_browser_update_sensitivity_cb (GthBrowser *browser)
 	set_action_sensitive (data, "Edit_Trash", sensitive);
 	set_action_sensitive (data, "Edit_Delete", sensitive);
 	set_action_sensitive (data, "Edit_Duplicate", sensitive);
-	set_action_sensitive (data, "Edit_Rename", sensitive);
 
 	folder = gth_folder_tree_get_selected (GTH_FOLDER_TREE (gth_browser_get_folder_tree (browser)));
 	set_action_sensitive (data, "Folder_Create", (folder != NULL) && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE));
diff --git a/extensions/list_tools/actions.c b/extensions/list_tools/actions.c
index f967f3a..16128bc 100644
--- a/extensions/list_tools/actions.c
+++ b/extensions/list_tools/actions.c
@@ -28,8 +28,8 @@
 
 
 void
-gth_browser_action_list_tools_edit_scripts (GtkAction  *action,
-					    GthBrowser *browser)
+gth_browser_action_edit_scripts (GtkAction  *action,
+				 GthBrowser *browser)
 {
 	dlg_personalize_scripts (browser);
 }
diff --git a/extensions/list_tools/actions.h b/extensions/list_tools/actions.h
index e082239..aa55847 100644
--- a/extensions/list_tools/actions.h
+++ b/extensions/list_tools/actions.h
@@ -27,6 +27,6 @@
 
 #define DEFINE_ACTION(x) void x (GtkAction *action, gpointer data);
 
-DEFINE_ACTION(gth_browser_action_list_tools_edit_scripts)
+DEFINE_ACTION(gth_browser_action_edit_scripts)
 
 #endif /* ACTIONS_H */
diff --git a/extensions/list_tools/callbacks.c b/extensions/list_tools/callbacks.c
index 91286e1..8d3eea4 100644
--- a/extensions/list_tools/callbacks.c
+++ b/extensions/list_tools/callbacks.c
@@ -63,7 +63,7 @@ static GtkActionEntry action_entries[] = {
 	{ "ListTools_EditScripts", GTK_STOCK_EDIT,
 	  N_("Personalize..."), NULL,
 	  NULL,
-	  G_CALLBACK (gth_browser_action_list_tools_edit_scripts) }
+	  G_CALLBACK (gth_browser_action_edit_scripts) }
 };
 
 
diff --git a/extensions/list_tools/gth-script-editor-dialog.c b/extensions/list_tools/gth-script-editor-dialog.c
index 0374ca4..ab6eb1c 100644
--- a/extensions/list_tools/gth-script-editor-dialog.c
+++ b/extensions/list_tools/gth-script-editor-dialog.c
@@ -146,7 +146,7 @@ gth_script_editor_dialog_construct (GthScriptEditorDialog *self,
     		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_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 5);
 	gtk_container_set_border_width (GTK_CONTAINER (self), 5);
 
 	gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
@@ -157,7 +157,7 @@ gth_script_editor_dialog_construct (GthScriptEditorDialog *self,
 
     	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);
+  	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), content, TRUE, TRUE, 0);
 
   	g_signal_connect (GET_WIDGET ("command_entry"),
   			  "icon-press",
diff --git a/extensions/list_tools/gth-script.c b/extensions/list_tools/gth-script.c
index d9258e9..ecb0443 100644
--- a/extensions/list_tools/gth-script.c
+++ b/extensions/list_tools/gth-script.c
@@ -423,7 +423,7 @@ gth_script_get_requested_attributes (GthScript *script)
 	char    **b;
 	char     *attributes;
 
-	re = g_regex_new ("%prop\\{([^}]+)\\}", 0, 0, NULL);
+	re = g_regex_new ("%attr\\{([^}]+)\\}", 0, 0, NULL);
 	a = g_regex_split (re, script->priv->command, 0);
 	for (i = 0, n = 0; a[i] != NULL; i++)
 		if ((i > 0) && (i % 2 == 0))
@@ -663,12 +663,16 @@ create_attribute_list (GList    *file_list,
 	GString   *s;
 	GList     *scan;
 
-	re = g_regex_new ("%prop\\{([^}]+)\\}", 0, 0, NULL);
+	re = g_regex_new ("%attr\\{([^}]+)\\}", 0, 0, NULL);
 	a = g_regex_split (re, match, 0);
 	if (g_strv_length (a) >= 2)
 		attribute = g_strstrip (a[1]);
-	if (attribute == NULL)
+
+	if (attribute == NULL) {
+		g_strfreev (a);
+		g_regex_unref (re);
 		return NULL;
+	}
 
 	s = g_string_new ("");
 	for (scan = file_list; scan; scan = scan->next) {
@@ -715,8 +719,8 @@ command_line_eval_cb (const GMatchInfo *info,
 		      gpointer          data)
 {
 	ReplaceData *replace_data = data;
+	char        *r = NULL;
 	char        *match;
-	char        *r;
 
 	match = g_match_info_fetch (info, 0);
 	if (strcmp (match, "%U") == 0)
@@ -731,7 +735,7 @@ command_line_eval_cb (const GMatchInfo *info,
 		r = create_file_list (replace_data->file_list, get_ext_func, replace_data->quote_values);
 	else if (strcmp (match, "%P") == 0)
 		r = create_file_list (replace_data->file_list, get_parent_func, replace_data->quote_values);
-	else if (strncmp (match, "%prop", 5) == 0) {
+	else if (strncmp (match, "%attr", 5) == 0) {
 		r = create_attribute_list (replace_data->file_list, match, replace_data->quote_values);
 		if (r == NULL)
 			*replace_data->error = g_error_new_literal (GTH_TASK_ERROR, GTH_TASK_ERROR_FAILED, _("Malformed command"));
diff --git a/extensions/rename_series/Makefile.am b/extensions/rename_series/Makefile.am
new file mode 100644
index 0000000..20230fe
--- /dev/null
+++ b/extensions/rename_series/Makefile.am
@@ -0,0 +1,36 @@
+SUBDIRS = data
+
+extensiondir = $(libdir)/gthumb-2.0/extensions
+extension_LTLIBRARIES = librename_series.la
+
+librename_series_la_SOURCES = 		\
+	actions.c			\
+	actions.h			\
+	callbacks.c			\
+	callbacks.h			\
+	dlg-rename-series.c		\
+	dlg-rename-series.h		\
+	gth-rename-task.c		\
+	gth-rename-task.h		\
+	main.c
+
+librename_series_la_CFLAGS = $(GTHUMB_CFLAGS) $(DISABLE_DEPRECATED) $(WARNINGS) -I$(top_srcdir) -I$(top_builddir)/gthumb 
+librename_series_la_LDFLAGS = $(EXTENSION_LIBTOOL_FLAGS)
+librename_series_la_LIBADD = $(GTHUMB_LIBS)
+librename_series_la_DEPENDENCIES = $(top_builddir)/gthumb/gthumb$(EXEEXT)
+
+extensioninidir = $(extensiondir)
+extensionini_in_files = rename_series.extension.in.in
+extensionini_DATA = $(extensionini_in_files:.extension.in.in=.extension)
+
+%.extension.in: %.extension.in.in $(extension_LTLIBRARIES)
+	sed -e "s|%LIBRARY%|`. ./$(extension_LTLIBRARIES) && echo $$dlname`|" \
+	$< > $@
+
+%.extension: %.extension.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+
+EXTRA_DIST = $(extensionini_in_files) 
+
+DISTCLEANFILES = $(extensionini_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/extensions/rename_series/actions.c b/extensions/rename_series/actions.c
new file mode 100644
index 0000000..bc5b8e3
--- /dev/null
+++ b/extensions/rename_series/actions.c
@@ -0,0 +1,43 @@
+/* -*- 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 <glib/gi18n.h>
+#include <gthumb.h>
+#include "dlg-rename-series.h"
+
+
+void
+gth_browser_activate_action_edit_rename (GtkAction  *action,
+					 GthBrowser *browser)
+{
+	GList *items;
+	GList *file_list;
+
+	items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
+	file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items);
+	dlg_rename_series (browser, file_list);
+
+	_g_object_list_unref (file_list);
+	_gtk_tree_path_list_free (items);
+}
diff --git a/extensions/rename_series/actions.h b/extensions/rename_series/actions.h
new file mode 100644
index 0000000..7688d82
--- /dev/null
+++ b/extensions/rename_series/actions.h
@@ -0,0 +1,32 @@
+/* -*- 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 ACTIONS_H
+#define ACTIONS_H
+
+#include <gtk/gtk.h>
+
+#define DEFINE_ACTION(x) void x (GtkAction *action, gpointer data);
+
+DEFINE_ACTION(gth_browser_activate_action_edit_rename)
+
+#endif /* ACTIONS_H */
diff --git a/extensions/rename_series/callbacks.c b/extensions/rename_series/callbacks.c
new file mode 100644
index 0000000..46cb978
--- /dev/null
+++ b/extensions/rename_series/callbacks.c
@@ -0,0 +1,163 @@
+/* -*- 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 <glib/gi18n.h>
+#include <glib-object.h>
+#include <gthumb.h>
+#include "actions.h"
+
+
+#define BROWSER_DATA_KEY "rename-series-browser-data"
+
+
+static const char *vfs_ui_info =
+"<ui>"
+"  <menubar name='MenuBar'>"
+"    <menu name='Edit' action='EditMenu'>"
+"      <placeholder name='Folder_Actions'>"
+"        <menuitem action='Edit_Rename'/>"
+"      </placeholder>"
+"    </menu>"
+"  </menubar>"
+"</ui>";
+
+
+static GtkActionEntry action_entries[] = {
+	{ "Edit_Rename", NULL,
+	  N_("_Rename"), "F2",
+	  N_("Rename the selected files"),
+	  G_CALLBACK (gth_browser_activate_action_edit_rename) },
+};
+
+
+typedef struct {
+	GtkActionGroup *action_group;
+	guint           vfs_merge_id;
+} BrowserData;
+
+
+static void
+browser_data_free (BrowserData *data)
+{
+	g_free (data);
+}
+
+
+static void
+set_action_sensitive (BrowserData *data,
+		      const char  *action_name,
+		      gboolean     sensitive)
+{
+	GtkAction *action;
+
+	action = gtk_action_group_get_action (data->action_group, action_name);
+	g_object_set (action, "sensitive", sensitive, NULL);
+}
+
+
+void
+rs__gth_browser_construct_cb (GthBrowser *browser)
+{
+	BrowserData *data;
+
+	g_return_if_fail (GTH_IS_BROWSER (browser));
+
+	data = g_new0 (BrowserData, 1);
+
+	data->action_group = gtk_action_group_new ("Rename Actions");
+	gtk_action_group_set_translation_domain (data->action_group, NULL);
+	gtk_action_group_add_actions (data->action_group,
+				      action_entries,
+				      G_N_ELEMENTS (action_entries),
+				      browser);
+	gtk_ui_manager_insert_action_group (gth_browser_get_ui_manager (browser), data->action_group, 0);
+
+	g_object_set_data_full (G_OBJECT (browser), BROWSER_DATA_KEY, data, (GDestroyNotify) browser_data_free);
+}
+
+
+static void
+file_manager_update_ui (BrowserData *data,
+			GthBrowser  *browser)
+{
+	if (GTH_IS_FILE_SOURCE_VFS (gth_browser_get_location_source (browser))) {
+		if (data->vfs_merge_id == 0) {
+			GError *local_error = NULL;
+
+			data->vfs_merge_id = gtk_ui_manager_add_ui_from_string (gth_browser_get_ui_manager (browser), vfs_ui_info, -1, &local_error);
+			if (data->vfs_merge_id == 0) {
+				g_warning ("building ui failed: %s", local_error->message);
+				g_error_free (local_error);
+			}
+		}
+	}
+	else if (data->vfs_merge_id != 0) {
+			gtk_ui_manager_remove_ui (gth_browser_get_ui_manager (browser), data->vfs_merge_id);
+			data->vfs_merge_id = 0;
+	}
+}
+
+
+void
+rs__gth_browser_set_current_page_cb (GthBrowser *browser)
+{
+	BrowserData *data;
+
+	data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
+	file_manager_update_ui (data, browser);
+}
+
+
+void
+rs__gth_browser_load_location_after_cb (GthBrowser   *browser,
+					GFile        *location,
+					const GError *error)
+{
+	BrowserData *data;
+
+	if (location == NULL)
+		return;
+
+	data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
+	file_manager_update_ui (data, browser);
+}
+
+
+void
+rs__gth_browser_update_sensitivity_cb (GthBrowser *browser)
+{
+	BrowserData   *data;
+	GthFileSource *file_source;
+	int            n_selected;
+	gboolean       sensitive;
+
+	data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
+	g_return_if_fail (data != NULL);
+
+	file_source = gth_browser_get_location_source (browser);
+	n_selected = gth_file_selection_get_n_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
+
+	sensitive = (n_selected > 0) && (file_source != NULL);
+	set_action_sensitive (data, "Edit_Rename", sensitive);
+}
diff --git a/extensions/rename_series/callbacks.h b/extensions/rename_series/callbacks.h
new file mode 100644
index 0000000..b882b43
--- /dev/null
+++ b/extensions/rename_series/callbacks.h
@@ -0,0 +1,35 @@
+/* -*- 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 CALLBACKS_H
+#define CALLBACKS_H
+
+#include <gthumb.h>
+
+void rs__gth_browser_construct_cb                (GthBrowser    *browser);
+void rs__gth_browser_set_current_page_cb         (GthBrowser    *browser);
+void rs__gth_browser_load_location_after_cb      (GthBrowser    *browser,
+					          GFile         *location,
+					          GError        *error);
+void rs__gth_browser_update_sensitivity_cb       (GthBrowser    *browser);
+
+#endif /* CALLBACKS_H */
diff --git a/extensions/rename_series/data/Makefile.am b/extensions/rename_series/data/Makefile.am
new file mode 100644
index 0000000..4d5385d
--- /dev/null
+++ b/extensions/rename_series/data/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = ui
+-include $(top_srcdir)/git.mk
diff --git a/extensions/rename_series/data/ui/Makefile.am b/extensions/rename_series/data/ui/Makefile.am
new file mode 100644
index 0000000..9cc1d5f
--- /dev/null
+++ b/extensions/rename_series/data/ui/Makefile.am
@@ -0,0 +1,5 @@
+uidir = $(datadir)/gthumb/ui
+ui_DATA = rename-series.ui
+EXTRA_DIST = $(ui_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/extensions/rename_series/data/ui/rename-series.ui b/extensions/rename_series/data/ui/rename-series.ui
new file mode 100644
index 0000000..62a8931
--- /dev/null
+++ b/extensions/rename_series/data/ui/rename-series.ui
@@ -0,0 +1,514 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="rename_series_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Rename</property>
+    <property name="type_hint">dialog</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkVBox" id="vbox1">
+            <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="label7">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Start _at:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">start_at_spinbutton</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">_Sort by:</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label123">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes" comments="Translators: this is the text case (upper or lower case).">Cas_e:</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="reverse_order_checkbutton">
+                    <property name="label" translatable="yes">Re_verse Order</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="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="sort_by_box">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <placeholder/>
+                    </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>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox2">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkSpinButton" id="start_at_spinbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="adjustment">start_at_adjustment</property>
+                      </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">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="change_case_box">
+                    <property name="visible">True</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </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>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox2">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkEntry" id="template_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="activates_default">True</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="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkTable" id="template_help_table">
+                        <property name="n_rows">6</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">#</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="label2">
+                            <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">%E</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="label9">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">New enumerator digit</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 original filename</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 original extension</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="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="label16">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes" comments="Translate only 'attribute name'">%attr{ attribute name }</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="label17">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">A file attribute</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="label18">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">%N</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="label19">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">The original enumerator</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>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox3">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel" id="label1">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">_Template:</property>
+                        <property name="use_underline">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox51">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkLabel" id="label69">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">_Preview:</property>
+                    <property name="use_markup">True</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="preview_scrolledwindow">
+                    <property name="width_request">300</property>
+                    <property name="height_request">200</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">in</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="cancel_button">
+                <property name="label">gtk-cancel</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="ok_button">
+                <property name="label" translatable="yes">_Rename</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="image">image1</property>
+                <property name="use_underline">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="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">2</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">cancel_button</action-widget>
+      <action-widget response="0">ok_button</action-widget>
+      <action-widget response="0">help_button</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkImage" id="image1">
+    <property name="visible">True</property>
+    <property name="stock">gtk-ok</property>
+  </object>
+  <object class="GtkSizeGroup" id="sizegroup1">
+    <property name="mode">vertical</property>
+    <widgets>
+      <widget name="label1"/>
+      <widget name="template_entry"/>
+    </widgets>
+  </object>
+  <object class="GtkAdjustment" id="start_at_adjustment">
+    <property name="upper">1000000000</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+    <property name="page_size">10</property>
+  </object>
+</interface>
diff --git a/extensions/rename_series/dlg-rename-series.c b/extensions/rename_series/dlg-rename-series.c
new file mode 100644
index 0000000..bdc30c3
--- /dev/null
+++ b/extensions/rename_series/dlg-rename-series.c
@@ -0,0 +1,491 @@
+/* -*- 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-rename-series.h"
+#include "gth-rename-task.h"
+
+
+#define GET_WIDGET(name) _gtk_builder_get_widget (data->builder, (name))
+
+
+enum {
+	GTH_CHANGE_CASE_NONE = 0,
+	GTH_CHANGE_CASE_LOWER,
+	GTH_CHANGE_CASE_UPPER,
+};
+
+enum {
+	SORT_DATA_COLUMN,
+	SORT_NAME_COLUMN,
+	SORT_NUM_COLUMNS
+};
+
+enum {
+	PREVIEW_OLD_NAME_COLUMN,
+	PREVIEW_NEW_NAME_COLUMN,
+	PREVIEW_NUM_COLUMNS
+};
+
+
+typedef struct {
+	GthBrowser    *browser;
+	GList         *file_list;
+	GList         *new_file_list;
+	GList         *new_names_list;
+	gboolean       single_file;
+	GtkBuilder    *builder;
+	GtkWidget     *dialog;
+	GtkWidget     *list_view;
+	GtkWidget     *sort_combobox;
+	GtkWidget     *change_case_combobox;
+	GtkListStore  *list_store;
+	GtkListStore  *sort_model;
+	gboolean       help_visible;
+} DialogData;
+
+
+static void
+destroy_cb (GtkWidget  *widget,
+	    DialogData *data)
+{
+	gth_browser_set_dialog (data->browser, "rename_series", NULL);
+
+	g_object_unref (data->builder);
+	_g_object_list_unref (data->file_list);
+	_g_string_list_free (data->new_names_list);
+	g_list_free (data->new_file_list);
+	g_free (data);
+}
+
+
+static void
+ok_clicked_cb (GtkWidget  *widget,
+	       DialogData *data)
+{
+	GList   *old_files;
+	GList   *new_files;
+	GList   *scan1;
+	GList   *scan2;
+	GthTask *task;
+
+	old_files = NULL;
+	new_files = NULL;
+
+	for (scan1 = data->new_file_list, scan2 = data->new_names_list;
+	     scan1 && scan2;
+	     scan1 = scan1->next, scan2 = scan2->next)
+	{
+		GthFileData *file_data = scan1->data;
+		char        *new_name  = scan2->data;
+		GFile       *parent;
+		GFile       *new_file;
+
+		parent = g_file_get_parent (file_data->file);
+		new_file = g_file_get_child (parent, new_name);
+
+		old_files = g_list_prepend (old_files, g_object_ref (file_data->file));
+		new_files = g_list_prepend (new_files, new_file);
+
+		g_object_unref (parent);
+	}
+	old_files = g_list_reverse (old_files);
+	new_files = g_list_reverse (new_files);
+
+	task = gth_rename_task_new (old_files, new_files);
+	gth_browser_exec_task (data->browser, task, FALSE);
+
+	gtk_widget_destroy (data->dialog);
+}
+
+
+typedef struct {
+	const char   *template;
+	GthFileData  *file_data;
+	int           n;
+	GError      **error;
+} TemplateData;
+
+
+static char *
+get_original_enum (GthFileData *file_data,
+	           char        *match)
+{
+	char    *basename;
+	GRegex  *re;
+	char   **a;
+	char    *value = NULL;
+
+	basename = g_file_get_basename (file_data->file);
+	re = g_regex_new ("([0-9]+)", 0, 0, NULL);
+	a = g_regex_split (re, basename, 0);
+	if (g_strv_length (a) >= 2)
+		value = g_strdup (g_strstrip (a[1]));
+
+	g_strfreev (a);
+	g_regex_unref (re);
+	g_free (basename);
+
+	return value;
+}
+
+
+static char *
+get_attribute_value (GthFileData *file_data,
+	             char        *match)
+{
+	GRegex    *re;
+	char     **a;
+	char      *attribute = NULL;
+	char      *value = NULL;
+
+	re = g_regex_new ("%attr\\{([^}]+)\\}", 0, 0, NULL);
+	a = g_regex_split (re, match, 0);
+	if (g_strv_length (a) >= 2)
+		attribute = g_strstrip (a[1]);
+
+	if ((attribute != NULL) && (*attribute != '\0')) {
+		value = gth_file_data_get_attribute_as_string (file_data, attribute);
+		if (value != NULL) {
+			char *tmp_value;
+
+			tmp_value = _g_utf8_replace (value, "[\r\n]", " ");
+			g_free (value);
+			value = tmp_value;
+		}
+	}
+
+	g_strfreev (a);
+	g_regex_unref (re);
+
+	return value;
+}
+
+
+static gboolean
+template_eval_cb (const GMatchInfo *info,
+		  GString          *res,
+		  gpointer          data)
+{
+	TemplateData *template_data = data;
+	char         *r = NULL;
+	char         *match;
+
+	match = g_match_info_fetch (info, 0);
+	if (strcmp (match, "%F") == 0) {
+		r = g_file_get_basename (template_data->file_data->file);
+	}
+	else if (strcmp (match, "%E") == 0) {
+		char *uri;
+
+		uri = g_file_get_uri (template_data->file_data->file);
+		r = g_strdup (_g_uri_get_file_extension (uri));
+
+		g_free (uri);
+	}
+	else if (strcmp (match, "%N") == 0) {
+		r = get_original_enum (template_data->file_data, match);
+	}
+	else if (strncmp (match, "%attr", 5) == 0) {
+		r = get_attribute_value (template_data->file_data, match);
+		/*if (r == NULL)
+			*template_data->error = g_error_new_literal (GTH_TASK_ERROR, GTH_TASK_ERROR_FAILED, _("Malformed template"));*/
+	}
+	else if (strncmp (match, "#", 1) == 0) {
+		char *format;
+
+		format = g_strdup_printf ("%%0%dd", strlen (match));
+		r = g_strdup_printf (format, template_data->n);
+
+		g_free (format);
+	}
+
+	if (r != NULL)
+		g_string_append (res, r);
+
+	g_free (r);
+	g_free (match);
+
+	return FALSE;
+}
+
+
+static void
+dlg_rename_series_update_preview (DialogData *data)
+{
+	GtkTreeIter   iter;
+	int           change_case;
+	TemplateData *template_data;
+	GRegex       *re;
+	GList        *scan;
+	GError       *error = NULL;
+	GList        *scan1, *scan2;
+
+	if (data->new_names_list != NULL) {
+		_g_string_list_free (data->new_names_list);
+		data->new_names_list = NULL;
+	}
+
+	if (data->new_file_list != NULL) {
+		g_list_free (data->new_file_list);
+		data->new_file_list = NULL;
+	}
+
+	data->new_file_list = g_list_copy (data->file_list);
+	if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (data->sort_combobox), &iter)) {
+		GthFileDataSort *sort_type;
+
+		gtk_tree_model_get (GTK_TREE_MODEL (data->sort_model),
+				    &iter,
+				    SORT_DATA_COLUMN, &sort_type,
+				    -1);
+
+		data->new_file_list = g_list_sort (data->new_file_list, (GCompareFunc) sort_type->cmp_func);
+	}
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("reverse_order_checkbutton"))))
+		data->new_file_list = g_list_reverse (data->new_file_list);
+
+	change_case = gtk_combo_box_get_active (GTK_COMBO_BOX (data->change_case_combobox));
+
+	template_data = g_new0 (TemplateData, 1);
+	template_data->error = &error;
+	template_data->n = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (GET_WIDGET ("start_at_spinbutton")));
+	template_data->template = gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("template_entry")));
+	re = g_regex_new ("#+|%F|%E|%N|%attr\\{[^}]+\\}", 0, 0, NULL);
+	for (scan = data->new_file_list; scan; scan = scan->next) {
+		char *new_name;
+		char *new_name2;
+
+		template_data->file_data = scan->data;
+		new_name = g_regex_replace_eval (re, template_data->template, -1, 0, 0, template_eval_cb, template_data, &error);
+		if (error != NULL)
+			break;
+
+		switch (change_case) {
+		case GTH_CHANGE_CASE_LOWER:
+			new_name2 = g_utf8_strdown (new_name, -1);
+			break;
+		case GTH_CHANGE_CASE_UPPER:
+			new_name2 = g_utf8_strup (new_name, -1);
+			break;
+		default:
+			new_name2 = g_strdup (new_name);
+			break;
+		}
+
+		data->new_names_list = g_list_prepend (data->new_names_list, new_name2);
+		template_data->n = template_data->n + 1;
+
+		g_free (new_name);
+	}
+	data->new_names_list = g_list_reverse (data->new_names_list);
+
+	if (error != NULL) {
+		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->dialog), _("Could not rename the files"), &error);
+		return;
+	}
+
+	/* -- update the list view -- */
+
+	gtk_list_store_clear (data->list_store);
+	for (scan1 = data->new_file_list, scan2 = data->new_names_list;
+	     scan1 && scan2;
+	     scan1 = scan1->next, scan2 = scan2->next)
+	{
+		GthFileData *file_data1 = scan1->data;
+		GthFileData *new_name = scan2->data;
+		GtkTreeIter  iter;
+
+		gtk_list_store_append (data->list_store, &iter);
+		gtk_list_store_set (data->list_store, &iter,
+				    PREVIEW_OLD_NAME_COLUMN, g_file_info_get_display_name (file_data1->info),
+				    PREVIEW_NEW_NAME_COLUMN, new_name,
+				    -1);
+	}
+}
+
+
+static void
+template_entry_icon_press_cb (GtkEntry             *entry,
+                              GtkEntryIconPosition  icon_pos,
+                              GdkEvent             *event,
+                              gpointer              user_data)
+{
+	DialogData *data = user_data;
+
+	data->help_visible = ! data->help_visible;
+
+	if (data->help_visible)
+		gtk_widget_show (GET_WIDGET("template_help_table"));
+	else
+		gtk_widget_hide (GET_WIDGET("template_help_table"));
+}
+
+
+static void
+update_preview_cb (GtkWidget  *widget,
+		   DialogData *data)
+{
+	dlg_rename_series_update_preview (data);
+}
+
+
+void
+dlg_rename_series (GthBrowser *browser,
+		   GList      *file_list)
+{
+	DialogData        *data;
+	GtkCellRenderer   *renderer;
+	GtkTreeViewColumn *column;
+	int                i;
+	GList             *scan;
+
+	if (gth_browser_get_dialog (browser, "rename_series") != NULL) {
+		gtk_window_present (GTK_WINDOW (gth_browser_get_dialog (browser, "rename_series")));
+		return;
+	}
+
+	data = g_new0 (DialogData, 1);
+	data->browser = browser;
+	data->builder = _gtk_builder_new_from_file ("rename-series.ui", "rename_series");
+	data->file_list = gth_file_data_list_dup (file_list);
+
+	/* Get the widgets. */
+
+	data->dialog = _gtk_builder_get_widget (data->builder, "rename_series_dialog");
+	gth_browser_set_dialog (browser, "rename_series", data->dialog);
+	g_object_set_data (G_OBJECT (data->dialog), "dialog_data", data);
+
+	/* Set widgets data. */
+
+	data->list_store = gtk_list_store_new (PREVIEW_NUM_COLUMNS,
+					       G_TYPE_STRING,
+					       G_TYPE_STRING);
+	data->list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (data->list_store));
+	g_object_unref (data->list_store);
+
+	renderer = gtk_cell_renderer_text_new ();
+	column = gtk_tree_view_column_new_with_attributes (_("Old Name"),
+							   renderer,
+							   "text", PREVIEW_OLD_NAME_COLUMN,
+							   NULL);
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (data->list_view), column);
+
+	renderer = gtk_cell_renderer_text_new ();
+	column = gtk_tree_view_column_new_with_attributes (_("New Name"),
+							   renderer,
+							   "text", PREVIEW_NEW_NAME_COLUMN,
+							   NULL);
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (data->list_view), column);
+
+	gtk_widget_show (data->list_view);
+	gtk_container_add (GTK_CONTAINER (GET_WIDGET ("preview_scrolledwindow")), data->list_view);
+
+	/* sort by */
+
+	data->sort_model = gtk_list_store_new (SORT_NUM_COLUMNS,
+					       G_TYPE_POINTER,
+					       G_TYPE_STRING);
+	data->sort_combobox = gtk_combo_box_new_with_model (GTK_TREE_MODEL (data->sort_model));
+	g_object_unref (data->sort_model);
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (data->sort_combobox), renderer, TRUE);
+	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (data->sort_combobox),
+					renderer,
+					"text", SORT_NAME_COLUMN,
+					NULL);
+
+	for (i = 0, scan = gth_main_get_all_sort_types (); scan; scan = scan->next, i++) {
+		GthFileDataSort *sort_type = scan->data;
+		GtkTreeIter      iter;
+
+		gtk_list_store_append (data->sort_model, &iter);
+		gtk_list_store_set (data->sort_model, &iter,
+				    SORT_DATA_COLUMN, sort_type,
+				    SORT_NAME_COLUMN, sort_type->display_name,
+				    -1);
+	}
+	gtk_combo_box_set_active (GTK_COMBO_BOX (data->sort_combobox), 0);
+	gtk_widget_show (data->sort_combobox);
+	gtk_container_add (GTK_CONTAINER (GET_WIDGET ("sort_by_box")), data->sort_combobox);
+
+	/* change case */
+
+	data->change_case_combobox = _gtk_combo_box_new_with_texts (_("Keep original case"),
+								    _("Convert to lower-case"),
+								    _("Convert to upper-case"),
+								    NULL);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (data->change_case_combobox), 0);
+	gtk_widget_show (data->change_case_combobox);
+	gtk_container_add (GTK_CONTAINER (GET_WIDGET ("change_case_box")), data->change_case_combobox);
+
+	dlg_rename_series_update_preview (data);
+
+	/* Set the signals handlers. */
+
+	g_signal_connect (G_OBJECT (data->dialog),
+			  "destroy",
+			  G_CALLBACK (destroy_cb),
+			  data);
+	g_signal_connect (GET_WIDGET ("ok_button"),
+			  "clicked",
+			  G_CALLBACK (ok_clicked_cb),
+			  data);
+	g_signal_connect_swapped (GET_WIDGET ("cancel_button"),
+				  "clicked",
+				  G_CALLBACK (gtk_widget_destroy),
+				  G_OBJECT (data->dialog));
+	g_signal_connect (GET_WIDGET ("template_entry"),
+  			  "icon-press",
+  			  G_CALLBACK (template_entry_icon_press_cb),
+  			  data);
+	g_signal_connect (GET_WIDGET ("template_entry"),
+			  "changed",
+			  G_CALLBACK (update_preview_cb),
+			  data);
+	g_signal_connect (GET_WIDGET ("start_at_spinbutton"),
+			  "value_changed",
+			  G_CALLBACK (update_preview_cb),
+			  data);
+	g_signal_connect (data->sort_combobox,
+			  "changed",
+			  G_CALLBACK (update_preview_cb),
+			  data);
+	g_signal_connect (data->change_case_combobox,
+                          "changed",
+                          G_CALLBACK (update_preview_cb),
+                          data);
+	g_signal_connect (GET_WIDGET ("reverse_order_checkbutton"),
+			  "toggled",
+			  G_CALLBACK (update_preview_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/rename_series/dlg-rename-series.h b/extensions/rename_series/dlg-rename-series.h
new file mode 100644
index 0000000..ce085d2
--- /dev/null
+++ b/extensions/rename_series/dlg-rename-series.h
@@ -0,0 +1,31 @@
+/* -*- 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_RENAME_SERIES_H
+#define DLG_RENAME_SERIES_H
+
+#include <gthumb.h>
+
+void dlg_rename_series (GthBrowser *browser,
+		        GList      *file_list);
+
+#endif /* DLG_RENAME_SERIES_H */
diff --git a/extensions/rename_series/gth-rename-task.c b/extensions/rename_series/gth-rename-task.c
new file mode 100644
index 0000000..57c4266
--- /dev/null
+++ b/extensions/rename_series/gth-rename-task.c
@@ -0,0 +1,308 @@
+/* -*- 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 "gth-rename-task.h"
+
+
+struct _GthRenameTaskPrivate {
+	GList                 *old_files;
+	GList                 *new_files;
+	GList                 *current_old;
+	GList                 *current_new;
+	int                    n_files;
+	int                    n_current;
+	GFile                 *source;
+	GFile                 *destination;
+	GCancellable          *cancellable;
+	GthOverwriteResponse   default_response;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+static void
+gth_rename_task_finalize (GObject *object)
+{
+	GthRenameTask *self;
+
+	self = GTH_RENAME_TASK (object);
+
+	g_object_unref (self->priv->cancellable);
+	_g_object_unref (self->priv->source);
+	_g_object_unref (self->priv->destination);
+	_g_object_list_unref (self->priv->old_files);
+	_g_object_list_unref (self->priv->new_files);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void _gth_rename_task_exec (GthRenameTask *self);
+
+
+static void
+_gth_rename_task_exec_next_file (GthRenameTask *self)
+{
+	self->priv->current_old = self->priv->current_old->next;
+	self->priv->current_new = self->priv->current_new->next;
+	self->priv->n_current++;
+
+	if (self->priv->current_old == NULL)
+		gth_task_completed (GTH_TASK (self), NULL);
+	else
+		_gth_rename_task_exec (self);
+}
+
+
+static void _gth_rename_task_try_rename (GthRenameTask  *self,
+					 GFile          *source,
+					 GFile          *destination,
+					 GFileCopyFlags  copy_flags);
+
+
+static void
+overwrite_dialog_response_cb (GtkDialog *dialog,
+                              gint       response_id,
+                              gpointer   user_data)
+{
+	GthRenameTask *self = user_data;
+
+	if (response_id != GTK_RESPONSE_OK)
+		self->priv->default_response = GTH_OVERWRITE_RESPONSE_UNSPECIFIED;
+	else
+		self->priv->default_response = gth_overwrite_dialog_get_response (GTH_OVERWRITE_DIALOG (dialog));
+
+	gtk_widget_hide (GTK_WIDGET (dialog));
+
+	switch (self->priv->default_response) {
+	case GTH_OVERWRITE_RESPONSE_NO:
+	case GTH_OVERWRITE_RESPONSE_ALWAYS_NO:
+	case GTH_OVERWRITE_RESPONSE_UNSPECIFIED:
+		_gth_rename_task_exec_next_file (self);
+		break;
+
+	case GTH_OVERWRITE_RESPONSE_YES:
+	case GTH_OVERWRITE_RESPONSE_ALWAYS_YES:
+		_gth_rename_task_try_rename (self,
+					     self->priv->source,
+					     self->priv->destination,
+					     G_FILE_COPY_OVERWRITE);
+		break;
+
+	case GTH_OVERWRITE_RESPONSE_RENAME:
+		{
+			GFile *parent;
+			GFile *new_destination;
+
+			parent = g_file_get_parent (self->priv->destination);
+			new_destination = g_file_get_child_for_display_name (parent, gth_overwrite_dialog_get_filename (GTH_OVERWRITE_DIALOG (dialog)), NULL);
+			_gth_rename_task_try_rename (self, self->priv->source, new_destination, 0);
+
+			g_object_unref (new_destination);
+			g_object_unref (parent);
+		}
+		break;
+	}
+
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+
+static void
+_gth_rename_task_try_rename (GthRenameTask   *self,
+			     GFile           *source,
+			     GFile           *destination,
+			     GFileCopyFlags   copy_flags)
+{
+	char   *source_name;
+	char   *destination_name;
+	char   *details;
+	GError *error = NULL;
+
+	if (g_cancellable_set_error_if_cancelled (self->priv->cancellable, &error)) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	g_object_ref (source);
+	_g_object_unref (self->priv->source);
+	self->priv->source = source;
+
+	g_object_ref (destination);
+	_g_object_unref (self->priv->destination);
+	self->priv->destination = destination;
+
+	source_name = g_file_get_parse_name (source);
+	destination_name = g_file_get_parse_name (destination);
+	details = g_strdup_printf ("Renaming '%s' as '%s'", source_name, destination_name);
+	gth_task_progress (GTH_TASK (self),
+			   _("Renaming files"),
+			   details,
+			   FALSE,
+			   (double) self->priv->n_current / (self->priv->n_files + 1));
+
+	g_free (destination_name);
+	g_free (source_name);
+
+	if (self->priv->default_response == GTH_OVERWRITE_RESPONSE_ALWAYS_YES)
+		copy_flags = G_FILE_COPY_OVERWRITE;
+
+	if (! _g_move_file (source,
+			    destination,
+			    G_FILE_COPY_ALL_METADATA | copy_flags,
+			    self->priv->cancellable,
+			    NULL,
+			    NULL,
+			    &error))
+	{
+		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
+			if (self->priv->default_response != GTH_OVERWRITE_RESPONSE_ALWAYS_NO) {
+				GtkWidget *dialog;
+
+				dialog = gth_overwrite_dialog_new (source,
+								   destination,
+								   self->priv->default_response,
+								   self->priv->n_files == 1);
+				g_signal_connect (dialog,
+						  "response",
+						  G_CALLBACK (overwrite_dialog_response_cb),
+						  self);
+				gtk_widget_show (dialog);
+
+				return;
+			}
+		}
+		else {
+			gth_task_completed (GTH_TASK (self), error);
+			return;
+		}
+	}
+
+	_gth_rename_task_exec_next_file (self);
+}
+
+
+static void
+_gth_rename_task_exec (GthRenameTask *self)
+{
+	GFile     *source;
+	GFile     *destination;
+
+	if (self->priv->current_old == NULL) {
+		gth_task_completed (GTH_TASK (self), NULL);
+		return;
+	}
+
+	source = (GFile *) self->priv->current_old->data;
+	destination = (GFile *) self->priv->current_new->data;
+
+	_gth_rename_task_try_rename (self, source, destination, 0);
+}
+
+
+static void
+gth_rename_task_exec (GthTask *task)
+{
+	_gth_rename_task_exec (GTH_RENAME_TASK (task));
+}
+
+
+static void
+gth_rename_task_cancel (GthTask *task)
+{
+	g_cancellable_cancel (GTH_RENAME_TASK (task)->priv->cancellable);
+}
+
+
+static void
+gth_rename_task_class_init (GthRenameTaskClass *klass)
+{
+	GObjectClass *object_class;
+	GthTaskClass *task_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthRenameTaskPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gth_rename_task_finalize;
+
+	task_class = GTH_TASK_CLASS (klass);
+	task_class->exec = gth_rename_task_exec;
+	task_class->cancel = gth_rename_task_cancel;
+}
+
+
+static void
+gth_rename_task_init (GthRenameTask *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_RENAME_TASK, GthRenameTaskPrivate);
+	self->priv->cancellable = g_cancellable_new ();
+	self->priv->default_response = GTH_OVERWRITE_RESPONSE_UNSPECIFIED;
+}
+
+
+GType
+gth_rename_task_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthRenameTaskClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_rename_task_class_init,
+			NULL,
+			NULL,
+			sizeof (GthRenameTask),
+			0,
+			(GInstanceInitFunc) gth_rename_task_init
+		};
+
+		type = g_type_register_static (GTH_TYPE_TASK,
+					       "GthRenameTask",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+GthTask *
+gth_rename_task_new (GList  *old_files,
+		     GList  *new_files)
+{
+	GthRenameTask *self;
+
+	self = GTH_RENAME_TASK (g_object_new (GTH_TYPE_RENAME_TASK, NULL));
+	self->priv->old_files = _g_object_list_ref (old_files);
+	self->priv->new_files = _g_object_list_ref (new_files);
+	self->priv->current_old = self->priv->old_files;
+	self->priv->current_new = self->priv->new_files;
+	self->priv->n_files = g_list_length (self->priv->old_files);
+	self->priv->n_current = 1;
+
+	return (GthTask *) self;
+}
diff --git a/extensions/rename_series/gth-rename-task.h b/extensions/rename_series/gth-rename-task.h
new file mode 100644
index 0000000..840e2a1
--- /dev/null
+++ b/extensions/rename_series/gth-rename-task.h
@@ -0,0 +1,57 @@
+/* -*- 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_RENAME_TASK_H
+#define GTH_RENAME_TASK_H
+
+#include <glib.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_RENAME_TASK            (gth_rename_task_get_type ())
+#define GTH_RENAME_TASK(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_RENAME_TASK, GthRenameTask))
+#define GTH_RENAME_TASK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_RENAME_TASK, GthRenameTaskClass))
+#define GTH_IS_RENAME_TASK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_RENAME_TASK))
+#define GTH_IS_RENAME_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_RENAME_TASK))
+#define GTH_RENAME_TASK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_RENAME_TASK, GthRenameTaskClass))
+
+typedef struct _GthRenameTask        GthRenameTask;
+typedef struct _GthRenameTaskClass   GthRenameTaskClass;
+typedef struct _GthRenameTaskPrivate GthRenameTaskPrivate;
+
+struct _GthRenameTask {
+	GthTask __parent;
+	GthRenameTaskPrivate *priv;
+};
+
+struct _GthRenameTaskClass {
+	GthTaskClass __parent;
+};
+
+GType         gth_rename_task_get_type     (void);
+GthTask *     gth_rename_task_new          (GList  *old_files, /* GFile */
+					    GList  *new_files  /* GFile */);
+
+G_END_DECLS
+
+#endif /* GTH_RENAME_TASK_H */
diff --git a/extensions/rename_series/main.c b/extensions/rename_series/main.c
new file mode 100644
index 0000000..bd4d00a
--- /dev/null
+++ b/extensions/rename_series/main.c
@@ -0,0 +1,56 @@
+/* -*- 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 "callbacks.h"
+
+
+G_MODULE_EXPORT void
+gthumb_extension_activate (void)
+{
+	gth_hook_add_callback ("gth-browser-construct", 10, G_CALLBACK (rs__gth_browser_construct_cb), NULL);
+	gth_hook_add_callback ("gth-browser-set-current-page", 10, G_CALLBACK (rs__gth_browser_set_current_page_cb), NULL);
+	gth_hook_add_callback ("gth-browser-load-location-after", 10, G_CALLBACK (rs__gth_browser_load_location_after_cb), NULL);
+	gth_hook_add_callback ("gth-browser-update-sensitivity", 10, G_CALLBACK (rs__gth_browser_update_sensitivity_cb), NULL);
+}
+
+
+G_MODULE_EXPORT void
+gthumb_extension_deactivate (void)
+{
+}
+
+
+G_MODULE_EXPORT gboolean
+gthumb_extension_is_configurable (void)
+{
+	return FALSE;
+}
+
+
+G_MODULE_EXPORT void
+gthumb_extension_configure (GtkWindow *parent)
+{
+}
diff --git a/extensions/rename_series/rename_series.extension.in.in b/extensions/rename_series/rename_series.extension.in.in
new file mode 100644
index 0000000..9481ec1
--- /dev/null
+++ b/extensions/rename_series/rename_series.extension.in.in
@@ -0,0 +1,10 @@
+[Extension]
+_Name=Rename files
+_Description=Rename series of files.
+_Authors=gthumb development team
+Copyright=Copyright © 2009 The Free Software Foundation, Inc.
+Version=1.0
+
+[Loader]
+Type=module
+File=%LIBRARY%
diff --git a/extensions/search/gth-search-editor-dialog.c b/extensions/search/gth-search-editor-dialog.c
index a668ca4..0cfbc0f 100644
--- a/extensions/search/gth-search-editor-dialog.c
+++ b/extensions/search/gth-search-editor-dialog.c
@@ -131,14 +131,14 @@ gth_search_editor_dialog_construct (GthSearchEditorDialog *self,
     		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_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 5);
 	gtk_container_set_border_width (GTK_CONTAINER (self), 5);
 
     	self->priv->builder = _gtk_builder_new_from_file ("search-editor.ui", "search");
 
     	content = _gtk_builder_get_widget (self->priv->builder, "search_editor");
     	gtk_container_set_border_width (GTK_CONTAINER (content), 5);
-  	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (self)->vbox), content, TRUE, TRUE, 0);
+  	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), content, TRUE, TRUE, 0);
 
 	self->priv->match_type_combobox = gtk_combo_box_new_text ();
   	_gtk_combo_box_append_texts (GTK_COMBO_BOX (self->priv->match_type_combobox),
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index f415f7f..3f3deab 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -71,6 +71,7 @@ PUBLIC_HEADER_FILES = 					\
 	gth-monitor.h					\
 	gth-multipage.h					\
 	gth-nav-window.h				\
+	gth-overwrite-dialog.h				\
 	gth-pixbuf-task.h				\
 	gth-preferences.h				\
 	gth-progress-dialog.h				\
@@ -180,6 +181,7 @@ gthumb_SOURCES = 					\
 	gth-monitor.c					\
 	gth-multipage.c					\
 	gth-nav-window.c				\
+	gth-overwrite-dialog.c				\
 	gth-pixbuf-task.c				\
 	gth-preferences.c				\
 	gth-progress-dialog.c				\
diff --git a/gthumb/dlg-extensions.c b/gthumb/dlg-extensions.c
index b65fd00..0d7de83 100644
--- a/gthumb/dlg-extensions.c
+++ b/gthumb/dlg-extensions.c
@@ -230,6 +230,22 @@ add_columns (GtkTreeView *treeview,
 	GtkCellRenderer   *renderer;
 	GtkTreeViewColumn *column;
 
+	/* the checkbox column */
+
+	column = gtk_tree_view_column_new ();
+	gtk_tree_view_column_set_title (column, _("Use"));
+
+	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_cell_data_func (column, renderer, extension_active_data_func_cb, data, NULL);
+
+	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
 	/* the name column. */
 
 	column = gtk_tree_view_column_new ();
@@ -247,22 +263,6 @@ add_columns (GtkTreeView *treeview,
 
         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, _("Use"));
-
-	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_cell_data_func (column, renderer, extension_active_data_func_cb, data, NULL);
-
-	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 }
 
 
@@ -384,6 +384,7 @@ dlg_extensions (GthBrowser *browser)
 	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_headers_visible (GTK_TREE_VIEW (data->list_view), TRUE);
+        gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (data->list_view), TRUE);
 
         add_columns (GTK_TREE_VIEW (data->list_view), data);
 	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (data->list_store), 0, extension_compare_func, NULL, NULL);
diff --git a/gthumb/gio-utils.c b/gthumb/gio-utils.c
index 6629906..832cdbb 100644
--- a/gthumb/gio-utils.c
+++ b/gthumb/gio-utils.c
@@ -1084,7 +1084,6 @@ g_copy_files_async (GList                 *sources,
 		GList *source_sidecars = NULL;
 		GList *destination_sidecars = NULL;
 
-
 		gth_hook_invoke ("add-sidecars", sources, &source_sidecars);
 		gth_hook_invoke ("add-sidecars", destinations, &destination_sidecars);
 
@@ -1501,6 +1500,66 @@ g_directory_copy_destination_info_ready_cb (GObject      *source_object,
 }
 
 
+gboolean
+_g_move_file (GFile                 *source,
+              GFile                 *destination,
+              GFileCopyFlags         flags,
+              GCancellable          *cancellable,
+              GFileProgressCallback  progress_callback,
+              gpointer               progress_callback_data,
+              GError               **error)
+{
+	GList *sources;
+	GList *destinations;
+	GList *source_sidecars = NULL;
+	GList *destination_sidecars = NULL;
+	GList *scan1;
+	GList *scan2;
+
+	if (! g_file_move (source,
+			   destination,
+			   flags,
+			   cancellable,
+			   progress_callback,
+			   progress_callback_data,
+			   error))
+	{
+		return FALSE;
+	}
+
+	if (flags && G_FILE_COPY_ALL_METADATA == 0)
+		return TRUE;
+
+	/* move the metadata sidecars if requested */
+
+	sources = g_list_prepend (NULL, source);
+	gth_hook_invoke ("add-sidecars", sources, &source_sidecars);
+	source_sidecars = g_list_reverse (source_sidecars);
+
+	destinations = g_list_prepend (NULL, destination);
+	gth_hook_invoke ("add-sidecars", destinations, &destination_sidecars);
+	destination_sidecars = g_list_reverse (destination_sidecars);
+
+	for (scan1 = source_sidecars, scan2 = destination_sidecars;
+	     scan1 && scan2;
+	     scan1 = scan1->next, scan2 = scan2->next)
+	{
+		source = scan1->data;
+		destination = scan2->data;
+
+		g_file_move (source, destination, 0, cancellable, NULL, NULL, NULL);
+	}
+
+	_g_object_list_unref (destination_sidecars);
+	g_list_free (destinations);
+	_g_object_list_unref (source_sidecars);
+	g_list_free (sources);
+
+
+	return TRUE;
+}
+
+
 void
 g_directory_copy_async (GFile                 *source,
 			GFile                 *destination,
diff --git a/gthumb/gio-utils.h b/gthumb/gio-utils.h
index 0bcf4e1..c72788c 100644
--- a/gthumb/gio-utils.h
+++ b/gthumb/gio-utils.h
@@ -130,6 +130,13 @@ void   g_directory_copy_async        (GFile                 *source,
 gboolean _g_delete_files             (GList                 *file_list,
 				      gboolean               include_metadata,
 				      GError               **error);
+gboolean _g_move_file                (GFile                 *source,
+                                      GFile                 *destination,
+                                      GFileCopyFlags         flags,
+                                      GCancellable          *cancellable,
+                                      GFileProgressCallback  progress_callback,
+                                      gpointer               progress_callback_data,
+                                      GError               **error);
 gboolean g_load_file_in_buffer       (GFile                 *file,
 				      void                 **buffer,
 				      gsize                 *size,
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index afd03a5..eaa40ad 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -488,7 +488,7 @@ gth_browser_update_sensitivity (GthBrowser *browser)
 	_gth_browser_set_action_sensitive (browser, "View_Stop", browser->priv->fullscreen || (browser->priv->activity_ref > 0));
 	_gth_browser_set_action_sensitive (browser, "View_Prev", current_file_pos > 0);
 	_gth_browser_set_action_sensitive (browser, "View_Next", (current_file_pos != -1) && (current_file_pos < n_files - 1));
-	_gth_browser_set_action_sensitive (browser, "Edit_Metadata", n_selected > 0);
+	_gth_browser_set_action_sensitive (browser, "Edit_Metadata", n_selected == 1);
 
 	gth_sidebar_update_sensitivity (GTH_SIDEBAR (browser->priv->viewer_sidebar));
 	if (browser->priv->viewer_page != NULL)
@@ -1655,8 +1655,10 @@ _gth_browser_close (GthWindow *window)
 {
 	GthBrowser *browser = (GthBrowser *) window;
 
-	if (browser->priv->background_tasks != NULL)
+	if (browser->priv->background_tasks != NULL) {
+		gtk_window_present (GTK_WINDOW (browser->priv->progress_dialog));
 		return;
+	}
 
 	if (gth_browser_get_file_modified (browser))
 		_gth_browser_ask_whether_to_save (browser,
@@ -3071,6 +3073,13 @@ gth_browser_get_location (GthBrowser *browser)
 
 
 GthFileData *
+gth_browser_get_location_data (GthBrowser *browser)
+{
+	return browser->priv->location;
+}
+
+
+GthFileData *
 gth_browser_get_current_file (GthBrowser *browser)
 {
 	return browser->priv->current_file;
diff --git a/gthumb/gth-browser.h b/gthumb/gth-browser.h
index 9c412d4..4aa8e82 100644
--- a/gthumb/gth-browser.h
+++ b/gthumb/gth-browser.h
@@ -68,6 +68,7 @@ struct _GthBrowserClass
 GType            gth_browser_get_type               (void);
 GtkWidget *      gth_browser_new                    (const char       *uri);
 GFile *          gth_browser_get_location           (GthBrowser       *browser);
+GthFileData *    gth_browser_get_location_data      (GthBrowser       *browser);
 GthFileData *    gth_browser_get_current_file       (GthBrowser       *browser);
 gboolean         gth_browser_get_file_modified      (GthBrowser       *browser);
 void             gth_browser_go_to                  (GthBrowser       *browser,
diff --git a/gthumb/gth-edit-metadata-dialog.c b/gthumb/gth-edit-metadata-dialog.c
index 189e52f..b741639 100644
--- a/gthumb/gth-edit-metadata-dialog.c
+++ b/gthumb/gth-edit-metadata-dialog.c
@@ -37,8 +37,8 @@ struct _GthEditMetadataDialogPrivate {
 };
 
 
-static void 
-gth_edit_metadata_dialog_class_init (GthEditMetadataDialogClass *klass) 
+static void
+gth_edit_metadata_dialog_class_init (GthEditMetadataDialogClass *klass)
 {
 	gth_edit_metadata_dialog_parent_class = g_type_class_peek_parent (klass);
 	g_type_class_add_private (klass, sizeof (GthEditMetadataDialogPrivate));
@@ -52,30 +52,30 @@ gth_edit_metadata_dialog_init (GthEditMetadataDialog *edit_metadata_dialog)
 }
 
 
-GType 
-gth_edit_metadata_dialog_get_type (void) 
+GType
+gth_edit_metadata_dialog_get_type (void)
 {
 	static GType type = 0;
-	
+
 	if (type == 0) {
-		static const GTypeInfo g_define_type_info = { 
-			sizeof (GthEditMetadataDialogClass), 
-			(GBaseInitFunc) NULL, 
-			(GBaseFinalizeFunc) NULL, 
-			(GClassInitFunc) gth_edit_metadata_dialog_class_init, 
-			(GClassFinalizeFunc) NULL, 
-			NULL, 
-			sizeof (GthEditMetadataDialog), 
-			0, 
-			(GInstanceInitFunc) gth_edit_metadata_dialog_init, 
-			NULL 
+		static const GTypeInfo g_define_type_info = {
+			sizeof (GthEditMetadataDialogClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gth_edit_metadata_dialog_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,
+			sizeof (GthEditMetadataDialog),
+			0,
+			(GInstanceInitFunc) gth_edit_metadata_dialog_init,
+			NULL
 		};
-		type = g_type_register_static (GTK_TYPE_DIALOG, 
-					       "GthEditMetadataDialog", 
-					       &g_define_type_info, 
+		type = g_type_register_static (GTK_TYPE_DIALOG,
+					       "GthEditMetadataDialog",
+					       &g_define_type_info,
 					       0);
 	}
-	
+
 	return type;
 }
 
@@ -85,10 +85,10 @@ gth_edit_metadata_dialog_construct (GthEditMetadataDialog *self)
 {
 	GArray *pages;
 	int     i;
-	
+
 	gtk_window_set_resizable (GTK_WINDOW (self), TRUE);
 	gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (self)->vbox), 5);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 5);
 	gtk_container_set_border_width (GTK_CONTAINER (self), 5);
 
 	gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
@@ -97,25 +97,25 @@ gth_edit_metadata_dialog_construct (GthEditMetadataDialog *self)
 	self->priv->notebook = gtk_notebook_new ();
 	gtk_widget_show (self->priv->notebook);
 	gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5);
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (self)->vbox), self->priv->notebook, TRUE, TRUE, 0);
- 	
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), self->priv->notebook, TRUE, TRUE, 0);
+
 	pages = gth_main_get_type_set ("edit-metadata-dialog-page");
 	if (pages == NULL)
 		return;
-  	
+
 	for (i = 0; i < pages->len; i++) {
 		GType      page_type;
 		GtkWidget *page;
-		
+
 		page_type = g_array_index (pages, GType, i);
 		page = g_object_new (page_type, NULL);
 		if (! GTH_IS_EDIT_METADATA_PAGE (page)) {
 			g_object_unref (page);
 			continue;
 		}
-		
+
 		gtk_widget_show (page);
-		gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook), 
+		gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
 					  page,
 					  gtk_label_new (gth_edit_metadata_page_get_name (GTH_EDIT_METADATA_PAGE (page))));
 	}
@@ -123,7 +123,7 @@ gth_edit_metadata_dialog_construct (GthEditMetadataDialog *self)
 
 
 GtkWidget *
-gth_edit_metadata_dialog_new (void) 
+gth_edit_metadata_dialog_new (void)
 {
 	GthEditMetadataDialog *self;
 
@@ -141,17 +141,17 @@ gth_edit_metadata_dialog_set_file (GthEditMetadataDialog *dialog,
 	char  *title;
 	GList *pages;
 	GList *scan;
-		
+
 	if (file == NULL)
 		return;
-	
+
 	title = g_strdup_printf (_("%s Properties"), g_file_info_get_display_name (file->info));
 	gtk_window_set_title (GTK_WINDOW (dialog), title);
-	
+
 	pages = gtk_container_get_children (GTK_CONTAINER (dialog->priv->notebook));
-	for (scan = pages; scan; scan = scan->next) 
+	for (scan = pages; scan; scan = scan->next)
 		gth_edit_metadata_page_set_file (GTH_EDIT_METADATA_PAGE (scan->data), file);
-		
+
 	g_list_free (pages);
 	g_free (title);
 }
@@ -163,11 +163,11 @@ gth_edit_metadata_dialog_update_info (GthEditMetadataDialog *dialog,
 {
 	GList *pages;
 	GList *scan;
-	
+
 	pages = gtk_container_get_children (GTK_CONTAINER (dialog->priv->notebook));
-	for (scan = pages; scan; scan = scan->next) 
+	for (scan = pages; scan; scan = scan->next)
 		gth_edit_metadata_page_update_info (GTH_EDIT_METADATA_PAGE (scan->data), info);
-		
+
 	g_list_free (pages);
 }
 
@@ -175,21 +175,21 @@ gth_edit_metadata_dialog_update_info (GthEditMetadataDialog *dialog,
 /* -- gth_edit_metadata_dialog_page -- */
 
 
-GType 
+GType
 gth_edit_metadata_page_get_type (void) {
 	static GType gth_edit_metadata_page_type_id = 0;
 	if (gth_edit_metadata_page_type_id == 0) {
-		static const GTypeInfo g_define_type_info = { 
-			sizeof (GthEditMetadataPageIface), 
-			(GBaseInitFunc) NULL, 
-			(GBaseFinalizeFunc) NULL, 
-			(GClassInitFunc) NULL, 
-			(GClassFinalizeFunc) NULL, 
-			NULL, 
-			0, 
-			0, 
-			(GInstanceInitFunc) NULL, 
-			NULL 
+		static const GTypeInfo g_define_type_info = {
+			sizeof (GthEditMetadataPageIface),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) NULL,
+			(GClassFinalizeFunc) NULL,
+			NULL,
+			0,
+			0,
+			(GInstanceInitFunc) NULL,
+			NULL
 		};
 		gth_edit_metadata_page_type_id = g_type_register_static (G_TYPE_INTERFACE, "GthEditMetadataPageIface", &g_define_type_info, 0);
 	}
@@ -197,9 +197,9 @@ gth_edit_metadata_page_get_type (void) {
 }
 
 
-void 
+void
 gth_edit_metadata_page_set_file (GthEditMetadataPage *self,
-				 GthFileData         *file_data) 
+				 GthFileData         *file_data)
 {
 	GTH_EDIT_METADATA_PAGE_GET_INTERFACE (self)->set_file (self, file_data);
 }
diff --git a/gthumb/gth-filter-editor-dialog.c b/gthumb/gth-filter-editor-dialog.c
index 55dd194..17298c8 100644
--- a/gthumb/gth-filter-editor-dialog.c
+++ b/gthumb/gth-filter-editor-dialog.c
@@ -170,14 +170,14 @@ gth_filter_editor_dialog_construct (GthFilterEditorDialog *self,
 	GList           *scan;
 	GtkListStore    *selection_model;
 	GtkCellRenderer *renderer;
-	
+
 	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_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 5);
 	gtk_container_set_border_width (GTK_CONTAINER (self), 5);
 
 	gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
@@ -187,7 +187,7 @@ gth_filter_editor_dialog_construct (GthFilterEditorDialog *self,
 
     	content = _gtk_builder_get_widget (self->priv->builder, "filter_editor");
     	gtk_container_set_border_width (GTK_CONTAINER (content), 5);
-  	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (self)->vbox), content, TRUE, TRUE, 0);
+  	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), content, TRUE, TRUE, 0);
 
 	/**/
 
@@ -220,7 +220,7 @@ gth_filter_editor_dialog_construct (GthFilterEditorDialog *self,
 	selection_model = gtk_list_store_new (2, G_TYPE_POINTER, G_TYPE_STRING);
 	self->priv->selection_combobox = gtk_combo_box_new_with_model (GTK_TREE_MODEL (selection_model));
 	g_object_unref (selection_model);
-  	
+
 	renderer = gtk_cell_renderer_text_new ();
 	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->priv->selection_combobox),
 				    renderer,
@@ -229,11 +229,11 @@ gth_filter_editor_dialog_construct (GthFilterEditorDialog *self,
 					renderer,
 					"text", SELECTION_COLUMN_NAME,
 					NULL);
-  	
+
 	for (scan = gth_main_get_all_sort_types (); scan; scan = scan->next) {
 		GthFileDataSort *sort_type = scan->data;
 		GtkTreeIter      iter;
-		
+
 		gtk_list_store_append (selection_model, &iter);
 		gtk_list_store_set (selection_model, &iter,
 				    SELECTION_COLUMN_DATA, sort_type,
@@ -357,25 +357,25 @@ _gth_filter_editor_dialog_set_new_filter (GthFilterEditorDialog *self)
 
 
 gboolean
-get_iter_for_sort_type (GthFilterEditorDialog *self, 
-			const char            *sort_type_name, 
+get_iter_for_sort_type (GthFilterEditorDialog *self,
+			const char            *sort_type_name,
 			GtkTreeIter           *iter)
 {
 	GtkTreeModel *model;
-	
+
 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->selection_combobox));
-	
+
 	if (! gtk_tree_model_get_iter_first (model, iter))
 		return FALSE;
 	do {
 		GthFileDataSort *sort_type;
-		
+
 		gtk_tree_model_get (model, iter, SELECTION_COLUMN_DATA, &sort_type, -1);
 		if (g_strcmp0 (sort_type->name, sort_type_name) == 0)
 			return TRUE;
-	} 
+	}
 	while (gtk_tree_model_iter_next (model, iter));
-	
+
 	return FALSE;
 }
 
@@ -408,13 +408,13 @@ gth_filter_editor_dialog_set_filter (GthFilterEditorDialog *self,
 	self->priv->filter_visible = gth_test_is_visible (GTH_TEST (filter));
 
 	gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("name_entry")), gth_test_get_display_name (GTH_TEST (filter)));
-	
+
 	chain = gth_filter_get_test (filter);
 	match_type = chain != NULL ? gth_test_chain_get_match_type (chain) : GTH_MATCH_TYPE_NONE;
-	
+
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("match_checkbutton")), match_type != GTH_MATCH_TYPE_NONE);
 	gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->match_type_combobox), match_type == GTH_MATCH_TYPE_ANY ? 1 : 0);
-	
+
 	_gtk_container_remove_children (GTK_CONTAINER (GET_WIDGET ("tests_box")), NULL, NULL);
 	if (match_type != GTH_MATCH_TYPE_NONE) {
 		GList *tests;
@@ -438,7 +438,7 @@ gth_filter_editor_dialog_set_filter (GthFilterEditorDialog *self,
 	if (limit_type != GTH_LIMIT_TYPE_NONE) {
 		char        *value;
 		GtkTreeIter  iter;
-		
+
 		gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->limit_object_combobox), limit_type - 1);
 		if (limit_type == GTH_LIMIT_TYPE_SIZE) {
 			int sizes[] = { 1024, 1024 * 1024, 1024 * 1024 * 1024 };
@@ -513,7 +513,7 @@ gth_filter_editor_dialog_get_filter (GthFilterEditorDialog  *self,
 			g_object_unref (test);
 		}
 		g_list_free (test_selectors);
-		
+
 		gth_filter_set_test (filter, GTH_TEST_CHAIN (chain));
 	}
 	else
@@ -526,7 +526,7 @@ gth_filter_editor_dialog_get_filter (GthFilterEditorDialog  *self,
 		GtkTreeIter      iter;
 		GthFileDataSort *sort_type;
 		GtkSortType      sort_direction;
-		
+
 		size = atol (gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("limit_size_entry"))));
 		idx = gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->limit_object_combobox));
 		if (idx == 0)
@@ -550,9 +550,9 @@ gth_filter_editor_dialog_get_filter (GthFilterEditorDialog  *self,
 		                    &iter,
 		                    SELECTION_COLUMN_DATA, &sort_type,
 		                    -1);
-		
+
 		sort_direction = gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->selection_order_combobox));
-		
+
 		gth_filter_set_limit (filter, limit_type, size, sort_type->name, sort_direction);
 	}
 
diff --git a/gthumb/gth-overwrite-dialog.c b/gthumb/gth-overwrite-dialog.c
new file mode 100644
index 0000000..89f9990
--- /dev/null
+++ b/gthumb/gth-overwrite-dialog.c
@@ -0,0 +1,288 @@
+/* -*- 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 <glib/gi18n.h>
+#include "glib-utils.h"
+#include "gth-image-viewer.h"
+#include "gth-metadata-provider.h"
+#include "gth-overwrite-dialog.h"
+#include "gtk-utils.h"
+
+
+static gpointer gth_overwrite_dialog_parent_class = NULL;
+
+
+struct _GthOverwriteDialogPrivate {
+	GtkBuilder           *builder;
+	GFile                *source;
+	GFile                *destination;
+	GtkWidget            *old_image_viewer;
+	GtkWidget            *new_image_viewer;
+};
+
+
+static void
+gth_overwrite_dialog_finalize (GObject *object)
+{
+        GthOverwriteDialog *dialog;
+
+        dialog = GTH_OVERWRITE_DIALOG (object);
+
+        g_object_unref (dialog->priv->builder);
+        g_object_unref (dialog->priv->source);
+        g_object_unref (dialog->priv->destination);
+
+        G_OBJECT_CLASS (gth_overwrite_dialog_parent_class)->finalize (object);
+}
+
+
+static void
+gth_overwrite_dialog_class_init (GthOverwriteDialogClass *klass)
+{
+	gth_overwrite_dialog_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthOverwriteDialogPrivate));
+
+	G_OBJECT_CLASS (klass)->finalize = gth_overwrite_dialog_finalize;
+}
+
+
+static void
+gth_overwrite_dialog_init (GthOverwriteDialog *dialog)
+{
+	dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog, GTH_TYPE_OVERWRITE_DIALOG, GthOverwriteDialogPrivate);
+}
+
+
+GType
+gth_overwrite_dialog_get_type (void)
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo g_define_type_info = {
+			sizeof (GthOverwriteDialogClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gth_overwrite_dialog_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,
+			sizeof (GthOverwriteDialog),
+			0,
+			(GInstanceInitFunc) gth_overwrite_dialog_init,
+			NULL
+		};
+		type = g_type_register_static (GTK_TYPE_DIALOG,
+					       "GthOverwriteDialog",
+					       &g_define_type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+static void
+info_ready_cb (GList    *files,
+	       GError   *error,
+	       gpointer  user_data)
+{
+	GthOverwriteDialog *self = user_data;
+	GthFileData        *source;
+	GthFileData        *destination;
+	char               *text;
+	GTimeVal           *timeval;
+	GIcon              *icon;
+	GdkPixbuf          *pixbuf;
+
+	if (error != NULL) {
+		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (self), _("Cannot read file information"), &error);
+		return;
+	}
+
+	/* source */
+
+	source = files->data;
+
+	gtk_label_set_text (GTK_LABEL (_gtk_builder_get_widget (self->priv->builder, "old_image_filename_label")), g_file_info_get_display_name (source->info));
+
+	text = g_format_size_for_display (g_file_info_get_size (source->info));
+	gtk_label_set_text (GTK_LABEL (_gtk_builder_get_widget (self->priv->builder, "old_image_size_label")), text);
+	g_free (text);
+
+	timeval = gth_file_data_get_modification_time (source);
+	text = _g_time_val_to_exif_date (timeval);
+	gtk_label_set_text (GTK_LABEL (_gtk_builder_get_widget (self->priv->builder, "old_image_time_label")), text);
+	g_free (text);
+
+	icon = (GIcon*) g_file_info_get_attribute_object (source->info, "preview::icon");
+	pixbuf = _g_icon_get_pixbuf (icon, 256, gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (self))));
+	if (pixbuf != NULL) {
+		gth_image_viewer_set_pixbuf (GTH_IMAGE_VIEWER (self->priv->old_image_viewer), pixbuf);
+		g_object_unref (pixbuf);
+	}
+
+	/* destination  */
+
+	destination = files->next->data;
+
+	gtk_label_set_text (GTK_LABEL (_gtk_builder_get_widget (self->priv->builder, "new_image_filename_label")), g_file_info_get_display_name (destination->info));
+
+	text = g_format_size_for_display (g_file_info_get_size (destination->info));
+	gtk_label_set_text (GTK_LABEL (_gtk_builder_get_widget (self->priv->builder, "new_image_size_label")), text);
+	g_free (text);
+
+	timeval = gth_file_data_get_modification_time (destination);
+	text = _g_time_val_to_exif_date (timeval);
+	gtk_label_set_text (GTK_LABEL (_gtk_builder_get_widget (self->priv->builder, "new_image_time_label")), text);
+	g_free (text);
+
+	/**/
+}
+
+
+static void
+overwrite_rename_radiobutton_toggled_cb (GtkToggleButton *button,
+					 gpointer         user_data)
+{
+	GthOverwriteDialog *self = user_data;
+
+	gtk_widget_set_sensitive (_gtk_builder_get_widget (self->priv->builder, "overwrite_rename_entry"),
+				  gtk_toggle_button_get_active (button));
+}
+
+
+static void
+gth_overwrite_dialog_construct (GthOverwriteDialog   *self,
+				GthOverwriteResponse  default_response,
+				gboolean              single_file)
+{
+	GtkWidget *box;
+	GtkWidget *overwrite_radiobutton;
+	GList     *files;
+
+	gtk_window_set_title (GTK_WINDOW (self), "");
+	gtk_window_set_resizable (GTK_WINDOW (self), TRUE);
+	gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 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_OK, GTK_RESPONSE_OK);
+
+	self->priv->builder = _gtk_builder_new_from_file ("overwrite-dialog.ui", NULL);
+	box = _gtk_builder_get_widget (self->priv->builder, "overwrite_dialog_box");
+	gtk_widget_show (box);
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), box, TRUE, TRUE, 0);
+
+	switch (default_response) {
+	case GTH_OVERWRITE_RESPONSE_YES:
+		overwrite_radiobutton = _gtk_builder_get_widget (self->priv->builder, "overwrite_yes_radiobutton");
+		break;
+	case GTH_OVERWRITE_RESPONSE_NO:
+	case GTH_OVERWRITE_RESPONSE_UNSPECIFIED:
+		overwrite_radiobutton = _gtk_builder_get_widget (self->priv->builder, "overwrite_no_radiobutton");
+		break;
+	case GTH_OVERWRITE_RESPONSE_ALWAYS_YES:
+		overwrite_radiobutton = _gtk_builder_get_widget (self->priv->builder, "overwrite_all_radiobutton");
+		break;
+	case GTH_OVERWRITE_RESPONSE_ALWAYS_NO:
+		overwrite_radiobutton = _gtk_builder_get_widget (self->priv->builder, "overwrite_none_radiobutton");
+		break;
+	case GTH_OVERWRITE_RESPONSE_RENAME:
+		overwrite_radiobutton = _gtk_builder_get_widget (self->priv->builder, "overwrite_rename_radiobutton");
+		break;
+	}
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (overwrite_radiobutton), TRUE);
+
+	if (single_file) {
+		gtk_widget_hide (_gtk_builder_get_widget (self->priv->builder, "overwrite_all_radiobutton"));
+		gtk_widget_hide (_gtk_builder_get_widget (self->priv->builder, "overwrite_none_radiobutton"));
+	}
+
+	gtk_widget_set_sensitive (_gtk_builder_get_widget (self->priv->builder, "overwrite_rename_entry"), default_response == GTH_OVERWRITE_RESPONSE_RENAME);
+	if (default_response == GTH_OVERWRITE_RESPONSE_RENAME)
+		gtk_widget_grab_focus (_gtk_builder_get_widget (self->priv->builder, "overwrite_rename_entry"));
+
+	self->priv->old_image_viewer = gth_image_viewer_new ();
+	gth_image_viewer_set_fit_mode (GTH_IMAGE_VIEWER (self->priv->old_image_viewer), GTH_FIT_SIZE_IF_LARGER);
+	gtk_widget_show (self->priv->old_image_viewer);
+	gtk_container_add (GTK_CONTAINER (_gtk_builder_get_widget (self->priv->builder, "old_image_frame")), self->priv->old_image_viewer);
+
+	self->priv->new_image_viewer = gth_image_viewer_new ();
+	gth_image_viewer_set_fit_mode (GTH_IMAGE_VIEWER (self->priv->new_image_viewer), GTH_FIT_SIZE_IF_LARGER);
+	gtk_widget_show (self->priv->new_image_viewer);
+	gtk_container_add (GTK_CONTAINER (_gtk_builder_get_widget (self->priv->builder, "new_image_frame")), self->priv->new_image_viewer);
+
+	g_signal_connect (_gtk_builder_get_widget (self->priv->builder, "overwrite_rename_radiobutton"),
+			  "toggled",
+			  G_CALLBACK (overwrite_rename_radiobutton_toggled_cb),
+			  self);
+
+	files = NULL;
+	files = g_list_append (files, self->priv->source);
+	files = g_list_append (files, self->priv->destination);
+	_g_query_all_metadata_async (files, "standard::*,time::modified,time::modified-usec,preview::icon", NULL, info_ready_cb, self);
+
+	g_list_free (files);
+}
+
+
+GtkWidget *
+gth_overwrite_dialog_new (GFile                *source,
+			  GFile                *destination,
+			  GthOverwriteResponse  default_respose,
+			  gboolean              single_file)
+{
+	GthOverwriteDialog *self;
+
+	self = g_object_new (GTH_TYPE_OVERWRITE_DIALOG, NULL);
+	self->priv->source = g_object_ref (source);
+	self->priv->destination = g_object_ref (destination);
+	gth_overwrite_dialog_construct (self, default_respose, single_file);
+
+	return (GtkWidget *) self;
+}
+
+
+GthOverwriteResponse
+gth_overwrite_dialog_get_response (GthOverwriteDialog *self)
+{
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (_gtk_builder_get_widget (self->priv->builder, "overwrite_yes_radiobutton"))))
+		return GTH_OVERWRITE_RESPONSE_YES;
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (_gtk_builder_get_widget (self->priv->builder, "overwrite_no_radiobutton"))))
+		return GTH_OVERWRITE_RESPONSE_NO;
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (_gtk_builder_get_widget (self->priv->builder, "overwrite_all_radiobutton"))))
+		return GTH_OVERWRITE_RESPONSE_ALWAYS_YES;
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (_gtk_builder_get_widget (self->priv->builder, "overwrite_none_radiobutton"))))
+		return GTH_OVERWRITE_RESPONSE_ALWAYS_NO;
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (_gtk_builder_get_widget (self->priv->builder, "overwrite_rename_radiobutton"))))
+		return GTH_OVERWRITE_RESPONSE_RENAME;
+	return GTH_OVERWRITE_RESPONSE_UNSPECIFIED;
+}
+
+
+const char *
+gth_overwrite_dialog_get_filename (GthOverwriteDialog *self)
+{
+	return gtk_entry_get_text (GTK_ENTRY (_gtk_builder_get_widget (self->priv->builder, "overwrite_rename_entry")));
+}
diff --git a/gthumb/gth-overwrite-dialog.h b/gthumb/gth-overwrite-dialog.h
new file mode 100644
index 0000000..e198225
--- /dev/null
+++ b/gthumb/gth-overwrite-dialog.h
@@ -0,0 +1,69 @@
+/* -*- 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_OVERWRITE_DIALOG_H
+#define GTH_OVERWRITE_DIALOG_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+	GTH_OVERWRITE_RESPONSE_UNSPECIFIED,
+	GTH_OVERWRITE_RESPONSE_YES,
+	GTH_OVERWRITE_RESPONSE_NO,
+	GTH_OVERWRITE_RESPONSE_ALWAYS_YES,
+	GTH_OVERWRITE_RESPONSE_ALWAYS_NO,
+	GTH_OVERWRITE_RESPONSE_RENAME
+} GthOverwriteResponse;
+
+#define GTH_TYPE_OVERWRITE_DIALOG            (gth_overwrite_dialog_get_type ())
+#define GTH_OVERWRITE_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_OVERWRITE_DIALOG, GthOverwriteDialog))
+#define GTH_OVERWRITE_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_OVERWRITE_DIALOG, GthOverwriteDialogClass))
+#define GTH_IS_OVERWRITE_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_OVERWRITE_DIALOG))
+#define GTH_IS_OVERWRITE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_OVERWRITE_DIALOG))
+#define GTH_OVERWRITE_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTH_TYPE_OVERWRITE_DIALOG, GthOverwriteDialogClass))
+
+typedef struct _GthOverwriteDialog GthOverwriteDialog;
+typedef struct _GthOverwriteDialogClass GthOverwriteDialogClass;
+typedef struct _GthOverwriteDialogPrivate GthOverwriteDialogPrivate;
+
+struct _GthOverwriteDialog {
+	GtkDialog parent_instance;
+	GthOverwriteDialogPrivate *priv;
+};
+
+struct _GthOverwriteDialogClass {
+	GtkDialogClass parent_class;
+};
+
+GType                 gth_overwrite_dialog_get_type      (void);
+GtkWidget *           gth_overwrite_dialog_new           (GFile                *source,
+						          GFile                *destination,
+						          GthOverwriteResponse  default_respose,
+						          gboolean              single_file);
+GthOverwriteResponse  gth_overwrite_dialog_get_response  (GthOverwriteDialog   *dialog);
+const char *          gth_overwrite_dialog_get_filename  (GthOverwriteDialog   *dialog);
+
+G_END_DECLS
+
+#endif /* GTH_OVERWRITE_DIALOG_H */
diff --git a/gthumb/gth-progress-dialog.c b/gthumb/gth-progress-dialog.c
index 30f6491..685f714 100644
--- a/gthumb/gth-progress-dialog.c
+++ b/gthumb/gth-progress-dialog.c
@@ -262,7 +262,7 @@ gth_progress_dialog_init (GthProgressDialog *self)
 	gtk_window_set_title (GTK_WINDOW (self), "");
 	gtk_window_set_resizable (GTK_WINDOW (self), TRUE);
 	gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (self)->vbox), 5);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 5);
 	gtk_container_set_border_width (GTK_CONTAINER (self), 5);
 
 	gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
@@ -270,7 +270,7 @@ gth_progress_dialog_init (GthProgressDialog *self)
 	self->priv->task_box = gtk_vbox_new (FALSE, 6);
 	gtk_widget_show (self->priv->task_box);
 	gtk_container_set_border_width (GTK_CONTAINER (self->priv->task_box), 5);
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (self)->vbox), self->priv->task_box, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), self->priv->task_box, FALSE, FALSE, 0);
 
 	g_signal_connect (self, "response", G_CALLBACK (progress_dialog_response_cb), self);
 	g_signal_connect (self, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), self);
diff --git a/gthumb/gtk-utils.c b/gthumb/gtk-utils.c
index e1566e2..f1d1d1c 100644
--- a/gthumb/gtk-utils.c
+++ b/gthumb/gtk-utils.c
@@ -102,8 +102,8 @@ _gtk_message_dialog_new (GtkWindow        *parent,
 
 	gtk_dialog_set_has_separator (GTK_DIALOG (d), FALSE);
 	gtk_container_set_border_width (GTK_CONTAINER (d), 6);
-	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (d)->vbox), 6);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (d)->vbox), 8);
+	gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (d))), 6);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))), 8);
 
 	/* Add label and image */
 
@@ -137,7 +137,7 @@ _gtk_message_dialog_new (GtkWindow        *parent,
 	gtk_box_pack_start (GTK_BOX (hbox), label,
 			    TRUE, TRUE, 0);
 
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (d)->vbox),
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))),
 			    hbox,
 			    FALSE, FALSE, 0);
 
@@ -194,8 +194,8 @@ _gtk_request_dialog_run (GtkWindow        *parent,
 
 	gtk_dialog_set_has_separator (GTK_DIALOG (d), FALSE);
 	gtk_container_set_border_width (GTK_CONTAINER (d), 6);
-	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (d)->vbox), 6);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (d)->vbox), 12);
+	gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (d))), 6);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))), 12);
 
 	/* Add label and image */
 
@@ -232,7 +232,7 @@ _gtk_request_dialog_run (GtkWindow        *parent,
 	gtk_box_pack_start (GTK_BOX (hbox), vbox,
 			    TRUE, TRUE, 0);
 
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (d)->vbox),
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))),
 			    hbox,
 			    FALSE, FALSE, 0);
 
@@ -294,8 +294,8 @@ _gtk_yesno_dialog_new (GtkWindow        *parent,
 
 	gtk_dialog_set_has_separator (GTK_DIALOG (d), FALSE);
 	gtk_container_set_border_width (GTK_CONTAINER (d), 6);
-	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (d)->vbox), 6);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (d)->vbox), 8);
+	gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (d))), 6);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))), 8);
 
 	/* Add label and image */
 
@@ -315,7 +315,7 @@ _gtk_yesno_dialog_new (GtkWindow        *parent,
 	gtk_box_pack_start (GTK_BOX (hbox), label,
 			    TRUE, TRUE, 0);
 
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (d)->vbox),
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))),
 			    hbox,
 			    FALSE, FALSE, 0);
 
@@ -374,8 +374,8 @@ _gtk_yesno_dialog_with_checkbutton_new (GtkWindow        *parent,
 
 	gtk_dialog_set_has_separator (GTK_DIALOG (d), FALSE);
 	gtk_container_set_border_width (GTK_CONTAINER (d), 6);
-	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (d)->vbox), 6);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (d)->vbox), 8);
+	gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (d))), 6);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))), 8);
 
 	/* Add label and image */
 
@@ -395,14 +395,14 @@ _gtk_yesno_dialog_with_checkbutton_new (GtkWindow        *parent,
 	gtk_box_pack_start (GTK_BOX (hbox), label,
 			    TRUE, TRUE, 0);
 
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (d)->vbox),
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))),
 			    hbox,
 			    FALSE, FALSE, 0);
 
 	/* Add checkbutton */
 
 	check_button = gtk_check_button_new_with_mnemonic (check_button_label);
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (d)->vbox),
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))),
 			    check_button,
 			    FALSE, FALSE, 0);
 	gtk_widget_show (check_button);
@@ -467,8 +467,8 @@ _gtk_message_dialog_with_checkbutton_new (GtkWindow        *parent,
 
 	gtk_dialog_set_has_separator (GTK_DIALOG (d), FALSE);
 	gtk_container_set_border_width (GTK_CONTAINER (d), 6);
-	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (d)->vbox), 6);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (d)->vbox), 8);
+	gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (d))), 6);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))), 8);
 
 	/* Add label and image */
 
@@ -502,7 +502,7 @@ _gtk_message_dialog_with_checkbutton_new (GtkWindow        *parent,
 	gtk_box_pack_start (GTK_BOX (hbox), label,
 			    TRUE, TRUE, 0);
 
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (d)->vbox),
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))),
 			    hbox,
 			    FALSE, FALSE, 0);
 
@@ -511,7 +511,7 @@ _gtk_message_dialog_with_checkbutton_new (GtkWindow        *parent,
 	/* Add checkbutton */
 
 	check_button = gtk_check_button_new_with_mnemonic (check_button_label);
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (d)->vbox),
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))),
 			    check_button,
 			    FALSE, FALSE, 0);
 	gtk_widget_show (check_button);



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