changeset 15925:f8c16848b76d

Allow selecting multiple files from the file-select dialog. You need to tag the files by pressing 't' to select the files. It is possible to tag files from different locations, ie. when you change the directory, the tags are remembered. You can untag a selection by pressing 't' again. To untag all selections, press 'c'.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Mon, 26 Mar 2007 01:19:59 +0000
parents b4086a92568f
children 5f9b7e2652f0 5b065c7ff5cd
files finch/libgnt/gntfilesel.c finch/libgnt/gntfilesel.h
diffstat 2 files changed, 112 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/finch/libgnt/gntfilesel.c	Mon Mar 26 00:44:09 2007 +0000
+++ b/finch/libgnt/gntfilesel.c	Mon Mar 26 01:19:59 2007 +0000
@@ -28,6 +28,10 @@
 {
 	GntFileSel *sel = GNT_FILE_SEL(widget);
 	g_free(sel->current);
+	if (sel->tags) {
+		g_list_foreach(sel->tags, (GFunc)g_free, NULL);
+		g_list_free(sel->tags);
+	}
 }
 
 static char *
@@ -73,6 +77,15 @@
 }
 
 static gboolean
+is_tagged(GntFileSel *sel, const char *f)
+{
+	char *ret = g_strdup_printf("%s%s%s", sel->current, sel->current[1] ? G_DIR_SEPARATOR_S : "", f);
+	gboolean find = g_list_find_custom(sel->tags, ret, (GCompareFunc)g_utf8_collate) != NULL;
+	g_free(ret);
+	return find;
+}
+
+static gboolean
 location_changed(GntFileSel *sel, GError **err)
 {
 	GDir *dir;
@@ -109,15 +122,19 @@
 		if (stat(fp, &st)) {
 			g_printerr("Error stating location %s\n", fp);
 		} else {
-			if (S_ISDIR(st.st_mode))
+			if (S_ISDIR(st.st_mode)) {
 				gnt_tree_add_row_after(GNT_TREE(sel->dirs), g_strdup(str),
 						gnt_tree_create_row(GNT_TREE(sel->dirs), str), NULL, NULL);
-			else if (!sel->dirsonly) {
+				if (sel->multiselect && sel->dirsonly && is_tagged(sel, str))
+					gnt_tree_set_row_flags(GNT_TREE(sel->dirs), (gpointer)str, GNT_TEXT_FLAG_BOLD);
+			} else if (!sel->dirsonly) {
 				char size[128];
 				snprintf(size, sizeof(size), "%ld", (long)st.st_size);
 
 				gnt_tree_add_row_after(GNT_TREE(sel->files), g_strdup(str),
 						gnt_tree_create_row(GNT_TREE(sel->files), str, size, ""), NULL, NULL);
+				if (sel->multiselect && is_tagged(sel, str))
+					gnt_tree_set_row_flags(GNT_TREE(sel->files), (gpointer)str, GNT_TEXT_FLAG_BOLD);
 			}
 		}
 		g_free(fp);
@@ -131,7 +148,6 @@
 dir_key_pressed(GntTree *tree, const char *key, GntFileSel *sel)
 {
 	if (strcmp(key, "\r") == 0) {
-		/* XXX: if we are moving up the tree, make sure the current node is selected after the redraw */
 		char *str = g_strdup(gnt_tree_get_selection_data(tree));
 		char *path = g_build_filename(sel->current, str, NULL);
 		char *dir = g_path_get_basename(sel->current);
@@ -225,7 +241,7 @@
 
 	vbox = gnt_vbox_new(FALSE);
 	gnt_box_set_pad(GNT_BOX(vbox), 0);
-	gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_LEFT);
+	gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_MID);
 
 	/* The dir. and files list */
 	hbox = gnt_hbox_new(FALSE);
@@ -253,9 +269,64 @@
 	update_location(sel);
 }
 
+static gboolean
+toggle_tag_selection(GntBindable *bind, GList *null)
+{
+	GntFileSel *sel = GNT_FILE_SEL(bind);
+	char *str;
+	GList *find;
+	char *file;
+	GntWidget *tree;
+
+	if (!sel->multiselect)
+		return FALSE;
+	tree = sel->dirsonly ? sel->dirs : sel->files;
+	if (!gnt_widget_has_focus(tree))
+		return FALSE;
+
+	file = gnt_tree_get_selection_data(sel->dirsonly ? GNT_TREE(sel->dirs) : GNT_TREE(sel->files));
+
+	str = gnt_file_sel_get_selected_file(sel);
+	if ((find = g_list_find_custom(sel->tags, str, (GCompareFunc)g_utf8_collate)) != NULL) {
+		g_free(find->data);
+		sel->tags = g_list_delete_link(sel->tags, find);
+		gnt_tree_set_row_flags(GNT_TREE(tree), file, GNT_TEXT_FLAG_NORMAL);
+		g_free(str);
+	} else {
+		sel->tags = g_list_prepend(sel->tags, str);
+		gnt_tree_set_row_flags(GNT_TREE(tree), file, GNT_TEXT_FLAG_BOLD);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+clear_tags(GntBindable *bind, GList *null)
+{
+	GntFileSel *sel = GNT_FILE_SEL(bind);
+	GntWidget *tree;
+	GList *iter;
+
+	if (!sel->multiselect)
+		return FALSE;
+	tree = sel->dirsonly ? sel->dirs : sel->files;
+	if (!gnt_widget_has_focus(tree))
+		return FALSE;
+
+	g_list_foreach(sel->tags, (GFunc)g_free, NULL);
+	g_list_free(sel->tags);
+	sel->tags = NULL;
+
+	for (iter = GNT_TREE(tree)->list; iter; iter = iter->next)
+		gnt_tree_set_row_flags(GNT_TREE(tree), iter->data, GNT_TEXT_FLAG_NORMAL);
+
+	return TRUE;
+}
+
 static void
 gnt_file_sel_class_init(GntFileSelClass *klass)
 {
+	GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass);
 	GntWidgetClass *kl = GNT_WIDGET_CLASS(klass);
 	parent_class = GNT_WINDOW_CLASS(klass);
 	kl->destroy = gnt_file_sel_destroy;
@@ -270,6 +341,9 @@
 					 NULL, NULL,
 					 gnt_closure_marshal_VOID__STRING_STRING,
 					 G_TYPE_NONE, 0);
+
+	gnt_bindable_class_register_action(bindable, "toggle-tag", toggle_tag_selection, "t", NULL);
+	gnt_bindable_class_register_action(bindable, "clear-tags", clear_tags, "c", NULL);
 	gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
 
 	GNTDEBUG;
@@ -395,3 +469,26 @@
 	return sel->must_exist;
 }
 
+void gnt_file_sel_set_multi_select(GntFileSel *sel, gboolean set)
+{
+	sel->multiselect = set;
+}
+
+GList *gnt_file_sel_get_selected_multi_files(GntFileSel *sel)
+{
+	GList *list = NULL, *iter;
+	char *str = gnt_file_sel_get_selected_file(sel);
+
+	for (iter = sel->tags; iter; iter = iter->next) {
+		list = g_list_prepend(list, g_strdup(iter->data));
+		if (g_utf8_collate(str, iter->data)) {
+			g_free(str);
+			str = NULL;
+		}
+	}
+	if (str)
+		list = g_list_prepend(list, str);
+	list = g_list_reverse(list);
+	return list;
+}
+
--- a/finch/libgnt/gntfilesel.h	Mon Mar 26 00:44:09 2007 +0000
+++ b/finch/libgnt/gntfilesel.h	Mon Mar 26 01:19:59 2007 +0000
@@ -17,11 +17,11 @@
 #define GNT_FILE_SEL_SET_FLAGS(obj, flags)		(GNT_FILE_SEL_FLAGS(obj) |= flags)
 #define GNT_FILE_SEL_UNSET_FLAGS(obj, flags)	(GNT_FILE_SEL_FLAGS(obj) &= ~(flags))
 
-typedef struct _GnFileSel			GntFileSel;
-typedef struct _GnFileSelPriv		GntFileSelPriv;
-typedef struct _GnFileSelClass		GntFileSelClass;
+typedef struct _GntFileSel			GntFileSel;
+typedef struct _GntFileSelPriv		GntFileSelPriv;
+typedef struct _GntFileSelClass		GntFileSelClass;
 
-struct _GnFileSel
+struct _GntFileSel
 {
 	GntWindow parent;
 
@@ -36,9 +36,11 @@
 	/* XXX: someone should make these useful */
 	gboolean must_exist; /* Make sure the selected file (the name entered in 'location') exists */
 	gboolean dirsonly;   /* Show only directories */
+    gboolean multiselect;
+    GList *tags;         /* List of tagged files when multiselect is set */
 };
 
-struct _GnFileSelClass
+struct _GntFileSelClass
 {
 	GntWindowClass parent;
 
@@ -57,8 +59,6 @@
 
 gboolean gnt_file_sel_set_current_location(GntFileSel *sel, const char *path);
 
-const char *gnt_file_sel_get_current_location(GntFileSel *sel);
-
 void gnt_file_sel_set_dirs_only(GntFileSel *sel, gboolean dirs);
 
 gboolean gnt_file_sel_get_dirs_only(GntFileSel *sel);
@@ -69,6 +69,10 @@
 
 char *gnt_file_sel_get_selected_file(GntFileSel *sel);  /* The returned value should be free'd */
 
+GList *gnt_file_sel_get_selected_multi_files(GntFileSel *sel);
+
+void gnt_file_sel_set_multi_select(GntFileSel *sel, gboolean set);
+
 G_END_DECLS
 
 #endif /* GNT_FILE_SEL_H */