diff options
Diffstat (limited to 'libcaja-private/caja-mime-application-chooser.c')
-rw-r--r-- | libcaja-private/caja-mime-application-chooser.c | 746 |
1 files changed, 746 insertions, 0 deletions
diff --git a/libcaja-private/caja-mime-application-chooser.c b/libcaja-private/caja-mime-application-chooser.c new file mode 100644 index 00000000..a183f0c5 --- /dev/null +++ b/libcaja-private/caja-mime-application-chooser.c @@ -0,0 +1,746 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* + caja-mime-application-chooser.c: an mime-application chooser + + Copyright (C) 2004 Novell, Inc. + Copyright (C) 2007 Red Hat, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but APPLICATIONOUT ANY WARRANTY; applicationout even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along application the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Dave Camp <[email protected]> + Alexander Larsson <[email protected]> +*/ + +#include <config.h> +#include "caja-mime-application-chooser.h" + +#include "caja-open-with-dialog.h" +#include "caja-signaller.h" +#include "caja-file.h" +#include <eel/eel-stock-dialogs.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-string.h> + +#include <string.h> +#include <glib/gi18n-lib.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gtk/gtk.h> +#include <gio/gio.h> + +struct _CajaMimeApplicationChooserDetails +{ + char *uri; + + char *content_type; + char *extension; + char *type_description; + char *orig_mime_type; + + guint refresh_timeout; + + GtkWidget *label; + GtkWidget *entry; + GtkWidget *treeview; + GtkWidget *remove_button; + + gboolean for_multiple_files; + + GtkListStore *model; + GtkCellRenderer *toggle_renderer; +}; + +enum +{ + COLUMN_APPINFO, + COLUMN_DEFAULT, + COLUMN_ICON, + COLUMN_NAME, + NUM_COLUMNS +}; + +G_DEFINE_TYPE (CajaMimeApplicationChooser, caja_mime_application_chooser, GTK_TYPE_VBOX); + +static void refresh_model (CajaMimeApplicationChooser *chooser); +static void refresh_model_soon (CajaMimeApplicationChooser *chooser); +static void mime_type_data_changed_cb (GObject *signaller, + gpointer user_data); + +static void +caja_mime_application_chooser_finalize (GObject *object) +{ + CajaMimeApplicationChooser *chooser; + + chooser = CAJA_MIME_APPLICATION_CHOOSER (object); + + if (chooser->details->refresh_timeout) + { + g_source_remove (chooser->details->refresh_timeout); + } + + g_signal_handlers_disconnect_by_func (caja_signaller_get_current (), + G_CALLBACK (mime_type_data_changed_cb), + chooser); + + + g_free (chooser->details->uri); + g_free (chooser->details->content_type); + g_free (chooser->details->extension); + g_free (chooser->details->type_description); + g_free (chooser->details->orig_mime_type); + + g_free (chooser->details); + + G_OBJECT_CLASS (caja_mime_application_chooser_parent_class)->finalize (object); +} + +static void +caja_mime_application_chooser_destroy (GtkObject *object) +{ + GTK_OBJECT_CLASS (caja_mime_application_chooser_parent_class)->destroy (object); +} + +static void +caja_mime_application_chooser_class_init (CajaMimeApplicationChooserClass *class) +{ + GObjectClass *gobject_class; + GtkObjectClass *object_class; + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = caja_mime_application_chooser_finalize; + + object_class = GTK_OBJECT_CLASS (class); + object_class->destroy = caja_mime_application_chooser_destroy; +} + +static void +default_toggled_cb (GtkCellRendererToggle *renderer, + const char *path_str, + gpointer user_data) +{ + CajaMimeApplicationChooser *chooser; + GtkTreeIter iter; + GtkTreePath *path; + GError *error; + + chooser = CAJA_MIME_APPLICATION_CHOOSER (user_data); + + path = gtk_tree_path_new_from_string (path_str); + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->model), + &iter, path)) + { + gboolean is_default; + gboolean success; + GAppInfo *info; + char *message; + + gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->model), + &iter, + COLUMN_DEFAULT, &is_default, + COLUMN_APPINFO, &info, + -1); + + if (!is_default && info != NULL) + { + error = NULL; + if (chooser->details->extension) + { + success = g_app_info_set_as_default_for_extension (info, + chooser->details->extension, + &error); + } + else + { + success = g_app_info_set_as_default_for_type (info, + chooser->details->content_type, + &error); + } + + if (!success) + { + message = g_strdup_printf (_("Could not set application as the default: %s"), error->message); + eel_show_error_dialog (_("Could not set as default application"), + message, + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (chooser)))); + g_free (message); + g_error_free (error); + } + + g_signal_emit_by_name (caja_signaller_get_current (), + "mime_data_changed"); + } + g_object_unref (info); + } + gtk_tree_path_free (path); +} + +static GAppInfo * +get_selected_application (CajaMimeApplicationChooser *chooser) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + GAppInfo *info; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chooser->details->treeview)); + + info = NULL; + if (gtk_tree_selection_get_selected (selection, + NULL, + &iter)) + { + gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->model), + &iter, + COLUMN_APPINFO, &info, + -1); + } + + return info; +} + +static void +selection_changed_cb (GtkTreeSelection *selection, + gpointer user_data) +{ + CajaMimeApplicationChooser *chooser; + GAppInfo *info; + + chooser = CAJA_MIME_APPLICATION_CHOOSER (user_data); + + info = get_selected_application (chooser); + if (info) + { + gtk_widget_set_sensitive (chooser->details->remove_button, + g_app_info_can_remove_supports_type (info)); + + g_object_unref (info); + } + else + { + gtk_widget_set_sensitive (chooser->details->remove_button, + FALSE); + } +} + +static GtkWidget * +create_tree_view (CajaMimeApplicationChooser *chooser) +{ + GtkWidget *treeview; + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + + treeview = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); + + store = gtk_list_store_new (NUM_COLUMNS, + G_TYPE_APP_INFO, + G_TYPE_BOOLEAN, + G_TYPE_ICON, + G_TYPE_STRING); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + COLUMN_NAME, + GTK_SORT_ASCENDING); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), + GTK_TREE_MODEL (store)); + chooser->details->model = store; + + renderer = gtk_cell_renderer_toggle_new (); + g_signal_connect (renderer, "toggled", + G_CALLBACK (default_toggled_cb), + chooser); + gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE (renderer), + TRUE); + + column = gtk_tree_view_column_new_with_attributes (_("Default"), + renderer, + "active", + COLUMN_DEFAULT, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + chooser->details->toggle_renderer = renderer; + + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL); + column = gtk_tree_view_column_new_with_attributes (_("Icon"), + renderer, + "gicon", + COLUMN_ICON, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Name"), + renderer, + "markup", + COLUMN_NAME, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_connect (selection, "changed", + G_CALLBACK (selection_changed_cb), + chooser); + + return treeview; +} + +static void +add_clicked_cb (GtkButton *button, + gpointer user_data) +{ + CajaMimeApplicationChooser *chooser; + GtkWidget *dialog; + + chooser = CAJA_MIME_APPLICATION_CHOOSER (user_data); + + if (chooser->details->for_multiple_files) + { + dialog = caja_add_application_dialog_new_for_multiple_files (chooser->details->extension, + chooser->details->orig_mime_type); + } + else + { + dialog = caja_add_application_dialog_new (chooser->details->uri, + chooser->details->orig_mime_type); + } + gtk_window_set_screen (GTK_WINDOW (dialog), + gtk_widget_get_screen (GTK_WIDGET (chooser))); + gtk_widget_show (dialog); +} + +static void +remove_clicked_cb (GtkButton *button, + gpointer user_data) +{ + CajaMimeApplicationChooser *chooser; + GError *error; + GAppInfo *info; + + chooser = CAJA_MIME_APPLICATION_CHOOSER (user_data); + + info = get_selected_application (chooser); + + if (info) + { + error = NULL; + if (!g_app_info_remove_supports_type (info, + chooser->details->content_type, + &error)) + { + eel_show_error_dialog (_("Could not remove application"), + error->message, + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (chooser)))); + g_error_free (error); + + } + g_signal_emit_by_name (caja_signaller_get_current (), + "mime_data_changed"); + g_object_unref (info); + } +} + +static void +reset_clicked_cb (GtkButton *button, + gpointer user_data) +{ + CajaMimeApplicationChooser *chooser; + + chooser = CAJA_MIME_APPLICATION_CHOOSER (user_data); + + g_app_info_reset_type_associations (chooser->details->content_type); + + g_signal_emit_by_name (caja_signaller_get_current (), + "mime_data_changed"); +} + +static void +mime_type_data_changed_cb (GObject *signaller, + gpointer user_data) +{ + CajaMimeApplicationChooser *chooser; + + chooser = CAJA_MIME_APPLICATION_CHOOSER (user_data); + + refresh_model_soon (chooser); +} + +static void +caja_mime_application_chooser_init (CajaMimeApplicationChooser *chooser) +{ + GtkWidget *box; + GtkWidget *scrolled; + GtkWidget *button; + + chooser->details = g_new0 (CajaMimeApplicationChooserDetails, 1); + + chooser->details->for_multiple_files = FALSE; + gtk_container_set_border_width (GTK_CONTAINER (chooser), 8); + gtk_box_set_spacing (GTK_BOX (chooser), 0); + gtk_box_set_homogeneous (GTK_BOX (chooser), FALSE); + + chooser->details->label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (chooser->details->label), 0.0, 0.5); + gtk_label_set_line_wrap (GTK_LABEL (chooser->details->label), TRUE); + gtk_label_set_line_wrap_mode (GTK_LABEL (chooser->details->label), + PANGO_WRAP_WORD_CHAR); + gtk_box_pack_start (GTK_BOX (chooser), chooser->details->label, + FALSE, FALSE, 0); + + gtk_widget_show (chooser->details->label); + + scrolled = gtk_scrolled_window_new (NULL, NULL); + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), + GTK_SHADOW_IN); + + gtk_widget_show (scrolled); + gtk_box_pack_start (GTK_BOX (chooser), scrolled, TRUE, TRUE, 6); + + chooser->details->treeview = create_tree_view (chooser); + gtk_widget_show (chooser->details->treeview); + + gtk_container_add (GTK_CONTAINER (scrolled), + chooser->details->treeview); + + box = gtk_hbutton_box_new (); + gtk_box_set_spacing (GTK_BOX (box), 6); + gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_END); + gtk_box_pack_start (GTK_BOX (chooser), box, FALSE, FALSE, 6); + gtk_widget_show (box); + + button = gtk_button_new_from_stock (GTK_STOCK_ADD); + g_signal_connect (button, "clicked", + G_CALLBACK (add_clicked_cb), + chooser); + + gtk_widget_show (button); + gtk_container_add (GTK_CONTAINER (box), button); + + button = gtk_button_new_from_stock (GTK_STOCK_REMOVE); + g_signal_connect (button, "clicked", + G_CALLBACK (remove_clicked_cb), + chooser); + + gtk_widget_show (button); + gtk_container_add (GTK_CONTAINER (box), button); + + chooser->details->remove_button = button; + + button = gtk_button_new_with_label (_("Reset")); + g_signal_connect (button, "clicked", + G_CALLBACK (reset_clicked_cb), + chooser); + + gtk_widget_show (button); + gtk_container_add (GTK_CONTAINER (box), button); + + g_signal_connect (caja_signaller_get_current (), + "mime_data_changed", + G_CALLBACK (mime_type_data_changed_cb), + chooser); +} + +static char * +get_extension (const char *basename) +{ + char *p; + + p = strrchr (basename, '.'); + + if (p && *(p + 1) != '\0') + { + return g_strdup (p + 1); + } + else + { + return NULL; + } +} + +static gboolean +refresh_model_timeout (gpointer data) +{ + CajaMimeApplicationChooser *chooser = data; + + chooser->details->refresh_timeout = 0; + + refresh_model (chooser); + + return FALSE; +} + +/* This adds a slight delay so that we're sure the mime data is + done writing */ +static void +refresh_model_soon (CajaMimeApplicationChooser *chooser) +{ + if (chooser->details->refresh_timeout != 0) + return; + + chooser->details->refresh_timeout = + g_timeout_add (300, + refresh_model_timeout, + chooser); +} + +static void +refresh_model (CajaMimeApplicationChooser *chooser) +{ + GList *applications; + GAppInfo *default_app; + GList *l; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + + column = gtk_tree_view_get_column (GTK_TREE_VIEW (chooser->details->treeview), 0); + gtk_tree_view_column_set_visible (column, TRUE); + + gtk_list_store_clear (chooser->details->model); + + applications = g_app_info_get_all_for_type (chooser->details->content_type); + default_app = g_app_info_get_default_for_type (chooser->details->content_type, FALSE); + + for (l = applications; l != NULL; l = l->next) + { + GtkTreeIter iter; + gboolean is_default; + GAppInfo *application; + char *escaped; + GIcon *icon; + + application = l->data; + + is_default = default_app && g_app_info_equal (default_app, application); + + escaped = g_markup_escape_text (g_app_info_get_display_name (application), -1); + + icon = g_app_info_get_icon (application); + + gtk_list_store_append (chooser->details->model, &iter); + gtk_list_store_set (chooser->details->model, &iter, + COLUMN_APPINFO, application, + COLUMN_DEFAULT, is_default, + COLUMN_ICON, icon, + COLUMN_NAME, escaped, + -1); + + g_free (escaped); + } + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chooser->details->treeview)); + + if (applications) + { + g_object_set (chooser->details->toggle_renderer, + "visible", TRUE, + NULL); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + } + else + { + GtkTreeIter iter; + char *name; + + gtk_tree_view_column_set_visible (column, FALSE); + gtk_list_store_append (chooser->details->model, &iter); + name = g_strdup_printf ("<i>%s</i>", _("No applications selected")); + gtk_list_store_set (chooser->details->model, &iter, + COLUMN_NAME, name, + COLUMN_APPINFO, NULL, + -1); + g_free (name); + + gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); + } + + if (default_app) + { + g_object_unref (default_app); + } + + eel_g_object_list_free (applications); +} + +static void +set_extension_and_description (CajaMimeApplicationChooser *chooser, + const char *extension, + const char *mime_type) +{ + if (extension != NULL && + g_content_type_is_unknown (mime_type)) + { + chooser->details->extension = g_strdup (extension); + chooser->details->content_type = g_strdup_printf ("application/x-extension-%s", extension); + /* the %s here is a file extension */ + chooser->details->type_description = + g_strdup_printf (_("%s document"), extension); + } + else + { + char *description; + + chooser->details->content_type = g_strdup (mime_type); + description = g_content_type_get_description (mime_type); + if (description == NULL) + { + description = g_strdup (_("Unknown")); + } + + chooser->details->type_description = description; + } +} + +static gboolean +set_uri_and_type (CajaMimeApplicationChooser *chooser, + const char *uri, + const char *mime_type) +{ + char *label; + char *name; + char *emname; + char *extension; + GFile *file; + + chooser->details->uri = g_strdup (uri); + + file = g_file_new_for_uri (uri); + name = g_file_get_basename (file); + g_object_unref (file); + + chooser->details->orig_mime_type = g_strdup (mime_type); + + extension = get_extension (name); + set_extension_and_description (CAJA_MIME_APPLICATION_CHOOSER (chooser), + extension, mime_type); + g_free (extension); + + /* first %s is filename, second %s is mime-type description */ + emname = g_strdup_printf ("<i>%s</i>", name); + label = g_strdup_printf (_("Select an application to open %s and other files of type \"%s\""), + emname, chooser->details->type_description); + g_free (emname); + + gtk_label_set_markup (GTK_LABEL (chooser->details->label), label); + + g_free (label); + g_free (name); + + refresh_model (chooser); + + return TRUE; +} + +static char * +get_extension_from_file (CajaFile *nfile) +{ + char *name; + char *extension; + + name = caja_file_get_name (nfile); + extension = get_extension (name); + + g_free (name); + + return extension; +} + +static gboolean +set_uri_and_type_for_multiple_files (CajaMimeApplicationChooser *chooser, + GList *uris, + const char *mime_type) +{ + char *label; + char *first_extension; + gboolean same_extension; + GList *iter; + + chooser->details->for_multiple_files = TRUE; + chooser->details->uri = NULL; + chooser->details->orig_mime_type = g_strdup (mime_type); + same_extension = TRUE; + first_extension = get_extension_from_file (CAJA_FILE (uris->data)); + iter = uris->next; + + while (iter != NULL) + { + char *extension_current; + + extension_current = get_extension_from_file (CAJA_FILE (iter->data)); + if (eel_strcmp (first_extension, extension_current)) + { + same_extension = FALSE; + g_free (extension_current); + break; + } + iter = iter->next; + + g_free (extension_current); + } + if (!same_extension) + { + set_extension_and_description (CAJA_MIME_APPLICATION_CHOOSER (chooser), + NULL, mime_type); + } + else + { + set_extension_and_description (CAJA_MIME_APPLICATION_CHOOSER (chooser), + first_extension, mime_type); + } + + g_free (first_extension); + + label = g_strdup_printf (_("Open all files of type \"%s\" with:"), + chooser->details->type_description); + gtk_label_set_markup (GTK_LABEL (chooser->details->label), label); + + g_free (label); + + refresh_model (chooser); + + return TRUE; +} + +GtkWidget * +caja_mime_application_chooser_new (const char *uri, + const char *mime_type) +{ + GtkWidget *chooser; + + chooser = gtk_widget_new (CAJA_TYPE_MIME_APPLICATION_CHOOSER, NULL); + + set_uri_and_type (CAJA_MIME_APPLICATION_CHOOSER (chooser), uri, mime_type); + + return chooser; +} + +GtkWidget * +caja_mime_application_chooser_new_for_multiple_files (GList *uris, + const char *mime_type) +{ + GtkWidget *chooser; + + chooser = gtk_widget_new (CAJA_TYPE_MIME_APPLICATION_CHOOSER, NULL); + + set_uri_and_type_for_multiple_files (CAJA_MIME_APPLICATION_CHOOSER (chooser), + uris, mime_type); + + return chooser; +} + |