Re: [PATCH]: Application chooser for the Open With dialog



Hello. I've updated the patch with the following issues:

El mié, 19-01-2005 a las 12:14 +0100, Alexander Larsson escribió:

> You need to allow the window to be resized.

I've changed to a bigger fixed size

> 
> The way this works is very bizzare. You select a desktop file from the
> menu, extract the exec line from it, remove stuff that is needed, and
> then create a new desktop file with the modified exec line (and none
> of the other information in the original desktop file) in the users
> home directory (this is what eel_mime_add_application does). A better
> solution would be to just put the name of the desktop file in the
> entry when you select one, and then make the code handle desktop 
> files. This should be easy, and there is even a comment about doing
> this in check_application.

Ok, I've changed it little bit.

The UI now shows by default the application list, and the entry is
hidden under an expander. I think 90% of users will select an
application from the list, and advanded users will use the entry to type
a custom app.

If the user has selected an application from the list, we store and
handle the .desktop file, and when adding the mime type, we just copy
the original to the user home dir (preserving comments and translations)
with the new mime type, with the eel_mime_add_desktop_file function. If
the user instead has typed a command in the entry, we create an
new .desktop file for it.

Maybe I should patch also the eel_mime_add_application function to use
the g_key_file_* as in the new one.

> +#define sure_string(s)                    ((const char *)((s)!=NULL?(s):""))
> 
> Define this in the c file, not in the public header!

done.


> +	gboolean      long_operation = FALSE;
> 
> no initialization in definition (per the nautilus styleguide)

okey, but it's done in eel-mime-extensions.c

> +	/* don't go back into the main loop if this wasn't very hard to do */
> +	} while (!long_operation);
> 
> Why aren't loads via the icon theme long? They also read a file.

Because they should be cached/mmap by gtk IIRC, but maybe I'm wrong.


> Anyway, this should use
> nautilus_icon_factory_get_pixbuf_for_icon_force_size()
> instead of manually loading icons, so that the results is cached.

Humm, we are doing this dialog in the eel lib, so we don't have access
to nautilus_icon_factory.

> Just do the prev_name comparison in the list store append loop instead.
> That means you don't have to call g_slist_delete_link() (which causes
> this
> loop to be O(n^2))

done

> 
> +		ditem = gnome_desktop_item_new_from_file (path,
> +							  GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS,
> +							  NULL /* error */);
> 
> This new code should probably use the new g_key_file_load_from_file()
> api.
> Also GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS doesn't do what you probably
> think it
> does, although it looks ok for this use. It only loads the file if the
> file specified
> in exec or tryexec exists.

Replaced with g_key_file_*

> +			/* Order is important here. We have to set the text first so that the
> +			 * drag source is enabled, otherwise the drag icon can't be set by
> +			 * panel_run_dialog_set_icon.
> +			 */
> 
> Eh?

Just crap from copy&paste, sorry.

Attached is the new patch.

? eel-2.0-uninstalled.pc
? mkinstalldirs
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/eel/ChangeLog,v
retrieving revision 1.667
diff -u -r1.667 ChangeLog
--- ChangeLog	13 Jan 2005 10:05:37 -0000	1.667
+++ ChangeLog	20 Jan 2005 10:06:54 -0000
@@ -1,3 +1,21 @@
+2005-01-20  Fernando Herrera  <set EMAIL_ADDRESS environment variable>
+
+	* configure.in:
+	* eel/Makefile.am:
+	* eel/eel-mime-extensions.c: (eel_mime_add_desktop_file):
+	* eel/eel-mime-extensions.h: New function to add add an application from
+	its original .desktop file.
+	* eel/eel-open-with-dialog.c: (check_application), (get_app_name),
+	(add_or_find_application), (entry_changed_cb),
+	(eel_open_with_dialog_add_icon_idle), (compare_applications),
+	(get_all_applications_from_dir), (get_all_applications),
+	(eel_open_with_dialog_add_items_idle), (remove_parameters),
+	(program_list_selection_changed),
+	(program_list_selection_activated), (expander_toggled),
+	(eel_open_with_dialog_instance_init),
+	(eel_add_application_dialog_new): Show know applications from .desktop files
+	and move the entry to an expander to specify a custom app/command line.
+
 2005-01-13  Alexander Larsson  <alexl redhat com>
 
 	* eel/eel-alert-dialog.c (eel_alert_dialog_set_primary_label):
Index: configure.in
===================================================================
RCS file: /cvs/gnome/eel/configure.in,v
retrieving revision 1.182
diff -u -r1.182 configure.in
--- configure.in	11 Jan 2005 08:41:11 -0000	1.182
+++ configure.in	20 Jan 2005 10:06:54 -0000
@@ -14,6 +14,8 @@
 XML_REQUIRED=2.4.7
 GAIL_REQUIRED=0.16
 LIBGLADE_REQUIRED=2.0.0
+LIBGNOME_DESKTOP_REQUIRED=2.1.4
+LIBGNOME_MENU_REQUIRED=2.9.1
 
 AC_SUBST(ART_REQUIRED)
 AC_SUBST(GCONF_REQUIRED)
@@ -82,6 +84,8 @@
 	libgnome-2.0		>= $GNOME_REQUIRED
 	libgnomeui-2.0		>= $GNOME_UI_REQUIRED
 	libxml-2.0		>= $XML_REQUIRED
+	libgnome-menu           >= $LIBGNOME_MENU_REQUIRED
+	gnome-desktop-2.0	>= $LIBGNOME_DESKTOP_REQUIRED
 ])
 AC_SUBST(EEL_CFLAGS)
 AC_SUBST(EEL_LIBS)
Index: eel/Makefile.am
===================================================================
RCS file: /cvs/gnome/eel/eel/Makefile.am,v
retrieving revision 1.82
diff -u -r1.82 Makefile.am
--- eel/Makefile.am	22 Jul 2004 03:55:49 -0000	1.82
+++ eel/Makefile.am	20 Jan 2005 10:06:54 -0000
@@ -12,6 +12,7 @@
 	-DG_DISABLE_DEPRECATED				\
 	-DGDK_DISABLE_DEPRECATED			\
 	-DGDK_PIXBUF_DISABLE_DEPRECATED			\
+	-DMENU_I_KNOW_THIS_IS_UNSTABLE			\
 	$(NULL)
 
 # Disable this for now due to gtk 2.4 deprecation
Index: eel/eel-mime-extensions.c
===================================================================
RCS file: /cvs/gnome/eel/eel/eel-mime-extensions.c,v
retrieving revision 1.8
diff -u -r1.8 eel-mime-extensions.c
--- eel/eel-mime-extensions.c	25 Nov 2004 17:07:56 -0000	1.8
+++ eel/eel-mime-extensions.c	20 Jan 2005 10:06:54 -0000
@@ -41,6 +41,8 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#define DESKTOP_ENTRY_GROUP                "Desktop Entry"
+
 static gboolean
 recursive_mkdir (const char *path)
 {
@@ -269,6 +271,80 @@
 	
 	return ret;
 }
+
+GnomeVFSMimeApplication *
+eel_mime_add_desktop_file (const char *desktop_file,
+			   const char *mime_type, 
+			   gboolean needs_terminal)
+{
+	GnomeVFSMimeApplication *ret;
+	GKeyFile *keyfile;
+	char *application_dir;
+	char *filename;
+	char *basename;
+	int i;
+
+	if (desktop_file == NULL) {
+		return NULL;
+	}
+
+	if (mime_type == NULL) {
+		return NULL;
+	}
+	
+	if (!ensure_application_dir ()) {
+		return NULL;
+	}
+
+	application_dir = get_user_dir ("applications");
+
+	/* Get a filename */
+	basename = g_path_get_basename (desktop_file);
+	filename = g_build_filename (application_dir, basename, NULL);
+
+	i = 1;
+	while (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+		char *name;
+
+		name = g_strndup (basename, strlen (basename) - strlen (".desktop"));
+		g_free (basename);
+		g_free (filename);
+		basename = g_strdup_printf ("%s%d.desktop", name, i);
+		filename = g_build_filename (application_dir, basename, NULL);
+		g_free (name);
+		
+		i++;
+	}
+
+	keyfile = g_key_file_new ();
+	if (g_key_file_load_from_file (keyfile, desktop_file, G_KEY_FILE_KEEP_COMMENTS |
+				   G_KEY_FILE_KEEP_TRANSLATIONS, NULL)) {
+		char *desktop_text;
+
+		g_key_file_set_string (keyfile, DESKTOP_ENTRY_GROUP, "MimeType", mime_type);
+		g_key_file_set_boolean (keyfile, DESKTOP_ENTRY_GROUP, "NoDisplay", TRUE);
+		g_key_file_set_boolean (keyfile, DESKTOP_ENTRY_GROUP, "Terminal", needs_terminal);
+		desktop_text = g_key_file_to_data (keyfile, NULL, NULL);
+
+		if (write_desktop_file (filename, desktop_text)) {
+			ret = gnome_vfs_mime_application_new_from_desktop_id (basename);
+			run_update_command ("update-desktop-database", "applications");
+		} else {
+			ret = NULL;
+		}
+        	g_free (desktop_text);
+	} else {
+		ret = NULL;
+	}
+
+	g_free (basename);
+	g_free (filename);
+	g_free (application_dir);
+	
+	return ret;
+}
+
+
 
 static char *
 get_override_filename (void)
Index: eel/eel-mime-extensions.h
===================================================================
RCS file: /cvs/gnome/eel/eel/eel-mime-extensions.h,v
retrieving revision 1.2
diff -u -r1.2 eel-mime-extensions.h
--- eel/eel-mime-extensions.h	22 Jul 2004 03:55:49 -0000	1.2
+++ eel/eel-mime-extensions.h	20 Jan 2005 10:06:54 -0000
@@ -34,6 +34,10 @@
 							     const char *command_line,
 							     const char *name,
 							     gboolean    needs_terminal);
+GnomeVFSMimeApplication *eel_mime_add_desktop_file          (const char *desktop_file,
+							     const char *mime_type,
+							     gboolean needs_terminal);
+
 gboolean                 eel_mime_add_glob_type             (const char *mime_type,
 							     const char *description,
 							     const char *glob);
Index: eel/eel-open-with-dialog.c
===================================================================
RCS file: /cvs/gnome/eel/eel/eel-open-with-dialog.c,v
retrieving revision 1.3
diff -u -r1.3 eel-open-with-dialog.c
--- eel/eel-open-with-dialog.c	23 Jul 2004 16:20:18 -0000	1.3
+++ eel/eel-open-with-dialog.c	20 Jan 2005 10:06:55 -0000
@@ -33,19 +33,29 @@
 #include <glib/gi18n-lib.h>
 #include <gtk/gtkalignment.h>
 #include <gtk/gtkbox.h>
+#include <gtk/gtkexpander.h>
 #include <gtk/gtkbutton.h>
 #include <gtk/gtkdialog.h>
 #include <gtk/gtkentry.h>
 #include <gtk/gtkfilechooserdialog.h>
 #include <gtk/gtkhbox.h>
 #include <gtk/gtkicontheme.h>
-#include <gtk/gtkimage.h>
 #include <gtk/gtkiconfactory.h>
 #include <gtk/gtklabel.h>
+#include <gtk/gtkscrolledwindow.h>
 #include <gtk/gtkstock.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkcellrendererpixbuf.h>
 #include <gtk/gtkvbox.h>
+#include <libgnome/gnome-desktop-item.h>
 #include <libgnomevfs/gnome-vfs-mime-handlers.h>
 #include <libgnomevfs/gnome-vfs-uri.h>
+#include <menu-tree.h>
+
+#define sure_string(s)                    ((const char *)((s)!=NULL?(s):""))
+#define DESKTOP_ENTRY_GROUP		  "Desktop Entry"
 
 struct _EelOpenWithDialogDetails {
 	char *uri;
@@ -55,12 +65,31 @@
 
 	gboolean new_mime_type;
 	char *new_glob;
+	char *desktop_file;
 
 	GtkWidget *label;
 	GtkWidget *entry;
+	GtkWidget *button;
+
+	GtkWidget *desc_label;
 
 	GtkWidget *open_label;
-	GtkWidget *open_image;
+
+	GtkWidget     *program_list;
+	GtkListStore  *program_list_store;
+	GSList	      *add_icon_paths;
+	gint	       add_items_idle_id;
+	gint	       add_icons_idle_id;
+};
+
+enum {
+        COLUMN_ICON,
+        COLUMN_ICON_FILE,
+        COLUMN_NAME,
+        COLUMN_COMMENT,
+        COLUMN_PATH,
+        COLUMN_EXEC,
+        NUM_COLUMNS
 };
 
 enum {
@@ -112,14 +141,30 @@
 static gboolean
 check_application (EelOpenWithDialog *dialog)
 {
+	char *command = NULL;
 	char *path = NULL;
 	char **argv = NULL;
 	int argc;
 	GError *error = NULL;
 	gint retval = TRUE;
 
-	g_shell_parse_argv (gtk_entry_get_text (GTK_ENTRY (dialog->details->entry)),
-			    &argc, &argv, &error);
+	if (dialog->details->desktop_file != NULL) {
+		GKeyFile *keyfile;
+		
+		keyfile = g_key_file_new ();
+		if (g_key_file_load_from_file (keyfile, dialog->details->desktop_file,
+						0, NULL))
+			command = g_strdup (g_key_file_get_string (keyfile,
+								   DESKTOP_ENTRY_GROUP,
+				      			           GNOME_DESKTOP_ITEM_EXEC,
+								   NULL));
+		g_key_file_free (keyfile);
+	}
+
+	if (command == NULL)
+		command = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->details->entry)));
+
+	g_shell_parse_argv (command, &argc, &argv, &error);
 
 	if (error) {
 		eel_show_error_dialog (_("Could not run application"),
@@ -173,6 +218,7 @@
  cleanup:
 	g_strfreev (argv);
 	g_free (path);
+	g_free (command);
 
 	return retval;
 }
@@ -181,13 +227,30 @@
 get_app_name (EelOpenWithDialog *dialog)
 {
 	GError *error = NULL;
+	char *command;
 	char *basename;
 	char *unquoted;
 	char **argv;
 	int argc;
 
-	g_shell_parse_argv (gtk_entry_get_text (GTK_ENTRY (dialog->details->entry)),
-			    &argc, &argv, &error);
+	command = NULL;
+	if (dialog->details->desktop_file != NULL) {
+		GKeyFile *keyfile;
+		
+		keyfile = g_key_file_new ();
+		if (g_key_file_load_from_file (keyfile, dialog->details->desktop_file,
+						0, NULL))
+			command = g_strdup (g_key_file_get_string (keyfile,
+								   DESKTOP_ENTRY_GROUP,
+				      			           GNOME_DESKTOP_ITEM_EXEC,
+								   NULL));
+		g_key_file_free (keyfile);
+	}
+
+	if (command == NULL)
+		command = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->details->entry)));
+
+	g_shell_parse_argv (command, &argc, &argv, &error);
 
 	if (error) {
 		eel_show_error_dialog (_("Could not run application"),
@@ -195,6 +258,7 @@
 				       _("Could not run application"),
 				       GTK_WINDOW (dialog));
 		g_error_free (error);
+		g_free (command);
 
 		return NULL;
 	}
@@ -210,6 +274,7 @@
 
 	g_free (unquoted);
 	g_strfreev (argv);
+	g_free (command);
 
 	return basename;
 }
@@ -229,22 +294,28 @@
 					dialog->details->new_glob);
 
 	}
-	
+
 	app = eel_mime_check_for_duplicates (dialog->details->mime_type,
 					     gtk_entry_get_text (GTK_ENTRY (dialog->details->entry)));
 	if (app != NULL)
 		return app;
 
 
-	app_name = get_app_name (dialog);
-
-	if (app_name) {
-		app = eel_mime_add_application (dialog->details->mime_type,
-						gtk_entry_get_text (GTK_ENTRY (dialog->details->entry)),
-						app_name,
-						FALSE);
+	if (dialog->details->desktop_file != NULL) {
+		app = eel_mime_add_desktop_file (dialog->details->desktop_file,
+						 dialog->details->mime_type,
+						 FALSE);
 	} else {
-		app = NULL;
+		app_name = get_app_name (dialog);
+
+		if (app_name) {
+			app = eel_mime_add_application (dialog->details->mime_type,
+							gtk_entry_get_text (GTK_ENTRY (dialog->details->entry)),
+							app_name,
+							FALSE);
+		} else {
+			app = NULL;
+		}
 	}
 
 	if (!app) {
@@ -387,40 +458,342 @@
 
 static void
 entry_changed_cb (GtkWidget *entry,
-		  GtkWidget *button)
+		  EelOpenWithDialog *dialog)
 {
-	if (gtk_entry_get_text (GTK_ENTRY (entry))[0] == '\000')
-		gtk_widget_set_sensitive (button, FALSE);
+	/* We are writing in the entry, so we are not using a known .dekstop
+	 * file anymore */
+	g_free (dialog->details->desktop_file);
+	dialog->details->desktop_file = NULL;
+
+	if (gtk_entry_get_text (GTK_ENTRY (dialog->details->entry))[0] == '\000')
+		gtk_widget_set_sensitive (dialog->details->button, FALSE);
 	else
-		gtk_widget_set_sensitive (button, TRUE);
+		gtk_widget_set_sensitive (dialog->details->button, TRUE);
+}
+
+static gboolean
+eel_open_with_dialog_add_icon_idle (EelOpenWithDialog *dialog)
+{
+	GtkTreeIter   iter;
+	GtkTreePath  *path;
+	GdkPixbuf    *pixbuf;
+	char         *file;
+	gboolean      long_operation;
+
+	long_operation = FALSE;
+	do {
+		if (!dialog->details->add_icon_paths) {
+			dialog->details->add_icons_idle_id = 0;
+			return FALSE;
+		}
+
+		path = dialog->details->add_icon_paths->data;
+		dialog->details->add_icon_paths->data = NULL;
+		dialog->details->add_icon_paths = g_slist_delete_link (dialog->details->add_icon_paths,
+						              dialog->details->add_icon_paths);
+
+		if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->details->program_list_store),
+					      &iter,
+					      path)) {
+			gtk_tree_path_free (path);
+			continue;
+		}
+		
+		gtk_tree_path_free (path);
+
+		gtk_tree_model_get (GTK_TREE_MODEL (dialog->details->program_list_store), &iter,
+				    COLUMN_ICON_FILE, &file, -1);
+
+		if (g_path_is_absolute (file)) {
+			pixbuf = gdk_pixbuf_new_from_file_at_size (file, 24, 24, 0);
+			long_operation = TRUE;
+		} else {
+			char *icon_no_extension;
+			char *p;
+
+			icon_no_extension = g_strdup (file);
+			p = strrchr (icon_no_extension, '.');
+			if (p &&
+			    (strcmp (p, ".png") == 0 ||
+			     strcmp (p, ".xpm") == 0 ||
+			     strcmp (p, ".svg") == 0)) {
+				*p = 0;
+			}
+			pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+							   icon_no_extension, 24, 0, NULL);
+			g_free (icon_no_extension);
+		}
+		if (pixbuf) {
+			gtk_list_store_set (dialog->details->program_list_store, &iter, COLUMN_ICON, pixbuf, -1);
+			g_object_unref (pixbuf);
+		}
+		g_free (file);
+		
+	/* don't go back into the main loop if this wasn't very hard to do */
+	} while (!long_operation);
+
+	return TRUE;
+}
+
+static int
+compare_applications (MenuTreeEntry *a,
+		      MenuTreeEntry *b)
+{
+	return g_utf8_collate (menu_tree_entry_get_name (a),
+			       menu_tree_entry_get_name (b));
 }
 
-static GtkWidget *
-get_run_dialog_image (void)
+static GSList *
+get_all_applications_from_dir (MenuTreeDirectory *directory,
+			       GSList            *list)
 {
-	GtkWidget *image;
-	static gboolean initted = FALSE;
+	GSList *subdirs;
+	GSList *l;
 
-	if (!initted) {
-		GtkIconFactory *ifactory;
-		GtkIconSet *iset;
-		GtkIconSource *isource;
+	list = g_slist_concat (list,
+	menu_tree_directory_get_entries (directory));
 
-		ifactory = gtk_icon_factory_new ();
-		iset = gtk_icon_set_new ();
-		isource = gtk_icon_source_new ();
-		gtk_icon_source_set_icon_name (isource, "gnome-run");
-		gtk_icon_set_add_source (iset, isource);
-		gtk_icon_factory_add (ifactory, "gnome-run", iset);
-		gtk_icon_factory_add_default (ifactory);
+	subdirs = menu_tree_directory_get_subdirs (directory);
+	for (l = subdirs; l; l = l->next) {
+		MenuTreeDirectory *subdir = l->data;
 
-		initted = TRUE;
+		list = get_all_applications_from_dir (subdir, list);
+
+		menu_tree_directory_unref (subdir);
 	}
+	g_slist_free (subdirs);
+
+	return list;
+}
+
+
+static GSList *
+get_all_applications (void)
+{
+	MenuTree          *tree;
+	MenuTreeDirectory *root;
+	GSList            *retval;
+
+	tree = menu_tree_lookup ("applications.menu");
+
+	root = menu_tree_get_root_directory (tree);
+
+	retval = get_all_applications_from_dir (root, NULL);
+
+	menu_tree_directory_unref (root);
+	menu_tree_unref (tree);
+
+	retval = g_slist_sort (retval,
+			       (GCompareFunc) compare_applications);
+
+	return retval;
+}
+
+
+static gboolean
+eel_open_with_dialog_add_items_idle (EelOpenWithDialog *dialog)
+{
+	GtkCellRenderer   *renderer;
+	GtkTreeViewColumn *column;
+	GSList            *all_applications;
+	GSList            *l;
+	const char        *prev_name;
+
+	/* create list store */
+	dialog->details->program_list_store = gtk_list_store_new (NUM_COLUMNS,
+								  GDK_TYPE_PIXBUF,
+								  G_TYPE_STRING,
+								  G_TYPE_STRING,
+								  G_TYPE_STRING,
+								  G_TYPE_STRING,
+								  G_TYPE_STRING);
+
+	all_applications = get_all_applications ();
+	
+	prev_name = NULL;
+	for (l = all_applications; l; l = l->next) {
+		MenuTreeEntry *entry = l->data;
+		GtkTreeIter    iter;
+		GtkTreePath   *path;
+
+		if (prev_name && strcmp (menu_tree_entry_get_name (entry), prev_name) == 0) {
+			menu_tree_entry_unref (entry);
+			continue;
+		}
 
-	image = gtk_image_new_from_stock ("gnome-run",
-					  GTK_ICON_SIZE_DIALOG);
+		gtk_list_store_append (dialog->details->program_list_store, &iter);
+		gtk_list_store_set (dialog->details->program_list_store, &iter,
+				    COLUMN_ICON,      NULL,
+				    COLUMN_ICON_FILE, menu_tree_entry_get_icon (entry),
+				    COLUMN_NAME,      menu_tree_entry_get_name (entry),
+				    COLUMN_COMMENT,   menu_tree_entry_get_comment (entry),
+				    COLUMN_PATH,      menu_tree_entry_get_desktop_file_path (entry),
+				    -1);
+
+		path = gtk_tree_model_get_path (GTK_TREE_MODEL (dialog->details->program_list_store), &iter);
+		if (path != NULL)
+			dialog->details->add_icon_paths = g_slist_prepend (dialog->details->add_icon_paths, path);
+
+		prev_name = menu_tree_entry_get_name (entry);
+		menu_tree_entry_unref (entry);
+	}
+	g_slist_free (all_applications);
+
+	gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->details->program_list), 
+				 GTK_TREE_MODEL (dialog->details->program_list_store));
+
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	column = gtk_tree_view_column_new ();
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_set_attributes (column, renderer,
+                                             "pixbuf", COLUMN_ICON,
+                                             NULL);
+        
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_column_set_attributes (column, renderer,
+                                             "text", COLUMN_NAME,
+                                             NULL);
+					          
+	gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->details->program_list), column);
+
+	dialog->details->add_icon_paths = g_slist_reverse (dialog->details->add_icon_paths);
+
+	if (!dialog->details->add_icons_idle_id)
+		dialog->details->add_icons_idle_id =
+			g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) eel_open_with_dialog_add_icon_idle,
+					 dialog, NULL);
 
-	return image;
+	dialog->details->add_items_idle_id = 0;					 
+	return FALSE;
+}
+
+
+static char *
+remove_parameters (const char *exec)
+{
+	GString *str;
+	char    *retval, *p;
+
+	str = g_string_new (exec);
+
+	while ((p = strstr (str->str, "%"))) {
+		switch (p [1]) {
+		case '%':
+			g_string_erase (str, p - str->str, 1);
+			break;
+		case 'U':
+		case 'F':
+		case 'N':
+		case 'D':
+		case 'f':
+		case 'u':
+		case 'd':
+		case 'n':
+		case 'm':
+		case 'i':
+		case 'c':
+		case 'k':
+		case 'v':
+			g_string_erase (str, p - str->str, 2);
+			break;
+		default:
+			break;
+		}
+	}
+
+	retval = str->str;
+	g_string_free (str, FALSE);
+
+	return retval;
+}
+
+static void
+program_list_selection_changed (GtkTreeSelection  *selection,
+				EelOpenWithDialog *dialog)
+{
+	GtkTreeModel     *model;
+	GtkTreeIter       iter;
+	const char       *temp;
+	char             *path, *stripped;
+	GKeyFile         *keyfile;
+		
+	if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		gtk_widget_set_sensitive (dialog->details->button, FALSE);
+		return;
+	}
+
+	path = NULL;
+	gtk_tree_model_get (model, &iter,
+			    COLUMN_PATH, &path,
+			    -1);
+				  
+	if (path == NULL)
+		return;
+
+	keyfile = g_key_file_new ();
+	if (!g_key_file_load_from_file (keyfile, path,
+					G_KEY_FILE_KEEP_COMMENTS |
+					G_KEY_FILE_KEEP_TRANSLATIONS, NULL)) {
+		g_free (path);
+		g_key_file_free (keyfile);
+		return;
+	}
+
+	temp = g_key_file_get_string (keyfile, DESKTOP_ENTRY_GROUP,
+				      GNOME_DESKTOP_ITEM_EXEC, NULL);
+			
+	if (temp) {
+		stripped = remove_parameters (temp);
+		gtk_entry_set_text (GTK_ENTRY (dialog->details->entry), stripped);
+		g_free (stripped);
+	} else {
+		temp = g_key_file_get_string (keyfile, DESKTOP_ENTRY_GROUP,
+					      GNOME_DESKTOP_ITEM_URL, NULL);
+		gtk_entry_set_text (GTK_ENTRY (dialog->details->entry), sure_string (temp));
+	}
+
+	temp = g_key_file_get_locale_string (keyfile, DESKTOP_ENTRY_GROUP,
+					     GNOME_DESKTOP_ITEM_COMMENT, NULL, NULL);
+	gtk_label_set_text (GTK_LABEL (dialog->details->desc_label), sure_string (temp));
+	gtk_widget_set_sensitive (dialog->details->button, TRUE);
+
+	g_free (dialog->details->desktop_file);
+	dialog->details->desktop_file = g_strdup (path);
+			
+	g_free (path);
+	g_key_file_free (keyfile);
+}
+
+static void
+program_list_selection_activated (GtkTreeView       *view,
+				  GtkTreePath       *path,
+				  GtkTreeViewColumn *column,
+				  EelOpenWithDialog *dialog)
+{
+	GtkTreeSelection *selection;
+
+	/* update the entry with the info from the selection */
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->details->program_list));	
+	program_list_selection_changed (selection, dialog);
+	
+	gtk_dialog_response (GTK_DIALOG (&dialog->parent), RESPONSE_OPEN);
+}
+
+static void
+expander_toggled (GtkWidget *expander, EelOpenWithDialog *dialog)
+{
+	if (gtk_expander_get_expanded (GTK_EXPANDER (expander)) == TRUE) {
+		gtk_widget_grab_focus (dialog->details->entry);
+		gtk_window_resize (GTK_WINDOW (dialog), 400, 1);
+	}
+	else {
+		GtkTreeSelection *selection;
+
+		gtk_widget_grab_focus (dialog->details->program_list);
+		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->details->program_list));
+		program_list_selection_changed (selection, dialog);
+	}
 }
 
 static void
@@ -428,38 +801,23 @@
 {
 	GtkWidget *hbox;
 	GtkWidget *vbox;
-	GtkWidget *button;
-	GtkWidget *image;
 	GtkWidget *label;
 	GtkWidget *align;
+	GtkWidget *scrolled_window;
+	GtkWidget *expander;
+	GtkTreeSelection *selection;
 
 	dialog->details = g_new0 (EelOpenWithDialogDetails, 1);
 
 	gtk_window_set_title (GTK_WINDOW (dialog), _("Open With"));
-	gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1);
 	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
 	gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
 	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 	gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
 
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 12);
-	hbox = gtk_hbox_new (FALSE, 12);
-	gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
 
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
-			    TRUE, TRUE, 0);
-	gtk_widget_show (hbox);
-
-	image = get_run_dialog_image ();
-	gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
-	gtk_widget_show (image);
-	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
-
-	/* Pack the text and the entry */
 	vbox = gtk_vbox_new (FALSE, 6);
-	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
-	gtk_widget_show (vbox);
-
 	dialog->details->label = gtk_label_new ("");
 	gtk_misc_set_alignment (GTK_MISC (dialog->details->label), 0.0, 0.5);
 	gtk_label_set_line_wrap (GTK_LABEL (dialog->details->label), TRUE);
@@ -467,8 +825,57 @@
 			    FALSE, FALSE, 0);
 	gtk_widget_show (dialog->details->label);
 
+
+	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+	gtk_widget_set_size_request (scrolled_window, 400, 400);
+	
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
+					     GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+	dialog->details->program_list = gtk_tree_view_new ();
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dialog->details->program_list),
+					   FALSE);
+	gtk_container_add (GTK_CONTAINER (scrolled_window), dialog->details->program_list);
+	
+	gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
+
+	dialog->details->desc_label = gtk_label_new (_("Select an application to view its description."));
+	gtk_misc_set_alignment (GTK_MISC (dialog->details->desc_label), 0.0, 0.5);
+	gtk_label_set_justify (GTK_LABEL (dialog->details->desc_label), GTK_JUSTIFY_LEFT);
+	gtk_label_set_line_wrap (GTK_LABEL (dialog->details->desc_label), TRUE);
+	gtk_label_set_single_line_mode (GTK_LABEL (dialog->details->desc_label), FALSE);
+	gtk_box_pack_start (GTK_BOX (vbox), dialog->details->desc_label, FALSE, FALSE, 0);
+	
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->details->program_list));
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+	g_signal_connect (selection, "changed",
+			  G_CALLBACK (program_list_selection_changed),
+			  dialog);
+	g_signal_connect (dialog->details->program_list, "row-activated",
+			  G_CALLBACK (program_list_selection_activated),
+			  dialog);
+
+	dialog->details->add_items_idle_id = g_idle_add_full (G_PRIORITY_LOW,
+						     (GSourceFunc) eel_open_with_dialog_add_items_idle,
+						      dialog, NULL);
+
+
+	
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
+	gtk_widget_show_all (vbox);
+
+
+	expander = gtk_expander_new_with_mnemonic (_("Use a _custom command"));
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), expander,
+			    FALSE, FALSE, 0);
+	g_signal_connect_after (expander, "activate", G_CALLBACK (expander_toggled), dialog);
+
+	gtk_widget_show (expander);
+
 	hbox = gtk_hbox_new (FALSE, 6);
-	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (expander), hbox);
 	gtk_widget_show (hbox);
 
 	dialog->details->entry = gtk_entry_new ();
@@ -478,11 +885,11 @@
 			    TRUE, TRUE, 0);
 	gtk_widget_show (dialog->details->entry);
 
-	button = gtk_button_new_with_mnemonic (_("_Browse..."));
-	g_signal_connect (button, "clicked",
+	dialog->details->button = gtk_button_new_with_mnemonic (_("_Browse..."));
+	g_signal_connect (dialog->details->button, "clicked",
 			  G_CALLBACK (browse_clicked_cb), dialog);
-	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
-	gtk_widget_show (button);
+	gtk_box_pack_start (GTK_BOX (hbox), dialog->details->button, FALSE, FALSE, 0);
+	gtk_widget_show (dialog->details->button);
 
 	gtk_dialog_add_button (GTK_DIALOG (dialog),
 			       GTK_STOCK_CANCEL,
@@ -490,25 +897,18 @@
 
 
 	/* Create a custom stock icon */
-	button = gtk_button_new ();
+	dialog->details->button = gtk_button_new ();
 
 	/* Hook up the entry to the button */
-	gtk_widget_set_sensitive (button, FALSE);
+	gtk_widget_set_sensitive (dialog->details->button, FALSE);
 	g_signal_connect (G_OBJECT (dialog->details->entry), "changed",
-			  G_CALLBACK (entry_changed_cb), button);
+			  G_CALLBACK (entry_changed_cb), dialog);
 
 	hbox = gtk_hbox_new (FALSE, 2);
 	gtk_widget_show (hbox);
 
-	image = gtk_image_new_from_stock (GTK_STOCK_EXECUTE,
-					  GTK_ICON_SIZE_BUTTON);
-	gtk_widget_show (image);
-	dialog->details->open_image = image;
-
-	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
-
 	label = gtk_label_new_with_mnemonic ("_Open");
-	gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (dialog->details->button));
 	gtk_widget_show (label);
 	dialog->details->open_label = label;
 
@@ -517,15 +917,16 @@
 	align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
 	gtk_widget_show (align);
 
-	gtk_widget_show (button);
-	GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+	gtk_widget_show (dialog->details->button);
+	GTK_WIDGET_SET_FLAGS (dialog->details->button, GTK_CAN_DEFAULT);
 
 
 	gtk_container_add (GTK_CONTAINER (align), hbox);
-	gtk_container_add (GTK_CONTAINER (button), align);
+	gtk_container_add (GTK_CONTAINER (dialog->details->button), align);
 
 	gtk_dialog_add_action_widget (GTK_DIALOG (dialog),
-				      button, RESPONSE_OPEN);
+				      dialog->details->button, RESPONSE_OPEN);
+
 
 	gtk_dialog_set_default_response (GTK_DIALOG (dialog),
 					 RESPONSE_OPEN);
@@ -629,10 +1030,6 @@
 	
 	gtk_label_set_text_with_mnemonic (GTK_LABEL (dialog->details->open_label),
 					  _("_Add"));
-	gtk_image_set_from_stock (GTK_IMAGE (dialog->details->open_image),
-				  GTK_STOCK_ADD,
-				  GTK_ICON_SIZE_BUTTON);
-
 	gtk_window_set_title (GTK_WINDOW (dialog), _("Add Application"));
 
 	return GTK_WIDGET (dialog);


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