Re: New treeviewized GtkFileSelection and GTK_SELECTION_MULTIPLE
- From: Manish Singh <yosh gimp org>
- To: Owen Taylor <otaylor redhat com>, gtk-devel-list gnome org
- Subject: Re: New treeviewized GtkFileSelection and GTK_SELECTION_MULTIPLE
- Date: Thu, 14 Feb 2002 15:21:55 -0800
On Mon, Feb 04, 2002 at 03:16:58PM -0800, Manish Singh wrote:
> On Mon, Feb 04, 2002 at 06:00:44PM -0500, Owen Taylor wrote:
> >
> > Manish Singh <yosh gimp org> writes:
> >
> > > A bit of an addendum:
> > >
> > > > Proposed API additions:
> > > >
> > > > 1) gtk_file_selection_set_selection_mode (): simply a wrapper around
> > > > gtk_tree_selection_set_mode () for the fs->file_list
> > >
> > > Also, a corresponding get_file_selection_get_selection_mode ()
> > >
> > > > 2) gtk_file_selection_get_selections (): Returns an array of filenames,
> > > > freed by the caller.
> > >
> > > It should also return whatever the user typed in the entry widget, and
> > > prepend the directory names to all the filenames. I'm not sure I like the
> > > function name, anyone have any better suggestions?
> >
> > * On reflection, as much as I don't like adding API at this point, I think
> > we need to do this. Multiple file selection is used in various current
> > users of GTK+-2.0 (the GIMP, libbonoboui/bonobo/bonobo-list) and probably
> > a elsewhere not using GTK+-2.0 yet, so currently we have
> > a reasonably large functionality regression.
> >
> > * Adding the API explicitely is definitely better than adding the API
> > implicitely by making it work if you poke into the internals in a certain
> > way.
> >
> > * I think it's probably worth spending the effort to make the filename
> > in that's put into entry not the first item among the selected items,
> > but the most recently selected item. (More exactly, the first newly
> > added item when the selection changes.)
> >
> > Unfortunately, the only clean way to do this that I (or Jonathan) could
> > think of is to to keep track of the current selection and do diffs
> > in selection::changed.
> >
> > The proposed API looks fine, except that I'd like to see;
> >
> > gtk_file_selection_set/get_select_multiple (GtkFileSelection *filesel, gboolean select_multiple);
> >
> > Then reusing the selection enum, since the "NONE" selection mode
> > doesn't make sense.
>
> All sounds fine to me, I'll come up with a patch tonight.
Patch is attached. The diff stuff logic isn't quite finished yet, but the
API is there and should be working.
-Yosh
Index: gtkfilesel.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkfilesel.c,v
retrieving revision 1.101
diff -u -p -r1.101 gtkfilesel.c
--- gtkfilesel.c 2002/02/11 21:17:11 1.101
+++ gtkfilesel.c 2002/02/14 23:18:03
@@ -396,13 +396,18 @@ static void gtk_file_selection_abort
static void gtk_file_selection_update_history_menu (GtkFileSelection *fs,
gchar *current_dir);
-static void gtk_file_selection_create_dir (GtkWidget *widget, gpointer data);
+static void gtk_file_selection_multiple_changed (GtkTreeSelection *selection,
+ gpointer user_data);
+
+static void gtk_file_selection_create_dir (GtkWidget *widget, gpointer data);
static void gtk_file_selection_delete_file (GtkWidget *widget, gpointer data);
static void gtk_file_selection_rename_file (GtkWidget *widget, gpointer data);
+static GtkDialogClass *parent_class = NULL;
-static GtkWindowClass *parent_class = NULL;
+static GQuark quark_selected_names = 0;
+static GQuark quark_last_selected = 0;
/* Saves errno when something cmpl does fails. */
static gint cmpl_errno;
@@ -505,8 +510,11 @@ gtk_file_selection_class_init (GtkFileSe
gobject_class = (GObjectClass*) class;
object_class = (GtkObjectClass*) class;
widget_class = (GtkWidgetClass*) class;
+
+ parent_class = g_type_class_peek_parent (class);
- parent_class = gtk_type_class (GTK_TYPE_DIALOG);
+ quark_selected_names = g_quark_from_static_string ("gtk-fs-selected-names");
+ quark_last_selected = g_quark_from_static_string ("gtk-fs-last_selected");
gobject_class->finalize = gtk_file_selection_finalize;
gobject_class->set_property = gtk_file_selection_set_property;
@@ -1815,7 +1823,7 @@ gtk_file_selection_update_history_menu (
}
static gchar *
-get_real_filename (gchar *filename)
+get_real_filename (gchar *filename)
{
#ifdef G_WITH_CYGWIN
/* Check to see if the selection was a drive selector */
@@ -1823,7 +1831,7 @@ get_real_filename (gchar *filename)
{
/* It is... map it to a CYGWIN32 drive */
gchar *temp_filename = g_strdup_printf ("//%c/", tolower (filename[0]));
- g_free(filename);
+ g_free (filename);
return temp_filename;
}
#else
@@ -2089,6 +2097,207 @@ gtk_file_selection_abort (GtkFileSelecti
if (fs->selection_entry)
gtk_label_set_text (GTK_LABEL (fs->selection_text), err_buf);
+}
+
+void
+gtk_file_selection_set_select_multiple (GtkFileSelection *filesel,
+ gboolean select_multiple)
+{
+ GtkTreeSelection *sel;
+ GtkSelectionMode mode;
+
+ g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list));
+
+ mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE;
+
+ gtk_tree_selection_set_mode (sel, mode);
+
+ g_signal_handlers_disconnect_matched (sel, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+ NULL, filesel);
+ if (select_multiple)
+ g_signal_connect (sel, "changed",
+ G_CALLBACK (gtk_file_selection_multiple_changed),
+ filesel);
+ else
+ g_signal_connect (sel, "changed",
+ G_CALLBACK (gtk_file_selection_file_changed),
+ filesel);
+}
+
+gboolean
+gtk_file_selection_get_select_multiple (GtkFileSelection *filesel)
+{
+ GtkTreeSelection *sel;
+
+ g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), FALSE);
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list));
+ return !!(gtk_tree_selection_get_mode (sel) == GTK_SELECTION_MULTIPLE);
+}
+
+static void
+multiple_changed_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GPtrArray *names = data;
+ gchar *filename;
+
+ gtk_tree_model_get (model, iter, FILE_COLUMN, &filename, -1);
+
+ g_ptr_array_add (names, filename);
+}
+
+static void
+free_selected_names (gpointer data)
+{
+ g_ptr_array_free ((GPtrArray *) data, TRUE);
+}
+
+#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
+#define ms_strcmp(a, b) strcmp(a, b)
+#else
+#define ms_strcmp(a, b) g_strcasecmp(a, b)
+#endif
+
+static void
+gtk_file_selection_multiple_changed (GtkTreeSelection *selection,
+ gpointer user_data)
+{
+ GtkFileSelection *fs = GTK_FILE_SELECTION (user_data);
+ GPtrArray *new_names, *old_names;
+ gchar *filename, *old_filename;
+ gint i, index = 0;
+
+ new_names = g_ptr_array_sized_new (8);
+
+ gtk_tree_selection_selected_foreach (selection,
+ multiple_changed_foreach,
+ new_names);
+ /* nothing selected */
+ if (new_names->len == 0)
+ {
+ g_ptr_array_free (new_names, TRUE);
+ g_object_set_qdata (G_OBJECT (selection), quark_selected_names, NULL);
+ return;
+ }
+
+ if (new_names->len != 1)
+ {
+ old_names = g_object_get_qdata (G_OBJECT (selection),
+ quark_selected_names);
+
+ if (old_names != NULL)
+ {
+ /* FIXME: unfinished logic here, need to get the cases for
+ * multiremoval correct
+ */
+ if (new_names->len > old_names->len)
+ {
+ if (ms_strcmp (g_ptr_array_index (old_names, old_names->len - 1),
+ g_ptr_array_index (new_names, new_names->len - 1)) < 0)
+ index = new_names->len - 1;
+ else
+ {
+ for (i = 0; i < old_names->len; i++)
+ {
+ if (ms_strcmp (g_ptr_array_index (old_names, i),
+ g_ptr_array_index (new_names, i)) != 0)
+ {
+ index = i;
+ break;
+ }
+ }
+ }
+ }
+ else if (new_names->len < old_names->len)
+ {
+ }
+ else
+ {
+ }
+ }
+ else
+ {
+ old_filename = g_object_get_qdata (G_OBJECT (selection),
+ quark_last_selected);
+
+ if (ms_strcmp (old_filename, g_ptr_array_index (new_names, 0)) == 0)
+ index = new_names->len - 1;
+ else
+ index = 0;
+ }
+ }
+ else
+ index = 0;
+
+ g_object_set_qdata_full (G_OBJECT (selection), quark_selected_names,
+ new_names, free_selected_names);
+
+ filename = g_ptr_array_index (new_names, index);
+ g_object_set_qdata_full (G_OBJECT (selection), quark_last_selected,
+ g_strdup (filename), g_free);
+
+ old_filename = filename;
+ filename = get_real_filename (filename);
+
+ gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename);
+
+ if (filename != old_filename)
+ g_free (filename);
+}
+
+gchar **
+gtk_file_selection_get_selections (GtkFileSelection *filesel)
+{
+ GtkTreeSelection *sel;
+ GPtrArray *names;
+ gchar **selections;
+ gchar *filename, *dirname, *current;
+ gint i, j;
+
+ g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), NULL);
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list));
+
+ names = g_object_get_qdata (G_OBJECT (sel), quark_selected_names);
+
+ selections = g_new (gchar *, names->len + 2);
+
+ filename = g_strdup (gtk_file_selection_get_filename (filesel));
+
+ if (strlen (filename) == 0)
+ return NULL;
+
+ selections[0] = filename;
+ j = 1;
+
+ if (names != NULL)
+ {
+ dirname = g_path_get_dirname (filename);
+
+ for (i = 0; i < names->len; i++, j++)
+ {
+ current = g_build_filename (dirname, g_ptr_array_index (names, i),
+ NULL);
+
+ if (ms_strcmp (current, filename) == 0)
+ {
+ g_free (current);
+ selections = g_realloc (selections, names->len + 1);
+ j--;
+ }
+ else
+ selections[j] = current;
+ }
+ }
+
+ selections[j] = NULL;
+
+ return selections;
}
/**********************************************************************/
Index: gtkfilesel.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkfilesel.h,v
retrieving revision 1.13
diff -u -p -r1.13 gtkfilesel.h
--- gtkfilesel.h 2001/03/23 23:39:24 1.13
+++ gtkfilesel.h 2002/02/14 23:18:03
@@ -74,7 +74,6 @@ struct _GtkFileSelection
GtkWidget *button_area;
GtkWidget *action_area;
-
};
struct _GtkFileSelectionClass
@@ -100,20 +99,15 @@ void gtk_file_selection_complete (
void gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel);
void gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel);
+gchar** gtk_file_selection_get_selections (GtkFileSelection *filesel);
+void gtk_file_selection_set_select_multiple (GtkFileSelection *filesel,
+ gboolean select_multiple);
+gboolean gtk_file_selection_get_select_multiple (GtkFileSelection *filesel);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GTK_FILESEL_H__ */
-
-
-
-
-
-
-
-
-
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]