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

gEDA-dev: [PATCH] gschem: recent files support



Hi everyone,


Attached is a patch that adds recent files support to 
gschem. The code basically reads $(HOME)/.gschem-recent-files
(determined by a compile-time constant) in order to construct 
a recently used files submenu. The patch applies cleanly
with the latest CVS and works fine for me. The only thing
that's missing is the "Clear" item in the submenu, but I
plan on adding that shortly.

Please test and send your comments and suggestions. Special
thanks to Ales for guiding me on this!

-- 
Ivan Stankovic, ivan.stankovic@fer.hr

"Protect your digital freedom and privacy, eliminate DRM, 
learn more at http://www.defectivebydesign.org/what_is_drm"
diff --git a/gschem/include/prototype.h b/gschem/include/prototype.h
index 242da2b..652e31c 100644
--- a/gschem/include/prototype.h
+++ b/gschem/include/prototype.h
@@ -834,6 +834,10 @@ GtkWidget *get_main_popup(TOPLEVEL *w_current);
 gint do_popup(TOPLEVEL *w_current, GdkEventButton *event);
 void x_menus_sensitivity(TOPLEVEL *w_current, const char *buf, int flag);
 void x_menus_popup_sensitivity(TOPLEVEL *w_current, const char *buf, int flag);
+void x_menu_add_recent_files_item(TOPLEVEL *w_current);
+void recent_files_load();
+void recent_files_save();
+void recent_files_add(const char *filename);
 /* x_multiattrib.c */
 void x_multiattrib_open (TOPLEVEL *toplevel, OBJECT *object);
 /* x_multimulti.c */
diff --git a/gschem/src/gschem.c b/gschem/src/gschem.c
index 093a254..f573c25 100644
--- a/gschem/src/gschem.c
+++ b/gschem/src/gschem.c
@@ -178,6 +178,7 @@ void main_prog(void *closure, int argc, char *argv[])
     exit(-1);
   }
 
+
   /* Allocate w_current.   */
   w_current = s_toplevel_new ();
   global_window_current = w_current;
@@ -204,6 +205,10 @@ void main_prog(void *closure, int argc, char *argv[])
   colormap = gdk_colormap_get_system ();
   x_window_setup_colors();
 
+  /* Load recent files list. This must be done
+   * before calling x_window_setup(). */
+  recent_files_load();
+
   x_window_setup (w_current);
 
   /* o_text_init(); goes away */
diff --git a/gschem/src/x_fileselect.c b/gschem/src/x_fileselect.c
index ce055e9..ec9f5eb 100644
--- a/gschem/src/x_fileselect.c
+++ b/gschem/src/x_fileselect.c
@@ -189,6 +189,7 @@ x_fileselect_open(TOPLEVEL *toplevel)
     /* open each file */ 
     for (tmp = filenames; tmp != NULL;tmp = g_slist_next (tmp)) {
       x_window_open_page (toplevel, (gchar*)tmp->data);
+      recent_files_add((char *)tmp->data);
     }
    
     /* free the list of filenames */
diff --git a/gschem/src/x_menus.c b/gschem/src/x_menus.c
index d1fc794..df413bd 100644
--- a/gschem/src/x_menus.c
+++ b/gschem/src/x_menus.c
@@ -363,3 +363,185 @@ void x_menus_popup_sensitivity (TOPLEVEL* w_current, const char *buf, int flag)
     s_log_message(_("Tried to set the sensitivity on a non-existent popup menu_item\n")); 
   }
 }
+
+
+/* The list of recently loaded files. */
+static GList *recent_files = NULL;
+
+#define RECENT_FILES_STORE ".gschem-recent-files"
+
+static void recent_file_clicked(gpointer data)
+{
+   TOPLEVEL *w = s_toplevel_new();
+   x_window_setup(w);
+   x_window_open_page(w, (char *)data);
+}
+
+/*! \brief This creates 'Recent files' menuitem in the 'File'
+ *         menu and attaches a submenu with filenames.
+ *
+ *  Called from x_window_setup().
+ */
+void x_menu_add_recent_files_item(TOPLEVEL *w_current)
+{
+  GList *menubar_list = gtk_container_get_children(GTK_CONTAINER(
+           w_current->menubar));
+  GtkWidget *file_menu = GTK_WIDGET(g_list_first(menubar_list)->data);
+  GtkWidget *submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(file_menu));
+
+  GtkWidget *recent_menu_item = gtk_menu_item_new_with_label("Recent files");
+  gtk_widget_show(recent_menu_item);
+  gtk_menu_shell_insert(GTK_MENU_SHELL(submenu), recent_menu_item, 11);
+
+  GtkWidget *recent_menu = gtk_menu_new();
+  
+  GList *p = g_list_first(recent_files);
+  while(p) {
+     GtkWidget *tmp = gtk_menu_item_new_with_label((gchar *)p->data);
+     gtk_signal_connect_object(GTK_OBJECT(tmp), "activate",
+                               GTK_SIGNAL_FUNC (recent_file_clicked),
+                               p->data);
+     gtk_menu_append(GTK_MENU(recent_menu), tmp);
+     p = g_list_next(p);
+  }
+  gtk_widget_show_all(recent_menu);
+  gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_menu_item), recent_menu);
+  g_list_free(menubar_list);
+}
+
+/*! \brief Add a filename to the list of recent files.
+ */
+void recent_files_add(const char *filename)
+{
+  /* check if it is a duplicate */
+  GList *p = g_list_first(recent_files);
+  while(p) {
+     if(strcmp((char *)p->data, filename) == 0)
+        return;
+     p = g_list_next(p);
+  }
+
+  filename = g_strdup(filename);
+  recent_files = g_list_prepend(recent_files, (gpointer)filename);
+
+  /* walk through all toplevels and add the filename to the recent file list */
+  TOPLEVEL *w = global_window_current;
+  while(w->prev)
+     w = w->prev;
+
+  while(w) {
+     if(w->menubar == NULL) {
+        w = w->next;
+        continue;
+     }
+
+     GList *menubar_list = gtk_container_get_children(GTK_CONTAINER(
+              w->menubar));
+     GtkWidget *file_menu = GTK_WIDGET(g_list_first(menubar_list)->data);
+     GtkWidget *submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(file_menu));
+
+     GList *tmp = gtk_container_get_children(GTK_CONTAINER(submenu));
+     GtkWidget *p = g_list_nth_data(tmp, 11);
+     GtkWidget *r = gtk_menu_item_get_submenu(GTK_MENU_ITEM(p));
+
+     GtkWidget *s = gtk_menu_item_new_with_label(filename);
+     gtk_widget_show(s);
+     gtk_menu_shell_prepend(GTK_MENU_SHELL(r), s);
+     gtk_signal_connect_object(GTK_OBJECT(s), "activate",
+           GTK_SIGNAL_FUNC (recent_file_clicked),
+           (gpointer)filename);
+     g_list_free(tmp);
+     g_list_free(menubar_list);
+     w = w->next;
+  }
+}
+
+/*! \brief Make RECENT_FILES_STORE contain an empty file list.
+ */
+static void recent_files_create_empty()
+{
+   gchar *c;
+   const gchar * const tmp[] = { NULL };
+   GKeyFile *kf = g_key_file_new();
+   gchar *file = g_build_filename(g_get_home_dir(), RECENT_FILES_STORE, NULL);
+
+   g_key_file_set_string_list(kf, "Recent files", "Files", tmp, 0);
+   c = g_key_file_to_data(kf, NULL, NULL);
+   g_key_file_free(kf);
+
+   g_file_set_contents(file, c, -1, NULL);
+   g_free(c);
+   g_free(file);
+}
+
+/*! \brief Save the list of recent files to RECENT_FILES_STORE.
+ */
+void recent_files_save()
+{
+   gchar **files = NULL;
+   int num = 0;
+   gchar *c;
+   gchar *file = g_build_filename(g_get_home_dir(), RECENT_FILES_STORE, NULL);
+
+   GList *p = g_list_first(recent_files);
+   if(p == NULL) 
+      return;
+
+   while(p) {
+      files = g_realloc(files, (num + 1) * sizeof(gchar *));
+      files[num++] = (gchar *)p->data;
+      p = g_list_next(p);
+   }
+
+   GKeyFile *kf = g_key_file_new();
+
+   g_key_file_set_string_list(kf, "Recent files", "Files", 
+         (const gchar **)files, num);
+   c = g_key_file_to_data(kf, NULL, NULL);
+   g_file_set_contents(file, c, -1, NULL);
+
+   g_free(c);
+   g_free(file);
+   g_free(files);
+   g_key_file_free(kf);
+}
+
+/*! \brief Load the recent file list using data from
+ *         RECENT_FILES_STORE. 
+ *
+ *  Must be called before any other recent-files-related
+ *  functions.
+ */
+void recent_files_load()
+{
+   GKeyFile *kf = g_key_file_new();
+   gchar *file = g_build_filename(g_get_home_dir(), RECENT_FILES_STORE, NULL);
+
+again:
+   if(!g_key_file_load_from_file(kf, file, G_KEY_FILE_NONE, NULL)) {
+      /* error opening key file, create an empty one */
+      recent_files_create_empty();
+      goto again;
+   }
+
+   gsize len;
+   gchar **list = g_key_file_get_string_list(kf, "Recent files",
+         "Files", &len, NULL);
+
+   if(list == NULL) {
+      /* error reading key file, don't bother to correct;
+       * just overwrite it with an empty one */
+      recent_files_create_empty();
+      goto again;
+   }
+
+   while(len > 0) {
+      len--;
+      recent_files = g_list_prepend(recent_files, list[len]);
+   }
+
+   g_free(list);
+   g_free(file);
+   g_key_file_free(kf);
+}
+
diff --git a/gschem/src/x_window.c b/gschem/src/x_window.c
index 1e294b4..6b40082 100644
--- a/gschem/src/x_window.c
+++ b/gschem/src/x_window.c
@@ -184,6 +184,8 @@ void x_window_setup (TOPLEVEL *toplevel)
   toplevel->DONT_EXPOSE=0;
   toplevel->DONT_RECALC=0;
 
+  /* add "Recent files" menu item to the "File" menu */
+  x_menu_add_recent_files_item(toplevel);
 }
 
 /*! \todo Finish function documentation!!!
@@ -869,6 +871,8 @@ void x_window_close_all(TOPLEVEL *toplevel)
 {
   TOPLEVEL *last, *current;
 
+  recent_files_save();
+
   /* find last toplevel in toplevel list */
   for (last = toplevel; last->next != NULL; last = last->next);
 
-- 
1.5.1



_______________________________________________
geda-dev mailing list
geda-dev@moria.seul.org
http://www.seul.org/cgi-bin/mailman/listinfo/geda-dev