From 68eec555c787ef354c646fd9f03ec7b86b753644 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Thu, 23 Apr 2020 10:40:19 +0100 Subject: [PATCH] Fix #714: find duplicates enhanced selection logic https://github.com/BestImageViewer/geeqie/issues/714 Sort by click on column header "Show all" option Revised layout Key "0" de-select all --- .../GuideImageSearchFindingDuplicates.xml | 14 +- .../GuideReferenceKeyboardShortcuts.xml | 7 + src/dupe.c | 332 +++++++++++++++--- src/dupe.h | 6 +- 4 files changed, 303 insertions(+), 56 deletions(-) diff --git a/doc/docbook/GuideImageSearchFindingDuplicates.xml b/doc/docbook/GuideImageSearchFindingDuplicates.xml index 29606d0f..29ba7e27 100644 --- a/doc/docbook/GuideImageSearchFindingDuplicates.xml +++ b/doc/docbook/GuideImageSearchFindingDuplicates.xml @@ -136,12 +136,22 @@ + + + Show all + + + + Do not compare. Show all images. + + +
Results list Files that match with the selected comparison method will appear in the list. Matching files are grouped in alternating color. - The order of the result list can not be changed, files will appear in the order of the search. When comparing by image content similarity, the matching groups will be sorted by order of rank starting with the files that are most similar. + The order of the result list can be changed by clicking on the column header. This will re-order the images within each set. When comparing by image content similarity, the matching sets will be sorted by order of rank starting with the files that are most similar. A context menu @@ -149,7 +159,7 @@ Groups in the results list may be selected by using the keyboard. Refer to the Find Duplicates Window section of - Keyboard Shortcuts + Keyboard Shortcuts . diff --git a/doc/docbook/GuideReferenceKeyboardShortcuts.xml b/doc/docbook/GuideReferenceKeyboardShortcuts.xml index 8a89e167..3a1aecf6 100644 --- a/doc/docbook/GuideReferenceKeyboardShortcuts.xml +++ b/doc/docbook/GuideReferenceKeyboardShortcuts.xml @@ -1114,6 +1114,13 @@ + + + 0 + + + Select none. + 1 diff --git a/src/dupe.c b/src/dupe.c index f74206ed..173bda93 100644 --- a/src/dupe.c +++ b/src/dupe.c @@ -70,6 +70,7 @@ enum { DUPE_COLUMN_DIMENSIONS, DUPE_COLUMN_PATH, DUPE_COLUMN_COLOR, + DUPE_COLUMN_SET, DUPE_COLUMN_COUNT /* total columns */ }; @@ -524,6 +525,7 @@ static void dupe_listview_add(DupeWindow *dw, DupeItem *parent, DupeItem *child) { gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DUPE_COLUMN_COLOR, &color_set, -1); color_set = !color_set; + dw->set_count++; } else { @@ -574,6 +576,7 @@ static void dupe_listview_add(DupeWindow *dw, DupeItem *parent, DupeItem *child) DUPE_COLUMN_DIMENSIONS, text[DUPE_COLUMN_DIMENSIONS], DUPE_COLUMN_PATH, text[DUPE_COLUMN_PATH], DUPE_COLUMN_COLOR, color_set, + DUPE_COLUMN_SET, dw->set_count, -1); g_free(text[DUPE_COLUMN_RANK]); @@ -737,6 +740,8 @@ static void dupe_listview_select_dupes(DupeWindow *dw, DupeSelectType parents) GtkTreeSelection *selection; GtkTreeIter iter; gboolean valid; + gint set_count = 0; + gint set_count_last = -1; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dw->listview)); gtk_tree_selection_unselect_all(selection); @@ -747,10 +752,21 @@ static void dupe_listview_select_dupes(DupeWindow *dw, DupeSelectType parents) { DupeItem *di; - gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di, -1); - if ((dupe_match_find_parent(dw, di) == di) == (parents == DUPE_SELECT_GROUP1)) + gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di, DUPE_COLUMN_SET, &set_count, -1); + if (set_count != set_count_last) { - gtk_tree_selection_select_iter(selection, &iter); + set_count_last = set_count; + if (parents == DUPE_SELECT_GROUP1) + { + gtk_tree_selection_select_iter(selection, &iter); + } + } + else + { + if (parents == DUPE_SELECT_GROUP2) + { + gtk_tree_selection_select_iter(selection, &iter); + } } valid = gtk_tree_model_iter_next(store, &iter); } @@ -1168,6 +1184,10 @@ static gboolean dupe_match(DupeItem *a, DupeItem *b, DupeMatchType mask, gdouble if (a->fd->path == b->fd->path) return FALSE; + if (mask & DUPE_MATCH_ALL) + { + return TRUE; + } if (mask & DUPE_MATCH_PATH) { if (utf8_compare(a->fd->path, b->fd->path, TRUE) != 0) return FALSE; @@ -1412,6 +1432,13 @@ static void dupe_check_stop(DupeWindow *dw) dw->img_loader = NULL; } +static void dupe_check_stop_cb(GtkWidget *widget, gpointer data) +{ + DupeWindow *dw = data; + + dupe_check_stop(dw); +} + static void dupe_loader_done_cb(ImageLoader *il, gpointer data) { DupeWindow *dw = data; @@ -1803,6 +1830,8 @@ static void dupe_files_add(DupeWindow *dw, CollectionData *collection, CollectIn if (!di) return; + dupe_item_read_cache(di); + /* Ensure images in the lists have unique FileDatas */ GList *work; DupeItem *di_list; @@ -2046,6 +2075,7 @@ static void dupe_window_recompare(DupeWindow *dw) dupe_match_reset_list(dw->list); dupe_match_reset_list(dw->second_list); + dw->set_count = 0; dupe_check_start(dw); } @@ -2749,6 +2779,8 @@ enum { DUPE_MENU_COLUMN_MASK }; +static void dupe_listview_show_rank(GtkWidget *listview, gboolean rank); + static void dupe_menu_type_cb(GtkWidget *combo, gpointer data) { DupeWindow *dw = data; @@ -2761,6 +2793,14 @@ static void dupe_menu_type_cb(GtkWidget *combo, gpointer data) options->duplicates_match = dw->match_mask; + if (dw->match_mask & (DUPE_MATCH_SIM_HIGH | DUPE_MATCH_SIM_MED | DUPE_MATCH_SIM_LOW | DUPE_MATCH_SIM_CUSTOM)) + { + dupe_listview_show_rank(dw->listview, TRUE); + } + else + { + dupe_listview_show_rank(dw->listview, FALSE); + } dupe_window_recompare(dw); } @@ -2800,6 +2840,7 @@ static void dupe_menu_setup(DupeWindow *dw) dupe_menu_add_item(store, _("Similarity"), DUPE_MATCH_SIM_MED, dw); dupe_menu_add_item(store, _("Similarity (low)"), DUPE_MATCH_SIM_LOW, dw); dupe_menu_add_item(store, _("Similarity (custom)"), DUPE_MATCH_SIM_CUSTOM, dw); + dupe_menu_add_item(store, _("Show all"), DUPE_MATCH_ALL, dw); g_signal_connect(G_OBJECT(dw->combo), "changed", G_CALLBACK(dupe_menu_type_cb), dw); @@ -2867,6 +2908,7 @@ static void dupe_listview_add_column(DupeWindow *dw, GtkWidget *listview, gint n column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, title); gtk_tree_view_column_set_min_width(column, 4); + gtk_tree_view_column_set_sort_column_id(column, n); if (n != DUPE_COLUMN_RANK && n != DUPE_COLUMN_THUMB) @@ -2913,6 +2955,7 @@ static void dupe_listview_set_height(GtkWidget *listview, gboolean thumb) if (!column) return; gtk_tree_view_column_set_fixed_width(column, (thumb) ? options->thumbnails.max_width : 4); + gtk_tree_view_column_set_visible(column, thumb); list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column)); if (!list) return; @@ -2923,6 +2966,15 @@ static void dupe_listview_set_height(GtkWidget *listview, gboolean thumb) gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview)); } +static void dupe_listview_show_rank(GtkWidget *listview, gboolean rank) +{ + GtkTreeViewColumn *column; + + column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), DUPE_COLUMN_RANK - 1); + if (!column) return; + + gtk_tree_view_column_set_visible(column, rank); +} /* *------------------------------------------------------------------- @@ -3167,6 +3219,10 @@ static gboolean dupe_window_keypress_cb(GtkWidget *widget, GdkEventKey *event, g dupe_window_collection_from_selection(dw); } break; + case '0': + options->duplicates_select_type = DUPE_SELECT_NONE; + dupe_listview_select_dupes(dw, DUPE_SELECT_NONE); + break; case '1': options->duplicates_select_type = DUPE_SELECT_GROUP1; dupe_listview_select_dupes(dw, DUPE_SELECT_GROUP1); @@ -3224,6 +3280,7 @@ void dupe_window_clear(DupeWindow *dw) dupe_list_free(dw->list); dw->list = NULL; + dw->set_count = 0; dupe_match_reset_list(dw->second_list); @@ -3265,6 +3322,15 @@ void dupe_window_close(DupeWindow *dw) g_free(dw); } +static gint dupe_window_close_cb(GtkWidget *widget, gpointer data) +{ + DupeWindow *dw = data; + + dupe_window_close(dw); + + return TRUE; +} + static gint dupe_window_delete(GtkWidget *widget, GdkEvent *event, gpointer data) { DupeWindow *dw = data; @@ -3273,14 +3339,131 @@ static gint dupe_window_delete(GtkWidget *widget, GdkEvent *event, gpointer data return TRUE; } +static void dupe_help_cb(GtkAction *action, gpointer data) +{ + help_window_show("GuideImageSearchFindingDuplicates.html"); +} + +static gint default_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data) +{ + return 0; +} + +static gint column_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data) +{ + GtkTreeSortable *sortable = data; + gint ret = 0; + gchar *rank_str_a, *rank_str_b; + gint rank_int_a; + gint rank_int_b; + gint group_a; + gint group_b; + gint sort_column_id; + GtkSortType sort_order; + DupeItem *di_a; + DupeItem *di_b; + + gtk_tree_sortable_get_sort_column_id(sortable, &sort_column_id, &sort_order); + + gtk_tree_model_get(model, a, DUPE_COLUMN_RANK, &rank_str_a, DUPE_COLUMN_SET, &group_a, DUPE_COLUMN_POINTER, &di_a, -1); + + gtk_tree_model_get(model, b, DUPE_COLUMN_RANK, &rank_str_b, DUPE_COLUMN_SET, &group_b, DUPE_COLUMN_POINTER, &di_b, -1); + + if (group_a == group_b) + { + switch (sort_column_id) + { + case DUPE_COLUMN_NAME: + ret = utf8_compare(di_a->fd->name, di_b->fd->name, TRUE); + break; + case DUPE_COLUMN_SIZE: + if (di_a->fd->size == di_b->fd->size) + { + ret = 0; + } + else + { + ret = (di_a->fd->size > di_b->fd->size) ? 1 : -1; + } + break; + case DUPE_COLUMN_DATE: + if (di_a->fd->date == di_b->fd->date) + { + ret = 0; + } + else + { + ret = (di_a->fd->date > di_b->fd->date) ? 1 : -1; + } + break; + case DUPE_COLUMN_DIMENSIONS: + if ((di_a->width == di_b->width) && (di_a->height == di_b->height)) + { + ret = 0; + } + else + { + ret = ((di_a->width * di_a->height) > (di_b->width * di_b->height)) ? 1 : -1; + } + break; + case DUPE_COLUMN_RANK: + rank_int_a = atoi(rank_str_a); + rank_int_b = atoi(rank_str_b); + if (rank_int_a == 0) rank_int_a = 101; + if (rank_int_b == 0) rank_int_b = 101; + + if (rank_int_a == rank_int_b) + { + ret = 0; + } + else + { + ret = (rank_int_a > rank_int_b) ? 1 : -1; + } + break; + case DUPE_COLUMN_PATH: + ret = utf8_compare(di_a->fd->path, di_b->fd->path, TRUE); + break; + } + } + else if (group_a < group_b) + { + ret = (sort_order == GTK_SORT_ASCENDING) ? 1 : -1; + } + else + { + ret = (sort_order == GTK_SORT_ASCENDING) ? -1 : 1; + } + + return ret; +} + +static gboolean dupe_window_recompare_cb(gpointer data) +{ + DupeWindow *dw = data; + + dupe_window_recompare_cb(dw); +} + +static void column_clicked_cb(GtkWidget *widget, gpointer data) +{ + DupeWindow *dw = data; + + options->duplicates_match = DUPE_SELECT_NONE; + dupe_listview_select_dupes(dw, DUPE_SELECT_NONE); + dupe_window_recompare_cb, dw; +} + /* collection and files can be NULL */ DupeWindow *dupe_window_new() { DupeWindow *dw; GtkWidget *vbox; + GtkWidget *hbox; GtkWidget *scrolled; GtkWidget *frame; GtkWidget *status_box; + GtkWidget *button_box; GtkWidget *label; GtkWidget *button; GtkListStore *store; @@ -3347,24 +3530,41 @@ DupeWindow *dupe_window_new() gtk_table_attach_defaults(GTK_TABLE(dw->table), scrolled, 0, 2, 0, 1); gtk_widget_show(scrolled); - store = gtk_list_store_new(9, G_TYPE_POINTER, G_TYPE_STRING, GDK_TYPE_PIXBUF, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); + store = gtk_list_store_new(DUPE_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_INT); dw->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(store); + dw->sortable = GTK_TREE_SORTABLE(store); + + gtk_tree_sortable_set_sort_func(dw->sortable, DUPE_COLUMN_RANK, column_sort_cb, dw->sortable, NULL); + gtk_tree_sortable_set_sort_func(dw->sortable, DUPE_COLUMN_SET, default_sort_cb, dw->sortable, NULL); + gtk_tree_sortable_set_sort_func(dw->sortable, DUPE_COLUMN_THUMB, default_sort_cb, dw->sortable, NULL); + gtk_tree_sortable_set_sort_func(dw->sortable, DUPE_COLUMN_NAME, column_sort_cb, dw->sortable, NULL); + gtk_tree_sortable_set_sort_func(dw->sortable, DUPE_COLUMN_SIZE, column_sort_cb, dw->sortable, NULL); + gtk_tree_sortable_set_sort_func(dw->sortable, DUPE_COLUMN_DATE, column_sort_cb, dw->sortable, NULL); + gtk_tree_sortable_set_sort_func(dw->sortable, DUPE_COLUMN_DIMENSIONS, column_sort_cb, dw->sortable, NULL); + gtk_tree_sortable_set_sort_func(dw->sortable, DUPE_COLUMN_PATH, column_sort_cb, dw->sortable, NULL); + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dw->listview)); gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(dw->listview), TRUE); gtk_tree_view_set_enable_search(GTK_TREE_VIEW(dw->listview), FALSE); - dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_RANK, "", FALSE, TRUE); - dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_THUMB, "", TRUE, FALSE); + dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_RANK, _("Rank"), FALSE, TRUE); + dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_THUMB, _("Thumb"), TRUE, FALSE); dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_NAME, _("Name"), FALSE, FALSE); dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_SIZE, _("Size"), FALSE, TRUE); dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_DATE, _("Date"), FALSE, TRUE); dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_DIMENSIONS, _("Dimensions"), FALSE, FALSE); dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_PATH, _("Path"), FALSE, FALSE); + dupe_listview_add_column(dw, dw->listview, DUPE_COLUMN_SET, _("Set"), FALSE, FALSE); + + g_signal_connect(gtk_tree_view_get_column(GTK_TREE_VIEW(dw->listview), DUPE_COLUMN_RANK - 1), "clicked", (GCallback)column_clicked_cb, dw); + g_signal_connect(gtk_tree_view_get_column(GTK_TREE_VIEW(dw->listview), DUPE_COLUMN_NAME - 1), "clicked", (GCallback)column_clicked_cb, dw); + g_signal_connect(gtk_tree_view_get_column(GTK_TREE_VIEW(dw->listview), DUPE_COLUMN_SIZE - 1), "clicked", (GCallback)column_clicked_cb, dw); + g_signal_connect(gtk_tree_view_get_column(GTK_TREE_VIEW(dw->listview), DUPE_COLUMN_DATE - 1), "clicked", (GCallback)column_clicked_cb, dw); + g_signal_connect(gtk_tree_view_get_column(GTK_TREE_VIEW(dw->listview), DUPE_COLUMN_DIMENSIONS - 1), "clicked", (GCallback)column_clicked_cb, dw); + g_signal_connect(gtk_tree_view_get_column(GTK_TREE_VIEW(dw->listview), DUPE_COLUMN_PATH - 1), "clicked", (GCallback)column_clicked_cb, dw); gtk_container_add(GTK_CONTAINER(scrolled), dw->listview); gtk_widget_show(dw->listview); @@ -3407,15 +3607,30 @@ DupeWindow *dupe_window_new() pref_line(dw->second_vbox, GTK_ORIENTATION_HORIZONTAL); - status_box = pref_box_new(vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0); + status_box = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), status_box, FALSE, FALSE, 0); + gtk_widget_show(status_box); - label = gtk_label_new(_("Compare by:")); - gtk_box_pack_start(GTK_BOX(status_box), label, FALSE, FALSE, PREF_PAD_SPACE); - gtk_widget_show(label); + frame = gtk_frame_new(NULL); + DEBUG_NAME(frame); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(status_box), frame, TRUE, TRUE, 0); + gtk_widget_show(frame); - dupe_menu_setup(dw); - gtk_box_pack_start(GTK_BOX(status_box), dw->combo, FALSE, FALSE, 0); - gtk_widget_show(dw->combo); + dw->status_label = gtk_label_new(""); + gtk_container_add(GTK_CONTAINER(frame), dw->status_label); + gtk_widget_show(dw->status_label); + + dw->extra_label = gtk_progress_bar_new(); + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dw->extra_label), 0.0); +#if GTK_CHECK_VERSION(3,0,0) + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(dw->extra_label), ""); + gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(dw->extra_label), TRUE); +#endif + gtk_box_pack_start(GTK_BOX(status_box), dw->extra_label, FALSE, FALSE, PREF_PAD_SPACE); + gtk_widget_show(dw->extra_label); + + status_box = pref_box_new(vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0); dw->button_thumbs = gtk_check_button_new_with_label(_("Thumbnails")); dw->show_thumbs = options->duplicates_thumbnails; @@ -3425,6 +3640,31 @@ DupeWindow *dupe_window_new() gtk_box_pack_start(GTK_BOX(status_box), dw->button_thumbs, FALSE, FALSE, PREF_PAD_SPACE); gtk_widget_show(dw->button_thumbs); + label = gtk_label_new(_("Compare by:")); + gtk_box_pack_start(GTK_BOX(status_box), label, FALSE, FALSE, PREF_PAD_SPACE); + gtk_widget_show(label); + + dupe_menu_setup(dw); + gtk_box_pack_start(GTK_BOX(status_box), dw->combo, FALSE, FALSE, 0); + gtk_widget_show(dw->combo); + + label = gtk_label_new(_("Custom Threshold")); + gtk_box_pack_start(GTK_BOX(status_box), label, FALSE, FALSE, PREF_PAD_SPACE); + gtk_widget_show(label); + dw->custom_threshold = gtk_spin_button_new_with_range(1, 100, 1); + gtk_widget_set_tooltip_text(GTK_WIDGET(dw->custom_threshold), "Custom similarity threshold"); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(dw->custom_threshold), options->duplicates_similarity_threshold); + g_signal_connect(G_OBJECT(dw->custom_threshold), "value_changed", G_CALLBACK(dupe_window_custom_threshold_cb), dw); + gtk_box_pack_start(GTK_BOX(status_box), dw->custom_threshold, FALSE, FALSE, PREF_PAD_SPACE); + gtk_widget_show(dw->custom_threshold); + + 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); + dw->button_rotation_invariant = gtk_check_button_new_with_label(_("Ignore Rotation")); gtk_widget_set_tooltip_text(GTK_WIDGET(dw->button_rotation_invariant), "Ignore image orientation"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dw->button_rotation_invariant), options->rot_invariant_sim); @@ -3437,51 +3677,34 @@ DupeWindow *dupe_window_new() gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dw->second_set); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(dupe_second_set_toggle_cb), dw); - gtk_box_pack_end(GTK_BOX(status_box), button, FALSE, FALSE, PREF_PAD_SPACE); + gtk_box_pack_start(GTK_BOX(status_box), button, FALSE, FALSE, PREF_PAD_SPACE); gtk_widget_show(button); - status_box = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), status_box, FALSE, FALSE, 0); - gtk_widget_show(status_box); - - frame = gtk_frame_new(NULL); - DEBUG_NAME(frame); - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(status_box), frame, TRUE, TRUE, 0); - gtk_widget_show(frame); + button_box = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), button_box, FALSE, FALSE, 0); + gtk_widget_show(button_box); - dw->status_label = gtk_label_new(""); - gtk_container_add(GTK_CONTAINER(frame), dw->status_label); - gtk_widget_show(dw->status_label); + hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_SPACE); + gtk_box_pack_end(GTK_BOX(button_box), hbox, FALSE, FALSE, 0); + gtk_widget_show(hbox); - 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); + button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE, G_CALLBACK(dupe_help_cb), NULL); + gtk_container_add(GTK_CONTAINER(hbox), button); + gtk_widget_set_can_default(button, TRUE); 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); - dw->custom_threshold = gtk_spin_button_new_with_range(1, 100, 1); - gtk_widget_set_tooltip_text(GTK_WIDGET(dw->custom_threshold), "Custom similarity threshold"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(dw->custom_threshold), options->duplicates_similarity_threshold); - g_signal_connect(G_OBJECT(dw->custom_threshold), "value_changed", - G_CALLBACK(dupe_window_custom_threshold_cb), dw); - gtk_box_pack_start(GTK_BOX(status_box), dw->custom_threshold, FALSE, FALSE, PREF_PAD_SPACE); - gtk_widget_show(dw->custom_threshold); - - dw->extra_label = gtk_progress_bar_new(); - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dw->extra_label), 0.0); -#if GTK_CHECK_VERSION(3,0,0) - gtk_progress_bar_set_text(GTK_PROGRESS_BAR(dw->extra_label), ""); - gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(dw->extra_label), TRUE); -#endif - gtk_box_pack_end(GTK_BOX(status_box), dw->extra_label, FALSE, FALSE, 0); - gtk_widget_show(dw->extra_label); + button = pref_button_new(NULL, GTK_STOCK_STOP, NULL, FALSE, G_CALLBACK(dupe_check_stop_cb), dw); + gtk_container_add(GTK_CONTAINER(hbox), button); + gtk_widget_set_can_default(button, TRUE); + gtk_widget_show(button); + button = pref_button_new(NULL, GTK_STOCK_CLOSE, NULL, FALSE, G_CALLBACK(dupe_window_close_cb), dw); + gtk_container_add(GTK_CONTAINER(hbox), button); + gtk_widget_set_can_default(button, TRUE); + gtk_widget_grab_default(button); + gtk_widget_show(button); dupe_dnd_init(dw); /* order is important here, dnd_init should be seeing mouse @@ -3498,6 +3721,9 @@ DupeWindow *dupe_window_new() gtk_widget_show(dw->window); + dupe_listview_set_height(dw->listview, dw->show_thumbs); + g_signal_emit_by_name(G_OBJECT(dw->combo), "changed"); + dupe_window_update_count(dw, TRUE); dupe_window_update_progress(dw, NULL, 0.0, FALSE); diff --git a/src/dupe.h b/src/dupe.h index 3e970551..c96d60e2 100644 --- a/src/dupe.h +++ b/src/dupe.h @@ -38,7 +38,8 @@ typedef enum DUPE_MATCH_SIM_MED = 1 << 7, DUPE_MATCH_SIM_LOW = 1 << 8, DUPE_MATCH_SIM_CUSTOM = 1 << 9, - DUPE_MATCH_NAME_CI = 1 << 10 /* same as name, but case insensitive */ + DUPE_MATCH_NAME_CI = 1 << 10, /* same as name, but case insensitive */ + DUPE_MATCH_ALL = 1 << 11 } DupeMatchType; typedef enum @@ -114,6 +115,9 @@ struct _DupeWindow ImageLoader *img_loader; + GtkTreeSortable *sortable; + gint set_count; + /* second set comparison stuff */ gboolean second_set; /* second set enabled ? */ -- 2.20.1