[gthumb: 3/14] find duplicates: started implementing the GthTask



commit 7550d9b5369ee07e1a9619d1a97c5a721b1504e8
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Tue Jan 25 23:53:51 2011 +0100

    find duplicates: started implementing the GthTask

 extensions/Makefile.am                             |    4 +-
 .../find_duplicates/.#gth-find-duplicates-task.c   |    1 +
 extensions/find_duplicates/Makefile.am             |    2 +
 extensions/find_duplicates/callbacks.c             |   32 -
 extensions/find_duplicates/callbacks.h             |    3 +-
 .../data/ui/find-duplicates-dialog.ui              |  501 +++++++++++++
 .../find_duplicates/data/ui/find-duplicates.ui     |   88 ++-
 extensions/find_duplicates/dlg-find-duplicates.c   |   52 ++-
 .../find_duplicates/gth-find-duplicates-task.c     |  764 ++++++++++++++++++++
 .../find_duplicates/gth-find-duplicates-task.h     |   56 ++
 extensions/find_duplicates/main.c                  |    1 -
 11 files changed, 1452 insertions(+), 52 deletions(-)
---
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index e253c2a..f554e0f 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -31,6 +31,7 @@ SUBDIRS = 			\
 	edit_metadata		\
 	exiv2_tools		\
 	export_tools		\
+	$(EXPORTERS)		\
 	find_duplicates		\
 	file_manager		\
 	file_viewer		\
@@ -39,7 +40,7 @@ SUBDIRS = 			\
 	gstreamer_tools		\
 	image_print		\
 	image_viewer		\
-	importer		\
+	importer		\	
 	jpeg_utils		\
 	$(JPEG_TOOLS)		\
 	list_tools		\
@@ -50,7 +51,6 @@ SUBDIRS = 			\
 	resize_images		\
 	search			\
 	slideshow		\
-	$(EXPORTERS)		\
 	$(IMAGE_VIEWER_TOOLS)	\
 	$(IMPORTERS)		\
 	$(NULL)
diff --git a/extensions/find_duplicates/.#gth-find-duplicates-task.c b/extensions/find_duplicates/.#gth-find-duplicates-task.c
new file mode 120000
index 0000000..0252f29
--- /dev/null
+++ b/extensions/find_duplicates/.#gth-find-duplicates-task.c
@@ -0,0 +1 @@
+paolo Terranova 3796:1295824240
\ No newline at end of file
diff --git a/extensions/find_duplicates/Makefile.am b/extensions/find_duplicates/Makefile.am
index ef673e2..7c92916 100644
--- a/extensions/find_duplicates/Makefile.am
+++ b/extensions/find_duplicates/Makefile.am
@@ -10,6 +10,8 @@ libfind_duplicates_la_SOURCES = 	\
 	callbacks.h			\
 	dlg-find-duplicates.c		\
 	dlg-find-duplicates.h		\
+	gth-find-duplicates-task.c	\
+	gth-find-duplicates-task.h	\
 	main.c
 
 libfind_duplicates_la_CFLAGS = $(GTHUMB_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb 
diff --git a/extensions/find_duplicates/callbacks.c b/extensions/find_duplicates/callbacks.c
index cbb1c49..61d2c4e 100644
--- a/extensions/find_duplicates/callbacks.c
+++ b/extensions/find_duplicates/callbacks.c
@@ -92,35 +92,3 @@ find_dup__gth_browser_construct_cb (GthBrowser *browser)
 
 	g_object_set_data_full (G_OBJECT (browser), BROWSER_DATA_KEY, data, (GDestroyNotify) browser_data_free);
 }
-
-
-void
-find_dup__gth_browser_update_extra_widget_cb (GthBrowser *browser)
-{
-	/* FIXME
-	GthFileData *location_data;
-	BrowserData *data;
-
-	location_data = gth_browser_get_location_data (browser);
-	if (! _g_content_type_is_a (g_file_info_get_content_type (location_data->info), "gthumb/search"))
-		return;
-
-	data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
-
-	if (data->refresh_button == NULL) {
-		data->refresh_button = gtk_button_new ();
-		gtk_container_add (GTK_CONTAINER (data->refresh_button), gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON));
-		g_object_add_weak_pointer (G_OBJECT (data->refresh_button), (gpointer *)&data->refresh_button);
-		gtk_button_set_relief (GTK_BUTTON (data->refresh_button), GTK_RELIEF_NONE);
-		gtk_widget_set_tooltip_text (data->refresh_button, _("Search again"));
-		gtk_widget_show_all (data->refresh_button);
-		gedit_message_area_add_action_widget (GEDIT_MESSAGE_AREA (gth_browser_get_list_extra_widget (browser)),
-					              data->refresh_button,
-					              _RESPONSE_REFRESH);
-		g_signal_connect (data->refresh_button,
-				  "clicked",
-				  G_CALLBACK (refresh_button_clicked_cb),
-				  browser);
-	}
-	*/
-}
diff --git a/extensions/find_duplicates/callbacks.h b/extensions/find_duplicates/callbacks.h
index b12facc..18e2e6d 100644
--- a/extensions/find_duplicates/callbacks.h
+++ b/extensions/find_duplicates/callbacks.h
@@ -24,7 +24,6 @@
 
 #include <gthumb.h>
 
-void  find_dup__gth_browser_construct_cb            (GthBrowser *browser);
-void  find_dup__gth_browser_update_extra_widget_cb  (GthBrowser *browser);
+void  find_dup__gth_browser_construct_cb  (GthBrowser *browser);
 
 #endif /* CALLBACKS_H */
diff --git a/extensions/find_duplicates/data/ui/find-duplicates-dialog.ui b/extensions/find_duplicates/data/ui/find-duplicates-dialog.ui
new file mode 100644
index 0000000..d1f20f7
--- /dev/null
+++ b/extensions/find_duplicates/data/ui/find-duplicates-dialog.ui
@@ -0,0 +1,501 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkListStore" id="files_liststore">
+    <columns>
+      <!-- column-name file -->
+      <column type="GObject"/>
+      <!-- column-name checked -->
+      <column type="gboolean"/>
+      <!-- column-name filename -->
+      <column type="gchararray"/>
+      <!-- column-name position -->
+      <column type="gchararray"/>
+      <!-- column-name last_modified -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkDialog" id="find_duplicates_dialog">
+    <property name="border_width">6</property>
+    <property name="title" translatable="yes">Search for Duplicates</property>
+    <property name="type_hint">dialog</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox12">
+        <property name="visible">True</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkVBox" id="vbox13">
+            <property name="visible">True</property>
+            <property name="border_width">6</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <property name="spacing">20</property>
+                <child>
+                  <object class="GtkHBox" id="hbox1">
+                    <property name="visible">True</property>
+                    <property name="spacing">24</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox4">
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkImage" id="image1">
+                            <property name="visible">True</property>
+                            <property name="stock">gtk-find</property>
+                            <property name="icon-size">6</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkVBox" id="vbox2">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkLabel" id="progress_label">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="ellipsize">end</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkVBox" id="vbox3">
+                            <property name="visible">True</property>
+                            <property name="spacing">3</property>
+                            <child>
+                              <object class="GtkProgressBar" id="search_progressbar">
+                                <property name="visible">True</property>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="search_details_label">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="ellipsize">end</property>
+                              </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>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHSeparator" id="hseparator7">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">6</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkNotebook" id="pages_notebook">
+                <property name="visible">True</property>
+                <property name="show_tabs">False</property>
+                <property name="show_border">False</property>
+                <child>
+                  <object class="GtkVBox" id="vbox19">
+                    <property name="visible">True</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox18">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkHBox" id="hbox46">
+                            <property name="visible">True</property>
+                            <property name="spacing">5</property>
+                            <child>
+                              <object class="GtkLabel" id="label73">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Duplicates:</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="total_duplicates_label">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHBox" id="duplicates_list_box">
+                            <property name="visible">True</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkVBox" id="vbox16">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkLabel" id="label78">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Files:</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHBox" id="hbox50">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkVBox" id="vbox14">
+                                <property name="visible">True</property>
+                                <property name="spacing">5</property>
+                                <child>
+                                  <object class="GtkHBox" id="hbox51">
+                                    <property name="visible">True</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <object class="GtkScrolledWindow" id="files_scrolledwindow">
+                                        <property name="width_request">450</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>
+                                          <object class="GtkTreeView" id="files_treeview">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="model">files_liststore</property>
+                                            <property name="rules_hint">True</property>
+                                            <property name="enable_search">False</property>
+                                            <child>
+                                              <object class="GtkTreeViewColumn" id="treeviewcolumn4">
+                                                <property name="sizing">autosize</property>
+                                                <child>
+                                                  <object class="GtkCellRendererToggle" id="file_cellrenderertoggle"/>
+                                                  <attributes>
+                                                    <attribute name="active">1</attribute>
+                                                  </attributes>
+                                                </child>
+                                              </object>
+                                            </child>
+                                            <child>
+                                              <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+                                                <property name="resizable">True</property>
+                                                <property name="sizing">autosize</property>
+                                                <property name="title">File</property>
+                                                <child>
+                                                  <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                                                  <attributes>
+                                                    <attribute name="text">2</attribute>
+                                                  </attributes>
+                                                </child>
+                                              </object>
+                                            </child>
+                                            <child>
+                                              <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+                                                <property name="resizable">True</property>
+                                                <property name="sizing">autosize</property>
+                                                <property name="title">Last modified</property>
+                                                <child>
+                                                  <object class="GtkCellRendererText" id="cellrenderertext2"/>
+                                                  <attributes>
+                                                    <attribute name="text">4</attribute>
+                                                  </attributes>
+                                                </child>
+                                              </object>
+                                            </child>
+                                            <child>
+                                              <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+                                                <property name="resizable">True</property>
+                                                <property name="title">Position</property>
+                                                <child>
+                                                  <object class="GtkCellRendererText" id="cellrenderertext3"/>
+                                                  <attributes>
+                                                    <attribute name="text">3</attribute>
+                                                  </attributes>
+                                                </child>
+                                              </object>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkVBox" id="files_commands_hbox">
+                                        <property name="visible">True</property>
+                                        <property name="spacing">5</property>
+                                        <child>
+                                          <object class="GtkButton" id="view_button">
+                                            <property name="label" translatable="yes">_View</property>
+                                            <property name="visible">True</property>
+                                            <property name="sensitive">False</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">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="GtkButton" id="delete_button">
+                                            <property name="label">gtk-delete</property>
+                                            <property name="visible">True</property>
+                                            <property name="sensitive">False</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                            <property name="use_stock">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="select_all_button">
+                                            <property name="label" translatable="yes">Select _All</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                            <property name="use_underline">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">2</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="unselect_all_button">
+                                            <property name="label" translatable="yes">_Unselect All</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                            <property name="use_underline">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">3</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child type="tab">
+                  <object class="GtkLabel" id="label80">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">label80</property>
+                  </object>
+                  <packing>
+                    <property name="tab_fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox53">
+                    <property name="visible">True</property>
+                    <property name="spacing">10</property>
+                    <child>
+                      <object class="GtkImage" id="image43">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="stock">gtk-dialog-warning</property>
+                        <property name="icon-size">6</property>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label82">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">No duplicates found.</property>
+                        <property name="wrap">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child type="tab">
+                  <object class="GtkLabel" id="label81">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">label81</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                    <property name="tab_fill">False</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area12">
+            <property name="layout_style">end</property>
+            <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">0</property>
+                <property name="secondary">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="stop_button">
+                <property name="label">gtk-stop</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="close_button">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">2</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">help_button</action-widget>
+      <action-widget response="0">stop_button</action-widget>
+      <action-widget response="0">close_button</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/extensions/find_duplicates/data/ui/find-duplicates.ui b/extensions/find_duplicates/data/ui/find-duplicates.ui
index 1626cad..3e9f538 100644
--- a/extensions/find_duplicates/data/ui/find-duplicates.ui
+++ b/extensions/find_duplicates/data/ui/find-duplicates.ui
@@ -18,23 +18,47 @@
             <property name="border_width">6</property>
             <property name="spacing">6</property>
             <child>
-              <object class="GtkHBox" id="location_box">
+              <object class="GtkHBox" id="hbox1">
                 <property name="visible">True</property>
                 <property name="spacing">6</property>
                 <child>
-                  <object class="GtkLabel" id="start_at_label">
+                  <object class="GtkHBox" id="location_box">
                     <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="spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="start_at_label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Start _at:</property>
+                        <property name="use_underline">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
-                  <placeholder/>
+                  <object class="GtkCheckButton" id="include_subfolder_checkbutton">
+                    <property name="label" translatable="yes">_Include sub-folders</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="position">1</property>
+                  </packing>
                 </child>
               </object>
               <packing>
@@ -42,14 +66,38 @@
               </packing>
             </child>
             <child>
-              <object class="GtkCheckButton" id="include_subfolder_checkbutton">
-                <property name="label" translatable="yes">_Include sub-folders</property>
+              <object class="GtkHBox" id="hbox2">
                 <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>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">_Filter:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">file_type_combobox</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="file_type_combobox">
+                    <property name="visible">True</property>
+                    <property name="model">file_type_liststore</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="position">1</property>
@@ -123,4 +171,16 @@
       <action-widget response="0">ok_button</action-widget>
     </action-widgets>
   </object>
+  <object class="GtkSizeGroup" id="sizegroup1">
+    <widgets>
+      <widget name="start_at_label"/>
+      <widget name="label1"/>
+    </widgets>
+  </object>
+  <object class="GtkListStore" id="file_type_liststore">
+    <columns>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
 </interface>
diff --git a/extensions/find_duplicates/dlg-find-duplicates.c b/extensions/find_duplicates/dlg-find-duplicates.c
index 35471b3..fecf300 100644
--- a/extensions/find_duplicates/dlg-find-duplicates.c
+++ b/extensions/find_duplicates/dlg-find-duplicates.c
@@ -23,6 +23,7 @@
 #include <gtk/gtk.h>
 #include <gthumb.h>
 #include "dlg-find-duplicates.h"
+#include "gth-find-duplicates-task.h"
 
 
 #define GET_WIDGET(name) _gtk_builder_get_widget (data->builder, (name))
@@ -33,6 +34,7 @@ typedef struct {
 	GtkBuilder *builder;
 	GtkWidget  *dialog;
 	GtkWidget  *location_chooser;
+	GList      *general_tests;
 } DialogData;
 
 
@@ -42,6 +44,7 @@ destroy_cb (GtkWidget  *widget,
 {
 	gth_browser_set_dialog (data->browser, "find_duplicates", NULL);
 
+	_g_string_list_free (data->general_tests);
 	g_object_unref (data->builder);
 	g_free (data);
 }
@@ -59,7 +62,15 @@ static void
 ok_clicked_cb (GtkWidget  *widget,
 	       DialogData *data)
 {
-	/* FIXME */
+	GthTask *task;
+
+	task = gth_find_duplicates_task_new (data->browser,
+					     gth_location_chooser_get_current (GTH_LOCATION_CHOOSER (data->location_chooser)),
+					     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("include_subfolder_checkbutton"))),
+					     g_list_nth_data (data->general_tests, gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("file_type_combobox")))));
+	gth_browser_exec_task (data->browser, task, FALSE);
+
+	g_object_unref (task);
 	gtk_widget_destroy (data->dialog);
 }
 
@@ -68,6 +79,12 @@ void
 dlg_find_duplicates (GthBrowser *browser)
 {
 	DialogData *data;
+	GList      *tests;
+	char       *general_filter;
+	int         active_filter;
+	int         i;
+	int         i_general;
+	GList      *scan;
 
 	if (gth_browser_get_dialog (browser, "find_duplicates") != NULL) {
 		gtk_window_present (GTK_WINDOW (gth_browser_get_dialog (browser, "find_duplicates")));
@@ -93,6 +110,39 @@ dlg_find_duplicates (GthBrowser *browser)
 
 	gth_location_chooser_set_current (GTH_LOCATION_CHOOSER (data->location_chooser), gth_browser_get_location (browser));
 
+	tests = gth_main_get_registered_objects_id (GTH_TYPE_TEST);
+	general_filter = eel_gconf_get_string (PREF_GENERAL_FILTER, DEFAULT_GENERAL_FILTER);
+	active_filter = 0;
+	for (i = 0, i_general = -1, scan = tests; scan; scan = scan->next, i++) {
+		const char  *registered_test_id = scan->data;
+		GthTest     *test;
+		GtkTreeIter  iter;
+
+		if (strncmp (registered_test_id, "file::type::", 12) != 0)
+			continue;
+
+		i_general += 1;
+
+		if (strcmp (registered_test_id, general_filter) == 0)
+			active_filter = i_general;
+
+		test = gth_main_get_registered_object (GTH_TYPE_TEST, registered_test_id);
+		data->general_tests = g_list_prepend (data->general_tests, g_strdup (gth_test_get_id (test)));
+
+		gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("file_type_liststore")), &iter);
+		gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("file_type_liststore")), &iter,
+				    0, gth_test_get_display_name (test),
+				    -1);
+
+		g_object_unref (test);
+	}
+	data->general_tests = g_list_reverse (data->general_tests);
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("file_type_combobox")), active_filter);
+
+	g_free (general_filter);
+	_g_string_list_free (tests);
+
 	/* Set the signals handlers. */
 
 	g_signal_connect (G_OBJECT (data->dialog),
diff --git a/extensions/find_duplicates/gth-find-duplicates-task.c b/extensions/find_duplicates/gth-find-duplicates-task.c
new file mode 100644
index 0000000..a1ee021
--- /dev/null
+++ b/extensions/find_duplicates/gth-find-duplicates-task.c
@@ -0,0 +1,764 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2010 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gthumb.h>
+#include <extensions/catalogs/gth-catalog.h>
+#include "gth-find-duplicates-task.h"
+
+
+#define GET_WIDGET(x) (_gtk_builder_get_widget (self->priv->builder, (x)))
+#define BUFFER_SIZE 4096
+
+
+struct _GthFindDuplicatesTaskPrivate
+{
+	GthBrowser    *browser;
+	GFile         *location;
+	gboolean       recursive;
+	GthTest       *test;
+	GtkBuilder    *builder;
+	GtkWidget     *duplicates_list;
+	GString       *attributes;
+	gboolean       io_operation;
+	GthFileSource *file_source;
+	int            n_duplicates;
+	goffset        duplicates_size;
+	int            n_files;
+	int            n_file;
+	GList         *files;
+	GList         *directories;
+	GFile         *current_directory;
+	GthFileData   *current_file;
+	guchar         buffer[BUFFER_SIZE];
+	GChecksum     *checksum;
+	GInputStream  *file_stream;
+	GHashTable    *duplicated;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+typedef struct {
+	GList   *files;
+	goffset  total_size;
+	int      n_files;
+} DuplicatedData;
+
+
+static DuplicatedData *
+duplicated_data_new (void)
+{
+	DuplicatedData *d_data;
+
+	d_data = g_new0 (DuplicatedData, 1);
+	d_data->files = 0;
+	d_data->total_size = 0;
+	d_data->n_files = 0;
+
+	return d_data;
+}
+
+
+static void
+duplicated_data_free (DuplicatedData *d_data)
+{
+	_g_object_list_unref (d_data->files);
+	g_free (d_data);
+}
+
+
+static void
+gth_task_finalize (GObject *object)
+{
+	GthFindDuplicatesTask *self;
+
+	self = GTH_FIND_DUPLICATES_TASK (object);
+
+	g_object_unref (self->priv->location);
+	_g_object_unref (self->priv->test);
+	_g_object_unref (self->priv->builder);
+	if (self->priv->attributes != NULL)
+		g_string_free (self->priv->attributes, TRUE);
+	_g_object_unref (self->priv->file_source);
+	_g_object_list_unref (self->priv->files);
+	_g_object_list_unref (self->priv->directories);
+	_g_object_unref (self->priv->current_file);
+	_g_object_unref (self->priv->current_directory);
+	if (self->priv->checksum != NULL)
+		g_checksum_free (self->priv->checksum);
+	_g_object_unref (self->priv->file_stream);
+	g_hash_table_unref (self->priv->duplicated);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void search_directory (GthFindDuplicatesTask *self,
+			      GFile                 *directory);
+
+
+static void
+search_next_directory (GthFindDuplicatesTask *self)
+{
+	GList *first;
+
+	if (self->priv->directories == NULL) {
+		gtk_label_set_text (GTK_LABEL (GET_WIDGET ("progress_label")), _("Search completed"));
+		gtk_label_set_text (GTK_LABEL (GET_WIDGET ("search_details_label")), "");
+		gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (GET_WIDGET ("search_progressbar")), 1.0);
+		gtk_widget_set_sensitive (GET_WIDGET ("stop_button"), FALSE);
+		/* FIXME */
+		return;
+	}
+
+	first = self->priv->directories;
+	self->priv->directories = g_list_remove_link (self->priv->directories, first);
+	search_directory (self, (GFile *) first->data);
+
+	_g_object_list_unref (first);
+}
+
+
+static void start_next_checksum (GthFindDuplicatesTask *self);
+
+
+static void
+file_input_stream_read_ready_cb (GObject      *source,
+		    	    	 GAsyncResult *result,
+		    	    	 gpointer      user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+	GError                *error = NULL;
+	gssize                 buffer_size;
+
+	buffer_size = g_input_stream_read_finish (G_INPUT_STREAM (source), result, &error);
+	if (buffer_size < 0) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+	else if (buffer_size == 0) {
+		const char     *checksum;
+		DuplicatedData *d_data;
+
+		self->priv->n_file += 1;
+
+		g_object_unref (self->priv->file_stream);
+		self->priv->file_stream = NULL;
+
+		g_print ("MD5 %s: %s\n",
+			 g_file_get_uri (self->priv->current_file->file),
+			 g_checksum_get_string (self->priv->checksum));
+
+		checksum = g_checksum_get_string (self->priv->checksum);
+		g_file_info_set_attribute_string (self->priv->current_file->info,
+						  "find-duplicates::checksum",
+						  checksum);
+
+		g_file_info_set_attribute_object (self->priv->current_file->info,
+						  "find-duplicates::directory",
+						  G_OBJECT (self->priv->current_directory));
+
+		d_data = g_hash_table_lookup (self->priv->duplicated, checksum);
+		if (d_data == NULL) {
+			d_data = duplicated_data_new ();
+			g_hash_table_insert (self->priv->duplicated, g_strdup (checksum), d_data);
+		}
+		d_data->files = g_list_prepend (d_data->files, g_object_ref (self->priv->current_file));
+		d_data->n_files += 1;
+		d_data->total_size += g_file_info_get_size (self->priv->current_file->info);
+		if (d_data->n_files > 1) {
+			GthFileData *file_data;
+			char        *text;
+			char        *size_formatted;
+			GList       *list;
+
+			file_data = g_list_last (d_data->files)->data;
+			text = g_strdup_printf (g_dngettext (NULL, "%d duplicate", "%d duplicates", d_data->n_files - 1), d_data->n_files - 1);
+			g_file_info_set_attribute_string (file_data->info,
+							  "find-duplicates::n-duplicates",
+							  text);
+			g_free (text);
+
+			self->priv->n_duplicates += 1;
+			self->priv->duplicates_size += g_file_info_get_size (file_data->info);
+
+			size_formatted = g_format_size_for_display (self->priv->duplicates_size);
+			text = g_strdup_printf (g_dngettext (NULL, "%d file (%s)", "%d files (%s)", self->priv->n_duplicates), self->priv->n_duplicates, size_formatted);
+			gtk_label_set_text (GTK_LABEL (GET_WIDGET ("total_duplicates_label")), text);
+			g_free (text);
+			g_free (size_formatted);
+
+			list = g_list_append (NULL, file_data);
+
+			if (d_data->n_files == 2)
+				gth_file_list_add_files (GTH_FILE_LIST (self->priv->duplicates_list), list);
+			else
+				gth_file_list_update_files (GTH_FILE_LIST (self->priv->duplicates_list), list);
+
+			g_list_free (list);
+		}
+
+		start_next_checksum (self);
+
+		return;
+	}
+
+	g_checksum_update (self->priv->checksum, self->priv->buffer, buffer_size);
+	g_input_stream_read_async (self->priv->file_stream,
+				   self->priv->buffer,
+				   BUFFER_SIZE,
+				   G_PRIORITY_DEFAULT,
+				   gth_task_get_cancellable (GTH_TASK (self)),
+				   file_input_stream_read_ready_cb,
+				   self);
+}
+
+
+static void
+read_current_file_ready_cb (GObject      *source,
+			    GAsyncResult *result,
+			    gpointer      user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+	GError                *error = NULL;
+
+	if (self->priv->file_stream != NULL)
+		g_object_unref (self->priv->file_stream);
+	self->priv->file_stream = (GInputStream *) g_file_read_finish (G_FILE (source), result, &error);
+	if (self->priv->file_stream == NULL) {
+		start_next_checksum (self);
+		return;
+	}
+
+	g_input_stream_read_async (self->priv->file_stream,
+				   self->priv->buffer,
+				   BUFFER_SIZE,
+				   G_PRIORITY_DEFAULT,
+				   gth_task_get_cancellable (GTH_TASK (self)),
+				   file_input_stream_read_ready_cb,
+				   self);
+}
+
+
+static void
+start_next_checksum (GthFindDuplicatesTask *self)
+{
+	GList *link;
+	char  *text;
+
+	link = self->priv->files;
+	if (link == NULL) {
+		search_next_directory (self);
+		return;
+	}
+
+	self->priv->files = g_list_remove_link (self->priv->files, link);
+	_g_object_unref (self->priv->current_file);
+	self->priv->current_file = (GthFileData *) link->data;
+	g_list_free (link);
+
+	text = g_strdup_printf (_("Checking file %s"), g_file_info_get_display_name (self->priv->current_file->info));
+	gtk_label_set_text (GTK_LABEL (GET_WIDGET ("search_details_label")), text);
+	g_free (text);
+
+	gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (GET_WIDGET ("search_progressbar")),
+				       (double) (self->priv->n_file + 1) / (self->priv->n_files + 1));
+
+	if (self->priv->checksum == NULL)
+		self->priv->checksum = g_checksum_new (G_CHECKSUM_MD5);
+	else
+		g_checksum_reset (self->priv->checksum);
+
+	g_file_read_async (self->priv->current_file->file,
+			   G_PRIORITY_DEFAULT,
+			   gth_task_get_cancellable (GTH_TASK (self)),
+			   read_current_file_ready_cb,
+			   self);
+}
+
+
+static void
+done_func (GObject  *object,
+	   GError   *error,
+	   gpointer  user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+
+	self->priv->io_operation = FALSE;
+
+	if (error != NULL) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	self->priv->files = g_list_reverse (self->priv->files);
+	if (self->priv->files != NULL) {
+		self->priv->n_files = g_list_length (self->priv->files);
+		self->priv->n_file = 0;
+		start_next_checksum (self);
+	}
+	else
+		search_next_directory (self);
+}
+
+
+static void
+for_each_file_func (GFile     *file,
+		    GFileInfo *info,
+		    gpointer   user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+	GthFileData           *file_data;
+
+	if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
+		return;
+
+	file_data = gth_file_data_new (file, info);
+	if (gth_test_match (self->priv->test, file_data))
+		self->priv->files = g_list_prepend (self->priv->files, g_object_ref (file_data));
+
+	g_object_unref (file_data);
+}
+
+
+static DirOp
+start_dir_func (GFile      *directory,
+		GFileInfo  *info,
+		GError    **error,
+		gpointer    user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+
+	if (g_file_equal (directory, self->priv->current_directory))
+		return DIR_OP_CONTINUE;
+
+	self->priv->directories = g_list_prepend (self->priv->directories, g_object_ref (directory));
+
+	return DIR_OP_SKIP;
+}
+
+
+static void
+search_directory (GthFindDuplicatesTask *self,
+		  GFile                 *directory)
+{
+	char *uri;
+	char *text;
+
+	gtk_widget_set_sensitive (GET_WIDGET ("stop_button"), TRUE);
+	self->priv->io_operation = TRUE;
+
+	_g_object_unref (self->priv->current_directory);
+	self->priv->current_directory = g_object_ref (directory);
+
+	uri = g_file_get_parse_name (self->priv->current_directory);
+	text = g_strdup_printf ("Searching in %s", uri);
+	gtk_label_set_text (GTK_LABEL (GET_WIDGET ("progress_label")), text);
+	gtk_label_set_text (GTK_LABEL (GET_WIDGET ("search_details_label")), _("Getting the file list"));
+	gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (GET_WIDGET ("search_progressbar")), 0.0);
+
+	gth_file_source_for_each_child (self->priv->file_source,
+					self->priv->current_directory,
+					self->priv->recursive,
+					self->priv->attributes->str,
+					start_dir_func,
+					for_each_file_func,
+					done_func,
+					self);
+
+	g_free (text);
+	g_free (uri);
+}
+
+
+static void
+find_duplicates_dialog_destroy_cb (GtkWidget *dialog,
+				   gpointer   user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+	gth_task_completed (GTH_TASK (self), NULL);
+}
+
+
+static void
+update_file_list_sensitivity (GthFindDuplicatesTask *self)
+{
+	GtkTreeModel *model;
+	GtkTreeIter   iter;
+	gboolean      one_active = FALSE;
+
+	model = GTK_TREE_MODEL (GET_WIDGET ("files_liststore"));
+	if (gtk_tree_model_get_iter_first (model, &iter)) {
+		do {
+			gboolean active;
+
+			gtk_tree_model_get (model, &iter, 1, &active, -1);
+			if (active) {
+				one_active = TRUE;
+				break;
+			}
+		}
+		while (gtk_tree_model_iter_next(model, &iter));
+	}
+
+	gtk_widget_set_sensitive (GET_WIDGET ("view_button"), one_active);
+	gtk_widget_set_sensitive (GET_WIDGET ("delete_button"), one_active);
+}
+
+
+static void
+duplicates_list_view_selection_changed_cb (GtkIconView *iconview,
+					   gpointer     user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+	GtkWidget             *duplicates_view;
+	int                    n_selected;
+
+	duplicates_view = gth_file_list_get_view (GTH_FILE_LIST (self->priv->duplicates_list));
+	n_selected = gth_file_selection_get_n_selected (GTH_FILE_SELECTION (duplicates_view));
+	if (n_selected == 1) {
+		GList          *items;
+		GList          *file_list;
+		GthFileData    *selected_file_data;
+		const char     *checksum;
+		DuplicatedData *d_data;
+		GList          *scan;
+
+		items = gth_file_selection_get_selected (GTH_FILE_SELECTION (duplicates_view));
+		file_list = gth_file_list_get_files (GTH_FILE_LIST (self->priv->duplicates_list), items);
+		selected_file_data = (GthFileData *) file_list->data;
+
+		gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("files_liststore")));
+
+		checksum = g_file_info_get_attribute_string (selected_file_data->info, "find-duplicates::checksum");
+		d_data = g_hash_table_lookup (self->priv->duplicated, checksum);
+
+		g_return_if_fail (d_data != NULL);
+
+		for (scan = d_data->files; scan; scan = scan->next) {
+			GthFileData *file_data = scan->data;
+			char        *directory_name;
+			GtkTreeIter  iter;
+
+			directory_name = g_file_get_parse_name (G_FILE (g_file_info_get_attribute_object (file_data->info, "find-duplicates::directory")));
+			gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("files_liststore")), &iter);
+			gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("files_liststore")), &iter,
+					    0, file_data,
+					    1, TRUE,
+					    2, g_file_info_get_display_name (file_data->info),
+					    3, directory_name,
+					    4, g_file_info_get_attribute_string (file_data->info, "gth::file::display-mtime"),
+					    -1);
+
+			g_free (directory_name);
+		}
+
+		update_file_list_sensitivity (self);
+
+		_g_object_list_unref (file_list);
+		_gtk_tree_path_list_free (items);
+	}
+}
+
+
+static void
+file_cellrenderertoggle_toggled_cb (GtkCellRendererToggle *cell_renderer,
+                		    char                  *path,
+                		    gpointer               user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+	GtkTreeModel          *model;
+	GtkTreePath           *tree_path;
+	GtkTreeIter            iter;
+	gboolean               active;
+
+	model = GTK_TREE_MODEL (GET_WIDGET ("files_liststore"));
+	tree_path = gtk_tree_path_new_from_string (path);
+	if (! gtk_tree_model_get_iter (model, &iter, tree_path)) {
+		gtk_tree_path_free (tree_path);
+		return;
+	}
+
+	gtk_tree_model_get (model, &iter, 1, &active, -1);
+	gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, ! active, -1);
+
+	update_file_list_sensitivity (self);
+
+	gtk_tree_path_free (tree_path);
+}
+
+
+static GList *
+get_selected_files (GthFindDuplicatesTask *self)
+{
+	GtkTreeModel *model;
+	GtkTreeIter   iter;
+	GList        *list;
+
+	model = GTK_TREE_MODEL (GET_WIDGET ("files_liststore"));
+	if (! gtk_tree_model_get_iter_first (model, &iter))
+		return NULL;
+
+	list = NULL;
+	do {
+		GthFileData *file_data;
+		gboolean     active;
+
+		gtk_tree_model_get (model, &iter,
+				    0, &file_data,
+				    1, &active,
+				    -1);
+		if (active)
+			list = g_list_prepend (list, g_object_ref (file_data->file));
+	}
+	while (gtk_tree_model_iter_next (model, &iter));
+
+	return g_list_reverse (list);
+}
+
+
+static void
+view_button_clicked_cb (GtkWidget *button,
+			gpointer   user_data)
+{
+	GthFindDuplicatesTask *self = user_data;
+	GList                 *files;
+	GthCatalog            *catalog;
+	GFile                 *catalog_file;
+
+	files = get_selected_files (self);
+	if (files == NULL)
+		return;
+
+	catalog = gth_catalog_new ();
+	catalog_file = gth_catalog_file_from_relative_path (_("Duplicates"), ".catalog");
+	gth_catalog_set_file (catalog, catalog_file);
+	gth_catalog_set_file_list (catalog, files);
+	gth_catalog_save (catalog);
+	gth_browser_go_to (self->priv->browser, catalog_file, NULL);
+
+	g_object_unref (catalog_file);
+	g_object_unref (catalog);
+	_g_object_list_unref (files);
+}
+
+
+static void
+select_all_files (GthFindDuplicatesTask *self,
+		  gboolean               active)
+{
+	GtkTreeModel *model;
+	GtkTreeIter   iter;
+
+	model = GTK_TREE_MODEL (GET_WIDGET ("files_liststore"));
+	if (! gtk_tree_model_get_iter_first (model, &iter))
+		return;
+
+	do {
+		gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, active, -1);
+	}
+	while (gtk_tree_model_iter_next (model, &iter));
+
+	update_file_list_sensitivity (self);
+}
+
+static void
+select_all_button_clicked_cb (GtkWidget *button,
+			      gpointer   user_data)
+{
+	select_all_files (GTH_FIND_DUPLICATES_TASK (user_data), TRUE);
+}
+
+
+static void
+unselect_all_button_clicked_cb (GtkWidget *button,
+			        gpointer   user_data)
+{
+	select_all_files (GTH_FIND_DUPLICATES_TASK (user_data), FALSE);
+}
+
+
+static void
+gth_find_duplicates_task_exec (GthTask *base)
+{
+	GthFindDuplicatesTask *self = (GthFindDuplicatesTask *) base;
+	const char            *test_attributes;
+
+	self->priv->file_source = gth_main_get_file_source (self->priv->location);
+	gth_file_source_set_cancellable (self->priv->file_source, gth_task_get_cancellable (GTH_TASK (self)));
+
+	self->priv->attributes = g_string_new (eel_gconf_get_boolean (PREF_FAST_FILE_TYPE, TRUE) ? GFILE_STANDARD_ATTRIBUTES_WITH_FAST_CONTENT_TYPE : GFILE_STANDARD_ATTRIBUTES_WITH_CONTENT_TYPE);
+	g_string_append (self->priv->attributes, ",gth::file::display-size");
+	test_attributes = gth_test_get_attributes (self->priv->test);
+	if (test_attributes[0] != '\0') {
+		g_string_append (self->priv->attributes, ",");
+		g_string_append (self->priv->attributes, test_attributes);
+	}
+
+	self->priv->builder = _gtk_builder_new_from_file ("find-duplicates-dialog.ui", "find_duplicates");
+	self->priv->duplicates_list = gth_file_list_new (GTH_FILE_LIST_TYPE_NORMAL, FALSE);
+	gth_file_list_set_caption (GTH_FILE_LIST (self->priv->duplicates_list), "find-duplicates::n-duplicates,gth::file::display-size");
+	gth_file_list_set_thumb_size (GTH_FILE_LIST (self->priv->duplicates_list), 112);
+	gtk_widget_set_size_request (self->priv->duplicates_list, -1, 200);
+	gtk_widget_show (self->priv->duplicates_list);
+	gtk_container_add (GTK_CONTAINER (GET_WIDGET ("duplicates_list_box")), self->priv->duplicates_list);
+
+	g_signal_connect (GET_WIDGET ("find_duplicates_dialog"),
+			  "destroy",
+			  G_CALLBACK (find_duplicates_dialog_destroy_cb),
+			  self);
+	g_signal_connect_swapped (GET_WIDGET ("close_button"),
+				  "clicked",
+				  G_CALLBACK (gtk_widget_destroy),
+				  GET_WIDGET ("find_duplicates_dialog"));
+	g_signal_connect_swapped (GET_WIDGET ("stop_button"),
+				  "clicked",
+				  G_CALLBACK (gth_task_cancel),
+				  self);
+	g_signal_connect (G_OBJECT (gth_file_list_get_view (GTH_FILE_LIST (self->priv->duplicates_list))),
+			  "selection_changed",
+			  G_CALLBACK (duplicates_list_view_selection_changed_cb),
+			  self);
+	g_signal_connect (GET_WIDGET ("file_cellrenderertoggle"),
+			  "toggled",
+			  G_CALLBACK (file_cellrenderertoggle_toggled_cb),
+			  self);
+	g_signal_connect (GET_WIDGET ("view_button"),
+			  "clicked",
+			  G_CALLBACK (view_button_clicked_cb),
+			  self);
+	g_signal_connect (GET_WIDGET ("select_all_button"),
+			  "clicked",
+			  G_CALLBACK (select_all_button_clicked_cb),
+			  self);
+	g_signal_connect (GET_WIDGET ("unselect_all_button"),
+			  "clicked",
+			  G_CALLBACK (unselect_all_button_clicked_cb),
+			  self);
+
+	gtk_widget_show (GET_WIDGET ("find_duplicates_dialog"));
+	gth_task_dialog (GTH_TASK (self), TRUE, GET_WIDGET ("find_duplicates_dialog"));
+
+	search_directory (self, self->priv->location);
+}
+
+
+static void
+gth_find_duplicates_task_cancelled (GthTask *self)
+{
+	/* FIXME
+	if (! GTH_FIND_DUPLICATES_TASK (self)->priv->io_operation)
+		gth_task_completed (self, g_error_new_literal (GTH_TASK_ERROR, GTH_TASK_ERROR_CANCELLED, ""));
+	*/
+}
+
+
+static void
+gth_find_duplicates_task_class_init (GthFindDuplicatesTaskClass *class)
+{
+	GObjectClass *object_class;
+	GthTaskClass *task_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class = (GObjectClass*) class;
+	object_class->finalize = gth_task_finalize;
+
+	task_class = (GthTaskClass*) class;
+	task_class->exec = gth_find_duplicates_task_exec;
+	task_class->cancelled = gth_find_duplicates_task_cancelled;
+}
+
+
+static void
+gth_find_duplicates_task_init (GthFindDuplicatesTask *self)
+{
+	self->priv = g_new0 (GthFindDuplicatesTaskPrivate, 1);
+	self->priv->test = NULL;
+	self->priv->builder = NULL;
+	self->priv->attributes = NULL;
+	self->priv->io_operation = FALSE;
+	self->priv->n_duplicates = 0;
+	self->priv->duplicates_size = 0;
+	self->priv->file_source = NULL;
+	self->priv->files = NULL;
+	self->priv->directories = NULL;
+	self->priv->current_directory = NULL;
+	self->priv->current_file = NULL;
+	self->priv->checksum = NULL;
+	self->priv->file_stream = NULL;
+	self->priv->duplicated = g_hash_table_new_full (g_str_hash,
+							g_str_equal,
+							g_free,
+							(GDestroyNotify) duplicated_data_free);
+}
+
+
+GType
+gth_find_duplicates_task_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthFindDuplicatesTaskClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_find_duplicates_task_class_init,
+			NULL,
+			NULL,
+			sizeof (GthFindDuplicatesTask),
+			0,
+			(GInstanceInitFunc) gth_find_duplicates_task_init
+		};
+
+		type = g_type_register_static (GTH_TYPE_TASK,
+					       "GthFindDuplicatesTask",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+GthTask *
+gth_find_duplicates_task_new (GthBrowser *browser,
+			      GFile      *location,
+			      gboolean    recursive,
+			      const char *filter)
+{
+	GthFindDuplicatesTask *self;
+
+	self = (GthFindDuplicatesTask *) g_object_new (GTH_TYPE_FIND_DUPLICATES_TASK, NULL);
+
+	self->priv->browser = browser;
+	self->priv->location = g_object_ref (location);
+	self->priv->recursive = recursive;
+	if (filter != NULL)
+		self->priv->test = gth_main_get_registered_object (GTH_TYPE_TEST, filter);
+
+	return (GthTask*) self;
+}
diff --git a/extensions/find_duplicates/gth-find-duplicates-task.h b/extensions/find_duplicates/gth-find-duplicates-task.h
new file mode 100644
index 0000000..a37d847
--- /dev/null
+++ b/extensions/find_duplicates/gth-find-duplicates-task.h
@@ -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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_FIND_DUPLICATES_TASK_H
+#define GTH_FIND_DUPLICATES_TASK_H
+
+#include <glib-object.h>
+#include <gthumb.h>
+
+#define GTH_TYPE_FIND_DUPLICATES_TASK         (gth_find_duplicates_task_get_type ())
+#define GTH_FIND_DUPLICATES_TASK(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_FIND_DUPLICATES_TASK, GthFindDuplicatesTask))
+#define GTH_FIND_DUPLICATES_TASK_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_FIND_DUPLICATES_TASK, GthFindDuplicatesTaskClass))
+#define GTH_IS_FIND_DUPLICATES_TASK(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_FIND_DUPLICATES_TASK))
+#define GTH_IS_FIND_DUPLICATES_TASK_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_FIND_DUPLICATES_TASK))
+#define GTH_FIND_DUPLICATES_TASK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_FIND_DUPLICATES_TASK, GthFindDuplicatesTaskClass))
+
+typedef struct _GthFindDuplicatesTask         GthFindDuplicatesTask;
+typedef struct _GthFindDuplicatesTaskPrivate  GthFindDuplicatesTaskPrivate;
+typedef struct _GthFindDuplicatesTaskClass    GthFindDuplicatesTaskClass;
+
+struct _GthFindDuplicatesTask
+{
+	GthTask __parent;
+	GthFindDuplicatesTaskPrivate *priv;
+};
+
+struct _GthFindDuplicatesTaskClass
+{
+	GthTaskClass __parent_class;
+};
+
+GType       gth_find_duplicates_task_get_type   (void) G_GNUC_CONST;
+GthTask *   gth_find_duplicates_task_new        (GthBrowser *browser,
+						 GFile      *location,
+						 gboolean    recursive,
+						 const char *filter);
+
+#endif /* GTH_FIND_DUPLICATES_TASK_H */
diff --git a/extensions/find_duplicates/main.c b/extensions/find_duplicates/main.c
index 483ae42..ab36633 100644
--- a/extensions/find_duplicates/main.c
+++ b/extensions/find_duplicates/main.c
@@ -30,7 +30,6 @@ G_MODULE_EXPORT void
 gthumb_extension_activate (void)
 {
 	gth_hook_add_callback ("gth-browser-construct", 10, G_CALLBACK (find_dup__gth_browser_construct_cb), NULL);
-	gth_hook_add_callback ("gth-browser-update-extra-widget", 20, G_CALLBACK (find_dup__gth_browser_update_extra_widget_cb), NULL);
 }
 
 



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