YA gtk_filesel patch



Here comes the filesel patch of the week.  This time we've added
persistence of the visible history.  It adds two interface functions,
gtk_filesel_set_history_filename() and gtk_filesel_get_history_filename().
If they are not called, we use $HOME/.gtk/<g_get_prgname()>/ to store the
data.

Note that the patch includes all our previous filesel patches as well.

-Lars

-- 
Lars Clausen (http://shasta.cs.uiuc.edu/~lrclause) | Hårdgrim of Numenor
"I do not agree with a word that you say, but I    | Retainer of Sir Kegg
will defend to the death your right to say it."    |   of Westfield
    --Evelyn Beatrice Hall paraphrasing Voltaire   | Chaos Berserker of Khorne

===File ~/src/GTK/gtk_filesel_persistent_history.diff=======
diff -bBru gtk+-1.2.8-orig/gtk/gtkfilesel.c gtk+-1.2.8/gtk/gtkfilesel.c
--- gtk+-1.2.8-orig/gtk/gtkfilesel.c	Wed Oct 18 15:05:25 2000
+++ gtk+-1.2.8/gtk/gtkfilesel.c	Mon Nov  6 17:26:34 2000
@@ -55,6 +55,7 @@
 #include "gtkclist.h"
 #include "gtkdialog.h"
 #include "gtkintl.h"
+#include "gtkcombo.h"
 
 #define DIR_LIST_WIDTH   180
 #define DIR_LIST_HEIGHT  180
@@ -322,7 +323,10 @@
 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 void gtk_file_selection_home (GtkWidget *widget, gpointer data);
 
+static void gtk_file_selection_save_history(GtkFileSelection *filesel);
+static void gtk_file_selection_load_history(GtkFileSelection *filesel);
 
 
 static GtkWindowClass *parent_class = NULL;
@@ -368,6 +372,30 @@
 }
 
 static void
+gtk_file_selection_file_chosen( GtkWidget *widget, gpointer data) {
+  GtkFileSelection *filesel = GTK_FILE_SELECTION(widget);
+  gchar *filename = gtk_file_selection_get_filename(filesel);
+  GList *elem = NULL;
+
+  if ((elem = g_list_find_custom(filesel->last_selected_files, 
+				 filename, strcmp)) != NULL) {
+    filesel->last_selected_files = g_list_remove_link(filesel->last_selected_files, elem);
+    g_free(elem->data);
+    g_list_free(elem);
+  }
+
+  filesel->last_selected_files = g_list_prepend(filesel->last_selected_files, g_strdup(filename));
+  if (g_list_length(filesel->last_selected_files) >
+      GTK_FILE_SELECTION_VISUAL_HISTORY_LENGTH) {
+    GList *last = g_list_last(filesel->last_selected_files);
+    filesel->last_selected_files = g_list_remove_link(filesel->last_selected_files, last);
+    g_free(last->data);
+    g_list_free(last);
+  }
+  gtk_file_selection_save_history(filesel);
+}
+
+static void
 gtk_file_selection_init (GtkFileSelection *filesel)
 {
   GtkWidget *entry_vbox;
@@ -488,7 +516,10 @@
   gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0);
   gtk_widget_show (label);
 
-  filesel->selection_entry = gtk_entry_new ();
+  filesel->selection_combo = gtk_combo_new();
+  gtk_combo_disable_activate(GTK_COMBO(filesel->selection_combo));
+
+  filesel->selection_entry = GTK_COMBO(filesel->selection_combo)->entry;
   gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event",
 		      (GtkSignalFunc) gtk_file_selection_key_press, filesel);
   gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "focus_in_event",
@@ -497,8 +528,11 @@
   gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "activate",
                              (GtkSignalFunc) gtk_button_clicked,
                              GTK_OBJECT (filesel->ok_button));
-  gtk_box_pack_start (GTK_BOX (entry_vbox), filesel->selection_entry, TRUE, TRUE, 0);
-  gtk_widget_show (filesel->selection_entry);
+  gtk_signal_connect_object (GTK_OBJECT (filesel->ok_button), "clicked",
+			     (GtkSignalFunc) gtk_file_selection_file_chosen,
+			     GTK_OBJECT(filesel));
+  gtk_box_pack_start (GTK_BOX (entry_vbox), filesel->selection_combo, TRUE, TRUE, 0);
+  gtk_widget_show (filesel->selection_combo);
 
   if (!cmpl_state_okay (filesel->cmpl_state))
     {
@@ -567,6 +601,17 @@
       gtk_widget_show (filesel->fileop_ren_file);
     }
 
+  if (!filesel->fileop_home)
+    {
+      filesel->fileop_home = gtk_button_new_with_label (_("Home"));
+      gtk_signal_connect (GTK_OBJECT (filesel->fileop_home), "clicked",
+			  (GtkSignalFunc) gtk_file_selection_home, 
+			  (gpointer) filesel);
+      gtk_box_pack_start (GTK_BOX (filesel->button_area), 
+			  filesel->fileop_home, TRUE, TRUE, 0);
+      gtk_widget_show (filesel->fileop_home);
+    }
+
   gtk_widget_queue_resize(GTK_WIDGET(filesel));
 }
 
@@ -576,6 +621,11 @@
   g_return_if_fail (filesel != NULL);
   g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
     
+  if (filesel->fileop_home)
+    {
+      gtk_widget_destroy (filesel->fileop_home);
+      filesel->fileop_home = NULL;
+    }
   if (filesel->fileop_ren_file) 
     {
       gtk_widget_destroy (filesel->fileop_ren_file);
@@ -700,6 +750,191 @@
     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 }
 
+static void
+unmake_directories(gchar *dirname, gchar *until) {
+  if (strcmp(dirname, until) && strcmp(dirname, "/")) {
+    if (!rmdir(dirname)) {
+      dirname = g_dirname(dirname);
+      unmake_directories(dirname, until);
+      g_free(dirname);
+    }
+  }
+}
+
+static gchar *
+make_directories(gchar *filename) {
+  struct stat dummy;
+
+  if ((stat(filename, &dummy) == -1) && 
+      errno == ENOENT) {
+    gchar *dirname = g_dirname(filename);
+    gchar *created = make_directories(dirname);
+    if (created) {
+      int retval = mkdir(filename, 0700);
+      if (retval == -1) {
+	g_warning("Unable to create history directory %s: %s\n",
+		  filename, strerror(errno));
+	unmake_directories(dirname, created);
+	created = NULL;
+      }
+      g_print("Making dir %s\n", filename);
+    }
+    g_free(dirname);
+    return created;
+  } else {
+    return filename;
+  }
+}
+
+void
+gtk_file_selection_set_history_filename(GtkFileSelection *filesel,
+					gchar *filename)
+{
+  g_assert(filesel != NULL);
+
+  if (filename == NULL) {
+    filename = "file_dialog_history";
+  }
+  
+  g_print("Setting persistence filename %s\n", filename);
+
+  if (*filename == '/')
+    filesel->file_history_filename = strdup(filename);
+  else {
+    gchar *full_filename;
+    char *home_dir = getenv("HOME");
+    gchar *dirname;
+    if (home_dir == NULL) {
+      g_warning("Couldn't find home directory!");
+      home_dir = "/tmp";
+    }
+    if (!strcmp(home_dir, "/") && getpid() != 0) {
+      home_dir = "/tmp";
+    }
+    full_filename = g_strdup_printf("%s/.gtk/%s/%s",
+				    home_dir, g_get_prgname(), filename);
+    g_print("Setting persistence filename %s\n", full_filename);
+
+    dirname = g_dirname(full_filename);
+    if (make_directories(dirname) == NULL) {
+      filesel->file_history_filename = (gchar *)-1;
+    } else {
+      filesel->file_history_filename = full_filename;
+    }
+    g_free(dirname);
+  }    
+}
+
+gchar *
+gtk_file_selection_get_history_filename(GtkFileSelection *filesel)
+{
+  return filesel->file_history_filename;
+}
+
+static void
+gtk_file_selection_load_history(GtkFileSelection *filesel) {
+  FILE *history_file;
+  GList *elem = NULL;
+  GString *history_entry;
+
+  if (filesel->file_history_filename == NULL)
+    gtk_file_selection_set_history_filename(filesel, NULL);
+  if (filesel->file_history_filename == (gchar *)-1)
+    return;
+
+  history_file = fopen(filesel->file_history_filename, "r");
+  if (history_file == NULL) {
+    /* Not a fail -- file might not have been written yet */
+    if (errno == ENOENT) return;
+    g_warning("Couldn't open file dialog persistence file %s: %s\n", 
+	      filesel->file_history_filename, strerror(errno));
+    return;
+  }
+  history_entry = g_string_new("");
+  while (!feof(history_file)) {
+    char buf[80];
+    int len = 0;
+    buf[0] = '\0';
+    do {
+      if (feof(history_file)) {
+	break;
+      }
+      if (fgets(buf, 80, history_file) == EOF) {
+	g_warning("Couldn't read file dialog persistence file %s: %s\n", 
+		  filesel->file_history_filename, strerror(errno));
+	g_string_free(history_entry, TRUE);
+	/* Failed reading, but we might as well use what we got */
+	filesel->last_selected_files = g_list_reverse(elem);
+	goto FAIL;
+      }
+      len += strlen(buf);
+      history_entry = g_string_append(history_entry, buf);
+    } while (!strchr(buf, '\n'));
+    if (len > 0) {
+      g_print("Found entry %s\n", history_entry->str);
+      /* Chop! */
+      history_entry = g_string_truncate(history_entry, len-1);
+      elem = g_list_prepend(elem, strdup(history_entry->str));
+      g_string_truncate(history_entry, 0);
+    }
+  }
+  g_string_free(history_entry, TRUE);
+  filesel->last_selected_files = g_list_reverse(elem);
+  if (fclose(history_file)) {
+    g_warning("Failed closing file dialog persistence file %s: %s\n", 
+	      filesel->file_history_filename, strerror(errno));
+    goto FAIL;
+  }
+  return;
+
+ FAIL:
+  g_free(filesel->file_history_filename);
+  filesel->file_history_filename = (gchar *)-1;
+  return;
+}
+
+static void
+gtk_file_selection_save_history(GtkFileSelection *filesel) {
+  FILE *history_file;
+  GList *file_list;
+
+  if (filesel->file_history_filename == NULL)
+    gtk_file_selection_set_history_filename(filesel, NULL);
+  if (filesel->file_history_filename == (gchar *)-1)
+    return;
+  
+  history_file = fopen(filesel->file_history_filename, "w");
+  if (history_file == NULL) {
+    g_warning("Couldn't write file dialog persistence file %s: %s\n", 
+	      filesel->file_history_filename, strerror(errno));
+    goto FAIL;
+  }
+  file_list = filesel->last_selected_files;
+  while (file_list != NULL) {
+    if (fprintf(history_file, file_list->data) == 0) {
+      g_warning("Failed writing file dialog persistence file %s: %s\n", 
+		filesel->file_history_filename, strerror(errno));
+      goto FAIL;
+    }
+    if (fprintf(history_file, "\n") == 0) {
+      g_warning("Failed writing file dialog persistence file %s: %s\n", 
+		filesel->file_history_filename, strerror(errno));
+      goto FAIL;
+    }
+    file_list = g_list_next(file_list);
+  }
+  if (fclose(history_file)) {
+    g_warning("Failed closing file dialog persistence file %s: %s\n", 
+	      filesel->file_history_filename, strerror(errno));
+    goto FAIL;
+  }
+  return;
+ FAIL:
+  g_free(filesel->file_history_filename);
+  filesel->file_history_filename = (gchar *)-1;
+  return;
+}
+
 /* Begin file operations callbacks */
 
 static void
@@ -1082,6 +1317,28 @@
 }
 
 
+static void
+gtk_file_selection_home (GtkWidget *widget, gpointer data)
+{
+  GtkFileSelection *fs = data;
+  char *home_dir = getenv("HOME");
+
+  g_return_if_fail (fs != NULL);
+  g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
+
+  if (home_dir == NULL) {
+    /* Pop up error dialog */
+    gtk_file_selection_fileop_error (fs, "No home directory found.");
+    return;
+  }
+
+  home_dir = g_strconcat(home_dir, "/", NULL);
+
+  gtk_file_selection_populate (fs, home_dir, FALSE);
+
+  g_free(home_dir); /* Does gtk_file_selection_populate keep it? */
+}
+
 static gint
 gtk_file_selection_key_press (GtkWidget   *widget,
 			      GdkEventKey *event,
@@ -1248,7 +1505,7 @@
       else
 	gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename);
 
-      g_free (filename);
+      g_free(filename);
     }
 }
 
@@ -1281,16 +1538,40 @@
 	    break;
 	  
 	  default:
+	    /*
 	    gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename);
+	    */
 	    break;
 	  }
       else
+	gtk_file_selection_populate (fs, filename, FALSE);
+	/*
 	gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename);
+	*/
 
       g_free (filename);
     }
 }
 
+static gint
+gtk_file_selection_find_last_row(GtkFileSelection *fs) {
+  gchar *name = fs->last_selected_files->data;
+  GList *rows = GTK_CLIST(fs->file_list)->row_list;
+  int i = 0;
+  
+  name = g_basename(name);
+
+  for (; rows != NULL; rows = g_list_next(rows)) {
+    GtkCListRow *row = GTK_CLIST_ROW(rows);
+
+    if (!strcmp(name, row->cell->u.text))
+      return i;
+    i++;
+  }
+
+  return -1;
+}
+
 static void
 gtk_file_selection_populate (GtkFileSelection *fs,
 			     gchar            *rel_path,
@@ -1431,8 +1712,37 @@
     }
   else
     {
+      if (fs->selection_entry) {
+	gchar * basename;
+	basename = g_basename(gtk_entry_get_text(GTK_ENTRY(fs->selection_entry)));
+	if (basename == NULL) {
+	  g_print("NULL basename");
+	} else if (basename != gtk_entry_get_text(GTK_ENTRY(fs->selection_entry))) {
+	  basename = strdup(basename);
+	  gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), basename);
+	  g_free(basename);
+	}
+	
+	if (!fs->last_selected_files) {
+	  gtk_file_selection_load_history(fs);
+	}
+
+	if (fs->last_selected_files) {
+	  gint row;
+	  row = gtk_file_selection_find_last_row(fs);
+	  if (row != -1) {
+	    gtk_clist_moveto(GTK_CLIST(fs->file_list),
+			     row, 0, .5, 0.0);
+	  }
+	  gtk_combo_set_popdown_strings(GTK_COMBO(fs->selection_combo),
+					fs->last_selected_files);
+	}
+      }
+     
+      /*
       if (fs->selection_entry)
 	gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), "");
+      */
     }
 
   if (!did_recurse)
diff -bBru gtk+-1.2.8-orig/gtk/gtkfilesel.h gtk+-1.2.8/gtk/gtkfilesel.h
--- gtk+-1.2.8-orig/gtk/gtkfilesel.h	Wed Oct 18 15:05:25 2000
+++ gtk+-1.2.8/gtk/gtkfilesel.h	Mon Nov  6 15:27:48 2000
@@ -42,9 +42,9 @@
 #define GTK_FILE_SELECTION_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SELECTION, GtkFileSelectionClass))
 #define GTK_IS_FILE_SELECTION(obj)         (GTK_CHECK_TYPE ((obj), GTK_TYPE_FILE_SELECTION))
 #define GTK_IS_FILE_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SELECTION))
+#define GTK_FILE_SELECTION_VISUAL_HISTORY_LENGTH 5
 
-
-typedef struct _GtkFileSelection       GtkFileSelection;
+  typedef struct _GtkFileSelection       GtkFileSelection;
 typedef struct _GtkFileSelectionClass  GtkFileSelectionClass;
 
 struct _GtkFileSelection
@@ -74,6 +74,11 @@
   GtkWidget *button_area;
   GtkWidget *action_area;
   
+  GtkWidget *fileop_home;
+
+  GtkWidget *selection_combo;
+  GList     *last_selected_files;
+  gchar     *file_history_filename;
 };
 
 struct _GtkFileSelectionClass
@@ -91,7 +96,9 @@
 						   const gchar	    *pattern);
 void       gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel);
 void       gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel);
-
+void       gtk_file_selection_set_history_filename(GtkFileSelection *filesel,
+						   gchar *filename);
+gchar     *gtk_file_selection_get_history_filename(GtkFileSelection *filesel);
 
 #ifdef __cplusplus
 }
============================================================




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]