diff --git a/po/POTFILES.in b/po/POTFILES.in index 587f917fc9b6e63266f6a1a769f19387ebd17daf..9eddda13fa109a6b28dc3799f56adf02dd5d990c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -66,9 +66,7 @@ thunar/thunar-renamer-progress.c thunar/thunar-sendto-model.c thunar/thunar-session-client.c thunar/thunar-shortcuts-icon-renderer.c -thunar/thunar-shortcuts-model.c thunar/thunar-shortcuts-pane.c -thunar/thunar-shortcuts-view.c thunar/thunar-side-pane.c thunar/thunar-simple-job.c thunar/thunar-size-label.c diff --git a/thunar/Makefile.am b/thunar/Makefile.am index ac6511ecd09d77bded0d511ef07569576387d685..4ee978e01acaac8d87cf4f914bf07ab216d7aa83 100644 --- a/thunar/Makefile.am +++ b/thunar/Makefile.am @@ -171,12 +171,8 @@ thunar_SOURCES = \ thunar-session-client.h \ thunar-shortcuts-icon-renderer.c \ thunar-shortcuts-icon-renderer.h \ - thunar-shortcuts-model.c \ - thunar-shortcuts-model.h \ thunar-shortcuts-pane.c \ thunar-shortcuts-pane.h \ - thunar-shortcuts-view.c \ - thunar-shortcuts-view.h \ thunar-side-pane.c \ thunar-side-pane.h \ thunar-simple-job.c \ diff --git a/thunar/thunar-location-entry.c b/thunar/thunar-location-entry.c index 9c101a4d31666a91d2cc9912059eccd4525dcd0b..20202d346079f7126bd609a7338cf1aa4332f70b 100644 --- a/thunar/thunar-location-entry.c +++ b/thunar/thunar-location-entry.c @@ -34,7 +34,6 @@ #include <thunar/thunar-marshal.h> #include <thunar/thunar-path-entry.h> #include <thunar/thunar-private.h> -#include <thunar/thunar-shortcuts-model.h> diff --git a/thunar/thunar-shortcuts-model.c b/thunar/thunar-shortcuts-model.c deleted file mode 100644 index ef2a5d2635c1a6d9a95c7b0ffc7757d1261fa523..0000000000000000000000000000000000000000 --- a/thunar/thunar-shortcuts-model.c +++ /dev/null @@ -1,2263 +0,0 @@ -/* vi:set et ai sw=2 sts=2 ts=2: */ -/*- - * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> - * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org> - * Copyright (c) 2012 Nick Schermer <nick@xfce.org> - * - * This program 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. - * - * This program 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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_LOCALE_H -#include <locale.h> -#endif - -#include <glib.h> -#include <glib/gstdio.h> - -#include <thunar/thunar-file.h> -#include <thunar/thunar-shortcuts-model.h> -#include <thunar/thunar-device-monitor.h> -#include <thunar/thunar-preferences.h> -#include <thunar/thunar-util.h> -#include <thunar/thunar-private.h> - -#define SPINNER_CYCLE_DURATION 1000 -#define SPINNER_NUM_STEPS 12 - - - -#define THUNAR_SHORTCUT(obj) ((ThunarShortcut *) (obj)) - - - -typedef struct _ThunarShortcut ThunarShortcut; - - - -enum -{ - PROP_0, - PROP_HIDDEN_BOOKMARKS, - PROP_FILE_SIZE_BINARY -}; - - - -static void thunar_shortcuts_model_tree_model_init (GtkTreeModelIface *iface); -static void thunar_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface); -static void thunar_shortcuts_model_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void thunar_shortcuts_model_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void thunar_shortcuts_model_finalize (GObject *object); -static GtkTreeModelFlags thunar_shortcuts_model_get_flags (GtkTreeModel *tree_model); -static gint thunar_shortcuts_model_get_n_columns (GtkTreeModel *tree_model); -static GType thunar_shortcuts_model_get_column_type (GtkTreeModel *tree_model, - gint idx); -static gboolean thunar_shortcuts_model_get_iter (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreePath *path); -static GtkTreePath *thunar_shortcuts_model_get_path (GtkTreeModel *tree_model, - GtkTreeIter *iter); -static void thunar_shortcuts_model_get_value (GtkTreeModel *tree_model, - GtkTreeIter *iter, - gint column, - GValue *value); -static gboolean thunar_shortcuts_model_iter_next (GtkTreeModel *tree_model, - GtkTreeIter *iter); -static gboolean thunar_shortcuts_model_iter_children (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent); -static gboolean thunar_shortcuts_model_iter_has_child (GtkTreeModel *tree_model, - GtkTreeIter *iter); -static gint thunar_shortcuts_model_iter_n_children (GtkTreeModel *tree_model, - GtkTreeIter *iter); -static gboolean thunar_shortcuts_model_iter_nth_child (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent, - gint n); -static gboolean thunar_shortcuts_model_iter_parent (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *child); -static gboolean thunar_shortcuts_model_row_draggable (GtkTreeDragSource *source, - GtkTreePath *path); -static gboolean thunar_shortcuts_model_drag_data_get (GtkTreeDragSource *source, - GtkTreePath *path, - GtkSelectionData *selection_data); -static gboolean thunar_shortcuts_model_drag_data_delete (GtkTreeDragSource *source, - GtkTreePath *path); -static void thunar_shortcuts_model_header_visibility (ThunarShortcutsModel *model); -static void thunar_shortcuts_model_shortcut_devices (ThunarShortcutsModel *model); -static void thunar_shortcuts_model_shortcut_places (ThunarShortcutsModel *model); -static void thunar_shortcuts_model_shortcut_network (ThunarShortcutsModel *model); -static gboolean thunar_shortcuts_model_get_hidden (ThunarShortcutsModel *model, - ThunarShortcut *shortcut); -static void thunar_shortcuts_model_add_shortcut (ThunarShortcutsModel *model, - ThunarShortcut *shortcut); -static void thunar_shortcuts_model_remove_shortcut (ThunarShortcutsModel *model, - ThunarShortcut *shortcut); -static gboolean thunar_shortcuts_model_load (gpointer data); -static void thunar_shortcuts_model_save (ThunarShortcutsModel *model); -static void thunar_shortcuts_model_monitor (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data); -static void thunar_shortcuts_model_file_changed (ThunarFile *file, - ThunarShortcutsModel *model); -static void thunar_shortcuts_model_file_destroy (ThunarFile *file, - ThunarShortcutsModel *model); -static void thunar_shortcuts_model_device_added (ThunarDeviceMonitor *device_monitor, - ThunarDevice *device, - ThunarShortcutsModel *model); -static void thunar_shortcuts_model_device_removed (ThunarDeviceMonitor *device_monitor, - ThunarDevice *device, - ThunarShortcutsModel *model); -static void thunar_shortcuts_model_device_changed (ThunarDeviceMonitor *device_monitor, - ThunarDevice *device, - ThunarShortcutsModel *model); - -static void thunar_shortcut_free (ThunarShortcut *shortcut, - ThunarShortcutsModel *model); - - - -struct _ThunarShortcutsModelClass -{ - GObjectClass __parent__; -}; - -struct _ThunarShortcutsModel -{ - GObject __parent__; - - /* the model stamp is only used when debugging is - * enabled, to make sure we don't accept iterators - * generated by another model. - */ -#ifndef NDEBUG - gint stamp; -#endif - - GList *shortcuts; - - ThunarPreferences *preferences; - gchar **hidden_bookmarks; - gboolean file_size_binary; - - ThunarDeviceMonitor *device_monitor; - - gint64 bookmarks_time; - GFile *bookmarks_file; - GFileMonitor *bookmarks_monitor; - guint bookmarks_idle_id; - - guint busy_timeout_id; -}; - -struct _ThunarShortcut -{ - ThunarShortcutGroup group; - - gchar *name; - GIcon *gicon; - gchar *tooltip; - gint sort_id; - - guint busy : 1; - guint busy_pulse; - - GFile *location; - ThunarFile *file; - ThunarDevice *device; - - guint hidden : 1; -}; - - - -G_DEFINE_TYPE_WITH_CODE (ThunarShortcutsModel, thunar_shortcuts_model, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, thunar_shortcuts_model_tree_model_init) - G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, thunar_shortcuts_model_drag_source_init)) - - - -static void -thunar_shortcuts_model_class_init (ThunarShortcutsModelClass *klass) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = thunar_shortcuts_model_finalize; - gobject_class->get_property = thunar_shortcuts_model_get_property; - gobject_class->set_property = thunar_shortcuts_model_set_property; - - g_object_class_install_property (gobject_class, - PROP_HIDDEN_BOOKMARKS, - g_param_spec_boxed ("hidden-bookmarks", - NULL, - NULL, - G_TYPE_STRV, - EXO_PARAM_READWRITE)); - - /** - * ThunarPropertiesDialog:file_size_binary: - * - * Whether the file size should be shown in binary or decimal. - **/ - g_object_class_install_property (gobject_class, - PROP_FILE_SIZE_BINARY, - g_param_spec_boolean ("file-size-binary", - "FileSizeBinary", - NULL, - FALSE, - EXO_PARAM_READWRITE)); -} - - - -static void -thunar_shortcuts_model_tree_model_init (GtkTreeModelIface *iface) -{ - iface->get_flags = thunar_shortcuts_model_get_flags; - iface->get_n_columns = thunar_shortcuts_model_get_n_columns; - iface->get_column_type = thunar_shortcuts_model_get_column_type; - iface->get_iter = thunar_shortcuts_model_get_iter; - iface->get_path = thunar_shortcuts_model_get_path; - iface->get_value = thunar_shortcuts_model_get_value; - iface->iter_next = thunar_shortcuts_model_iter_next; - iface->iter_children = thunar_shortcuts_model_iter_children; - iface->iter_has_child = thunar_shortcuts_model_iter_has_child; - iface->iter_n_children = thunar_shortcuts_model_iter_n_children; - iface->iter_nth_child = thunar_shortcuts_model_iter_nth_child; - iface->iter_parent = thunar_shortcuts_model_iter_parent; -} - - - -static void -thunar_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface) -{ - iface->row_draggable = thunar_shortcuts_model_row_draggable; - iface->drag_data_get = thunar_shortcuts_model_drag_data_get; - iface->drag_data_delete = thunar_shortcuts_model_drag_data_delete; -} - - - -static void -thunar_shortcuts_model_init (ThunarShortcutsModel *model) -{ -#ifndef NDEBUG - model->stamp = g_random_int (); -#endif - - /* hidden bookmarks */ - model->preferences = thunar_preferences_get (); - exo_binding_new (G_OBJECT (model->preferences), "hidden-bookmarks", - G_OBJECT (model), "hidden-bookmarks"); - - /* binary file size */ - exo_binding_new (G_OBJECT (model->preferences), "misc-file-size-binary", - G_OBJECT (model), "file-size-binary"); - - /* load volumes */ - thunar_shortcuts_model_shortcut_devices (model); - - /* add network */ - thunar_shortcuts_model_shortcut_network (model); - - /* add bookmarks */ - thunar_shortcuts_model_shortcut_places (model); -} - - - -static void -thunar_shortcuts_model_finalize (GObject *object) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (object); - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - /* stop the busy timeout */ - if (model->busy_timeout_id != 0) - g_source_remove (model->busy_timeout_id); - - /* stop bookmark load idle */ - if (model->bookmarks_idle_id != 0) - g_source_remove (model->bookmarks_idle_id); - - /* free all shortcuts */ - g_list_foreach (model->shortcuts, (GFunc) thunar_shortcut_free, model); - g_list_free (model->shortcuts); - - /* disconnect from the preferences */ - g_object_unref (model->preferences); - - /* free hidden list */ - g_strfreev (model->hidden_bookmarks); - - /* detach from the file monitor */ - if (model->bookmarks_monitor != NULL) - { - g_file_monitor_cancel (model->bookmarks_monitor); - g_object_unref (model->bookmarks_monitor); - } - - if (model->bookmarks_file != NULL) - g_object_unref (model->bookmarks_file); - - /* unlink from the device monitor */ - g_signal_handlers_disconnect_matched (model->device_monitor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); - g_object_unref (model->device_monitor); - - (*G_OBJECT_CLASS (thunar_shortcuts_model_parent_class)->finalize) (object); -} - - - -static void -thunar_shortcuts_model_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (object); - - switch (prop_id) - { - case PROP_HIDDEN_BOOKMARKS: - g_value_set_boxed (value, model->hidden_bookmarks); - break; - - case PROP_FILE_SIZE_BINARY: - g_value_set_boolean (value, model->file_size_binary); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - - -static void -thunar_shortcuts_model_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (object); - GList *lp; - ThunarShortcut *shortcut; - gboolean hidden; - GtkTreeIter iter; - GtkTreePath *path; - guint idx; - - switch (prop_id) - { - case PROP_HIDDEN_BOOKMARKS: - g_strfreev (model->hidden_bookmarks); - model->hidden_bookmarks = g_value_dup_boxed (value); - - /* update shortcuts */ - for (lp = model->shortcuts, idx = 0; lp != NULL; lp = lp->next, idx++) - { - shortcut = lp->data; - - /* skip devices and headers*/ - if (shortcut->device != NULL - || (shortcut->file == NULL && shortcut->location == NULL)) - continue; - - /* update state if required */ - hidden = thunar_shortcuts_model_get_hidden (model, shortcut); - if (shortcut->hidden != hidden) - { - shortcut->hidden = hidden; - - GTK_TREE_ITER_INIT (iter, model->stamp, lp); - - path = gtk_tree_path_new_from_indices (idx, -1); - gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); - gtk_tree_path_free (path); - } - } - - /* update header visibility */ - thunar_shortcuts_model_header_visibility (model); - break; - - case PROP_FILE_SIZE_BINARY: - model->file_size_binary = g_value_get_boolean (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - - -static GtkTreeModelFlags -thunar_shortcuts_model_get_flags (GtkTreeModel *tree_model) -{ - return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY; -} - - - -static gint -thunar_shortcuts_model_get_n_columns (GtkTreeModel *tree_model) -{ - return THUNAR_SHORTCUTS_MODEL_N_COLUMNS; -} - - - -static GType -thunar_shortcuts_model_get_column_type (GtkTreeModel *tree_model, - gint idx) -{ - switch (idx) - { - case THUNAR_SHORTCUTS_MODEL_COLUMN_IS_HEADER: - return G_TYPE_BOOLEAN; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_IS_ITEM: - return G_TYPE_BOOLEAN; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_VISIBLE: - return G_TYPE_BOOLEAN; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_NAME: - return G_TYPE_STRING; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_TOOLTIP: - return G_TYPE_STRING; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_FILE: - return THUNAR_TYPE_FILE; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION: - return G_TYPE_FILE; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_GICON: - return G_TYPE_ICON; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE: - return THUNAR_TYPE_DEVICE; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE: - return G_TYPE_BOOLEAN; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_CAN_EJECT: - return G_TYPE_BOOLEAN; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP: - return G_TYPE_UINT; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY: - return G_TYPE_BOOLEAN; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY_PULSE: - return G_TYPE_UINT; - } - - _thunar_assert_not_reached (); - return G_TYPE_INVALID; -} - - - -static gboolean -thunar_shortcuts_model_get_iter (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreePath *path) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (tree_model); - GList *lp; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - _thunar_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE); - - /* determine the list item for the path */ - lp = g_list_nth (model->shortcuts, gtk_tree_path_get_indices (path)[0]); - if (G_LIKELY (lp != NULL)) - { - GTK_TREE_ITER_INIT (*iter, model->stamp, lp); - return TRUE; - } - - return FALSE; -} - - - -static GtkTreePath* -thunar_shortcuts_model_get_path (GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (tree_model); - gint idx; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), NULL); - _thunar_return_val_if_fail (iter->stamp == model->stamp, NULL); - - /* lookup the list item in the shortcuts list */ - idx = g_list_position (model->shortcuts, iter->user_data); - if (G_LIKELY (idx >= 0)) - return gtk_tree_path_new_from_indices (idx, -1); - - return NULL; -} - - - -static void -thunar_shortcuts_model_get_value (GtkTreeModel *tree_model, - GtkTreeIter *iter, - gint column, - GValue *value) -{ - ThunarShortcut *shortcut; - gboolean can_eject; - GFile *file; - gchar *disk_usage; - guint32 trash_items; - gchar *trash_string; - gchar *parse_name; - gboolean file_size_binary; - - _thunar_return_if_fail (iter->stamp == THUNAR_SHORTCUTS_MODEL (tree_model)->stamp); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (tree_model)); - - /* determine the shortcut for the list item */ - shortcut = THUNAR_SHORTCUT (((GList *) iter->user_data)->data); - if (shortcut == NULL) - return; - - switch (column) - { - case THUNAR_SHORTCUTS_MODEL_COLUMN_IS_HEADER: - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, (shortcut->group & THUNAR_SHORTCUT_GROUP_HEADER) != 0); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_IS_ITEM: - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, (shortcut->group & THUNAR_SHORTCUT_GROUP_HEADER) == 0); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_VISIBLE: - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, !shortcut->hidden); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_NAME: - g_value_init (value, G_TYPE_STRING); - if (G_UNLIKELY (shortcut->device != NULL)) - g_value_take_string (value, thunar_device_get_name (shortcut->device)); - else if (shortcut->name != NULL) - g_value_set_static_string (value, shortcut->name); - else if (shortcut->file != NULL) - g_value_set_static_string (value, thunar_file_get_display_name (shortcut->file)); - else if (shortcut->location != NULL) - g_value_take_string (value, thunar_g_file_get_display_name_remote (shortcut->location)); - else - g_value_set_static_string (value, ""); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_TOOLTIP: - g_value_init (value, G_TYPE_STRING); - if ((shortcut->group & THUNAR_SHORTCUT_GROUP_DEVICES) != 0) - { - if (shortcut->device != NULL) - file = thunar_device_get_root (shortcut->device); - else if (shortcut->file != NULL) - file = g_object_ref (thunar_file_get_file (shortcut->file)); - else - file = NULL; - - if (file != NULL) - { - file_size_binary = THUNAR_SHORTCUTS_MODEL (tree_model)->file_size_binary; - disk_usage = thunar_g_file_get_free_space_string (file, file_size_binary); - g_object_unref (file); - g_value_take_string (value, disk_usage); - } - break; - } - else if ((shortcut->group & THUNAR_SHORTCUT_GROUP_PLACES_TRASH) != 0) - { - trash_items = thunar_file_get_item_count (shortcut->file); - if (trash_items == 0) - { - g_value_set_static_string (value, _("Trash is empty")); - } - else - { - trash_string = g_strdup_printf (ngettext ("Trash contains %d file", - "Trash contains %d files", - trash_items), trash_items); - g_value_take_string (value, trash_string); - } - break; - } - else if (shortcut->tooltip == NULL) - { - if (shortcut->file != NULL) - file = thunar_file_get_file (shortcut->file); - else if (shortcut->location != NULL) - file = shortcut->location; - else - file = NULL; - - if (G_LIKELY (file != NULL)) - { - parse_name = g_file_get_parse_name (file); - shortcut->tooltip = g_markup_escape_text (parse_name, -1); - g_free (parse_name); - } - } - - g_value_set_static_string (value, shortcut->tooltip); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_FILE: - g_value_init (value, THUNAR_TYPE_FILE); - g_value_set_object (value, shortcut->file); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_GICON: - g_value_init (value, G_TYPE_ICON); - g_value_set_object (value, shortcut->gicon); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE: - g_value_init (value, THUNAR_TYPE_DEVICE); - g_value_set_object (value, shortcut->device); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION: - g_value_init (value, G_TYPE_FILE); - if (shortcut->location != NULL) - g_value_set_object (value, shortcut->location); - else if (shortcut->file != NULL) - g_value_set_object (value, thunar_file_get_file (shortcut->file)); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE: - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, - shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_CAN_EJECT: - if (shortcut->device != NULL) - can_eject = thunar_device_can_eject (shortcut->device); - else - can_eject = FALSE; - - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, can_eject); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP: - g_value_init (value, G_TYPE_UINT); - g_value_set_uint (value, shortcut->group); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY: - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, shortcut->busy); - break; - - case THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY_PULSE: - g_value_init (value, G_TYPE_UINT); - g_value_set_uint (value, shortcut->busy_pulse); - break; - - default: - _thunar_assert_not_reached (); - } -} - - - -static gboolean -thunar_shortcuts_model_iter_next (GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (tree_model), FALSE); - _thunar_return_val_if_fail (iter->stamp == THUNAR_SHORTCUTS_MODEL (tree_model)->stamp, FALSE); - - iter->user_data = g_list_next (iter->user_data); - return (iter->user_data != NULL); -} - - - -static gboolean -thunar_shortcuts_model_iter_children (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (tree_model); - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - - if (G_LIKELY (parent == NULL && model->shortcuts != NULL)) - { - GTK_TREE_ITER_INIT (*iter, model->stamp, model->shortcuts); - return TRUE; - } - - return FALSE; -} - - - -static gboolean -thunar_shortcuts_model_iter_has_child (GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - return FALSE; -} - - - -static gint -thunar_shortcuts_model_iter_n_children (GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (tree_model); - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), 0); - - return (iter == NULL) ? g_list_length (model->shortcuts) : 0; -} - - - -static gboolean -thunar_shortcuts_model_iter_nth_child (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent, - gint n) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (tree_model); - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - - if (G_LIKELY (parent == NULL)) - { - GTK_TREE_ITER_INIT (*iter, model->stamp, g_list_nth (model->shortcuts, n)); - return (iter->user_data != NULL); - } - - return FALSE; -} - - - -static gboolean -thunar_shortcuts_model_iter_parent (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *child) -{ - return FALSE; -} - - - -static gboolean -thunar_shortcuts_model_row_draggable (GtkTreeDragSource *source, - GtkTreePath *path) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (source); - ThunarShortcut *shortcut; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - _thunar_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE); - - /* lookup the ThunarShortcut for the path */ - shortcut = g_list_nth_data (model->shortcuts, gtk_tree_path_get_indices (path)[0]); - - /* special shortcuts cannot be reordered */ - return (shortcut != NULL && shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS); -} - - - -static gboolean -thunar_shortcuts_model_drag_data_get (GtkTreeDragSource *source, - GtkTreePath *path, - GtkSelectionData *selection_data) -{ - /* we simply return FALSE here, as the drag handling is done in - * the ThunarShortcutsView class. - */ - return FALSE; -} - - - -static gboolean -thunar_shortcuts_model_drag_data_delete (GtkTreeDragSource *source, - GtkTreePath *path) -{ - /* we simply return FALSE here, as this function can only be - * called if the user is re-arranging shortcuts within the - * model, which will be handle by the exchange method. - */ - return FALSE; -} - - - -static void -thunar_shortcuts_model_header_visibility (ThunarShortcutsModel *model) -{ - GList *lp; - ThunarShortcut *shortcut; - ThunarShortcut *header; - guint n_children = 0; - GList *lp_header = NULL; - gint idx_header = 0; - gint i; - GtkTreePath *path; - GtkTreeIter iter; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - for (lp = model->shortcuts, i = 0; lp != NULL; lp = lp->next, i++) - { - shortcut = lp->data; - - if ((shortcut->group & THUNAR_SHORTCUT_GROUP_HEADER) != 0) - { - if (lp_header != NULL) - { - update_header: - - header = lp_header->data; - if (header->hidden != (n_children == 0)) - { - /* set new visibility */ - header->hidden = (n_children == 0); - - /* notify view */ - path = gtk_tree_path_new_from_indices (idx_header, -1); - GTK_TREE_ITER_INIT (iter, model->stamp, lp_header); - gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); - gtk_tree_path_free (path); - } - - if (lp == NULL) - return; - } - - /* reset for new */ - idx_header = i; - lp_header = lp; - n_children = 0; - } - else if (!shortcut->hidden) - { - n_children++; - } - } - - _thunar_assert (lp == NULL); - if (lp_header != NULL) - goto update_header; -} - - - -static void -thunar_shortcuts_model_shortcut_devices (ThunarShortcutsModel *model) -{ - ThunarShortcut *shortcut; - GList *devices; - GList *lp; - - /* add the devices heading */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_DEVICES_HEADER; - shortcut->name = g_strdup (_("DEVICES")); - thunar_shortcuts_model_add_shortcut (model, shortcut); - - /* the filesystem entry */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_DEVICES_FILESYSTEM; - shortcut->name = g_strdup (_("File System")); - shortcut->file = thunar_file_get_for_uri ("file:///", NULL); - shortcut->gicon = g_themed_icon_new ("drive-harddisk"); - shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut); - thunar_shortcuts_model_add_shortcut (model, shortcut); - - /* connect to the device monitor */ - model->device_monitor = thunar_device_monitor_get (); - - /* get a list of all devices available */ - devices = thunar_device_monitor_get_devices (model->device_monitor); - for (lp = devices; lp != NULL; lp = lp->next) - { - thunar_shortcuts_model_device_added (NULL, lp->data, model); - g_object_unref (G_OBJECT (lp->data)); - } - g_list_free (devices); - - /* monitor for changes */ - g_signal_connect (model->device_monitor, "device-added", G_CALLBACK (thunar_shortcuts_model_device_added), model); - g_signal_connect (model->device_monitor, "device-removed", G_CALLBACK (thunar_shortcuts_model_device_removed), model); - g_signal_connect (model->device_monitor, "device-changed", G_CALLBACK (thunar_shortcuts_model_device_changed), model); - - thunar_shortcuts_model_header_visibility (model); -} - - - -static void -thunar_shortcuts_model_shortcut_network (ThunarShortcutsModel *model) -{ - ThunarShortcut *shortcut; - - /* add the network heading */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_NETWORK_HEADER; - shortcut->name = g_strdup (_("NETWORK")); - thunar_shortcuts_model_add_shortcut (model, shortcut); - - /* the browse network entry */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_NETWORK_DEFAULT; - shortcut->name = g_strdup (_("Browse Network")); - shortcut->location = g_file_new_for_uri ("network://"); - shortcut->gicon = g_themed_icon_new ("network-workgroup"); - shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut); - thunar_shortcuts_model_add_shortcut (model, shortcut); -} - - - -static void -thunar_shortcuts_model_shortcut_places (ThunarShortcutsModel *model) -{ - ThunarShortcut *shortcut; - GFile *home; - GFile *desktop; - GFile *trash; - ThunarFile *file; - - /* add the places heading */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_HEADER; - shortcut->name = g_strdup (_("PLACES")); - thunar_shortcuts_model_add_shortcut (model, shortcut); - - /* get home path */ - home = thunar_g_file_new_for_home (); - - /* add home entry */ - file = thunar_file_get (home, NULL); - if (file != NULL) - { - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_DEFAULT; - shortcut->file = file; - shortcut->gicon = g_themed_icon_new ("go-home"); - shortcut->sort_id = 0; - shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut); - thunar_shortcuts_model_add_shortcut (model, shortcut); - } - - /* add desktop entry */ - desktop = thunar_g_file_new_for_desktop (); - if (!g_file_equal (desktop, home)) - { - file = thunar_file_get (desktop, NULL); - if (file != NULL) - { - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_DEFAULT; - shortcut->file = file; - shortcut->sort_id = 1; - shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut); - thunar_shortcuts_model_add_shortcut (model, shortcut); - } - } - g_object_unref (desktop); - g_object_unref (home); - - /* append the trash icon if the trash is supported */ - if (thunar_g_vfs_is_uri_scheme_supported ("trash")) - { - trash = thunar_g_file_new_for_trash (); - file = thunar_file_get (trash, NULL); - g_object_unref (trash); - - if (file != NULL) - { - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_TRASH; - shortcut->file = file; - shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut); - thunar_shortcuts_model_add_shortcut (model, shortcut); - } - } - - /* determine the URI to the Gtk+ bookmarks file */ - model->bookmarks_file = thunar_g_file_new_for_bookmarks (); - - /* register with the alteration monitor for the bookmarks file */ - model->bookmarks_monitor = g_file_monitor_file (model->bookmarks_file, G_FILE_MONITOR_NONE, NULL, NULL); - if (G_LIKELY (model->bookmarks_monitor != NULL)) - { - g_signal_connect (model->bookmarks_monitor, "changed", - G_CALLBACK (thunar_shortcuts_model_monitor), model); - } - - /* read the Gtk+ bookmarks file */ - model->bookmarks_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT, thunar_shortcuts_model_load, model, NULL); -} - - - -static gboolean -thunar_shortcuts_model_get_hidden (ThunarShortcutsModel *model, - ThunarShortcut *shortcut) -{ - gchar *uri; - guint n; - gboolean hidden = FALSE; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - _thunar_return_val_if_fail (shortcut->device == NULL, FALSE); - - if (model->hidden_bookmarks == NULL) - return FALSE; - - /* get the uri */ - if (shortcut->file != NULL) - uri = thunar_file_dup_uri (shortcut->file); - else if (shortcut->location != NULL) - uri = g_file_get_uri (shortcut->location); - else - _thunar_assert_not_reached (); - - if (uri == NULL) - return FALSE; - - for (n = 0; !hidden && model->hidden_bookmarks[n] != NULL; n++) - hidden = (g_strcmp0 (model->hidden_bookmarks[n], uri) == 0); - - g_free (uri); - - return hidden; -} - - - -static gint -thunar_shortcuts_model_sort_func (gconstpointer shortcut_a, - gconstpointer shortcut_b) -{ - const ThunarShortcut *a = shortcut_a; - const ThunarShortcut *b = shortcut_b; - - /* sort groups */ - if (a->group != b->group) - return a->group - b->group; - - /* use sort order */ - if (a->sort_id != b->sort_id) - return a->sort_id > b->sort_id ? 1 : -1; - - /* properly sort devices by timestamp */ - if (a->device != NULL && b->device != NULL) - return thunar_device_sort (a->device, b->device); - - return g_strcmp0 (a->name, b->name); -} - - - -static void -thunar_shortcuts_model_add_shortcut_with_path (ThunarShortcutsModel *model, - ThunarShortcut *shortcut, - GtkTreePath *path) -{ - GtkTreeIter iter; - GtkTreePath *sorted_path = NULL; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (shortcut->file == NULL || THUNAR_IS_FILE (shortcut->file)); - - /* we want to stay informed about changes to the file */ - if (G_LIKELY (shortcut->file != NULL)) - { - /* watch the file for changes */ - thunar_file_watch (shortcut->file); - - /* connect appropriate signals */ - g_signal_connect (G_OBJECT (shortcut->file), "changed", - G_CALLBACK (thunar_shortcuts_model_file_changed), model); - g_signal_connect (G_OBJECT (shortcut->file), "destroy", - G_CALLBACK (thunar_shortcuts_model_file_destroy), model); - } - - if (path == NULL) - { - /* insert the new shortcut to the shortcuts list */ - model->shortcuts = g_list_insert_sorted (model->shortcuts, shortcut, thunar_shortcuts_model_sort_func); - sorted_path = gtk_tree_path_new_from_indices (g_list_index (model->shortcuts, shortcut), -1); - path = sorted_path; - } - else - { - model->shortcuts = g_list_insert (model->shortcuts, shortcut, gtk_tree_path_get_indices (path)[0]); - } - - /* tell everybody that we have a new shortcut */ - gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path); - gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter); - - if (sorted_path) - gtk_tree_path_free (sorted_path); -} - - - -static void -thunar_shortcuts_model_add_shortcut (ThunarShortcutsModel *model, - ThunarShortcut *shortcut) -{ - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (shortcut->file == NULL || THUNAR_IS_FILE (shortcut->file)); - - thunar_shortcuts_model_add_shortcut_with_path (model, shortcut, NULL); -} - - - -static void -thunar_shortcuts_model_remove_shortcut (ThunarShortcutsModel *model, - ThunarShortcut *shortcut) -{ - GtkTreePath *path; - gint idx; - gboolean needs_save; - - /* determine the index of the shortcut */ - idx = g_list_index (model->shortcuts, shortcut); - if (G_LIKELY (idx >= 0)) - { - /* unlink the shortcut from the model */ - model->shortcuts = g_list_remove (model->shortcuts, shortcut); - - /* tell everybody that we have lost a shortcut */ - path = gtk_tree_path_new_from_indices (idx, -1); - gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); - gtk_tree_path_free (path); - - /* check if we need to save */ - needs_save = (shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS); - - /* actually free the shortcut */ - thunar_shortcut_free (shortcut, model); - - /* the shortcuts list was changed, so write the gtk bookmarks file */ - if (needs_save) - thunar_shortcuts_model_save (model); - - /* update header visibility */ - thunar_shortcuts_model_header_visibility (model); - } -} - - - -static gboolean -thunar_shortcuts_model_local_file (GFile *gfile) -{ - _thunar_return_val_if_fail (G_IS_FILE (gfile), FALSE); - - /* schemes we'd like to have as ThunarFiles in the model */ - if (g_file_has_uri_scheme (gfile, "file") - || g_file_has_uri_scheme (gfile, "computer") - || g_file_has_uri_scheme (gfile, "recent")) - return TRUE; - - return FALSE; -} - - - -static void -thunar_shortcuts_model_load_line (GFile *file_path, - const gchar *name, - gint row_num, - gpointer user_data) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (user_data); - ThunarShortcut *shortcut; - ThunarFile *file; - - _thunar_return_if_fail (G_IS_FILE (file_path)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL)); - - /* handle local and remove files differently */ - if (thunar_shortcuts_model_local_file (file_path)) - { - /* try to open the file corresponding to the uri */ - file = thunar_file_get (file_path, NULL); - if (G_UNLIKELY (file == NULL)) - return; - - /* make sure the file refers to a directory */ - if (G_UNLIKELY (thunar_file_is_directory (file))) - { - /* create the shortcut entry */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS; - shortcut->file = file; - shortcut->sort_id = row_num; - shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut); - shortcut->name = g_strdup (name); - - /* append the shortcut to the list */ - thunar_shortcuts_model_add_shortcut (model, shortcut); - } - else - { - g_object_unref (file); - } - } - else - { - /* create the shortcut entry */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS; - shortcut->gicon = g_themed_icon_new ("folder-remote"); - shortcut->location = g_object_ref (file_path); - shortcut->sort_id = row_num; - shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut); - shortcut->name = g_strdup (name); - - /* append the shortcut to the list */ - thunar_shortcuts_model_add_shortcut (model, shortcut); - } -} - - - -static gboolean -thunar_shortcuts_model_load (gpointer data) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (data); - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - - GDK_THREADS_ENTER (); - - /* parse the bookmarks */ - thunar_util_load_bookmarks (model->bookmarks_file, - thunar_shortcuts_model_load_line, - model); - - /* update the visibility */ - thunar_shortcuts_model_header_visibility (model); - - GDK_THREADS_LEAVE (); - - model->bookmarks_idle_id = 0; - - return FALSE; -} - - - -static gboolean -thunar_shortcuts_model_reload (gpointer data) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (data); - ThunarShortcut *shortcut; - GtkTreePath *path; - GList *lp; - gint idx; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - - GDK_THREADS_ENTER (); - - /* drop all existing user-defined shortcuts from the model */ - for (idx = 0, lp = model->shortcuts; lp != NULL; ) - { - /* grab the shortcut */ - shortcut = THUNAR_SHORTCUT (lp->data); - - /* advance to the next list item */ - lp = g_list_next (lp); - - /* drop the shortcut if it is user-defined */ - if (shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS) - { - /* unlink the shortcut from the model */ - model->shortcuts = g_list_remove (model->shortcuts, shortcut); - - /* tell everybody that we have lost a shortcut */ - path = gtk_tree_path_new_from_indices (idx, -1); - gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); - gtk_tree_path_free (path); - - /* actually free the shortcut */ - thunar_shortcut_free (shortcut, model); - } - else - { - ++idx; - } - } - - GDK_THREADS_LEAVE (); - - /* load new bookmarks */ - return thunar_shortcuts_model_load (data); -} - - - -static void -thunar_shortcuts_model_monitor (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (user_data); - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (model->bookmarks_monitor == monitor); - - /* leave if we saved less than 2 seconds ago */ - if (model->bookmarks_time + 2 * G_USEC_PER_SEC > g_get_real_time ()) - return; - - /* reload the shortcuts model */ - if (model->bookmarks_idle_id == 0) - model->bookmarks_idle_id = g_idle_add (thunar_shortcuts_model_reload, model); -} - - - -static void -thunar_shortcuts_model_save (ThunarShortcutsModel *model) -{ - GString *contents; - ThunarShortcut *shortcut; - gchar *bookmarks_path; - gchar *uri; - GList *lp; - GError *err = NULL; - GFile *parent = NULL; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - contents = g_string_new (NULL); - - for (lp = model->shortcuts; lp != NULL; lp = lp->next) - { - shortcut = THUNAR_SHORTCUT (lp->data); - if (shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS) - { - if (shortcut->file != NULL) - uri = thunar_file_dup_uri (shortcut->file); - else if (shortcut->location != NULL) - uri = g_file_get_uri (shortcut->location); - else - continue; - - if (G_LIKELY (shortcut->name != NULL)) - g_string_append_printf (contents, "%s %s\n", uri, shortcut->name); - else - g_string_append_printf (contents, "%s\n", uri); - g_free (uri); - } - } - - /* create folder if it does not exist */ - parent = g_file_get_parent (model->bookmarks_file); - if (!g_file_make_directory_with_parents (parent, NULL, &err)) - { - if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_EXISTS)) - { - g_clear_error (&err); - } - else - { - g_warning ("Failed to create bookmarks folder: %s", err->message); - g_error_free (err); - } - } - g_clear_object (&parent); - - /* write data to the disk */ - bookmarks_path = g_file_get_path (model->bookmarks_file); - if (!g_file_set_contents (bookmarks_path, contents->str, contents->len, &err)) - { - g_warning ("Failed to write \"%s\": %s", bookmarks_path, err->message); - g_error_free (err); - } - g_free (bookmarks_path); - g_string_free (contents, TRUE); - - /* store the save time */ - model->bookmarks_time = g_get_real_time (); -} - - - -static void -thunar_shortcuts_model_file_changed (ThunarFile *file, - ThunarShortcutsModel *model) -{ - ThunarShortcut *shortcut; - GtkTreePath *path; - GtkTreeIter iter; - GList *lp; - gint idx; - - _thunar_return_if_fail (THUNAR_IS_FILE (file)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - /* check if the file still refers to a directory or a not mounted URI, - * otherwise we cannot keep it on the shortcuts list, and so we'll treat - * it like the file was destroyed (and thereby removed) */ - - if (G_UNLIKELY (!thunar_file_is_directory (file))) - { - thunar_shortcuts_model_file_destroy (file, model); - return; - } - - for (idx = 0, lp = model->shortcuts; lp != NULL; ++idx, lp = lp->next) - { - shortcut = THUNAR_SHORTCUT (lp->data); - if (shortcut->file == file) - { - GTK_TREE_ITER_INIT (iter, model->stamp, lp); - - path = gtk_tree_path_new_from_indices (idx, -1); - gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); - gtk_tree_path_free (path); - break; - } - } -} - - - -static void -thunar_shortcuts_model_file_destroy (ThunarFile *file, - ThunarShortcutsModel *model) -{ - ThunarShortcut *shortcut = NULL; - GList *lp; - - _thunar_return_if_fail (THUNAR_IS_FILE (file)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - /* lookup the shortcut matching the file */ - for (lp = model->shortcuts; lp != NULL; lp = lp->next) - { - shortcut = THUNAR_SHORTCUT (lp->data); - if (shortcut->file == file) - break; - } - - /* verify that we actually found a shortcut */ - _thunar_assert (lp != NULL); - _thunar_assert (THUNAR_IS_FILE (shortcut->file)); - - /* drop the shortcut from the model */ - thunar_shortcuts_model_remove_shortcut (model, shortcut); -} - - - -static void -thunar_shortcuts_model_device_added (ThunarDeviceMonitor *device_monitor, - ThunarDevice *device, - ThunarShortcutsModel *model) -{ - ThunarShortcut *shortcut; - - _thunar_return_if_fail (device_monitor == NULL || THUNAR_DEVICE_MONITOR (device_monitor)); - _thunar_return_if_fail (device_monitor == NULL || model->device_monitor == device_monitor); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - /* allocate a new shortcut */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->device = g_object_ref (device); - shortcut->hidden = thunar_device_get_hidden (device); - - switch (thunar_device_get_kind (device)) - { - case THUNAR_DEVICE_KIND_VOLUME: - shortcut->group = THUNAR_SHORTCUT_GROUP_DEVICES_VOLUMES; - break; - - case THUNAR_DEVICE_KIND_MOUNT_LOCAL: - shortcut->group = THUNAR_SHORTCUT_GROUP_DEVICES_MOUNTS; - break; - - case THUNAR_DEVICE_KIND_MOUNT_REMOTE: - shortcut->group = THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS; - break; - } - - /* insert in the model */ - thunar_shortcuts_model_add_shortcut (model, shortcut); - - /* header visibility if call is from monitor */ - if (device_monitor != NULL - && !shortcut->hidden) - thunar_shortcuts_model_header_visibility (model); -} - - - -static void -thunar_shortcuts_model_device_removed (ThunarDeviceMonitor *device_monitor, - ThunarDevice *device, - ThunarShortcutsModel *model) -{ - GList *lp; - - _thunar_return_if_fail (THUNAR_DEVICE_MONITOR (device_monitor)); - _thunar_return_if_fail (model->device_monitor == device_monitor); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - /* find the shortcut */ - for (lp = model->shortcuts; lp != NULL; lp = lp->next) - if (THUNAR_SHORTCUT (lp->data)->device == device) - break; - - /* something is broken if we don't have a shortcut here */ - _thunar_assert (lp != NULL); - _thunar_assert (THUNAR_SHORTCUT (lp->data)->device == device); - - /* drop the shortcut from the model */ - if (G_LIKELY (lp != NULL)) - thunar_shortcuts_model_remove_shortcut (model, lp->data); -} - - - -static void -thunar_shortcuts_model_device_changed (ThunarDeviceMonitor *device_monitor, - ThunarDevice *device, - ThunarShortcutsModel *model) -{ - GtkTreeIter iter; - GList *lp; - gint idx; - GtkTreePath *path; - ThunarShortcut *shortcut; - gboolean update_header = FALSE; - - _thunar_return_if_fail (THUNAR_DEVICE_MONITOR (device_monitor)); - _thunar_return_if_fail (model->device_monitor == device_monitor); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - /* find the shortcut */ - for (lp = model->shortcuts, idx = 0; lp != NULL; lp = lp->next, idx++) - if (THUNAR_SHORTCUT (lp->data)->device == device) - break; - - /* something is broken if we don't have a shortcut here */ - _thunar_assert (lp != NULL); - _thunar_assert (THUNAR_SHORTCUT (lp->data)->device == device); - - if (G_LIKELY (lp != NULL)) - { - shortcut = lp->data; - - /* cleanup tooltip */ - g_free (shortcut->tooltip); - shortcut->tooltip = NULL; - - /* hidden state */ - if (shortcut->hidden != thunar_device_get_hidden (device)) - { - shortcut->hidden = thunar_device_get_hidden (device); - update_header = TRUE; - } - - /* generate an iterator for the path */ - GTK_TREE_ITER_INIT (iter, model->stamp, lp); - - /* tell the view that the volume has changed in some way */ - path = gtk_tree_path_new_from_indices (idx, -1); - gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); - gtk_tree_path_free (path); - } - - /* header visibility */ - if (update_header) - thunar_shortcuts_model_header_visibility (model); -} - - - -static void -thunar_shortcut_free (ThunarShortcut *shortcut, - ThunarShortcutsModel *model) -{ - if (G_LIKELY (shortcut->file != NULL)) - { - /* drop the file watch */ - thunar_file_unwatch (shortcut->file); - - /* unregister from the file */ - g_signal_handlers_disconnect_matched (shortcut->file, - G_SIGNAL_MATCH_DATA, 0, - 0, NULL, NULL, model); - g_object_unref (shortcut->file); - } - - if (G_LIKELY (shortcut->device != NULL)) - g_object_unref (shortcut->device); - - if (G_LIKELY (shortcut->gicon != NULL)) - g_object_unref (shortcut->gicon); - - if (G_LIKELY (shortcut->location != NULL)) - g_object_unref (shortcut->location); - - g_free (shortcut->name); - g_free (shortcut->tooltip); - - /* release the shortcut itself */ - g_slice_free (ThunarShortcut, shortcut); -} - - - -static gboolean -thunar_shortcuts_model_busy_timeout (gpointer data) -{ - ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (data); - gboolean keep_running = FALSE; - ThunarShortcut *shortcut; - GtkTreePath *path; - guint idx; - GtkTreeIter iter; - GList *lp; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (data), FALSE); - - for (lp = model->shortcuts, idx = 0; lp != NULL; lp = lp->next, idx++) - { - shortcut = lp->data; - if (!shortcut->busy) - continue; - - /* loop the pulse of the shortcut */ - shortcut->busy_pulse++; - if (shortcut->busy_pulse >= SPINNER_NUM_STEPS) - shortcut->busy_pulse = 0; - - /* generate an iterator for the path */ - GTK_TREE_ITER_INIT (iter, model->stamp, lp); - - /* notify the views about the change */ - path = gtk_tree_path_new_from_indices (idx, -1); - gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); - gtk_tree_path_free (path); - - /* keep the timeout running */ - keep_running = TRUE; - } - - return keep_running; -} - - - -static void -thunar_shortcuts_model_busy_timeout_destroyed (gpointer data) -{ - THUNAR_SHORTCUTS_MODEL (data)->busy_timeout_id = 0; -} - - - -/** - * thunar_shortcuts_model_get_default: - * - * Returns the default #ThunarShortcutsModel instance shared by - * all #ThunarShortcutsView instances. - * - * Call #g_object_unref() on the returned object when you - * don't need it any longer. - * - * Return value: the default #ThunarShortcutsModel instance. - **/ -ThunarShortcutsModel* -thunar_shortcuts_model_get_default (void) -{ - static ThunarShortcutsModel *model = NULL; - - if (G_UNLIKELY (model == NULL)) - { - model = g_object_new (THUNAR_TYPE_SHORTCUTS_MODEL, NULL); - g_object_add_weak_pointer (G_OBJECT (model), (gpointer) &model); - } - else - { - g_object_ref (G_OBJECT (model)); - } - - return model; -} - - - -/** - * thunar_shortcuts_model_has_bookmark: - * @model : a #ThunarShortcutsModel instance. - * @file : a #ThuanrFile instance. - * - * Returns %TRUE if there is a bookmark (not a mount or volume) with - * @file as destination. - * - * Return value: %TRUE if @file was found, else %FALSE. - **/ -gboolean -thunar_shortcuts_model_has_bookmark (ThunarShortcutsModel *model, - GFile *file) -{ - GList *lp; - ThunarShortcut *shortcut; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - _thunar_return_val_if_fail (G_IS_FILE (file), FALSE); - - for (lp = model->shortcuts; lp != NULL; lp = lp->next) - { - shortcut = lp->data; - - /* only check bookmarks */ - if (shortcut->group != THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS) - continue; - - if (shortcut->file != NULL - && g_file_equal (thunar_file_get_file (shortcut->file), file)) - return TRUE; - - if (shortcut->location != NULL - && g_file_equal (shortcut->location, file)) - return TRUE; - } - - return FALSE; -} - - - -/** - * thunar_shortcuts_model_iter_for_file: - * @model : a #ThunarShortcutsModel instance. - * @file : a #ThuanrFile instance. - * @iter : pointer to a #GtkTreeIter. - * - * Tries to lookup the #GtkTreeIter, that belongs to a shortcut, which - * refers to @file and stores it to @iter. If no such #GtkTreeIter was - * found, %FALSE will be returned and @iter won't be changed. Else - * %TRUE will be returned and @iter will be set appropriately. - * - * Return value: %TRUE if @file was found, else %FALSE. - **/ -gboolean -thunar_shortcuts_model_iter_for_file (ThunarShortcutsModel *model, - ThunarFile *file, - GtkTreeIter *iter) -{ - GFile *mount_point; - GList *lp; - ThunarShortcut *shortcut; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); - _thunar_return_val_if_fail (iter != NULL, FALSE); - - for (lp = model->shortcuts; lp != NULL; lp = lp->next) - { - shortcut = lp->data; - - /* check if we have a location that matches */ - if (shortcut->file == file) - { - GTK_TREE_ITER_INIT (*iter, model->stamp, lp); - return TRUE; - } - - if (shortcut->location != NULL - && g_file_equal (shortcut->location, thunar_file_get_file (file))) - { - GTK_TREE_ITER_INIT (*iter, model->stamp, lp); - return TRUE; - } - - /* but maybe we have a mounted(!) volume with a matching mount point */ - if (shortcut->device != NULL - && !thunar_device_get_hidden (shortcut->device)) - { - mount_point = thunar_device_get_root (shortcut->device); - if (mount_point != NULL) - { - if (g_file_equal (mount_point, thunar_file_get_file (file))) - { - GTK_TREE_ITER_INIT (*iter, model->stamp, lp); - g_object_unref (mount_point); - return TRUE; - } - - g_object_unref (mount_point); - } - } - } - - return FALSE; -} - - - -/** - * thunar_shortcuts_model_drop_possible: - * @model : a #ThunarShortcutstModel. - * @path : a #GtkTreePath. - * - * Determines whether a drop is possible before the given @path, at the same depth - * as @path. I.e., can we drop data at that location. @path does not have to exist; - * the return value will almost certainly be FALSE if the parent of @path doesn't - * exist, though. - * - * Return value: %TRUE if it's possible to drop data before @path, else %FALSE. - **/ -gboolean -thunar_shortcuts_model_drop_possible (ThunarShortcutsModel *model, - GtkTreePath *path) -{ - ThunarShortcut *shortcut; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE); - _thunar_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE); - - /* determine the list item for the path */ - shortcut = g_list_nth_data (model->shortcuts, gtk_tree_path_get_indices (path)[0]); - - /* append to the list is not possible */ - if (G_LIKELY (shortcut == NULL)) - return FALSE; - - /* cannot drop before special shortcuts! */ - if (shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS) - return TRUE; - - /* we can drop at the end of the bookmarks (before network header) */ - if (shortcut->group == THUNAR_SHORTCUT_GROUP_NETWORK_HEADER) - return TRUE; - - return FALSE; -} - - - -/** - * thunar_shortcuts_model_add: - * @model : a #ThunarShortcutsModel. - * @dst_path : the destination path. - * @file : the #ThunarFile that should be added to the shortcuts list. - * - * Adds the shortcut @file to the @model at @dst_path, unless @file is - * already present in @model in which case no action is performed. - **/ -void -thunar_shortcuts_model_add (ThunarShortcutsModel *model, - GtkTreePath *dst_path, - gpointer file) -{ - ThunarShortcut *shortcut; - GFile *location; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (dst_path == NULL || gtk_tree_path_get_depth (dst_path) > 0); - _thunar_return_if_fail (dst_path == NULL || gtk_tree_path_get_indices (dst_path)[0] >= 0); - _thunar_return_if_fail (dst_path == NULL || gtk_tree_path_get_indices (dst_path)[0] <= (gint) g_list_length (model->shortcuts)); - _thunar_return_if_fail (THUNAR_IS_FILE (file) || G_IS_FILE (file)); - - location = G_IS_FILE (file) ? file : thunar_file_get_file (file); - - /* verify that the file is not already in use as shortcut */ - if (thunar_shortcuts_model_has_bookmark (model, location)) - return; - - /* create the new shortcut that will be inserted */ - shortcut = g_slice_new0 (ThunarShortcut); - shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS; - - if (thunar_shortcuts_model_local_file (location)) - { - shortcut->file = thunar_file_get (location, NULL); - } - else - { - shortcut->location = g_object_ref (G_OBJECT (location)); - shortcut->gicon = g_themed_icon_new ("folder-remote"); - } - - /* add the shortcut to the list at the given position */ - thunar_shortcuts_model_add_shortcut_with_path (model, shortcut, dst_path); - - /* the shortcuts list was changed, so write the gtk bookmarks file */ - thunar_shortcuts_model_save (model); -} - - - -/** - * thunar_shortcuts_model_move: - * @model : a #ThunarShortcutsModel. - * @src_path : the source path. - * @dst_path : the destination path. - * - * Moves the shortcut at @src_path to @dst_path, adjusting other - * shortcut's positions as required. - **/ -void -thunar_shortcuts_model_move (ThunarShortcutsModel *model, - GtkTreePath *src_path, - GtkTreePath *dst_path) -{ - ThunarShortcut *shortcut; - GtkTreePath *path; - GList *lp; - gint *order; - gint index_src; - gint index_dst; - gint idx; - gint n_shortcuts; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (gtk_tree_path_get_depth (src_path) > 0); - _thunar_return_if_fail (gtk_tree_path_get_depth (dst_path) > 0); - _thunar_return_if_fail (gtk_tree_path_get_indices (src_path)[0] >= 0); - _thunar_return_if_fail (gtk_tree_path_get_indices (src_path)[0] < (gint) g_list_length (model->shortcuts)); - _thunar_return_if_fail (gtk_tree_path_get_indices (dst_path)[0] > 0); - - index_src = gtk_tree_path_get_indices (src_path)[0]; - index_dst = gtk_tree_path_get_indices (dst_path)[0]; - - if (G_UNLIKELY (index_src == index_dst)) - return; - - /* generate the order for the rows prior the dst/src rows */ - n_shortcuts = g_list_length (model->shortcuts); - order = g_newa (gint, n_shortcuts); - for (idx = 0, lp = model->shortcuts; idx < index_src && idx < index_dst; ++idx, lp = lp->next) - order[idx] = idx; - - if (idx == index_src) - { - shortcut = THUNAR_SHORTCUT (lp->data); - - for (; idx < index_dst; ++idx, lp = lp->next) - { - if (lp->next == NULL) - break; - lp->data = lp->next->data; - order[idx] = idx + 1; - } - - lp->data = shortcut; - order[idx++] = index_src; - } - else - { - for (; idx < index_src; ++idx, lp = lp->next) - ; - - _thunar_assert (idx == index_src); - - shortcut = THUNAR_SHORTCUT (lp->data); - - for (; idx > index_dst; --idx, lp = lp->prev) - { - lp->data = lp->prev->data; - order[idx] = idx - 1; - } - - _thunar_assert (idx == index_dst); - - lp->data = shortcut; - order[idx] = index_src; - idx = index_src + 1; - } - - /* generate the remaining order */ - for (; idx < n_shortcuts; ++idx) - order[idx] = idx; - - /* tell all listeners about the reordering just performed */ - path = gtk_tree_path_new_first (); - gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model), path, NULL, order); - gtk_tree_path_free (path); - - /* the shortcuts list was changed, so write the gtk bookmarks file */ - thunar_shortcuts_model_save (model); -} - - - -/** - * thunar_shortcuts_model_remove: - * @model : a #ThunarShortcutsModel. - * @path : the #GtkTreePath of the shortcut to remove. - * - * Removes the shortcut at @path from the @model and syncs to - * on-disk storage. @path must refer to a valid, user-defined - * shortcut, as you cannot remove system-defined entities (they - * are managed internally). - **/ -void -thunar_shortcuts_model_remove (ThunarShortcutsModel *model, - GtkTreePath *path) -{ - ThunarShortcut *shortcut; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (gtk_tree_path_get_depth (path) > 0); - _thunar_return_if_fail (gtk_tree_path_get_indices (path)[0] >= 0); - _thunar_return_if_fail (gtk_tree_path_get_indices (path)[0] < (gint) g_list_length (model->shortcuts)); - - /* lookup the shortcut for the given path */ - shortcut = g_list_nth_data (model->shortcuts, gtk_tree_path_get_indices (path)[0]); - - /* verify that the shortcut is removable */ - _thunar_assert (shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS); - - /* remove the shortcut (using the file destroy handler) */ - thunar_shortcuts_model_remove_shortcut (model, shortcut); -} - - - -/** - * thunar_shortcuts_model_rename: - * @model : a #ThunarShortcutsModel. - * @iter : the #GtkTreeIter which refers to the shortcut that - * should be renamed to @name. - * @name : the new name for the shortcut at @path or %NULL to - * return to the default name. - * - * Renames the shortcut at @iter to the new @name in @model. - * - * @name may be %NULL or an empty to reset the shortcut to - * its default name. - **/ -void -thunar_shortcuts_model_rename (ThunarShortcutsModel *model, - GtkTreeIter *iter, - const gchar *name) -{ - ThunarShortcut *shortcut; - GtkTreePath *path; - - _thunar_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (iter->stamp == model->stamp); - _thunar_return_if_fail (iter->user_data != NULL); - - /* lookup the shortcut for the given path */ - shortcut = THUNAR_SHORTCUT (((GList *) iter->user_data)->data); - - /* verify the shortcut */ - _thunar_assert (shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS); - - /* perform the rename */ - if (G_UNLIKELY (shortcut->name != NULL)) - g_free (shortcut->name); - if (G_UNLIKELY (name == NULL || *name == '\0')) - shortcut->name = NULL; - else - shortcut->name = g_strdup (name); - - /* notify the views about the change */ - path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); - gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, iter); - gtk_tree_path_free (path); - - /* save the changes to the model */ - thunar_shortcuts_model_save (model); -} - - - -void -thunar_shortcuts_model_set_busy (ThunarShortcutsModel *model, - ThunarDevice *device, - gboolean busy) -{ - ThunarShortcut *shortcut; - GList *lp; - guint idx; - GtkTreeIter iter; - GtkTreePath *path; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - - /* get the device */ - for (lp = model->shortcuts, idx = 0; lp != NULL; lp = lp->next, idx++) - if (THUNAR_SHORTCUT (lp->data)->device == device) - break; - - if (lp == NULL) - return; - - shortcut = lp->data; - _thunar_assert (shortcut->device == device); - - if (G_LIKELY (shortcut->busy != busy)) - { - shortcut->busy = busy; - - if (busy && model->busy_timeout_id == 0) - { - /* start the global cycle timeout */ - model->busy_timeout_id = - gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT, - SPINNER_CYCLE_DURATION / SPINNER_NUM_STEPS, - thunar_shortcuts_model_busy_timeout, model, - thunar_shortcuts_model_busy_timeout_destroyed); - } - else if (!busy) - { - /* generate an iterator for the path */ - GTK_TREE_ITER_INIT (iter, model->stamp, lp); - - /* notify the views about the change */ - path = gtk_tree_path_new_from_indices (idx, -1); - gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); - gtk_tree_path_free (path); - } - } -} - - - - -void -thunar_shortcuts_model_set_hidden (ThunarShortcutsModel *model, - GtkTreePath *path, - gboolean hidden) -{ - ThunarShortcut *shortcut; - guint length; - gchar **bookmarks; - guint pos; - gchar *uri; - guint n; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - _thunar_return_if_fail (gtk_tree_path_get_depth (path) > 0); - _thunar_return_if_fail (gtk_tree_path_get_indices (path)[0] >= 0); - _thunar_return_if_fail (gtk_tree_path_get_indices (path)[0] < (gint) g_list_length (model->shortcuts)); - - /* lookup the shortcut for the given path */ - shortcut = g_list_nth_data (model->shortcuts, gtk_tree_path_get_indices (path)[0]); - _thunar_return_if_fail (shortcut != NULL); - - if (shortcut->device != NULL) - { - /* if this is a device, store in the device monitor */ - thunar_device_monitor_set_hidden (model->device_monitor, shortcut->device, hidden); - return; - } - - /* get the uri */ - if (shortcut->file != NULL) - uri = thunar_file_dup_uri (shortcut->file); - else if (shortcut->location != NULL) - uri = g_file_get_uri (shortcut->location); - else - _thunar_assert_not_reached (); - - /* prepare array */ - length = model->hidden_bookmarks != NULL ? g_strv_length (model->hidden_bookmarks) : 0; - bookmarks = g_new0 (gchar *, length + 2); - pos = 0; - - /* copy other uuid in the new list */ - if (model->hidden_bookmarks != NULL) - { - for (n = 0; model->hidden_bookmarks[n] != NULL; n++) - if (g_strcmp0 (model->hidden_bookmarks[n], uri) != 0) - bookmarks[pos++] = g_strdup (model->hidden_bookmarks[n]); - } - - /* add the new uri if it should hide */ - if (hidden) - bookmarks[pos++] = uri; - else - g_free (uri); - - /* store new list */ - g_object_set (G_OBJECT (model->preferences), "hidden-bookmarks", bookmarks, NULL); - g_strfreev (bookmarks); - - /* header visibility */ - thunar_shortcuts_model_header_visibility (model); -} diff --git a/thunar/thunar-shortcuts-model.h b/thunar/thunar-shortcuts-model.h deleted file mode 100644 index cb87a1f7f639dd612811038b98532f3c19e34b16..0000000000000000000000000000000000000000 --- a/thunar/thunar-shortcuts-model.h +++ /dev/null @@ -1,129 +0,0 @@ -/* vi:set et ai sw=2 sts=2 ts=2: */ -/*- - * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> - * - * This program 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. - * - * This program 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 - */ - -#ifndef __THUNAR_SHORTCUTS_MODEL_H__ -#define __THUNAR_SHORTCUTS_MODEL_H__ - -#include <thunar/thunar-file.h> -#include <thunar/thunar-device.h> - -G_BEGIN_DECLS; - -typedef struct _ThunarShortcutsModelClass ThunarShortcutsModelClass; -typedef struct _ThunarShortcutsModel ThunarShortcutsModel; -typedef enum _ThunarShortcutGroup ThunarShortcutGroup; - -#define THUNAR_TYPE_SHORTCUTS_MODEL (thunar_shortcuts_model_get_type ()) -#define THUNAR_SHORTCUTS_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_SHORTCUTS_MODEL, ThunarShortcutsModel)) -#define THUNAR_SHORTCUTS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_SHORTCUTS_MODEL, ThunarShortcutsModelClass)) -#define THUNAR_IS_SHORTCUTS_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_SHORTCUTS_MODEL)) -#define THUNAR_IS_SHORTCUTS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_SHORTCUTS_MODEL)) -#define THUNAR_SHORTCUTS_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_MODEL_SHORTCUTS_MODEL, ThunarShortcutsModelClass)) - -typedef enum -{ - THUNAR_SHORTCUTS_MODEL_COLUMN_IS_HEADER, - THUNAR_SHORTCUTS_MODEL_COLUMN_IS_ITEM, - THUNAR_SHORTCUTS_MODEL_COLUMN_VISIBLE, - THUNAR_SHORTCUTS_MODEL_COLUMN_NAME, - THUNAR_SHORTCUTS_MODEL_COLUMN_TOOLTIP, - THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, - THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION, - THUNAR_SHORTCUTS_MODEL_COLUMN_GICON, - THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, - THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE, - THUNAR_SHORTCUTS_MODEL_COLUMN_CAN_EJECT, - THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP, - THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY, - THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY_PULSE, - THUNAR_SHORTCUTS_MODEL_N_COLUMNS, -} ThunarShortcutsModelColumn; - -#define THUNAR_SHORTCUT_GROUP_DEVICES (THUNAR_SHORTCUT_GROUP_DEVICES_HEADER \ - | THUNAR_SHORTCUT_GROUP_DEVICES_FILESYSTEM \ - | THUNAR_SHORTCUT_GROUP_DEVICES_VOLUMES \ - | THUNAR_SHORTCUT_GROUP_DEVICES_MOUNTS) -#define THUNAR_SHORTCUT_GROUP_PLACES (THUNAR_SHORTCUT_GROUP_PLACES_HEADER \ - | THUNAR_SHORTCUT_GROUP_PLACES_DEFAULT \ - | THUNAR_SHORTCUT_GROUP_PLACES_TRASH \ - | THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS) -#define THUNAR_SHORTCUT_GROUP_NETWORK (THUNAR_SHORTCUT_GROUP_NETWORK_HEADER \ - | THUNAR_SHORTCUT_GROUP_NETWORK_DEFAULT \ - | THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS) -#define THUNAR_SHORTCUT_GROUP_HEADER (THUNAR_SHORTCUT_GROUP_DEVICES_HEADER \ - | THUNAR_SHORTCUT_GROUP_PLACES_HEADER \ - | THUNAR_SHORTCUT_GROUP_NETWORK_HEADER) - -enum _ThunarShortcutGroup -{ - /* THUNAR_SHORTCUT_GROUP_DEVICES */ - THUNAR_SHORTCUT_GROUP_DEVICES_HEADER = (1 << 0), /* devices header */ - THUNAR_SHORTCUT_GROUP_DEVICES_FILESYSTEM = (1 << 1), /* local filesystem */ - THUNAR_SHORTCUT_GROUP_DEVICES_VOLUMES = (1 << 2), /* local ThunarDevices */ - THUNAR_SHORTCUT_GROUP_DEVICES_MOUNTS = (1 << 3), /* local mounts, like cameras and archives */ - - /* THUNAR_SHORTCUT_GROUP_PLACES */ - THUNAR_SHORTCUT_GROUP_PLACES_HEADER = (1 << 4), /* places header */ - THUNAR_SHORTCUT_GROUP_PLACES_DEFAULT = (1 << 5), /* home and desktop */ - THUNAR_SHORTCUT_GROUP_PLACES_TRASH = (1 << 6), /* trash */ - THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS = (1 << 7), /* gtk-bookmarks */ - - /* THUNAR_SHORTCUT_GROUP_NETWORK */ - THUNAR_SHORTCUT_GROUP_NETWORK_HEADER = (1 << 8), /* network header */ - THUNAR_SHORTCUT_GROUP_NETWORK_DEFAULT = (1 << 9), /* browse network */ - THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS = (1 << 10), /* remote ThunarDevices */ -}; - - - -GType thunar_shortcuts_model_get_type (void) G_GNUC_CONST; - -ThunarShortcutsModel *thunar_shortcuts_model_get_default (void); - -gboolean thunar_shortcuts_model_has_bookmark (ThunarShortcutsModel *model, - GFile *file); - -gboolean thunar_shortcuts_model_iter_for_file (ThunarShortcutsModel *model, - ThunarFile *file, - GtkTreeIter *iter); - -gboolean thunar_shortcuts_model_drop_possible (ThunarShortcutsModel *model, - GtkTreePath *path); - -void thunar_shortcuts_model_add (ThunarShortcutsModel *model, - GtkTreePath *dst_path, - gpointer file); -void thunar_shortcuts_model_move (ThunarShortcutsModel *model, - GtkTreePath *src_path, - GtkTreePath *dst_path); -void thunar_shortcuts_model_remove (ThunarShortcutsModel *model, - GtkTreePath *path); -void thunar_shortcuts_model_rename (ThunarShortcutsModel *model, - GtkTreeIter *iter, - const gchar *name); -void thunar_shortcuts_model_set_busy (ThunarShortcutsModel *model, - ThunarDevice *device, - gboolean busy); -void thunar_shortcuts_model_set_hidden (ThunarShortcutsModel *model, - GtkTreePath *path, - gboolean hidden); - -G_END_DECLS; - -#endif /* !__THUNAR_SHORTCUTS_MODEL_H__ */ diff --git a/thunar/thunar-shortcuts-pane.c b/thunar/thunar-shortcuts-pane.c index 590a92cf83b95cd468f3672a5768987bcdf1f46a..fa646b4c43a502951c07c9586b0c129945da926b 100644 --- a/thunar/thunar-shortcuts-pane.c +++ b/thunar/thunar-shortcuts-pane.c @@ -1,6 +1,7 @@ /* vi:set et ai sw=2 sts=2 ts=2: */ /*- * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2015 Jonas Kümmerlin <rgcjonas@gmail.com> * * This program 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 @@ -23,12 +24,17 @@ #include <thunar/thunar-gobject-extensions.h> #include <thunar/thunar-private.h> -#include <thunar/thunar-shortcuts-model.h> #include <thunar/thunar-shortcuts-pane.h> #include <thunar/thunar-shortcuts-pane-ui.h> -#include <thunar/thunar-shortcuts-view.h> #include <thunar/thunar-side-pane.h> #include <thunar/thunar-stock.h> +#include <thunar/thunar-browser.h> +#include <thunar/thunar-dialogs.h> +#include <thunar/thunar-application.h> +#include <thunar/thunar-dnd.h> +#include <thunar/thunar-gtk-extensions.h> +#include <thunar/thunar-gio-extensions.h> +#include <thunar/thunar-util.h> @@ -67,17 +73,35 @@ static void thunar_shortcuts_pane_set_ui_manager (ThunarComponen GtkUIManager *ui_manager); static void thunar_shortcuts_pane_action_shortcuts_add (GtkAction *action, ThunarShortcutsPane *shortcuts_pane); +static void thunar_shortcuts_pane_open_location (GtkPlacesSidebar *sidebar, + GFile *location, + GtkPlacesOpenFlags flags, + ThunarShortcutsPane *shortcuts_pane); +static gint thunar_shortcuts_pane_drag_action_requested (GtkPlacesSidebar *sidebar, + GdkDragContext *context, + GFile *dest_file, + GList *source_file_list, + ThunarShortcutsPane *shortcuts_pane); +static void thunar_shortcuts_pane_drag_perform_drop (GtkPlacesSidebar *sidebar, + GFile *dest_file, + GList *source_file_list, + GdkDragAction action, + ThunarShortcutsPane *shortcuts_pane); +static gint thunar_shortcuts_pane_drag_action_ask (GtkPlacesSidebar *sidebar, + GdkDragAction actions, + ThunarShortcutsPane *shortcuts_pane); + struct _ThunarShortcutsPaneClass { - GtkScrolledWindowClass __parent__; + GtkBinClass __parent__; }; struct _ThunarShortcutsPane { - GtkScrolledWindow __parent__; + GtkBin __parent__; ThunarFile *current_directory; GList *selected_files; @@ -86,7 +110,7 @@ struct _ThunarShortcutsPane GtkUIManager *ui_manager; guint ui_merge_id; - GtkWidget *view; + GtkWidget *places; guint idle_select_directory; }; @@ -100,10 +124,11 @@ static const GtkActionEntry action_entries[] = -G_DEFINE_TYPE_WITH_CODE (ThunarShortcutsPane, thunar_shortcuts_pane, GTK_TYPE_SCROLLED_WINDOW, +G_DEFINE_TYPE_WITH_CODE (ThunarShortcutsPane, thunar_shortcuts_pane, GTK_TYPE_BIN, G_IMPLEMENT_INTERFACE (THUNAR_TYPE_NAVIGATOR, thunar_shortcuts_pane_navigator_init) G_IMPLEMENT_INTERFACE (THUNAR_TYPE_COMPONENT, thunar_shortcuts_pane_component_init) - G_IMPLEMENT_INTERFACE (THUNAR_TYPE_SIDE_PANE, thunar_shortcuts_pane_side_pane_init)) + G_IMPLEMENT_INTERFACE (THUNAR_TYPE_SIDE_PANE, thunar_shortcuts_pane_side_pane_init) + G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER, NULL)) @@ -168,20 +193,17 @@ thunar_shortcuts_pane_init (ThunarShortcutsPane *shortcuts_pane) gtk_action_group_set_translation_domain (shortcuts_pane->action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions (shortcuts_pane->action_group, action_entries, G_N_ELEMENTS (action_entries), shortcuts_pane); - /* configure the GtkScrolledWindow */ - gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (shortcuts_pane), NULL); - gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (shortcuts_pane), NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (shortcuts_pane), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (shortcuts_pane), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + /* configure the places sidebar */ + shortcuts_pane->places = gtk_places_sidebar_new (); + gtk_places_sidebar_set_open_flags (GTK_PLACES_SIDEBAR (shortcuts_pane->places), GTK_PLACES_OPEN_NORMAL|GTK_PLACES_OPEN_NEW_TAB|GTK_PLACES_OPEN_NEW_WINDOW); - /* allocate the shortcuts view */ - shortcuts_pane->view = thunar_shortcuts_view_new (); - gtk_container_add (GTK_CONTAINER (shortcuts_pane), shortcuts_pane->view); - gtk_widget_show (shortcuts_pane->view); + g_signal_connect (shortcuts_pane->places, "open-location", G_CALLBACK (thunar_shortcuts_pane_open_location), shortcuts_pane); + g_signal_connect (shortcuts_pane->places, "drag-action-requested", G_CALLBACK (thunar_shortcuts_pane_drag_action_requested), shortcuts_pane); + g_signal_connect (shortcuts_pane->places, "drag-perform-drop", G_CALLBACK (thunar_shortcuts_pane_drag_perform_drop), shortcuts_pane); + g_signal_connect (shortcuts_pane->places, "drag-action-ask", G_CALLBACK (thunar_shortcuts_pane_drag_action_ask), shortcuts_pane); - /* connect the "shortcut-activated" signal */ - g_signal_connect_swapped (G_OBJECT (shortcuts_pane->view), "shortcut-activated", G_CALLBACK (thunar_navigator_change_directory), shortcuts_pane); - g_signal_connect_swapped (G_OBJECT (shortcuts_pane->view), "shortcut-activated-tab", G_CALLBACK (thunar_navigator_open_new_tab), shortcuts_pane); + gtk_container_add (GTK_CONTAINER (shortcuts_pane), shortcuts_pane->places); + gtk_widget_show (shortcuts_pane->places); } @@ -292,8 +314,8 @@ thunar_shortcuts_pane_set_current_directory_idle (gpointer data) if (shortcuts_pane->current_directory != NULL) { - thunar_shortcuts_view_select_by_file (THUNAR_SHORTCUTS_VIEW (shortcuts_pane->view), - shortcuts_pane->current_directory); + gtk_places_sidebar_set_location (GTK_PLACES_SIDEBAR (shortcuts_pane->places), + thunar_file_get_file (shortcuts_pane->current_directory)); } /* unset id */ @@ -378,20 +400,12 @@ thunar_shortcuts_pane_set_selected_files (ThunarComponent *component, if (lp == NULL && selected_files != NULL) { /* check if atleast one of the selected folders is not already present in the model */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (shortcuts_pane->view)); - if (G_LIKELY (model != NULL)) - { - /* check all selected folders */ - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - for (lp = selected_files; lp != NULL; lp = lp->next) - if (!thunar_shortcuts_model_has_bookmark (THUNAR_SHORTCUTS_MODEL (child_model), thunar_file_get_file (lp->data))) - break; - } + /* TODO */ /* display the action and change the label appropriately */ g_object_set (G_OBJECT (action), "label", ngettext ("Side Pane (Create Shortcut)", "Side Pane (Create Shortcuts)", n), - "sensitive", (lp != NULL), + "sensitive", /*(lp != NULL)*/ TRUE, "tooltip", ngettext ("Add the selected folder to the shortcuts side pane", "Add the selected folders to the shortcuts side pane", n), "visible", TRUE, @@ -462,35 +476,316 @@ thunar_shortcuts_pane_set_ui_manager (ThunarComponent *component, g_object_notify (G_OBJECT (shortcuts_pane), "ui-manager"); } +struct bookmark +{ + struct bookmark *next; + GFile *file; + gchar *name; +}; + +static void store_bookmark (GFile *file, + const gchar *name, + gint row_num, + gpointer user_data) +{ + struct bookmark **plist = user_data; + struct bookmark *bm = g_slice_new0 (struct bookmark); + + _thunar_return_if_fail (plist != NULL); + + bm->next = *plist; + bm->file = g_object_ref (file); + bm->name = g_strdup (name); + + *plist = bm; +} + static void thunar_shortcuts_pane_action_shortcuts_add (GtkAction *action, ThunarShortcutsPane *shortcuts_pane) { - GtkTreeModel *model; - GtkTreeModel *child_model; - GList *lp; + GFile *bookmark_file = NULL, *parent = NULL; + gchar *uri = NULL; + GString *contents = NULL; + struct bookmark *bm_list = NULL, *bm_i = NULL; + GList *lp = NULL; + GError *error = NULL; _thunar_return_if_fail (GTK_IS_ACTION (action)); _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_PANE (shortcuts_pane)); - /* determine the shortcuts model for the view */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (shortcuts_pane->view)); - if (G_LIKELY (model != NULL)) - { - /* add all selected folders to the model */ - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - for (lp = shortcuts_pane->selected_files; lp != NULL; lp = lp->next) - if (G_LIKELY (thunar_file_is_directory (lp->data))) + bookmark_file = thunar_g_file_new_for_bookmarks (); + + thunar_util_load_bookmarks (bookmark_file, store_bookmark, &bm_list); + + /* add all selected folders to the list - unless they are already contained in there */ + /* FIXME: complexity */ + for (lp = shortcuts_pane->selected_files; lp != NULL; lp = lp->next) + if (G_LIKELY (thunar_file_is_directory (lp->data))) + { + uri = thunar_file_dup_uri (lp->data); + + for (bm_i = bm_list; bm_i != NULL; bm_i = bm_i->next) { - /* append the folder to the shortcuts model */ - thunar_shortcuts_model_add (THUNAR_SHORTCUTS_MODEL (child_model), NULL, lp->data); + if (g_file_equal(thunar_file_get_file (lp->data), bm_i->file)) + break; } - /* update the user interface to reflect the new action state */ - lp = thunar_g_file_list_copy (shortcuts_pane->selected_files); - thunar_component_set_selected_files (THUNAR_COMPONENT (shortcuts_pane), lp); - thunar_g_file_list_free (lp); + if (bm_i == NULL) + { + bm_i = g_slice_new0 (struct bookmark); + bm_i->next = bm_list; + bm_i->file = g_object_ref (thunar_file_get_file (lp->data)); + bm_i->name = NULL; + + bm_list = bm_i; + } + } + + /* create the new contents of the file */ + contents = g_string_new (""); + + for (bm_i = bm_list; bm_i != NULL; bm_i = bm_i->next) + { + uri = g_file_get_uri (bm_i->file); + if (!uri) + continue; + + /* Since we built the list in reverse, we will prepend instead of append + * to the string. That way, it evens out. */ + g_string_prepend_c (contents, '\n'); + + if (bm_i->name) + { + g_string_prepend (contents, bm_i->name); + g_string_prepend_c (contents, ' '); + } + + g_string_prepend (contents, uri); + + g_free (uri); } + + /* save the contents back into the file */ + parent = g_file_get_parent (bookmark_file); + if (!g_file_make_directory_with_parents (parent, NULL, &error)) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + g_clear_error (&error); + else + goto out; + } + + if (!g_file_replace_contents (bookmark_file, + contents->str, + contents->len, + NULL, FALSE, 0, NULL, + NULL, &error)) + + /* update the user interface to reflect the new action state */ + lp = thunar_g_file_list_copy (shortcuts_pane->selected_files); + thunar_component_set_selected_files (THUNAR_COMPONENT (shortcuts_pane), lp); + thunar_g_file_list_free (lp); + +out: + if (error) + { + g_critical ("%s", error->message); + g_error_free (error); + } + g_string_free (contents, TRUE); + g_object_unref (parent); + g_object_unref (bookmark_file); + + for (bm_i = bm_list; bm_i != NULL; bm_i = bm_list) + { + g_object_unref (bm_i->file); + g_free (bm_i->name); + + bm_list = bm_i->next; + g_slice_free (struct bookmark, bm_i); + } +} + + + +static void +thunar_shortcuts_pane_poke_location_finish (ThunarBrowser *browser, + GFile *location, + ThunarFile *file, + ThunarFile *target_file, + GError *error, + gpointer user_data) +{ + gchar *name; + GtkPlacesOpenFlags open_in; + ThunarApplication *application; + + _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_PANE (browser)); + _thunar_return_if_fail (G_IS_FILE (location)); + + open_in = (GtkPlacesOpenFlags)GPOINTER_TO_INT (user_data); + + /* sotre the new file in the shortcuts model */ + if (error == NULL) + { + if (open_in == GTK_PLACES_OPEN_NEW_WINDOW) + { + /* open a new window for the target folder */ + application = thunar_application_get (); + thunar_application_open_window (application, target_file, + gtk_widget_get_screen (GTK_WIDGET (browser)), NULL); + g_object_unref (application); + } + else if (open_in == GTK_PLACES_OPEN_NEW_TAB) + { + thunar_navigator_open_new_tab (THUNAR_NAVIGATOR (browser), target_file); + } + else if (thunar_file_check_loaded (target_file)) + { + thunar_navigator_change_directory (THUNAR_NAVIGATOR (browser), target_file); + } + else + { + g_warning ("WTF: File to be activated but not loaded!"); + } + } + else + { + name = thunar_g_file_get_display_name_remote (location); + thunar_dialogs_show_error (GTK_WIDGET (browser), error, _("Failed to open \"%s\""), name); + g_free (name); + } +} + + + +static void +thunar_shortcuts_pane_open_location (GtkPlacesSidebar *sidebar, + GFile *location, + GtkPlacesOpenFlags flags, + ThunarShortcutsPane *shortcuts_pane) +{ + thunar_browser_poke_location (THUNAR_BROWSER (shortcuts_pane), location, + GTK_WIDGET (shortcuts_pane), + thunar_shortcuts_pane_poke_location_finish, + GINT_TO_POINTER (flags)); +} + + + +static gint thunar_shortcuts_pane_drag_action_requested (GtkPlacesSidebar *sidebar, + GdkDragContext *context, + GFile *dest_file, + GList *source_file_list, + ThunarShortcutsPane *shortcuts_pane) +{ + ThunarFile *th_dest_file; + GdkDragAction suggested_action; + + /* create ThunarFile* instances for the given file */ + th_dest_file = thunar_file_get (dest_file, NULL); + + _thunar_return_val_if_fail (th_dest_file != NULL, 0); + + /* check for allowed drop actions */ + thunar_file_accepts_drop (th_dest_file, source_file_list, context, &suggested_action); + + /* cleanup */ + g_object_unref (th_dest_file); + + return suggested_action; +} + + + +void thunar_shortcuts_pane_drag_perform_drop (GtkPlacesSidebar *sidebar, + GFile *dest_file, + GList *source_file_list, + GdkDragAction action, + ThunarShortcutsPane *shortcuts_pane) +{ + ThunarFile *th_dest_file; + + if (G_UNLIKELY ((action & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK)) == 0)) + return; + + /* get the thunar file */ + th_dest_file = thunar_file_get (dest_file, NULL); + + _thunar_return_if_fail (th_dest_file != NULL); + + /* perform the drop */ + thunar_dnd_perform (GTK_WIDGET (shortcuts_pane), th_dest_file, source_file_list, action, NULL); + + /* cleanup */ + g_object_unref (th_dest_file); +} + +static void drag_ask_menu_copy_activated (GtkMenuItem *menuitem, + GdkDragAction *out_action) +{ + *out_action = GDK_ACTION_COPY; +} +static void drag_ask_menu_link_activated (GtkMenuItem *menuitem, + GdkDragAction *out_action) +{ + *out_action = GDK_ACTION_LINK; +} +static void drag_ask_menu_move_activated (GtkMenuItem *menuitem, + GdkDragAction *out_action) +{ + *out_action = GDK_ACTION_MOVE; +} + +static gint thunar_shortcuts_pane_drag_action_ask (GtkPlacesSidebar *sidebar, + GdkDragAction actions, + ThunarShortcutsPane *shortcuts_pane) +{ + GtkWidget *menu, *item; + GdkDragAction chosen_action = 0; + + /* prepare the popup menu */ + menu = gtk_menu_new (); + + /* append copy */ + if (actions & GDK_ACTION_COPY) + { + item = gtk_menu_item_new_with_mnemonic (_ ("_Copy here")); + g_signal_connect (item, "activate", G_CALLBACK (drag_ask_menu_copy_activated), &chosen_action); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + } + if (actions & GDK_ACTION_MOVE) + { + item = gtk_menu_item_new_with_mnemonic (_ ("_Move here")); + g_signal_connect (item, "activate", G_CALLBACK (drag_ask_menu_move_activated), &chosen_action); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + } + if (actions & GDK_ACTION_LINK) + { + item = gtk_menu_item_new_with_mnemonic (_ ("_Link here")); + g_signal_connect (item, "activate", G_CALLBACK (drag_ask_menu_link_activated), &chosen_action); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + } + + /* append the separator */ + item = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + + /* append the cancel item */ + item = gtk_menu_item_new_with_mnemonic (_ ("_Cancel")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + /* run the menu on the widget's screen (takes over the floating reference of menu) */ + thunar_gtk_menu_run (GTK_MENU (menu), sidebar, NULL, NULL, 3, 0); + + return chosen_action; } diff --git a/thunar/thunar-shortcuts-view.c b/thunar/thunar-shortcuts-view.c deleted file mode 100644 index 4119cae1953513043f629f08eb6301b0f314b465..0000000000000000000000000000000000000000 --- a/thunar/thunar-shortcuts-view.c +++ /dev/null @@ -1,2139 +0,0 @@ -/* vi:set et ai sw=2 sts=2 ts=2: */ -/*- - * Copyright (c) 2005-2007 Benedikt Meurer <benny@xfce.org> - * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org> - * Copyright (c) 2012 Nick Schermer <nick@xfce.org> - * - * This program 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. - * - * This program 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef HAVE_MEMORY_H -#include <memory.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#include <gdk/gdkkeysyms.h> - -#include <thunar/thunar-application.h> -#include <thunar/thunar-browser.h> -#include <thunar/thunar-dialogs.h> -#include <thunar/thunar-dnd.h> -#include <thunar/thunar-gio-extensions.h> -#include <thunar/thunar-gtk-extensions.h> -#include <thunar/thunar-preferences.h> -#include <thunar/thunar-private.h> -#include <thunar/thunar-shortcuts-icon-renderer.h> -#include <thunar/thunar-shortcuts-model.h> -#include <thunar/thunar-shortcuts-view.h> -#include <thunar/thunar-device-monitor.h> -#include <thunar/thunar-stock.h> - - - -/* Identifiers for signals */ -enum -{ - SHORTCUT_ACTIVATED, - SHORTCUT_ACTIVATED_TAB, - LAST_SIGNAL, -}; - -/* Identifiers for DnD target types */ -enum -{ - GTK_TREE_MODEL_ROW, - TEXT_URI_LIST, -}; - -/* Target for open action */ -typedef enum -{ - OPEN_IN_VIEW, - OPEN_IN_WINDOW, - OPEN_IN_TAB -} -OpenTarget; - - - -static void thunar_shortcuts_view_finalize (GObject *object); -static gboolean thunar_shortcuts_view_button_press_event (GtkWidget *widget, - GdkEventButton *event); -static gboolean thunar_shortcuts_view_button_release_event (GtkWidget *widget, - GdkEventButton *event); -static gboolean thunar_shortcuts_view_key_release_event (GtkWidget *widget, - GdkEventKey *event); -static void thunar_shortcuts_view_drag_begin (GtkWidget *widget, - GdkDragContext *context); -static void thunar_shortcuts_view_drag_data_received (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection_data, - guint info, - guint timestamp); -static gboolean thunar_shortcuts_view_drag_drop (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint timestamp); -static gboolean thunar_shortcuts_view_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint timestamp); -static void thunar_shortcuts_view_drag_leave (GtkWidget *widget, - GdkDragContext *context, - guint timestamp); -static gboolean thunar_shortcuts_view_popup_menu (GtkWidget *widget); -static void thunar_shortcuts_view_row_activated (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column); -static gboolean thunar_shortcuts_view_selection_func (GtkTreeSelection *selection, - GtkTreeModel *model, - GtkTreePath *path, - gboolean path_currently_selected, - gpointer user_data); -static void thunar_shortcuts_view_context_menu_visibility (ThunarShortcutsView *view, - GdkEventButton *event, - GtkTreeModel *model); -static void thunar_shortcuts_view_context_menu (ThunarShortcutsView *view, - GdkEventButton *event, - GtkTreeModel *model, - GtkTreeIter *iter); -static void thunar_shortcuts_view_remove_activated (GtkWidget *item, - GtkTreeModel *model); -static void thunar_shortcuts_view_editing_canceled (GtkCellRenderer *renderer, - ThunarShortcutsView *view); -static void thunar_shortcuts_view_rename_activated (GtkWidget *item, - ThunarShortcutsView *view); -static void thunar_shortcuts_view_renamed (GtkCellRenderer *renderer, - const gchar *path_string, - const gchar *text, - ThunarShortcutsView *view); -static GdkDragAction thunar_shortcuts_view_compute_drop_actions (ThunarShortcutsView *view, - GdkDragContext *context, - gint x, - gint y, - GtkTreePath **path_return, - GdkDragAction *action_return, - GtkTreeViewDropPosition *position_return); -static GtkTreePath *thunar_shortcuts_view_compute_drop_position (ThunarShortcutsView *view, - gint x, - gint y); -static void thunar_shortcuts_view_drop_uri_list (ThunarShortcutsView *view, - GList *path_list, - GtkTreePath *dst_path); -static void thunar_shortcuts_view_open_clicked (ThunarShortcutsView *view); -static void thunar_shortcuts_view_open (ThunarShortcutsView *view, - OpenTarget open_in); -static void thunar_shortcuts_view_open_in_new_window_clicked (ThunarShortcutsView *view); -static void thunar_shortcuts_view_open_in_new_tab_clicked (ThunarShortcutsView *view); -static void thunar_shortcuts_view_empty_trash (ThunarShortcutsView *view); -static void thunar_shortcuts_view_create_shortcut (ThunarShortcutsView *view); -static void thunar_shortcuts_view_eject (ThunarShortcutsView *view); -static void thunar_shortcuts_view_mount (ThunarShortcutsView *view); -static void thunar_shortcuts_view_unmount (ThunarShortcutsView *view); - - - -struct _ThunarShortcutsViewClass -{ - GtkTreeViewClass __parent__; -}; - -struct _ThunarShortcutsView -{ - GtkTreeView __parent__; - - - ThunarPreferences *preferences; - GtkCellRenderer *icon_renderer; - - ThunarxProviderFactory *provider_factory; - - /* the currently pressed mouse button, set in the - * button-press-event handler if the associated - * button-release-event should activate. - */ - gint pressed_button; - guint pressed_eject_button : 1; - - /* drop site support */ - guint drop_data_ready : 1; /* whether the drop data was received already */ - guint drop_occurred : 1; - GList *drop_file_list; /* the list of URIs that are contained in the drop data */ - - /* id of the signal used to queue a resize on the - * column whenever the shortcuts icon size is changed. - */ - gulong queue_resize_signal_id; -}; - - - -/* Target types for dragging from the shortcuts view */ -static const GtkTargetEntry drag_targets[] = { - { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }, -}; - -/* Target types for dropping into the shortcuts view */ -static const GtkTargetEntry drop_targets[] = { - { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }, - { "text/uri-list", 0, TEXT_URI_LIST }, -}; - - - -static guint view_signals[LAST_SIGNAL]; - - - -G_DEFINE_TYPE_WITH_CODE (ThunarShortcutsView, thunar_shortcuts_view, GTK_TYPE_TREE_VIEW, - G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER, NULL)) - - - -static void -thunar_shortcuts_view_class_init (ThunarShortcutsViewClass *klass) -{ - GtkTreeViewClass *gtktree_view_class; - GtkWidgetClass *gtkwidget_class; - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = thunar_shortcuts_view_finalize; - - gtkwidget_class = GTK_WIDGET_CLASS (klass); - gtkwidget_class->button_press_event = thunar_shortcuts_view_button_press_event; - gtkwidget_class->button_release_event = thunar_shortcuts_view_button_release_event; - gtkwidget_class->key_release_event = thunar_shortcuts_view_key_release_event; - gtkwidget_class->drag_begin = thunar_shortcuts_view_drag_begin; - gtkwidget_class->drag_data_received = thunar_shortcuts_view_drag_data_received; - gtkwidget_class->drag_drop = thunar_shortcuts_view_drag_drop; - gtkwidget_class->drag_motion = thunar_shortcuts_view_drag_motion; - gtkwidget_class->drag_leave = thunar_shortcuts_view_drag_leave; - gtkwidget_class->popup_menu = thunar_shortcuts_view_popup_menu; - - gtktree_view_class = GTK_TREE_VIEW_CLASS (klass); - gtktree_view_class->row_activated = thunar_shortcuts_view_row_activated; - - /** - * ThunarShortcutsView:shortcut-activated: - * - * Invoked whenever a shortcut is activated by the user. - **/ - view_signals[SHORTCUT_ACTIVATED] = - g_signal_new (I_("shortcut-activated"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, THUNAR_TYPE_FILE); - - /** - * ThunarShortcutsView:shortcut-activated-tab: - * - * Invoked whenever a shortcut is activated by the user and should be opened in a new tab, - **/ - view_signals[SHORTCUT_ACTIVATED_TAB] = - g_signal_new (I_("shortcut-activated-tab"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, THUNAR_TYPE_FILE); -} - - - -static void -thunar_shortcuts_view_init (ThunarShortcutsView *view) -{ - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - GtkTreeSelection *selection; - - /* configure the tree view */ - gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); - gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (view), THUNAR_SHORTCUTS_MODEL_COLUMN_TOOLTIP); - - /* grab a reference on the provider factory */ - view->provider_factory = thunarx_provider_factory_get_default (); - - /* grab a reference on the preferences; be sure to redraw the view - * whenever the "shortcuts-icon-emblems" preference changes. - */ - view->preferences = thunar_preferences_get (); - g_signal_connect_swapped (G_OBJECT (view->preferences), "notify::shortcuts-icon-emblems", G_CALLBACK (gtk_widget_queue_draw), view); - - /* allocate a single column for our renderers */ - column = g_object_new (GTK_TYPE_TREE_VIEW_COLUMN, - "reorderable", FALSE, - "resizable", FALSE, - "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, - "spacing", 2, - NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); - - /* queue a resize on the column whenever the icon size is changed */ - view->queue_resize_signal_id = g_signal_connect_swapped (G_OBJECT (view->preferences), "notify::shortcuts-icon-size", - G_CALLBACK (gtk_tree_view_column_queue_resize), column); - - /* header */ - renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, - "weight", PANGO_WEIGHT_BOLD, - "xpad", 6, - "ypad", 6, - NULL); - gtk_tree_view_column_pack_start (column, renderer, FALSE); - gtk_tree_view_column_set_attributes (column, renderer, - "text", THUNAR_SHORTCUTS_MODEL_COLUMN_NAME, - "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_IS_HEADER, - NULL); - - /* separator for indent */ - renderer = gtk_cell_renderer_text_new (); - g_object_set (G_OBJECT (renderer), "xpad", 6, NULL); - gtk_tree_view_column_pack_start (column, renderer, FALSE); - gtk_tree_view_column_set_attributes (column, renderer, - "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_IS_ITEM, - NULL); - - /* allocate the special icon renderer */ - view->icon_renderer = thunar_shortcuts_icon_renderer_new (); - gtk_tree_view_column_pack_start (column, view->icon_renderer, FALSE); - gtk_tree_view_column_set_attributes (column, view->icon_renderer, - "gicon", THUNAR_SHORTCUTS_MODEL_COLUMN_GICON, - "file", THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, - "device", THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, - "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_IS_ITEM, - NULL); - - /* sync the "emblems" property of the icon renderer with the "shortcuts-icon-emblems" preference - * and the "size" property of the renderer with the "shortcuts-icon-size" preference. - */ - exo_binding_new (G_OBJECT (view->preferences), "shortcuts-icon-size", G_OBJECT (view->icon_renderer), "size"); - exo_binding_new (G_OBJECT (view->preferences), "shortcuts-icon-emblems", G_OBJECT (view->icon_renderer), "emblems"); - - /* allocate the text renderer (ellipsizing as required, but "File System" must fit) */ - renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, - "ellipsize", PANGO_ELLIPSIZE_END, - NULL); - g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (thunar_shortcuts_view_renamed), view); - gtk_tree_view_column_pack_start (column, renderer, TRUE); - gtk_tree_view_column_set_attributes (column, renderer, - "text", THUNAR_SHORTCUTS_MODEL_COLUMN_NAME, - "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_IS_ITEM, - NULL); - - /* spinner to indicate (un)mount/eject delay */ - renderer = gtk_cell_renderer_spinner_new (); - gtk_tree_view_column_pack_start (column, renderer, FALSE); - gtk_tree_view_column_set_attributes (column, renderer, - "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY, - "active", THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY, - "pulse", THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY_PULSE, - NULL); - - /* allocate icon renderer for the eject symbol */ - renderer = gtk_cell_renderer_pixbuf_new (); - g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, "icon-name", "media-eject", NULL); - gtk_tree_view_column_pack_start (column, renderer, FALSE); - gtk_tree_view_column_set_attributes (column, renderer, - "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_CAN_EJECT, - NULL); - - /* enable drag support for the shortcuts view (actually used to support reordering) */ - gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (view), GDK_BUTTON1_MASK, drag_targets, - G_N_ELEMENTS (drag_targets), GDK_ACTION_MOVE); - - /* enable drop support for the shortcuts view (both internal reordering - * and adding new shortcuts from other widgets) - */ - gtk_drag_dest_set (GTK_WIDGET (view), 0, drop_targets, G_N_ELEMENTS (drop_targets), - GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_MOVE); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - gtk_tree_selection_set_select_function (selection, thunar_shortcuts_view_selection_func, NULL, NULL); -} - - - -static void -thunar_shortcuts_view_finalize (GObject *object) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (object); - - /* release drop path list (if drag_leave wasn't called) */ - thunar_g_file_list_free (view->drop_file_list); - - /* release the provider factory */ - g_object_unref (G_OBJECT (view->provider_factory)); - - /* disconnect the queue resize signal handler */ - g_signal_handler_disconnect (G_OBJECT (view->preferences), view->queue_resize_signal_id); - - /* disconnect from the preferences object */ - g_signal_handlers_disconnect_matched (G_OBJECT (view->preferences), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view); - g_object_unref (G_OBJECT (view->preferences)); - - (*G_OBJECT_CLASS (thunar_shortcuts_view_parent_class)->finalize) (object); -} - - - -static gboolean -thunar_shortcuts_view_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - gboolean result; - gboolean can_eject; - gint icon_width, icon_height, column_width; - - /* reset the pressed button state */ - view->pressed_button = -1; - view->pressed_eject_button = 0; - - /* completely ignore double click events */ - if (event->type == GDK_2BUTTON_PRESS) - return TRUE; - - /* let the widget process the event first (handles focussing and scrolling) */ - result = (*GTK_WIDGET_CLASS (thunar_shortcuts_view_parent_class)->button_press_event) (widget, event); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - - /* resolve the path at the cursor position */ - if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), event->x, event->y, &path, NULL, NULL, NULL)) - { - /* check if we should popup the context menu */ - if (G_UNLIKELY (event->button == 3)) - { - /* determine the iterator for the path */ - if (gtk_tree_model_get_iter (model, &iter, path)) - { - /* popup the context menu */ - thunar_shortcuts_view_context_menu (view, event, model, &iter); - - /* we effectively handled the event */ - result = TRUE; - } - } - else if (event->button == 1 || event->button == 2) - { - /* check if we clicked the eject button area */ - column_width = gtk_tree_view_column_get_width (gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0)); - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height); - if (event->button == 1 && event->x >= column_width - icon_width - 3) - { - /* check if that shortcut actually has an eject button */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - if (gtk_tree_model_get_iter (model, &iter, path)) - { - gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_CAN_EJECT, &can_eject, -1); - if (can_eject) - view->pressed_eject_button = 1; - } - } - else - gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0), FALSE); - - /* remember the button as pressed and handle it in the release handler */ - view->pressed_button = event->button; - } - - /* release the path */ - gtk_tree_path_free (path); - } - else if (event->button == 3) - { - thunar_shortcuts_view_context_menu_visibility (view, event, model); - result = TRUE; - } - - return result; -} - - - -static gboolean -thunar_shortcuts_view_button_release_event (GtkWidget *widget, - GdkEventButton *event) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - gboolean in_tab; - - /* check if we have an event matching the pressed button state */ - if (G_LIKELY (view->pressed_button == (gint) event->button)) - { - /* check if the eject button has been pressed */ - if (view->pressed_eject_button) - { - thunar_shortcuts_view_eject (view); - } - else if (G_LIKELY (event->button == 1)) - { - /* button 1 opens in the same window */ - thunar_shortcuts_view_open (view, OPEN_IN_VIEW); - } - else if (G_UNLIKELY (event->button == 2)) - { - /* button 2 opens in a new window or tab */ - g_object_get (view->preferences, "misc-middle-click-in-tab", &in_tab, NULL); - - /* holding ctrl inverts the action */ - if ((event->state & GDK_CONTROL_MASK) != 0) - in_tab = !in_tab; - - thunar_shortcuts_view_open (view, in_tab ? OPEN_IN_TAB : OPEN_IN_WINDOW); - } - } - - /* reset the pressed button state */ - view->pressed_button = -1; - view->pressed_eject_button = 0; - - /* call the parent's release event handler */ - return (*GTK_WIDGET_CLASS (thunar_shortcuts_view_parent_class)->button_release_event) (widget, event); -} - - - -static gboolean -thunar_shortcuts_view_key_release_event (GtkWidget *widget, - GdkEventKey *event) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - - /* work nicer with keyboard navigation */ - switch (event->keyval) - { - case GDK_KEY_Up: - case GDK_KEY_Down: - case GDK_KEY_KP_Up: - case GDK_KEY_KP_Down: - thunar_shortcuts_view_open (view, OPEN_IN_VIEW); - - /* keep focus on us */ - gtk_widget_grab_focus (widget); - break; - } - - /* call the parent's release event handler */ - return (*GTK_WIDGET_CLASS (thunar_shortcuts_view_parent_class)->key_release_event) (widget, event); -} - - - -static void -thunar_shortcuts_view_drag_begin (GtkWidget *widget, - GdkDragContext *context) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - - /* reset the pressed button state */ - view->pressed_button = -1; - - /* call the parent's drag_begin() handler */ - if (GTK_WIDGET_CLASS (thunar_shortcuts_view_parent_class)->drag_begin != NULL) - (*GTK_WIDGET_CLASS (thunar_shortcuts_view_parent_class)->drag_begin) (widget, context); -} - - - -static void -thunar_shortcuts_view_drag_data_received (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection_data, - guint info, - guint timestamp) -{ - GtkTreeViewDropPosition position = GTK_TREE_VIEW_DROP_BEFORE; - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - GdkDragAction actions; - GdkDragAction action; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - ThunarFile *file; - gboolean succeed = FALSE; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* check if we don't already know the drop data */ - if (G_LIKELY (!view->drop_data_ready)) - { - /* extract the URI list from the selection data (if valid) */ - if (info == TEXT_URI_LIST && gtk_selection_data_get_format (selection_data) == 8 && gtk_selection_data_get_length (selection_data) > 0) - view->drop_file_list = thunar_g_file_list_new_from_string ((const gchar *) gtk_selection_data_get_data (selection_data)); - - /* reset the state */ - view->drop_data_ready = TRUE; - } - - /* check if the data was droppped */ - if (G_UNLIKELY (view->drop_occurred)) - { - /* reset the state */ - view->drop_occurred = FALSE; - - /* verify that we only handle text/uri-list here */ - if (G_LIKELY (info == TEXT_URI_LIST)) - { - /* determine the drop actions */ - actions = thunar_shortcuts_view_compute_drop_actions (view, context, x, y, &path, &action, &position); - if (G_LIKELY (actions != 0)) - { - /* check if we should add a shortcut */ - if (position == GTK_TREE_VIEW_DROP_BEFORE || position == GTK_TREE_VIEW_DROP_AFTER) - { - /* if position is "after", we need to advance the path, - * as the drop_uri_list() will insert "at" the path. - */ - if (position == GTK_TREE_VIEW_DROP_AFTER) - gtk_tree_path_next (path); - - /* just add the required shortcuts then */ - thunar_shortcuts_view_drop_uri_list (view, view->drop_file_list, path); - } - else if (G_LIKELY ((actions & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK)) != 0)) - { - /* get the shortcuts model */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - - /* determine the iterator for the path */ - if (gtk_tree_model_get_iter (model, &iter, path)) - { - /* determine the file for the iter */ - gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, &file, -1); - if (G_LIKELY (file != NULL)) - { - /* ask the user what to do with the drop data */ - if (G_UNLIKELY (action == GDK_ACTION_ASK)) - action = thunar_dnd_ask (widget, file, view->drop_file_list, timestamp, actions); - - /* perform the requested action */ - if (G_LIKELY (action != 0)) - { - /* really perform the drop :-) */ - succeed = thunar_dnd_perform (widget, file, view->drop_file_list, action, NULL); - } - - /* release the file */ - g_object_unref (G_OBJECT (file)); - } - } - } - - /* release the tree path */ - gtk_tree_path_free (path); - } - } - - /* disable the drop highlighting */ - thunar_shortcuts_view_drag_leave (widget, context, timestamp); - - /* tell the peer that we handled the drop */ - gtk_drag_finish (context, succeed, FALSE, timestamp); - } - else - { - gdk_drag_status (context, 0, timestamp); - } -} - - - -static gboolean -thunar_shortcuts_view_drag_drop (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint timestamp) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreePath *dst_path; - GtkTreePath *src_path; - GtkTreeIter iter; - GdkAtom target; - GtkTreeModel *child_model; - GtkTreePath *child_dst_path; - GtkTreePath *child_src_path; - - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view), FALSE); - - /* determine the drop target */ - target = gtk_drag_dest_find_target (widget, context, NULL); - if (G_LIKELY (target == gdk_atom_intern_static_string ("text/uri-list"))) - { - /* set state so the drag-data-received handler - * knows that this is really a drop this time. - */ - view->drop_occurred = TRUE; - - /* request the drag data from the source. */ - gtk_drag_get_data (widget, context, target, timestamp); - } - else if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW")) - { - /* compute the drop position */ - dst_path = thunar_shortcuts_view_compute_drop_position (view, x, y); - - /* determine the source path */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - /* get the source path */ - src_path = gtk_tree_model_get_path (model, &iter); - - /* if we drop downwards, correct the drop destination */ - if (gtk_tree_path_compare (src_path, dst_path) < 0) - gtk_tree_path_prev (dst_path); - - /* convert iters */ - src_path = gtk_tree_model_get_path (model, &iter); - child_src_path = gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (model), src_path); - child_dst_path = gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (model), dst_path); - gtk_tree_path_free (src_path); - - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - - /* perform the move */ - thunar_shortcuts_model_move (THUNAR_SHORTCUTS_MODEL (child_model), child_src_path, child_dst_path); - - gtk_tree_path_free (child_src_path); - gtk_tree_path_free (child_dst_path); - - /* make sure the new position is selectde */ - gtk_tree_selection_select_path (selection, dst_path); - } - - /* release the dst path */ - gtk_tree_path_free (dst_path); - - /* finish the dnd operation */ - gtk_drag_finish (context, TRUE, FALSE, timestamp); - } - else - { - /* we cannot handle the drop */ - return FALSE; - } - - return TRUE; -} - - - -static gboolean -thunar_shortcuts_view_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint timestamp) -{ - GtkTreeViewDropPosition position = GTK_TREE_VIEW_DROP_BEFORE; - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - GdkDragAction action = 0; - GtkTreeModel *model; - GtkTreePath *path = NULL; - GdkAtom target; - - /* reset the "drop-file" of the icon renderer */ - g_object_set (G_OBJECT (view->icon_renderer), "drop-file", NULL, NULL); - - /* determine the drag target */ - target = gtk_drag_dest_find_target (widget, context, NULL); - if (target == gdk_atom_intern_static_string ("text/uri-list")) - { - /* request the drop data on-demand (if we don't have it already) */ - if (G_UNLIKELY (!view->drop_data_ready)) - { - /* request the drag data from the source */ - gtk_drag_get_data (widget, context, target, timestamp); - - /* gdk_drag_status() will be called by drag_data_received */ - return TRUE; - } - else - { - /* compute the drop position */ - thunar_shortcuts_view_compute_drop_actions (view, context, x, y, &path, &action, &position); - } - } - else if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW")) - { - /* check the action that should be performed */ - if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_LINK || (gdk_drag_context_get_actions (context) & GDK_ACTION_LINK) != 0) - action = GDK_ACTION_LINK; - else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_COPY || (gdk_drag_context_get_actions (context) & GDK_ACTION_COPY) != 0) - action = GDK_ACTION_COPY; - else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_MOVE || (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0) - action = GDK_ACTION_MOVE; - else - return FALSE; - - /* compute the drop position for the coordinates */ - path = thunar_shortcuts_view_compute_drop_position (view, x, y); - if (path == NULL) - return FALSE; - - /* check if path is about to append to the model */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - if (gtk_tree_path_get_indices (path)[0] >= gtk_tree_model_iter_n_children (model, NULL)) - { - /* set the position to "after" and move the path to - * point to the previous row instead; required to - * get the highlighting in GtkTreeView correct. - */ - position = GTK_TREE_VIEW_DROP_AFTER; - gtk_tree_path_prev (path); - } - } - else - { - /* we cannot handle the drop */ - return FALSE; - } - - /* check if we have a drop path */ - if (G_LIKELY (path != NULL)) - { - /* highlight the appropriate row */ - gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), path, position); - gtk_tree_path_free (path); - } - - /* tell Gdk whether we can drop here */ - gdk_drag_status (context, action, timestamp); - - return TRUE; -} - - - -static void -thunar_shortcuts_view_drag_leave (GtkWidget *widget, - GdkDragContext *context, - guint timestamp) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - - /* reset the "drop-file" of the icon renderer */ - g_object_set (G_OBJECT (view->icon_renderer), "drop-file", NULL, NULL); - - /* reset the "drop data ready" status and free the URI list */ - if (G_LIKELY (view->drop_data_ready)) - { - thunar_g_file_list_free (view->drop_file_list); - view->drop_data_ready = FALSE; - view->drop_file_list = NULL; - } - - /* schedule a repaint to make sure the special drop icon for the target row - * is reset to its default (http://bugzilla.xfce.org/show_bug.cgi?id=2498). - */ - gtk_widget_queue_draw (widget); - - /* call the parent's handler */ - (*GTK_WIDGET_CLASS (thunar_shortcuts_view_parent_class)->drag_leave) (widget, context, timestamp); -} - - - -static gboolean -thunar_shortcuts_view_popup_menu (GtkWidget *widget) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget); - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - - /* determine the selection for the tree view */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - - /* determine the selected row */ - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - /* popup the context menu */ - thunar_shortcuts_view_context_menu (view, NULL, model, &iter); - return TRUE; - } - else if (GTK_WIDGET_CLASS (thunar_shortcuts_view_parent_class)->popup_menu != NULL) - { - /* call the parent's "popup-menu" handler */ - return (*GTK_WIDGET_CLASS (thunar_shortcuts_view_parent_class)->popup_menu) (widget); - } - - return FALSE; -} - - - -static void -thunar_shortcuts_view_row_activated (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (tree_view); - - /* call the parent's "row-activated" handler */ - if (GTK_TREE_VIEW_CLASS (thunar_shortcuts_view_parent_class)->row_activated != NULL) - (*GTK_TREE_VIEW_CLASS (thunar_shortcuts_view_parent_class)->row_activated) (tree_view, path, column); - - /* open the selected shortcut */ - thunar_shortcuts_view_open (view, OPEN_IN_VIEW); -} - - - -static gboolean -thunar_shortcuts_view_selection_func (GtkTreeSelection *selection, - GtkTreeModel *model, - GtkTreePath *path, - gboolean path_currently_selected, - gpointer user_data) -{ - GtkTreeIter iter; - gboolean is_header; - - /* don't allow selecting headers */ - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_IS_HEADER, &is_header, -1); - return !is_header; -} - - - -static void -thunar_shortcuts_view_context_menu_visibility_toggled (GtkCheckMenuItem *item, - GtkTreeModel *model) -{ - gboolean hidden; - GtkTreePath *path; - GtkTreeRowReference *row; - - _thunar_return_if_fail (GTK_IS_CHECK_MENU_ITEM (item)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model)); - - row = g_object_get_data (G_OBJECT (item), I_("thunar-shortcuts-row")); - path = gtk_tree_row_reference_get_path (row); - if (G_LIKELY (path != NULL)) - { - hidden = !gtk_check_menu_item_get_active (item); - thunar_shortcuts_model_set_hidden (THUNAR_SHORTCUTS_MODEL (model), path, hidden); - gtk_tree_path_free (path); - } -} - - - -static void -thunar_shortcuts_view_context_menu_visibility (ThunarShortcutsView *view, - GdkEventButton *event, - GtkTreeModel *model) -{ - GtkTreeIter iter; - guint mask = 0; - ThunarShortcutGroup group; - GtkWidget *menu; - GtkWidget *mi; - gchar *label; - GtkTreeSelection *selection; - gboolean visible; - GtkTreePath *path; - GtkTreeModel *child_model; - GtkWidget *submenu; - - /* unselect the items */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - gtk_tree_selection_unselect_all (GTK_TREE_SELECTION (selection)); - - /* prepare the popup menu */ - menu = submenu = gtk_menu_new (); - - /* process all items below the header */ - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (child_model), &iter)) - return; - path = gtk_tree_model_get_path (child_model, &iter); - do - { - /* get all the info */ - gtk_tree_model_get (GTK_TREE_MODEL (child_model), &iter, - THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP, &group, - THUNAR_SHORTCUTS_MODEL_COLUMN_NAME, &label, - THUNAR_SHORTCUTS_MODEL_COLUMN_VISIBLE, &visible, - -1); - - if ((group & THUNAR_SHORTCUT_GROUP_HEADER) != 0) - { - /* get the mask of the group */ - if ((group & THUNAR_SHORTCUT_GROUP_DEVICES) != 0) - mask = THUNAR_SHORTCUT_GROUP_DEVICES; - else if ((group & THUNAR_SHORTCUT_GROUP_PLACES) != 0) - mask = THUNAR_SHORTCUT_GROUP_PLACES; - else if ((group & THUNAR_SHORTCUT_GROUP_NETWORK) != 0) - mask = THUNAR_SHORTCUT_GROUP_NETWORK; - else - _thunar_assert_not_reached (); - - /* create menu items */ - mi = gtk_menu_item_new_with_label (label); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); - gtk_widget_show (mi); - - submenu = gtk_menu_new (); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu); - } - else if ((group & mask) != 0) - { - mi = gtk_check_menu_item_new_with_label (label); - gtk_menu_shell_append (GTK_MENU_SHELL (submenu), mi); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), visible); - g_object_set_data_full (G_OBJECT (mi), I_("thunar-shortcuts-row"), - gtk_tree_row_reference_new (child_model, path), - (GDestroyNotify) gtk_tree_row_reference_free); - g_signal_connect (G_OBJECT (mi), "toggled", - G_CALLBACK (thunar_shortcuts_view_context_menu_visibility_toggled), child_model); - gtk_widget_show (mi); - } - - g_free (label); - gtk_tree_path_next (path); - } - while (gtk_tree_model_iter_next (child_model, &iter)); - - gtk_tree_path_free (path); - - /* run the menu on the view's screen (taking over the floating reference on menu) */ - thunar_gtk_menu_run (GTK_MENU (menu), GTK_WIDGET (view), NULL, NULL, - (event != NULL) ? event->button : 0, - (event != NULL) ? event->time : gtk_get_current_event_time ()); -} - - - -static void -thunar_shortcuts_view_context_menu (ThunarShortcutsView *view, - GdkEventButton *event, - GtkTreeModel *model, - GtkTreeIter *iter) -{ - GtkTreePath *path; - ThunarFile *file; - GtkWidget *image; - GtkWidget *menu; - GtkWidget *item; - GtkWidget *window; - gboolean mutable; - ThunarDevice *device; - GList *providers, *lp; - GList *actions = NULL, *tmp; - ThunarShortcutGroup group; - gboolean is_header; - GFile *mount_point; - GtkTreeModel *shortcuts_model; - gboolean can_mount; - gboolean can_unmount; - gboolean can_eject; - - /* check if this is an item menu or a header menu */ - gtk_tree_model_get (model, iter, THUNAR_SHORTCUTS_MODEL_COLUMN_IS_HEADER, &is_header, -1); - if (is_header) - { - thunar_shortcuts_view_context_menu_visibility (view, event, model); - return; - } - - /* determine the tree path for the given iter */ - path = gtk_tree_model_get_path (model, iter); - if (G_UNLIKELY (path == NULL)) - return; - - /* check whether the shortcut at the given path is mutable */ - gtk_tree_model_get (model, iter, - THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, &file, - THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, - THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE, &mutable, - THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP, &group, - -1); - - /* prepare the popup menu */ - menu = gtk_menu_new (); - - /* append the "Open" menu action */ - item = gtk_image_menu_item_new_with_mnemonic (_("_Open")); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_open_clicked), view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* set the stock icon */ - image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - - /* append the "Open in New Tab" menu action */ - item = gtk_image_menu_item_new_with_mnemonic (_("Open in New Tab")); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_open_in_new_tab_clicked), view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* append the "Open in New Window" menu action */ - item = gtk_image_menu_item_new_with_mnemonic (_("Open in New Window")); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_open_in_new_window_clicked), view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - switch (group) - { - case THUNAR_SHORTCUT_GROUP_DEVICES_VOLUMES: - can_mount = thunar_device_can_mount (device); - can_unmount = thunar_device_can_unmount (device); - can_eject = thunar_device_can_eject (device); - - if (!can_mount && !can_unmount && !can_eject) - break; - - /* append a menu separator */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* append the "Mount" item */ - item = gtk_image_menu_item_new_with_mnemonic (_("_Mount")); - gtk_widget_set_visible (item, can_mount); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_mount), view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - /* append the "Unmount" item */ - item = gtk_image_menu_item_new_with_mnemonic (_("_Unmount")); - gtk_widget_set_visible (item, can_unmount); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_unmount), view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - /* append the "Disconnect" (eject + safely remove drive) item */ - item = gtk_image_menu_item_new_with_mnemonic (_("_Eject")); - gtk_widget_set_visible (item, can_eject); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_eject), view); - break; - - case THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS: - /* append a menu separator */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* get the mount point */ - mount_point = thunar_device_get_root (device); - shortcuts_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - - /* append the "Disconnect" item */ - item = gtk_image_menu_item_new_with_mnemonic (_("Create _Shortcut")); - gtk_widget_set_sensitive (item, mount_point != NULL && !thunar_shortcuts_model_has_bookmark (THUNAR_SHORTCUTS_MODEL (shortcuts_model), mount_point)); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_create_shortcut), view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - image = gtk_image_new_from_stock (THUNAR_STOCK_SHORTCUTS, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - - if (mount_point != NULL) - g_object_unref (mount_point); - - /* fall-through */ - - case THUNAR_SHORTCUT_GROUP_DEVICES_MOUNTS: - /* append a menu separator */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* append the "Disconnect" item */ - item = gtk_image_menu_item_new_with_mnemonic (_("Disconn_ect")); - gtk_widget_set_sensitive (item, thunar_device_can_eject (device)); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_eject), view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - image = gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - break; - - case THUNAR_SHORTCUT_GROUP_PLACES_TRASH: - /* append a menu separator */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* append the "Empty Trash" menu action */ - item = gtk_image_menu_item_new_with_mnemonic (_("_Empty Trash")); - gtk_widget_set_sensitive (item, (thunar_file_get_item_count (file) > 0)); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_empty_trash), view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - break; - - default: - break; - } - - /* create provider menu items if there is a non-trashed file */ - if (G_LIKELY (file != NULL && !thunar_file_is_trashed (file))) - { - /* load the menu providers from the provider factory */ - providers = thunarx_provider_factory_list_providers (view->provider_factory, THUNARX_TYPE_MENU_PROVIDER); - if (G_LIKELY (providers != NULL)) - { - /* determine the toplevel window we belong to */ - window = gtk_widget_get_toplevel (GTK_WIDGET (view)); - - /* load the actions offered by the menu providers */ - for (lp = providers; lp != NULL; lp = lp->next) - { - tmp = thunarx_menu_provider_get_folder_actions (lp->data, window, THUNARX_FILE_INFO (file)); - actions = g_list_concat (actions, tmp); - g_object_unref (G_OBJECT (lp->data)); - } - g_list_free (providers); - - if (actions != NULL) - { - /* append a menu separator */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - } - - /* add the actions to the menu */ - for (lp = actions; lp != NULL; lp = lp->next) - { - item = gtk_action_create_menu_item (GTK_ACTION (lp->data)); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* release the reference on the action */ - g_object_unref (G_OBJECT (lp->data)); - } - - /* cleanup */ - g_list_free (actions); - } - } - - /* append the remove menu item */ - if (group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS) - { - /* append a menu separator */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - item = gtk_image_menu_item_new_with_mnemonic (_("_Remove Shortcut")); - g_object_set_data_full (G_OBJECT (item), I_("thunar-shortcuts-row"), - gtk_tree_row_reference_new (model, path), - (GDestroyNotify) gtk_tree_row_reference_free); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_remove_activated), model); - gtk_widget_set_sensitive (item, mutable); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* set the remove stock icon */ - image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - - /* append the rename menu item */ - item = gtk_image_menu_item_new_with_mnemonic (_("Re_name Shortcut")); - g_object_set_data_full (G_OBJECT (item), I_("thunar-shortcuts-row"), - gtk_tree_row_reference_new (model, path), - (GDestroyNotify) gtk_tree_row_reference_free); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_rename_activated), view); - gtk_widget_set_sensitive (item, mutable); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - gtk_widget_show (item); - } - - /* clean up */ - if (G_LIKELY (file != NULL)) - g_object_unref (G_OBJECT (file)); - if (G_UNLIKELY (device != NULL)) - g_object_unref (G_OBJECT (device)); - gtk_tree_path_free (path); - - /* run the menu on the view's screen (taking over the floating reference on menu) */ - thunar_gtk_menu_run (GTK_MENU (menu), GTK_WIDGET (view), NULL, NULL, (event != NULL) ? event->button : 0, - (event != NULL) ? event->time : gtk_get_current_event_time ()); -} - - - -static void -thunar_shortcuts_view_remove_activated (GtkWidget *item, - GtkTreeModel *model) -{ - GtkTreeRowReference *row; - GtkTreeModel *child_model; - GtkTreePath *path; - GtkTreePath *child_path; - - row = g_object_get_data (G_OBJECT (item), I_("thunar-shortcuts-row")); - path = gtk_tree_row_reference_get_path (row); - if (G_LIKELY (path != NULL)) - { - child_path = gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (model), path); - gtk_tree_path_free (path); - - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_remove (THUNAR_SHORTCUTS_MODEL (child_model), child_path); - gtk_tree_path_free (child_path); - } -} - - - -static void -thunar_shortcuts_view_editing_canceled (GtkCellRenderer *renderer, - ThunarShortcutsView *view) -{ - g_object_set (G_OBJECT (renderer), "editable", FALSE, NULL); - - g_signal_handlers_disconnect_by_func (G_OBJECT (renderer), - G_CALLBACK (thunar_shortcuts_view_editing_canceled), - view); -} - - - -static void -thunar_shortcuts_view_rename_activated (GtkWidget *item, - ThunarShortcutsView *view) -{ - GtkTreeRowReference *row; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - GtkTreePath *path; - GList *renderers; - - row = g_object_get_data (G_OBJECT (item), I_("thunar-shortcuts-row")); - path = gtk_tree_row_reference_get_path (row); - if (G_LIKELY (path != NULL)) - { - /* determine the text renderer */ - column = gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0); - renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column)); - renderer = g_list_nth_data (renderers, 3); - - /* make sure the text renderer is editable */ - g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL); - - /* set up signals for the cell renderer */ - g_signal_connect (G_OBJECT (renderer), "editing-canceled", - G_CALLBACK (thunar_shortcuts_view_editing_canceled), view); - - /* tell the tree view to start editing the given row */ - gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (view), path, column, renderer, TRUE); - - /* cleanup */ - gtk_tree_path_free (path); - g_list_free (renderers); - } -} - - - -static void -thunar_shortcuts_view_renamed (GtkCellRenderer *renderer, - const gchar *path_string, - const gchar *text, - ThunarShortcutsView *view) -{ - GtkTreeModel *model; - GtkTreeIter iter; - GtkTreeModel *child_model; - GtkTreeIter child_iter; - - /* reset the editable flag */ - g_object_set (G_OBJECT (renderer), "editable", FALSE, NULL); - - /* perform the rename */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - if (gtk_tree_model_get_iter_from_string (model, &iter, path_string)) - { - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, &iter); - thunar_shortcuts_model_rename (THUNAR_SHORTCUTS_MODEL (child_model), &child_iter, text); - } -} - - - -static GdkDragAction -thunar_shortcuts_view_compute_drop_actions (ThunarShortcutsView *view, - GdkDragContext *context, - gint x, - gint y, - GtkTreePath **path_return, - GdkDragAction *action_return, - GtkTreeViewDropPosition *position_return) -{ - GtkTreeViewColumn *column; - GdkDragAction actions = 0; - GdkRectangle cell_area; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - ThunarFile *file; - gint cell_y; - - /* determine the shortcuts model */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - - /* determine the path for x/y */ - if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view), x, y, &path, &column, NULL, &cell_y)) - { - /* determine the background area of the column */ - gtk_tree_view_get_background_area (GTK_TREE_VIEW (view), path, column, &cell_area); - - /* check if 1/6th inside the cell and the path is within the model */ - if ((cell_y > (cell_area.height / 6) && cell_y < (cell_area.height - cell_area.height / 6)) - && gtk_tree_model_get_iter (model, &iter, path)) - { - /* determine the file for the iterator */ - gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, &file, -1); - if (G_LIKELY (file != NULL)) - { - /* check if the file accepts the drop */ - actions = thunar_file_accepts_drop (file, view->drop_file_list, context, action_return); - if (G_LIKELY (actions != 0)) - { - /* we can drop into this location */ - *position_return = GTK_TREE_VIEW_DROP_INTO_OR_AFTER; - *path_return = gtk_tree_path_copy (path); - - /* display a drop icon for the file */ - g_object_set (G_OBJECT (view->icon_renderer), "drop-file", file, NULL); - } - - /* release the file */ - g_object_unref (G_OBJECT (file)); - } - } - - /* release the path */ - gtk_tree_path_free (path); - } - - /* check if we cannot drop into the shortcut */ - if (G_UNLIKELY (actions == 0)) - { - /* check the action that should be performed */ - if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_LINK || (gdk_drag_context_get_actions (context) & GDK_ACTION_LINK) != 0) - actions = GDK_ACTION_LINK; - else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_COPY || (gdk_drag_context_get_actions (context) & GDK_ACTION_COPY) != 0) - actions = GDK_ACTION_COPY; - else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_MOVE || (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0) - actions = GDK_ACTION_MOVE; - else - return 0; - - /* but maybe we can add as shortcut */ - path = thunar_shortcuts_view_compute_drop_position (view, x, y); - - if (path == NULL) - return 0; - - /* check if path is about to append to the model */ - if (gtk_tree_path_get_indices (path)[0] >= gtk_tree_model_iter_n_children (model, NULL)) - { - /* set the position to "after" and move the path to - * point to the previous row instead; required to - * get the highlighting in GtkTreeView correct. - */ - *position_return = GTK_TREE_VIEW_DROP_AFTER; - gtk_tree_path_prev (path); - } - else - { - /* drop before the path */ - *position_return = GTK_TREE_VIEW_DROP_BEFORE; - } - - /* got it */ - *action_return = actions; - *path_return = path; - } - - return actions; -} - - - -static GtkTreePath* -thunar_shortcuts_view_compute_drop_position (ThunarShortcutsView *view, - gint x, - gint y) -{ - GtkTreeViewColumn *column; - GtkTreeModel *model; - GdkRectangle area; - GtkTreePath *path; - gint n_rows; - gboolean result; - GtkTreePath *child_path; - GtkTreeModel *child_model; - - _thunar_return_val_if_fail (gtk_tree_view_get_model (GTK_TREE_VIEW (view)) != NULL, NULL); - _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view), NULL); - - /* query the number of rows in the model */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - n_rows = gtk_tree_model_iter_n_children (model, NULL); - - if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view), x, y, - &path, &column, &x, &y)) - { - /* determine the exact path of the row the user is trying to drop - * (taking into account the relative y position) - */ - gtk_tree_view_get_background_area (GTK_TREE_VIEW (view), path, column, &area); - if (y >= area.height / 2) - gtk_tree_path_next (path); - - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - - /* find a suitable drop path (we cannot drop into the default shortcuts list) */ - for (; gtk_tree_path_get_indices (path)[0] < n_rows; gtk_tree_path_next (path)) - { - child_path = gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (model), path); - result = thunar_shortcuts_model_drop_possible (THUNAR_SHORTCUTS_MODEL (child_model), child_path); - gtk_tree_path_free (child_path); - if (result) - return path; - } - - gtk_tree_path_free (path); - } - - return NULL; -} - - - -static void -thunar_shortcuts_view_drop_uri_list (ThunarShortcutsView *view, - GList *path_list, - GtkTreePath *dst_path) -{ - GtkTreeModel *model; - GtkTreePath *path; - ThunarFile *file; - GError *error = NULL; - GList *lp; - GtkTreeModel *child_model; - GtkTreePath *child_path; - - /* take a copy of the destination path */ - path = gtk_tree_path_copy (dst_path); - - /* process the URIs one-by-one and stop on error */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - for (lp = path_list; lp != NULL; lp = lp->next) - { - file = thunar_file_get (lp->data, &error); - if (G_UNLIKELY (file == NULL)) - break; - - /* make sure, that only directories gets added to the shortcuts list */ - if (G_UNLIKELY (!thunar_file_is_directory (file))) - { - g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_NOTDIR, - _("The path \"%s\" does not refer to a directory"), - thunar_file_get_display_name (file)); - g_object_unref (file); - break; - } - - child_path = gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (model), path); - thunar_shortcuts_model_add (THUNAR_SHORTCUTS_MODEL (child_model), child_path, file); - gtk_tree_path_free (child_path); - - g_object_unref (file); - gtk_tree_path_next (path); - } - - /* release the tree path copy */ - gtk_tree_path_free (path); - - if (G_UNLIKELY (error != NULL)) - { - /* display an error message to the user */ - thunar_dialogs_show_error (GTK_WIDGET (view), error, _("Failed to add new shortcut")); - - /* release the error */ - g_error_free (error); - } -} - - - -static void -thunar_shortcuts_view_open_clicked (ThunarShortcutsView *view) -{ - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - thunar_shortcuts_view_open (view, OPEN_IN_VIEW); -} - - - -static void -thunar_shortcuts_view_poke_file_finish (ThunarBrowser *browser, - ThunarFile *file, - ThunarFile *target_file, - GError *error, - gpointer user_data) -{ - ThunarApplication *application; - OpenTarget open_in = GPOINTER_TO_UINT (user_data); - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (browser)); - _thunar_return_if_fail (THUNAR_IS_FILE (target_file)); - - if (error == NULL) - { - if (open_in == OPEN_IN_WINDOW) - { - /* open a new window for the target folder */ - application = thunar_application_get (); - thunar_application_open_window (application, target_file, - gtk_widget_get_screen (GTK_WIDGET (browser)), NULL); - g_object_unref (application); - } - else if (open_in == OPEN_IN_TAB) - { - /* invoke the signal to change to open folder in a new tab */ - g_signal_emit (browser, view_signals[SHORTCUT_ACTIVATED_TAB], 0, target_file); - } - else if (thunar_file_check_loaded (target_file)) - { - /* invoke the signal to change to that folder */ - g_signal_emit (browser, view_signals[SHORTCUT_ACTIVATED], 0, target_file); - } - } - else - { - thunar_dialogs_show_error (GTK_WIDGET (browser), error, _("Failed to open \"%s\""), - thunar_file_get_display_name (file)); - } -} - - - -static void -thunar_shortcuts_view_poke_location_finish (ThunarBrowser *browser, - GFile *location, - ThunarFile *file, - ThunarFile *target_file, - GError *error, - gpointer user_data) -{ - gchar *name; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (browser)); - _thunar_return_if_fail (G_IS_FILE (location)); - - /* sotre the new file in the shortcuts model */ - if (error == NULL) - { - thunar_shortcuts_view_poke_file_finish (browser, file, target_file, error, user_data); - } - else - { - name = thunar_g_file_get_display_name_remote (location); - thunar_dialogs_show_error (GTK_WIDGET (browser), error, _("Failed to open \"%s\""), name); - g_free (name); - } -} - - - -static void -thunar_shortcuts_view_poke_device_finish (ThunarBrowser *browser, - ThunarDevice *device, - ThunarFile *mount_point, - GError *error, - gpointer user_data) -{ - gchar *device_name; - GtkTreeModel *model; - GtkTreeModel *child_model; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (browser)); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - - if (error == NULL) - { - thunar_browser_poke_file (browser, mount_point, GTK_WIDGET (browser), - thunar_shortcuts_view_poke_file_finish, - user_data); - } - else - { - device_name = thunar_device_get_name (device); - thunar_dialogs_show_error (GTK_WIDGET (browser), error, - _("Failed to mount \"%s\""), device_name); - g_free (device_name); - } - - /* stop the spinner */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (browser)); - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, FALSE); -} - - - -static void -thunar_shortcuts_view_open (ThunarShortcutsView *view, - OpenTarget open_in) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - ThunarFile *file; - ThunarDevice *device; - GFile *location; - GtkTreeModel *child_model; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* determine the selected item */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - - /* avoid dealing with invalid selections */ - if (!GTK_IS_TREE_SELECTION (selection)) - return; - - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - /* determine the file for the shortcut at the given tree iterator */ - gtk_tree_model_get (model, &iter, - THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, &file, - THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, - THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION, &location, - -1); - - if (G_LIKELY (device != NULL)) - { - /* start the spinner */ - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, TRUE); - - thunar_browser_poke_device (THUNAR_BROWSER (view), device, view, - thunar_shortcuts_view_poke_device_finish, - GUINT_TO_POINTER (open_in)); - } - else if (file != NULL) - { - thunar_browser_poke_file (THUNAR_BROWSER (view), file, view, - thunar_shortcuts_view_poke_file_finish, - GUINT_TO_POINTER (open_in)); - } - else if (location != NULL) - { - thunar_browser_poke_location (THUNAR_BROWSER (view), location, view, - thunar_shortcuts_view_poke_location_finish, - GUINT_TO_POINTER (open_in)); - } - - if (file != NULL) - g_object_unref (file); - - if (device != NULL) - g_object_unref (device); - - if (location != NULL) - g_object_unref (location); - } -} - - - -static void -thunar_shortcuts_view_open_in_new_window_clicked (ThunarShortcutsView *view) -{ - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - thunar_shortcuts_view_open (view, OPEN_IN_WINDOW); -} - - - -static void -thunar_shortcuts_view_open_in_new_tab_clicked (ThunarShortcutsView *view) -{ - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - thunar_shortcuts_view_open (view, OPEN_IN_TAB); -} - - - -static void -thunar_shortcuts_view_empty_trash (ThunarShortcutsView *view) -{ - ThunarApplication *application; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* empty the trash bin (asking the user first) */ - application = thunar_application_get (); - thunar_application_empty_trash (application, GTK_WIDGET (view), NULL); - g_object_unref (G_OBJECT (application)); -} - - - -static void -thunar_shortcuts_view_create_shortcut (ThunarShortcutsView *view) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - ThunarDevice *device; - GFile *mount_point; - GtkTreeModel *shortcuts_model; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* determine the selected item */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - /* determine the device/mount for the shortcut at the given tree iterator */ - gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, -1); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - - /* add the mount point to the model */ - mount_point = thunar_device_get_root (device); - if (mount_point != NULL) - { - shortcuts_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_add (THUNAR_SHORTCUTS_MODEL (shortcuts_model), NULL, mount_point); - g_object_unref (mount_point); - } - - g_object_unref (G_OBJECT (device)); - } -} - - - -static void -thunar_shortcuts_view_eject_finish (ThunarDevice *device, - const GError *error, - gpointer user_data) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (user_data); - gchar *device_name; - GtkTreeModel *model; - GtkTreeModel *child_model; - - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* check if there was an error */ - if (error != NULL) - { - /* display an error dialog to inform the user */ - device_name = thunar_device_get_name (device); - thunar_dialogs_show_error (GTK_WIDGET (view), error, _("Failed to eject \"%s\""), device_name); - g_free (device_name); - } - - /* stop the spinner */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, FALSE); - - g_object_unref (view); -} - - - -static void -thunar_shortcuts_view_eject (ThunarShortcutsView *view) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - ThunarDevice *device; - GMountOperation *mount_operation; - GtkTreeModel *child_model; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* determine the selected item */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - /* determine the device/mount for the shortcut at the given tree iterator */ - gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, -1); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - - /* prepare a mount operation */ - mount_operation = thunar_gtk_mount_operation_new (GTK_WIDGET (view)); - - /* start the spinner */ - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, TRUE); - - /* try to unmount */ - thunar_device_eject (device, - mount_operation, - NULL, - thunar_shortcuts_view_eject_finish, - g_object_ref (view)); - - g_object_unref (G_OBJECT (device)); - g_object_unref (G_OBJECT (mount_operation)); - } -} - - - -static void -thunar_shortcuts_view_poke_device_mount_finish (ThunarBrowser *browser, - ThunarDevice *device, - ThunarFile *mount_point, - GError *error, - gpointer ignored) -{ - gchar *device_name; - GtkTreeModel *model; - GtkTreeModel *child_model; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (browser)); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - - if (error != NULL) - { - device_name = thunar_device_get_name (device); - thunar_dialogs_show_error (GTK_WIDGET (browser), error, - _("Failed to mount \"%s\""), device_name); - g_free (device_name); - } - - /* stop the spinner */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (browser)); - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, FALSE); -} - - - -static void -thunar_shortcuts_view_mount (ThunarShortcutsView *view) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - ThunarDevice *device; - GtkTreeModel *child_model; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* determine the selected item */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - - /* avoid dealing with invalid selections */ - if (!GTK_IS_TREE_SELECTION (selection)) - return; - - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - /* determine the file for the shortcut at the given tree iterator */ - gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, -1); - - if (G_LIKELY (device != NULL)) - { - /* start the spinner */ - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, TRUE); - - thunar_browser_poke_device (THUNAR_BROWSER (view), device, view, - thunar_shortcuts_view_poke_device_mount_finish, - NULL); - g_object_unref (device); - } - } -} - - - -static void -thunar_shortcuts_view_unmount_finish (ThunarDevice *device, - const GError *error, - gpointer user_data) -{ - ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (user_data); - gchar *device_name; - GtkTreeModel *model; - GtkTreeModel *child_model; - - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* check if there was an error */ - if (error != NULL) - { - /* display an error dialog to inform the user */ - device_name = thunar_device_get_name (device); - thunar_dialogs_show_error (GTK_WIDGET (view), error, _("Failed to unmount \"%s\""), device_name); - g_free (device_name); - } - - /* stop the spinner */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, FALSE); - - g_object_unref (view); -} - - - -static void -thunar_shortcuts_view_unmount (ThunarShortcutsView *view) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - ThunarDevice *device; - GMountOperation *mount_operation; - GtkTreeModel *child_model; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - - /* determine the selected item */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - /* determine the device/mount for the shortcut at the given tree iterator */ - gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, -1); - _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); - - /* prepare a mount operation */ - mount_operation = thunar_gtk_mount_operation_new (GTK_WIDGET (view)); - - /* start the spinner */ - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, TRUE); - - /* try to unmount */ - thunar_device_unmount (device, - mount_operation, - NULL, - thunar_shortcuts_view_unmount_finish, - g_object_ref (view)); - - g_object_unref (G_OBJECT (device)); - g_object_unref (G_OBJECT (mount_operation)); - } -} - - - -/** - * thunar_shortcuts_view_new: - * - * Allocates a new #ThunarShortcutsView instance and associates - * it with the default #ThunarShortcutsModel instance. - * - * Return value: the newly allocated #ThunarShortcutsView instance. - **/ -GtkWidget* -thunar_shortcuts_view_new (void) -{ - ThunarShortcutsModel *model; - GtkWidget *view; - GtkTreeModel *filter_model; - - model = thunar_shortcuts_model_get_default (); - filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (model), NULL); - gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), THUNAR_SHORTCUTS_MODEL_COLUMN_VISIBLE); - g_object_unref (G_OBJECT (model)); - - view = g_object_new (THUNAR_TYPE_SHORTCUTS_VIEW, "model", filter_model, NULL); - g_object_unref (G_OBJECT (filter_model)); - - return view; -} - - - -/** - * thunar_shortcuts_view_select_by_file: - * @view : a #ThunarShortcutsView instance. - * @file : a #ThunarFile instance. - * - * Looks up the first shortcut that refers to @file in @view and selects it. - * If @file is not present in the underlying #ThunarShortcutsModel, no - * shortcut will be selected afterwards. - **/ -void -thunar_shortcuts_view_select_by_file (ThunarShortcutsView *view, - ThunarFile *file) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - GtkTreeModel *child_model; - GtkTreeIter child_iter; - - _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view)); - _thunar_return_if_fail (THUNAR_IS_FILE (file)); - - /* get the selection */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); - - /* try to lookup a tree iter for the given file */ - if (thunar_shortcuts_model_iter_for_file (THUNAR_SHORTCUTS_MODEL (child_model), file, &child_iter) - && gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (model), &iter, &child_iter)) - gtk_tree_selection_select_iter (selection, &iter); - else - gtk_tree_selection_unselect_all (selection); -} - - diff --git a/thunar/thunar-shortcuts-view.h b/thunar/thunar-shortcuts-view.h deleted file mode 100644 index 5f81f0b25641f7a7ac7ca7f4ae61c430676616ef..0000000000000000000000000000000000000000 --- a/thunar/thunar-shortcuts-view.h +++ /dev/null @@ -1,46 +0,0 @@ -/* vi:set et ai sw=2 sts=2 ts=2: */ -/*- - * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org> - * - * This program 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. - * - * This program 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 - */ - -#ifndef __THUNAR_SHORTCUTS_VIEW_H__ -#define __THUNAR_SHORTCUTS_VIEW_H__ - -#include <thunar/thunar-file.h> - -G_BEGIN_DECLS; - -typedef struct _ThunarShortcutsViewClass ThunarShortcutsViewClass; -typedef struct _ThunarShortcutsView ThunarShortcutsView; - -#define THUNAR_TYPE_SHORTCUTS_VIEW (thunar_shortcuts_view_get_type ()) -#define THUNAR_SHORTCUTS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_SHORTCUTS_VIEW, ThunarShortcutsView)) -#define THUNAR_SHORTCUTS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_SHORTCUTS_VIEW, ThunarShortcutsViewClass)) -#define THUNAR_IS_SHORTCUTS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_SHORTCUTS_VIEW)) -#define THUNAR_IS_SHORTCUTS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_SHORTCUTS_VIEW)) -#define THUNAR_SHORTCUTS_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_SHORTCUTS_VIEW, ThunarShortcutsViewClass)) - -GType thunar_shortcuts_view_get_type (void) G_GNUC_CONST; - -GtkWidget *thunar_shortcuts_view_new (void) G_GNUC_MALLOC; - -void thunar_shortcuts_view_select_by_file (ThunarShortcutsView *view, - ThunarFile *file); - -G_END_DECLS; - -#endif /* !__THUNAR_SHORTCUTS_VIEW_H__ */