Fix #477: similarity duplicate search
authorColin Clark <colin.clark@cclark.uk>
Sun, 28 May 2017 18:30:41 +0000 (19:30 +0100)
committerColin Clark <colin.clark@cclark.uk>
Sun, 28 May 2017 18:30:41 +0000 (19:30 +0100)
https://github.com/BestImageViewer/geeqie/issues/477

Additional find dupes option: sort groups with the lowest number of
matches to the top of the results list

doc/docbook/GuideImageSearchFindingDuplicates.xml
src/dupe.c
src/options.c
src/options.h
src/rcfile.c

index b963f33..29606d0 100644 (file)
     <title>Ignore Rotation</title>\r
     <para>When checked, the rotational orientation of images will be ignored.</para>\r
   </section>\r
+  <section id="Sort">\r
+    <title>Sort</title>\r
+    <para>\r
+      The normal sort order is for groups (in the case of Similarity checks) with the highest number of near-100% matches to be at the top of the list.\r
+      <para />\r
+      If this box is checked, groups with the lowest number of matches are placed at the top of the list.\r
+    </para>\r
+  </section>\r
   <section id="Comparetwofilesets">\r
     <title>Compare two file sets</title>\r
     <para>Sometimes it is useful to compare one group of files to another, different group of files. Enable this check box to compare two groups of files. When enabled, a second list will appear and files can be added to this list using the same methods for the main list.</para>\r
     </para>\r
     <para />\r
   </section>\r
-</section>
+</section>\r
index c04e501..932606e 100644 (file)
@@ -1066,6 +1066,20 @@ static void dupe_match_sort_groups(GList *list)
                }
 }
 
+static gint dupe_match_totals_sort_cb(gconstpointer a, gconstpointer b)
+{
+       DupeItem *da = (DupeItem *)a;
+       DupeItem *db = (DupeItem *)b;
+
+       if (g_list_length(da->group) > g_list_length(db->group)) return -1;
+       if (g_list_length(da->group) < g_list_length(db->group)) return 1;
+
+       if (da->group_rank < db->group_rank) return -1;
+       if (da->group_rank > db->group_rank) return 1;
+
+       return 0;
+}
+
 static gint dupe_match_rank_sort_cb(gconstpointer a, gconstpointer b)
 {
        DupeItem *da = (DupeItem *)a;
@@ -1099,6 +1113,15 @@ static GList *dupe_match_rank_sort(GList *source_list)
        return g_list_sort(list, dupe_match_rank_sort_cb);
 }
 
+/* returns allocated GList of dupes sorted by totals */
+static GList *dupe_match_totals_sort(GList *source_list)
+{
+       source_list = g_list_sort(source_list, dupe_match_totals_sort_cb);
+
+       source_list = g_list_first(source_list);
+       return g_list_reverse(source_list);
+}
+
 static void dupe_match_rank(DupeWindow *dw)
 {
        GList *list;
@@ -1116,6 +1139,11 @@ static void dupe_match_rank(DupeWindow *dw)
        if (required_debug_level(2)) dupe_match_print_list(list);
 
        list = dupe_match_rank_sort(list);
+       if (options->sort_totals)
+               {
+               list = dupe_match_totals_sort(list);
+               }
+       if (required_debug_level(2)) dupe_match_print_list(list);
 
        g_list_free(dw->dupes);
        dw->dupes = list;
@@ -2648,6 +2676,15 @@ static void dupe_second_set_toggle_cb(GtkWidget *widget, gpointer data)
        dupe_window_recompare(dw);
 }
 
+static void dupe_sort_totals_toggle_cb(GtkWidget *widget, gpointer data)
+{
+       DupeWindow *dw = data;
+
+       options->sort_totals = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+       dupe_window_recompare(dw);
+
+}
+
 /*
  *-------------------------------------------------------------------
  * match type menu
@@ -3331,6 +3368,14 @@ DupeWindow *dupe_window_new()
        gtk_container_add(GTK_CONTAINER(frame), dw->status_label);
        gtk_widget_show(dw->status_label);
 
+       button = gtk_check_button_new_with_label(_("Sort"));
+       gtk_widget_set_tooltip_text(GTK_WIDGET(button), "Sort by group totals");
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), options->sort_totals);
+       g_signal_connect(G_OBJECT(button), "toggled",
+                        G_CALLBACK(dupe_sort_totals_toggle_cb), dw);
+       gtk_box_pack_start(GTK_BOX(status_box), button, FALSE, FALSE, PREF_PAD_SPACE);
+       gtk_widget_show(button);
+
        label = gtk_label_new(_("Custom Threshold"));
        gtk_box_pack_start(GTK_BOX(status_box), label, FALSE, FALSE, PREF_PAD_SPACE);
        gtk_widget_show(label);
index 5477dff..9a1ff34 100644 (file)
@@ -48,6 +48,7 @@ ConfOptions *init_options(ConfOptions *options)
        options->dnd_icon_size = 48;
        options->duplicates_similarity_threshold = 99;
        options->rot_invariant_sim = TRUE;
+       options->sort_totals = FALSE;
 
        options->file_filter.disable = FALSE;
        options->file_filter.show_dot_directory = FALSE;
index 9fb78f8..f538ded 100644 (file)
@@ -45,6 +45,7 @@ struct _ConfOptions
        gboolean duplicates_thumbnails;
        guint duplicates_select_type;
        gboolean rot_invariant_sim;
+       gboolean sort_totals;
 
        gint open_recent_list_maxsize;
        gint dnd_icon_size;
index 52aa2b9..cf2f474 100644 (file)
@@ -322,6 +322,7 @@ static void write_global_attributes(GString *outstr, gint indent)
        WRITE_NL(); WRITE_UINT(*options, duplicates_select_type);
        WRITE_NL(); WRITE_BOOL(*options, duplicates_thumbnails);
        WRITE_NL(); WRITE_BOOL(*options, rot_invariant_sim);
+       WRITE_NL(); WRITE_BOOL(*options, sort_totals);
        WRITE_SEPARATOR();
 
        WRITE_NL(); WRITE_BOOL(*options, mousewheel_scrolls);
@@ -606,6 +607,7 @@ static gboolean load_global_params(const gchar **attribute_names, const gchar **
                if (READ_UINT_CLAMP(*options, duplicates_select_type, 0, DUPE_SELECT_GROUP2)) continue;
                if (READ_BOOL(*options, duplicates_thumbnails)) continue;
                if (READ_BOOL(*options, rot_invariant_sim)) continue;
+               if (READ_BOOL(*options, sort_totals)) continue;
 
                if (READ_BOOL(*options, progressive_key_scrolling)) continue;
                if (READ_UINT_CLAMP(*options, keyboard_scroll_step, 1, 32)) continue;