changeset 2582:03014a1eb7e7

Right-click menus - collections On all relevent right-click menus include a sub-menu to store an image selection to either a new or existing collection. On Collection window right-click menu, remove "Append from file list" - that can be achieved with "Append from file selection"
author Colin Clark <colin.clark@cclark.uk>
date Fri, 18 Aug 2017 14:25:36 +0100
parents e6847b39721f
children 6e92c0ad76f2
files src/collect-io.c src/collect-io.h src/collect-table.c src/collect.c src/collect.h src/dupe.c src/img-view.c src/layout_image.c src/main.c src/menu.c src/menu.h src/pan-view/pan-view.c src/search.c src/typedefs.h src/view_file/view_file.c
diffstat 15 files changed, 363 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/src/collect-io.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/collect-io.c	Fri Aug 18 14:25:36 2017 +0100
@@ -969,6 +969,75 @@
 		case FILEDATA_CHANGE_WRITE_METADATA:
 			break;
 		}
+}
 
+static gint collection_manager_sort_cb(gconstpointer a, gconstpointer b)
+{
+	const gchar *char_a = a;
+	const gchar *char_b = b;
+
+	return g_strcmp0(char_a, char_b);
+}
+
+/* Creates sorted list of collections
+ * Inputs: none
+ * Outputs: list of type gchar
+ * 			sorted list of collections names excluding extension
+ * 			sorted list of collections names including extension
+ * 			sorted list of collection paths
+ * Return: none
+ * Used lists must be freed with string_list_free()
+ */
+void collect_manager_list(GList **names_exc, GList **names_inc, GList **paths)
+{
+	FileData *dir_fd;
+	GList *list = NULL;
+	gchar *name;
+	FileData *fd;
+	gchar *filename;
+
+	if (names_exc == NULL && names_inc == NULL && paths == NULL)
+		{
+		return;
+		}
+
+	dir_fd = file_data_new_dir((get_collections_dir()));
+
+	filelist_read(dir_fd, &list, NULL);
+
+	while (list)
+		{
+		fd = list->data;
+		filename = g_strdup(filename_from_path((gchar *)fd->path));
+
+		if (file_extension_match(filename, GQ_COLLECTION_EXT))
+			{
+			name = remove_extension_from_path(filename);
+
+			if (names_exc != NULL)
+				{
+				*names_exc = g_list_insert_sorted(*names_exc, g_strdup(name),
+											collection_manager_sort_cb);
+				*names_exc = g_list_first(*names_exc);
+				}
+			if (names_inc != NULL)
+				{
+				*names_inc = g_list_insert_sorted(*names_inc,filename,
+											collection_manager_sort_cb);
+				*names_inc = g_list_first(*names_inc);
+				}
+			if (paths != NULL)
+				{
+				*paths = g_list_insert_sorted(*paths,fd->path,
+											collection_manager_sort_cb);
+				*paths = g_list_first(*paths);
+				}
+			g_free(name);
+			}
+		list = list->next;
+		g_free(filename);
+		}
+
+	filelist_free(list);
 }
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/collect-io.h	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/collect-io.h	Fri Aug 18 14:25:36 2017 +0100
@@ -57,7 +57,7 @@
 void collect_manager_flush(void);
 
 void collect_manager_notify_cb(FileData *fd, NotifyType type, gpointer data);
-
+void collect_manager_list(GList **names_exc, GList **names_inc, GList **paths);
 
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/collect-table.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/collect-table.c	Fri Aug 18 14:25:36 2017 +0100
@@ -828,20 +828,6 @@
 	g_list_free(list);
 }
 
-static void collection_table_popup_add_filelist_cb(GtkWidget *widget, gpointer data)
-{
-	CollectTable *ct = data;
-	GList *list;
-
-	list = layout_list(NULL);
-
-	if (list)
-		{
-		collection_table_add_filelist(ct, list);
-		filelist_free(list);
-		}
-}
-
 static void collection_table_popup_add_file_selection_cb(GtkWidget *widget, gpointer data)
 {
 	CollectTable *ct = data;
@@ -929,8 +915,6 @@
 
 	menu_item_add_stock(menu, _("Append from file selection"), GTK_STOCK_ADD,
 			G_CALLBACK(collection_table_popup_add_file_selection_cb), ct);
-	menu_item_add_stock(menu, _("Append from file list"), GTK_STOCK_ADD,
-			G_CALLBACK(collection_table_popup_add_filelist_cb), ct);
 	menu_item_add_stock(menu, _("Append from collection..."), GTK_STOCK_OPEN,
 			G_CALLBACK(collection_table_popup_add_collection_cb), ct);
 	menu_item_add_divider(menu);
--- a/src/collect.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/collect.c	Fri Aug 18 14:25:36 2017 +0100
@@ -44,8 +44,12 @@
 #define COLLECT_DEF_WIDTH 440
 #define COLLECT_DEF_HEIGHT 450
 
-static GList *collection_list = NULL;
-static GList *collection_window_list = NULL;
+/* list of paths to collections */
+
+/* List of currently open Collections*/
+static GList *collection_list = NULL; /* type CollectionData */
+/* List of currently open Collection windows*/
+static GList *collection_window_list = NULL; /* type CollectWindow */
 
 static void collection_window_get_geometry(CollectWindow *cw);
 static void collection_window_refresh(CollectWindow *cw);
@@ -307,6 +311,57 @@
 	return NULL;
 }
 
+/* Checks string for existence of Collection.
+ * The parameter is the filename,
+ * with or without extension of any collection
+ *
+ * Returns: full pathname if found or NULL
+ * Return value must be freed with g_free()
+ */
+gchar *collection_path(gchar *param)
+{
+	gchar *path = NULL;
+	gchar *full_name = NULL;
+
+	if (file_extension_match(param, GQ_COLLECTION_EXT))
+		{
+		path = g_build_filename(get_collections_dir(), param, NULL);
+		}
+	else if (file_extension_match(param, NULL))
+		{
+		full_name = g_strconcat(param, GQ_COLLECTION_EXT, NULL);
+		path = g_build_filename(get_collections_dir(), full_name, NULL);
+		}
+
+	if (!isfile(path))
+		{
+		g_free(path);
+		path = NULL;
+		}
+
+	g_free(full_name);
+	return path;
+}
+
+/* Checks input string for existence of Collection.
+ * The parameter is the filename
+ * with or without extension of any collection
+ * 
+ * Returns TRUE if found
+ */
+gboolean is_collection(gchar *param)
+{
+	gchar *name = NULL;
+
+	name = collection_path(param);
+	if (name)
+		{
+		g_free(name);
+		return TRUE;
+		}
+	return FALSE;
+}
+
 /*
  *-------------------------------------------------------------------
  * please use these to actually add/remove stuff
--- a/src/collect.h	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/collect.h	Fri Aug 18 14:25:36 2017 +0100
@@ -86,6 +86,7 @@
 CollectWindow *collection_window_find_by_path(const gchar *path);
 gboolean collection_window_modified_exists(void);
 
-
+gboolean is_collection(gchar *param);
+gchar *collection_path(gchar *param);
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/dupe.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/dupe.c	Fri Aug 18 14:25:36 2017 +0100
@@ -2309,12 +2309,30 @@
 	return list;
 }
 
+/* Add file selection list to a collection
+ * Called from a right-click menu
+ * Inputs:
+ * data: index to the collection list menu item selected, or -1 for new collection
+ */
+static void dupe_pop_menu_collections_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_collections(selection_list, data);
+
+	filelist_free(selection_list);
+}
+
 static GtkWidget *dupe_menu_popup_main(DupeWindow *dw, DupeItem *di)
 {
 	GtkWidget *menu;
 	GtkWidget *item;
 	gint on_row;
 	GList *editmenu_fd_list;
+	GtkWidget *submenu;
 
 	on_row = (di != NULL);
 
@@ -2340,8 +2358,11 @@
 			 G_CALLBACK(dupe_menu_popup_destroy_cb), editmenu_fd_list);
 	submenu_add_edit(menu, &item, G_CALLBACK(dupe_menu_edit_cb), dw, editmenu_fd_list);
 	if (!on_row) gtk_widget_set_sensitive(item, FALSE);
-	menu_item_add_stock_sensitive(menu, _("Add to new collection"), GTK_STOCK_INDEX, on_row,
-				G_CALLBACK(dupe_menu_collection_cb), dw);
+
+	submenu = submenu_add_collections(menu, &item,
+								G_CALLBACK(dupe_pop_menu_collections_cb), dw);
+	gtk_widget_set_sensitive(item, on_row);
+
 	menu_item_add_stock_sensitive(menu, _("Print..."), GTK_STOCK_PRINT, on_row,
 				G_CALLBACK(dupe_menu_print_cb), dw);
 	menu_item_add_divider(menu);
--- a/src/img-view.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/img-view.c	Fri Aug 18 14:25:36 2017 +0100
@@ -1254,9 +1254,31 @@
 	return list;
 }
 
+/* Add file selection list to a collection
+ * Called from a right-click submenu
+ * Inputs:
+ * data: index to the collection list menu item selected, or -1 for new collection
+ */
+static void image_pop_menu_collections_cb(GtkWidget *widget, gpointer data)
+{
+	ViewWindow *vw;
+	ImageWindow *imd;
+	FileData *fd;
+	GList *selection_list = NULL;
+
+	vw = submenu_item_get_data(widget);
+	imd = view_window_active_image(vw);
+	fd = image_get_fd(imd);
+	selection_list = g_list_append(selection_list, fd);
+	pop_menu_collections(selection_list, data);
+
+	filelist_free(selection_list);
+}
+
 static GtkWidget *view_popup_menu(ViewWindow *vw)
 {
 	GtkWidget *menu;
+	GtkWidget *submenu;
 	GtkWidget *item;
 	GList *editmenu_fd_list;
 
@@ -1291,6 +1313,11 @@
 
 	menu_item_add_divider(menu);
 
+	submenu = submenu_add_collections(menu, &item,
+				G_CALLBACK(image_pop_menu_collections_cb), vw);
+	gtk_widget_set_sensitive(item, TRUE);
+	menu_item_add_divider(menu);
+
 	if (vw->ss)
 		{
 		menu_item_add(menu, _("_Stop slideshow"), G_CALLBACK(view_slideshow_stop_cb), vw);
--- a/src/layout_image.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/layout_image.c	Fri Aug 18 14:25:36 2017 +0100
@@ -642,6 +642,23 @@
 	return list;
 }
 
+/* Add file selection list to a collection
+ * Called from a right-click submenu
+ * Inputs:
+ * data: index to the collection list menu item selected, or -1 for new collection
+ */
+static void layout_pop_menu_collections_cb(GtkWidget *widget, gpointer data)
+{
+	LayoutWindow *lw;
+	GList *selection_list = NULL;
+
+	lw = submenu_item_get_data(widget);
+	selection_list = g_list_append(selection_list, layout_image_get_fd(lw));
+	pop_menu_collections(selection_list, data);
+
+	filelist_free(selection_list);
+}
+
 static GtkWidget *layout_image_pop_menu(LayoutWindow *lw)
 {
 	GtkWidget *menu;
@@ -691,7 +708,11 @@
 	if (!path) gtk_widget_set_sensitive(item, FALSE);
 	item = menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(li_pop_menu_delete_cb), lw);
 	if (!path) gtk_widget_set_sensitive(item, FALSE);
-
+	menu_item_add_divider(menu);
+
+	submenu = submenu_add_collections(menu, &item,
+				G_CALLBACK(layout_pop_menu_collections_cb), lw);
+	gtk_widget_set_sensitive(item, TRUE);
 	menu_item_add_divider(menu);
 
 	if (layout_image_slideshow_active(lw))
--- a/src/main.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/main.c	Fri Aug 18 14:25:36 2017 +0100
@@ -214,32 +214,6 @@
 	parse_command_line_add_file(file_path, path, file, list, collection_list);
 }
 
-static gboolean is_collection(gchar *cmd_param)
-{
-	gchar *path = NULL;
-	gchar *full_name = NULL;
-	gboolean result = FALSE;
-
-	if (file_extension_match(cmd_param, GQ_COLLECTION_EXT))
-		{
-		path = g_build_filename(get_collections_dir(), cmd_param, NULL);
-		}
-	else if (file_extension_match(cmd_param, NULL))
-		{
-		full_name = g_strconcat(cmd_param, GQ_COLLECTION_EXT, NULL);
-		path = g_build_filename(get_collections_dir(), full_name, NULL);
-		}
-
-	if (isfile(path))
-		{
-		result = TRUE;
-		}
-
-	g_free(path);
-	g_free(full_name);
-	return result;
-}
-
 static void parse_command_line(gint argc, gchar *argv[])
 {
 	GList *list = NULL;
@@ -285,21 +259,11 @@
 			else if (is_collection(cmd_line))
 				{
 				gchar *path = NULL;
-				gchar *full_name = NULL;
 
-				if (file_extension_match(cmd_line, GQ_COLLECTION_EXT))
-					{
-					path = g_build_filename(get_collections_dir(), cmd_line, NULL);
-					}
-				else
-					{
-					full_name = g_strconcat(cmd_line, GQ_COLLECTION_EXT, NULL);
-					path = g_build_filename(get_collections_dir(), full_name, NULL);
-					}
+				path = collection_path(cmd_line);
 				parse_command_line_process_file(path, &command_line->path, &command_line->file,
 								&list, &command_line->collection_list, &first_dir);
 				g_free(path);
-				g_free(full_name);
 				}
 			else if (strncmp(cmd_line, "--debug", 7) == 0 && (cmd_line[7] == '\0' || cmd_line[7] == '='))
 				{
--- a/src/menu.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/menu.c	Fri Aug 18 14:25:36 2017 +0100
@@ -25,6 +25,8 @@
 #include "cache_maint.h"
 #include "collect.h"
 #include "collect-dlg.h"
+#include "collect-io.h"
+#include "collect-table.h"
 #include "dupe.h"
 #include "editors.h"
 #include "filedata.h"
@@ -379,4 +381,92 @@
 {
 	return real_submenu_add_alter(menu, func, data, NULL);
 }
+
+/*
+ *-----------------------------------------------------------------------------
+ * collections
+ *-----------------------------------------------------------------------------
+ */
+
+/* Add submenu consisting of "New collection", and list of existing collections
+ * to a right-click menu.
+ * Used by image windows
+ */
+static void add_collection_list(GtkWidget *menu, GCallback func,
+								GList *collection_list, gpointer data)
+{
+	GList *work;
+	gint index = 0; /* index to existing collection list menu item selected */
+	GtkWidget *item;
+
+	work = collection_list;
+	while (work)
+		{
+		const gchar *collection_name = work->data;
+
+		item = menu_item_add(menu, collection_name, func,
+													GINT_TO_POINTER(index));
+		work = work->next;
+		index++;
+		}
+}
+
+GtkWidget *submenu_add_collections(GtkWidget *menu, GtkWidget **menu_item,
+										GCallback func, gpointer data)
+{
+	GtkWidget *item;
+	GtkWidget *submenu;
+	GList *collection_list = NULL;
+
+	item = menu_item_add(menu, _("_Add to Collection"), NULL, NULL);
+
+	submenu = gtk_menu_new();
+	g_object_set_data(G_OBJECT(submenu), "submenu_data", data);
+
+	menu_item_add_stock_sensitive(submenu, _("New collection"),
+					GTK_STOCK_INDEX, TRUE, G_CALLBACK(func), GINT_TO_POINTER(-1));
+	menu_item_add_divider(submenu);
+
+	collect_manager_list(&collection_list,NULL,NULL);
+	add_collection_list(submenu, func, collection_list, data);
+
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
+	if (menu_item) *menu_item = item;
+
+	g_list_free(collection_list);
+
+	return submenu;
+}
+
+/* Add file selection list to a collection
+ * Called from a right-click submenu
+ * Inputs:
+ * selection_list: GList of FileData
+ * data: index to the collection list menu item selected, or -1 for new collection
+ */
+void pop_menu_collections(GList *selection_list, gpointer data)
+{
+	CollectWindow *cw;
+	gchar *collection_name;
+	GList *collection_list = NULL;
+	gchar *name;
+	const gint index = GPOINTER_TO_INT(data);
+
+	if (index >= 0)
+		{
+		collect_manager_list(&collection_list, NULL, NULL);
+		collection_name = g_list_nth_data(collection_list, index);
+		name = collection_path(collection_name);
+		cw = collection_window_new(name);
+		g_free(name);
+		string_list_free(collection_list);
+		}
+	else
+		{
+		cw = collection_window_new(NULL);
+		}
+
+	collection_table_add_filelist(cw->table, selection_list);
+}
+
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/menu.h	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/menu.h	Fri Aug 18 14:25:36 2017 +0100
@@ -37,6 +37,8 @@
 gchar *alter_type_get_text(AlterType type);
 GtkWidget *submenu_add_alter(GtkWidget *menu, GCallback func, gpointer data);
 
-
+GtkWidget *submenu_add_collections(GtkWidget *menu, GtkWidget **menu_item,
+										GCallback func, gpointer data);
+void pop_menu_collections(GList *selection_list, gpointer data);
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/pan-view/pan-view.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/pan-view/pan-view.c	Fri Aug 18 14:25:36 2017 +0100
@@ -2196,6 +2196,23 @@
 	return list;
 }
 
+/* Add file selection list to a collection
+ * Called from a right-click submenu
+ * Inputs:
+ * data: index to the collection list menu item selected, or -1 for new collection
+ */
+static void pan_pop_menu_collections_cb(GtkWidget *widget, gpointer data)
+{
+	PanWindow *pw;
+	GList *selection_list = NULL;
+
+	pw = submenu_item_get_data(widget);
+	selection_list = g_list_append(selection_list, pan_menu_click_fd(pw));
+	pop_menu_collections(selection_list, data);
+
+	filelist_free(selection_list);
+}
+
 static GtkWidget *pan_popup_menu(PanWindow *pw)
 {
 	GtkWidget *menu;
@@ -2239,6 +2256,13 @@
 				      G_CALLBACK(pan_delete_cb), pw);
 
 	menu_item_add_divider(menu);
+
+	submenu = submenu_add_collections(menu, &item,
+				G_CALLBACK(pan_pop_menu_collections_cb), pw);
+	gtk_widget_set_sensitive(item, TRUE);
+	menu_item_add_divider(menu);
+
+
 	item = menu_item_add_check(menu, _("Sort by E_xif date"), pw->exif_date_enable,
 				   G_CALLBACK(pan_exif_date_toggle_cb), pw);
 	gtk_widget_set_sensitive(item, (pw->layout == PAN_LAYOUT_TIMELINE || pw->layout == PAN_LAYOUT_CALENDAR));
--- a/src/search.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/search.c	Fri Aug 18 14:25:36 2017 +0100
@@ -1030,11 +1030,29 @@
 	filelist_free(editmenu_fd_list);
 }
 
+/* Add file selection list to a collection
+ * Called from a right-click submenu
+ * Inputs:
+ * data: index to the collection list menu item selected, or -1 for new collection
+ */
+static void search_pop_menu_collections_cb(GtkWidget *widget, gpointer data)
+{
+	SearchData *sd;
+	GList *selection_list;
+
+	sd = submenu_item_get_data(widget);
+	selection_list = search_result_selection_list(sd);
+	pop_menu_collections(selection_list, data);
+
+	filelist_free(selection_list);
+}
+
 static GtkWidget *search_result_menu(SearchData *sd, gboolean on_row, gboolean empty)
 {
 	GtkWidget *menu;
 	GtkWidget *item;
 	GList *editmenu_fd_list;
+	GtkWidget *submenu;
 
 	menu = popup_menu_short_lived();
 
@@ -1054,8 +1072,11 @@
 			 G_CALLBACK(search_result_menu_destroy_cb), editmenu_fd_list);
 	submenu_add_edit(menu, &item, G_CALLBACK(sr_menu_edit_cb), sd, editmenu_fd_list);
 	if (!on_row) gtk_widget_set_sensitive(item, FALSE);
-	menu_item_add_stock_sensitive(menu, _("Add to new collection"), GTK_STOCK_INDEX, on_row,
-				      G_CALLBACK(sr_menu_collection_cb), sd);
+
+	submenu = submenu_add_collections(menu, &item,
+				G_CALLBACK(search_pop_menu_collections_cb), sd);
+	gtk_widget_set_sensitive(item, on_row);
+
 	menu_item_add_stock_sensitive(menu, _("Print..."), GTK_STOCK_PRINT, on_row,
 				      G_CALLBACK(sr_menu_print_cb), sd);
 	menu_item_add_divider(menu);
--- a/src/typedefs.h	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/typedefs.h	Fri Aug 18 14:25:36 2017 +0100
@@ -437,7 +437,6 @@
 	GtkWidget *window;
 	CollectTable *table;
 	GtkWidget *status_box;
-	GList *list;
 
 	GtkWidget *close_dialog;
 
--- a/src/view_file/view_file.c	Wed Aug 16 09:42:42 2017 +0100
+++ b/src/view_file/view_file.c	Fri Aug 18 14:25:36 2017 +0100
@@ -504,6 +504,23 @@
 	vf->editmenu_fd_list = NULL;
 }
 
+/* Add file selection list to a collection
+ * Called from a right-click menu
+ * Inputs:
+ * data: index to the collection list menu item selected, or -1 for new collection
+ */
+static void vf_pop_menu_collections_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf;
+	GList *selection_list;
+
+	vf = submenu_item_get_data(widget);
+	selection_list = vf_selection_get_list(vf);
+	pop_menu_collections(selection_list, data);
+
+	filelist_free(selection_list);
+}
+
 GtkWidget *vf_pop_menu(ViewFile *vf)
 {
 	GtkWidget *menu;
@@ -603,8 +620,10 @@
 	menu_item_add_stock_sensitive(menu, _("_Find duplicates..."), GTK_STOCK_FIND, active,
 				G_CALLBACK(vf_pop_menu_duplicates_cb), vf);
 	menu_item_add_divider(menu);
-	menu_item_add_stock_sensitive(menu, _("Add to new collection"), GTK_STOCK_INDEX, active,
-				G_CALLBACK(vf_pop_menu_add_collection_cb), vf);
+
+	submenu = submenu_add_collections(menu, &item,
+				G_CALLBACK(vf_pop_menu_collections_cb), vf);
+	gtk_widget_set_sensitive(item, active);
 	menu_item_add_divider(menu);
 
 	submenu = submenu_add_sort(NULL, G_CALLBACK(vf_pop_menu_sort_cb), vf,