Ref #714,412: Export duplicates data to file
authorColin Clark <colin.clark@cclark.uk>
Thu, 19 Dec 2019 12:18:19 +0000 (12:18 +0000)
committerColin Clark <colin.clark@cclark.uk>
Thu, 19 Dec 2019 12:18:19 +0000 (12:18 +0000)
Right-click option on duplicates window to export to comma- or
tab-delimited file.

src/dupe.c

index 23f9c32..5f9f9cb 100644 (file)
@@ -28,6 +28,7 @@
 #include "dnd.h"
 #include "editors.h"
 #include "filedata.h"
+#include "history_list.h"
 #include "image-load.h"
 #include "img-view.h"
 #include "layout.h"
@@ -94,6 +95,8 @@ static void dupe_dnd_init(DupeWindow *dw);
 
 static void dupe_notify_cb(FileData *fd, NotifyType type, gpointer data);
 
+static GtkWidget *submenu_add_export(GtkWidget *menu, GtkWidget **menu_item, GCallback func, gpointer data);
+static void dupe_pop_menu_export_cb(GtkWidget *widget, gpointer data);
 /*
  * ------------------------------------------------------------------
  * Window updates
@@ -2366,6 +2369,10 @@ static GtkWidget *dupe_menu_popup_main(DupeWindow *dw, DupeItem *di)
                                G_CALLBACK(dupe_menu_select_dupes_set2_cb), dw);
        menu_item_add_divider(menu);
 
+       submenu_add_export(menu, &item, G_CALLBACK(dupe_pop_menu_export_cb), dw);
+       gtk_widget_set_sensitive(item, on_row);
+       menu_item_add_divider(menu);
+
        editmenu_fd_list = dupe_window_get_fd_list(dw);
        g_signal_connect(G_OBJECT(menu), "destroy",
                         G_CALLBACK(dupe_menu_popup_destroy_cb), editmenu_fd_list);
@@ -3770,4 +3777,246 @@ static void dupe_notify_cb(FileData *fd, NotifyType type, gpointer data)
                }
 
 }
+
+/*
+ *-------------------------------------------------------------------
+ * Export duplicates data
+ *-------------------------------------------------------------------
+ */
+
+ typedef enum {
+       EXPORT_CSV = 0,
+       EXPORT_TSV
+} SeparatorType;
+
+typedef struct _ExportDupesData ExportDupesData;
+struct _ExportDupesData
+{
+       FileDialog *dialog;
+       SeparatorType separator;
+       DupeWindow *dupewindow;
+};
+
+static void export_duplicates_close(ExportDupesData *edd)
+{
+       if (edd->dialog) file_dialog_close(edd->dialog);
+       edd->dialog = NULL;
+}
+
+static void export_duplicates_data_cancel_cb(FileDialog *fdlg, gpointer data)
+{
+       ExportDupesData *edd = data;
+
+       export_duplicates_close(edd);
+}
+
+static void export_duplicates_data_save_cb(FileDialog *fdlg, gpointer data)
+{
+       ExportDupesData *edd = data;
+       GError *error = NULL;
+       GtkTreeModel *store;
+       GtkTreeIter iter;
+       DupeItem *di;
+       GFileOutputStream *gfstream;
+       GFile *out_file;
+       GString *output_string;
+       gchar *sep;
+       gchar* rank;
+       GList *work;
+       GtkTreeSelection *selection;
+       GList *slist;
+       gchar *thumb_cache;
+       gchar **rank_split;
+       GtkTreePath *tpath;
+       gboolean color_old = FALSE;
+       gboolean color_new = FALSE;
+       gint match_count;
+       gchar *name;
+
+       history_list_add_to_key("export_duplicates", fdlg->dest_path, -1);
+
+       out_file = g_file_new_for_path(fdlg->dest_path);
+
+       gfstream = g_file_replace(out_file, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &error);
+       if (error)
+               {
+               log_printf(_("Error creating Export duplicates data file: Error: %s\n"), error->message);
+               g_error_free(error);
+               return;
+               }
+
+       sep = g_strdup((edd->separator == EXPORT_CSV) ?  "," : "\t");
+       output_string = g_string_new(g_strjoin(sep, _("Match"), _("Group"), _("Similarity"), _("Set"), _("Thumbnail"), _("Name"), _("Size"), _("Date"), _("Width"), _("Height"), _("Path\n"), NULL));
+
+       selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(edd->dupewindow->listview));
+       slist = gtk_tree_selection_get_selected_rows(selection, &store);
+       work = slist;
+
+       tpath = work->data;
+       gtk_tree_model_get_iter(store, &iter, tpath);
+       gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DUPE_COLUMN_COLOR, &color_new, -1);
+       color_old = !color_new;
+       match_count = 0;
+
+       while (work)
+               {
+               tpath = work->data;
+               gtk_tree_model_get_iter(store, &iter, tpath);
+
+               gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DUPE_COLUMN_POINTER, &di, -1);
+
+               gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DUPE_COLUMN_COLOR, &color_new, -1);
+               if (color_new != color_old)
+                       {
+                       match_count++;
+                       }
+               color_old = color_new;
+               output_string = g_string_append(output_string, g_strdup_printf("%d", match_count));
+               output_string = g_string_append(output_string, sep);
+
+               if ((dupe_match_find_parent(edd->dupewindow, di) == di) == (DUPE_SELECT_GROUP1 == DUPE_SELECT_GROUP1))
+                       {
+                       output_string = g_string_append(output_string, "1");
+                       }
+               else
+                       {
+                       output_string = g_string_append(output_string, "2");
+                       }
+               output_string = g_string_append(output_string, sep);
+
+               gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DUPE_COLUMN_RANK, &rank, -1);
+               rank_split = g_strsplit_set(rank, " [(", -1);
+               if (rank_split[0] == NULL)
+                       {
+                       output_string = g_string_append(output_string, "");
+                       }
+               else
+                       {
+                       output_string = g_string_append(output_string, g_strdup_printf("%s", rank_split[0]));
+                       }
+               output_string = g_string_append(output_string, sep);
+               g_free(rank);
+               g_strfreev(rank_split);
+
+               output_string = g_string_append(output_string, g_strdup_printf("%d", (di->second + 1)));
+               output_string = g_string_append(output_string, sep);
+
+               thumb_cache = cache_find_location(CACHE_TYPE_THUMB, di->fd->path);
+               if (thumb_cache)
+                       {
+                       output_string = g_string_append(output_string, thumb_cache);
+                       g_free(thumb_cache);
+                       }
+               else
+                       {
+                       output_string = g_string_append(output_string, "");
+                       }
+               output_string = g_string_append(output_string, sep);
+
+               gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DUPE_COLUMN_NAME, &name, -1);
+               output_string = g_string_append(output_string, name);
+               output_string = g_string_append(output_string, sep);
+               g_free(name);
+
+               output_string = g_string_append(output_string, g_strdup_printf("%ld", di->fd->size));
+               output_string = g_string_append(output_string, sep);
+               output_string = g_string_append(output_string, text_from_time(di->fd->date));
+               output_string = g_string_append(output_string, sep);
+               output_string = g_string_append(output_string, g_strdup_printf("%d", (di->width ? di->width : 0)));
+               output_string = g_string_append(output_string, sep);
+               output_string = g_string_append(output_string, g_strdup_printf("%d", (di->height ? di->height : 0)));
+               output_string = g_string_append(output_string, sep);
+               output_string = g_string_append(output_string, di->fd->path);
+               output_string = g_string_append_c(output_string, '\n');
+
+               work = work->next;
+               }
+
+       g_output_stream_write(G_OUTPUT_STREAM(gfstream), output_string->str, strlen(output_string->str), NULL, &error);
+
+       g_free(sep);
+       g_string_free(output_string, TRUE);
+       g_object_unref(gfstream);
+       g_object_unref(out_file);
+
+       export_duplicates_close(edd);
+}
+
+static void pop_menu_export(GList *selection_list, gpointer dupe_window, gpointer data)
+{
+       const gint index = GPOINTER_TO_INT(data);
+       DupeWindow *dw = dupe_window;
+       gchar *title = "Export duplicates data";
+       gchar *default_path = "/tmp/";
+       gchar *file_extension;
+       const gchar *stock_id;
+       ExportDupesData *edd;
+       const gchar *previous_path;
+
+       edd = g_new0(ExportDupesData, 1);
+       edd->dialog = file_util_file_dlg(title, "export_duplicates", NULL, export_duplicates_data_cancel_cb, edd);
+
+       switch (index)
+               {
+               case EXPORT_CSV:
+                       edd->separator = EXPORT_CSV;
+                       file_extension = g_strdup(".csv");
+                       break;
+               case EXPORT_TSV:
+                       edd->separator = EXPORT_TSV;
+                       file_extension = g_strdup(".tsv");
+                       break;
+               default:
+                       return;
+               }
+
+       stock_id = GTK_STOCK_SAVE;
+
+       generic_dialog_add_message(GENERIC_DIALOG(edd->dialog), NULL, title, NULL, FALSE);
+       file_dialog_add_button(edd->dialog, stock_id, NULL, export_duplicates_data_save_cb, TRUE);
+
+       previous_path = history_list_find_last_path_by_key("export_duplicates");
+
+       file_dialog_add_path_widgets(edd->dialog, default_path, previous_path, "export_duplicates", file_extension, _("Export Files"));
+
+       edd->dupewindow = dw;
+
+       gtk_widget_show(GENERIC_DIALOG(edd->dialog)->dialog);
+
+       g_free(file_extension);
+}
+
+static void dupe_pop_menu_export_cb(GtkWidget *widget, gpointer data)
+{
+       DupeWindow *dw;
+       GList *selection_list;
+
+       dw = submenu_item_get_data(widget);
+       selection_list = dupe_listview_get_selection(dw, dw->listview);
+       pop_menu_export(selection_list, dw, data);
+
+       filelist_free(selection_list);
+}
+
+static GtkWidget *submenu_add_export(GtkWidget *menu, GtkWidget **menu_item, GCallback func, gpointer data)
+{
+       GtkWidget *item;
+       GtkWidget *submenu;
+
+       item = menu_item_add(menu, _("Export"), NULL, NULL);
+
+       submenu = gtk_menu_new();
+       g_object_set_data(G_OBJECT(submenu), "submenu_data", data);
+
+       menu_item_add_stock_sensitive(submenu, _("Export to csv"),
+                                       GTK_STOCK_INDEX, TRUE, G_CALLBACK(func), GINT_TO_POINTER(0));
+       menu_item_add_stock_sensitive(submenu, _("Export to tab-delimited"),
+                                       GTK_STOCK_INDEX, TRUE, G_CALLBACK(func), GINT_TO_POINTER(1));
+
+       gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
+       if (menu_item) *menu_item = item;
+
+       return submenu;
+}
+
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */