Logo Search packages:      
Sourcecode: nautilus version File versions  Download package

nautilus-mime-application-chooser.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */

/*
 *  nautilus-mime-application-chooser.c: an mime-application chooser
 *
 *  Copyright (C) 2004 Novell, Inc.
 *  Copyright (C) 2007, 2010 Red Hat, Inc.
 *
 *  The Gnome 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 Gnome 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 Gnome 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 <dave@novell.com>
 *           Alexander Larsson <alexl@redhat.com>
 *           Cosimo Cecchi <ccecchi@redhat.com>
 */

#include <config.h>
#include "nautilus-mime-application-chooser.h"

#include "nautilus-file.h"
#include "nautilus-signaller.h"
#include <eel/eel-stock-dialogs.h>

#include <string.h>
#include <glib/gi18n-lib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>
#include <gio/gio.h>

00042 struct _NautilusMimeApplicationChooserDetails {
      GList *files;
      char *uri;

      char *content_type;

      GtkWidget *label;
      GtkWidget *entry;
      GtkWidget *set_as_default_button;
      GtkWidget *open_with_widget;
      GtkWidget *add_button;
};

enum {
      PROP_CONTENT_TYPE = 1,
      PROP_URI,
      PROP_FILES,
      NUM_PROPERTIES
};

static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };

G_DEFINE_TYPE (NautilusMimeApplicationChooser, nautilus_mime_application_chooser, GTK_TYPE_BOX);

static void
add_clicked_cb (GtkButton *button,
            gpointer user_data)
{
      NautilusMimeApplicationChooser *chooser = user_data;
      GAppInfo *info;
      gchar *message;
      GError *error = NULL;

      info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget));

      if (info == NULL)
            return;

      g_app_info_set_as_last_used_for_type (info, chooser->details->content_type, &error);

      if (error != NULL) {
            message = g_strdup_printf (_("Error while adding \"%s\": %s"),
                                 g_app_info_get_display_name (info), error->message);
            eel_show_error_dialog (_("Could not add application"),
                               message,
                               GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (chooser))));
            g_error_free (error);
            g_free (message);
      } else {          
            gtk_app_chooser_refresh (GTK_APP_CHOOSER (chooser->details->open_with_widget));
            g_signal_emit_by_name (nautilus_signaller_get_current (), "mime_data_changed");
      }

      g_object_unref (info);
}

static void
remove_clicked_cb (GtkMenuItem *item, 
               gpointer user_data)
{
      NautilusMimeApplicationChooser *chooser = user_data;
      GError *error;
      GAppInfo *info;

      info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget));

      if (info) {
            error = NULL;
            if (!g_app_info_remove_supports_type (info,
                                          chooser->details->content_type,
                                          &error)) {
                  eel_show_error_dialog (_("Could not forget association"),
                                     error->message,
                                     GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (chooser))));
                  g_error_free (error);
                  
            }

            gtk_app_chooser_refresh (GTK_APP_CHOOSER (chooser->details->open_with_widget));
            g_object_unref (info);
      }

      g_signal_emit_by_name (nautilus_signaller_get_current (), "mime_data_changed");
}

static void
populate_popup_cb (GtkAppChooserWidget *widget,
               GtkMenu *menu,
               GAppInfo *app,
               gpointer user_data)
{
      GtkWidget *item;
      NautilusMimeApplicationChooser *chooser = user_data;

      if (g_app_info_can_remove_supports_type (app)) {
            item = gtk_menu_item_new_with_label (_("Forget association"));
            gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
            gtk_widget_show (item);
            
            g_signal_connect (item, "activate",
                          G_CALLBACK (remove_clicked_cb), chooser);
      }
}

static void
reset_clicked_cb (GtkButton *button,
                  gpointer   user_data)
{
      NautilusMimeApplicationChooser *chooser;
      
      chooser = NAUTILUS_MIME_APPLICATION_CHOOSER (user_data);

      g_app_info_reset_type_associations (chooser->details->content_type);
      gtk_app_chooser_refresh (GTK_APP_CHOOSER (chooser->details->open_with_widget));

      g_signal_emit_by_name (nautilus_signaller_get_current (), "mime_data_changed");
}

static void
set_as_default_clicked_cb (GtkButton *button,
                     gpointer user_data)
{
      NautilusMimeApplicationChooser *chooser = user_data;
      GAppInfo *info;
      GError *error = NULL;
      gchar *message = NULL;

      info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget));

      g_app_info_set_as_default_for_type (info, chooser->details->content_type,
                                  &error);

      if (error != NULL) {
            message = g_strdup_printf (_("Error while setting \"%s\" as default application: %s"),
                                 g_app_info_get_display_name (info), error->message);
            eel_show_error_dialog (_("Could not set as default"),
                               message,
                               GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (chooser))));
      }

      g_object_unref (info);

      gtk_app_chooser_refresh (GTK_APP_CHOOSER (chooser->details->open_with_widget));
      g_signal_emit_by_name (nautilus_signaller_get_current (), "mime_data_changed");
}

static gint
app_compare (gconstpointer a,
           gconstpointer b)
{
      return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b));
}

static gboolean
app_info_can_add (GAppInfo *info,
              const gchar *content_type)
{
      GList *recommended, *fallback;
      gboolean retval = FALSE;

      recommended = g_app_info_get_recommended_for_type (content_type);
      fallback = g_app_info_get_fallback_for_type (content_type);

      if (g_list_find_custom (recommended, info, app_compare)) {
            goto out;
      }

      if (g_list_find_custom (fallback, info, app_compare)) {
            goto out;
      }

      retval = TRUE;

 out:
      g_list_free_full (recommended, g_object_unref);
      g_list_free_full (fallback, g_object_unref);

      return retval;
}

static void
application_selected_cb (GtkAppChooserWidget *widget,
                   GAppInfo *info,
                   gpointer user_data)
{
      NautilusMimeApplicationChooser *chooser = user_data;
      GAppInfo *default_app;

      default_app = g_app_info_get_default_for_type (chooser->details->content_type, FALSE);
      gtk_widget_set_sensitive (chooser->details->set_as_default_button,
                          !g_app_info_equal (info, default_app));

      gtk_widget_set_sensitive (chooser->details->add_button,
                          app_info_can_add (info, chooser->details->content_type));

      g_object_unref (default_app);
}

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 gchar *
get_extension_from_file (NautilusFile *nfile)
{
      char *name;
      char *extension;

      name = nautilus_file_get_name (nfile);
      extension = get_extension (name);

      g_free (name);

      return extension;
}

static void
nautilus_mime_application_chooser_apply_labels (NautilusMimeApplicationChooser *chooser)
{
      gchar *label, *extension = NULL, *description = NULL;

      if (chooser->details->files != NULL) {
            /* here we assume all files are of the same content type */
            if (g_content_type_is_unknown (chooser->details->content_type)) {
                  extension = get_extension_from_file (NAUTILUS_FILE (chooser->details->files->data));

                  /* the %s here is a file extension */
                  description = g_strdup_printf (_("%s document"), extension);
            } else {
                  description = g_content_type_get_description (chooser->details->content_type);
            }

            label = g_strdup_printf (_("Open all files of type \"%s\" with"),
                               description);
      } else {
            GFile *file;
            gchar *basename, *emname;

            file = g_file_new_for_uri (chooser->details->uri);
            basename = g_file_get_basename (file);

            if (g_content_type_is_unknown (chooser->details->content_type)) {
                  extension = get_extension (basename);

                  /* the %s here is a file extension */
                  description = g_strdup_printf (_("%s document"), extension);
            } else {
                  description = g_content_type_get_description (chooser->details->content_type);
            }

            /* first %s is filename, second %s is mime-type description */
            emname = g_strdup_printf ("<i>%s</i>", basename);
            label = g_strdup_printf (_("Select an application to open %s and other files of type \"%s\""),
                               emname, description);

            g_free (emname);
            g_free (basename);
            g_object_unref (file);
      }

      gtk_label_set_markup (GTK_LABEL (chooser->details->label), label);

      g_free (label);
      g_free (extension);
      g_free (description);
}

static void
show_more_clicked_cb (GtkWidget *button,
                  gpointer user_data)
{
      NautilusMimeApplicationChooser *chooser = user_data;

      gtk_app_chooser_widget_set_show_other (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget),
                                     TRUE);
      gtk_widget_hide (button);
}

static void
nautilus_mime_application_chooser_build_ui (NautilusMimeApplicationChooser *chooser)
{
      GtkWidget *box, *button;
      GAppInfo *info;

      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);

      chooser->details->open_with_widget = gtk_app_chooser_widget_new (chooser->details->content_type);
      gtk_app_chooser_widget_set_show_default (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget),
                                     TRUE);
      gtk_app_chooser_widget_set_show_fallback (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget),
                                      TRUE);
      gtk_box_pack_start (GTK_BOX (chooser), chooser->details->open_with_widget,
                      TRUE, TRUE, 6);
      gtk_widget_show (chooser->details->open_with_widget);

      g_signal_connect (chooser->details->open_with_widget, "application-selected",
                    G_CALLBACK (application_selected_cb),
                    chooser);
      g_signal_connect (chooser->details->open_with_widget, "populate-popup",
                    G_CALLBACK (populate_popup_cb),
                    chooser);

      button = gtk_button_new_with_label (_("Show other applications"));
      gtk_box_pack_start (GTK_BOX (chooser->details->open_with_widget), button, FALSE, FALSE, 6);
      gtk_widget_show_all (button);

      g_signal_connect (button, "clicked",
                    G_CALLBACK (show_more_clicked_cb), chooser);

      box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
      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_with_label (_("Reset"));
      g_signal_connect (button, "clicked", 
                    G_CALLBACK (reset_clicked_cb),
                    chooser);
      gtk_widget_show (button);
      gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
      gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (box), button, TRUE);

      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_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
      chooser->details->add_button = button;

      button = gtk_button_new_with_label (_("Set as default"));
      g_signal_connect (button, "clicked",
                    G_CALLBACK (set_as_default_clicked_cb),
                    chooser);
      gtk_widget_show (button);
      gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);

      chooser->details->set_as_default_button = button;

      /* initialize sensitivity */
      info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget));
      if (info != NULL) {
            application_selected_cb (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget),
                               info, chooser);
            g_object_unref (info);
      }
}

static void
nautilus_mime_application_chooser_init (NautilusMimeApplicationChooser *chooser)
{
      chooser->details = G_TYPE_INSTANCE_GET_PRIVATE (chooser, NAUTILUS_TYPE_MIME_APPLICATION_CHOOSER,
                                          NautilusMimeApplicationChooserDetails);

      gtk_orientable_set_orientation (GTK_ORIENTABLE (chooser),
                              GTK_ORIENTATION_VERTICAL);
}

static void
nautilus_mime_application_chooser_constructed (GObject *object)
{
      NautilusMimeApplicationChooser *chooser = NAUTILUS_MIME_APPLICATION_CHOOSER (object);

      if (G_OBJECT_CLASS (nautilus_mime_application_chooser_parent_class)->constructed != NULL)
            G_OBJECT_CLASS (nautilus_mime_application_chooser_parent_class)->constructed (object);

      nautilus_mime_application_chooser_build_ui (chooser);
      nautilus_mime_application_chooser_apply_labels (chooser);
}

static void
nautilus_mime_application_chooser_finalize (GObject *object)
{
      NautilusMimeApplicationChooser *chooser;

      chooser = NAUTILUS_MIME_APPLICATION_CHOOSER (object);

      g_free (chooser->details->uri);
      g_free (chooser->details->content_type);

      G_OBJECT_CLASS (nautilus_mime_application_chooser_parent_class)->finalize (object);
}

static void
nautilus_mime_application_chooser_get_property (GObject *object,
                                    guint property_id,
                                    GValue *value,
                                    GParamSpec *pspec)
{
      NautilusMimeApplicationChooser *chooser = NAUTILUS_MIME_APPLICATION_CHOOSER (object);

      switch (property_id) {
      case PROP_CONTENT_TYPE:
            g_value_set_string (value, chooser->details->content_type);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
            break;
      }
}

static void
nautilus_mime_application_chooser_set_property (GObject *object,
                                    guint property_id,
                                    const GValue *value,
                                    GParamSpec *pspec)
{
      NautilusMimeApplicationChooser *chooser = NAUTILUS_MIME_APPLICATION_CHOOSER (object);

      switch (property_id) {
      case PROP_CONTENT_TYPE:
            chooser->details->content_type = g_value_dup_string (value);
            break;
      case PROP_FILES:
            chooser->details->files = g_value_get_pointer (value);
            break;
      case PROP_URI:
            chooser->details->uri = g_value_dup_string (value);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
            break;
      }
}

static void
nautilus_mime_application_chooser_class_init (NautilusMimeApplicationChooserClass *class)
{
      GObjectClass *gobject_class;

      gobject_class = G_OBJECT_CLASS (class);
      gobject_class->set_property = nautilus_mime_application_chooser_set_property;
      gobject_class->get_property = nautilus_mime_application_chooser_get_property;
      gobject_class->finalize = nautilus_mime_application_chooser_finalize;
      gobject_class->constructed = nautilus_mime_application_chooser_constructed;

      properties[PROP_CONTENT_TYPE] = g_param_spec_string ("content-type",
                                               "Content type",
                                               "Content type for this widget",
                                               NULL,
                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                                               G_PARAM_STATIC_STRINGS);
      properties[PROP_URI] = g_param_spec_string ("uri",
                                        "URI",
                                        "URI for this widget",
                                        NULL,
                                        G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
                                        G_PARAM_STATIC_STRINGS);
      properties[PROP_FILES] = g_param_spec_pointer ("files",
                                           "Files",
                                           "Files for this widget",
                                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
                                           G_PARAM_STATIC_STRINGS);

      g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);

      g_type_class_add_private (class, sizeof (NautilusMimeApplicationChooserDetails));
}

GtkWidget *
nautilus_mime_application_chooser_new (const char *uri,
                               GList *files,
                               const char *mime_type)
{
      GtkWidget *chooser;

      chooser = g_object_new (NAUTILUS_TYPE_MIME_APPLICATION_CHOOSER,
                        "uri", uri,
                        "files", files,
                        "content-type", mime_type,
                        NULL);

      return chooser;
}

Generated by  Doxygen 1.6.0   Back to index