summaryrefslogtreecommitdiff
path: root/src/caja-information-panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/caja-information-panel.c')
-rw-r--r--src/caja-information-panel.c1271
1 files changed, 1271 insertions, 0 deletions
diff --git a/src/caja-information-panel.c b/src/caja-information-panel.c
new file mode 100644
index 00000000..e31173aa
--- /dev/null
+++ b/src/caja-information-panel.c
@@ -0,0 +1,1271 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/*
+ * Caja
+ *
+ * Copyright (C) 1999, 2000, 2001 Eazel, Inc.
+ *
+ * Caja is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Caja is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Andy Hertzfeld <[email protected]>
+ *
+ */
+
+#include <config.h>
+#include "caja-information-panel.h"
+
+#include "caja-sidebar-title.h"
+
+#include <eel/eel-background.h>
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gtk-extensions.h>
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-stock-dialogs.h>
+#include <eel/eel-string.h>
+#include <eel/eel-vfs-extensions.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <libcaja-private/caja-dnd.h>
+#include <libcaja-private/caja-directory.h>
+#include <libcaja-private/caja-file-dnd.h>
+#include <libcaja-private/caja-file.h>
+#include <libcaja-private/caja-global-preferences.h>
+#include <libcaja-private/caja-keep-last-vertical-box.h>
+#include <libcaja-private/caja-metadata.h>
+#include <libcaja-private/caja-mime-actions.h>
+#include <libcaja-private/caja-program-choosing.h>
+#include <libcaja-private/caja-sidebar-provider.h>
+#include <libcaja-private/caja-module.h>
+
+struct CajaInformationPanelDetails
+{
+ GtkVBox *container;
+ CajaWindowInfo *window;
+ CajaSidebarTitle *title;
+ GtkHBox *button_box_centerer;
+ GtkVBox *button_box;
+ gboolean has_buttons;
+ CajaFile *file;
+ guint file_changed_connection;
+ gboolean background_connected;
+
+ char *default_background_color;
+ char *default_background_image;
+ char *current_background_color;
+ char *current_background_image;
+};
+
+/* button assignments */
+#define CONTEXTUAL_MENU_BUTTON 3
+
+static gboolean caja_information_panel_press_event (GtkWidget *widget,
+ GdkEventButton *event);
+static void caja_information_panel_finalize (GObject *object);
+static void caja_information_panel_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ int x,
+ int y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time);
+static void caja_information_panel_read_defaults (CajaInformationPanel *information_panel);
+static void caja_information_panel_style_set (GtkWidget *widget,
+ GtkStyle *previous_style);
+static void caja_information_panel_theme_changed (gpointer user_data);
+static void caja_information_panel_update_appearance (CajaInformationPanel *information_panel);
+static void caja_information_panel_update_buttons (CajaInformationPanel *information_panel);
+static void background_metadata_changed_callback (CajaInformationPanel *information_panel);
+static void caja_information_panel_iface_init (CajaSidebarIface *iface);
+static void caja_information_panel_iface_init (CajaSidebarIface *iface);
+static void sidebar_provider_iface_init (CajaSidebarProviderIface *iface);
+static GType caja_information_panel_provider_get_type (void);
+
+enum
+{
+ LOCATION_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+/* drag and drop definitions */
+
+enum
+{
+ TARGET_URI_LIST,
+ TARGET_COLOR,
+ TARGET_BGIMAGE,
+ TARGET_KEYWORD,
+ TARGET_BACKGROUND_RESET,
+ TARGET_MATE_URI_LIST
+};
+
+static const GtkTargetEntry target_table[] =
+{
+ { "text/uri-list", 0, TARGET_URI_LIST },
+ { "application/x-color", 0, TARGET_COLOR },
+ { "property/bgimage", 0, TARGET_BGIMAGE },
+ { "property/keyword", 0, TARGET_KEYWORD },
+ { "x-special/mate-reset-background", 0, TARGET_BACKGROUND_RESET },
+ { "x-special/mate-icon-list", 0, TARGET_MATE_URI_LIST }
+};
+
+typedef enum
+{
+ NO_PART,
+ BACKGROUND_PART,
+ ICON_PART
+} InformationPanelPart;
+
+typedef struct
+{
+ GObject parent;
+} CajaInformationPanelProvider;
+
+typedef struct
+{
+ GObjectClass parent;
+} CajaInformationPanelProviderClass;
+
+
+G_DEFINE_TYPE_WITH_CODE (CajaInformationPanel, caja_information_panel, EEL_TYPE_BACKGROUND_BOX,
+ G_IMPLEMENT_INTERFACE (CAJA_TYPE_SIDEBAR,
+ caja_information_panel_iface_init));
+/* for EEL_CALL_PARENT */
+#define parent_class caja_information_panel_parent_class
+
+G_DEFINE_TYPE_WITH_CODE (CajaInformationPanelProvider, caja_information_panel_provider, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (CAJA_TYPE_SIDEBAR_PROVIDER,
+ sidebar_provider_iface_init));
+
+
+static const char *
+caja_information_panel_get_sidebar_id (CajaSidebar *sidebar)
+{
+ return CAJA_INFORMATION_PANEL_ID;
+}
+
+static char *
+caja_information_panel_get_tab_label (CajaSidebar *sidebar)
+{
+ return g_strdup (_("Information"));
+}
+
+static char *
+caja_information_panel_get_tab_tooltip (CajaSidebar *sidebar)
+{
+ return g_strdup (_("Show Information"));
+}
+
+static GdkPixbuf *
+caja_information_panel_get_tab_icon (CajaSidebar *sidebar)
+{
+ return NULL;
+}
+
+static void
+caja_information_panel_is_visible_changed (CajaSidebar *sidebar,
+ gboolean is_visible)
+{
+ /* Do nothing */
+}
+
+static void
+caja_information_panel_iface_init (CajaSidebarIface *iface)
+{
+ iface->get_sidebar_id = caja_information_panel_get_sidebar_id;
+ iface->get_tab_label = caja_information_panel_get_tab_label;
+ iface->get_tab_tooltip = caja_information_panel_get_tab_tooltip;
+ iface->get_tab_icon = caja_information_panel_get_tab_icon;
+ iface->is_visible_changed = caja_information_panel_is_visible_changed;
+}
+
+/* initializing the class object by installing the operations we override */
+static void
+caja_information_panel_class_init (CajaInformationPanelClass *klass)
+{
+ GtkWidgetClass *widget_class;
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->finalize = caja_information_panel_finalize;
+
+ widget_class->drag_data_received = caja_information_panel_drag_data_received;
+ widget_class->button_press_event = caja_information_panel_press_event;
+ widget_class->style_set = caja_information_panel_style_set;
+
+ /* add the "location changed" signal */
+ signals[LOCATION_CHANGED] = g_signal_new
+ ("location_changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CajaInformationPanelClass,
+ location_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+/* utility routine to allocate the box the holds the command buttons */
+static void
+make_button_box (CajaInformationPanel *information_panel)
+{
+ information_panel->details->button_box_centerer = GTK_HBOX (gtk_hbox_new (FALSE, 0));
+ gtk_box_pack_start (GTK_BOX (information_panel->details->container),
+ GTK_WIDGET (information_panel->details->button_box_centerer), TRUE, TRUE, 0);
+
+ information_panel->details->button_box = GTK_VBOX (caja_keep_last_vertical_box_new (4));
+ gtk_container_set_border_width (GTK_CONTAINER (information_panel->details->button_box), 8);
+ gtk_widget_show (GTK_WIDGET (information_panel->details->button_box));
+ gtk_box_pack_start (GTK_BOX (information_panel->details->button_box_centerer),
+ GTK_WIDGET (information_panel->details->button_box),
+ TRUE, TRUE, 0);
+ information_panel->details->has_buttons = FALSE;
+}
+
+/* initialize the instance's fields, create the necessary subviews, etc. */
+
+static void
+caja_information_panel_init (CajaInformationPanel *information_panel)
+{
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (information_panel);
+
+ information_panel->details = g_new0 (CajaInformationPanelDetails, 1);
+
+ /* load the default background */
+ caja_information_panel_read_defaults (information_panel);
+
+ /* enable mouse tracking */
+ gtk_widget_add_events (GTK_WIDGET (information_panel), GDK_POINTER_MOTION_MASK);
+
+ /* create the container box */
+ information_panel->details->container = GTK_VBOX (gtk_vbox_new (FALSE, 0));
+ gtk_container_set_border_width (GTK_CONTAINER (information_panel->details->container), 0);
+ gtk_widget_show (GTK_WIDGET (information_panel->details->container));
+ gtk_container_add (GTK_CONTAINER (information_panel),
+ GTK_WIDGET (information_panel->details->container));
+
+ /* allocate and install the index title widget */
+ information_panel->details->title = CAJA_SIDEBAR_TITLE (caja_sidebar_title_new ());
+ gtk_widget_show (GTK_WIDGET (information_panel->details->title));
+ gtk_box_pack_start (GTK_BOX (information_panel->details->container),
+ GTK_WIDGET (information_panel->details->title),
+ FALSE, FALSE, 8);
+
+ /* allocate and install the command button container */
+ make_button_box (information_panel);
+
+ /* add a callback for when the theme changes */
+ eel_preferences_add_callback (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_SET, caja_information_panel_theme_changed, information_panel);
+ eel_preferences_add_callback (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR, caja_information_panel_theme_changed, information_panel);
+ eel_preferences_add_callback (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME, caja_information_panel_theme_changed, information_panel);
+
+ /* prepare ourselves to receive dropped objects */
+ gtk_drag_dest_set (GTK_WIDGET (information_panel),
+ GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
+ target_table, G_N_ELEMENTS (target_table),
+ GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
+}
+
+static void
+caja_information_panel_finalize (GObject *object)
+{
+ CajaInformationPanel *information_panel;
+
+ information_panel = CAJA_INFORMATION_PANEL (object);
+
+ if (information_panel->details->file != NULL)
+ {
+ caja_file_monitor_remove (information_panel->details->file, information_panel);
+ caja_file_unref (information_panel->details->file);
+ }
+
+ g_free (information_panel->details->default_background_color);
+ g_free (information_panel->details->default_background_image);
+ g_free (information_panel->details->current_background_color);
+ g_free (information_panel->details->current_background_image);
+ g_free (information_panel->details);
+
+ eel_preferences_remove_callback (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_SET,
+ caja_information_panel_theme_changed,
+ information_panel);
+ eel_preferences_remove_callback (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR,
+ caja_information_panel_theme_changed,
+ information_panel);
+ eel_preferences_remove_callback (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME,
+ caja_information_panel_theme_changed,
+ information_panel);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+/* callback to handle resetting the background */
+static void
+reset_background_callback (GtkWidget *menu_item, GtkWidget *information_panel)
+{
+ EelBackground *background;
+
+ background = eel_get_widget_background (information_panel);
+ if (background != NULL)
+ {
+ eel_background_reset (background);
+ }
+}
+
+static gboolean
+information_panel_has_background (CajaInformationPanel *information_panel)
+{
+ EelBackground *background;
+ gboolean has_background;
+ char *color;
+ char *image;
+
+ background = eel_get_widget_background (GTK_WIDGET(information_panel));
+
+ color = eel_background_get_color (background);
+ image = eel_background_get_image_uri (background);
+
+ has_background = (color || image);
+
+ return has_background;
+}
+
+/* create the context menu */
+static GtkWidget *
+caja_information_panel_create_context_menu (CajaInformationPanel *information_panel)
+{
+ GtkWidget *menu, *menu_item;
+
+ menu = gtk_menu_new ();
+ gtk_menu_set_screen (GTK_MENU (menu),
+ gtk_widget_get_screen (GTK_WIDGET (information_panel)));
+
+ /* add the reset background item, possibly disabled */
+ menu_item = gtk_menu_item_new_with_mnemonic (_("Use _Default Background"));
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ gtk_widget_set_sensitive (menu_item, information_panel_has_background (information_panel));
+ g_signal_connect_object (menu_item, "activate",
+ G_CALLBACK (reset_background_callback), information_panel, 0);
+
+ return menu;
+}
+
+/* set up the default backgrounds and images */
+static void
+caja_information_panel_read_defaults (CajaInformationPanel *information_panel)
+{
+ gboolean background_set;
+ char *background_color, *background_image;
+
+ background_set = eel_preferences_get_boolean (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_SET);
+
+ background_color = NULL;
+ background_image = NULL;
+ if (background_set)
+ {
+ background_color = eel_preferences_get (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR);
+ background_image = eel_preferences_get (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME);
+ }
+
+ g_free (information_panel->details->default_background_color);
+ information_panel->details->default_background_color = NULL;
+ g_free (information_panel->details->default_background_image);
+ information_panel->details->default_background_image = NULL;
+
+ if (background_color && strlen (background_color))
+ {
+ information_panel->details->default_background_color = g_strdup (background_color);
+ }
+
+ /* set up the default background image */
+
+ if (background_image && strlen (background_image))
+ {
+ information_panel->details->default_background_image = g_strdup (background_image);
+ }
+
+ g_free (background_color);
+ g_free (background_image);
+}
+
+/* handler for handling theme changes */
+
+static void
+caja_information_panel_theme_changed (gpointer user_data)
+{
+ CajaInformationPanel *information_panel;
+
+ information_panel = CAJA_INFORMATION_PANEL (user_data);
+ caja_information_panel_read_defaults (information_panel);
+ caja_information_panel_update_appearance (information_panel);
+ gtk_widget_queue_draw (GTK_WIDGET (information_panel)) ;
+}
+
+/* hit testing */
+
+static InformationPanelPart
+hit_test (CajaInformationPanel *information_panel,
+ int x, int y)
+{
+ if (caja_sidebar_title_hit_test_icon (information_panel->details->title, x, y))
+ {
+ return ICON_PART;
+ }
+
+ if (eel_point_in_widget (GTK_WIDGET (information_panel), x, y))
+ {
+ return BACKGROUND_PART;
+ }
+
+ return NO_PART;
+}
+
+/* utility to test if a uri refers to a local image */
+static gboolean
+uri_is_local_image (const char *uri)
+{
+ GdkPixbuf *pixbuf;
+ char *image_path;
+
+ image_path = g_filename_from_uri (uri, NULL, NULL);
+ if (image_path == NULL)
+ {
+ return FALSE;
+ }
+
+ pixbuf = gdk_pixbuf_new_from_file (image_path, NULL);
+ g_free (image_path);
+
+ if (pixbuf == NULL)
+ {
+ return FALSE;
+ }
+ g_object_unref (pixbuf);
+ return TRUE;
+}
+
+static void
+receive_dropped_uri_list (CajaInformationPanel *information_panel,
+ GdkDragAction action,
+ int x, int y,
+ GtkSelectionData *selection_data)
+{
+ char **uris;
+ gboolean exactly_one;
+ GtkWindow *window;
+
+ uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
+ exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0');
+ window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (information_panel)));
+
+ switch (hit_test (information_panel, x, y))
+ {
+ case NO_PART:
+ case BACKGROUND_PART:
+ /* FIXME bugzilla.gnome.org 42507: Does this work for all images, or only background images?
+ * Other views handle background images differently from other URIs.
+ */
+ if (exactly_one && uri_is_local_image (uris[0]))
+ {
+ if (action == GDK_ACTION_ASK)
+ {
+ action = caja_drag_drop_background_ask (GTK_WIDGET (information_panel), CAJA_DND_ACTION_SET_AS_BACKGROUND | CAJA_DND_ACTION_SET_AS_GLOBAL_BACKGROUND);
+ }
+
+ if (action > 0)
+ {
+ eel_background_receive_dropped_background_image
+ (eel_get_widget_background (GTK_WIDGET (information_panel)),
+ action,
+ uris[0]);
+ }
+ }
+ else if (exactly_one)
+ {
+ g_signal_emit (information_panel,
+ signals[LOCATION_CHANGED], 0,
+ uris[0]);
+ }
+ break;
+ case ICON_PART:
+ /* handle images dropped on the logo specially */
+
+ if (!exactly_one)
+ {
+ eel_show_error_dialog (
+ _("You cannot assign more than one custom icon at a time."),
+ _("Please drag just one image to set a custom icon."),
+ window);
+ break;
+ }
+
+ if (uri_is_local_image (uris[0]))
+ {
+ if (information_panel->details->file != NULL)
+ {
+ caja_file_set_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_CUSTOM_ICON,
+ NULL,
+ uris[0]);
+ caja_file_set_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_ICON_SCALE,
+ NULL,
+ NULL);
+ }
+ }
+ else
+ {
+ GFile *f;
+
+ f = g_file_new_for_uri (uris[0]);
+ if (!g_file_is_native (f))
+ {
+ eel_show_error_dialog (
+ _("The file that you dropped is not local."),
+ _("You can only use local images as custom icons."),
+ window);
+
+ }
+ else
+ {
+ eel_show_error_dialog (
+ _("The file that you dropped is not an image."),
+ _("You can only use images as custom icons."),
+ window);
+ }
+ g_object_unref (f);
+ }
+ break;
+ }
+
+ g_strfreev (uris);
+}
+
+static void
+receive_dropped_color (CajaInformationPanel *information_panel,
+ GdkDragAction action,
+ int x, int y,
+ GtkSelectionData *selection_data)
+{
+ guint16 *channels;
+ char color_spec[8];
+
+ if (gtk_selection_data_get_length (selection_data) != 8 ||
+ gtk_selection_data_get_format (selection_data) != 16)
+ {
+ g_warning ("received invalid color data");
+ return;
+ }
+
+ channels = (guint16 *) gtk_selection_data_get_data (selection_data);
+ g_snprintf (color_spec, sizeof (color_spec),
+ "#%02X%02X%02X", channels[0] >> 8, channels[1] >> 8, channels[2] >> 8);
+
+ switch (hit_test (information_panel, x, y))
+ {
+ case NO_PART:
+ g_warning ("dropped color, but not on any part of information_panel");
+ break;
+ case ICON_PART:
+ case BACKGROUND_PART:
+ if (action == GDK_ACTION_ASK)
+ {
+ action = caja_drag_drop_background_ask (GTK_WIDGET (information_panel), CAJA_DND_ACTION_SET_AS_BACKGROUND | CAJA_DND_ACTION_SET_AS_GLOBAL_BACKGROUND);
+ }
+
+ if (action > 0)
+ {
+ /* Let the background change based on the dropped color. */
+ eel_background_receive_dropped_color
+ (eel_get_widget_background (GTK_WIDGET (information_panel)),
+ GTK_WIDGET (information_panel),
+ action, x, y, selection_data);
+ }
+
+ break;
+ }
+}
+
+/* handle receiving a dropped keyword */
+
+static void
+receive_dropped_keyword (CajaInformationPanel *information_panel,
+ int x, int y,
+ GtkSelectionData *selection_data)
+{
+ caja_drag_file_receive_dropped_keyword (information_panel->details->file,
+ gtk_selection_data_get_data (selection_data));
+
+ /* regenerate the display */
+ caja_information_panel_update_appearance (information_panel);
+}
+
+static void
+caja_information_panel_drag_data_received (GtkWidget *widget, GdkDragContext *context,
+ int x, int y,
+ GtkSelectionData *selection_data,
+ guint info, guint time)
+{
+ CajaInformationPanel *information_panel;
+ EelBackground *background;
+
+ g_return_if_fail (CAJA_IS_INFORMATION_PANEL (widget));
+
+ information_panel = CAJA_INFORMATION_PANEL (widget);
+
+ switch (info)
+ {
+ case TARGET_MATE_URI_LIST:
+ case TARGET_URI_LIST:
+ receive_dropped_uri_list (information_panel,
+ gdk_drag_context_get_selected_action (context), x, y, selection_data);
+ break;
+ case TARGET_COLOR:
+ receive_dropped_color (information_panel,
+ gdk_drag_context_get_selected_action (context), x, y, selection_data);
+ break;
+ case TARGET_BGIMAGE:
+ if (hit_test (information_panel, x, y) == BACKGROUND_PART)
+ receive_dropped_uri_list (information_panel,
+ gdk_drag_context_get_selected_action (context), x, y, selection_data);
+ break;
+ case TARGET_BACKGROUND_RESET:
+ background = eel_get_widget_background ( GTK_WIDGET (information_panel));
+ if (background != NULL)
+ {
+ eel_background_reset (background);
+ }
+ break;
+ case TARGET_KEYWORD:
+ receive_dropped_keyword (information_panel, x, y, selection_data);
+ break;
+ default:
+ g_warning ("unknown drop type");
+ }
+}
+
+/* handle the context menu if necessary */
+static gboolean
+caja_information_panel_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+ CajaInformationPanel *information_panel;
+ GtkWidget *menu;
+
+ if (gtk_widget_get_window (widget) != event->window)
+ {
+ return FALSE;
+ }
+
+ information_panel = CAJA_INFORMATION_PANEL (widget);
+
+ /* handle the context menu */
+ if (event->button == CONTEXTUAL_MENU_BUTTON)
+ {
+ menu = caja_information_panel_create_context_menu (information_panel);
+ eel_pop_up_context_menu (GTK_MENU(menu),
+ EEL_DEFAULT_POPUP_MENU_DISPLACEMENT,
+ EEL_DEFAULT_POPUP_MENU_DISPLACEMENT,
+ event);
+ }
+ return TRUE;
+}
+
+static gboolean
+value_different (const char *a, const char *b)
+{
+ if (!a && !b)
+ return FALSE;
+
+ if (!a || !b)
+ return TRUE;
+
+ return strcmp (a, b);
+}
+
+/* Handle the background changed signal by writing out the settings to metadata.
+ */
+static void
+background_settings_changed_callback (EelBackground *background, GdkDragAction action, CajaInformationPanel *information_panel)
+{
+ char *image;
+ char *color;
+
+ g_assert (EEL_IS_BACKGROUND (background));
+ g_assert (CAJA_IS_INFORMATION_PANEL (information_panel));
+
+ if (information_panel->details->file == NULL)
+ {
+ return;
+ }
+
+ /* Block so we don't respond to our own metadata changes.
+ */
+ g_signal_handlers_block_by_func (information_panel->details->file,
+ G_CALLBACK (background_metadata_changed_callback),
+ information_panel);
+
+ color = eel_background_get_color (background);
+ image = eel_background_get_image_uri (background);
+
+ if (action != (GdkDragAction) CAJA_DND_ACTION_SET_AS_BACKGROUND)
+ {
+ caja_file_set_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
+ NULL,
+ NULL);
+
+ caja_file_set_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
+ NULL,
+ NULL);
+
+ eel_preferences_set
+ (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR, color ? color : "");
+ eel_preferences_set
+ (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME, image ? image : "");
+ eel_preferences_set_boolean
+ (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_SET, TRUE);
+ }
+ else
+ {
+ caja_file_set_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
+ NULL,
+ color);
+
+ caja_file_set_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
+ NULL,
+ image);
+ }
+
+ if (value_different (information_panel->details->current_background_color, color))
+ {
+ g_free (information_panel->details->current_background_color);
+ information_panel->details->current_background_color = g_strdup (color);
+ }
+
+ if (value_different (information_panel->details->current_background_image, image))
+ {
+ g_free (information_panel->details->current_background_image);
+ information_panel->details->current_background_image = g_strdup (image);
+ }
+
+ g_free (color);
+ g_free (image);
+
+ g_signal_handlers_unblock_by_func (information_panel->details->file,
+ G_CALLBACK (background_metadata_changed_callback),
+ information_panel);
+}
+
+/* handle the background reset signal by writing out NULL to metadata and setting the backgrounds
+ fields to their default values */
+static void
+background_reset_callback (EelBackground *background, CajaInformationPanel *information_panel)
+{
+ char *color;
+ char *image;
+ g_assert (EEL_IS_BACKGROUND (background));
+ g_assert (CAJA_IS_INFORMATION_PANEL (information_panel));
+
+ if (information_panel->details->file == NULL)
+ {
+ return;
+ }
+
+ /* Block so we don't respond to our own metadata changes.
+ */
+ g_signal_handlers_block_by_func (information_panel->details->file,
+ G_CALLBACK (background_metadata_changed_callback),
+ information_panel);
+
+ color = caja_file_get_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
+ NULL);
+
+ image = caja_file_get_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
+ NULL);
+ if (color || image)
+ {
+ caja_file_set_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
+ NULL,
+ NULL);
+
+ caja_file_set_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
+ NULL,
+ NULL);
+ }
+ else
+ {
+ eel_preferences_set_boolean (CAJA_PREFERENCES_SIDE_PANE_BACKGROUND_SET, FALSE);
+ }
+
+ g_signal_handlers_unblock_by_func (information_panel->details->file,
+ G_CALLBACK (background_metadata_changed_callback),
+ information_panel);
+
+ /* Force a read from the metadata to set the defaults
+ */
+ background_metadata_changed_callback (information_panel);
+}
+
+static GtkWindow *
+caja_information_panel_get_window (CajaInformationPanel *information_panel)
+{
+ GtkWidget *result;
+
+ result = gtk_widget_get_ancestor (GTK_WIDGET (information_panel), GTK_TYPE_WINDOW);
+
+ return result == NULL ? NULL : GTK_WINDOW (result);
+}
+
+static void
+command_button_callback (GtkWidget *button, GAppInfo *application)
+{
+ CajaInformationPanel *information_panel;
+ GList files;
+
+ information_panel = CAJA_INFORMATION_PANEL (g_object_get_data (G_OBJECT (button), "user_data"));
+
+ files.next = NULL;
+ files.prev = NULL;
+ files.data = information_panel->details->file;
+ caja_launch_application (application, &files,
+ caja_information_panel_get_window (information_panel));
+}
+
+/* interpret commands for buttons specified by metadata. Handle some built-in ones explicitly, or fork
+ a shell to handle general ones */
+/* for now, we don't have any of these */
+static void
+metadata_button_callback (GtkWidget *button, const char *command_str)
+{
+ CajaInformationPanel *information_panel;
+
+ information_panel = CAJA_INFORMATION_PANEL (g_object_get_data (G_OBJECT (button), "user_data"));
+}
+
+/* utility routine that allocates the command buttons from the command list */
+
+static void
+add_command_button (CajaInformationPanel *information_panel, GAppInfo *application)
+{
+ char *temp_str;
+ GtkWidget *temp_button, *label;
+
+ /* There's always at least the "Open with..." button */
+ information_panel->details->has_buttons = TRUE;
+
+ temp_str = g_strdup_printf (_("Open With %s"), g_app_info_get_display_name (application));
+ temp_button = gtk_button_new_with_label (temp_str);
+ label = gtk_bin_get_child (GTK_BIN (temp_button));
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_START);
+ g_free (temp_str);
+ gtk_box_pack_start (GTK_BOX (information_panel->details->button_box),
+ temp_button,
+ FALSE, FALSE,
+ 0);
+
+ g_signal_connect_data (temp_button,
+ "clicked",
+ G_CALLBACK (command_button_callback),
+ g_object_ref (application),
+ (GClosureNotify)g_object_unref,
+ 0);
+
+ g_object_set_data (G_OBJECT (temp_button), "user_data", information_panel);
+
+ gtk_widget_show (temp_button);
+}
+
+/* utility to construct command buttons for the information_panel from the passed in metadata string */
+
+static void
+add_buttons_from_metadata (CajaInformationPanel *information_panel, const char *button_data)
+{
+ char **terms;
+ char *current_term, *temp_str;
+ char *button_name, *command_string;
+ const char *term;
+ int index;
+ GtkWidget *temp_button;
+
+ /* split the button specification into a set of terms */
+ button_name = NULL;
+ terms = g_strsplit (button_data, ";", 0);
+
+ /* for each term, either create a button or attach a property to one */
+ for (index = 0; (term = terms[index]) != NULL; index++)
+ {
+ current_term = g_strdup (term);
+ temp_str = strchr (current_term, '=');
+ if (temp_str)
+ {
+ *temp_str = '\0';
+ if (!g_ascii_strcasecmp (current_term, "button"))
+ {
+ button_name = g_strdup (temp_str + 1);
+ }
+ else if (!g_ascii_strcasecmp (current_term, "script"))
+ {
+ if (button_name != NULL)
+ {
+ temp_button = gtk_button_new_with_label (button_name);
+ gtk_box_pack_start (GTK_BOX (information_panel->details->button_box),
+ temp_button,
+ FALSE, FALSE,
+ 0);
+ information_panel->details->has_buttons = TRUE;
+ command_string = g_strdup (temp_str + 1);
+ g_free (button_name);
+
+ g_signal_connect_data (temp_button,
+ "clicked",
+ G_CALLBACK (metadata_button_callback),
+ command_string,
+ (GClosureNotify)g_free,
+ 0);
+
+ g_object_set_data (G_OBJECT (temp_button), "user_data", information_panel);
+
+ gtk_widget_show (temp_button);
+ }
+ }
+ }
+ g_free(current_term);
+ }
+ g_strfreev (terms);
+}
+
+/*
+ * caja_information_panel_update_buttons:
+ *
+ * Update the list of program-launching buttons based on the current uri.
+ */
+static void
+caja_information_panel_update_buttons (CajaInformationPanel *information_panel)
+{
+ char *button_data;
+ GAppInfo *default_app;
+
+ /* dispose of any existing buttons */
+ if (information_panel->details->has_buttons)
+ {
+ gtk_container_remove (GTK_CONTAINER (information_panel->details->container),
+ GTK_WIDGET (information_panel->details->button_box_centerer));
+ make_button_box (information_panel);
+ }
+
+ /* create buttons from file metadata if necessary */
+ button_data = caja_file_get_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BUTTONS,
+ NULL);
+ if (button_data)
+ {
+ add_buttons_from_metadata (information_panel, button_data);
+ g_free(button_data);
+ }
+
+ /* Make a button for the default application */
+ if (caja_mime_has_any_applications_for_file (information_panel->details->file) &&
+ !caja_file_is_directory (information_panel->details->file))
+ {
+ default_app =
+ caja_mime_get_default_application_for_file (information_panel->details->file);
+ add_command_button (information_panel, default_app);
+ g_object_unref (default_app);
+ }
+
+ gtk_widget_show (GTK_WIDGET (information_panel->details->button_box_centerer));
+}
+
+static void
+caja_information_panel_update_appearance (CajaInformationPanel *information_panel)
+{
+ EelBackground *background;
+ char *background_color;
+ char *background_image;
+
+ g_return_if_fail (CAJA_IS_INFORMATION_PANEL (information_panel));
+
+ /* Connect the background changed signal to code that writes the color. */
+ background = eel_get_widget_background (GTK_WIDGET (information_panel));
+ if (!information_panel->details->background_connected)
+ {
+ information_panel->details->background_connected = TRUE;
+ g_signal_connect_object (background,"settings_changed",
+ G_CALLBACK (background_settings_changed_callback), information_panel, 0);
+ g_signal_connect_object (background, "reset",
+ G_CALLBACK (background_reset_callback), information_panel, 0);
+ }
+
+ /* Set up the background color and image from the metadata. */
+ background_color = caja_file_get_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
+ NULL);
+ background_image = caja_file_get_metadata (information_panel->details->file,
+ CAJA_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
+ NULL);
+
+ if (background_color == NULL && background_image == NULL)
+ {
+ background_color = g_strdup (information_panel->details->default_background_color);
+ background_image = g_strdup (information_panel->details->default_background_image);
+ }
+
+ /* Block so we don't write these settings out in response to our set calls below */
+ g_signal_handlers_block_by_func (background,
+ G_CALLBACK (background_settings_changed_callback),
+ information_panel);
+
+ if (value_different (information_panel->details->current_background_color, background_color) ||
+ value_different (information_panel->details->current_background_image, background_image))
+ {
+
+ g_free (information_panel->details->current_background_color);
+ information_panel->details->current_background_color = g_strdup (background_color);
+ g_free (information_panel->details->current_background_image);
+ information_panel->details->current_background_image = g_strdup (background_image);
+
+ eel_background_set_image_uri (background, background_image);
+ eel_background_set_color (background, background_color);
+
+ caja_sidebar_title_select_text_color
+ (information_panel->details->title, background,
+ !information_panel_has_background (information_panel));
+ }
+
+ g_free (background_color);
+ g_free (background_image);
+
+ g_signal_handlers_unblock_by_func (background,
+ G_CALLBACK (background_settings_changed_callback),
+ information_panel);
+}
+
+static void
+background_metadata_changed_callback (CajaInformationPanel *information_panel)
+{
+ CajaFileAttributes attributes;
+ gboolean ready;
+
+ attributes = caja_mime_actions_get_required_file_attributes ();
+ ready = caja_file_check_if_ready (information_panel->details->file, attributes);
+
+ if (ready)
+ {
+ caja_information_panel_update_appearance (information_panel);
+
+ /* set up the command buttons */
+ caja_information_panel_update_buttons (information_panel);
+ }
+}
+
+/* here is the key routine that populates the information_panel with the appropriate information when the uri changes */
+
+static void
+caja_information_panel_set_uri (CajaInformationPanel *information_panel,
+ const char* new_uri,
+ const char* initial_title)
+{
+ CajaFile *file;
+ CajaFileAttributes attributes;
+
+ g_return_if_fail (CAJA_IS_INFORMATION_PANEL (information_panel));
+ g_return_if_fail (new_uri != NULL);
+ g_return_if_fail (initial_title != NULL);
+
+ /* there's nothing to do if the uri is the same as the current one */
+ if (information_panel->details->file != NULL &&
+ caja_file_matches_uri (information_panel->details->file, new_uri))
+ {
+ return;
+ }
+
+ if (information_panel->details->file != NULL)
+ {
+ g_signal_handler_disconnect (information_panel->details->file,
+ information_panel->details->file_changed_connection);
+ caja_file_monitor_remove (information_panel->details->file, information_panel);
+ }
+
+ file = caja_file_get_by_uri (new_uri);
+
+ caja_file_unref (information_panel->details->file);
+ information_panel->details->file = file;
+
+ information_panel->details->file_changed_connection =
+ g_signal_connect_object (information_panel->details->file, "changed",
+ G_CALLBACK (background_metadata_changed_callback),
+ information_panel, G_CONNECT_SWAPPED);
+
+ attributes = caja_mime_actions_get_required_file_attributes ();
+ caja_file_monitor_add (information_panel->details->file, information_panel, attributes);
+
+ background_metadata_changed_callback (information_panel);
+
+ /* tell the title widget about it */
+ caja_sidebar_title_set_file (information_panel->details->title,
+ information_panel->details->file,
+ initial_title);
+}
+
+static void
+title_changed_callback (CajaWindowInfo *window,
+ char *new_title,
+ CajaInformationPanel *panel)
+{
+ caja_sidebar_title_set_text (panel->details->title,
+ new_title);
+}
+
+/* ::style_set handler for the information_panel */
+static void
+caja_information_panel_style_set (GtkWidget *widget, GtkStyle *previous_style)
+{
+ CajaInformationPanel *information_panel;
+
+ information_panel = CAJA_INFORMATION_PANEL (widget);
+
+ caja_information_panel_theme_changed (information_panel);
+}
+
+static void
+loading_uri_callback (CajaWindowInfo *window,
+ char *uri,
+ CajaInformationPanel *panel)
+{
+ CajaWindowSlotInfo *slot;
+ char *title;
+
+ slot = caja_window_info_get_active_slot (window);
+
+ title = caja_window_slot_info_get_title (slot);
+ caja_information_panel_set_uri (panel,
+ uri,
+ title);
+ g_free (title);
+}
+
+static void
+selection_changed_callback (CajaWindowInfo *window,
+ CajaInformationPanel *panel)
+{
+ int selection_count;
+ GList *selection;
+ GFile *selected;
+ CajaFile *file;
+ char *uri, *name;
+
+ selection = caja_window_info_get_selection (window);
+ selection_count = g_list_length (selection);
+
+ if (selection_count == 1)
+ {
+ selection = caja_window_info_get_selection (window);
+ selected = selection->data;
+
+ /* this should never fail here, as we're displaying the file */
+ file = caja_file_get_existing (selected);
+ uri = caja_file_get_uri (file);
+ name = caja_file_get_display_name (file);
+
+ caja_file_unref (file);
+ }
+ else
+ {
+ uri = caja_window_info_get_current_location (window);
+ name = caja_window_info_get_title (window);
+ }
+
+ caja_information_panel_set_uri (panel, uri, name);
+
+ eel_g_object_list_unref (selection);
+ g_free (uri);
+ g_free (name);
+}
+
+static void
+caja_information_panel_set_parent_window (CajaInformationPanel *panel,
+ CajaWindowInfo *window)
+{
+ gpointer slot;
+ char *title, *location;
+
+ panel->details->window = window;
+
+ g_signal_connect_object (window, "loading_uri",
+ G_CALLBACK (loading_uri_callback), panel, 0);
+ g_signal_connect_object (window, "title_changed",
+ G_CALLBACK (title_changed_callback), panel, 0);
+ g_signal_connect_object (window, "selection-changed",
+ G_CALLBACK (selection_changed_callback), panel, 0);
+
+ slot = caja_window_info_get_active_slot (window);
+
+ title = caja_window_slot_info_get_title (slot);
+ location = caja_window_slot_info_get_current_location (slot);
+ caja_information_panel_set_uri (panel,
+ location,
+ title);
+ g_free (location);
+ g_free (title);
+}
+
+static CajaSidebar *
+caja_information_panel_create (CajaSidebarProvider *provider,
+ CajaWindowInfo *window)
+{
+ CajaInformationPanel *panel;
+
+ panel = g_object_new (caja_information_panel_get_type (), NULL);
+ caja_information_panel_set_parent_window (panel, window);
+ g_object_ref_sink (panel);
+
+ return CAJA_SIDEBAR (panel);
+}
+
+static void
+sidebar_provider_iface_init (CajaSidebarProviderIface *iface)
+{
+ iface->create = caja_information_panel_create;
+}
+
+static void
+caja_information_panel_provider_init (CajaInformationPanelProvider *sidebar)
+{
+}
+
+static void
+caja_information_panel_provider_class_init (CajaInformationPanelProviderClass *class)
+{
+}
+
+void
+caja_information_panel_register (void)
+{
+ caja_module_add_type (caja_information_panel_provider_get_type ());
+}
+