[Xfce4-commits] <thunar:nick/new-shortcuts-pane-model> Work on a fancy-pancy sidepane in GtkTreeView.
Nick Schermer
noreply at xfce.org
Fri Oct 5 23:04:08 CEST 2012
Updating branch refs/heads/nick/new-shortcuts-pane-model
to 16cad68487d7c1d82177f19fec561b58caec3c6a (commit)
from 8e194c6b479de6df6fcfb2d4fae8df1006191059 (commit)
commit 16cad68487d7c1d82177f19fec561b58caec3c6a
Author: Nick Schermer <nick at xfce.org>
Date: Fri Oct 5 23:02:00 2012 +0200
Work on a fancy-pancy sidepane in GtkTreeView.
thunar/thunar-file.c | 10 +-
thunar/thunar-shortcuts-icon-renderer.c | 66 +++-
thunar/thunar-shortcuts-model.c | 685 ++++++++++++++++++++++---------
thunar/thunar-shortcuts-model.h | 20 +-
thunar/thunar-shortcuts-view.c | 570 +++++++++++++++++++-------
5 files changed, 973 insertions(+), 378 deletions(-)
diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c
index 52d223d..cb93e57 100644
--- a/thunar/thunar-file.c
+++ b/thunar/thunar-file.c
@@ -3398,10 +3398,12 @@ thunar_file_compare_by_name (const ThunarFile *file_a,
if (result == 0)
result = strcmp (file_a->collate_key, file_b->collate_key);
-#ifdef G_ENABLE_DEBUG
- /* check final output */
- _thunar_return_val_if_fail (result != 0, 0);
- #endif
+ /* this happens in the trash */
+ if (result == 0)
+ {
+ result = g_strcmp0 (thunar_file_get_original_path (file_a),
+ thunar_file_get_original_path (file_b));
+ }
return result;
}
diff --git a/thunar/thunar-shortcuts-icon-renderer.c b/thunar/thunar-shortcuts-icon-renderer.c
index ff949c8..a31f553 100644
--- a/thunar/thunar-shortcuts-icon-renderer.c
+++ b/thunar/thunar-shortcuts-icon-renderer.c
@@ -36,6 +36,7 @@ enum
{
PROP_0,
PROP_VOLUME,
+ PROP_MOUNT,
PROP_GICON,
};
@@ -70,6 +71,7 @@ struct _ThunarShortcutsIconRenderer
ThunarIconRenderer __parent__;
GVolume *volume;
+ GMount *mount;
GIcon *gicon;
};
@@ -106,6 +108,18 @@ thunar_shortcuts_icon_renderer_class_init (ThunarShortcutsIconRendererClass *kla
EXO_PARAM_READWRITE));
/**
+ * ThunarShortcutsIconRenderer:mount:
+ *
+ * The #GMount for which to render an icon or %NULL to fallback
+ * to the default icon renderering (see #ThunarIconRenderer).
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_MOUNT,
+ g_param_spec_object ("mount", "mount", "mount",
+ G_TYPE_MOUNT,
+ EXO_PARAM_READWRITE));
+
+ /**
* ThunarIconRenderer:gicon:
*
* The GIcon to render, this property has preference over the the icon returned
@@ -133,15 +147,16 @@ thunar_shortcuts_icon_renderer_init (ThunarShortcutsIconRenderer *shortcuts_icon
static void
thunar_shortcuts_icon_renderer_finalize (GObject *object)
{
- ThunarShortcutsIconRenderer *shortcuts_icon_renderer = THUNAR_SHORTCUTS_ICON_RENDERER (object);
+ ThunarShortcutsIconRenderer *renderer = THUNAR_SHORTCUTS_ICON_RENDERER (object);
- /* release the volume (if any) */
- if (G_UNLIKELY (shortcuts_icon_renderer->volume != NULL))
- g_object_unref (shortcuts_icon_renderer->volume);
+ if (G_UNLIKELY (renderer->volume != NULL))
+ g_object_unref (renderer->volume);
- /* release the icon */
- if (G_UNLIKELY (shortcuts_icon_renderer->gicon != NULL))
- g_object_unref (shortcuts_icon_renderer->gicon);
+ if (G_UNLIKELY (renderer->mount != NULL))
+ g_object_unref (renderer->mount);
+
+ if (G_UNLIKELY (renderer->gicon != NULL))
+ g_object_unref (renderer->gicon);
(*G_OBJECT_CLASS (thunar_shortcuts_icon_renderer_parent_class)->finalize) (object);
}
@@ -154,16 +169,20 @@ thunar_shortcuts_icon_renderer_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
- ThunarShortcutsIconRenderer *shortcuts_icon_renderer = THUNAR_SHORTCUTS_ICON_RENDERER (object);
+ ThunarShortcutsIconRenderer *renderer = THUNAR_SHORTCUTS_ICON_RENDERER (object);
switch (prop_id)
{
case PROP_VOLUME:
- g_value_set_object (value, shortcuts_icon_renderer->volume);
+ g_value_set_object (value, renderer->volume);
+ break;
+
+ case PROP_MOUNT:
+ g_value_set_object (value, renderer->mount);
break;
case PROP_GICON:
- g_value_set_object (value, shortcuts_icon_renderer->gicon);
+ g_value_set_object (value, renderer->gicon);
break;
default:
@@ -180,20 +199,26 @@ thunar_shortcuts_icon_renderer_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
- ThunarShortcutsIconRenderer *shortcuts_icon_renderer = THUNAR_SHORTCUTS_ICON_RENDERER (object);
+ ThunarShortcutsIconRenderer *renderer = THUNAR_SHORTCUTS_ICON_RENDERER (object);
switch (prop_id)
{
case PROP_VOLUME:
- if (G_UNLIKELY (shortcuts_icon_renderer->volume != NULL))
- g_object_unref (shortcuts_icon_renderer->volume);
- shortcuts_icon_renderer->volume = g_value_dup_object (value);
+ if (G_UNLIKELY (renderer->volume != NULL))
+ g_object_unref (renderer->volume);
+ renderer->volume = g_value_dup_object (value);
+ break;
+
+ case PROP_MOUNT:
+ if (G_UNLIKELY (renderer->mount != NULL))
+ g_object_unref (renderer->mount);
+ renderer->mount = g_value_dup_object (value);
break;
case PROP_GICON:
- if (G_UNLIKELY (shortcuts_icon_renderer->gicon != NULL))
- g_object_unref (shortcuts_icon_renderer->gicon);
- shortcuts_icon_renderer->gicon = g_value_dup_object (value);
+ if (G_UNLIKELY (renderer->gicon != NULL))
+ g_object_unref (renderer->gicon);
+ renderer->gicon = g_value_dup_object (value);
break;
default:
@@ -224,7 +249,8 @@ thunar_shortcuts_icon_renderer_render (GtkCellRenderer *renderer,
/* check if we have a volume set */
if (G_UNLIKELY (shortcuts_icon_renderer->volume != NULL
- || shortcuts_icon_renderer->gicon != NULL))
+ || shortcuts_icon_renderer->gicon != NULL
+ || shortcuts_icon_renderer->mount != NULL))
{
/* load the volume icon */
icon_theme = gtk_icon_theme_get_for_screen (gdk_drawable_get_screen (window));
@@ -232,8 +258,10 @@ thunar_shortcuts_icon_renderer_render (GtkCellRenderer *renderer,
/* look up the icon info */
if (shortcuts_icon_renderer->gicon != NULL)
gicon = g_object_ref (shortcuts_icon_renderer->gicon);
- else
+ else if (shortcuts_icon_renderer->volume != NULL)
gicon = g_volume_get_icon (shortcuts_icon_renderer->volume);
+ else
+ gicon = g_mount_get_icon (shortcuts_icon_renderer->mount);
icon_info = gtk_icon_theme_lookup_by_gicon (icon_theme, gicon, cell_area->width,
GTK_ICON_LOOKUP_USE_BUILTIN);
diff --git a/thunar/thunar-shortcuts-model.c b/thunar/thunar-shortcuts-model.c
index bf6d67e..c16988c 100644
--- a/thunar/thunar-shortcuts-model.c
+++ b/thunar/thunar-shortcuts-model.c
@@ -57,14 +57,6 @@ const gchar *_thunar_user_directory_names[9] = {
typedef struct _ThunarShortcut ThunarShortcut;
-typedef enum
-{
- THUNAR_SHORTCUT_SEPARATOR,
- THUNAR_SHORTCUT_SYSTEM_DEFINED,
- THUNAR_SHORTCUT_REMOVABLE_MEDIA,
- THUNAR_SHORTCUT_USER_DEFINED,
-} ThunarShortcutType;
-
static void thunar_shortcuts_model_tree_model_init (GtkTreeModelIface *iface);
@@ -107,8 +99,7 @@ static gboolean thunar_shortcuts_model_drag_data_get (GtkTreeDrag
static gboolean thunar_shortcuts_model_drag_data_delete (GtkTreeDragSource *source,
GtkTreePath *path);
static void thunar_shortcuts_model_add_shortcut (ThunarShortcutsModel *model,
- ThunarShortcut *shortcut,
- GtkTreePath *path);
+ ThunarShortcut *shortcut);
static void thunar_shortcuts_model_remove_shortcut (ThunarShortcutsModel *model,
ThunarShortcut *shortcut);
static void thunar_shortcuts_model_load (ThunarShortcutsModel *model);
@@ -131,6 +122,16 @@ static void thunar_shortcuts_model_volume_removed (GVolumeMoni
static void thunar_shortcuts_model_volume_changed (GVolumeMonitor *monitor,
GVolume *volume,
ThunarShortcutsModel *model);
+static void thunar_shortcuts_model_mount_added (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ ThunarShortcutsModel *model);
+static void thunar_shortcuts_model_mount_removed (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ ThunarShortcutsModel *model);
+static void thunar_shortcuts_model_mount_changed (GVolumeMonitor *monitor,
+ GMount *mount,
+ ThunarShortcutsModel *model);
+
static void thunar_shortcut_free (ThunarShortcut *shortcut,
ThunarShortcutsModel *model);
@@ -162,13 +163,18 @@ struct _ThunarShortcutsModel
struct _ThunarShortcut
{
- ThunarShortcutType type;
+ ThunarShortcutGroup group;
+
+ guint is_header : 1;
- GFile *location;
- gchar *name;
- GIcon *gicon;
- ThunarFile *file;
- GVolume *volume;
+ gchar *name;
+ GIcon *gicon;
+ gint sort_id;
+
+ GFile *location;
+ ThunarFile *file;
+ GVolume *volume;
+ GMount *mount;
};
@@ -178,7 +184,7 @@ G_DEFINE_TYPE_WITH_CODE (ThunarShortcutsModel, thunar_shortcuts_model, G_TYPE_OB
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, thunar_shortcuts_model_drag_source_init))
-
+
static void
thunar_shortcuts_model_class_init (ThunarShortcutsModelClass *klass)
{
@@ -218,124 +224,138 @@ thunar_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface)
}
+
static void
-thunar_shortcuts_model_add_shortcut_system (ThunarShortcutsModel *model,
- GFile *location,
- const gchar *name,
- const gchar *icon_name,
- GtkTreePath *path)
+thunar_shortcuts_model_volumes_load (ThunarShortcutsModel *model)
{
ThunarShortcut *shortcut;
+ GList *volumes;
+ GList *lp;
+ GList *mounts;
+ /* add the devices heading */
shortcut = g_slice_new0 (ThunarShortcut);
- shortcut->type = THUNAR_SHORTCUT_SYSTEM_DEFINED;
- shortcut->location = g_object_ref (location);
- shortcut->name = g_strdup (name);
- shortcut->gicon = g_themed_icon_new (icon_name);
- thunar_shortcuts_model_add_shortcut (model, shortcut, path);
-}
+ shortcut->group = THUNAR_SHORTCUT_GROUP_DEVICES;
+ shortcut->name = g_strdup (_("DEVICES"));
+ shortcut->is_header = TRUE;
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
-
-static void
-thunar_shortcuts_model_init (ThunarShortcutsModel *model)
-{
- ThunarShortcut *shortcut;
- GtkTreePath *path;
- GVolume *volume;
- GFile *bookmarks;
- GFile *home;
- GFile *file;
- GList *volumes;
- GList *lp;
-
-#ifndef NDEBUG
- model->stamp = g_random_int ();
-#endif
+ /* the filesystem entry */
+ shortcut = g_slice_new0 (ThunarShortcut);
+ shortcut->group = THUNAR_SHORTCUT_GROUP_DEVICES;
+ shortcut->name = g_strdup (_("File System"));
+ shortcut->file = thunar_file_get_for_uri ("file:///", NULL);
+ shortcut->gicon = g_themed_icon_new (GTK_STOCK_HARDDISK);
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
/* connect to the volume monitor */
model->volume_monitor = g_volume_monitor_get ();
+
+ /* get a list of all volumes available */
+ volumes = g_volume_monitor_get_volumes (model->volume_monitor);
+ for (lp = volumes; lp != NULL; lp = lp->next)
+ {
+ thunar_shortcuts_model_volume_added (model->volume_monitor, lp->data, model);
+ g_object_unref (G_OBJECT (lp->data));
+ }
+ g_list_free (volumes);
+
+ /* get a list of all mounts available */
+ mounts = g_volume_monitor_get_mounts (model->volume_monitor);
+ for (lp = mounts; lp != NULL; lp = lp->next)
+ {
+ thunar_shortcuts_model_mount_added (model->volume_monitor, lp->data, model);
+ g_object_unref (G_OBJECT (lp->data));
+ }
+ g_list_free (mounts);
+
+ /* monitor for changes */
g_signal_connect (model->volume_monitor, "volume-added", G_CALLBACK (thunar_shortcuts_model_volume_added), model);
g_signal_connect (model->volume_monitor, "volume-removed", G_CALLBACK (thunar_shortcuts_model_volume_removed), model);
g_signal_connect (model->volume_monitor, "volume-changed", G_CALLBACK (thunar_shortcuts_model_volume_changed), model);
+ g_signal_connect (model->volume_monitor, "mount-added", G_CALLBACK (thunar_shortcuts_model_mount_added), model);
+ g_signal_connect (model->volume_monitor, "mount-removed", G_CALLBACK (thunar_shortcuts_model_mount_removed), model);
+ g_signal_connect (model->volume_monitor, "mount-changed", G_CALLBACK (thunar_shortcuts_model_mount_changed), model);
+}
- /* get home path */
- home = thunar_g_file_new_for_home ();
- /* will be used to append the shortcuts to the list */
- path = gtk_tree_path_new_from_indices (0, -1);
- /* add the home folder to the system paths */
- thunar_shortcuts_model_add_shortcut_system (model, home, NULL, "user-home", path);
- gtk_tree_path_next (path);
+static void
+thunar_shortcuts_model_shortcut_network (ThunarShortcutsModel *model)
+{
+ ThunarShortcut *shortcut;
- /* append the user's desktop folder */
- file = thunar_g_file_new_for_desktop ();
- if (!g_file_equal (file, home))
- {
- thunar_shortcuts_model_add_shortcut_system (model, file, NULL, "user-desktop", path);
- gtk_tree_path_next (path);
- }
- g_object_unref (file);
+ /* add the network heading */
+ shortcut = g_slice_new0 (ThunarShortcut);
+ shortcut->group = THUNAR_SHORTCUT_GROUP_NETWORK;
+ shortcut->name = g_strdup (_("NETWORK"));
+ shortcut->is_header = TRUE;
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
- /* append the trash icon if the trash is supported */
- if (thunar_g_vfs_is_uri_scheme_supported ("trash"))
- {
- file = thunar_g_file_new_for_trash ();
- thunar_shortcuts_model_add_shortcut_system (model, file, _("Trash"), "user-trash", path);
- g_object_unref (file);
- gtk_tree_path_next (path);
- }
+ /* the browse network entry */
+ shortcut = g_slice_new0 (ThunarShortcut);
+ shortcut->group = THUNAR_SHORTCUT_GROUP_NETWORK;
+ shortcut->name = g_strdup (_("Browse Network"));
+ shortcut->location = g_file_new_for_uri ("network://");
+ shortcut->gicon = g_themed_icon_new (GTK_STOCK_NETWORK);
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
+}
- /* append the trash icon if the trash is supported */
- if (thunar_g_vfs_is_uri_scheme_supported ("network"))
+
+static void
+thunar_shortcuts_model_shortcut_places (ThunarShortcutsModel *model)
+{
+ ThunarShortcut *shortcut;
+ GFile *home;
+ GFile *bookmarks;
+ GFile *desktop;
+ GFile *trash;
+
+ /* add the places heading */
+ shortcut = g_slice_new0 (ThunarShortcut);
+ shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES;
+ shortcut->name = g_strdup (_("PLACES"));
+ shortcut->is_header = TRUE;
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
+
+ /* get home path */
+ home = thunar_g_file_new_for_home ();
+
+ /* add home entry */
+ shortcut = g_slice_new0 (ThunarShortcut);
+ shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES;
+ shortcut->file = thunar_file_get (home, NULL);
+ shortcut->sort_id = 0;
+ shortcut->gicon = g_themed_icon_new ("user-home");
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
+
+ /* add desktop entry */
+ desktop = thunar_g_file_new_for_desktop ();
+ if (!g_file_equal (desktop, home))
{
- file = g_file_new_for_uri ("network://");
- thunar_shortcuts_model_add_shortcut_system (model, file, _("Browse Network"), GTK_STOCK_NETWORK, path);
- g_object_unref (file);
- gtk_tree_path_next (path);
+ shortcut = g_slice_new0 (ThunarShortcut);
+ shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES;
+ shortcut->file = thunar_file_get (desktop, NULL);
+ shortcut->gicon = g_themed_icon_new ("user-desktop");
+ shortcut->sort_id = 1;
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
}
+ g_object_unref (desktop);
- /* append the root file system */
- file = thunar_g_file_new_for_root ();
- thunar_shortcuts_model_add_shortcut_system (model, file, _("File System"), GTK_STOCK_HARDDISK, path);
- g_object_unref (file);
- gtk_tree_path_next (path);
-
- /* prepend the removable media volumes */
- volumes = g_volume_monitor_get_volumes (model->volume_monitor);
- for (lp = volumes; lp != NULL; lp = lp->next)
+ /* append the trash icon if the trash is supported */
+ if (thunar_g_vfs_is_uri_scheme_supported ("trash"))
{
- /* monitor the volume for changes */
- volume = G_VOLUME (lp->data);
+ trash = thunar_g_file_new_for_trash ();
- /* we list only present, removable devices here */
- if (thunar_g_volume_is_removable (volume) && thunar_g_volume_is_present (volume))
- {
- /* generate the shortcut (w/o a file, else we might
- * prevent the volume from being unmounted)
- */
- shortcut = g_slice_new0 (ThunarShortcut);
- shortcut->type = THUNAR_SHORTCUT_REMOVABLE_MEDIA;
- shortcut->volume = volume;
+ shortcut = g_slice_new0 (ThunarShortcut);
+ shortcut->group = THUNAR_SHORTCUT_GROUP_TRASH;
+ shortcut->file = thunar_file_get (trash, NULL);
+ shortcut->gicon = g_themed_icon_new ("user-trash");
+ shortcut->name = g_strdup (_("Trash"));
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
- /* link the shortcut to the list */
- thunar_shortcuts_model_add_shortcut (model, shortcut, path);
- gtk_tree_path_next (path);
- }
- else
- {
- /* schedule the volume for later checking, not removable or
- * there's no medium present */
- model->hidden_volumes = g_list_prepend (model->hidden_volumes, volume);
- }
+ g_object_unref (trash);
}
- g_list_free (volumes);
-
- /* prepend the row separator */
- shortcut = g_slice_new0 (ThunarShortcut);
- shortcut->type = THUNAR_SHORTCUT_SEPARATOR;
- thunar_shortcuts_model_add_shortcut (model, shortcut, path);
- gtk_tree_path_next (path);
/* determine the URI to the Gtk+ bookmarks file */
bookmarks = g_file_resolve_relative_path (home, ".gtk-bookmarks");
@@ -348,10 +368,28 @@ thunar_shortcuts_model_init (ThunarShortcutsModel *model)
/* read the Gtk+ bookmarks file */
thunar_shortcuts_model_load (model);
- /* cleanup */
- g_object_unref (bookmarks);
g_object_unref (home);
- gtk_tree_path_free (path);
+ g_object_unref (bookmarks);
+}
+
+
+
+
+static void
+thunar_shortcuts_model_init (ThunarShortcutsModel *model)
+{
+#ifndef NDEBUG
+ model->stamp = g_random_int ();
+#endif
+
+ /* load volumes */
+ thunar_shortcuts_model_volumes_load (model);
+
+ /* add network */
+ thunar_shortcuts_model_shortcut_network (model);
+
+ /* add bookmarks */
+ thunar_shortcuts_model_shortcut_places (model);
}
@@ -408,6 +446,10 @@ thunar_shortcuts_model_get_column_type (GtkTreeModel *tree_model,
{
switch (idx)
{
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_HEADER:
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_NOT_HEADER:
+ return G_TYPE_BOOLEAN;
+
case THUNAR_SHORTCUTS_MODEL_COLUMN_NAME:
return G_TYPE_STRING;
@@ -423,14 +465,17 @@ thunar_shortcuts_model_get_column_type (GtkTreeModel *tree_model,
case THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME:
return G_TYPE_VOLUME;
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_MOUNT:
+ return G_TYPE_MOUNT;
+
case THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE:
return G_TYPE_BOOLEAN;
case THUNAR_SHORTCUTS_MODEL_COLUMN_EJECT:
return G_TYPE_STRING;
- case THUNAR_SHORTCUTS_MODEL_COLUMN_SEPARATOR:
- return G_TYPE_BOOLEAN;
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP:
+ return G_TYPE_UINT;
}
_thunar_assert_not_reached ();
@@ -502,10 +547,22 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model,
switch (column)
{
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_HEADER:
+ g_value_init (value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (value, shortcut->is_header);
+ break;
+
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_NOT_HEADER:
+ g_value_init (value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (value, !shortcut->is_header);
+ break;
+
case THUNAR_SHORTCUTS_MODEL_COLUMN_NAME:
g_value_init (value, G_TYPE_STRING);
if (G_UNLIKELY (shortcut->volume != NULL))
g_value_take_string (value, g_volume_get_name (shortcut->volume));
+ else if (shortcut->mount != NULL)
+ g_value_take_string (value, g_mount_get_name (shortcut->mount));
else if (shortcut->name != NULL)
g_value_set_static_string (value, shortcut->name);
else if (shortcut->file != NULL)
@@ -518,11 +575,20 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model,
case THUNAR_SHORTCUTS_MODEL_COLUMN_FILE:
g_value_init (value, THUNAR_TYPE_FILE);
- if (shortcut->volume != NULL && shortcut->file == NULL)
+
+ if (shortcut->file != NULL)
+ {
+ g_value_set_object (value, shortcut->file);
+ }
+ if (shortcut->volume != NULL
+ || shortcut->mount != NULL)
{
/* determine the mount of the volume */
- mount = g_volume_get_mount (shortcut->volume);
-
+ if (shortcut->volume != NULL)
+ mount = g_volume_get_mount (shortcut->volume);
+ else
+ mount = g_object_ref (shortcut->mount);
+
if (G_LIKELY (mount != NULL))
{
/* the volume is mounted, get the mount point */
@@ -537,10 +603,6 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model,
g_object_unref (mount);
}
}
- else
- {
- g_value_set_object (value, shortcut->file);
- }
break;
case THUNAR_SHORTCUTS_MODEL_COLUMN_GICON:
@@ -553,6 +615,11 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model,
g_value_set_object (value, shortcut->volume);
break;
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_MOUNT:
+ g_value_init (value, G_TYPE_MOUNT);
+ g_value_set_object (value, shortcut->mount);
+ break;
+
case THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION:
g_value_init (value, G_TYPE_FILE);
if (shortcut->location != NULL)
@@ -563,14 +630,14 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model,
case THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE:
g_value_init (value, G_TYPE_BOOLEAN);
- g_value_set_boolean (value, shortcut->type == THUNAR_SHORTCUT_USER_DEFINED);
+ g_value_set_boolean (value, shortcut->group == THUNAR_SHORTCUT_GROUP_BOOKMARKS);
break;
case THUNAR_SHORTCUTS_MODEL_COLUMN_EJECT:
g_value_init (value, G_TYPE_STRING);
if (shortcut->volume != NULL)
{
- if (thunar_g_volume_is_removable (shortcut->volume)
+ if (thunar_g_volume_is_removable (shortcut->volume)
&& thunar_g_volume_is_present (shortcut->volume))
{
g_value_set_static_string (value, "media-eject");
@@ -586,9 +653,9 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model,
}
break;
- case THUNAR_SHORTCUTS_MODEL_COLUMN_SEPARATOR:
- g_value_init (value, G_TYPE_BOOLEAN);
- g_value_set_boolean (value, shortcut->type == THUNAR_SHORTCUT_SEPARATOR);
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP:
+ g_value_init (value, G_TYPE_UINT);
+ g_value_set_uint (value, shortcut->group);
break;
default:
@@ -698,7 +765,7 @@ thunar_shortcuts_model_row_draggable (GtkTreeDragSource *source,
shortcut = g_list_nth_data (model->shortcuts, gtk_tree_path_get_indices (path)[0]);
/* special shortcuts cannot be reordered */
- return (shortcut != NULL && shortcut->type == THUNAR_SHORTCUT_USER_DEFINED);
+ return (shortcut != NULL && shortcut->group == THUNAR_SHORTCUT_GROUP_BOOKMARKS);
}
@@ -729,18 +796,50 @@ thunar_shortcuts_model_drag_data_delete (GtkTreeDragSource *source,
+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;
+
+ /* sort header at the top of a group */
+ if (a->is_header != b->is_header)
+ return b->is_header ? 1 : -1;
+
+ /* use sort order */
+ if (a->sort_id != b->sort_id)
+ return a->sort_id > b->sort_id ? 1 : -1;
+
+ /* properly sort volumes by timestamp */
+ if (a->volume != NULL && b->volume != NULL)
+ return -g_strcmp0 (g_volume_get_sort_key (a->volume),
+ g_volume_get_sort_key (b->volume));
+
+ /* properly sort mounts by timestamp */
+ if (a->mount != NULL && b->mount != NULL)
+ return -g_strcmp0 (g_mount_get_sort_key (a->mount),
+ g_mount_get_sort_key (b->mount));
+
+ return g_strcmp0 (a->name, b->name);
+}
+
+
+
static void
-thunar_shortcuts_model_add_shortcut (ThunarShortcutsModel *model,
- ThunarShortcut *shortcut,
- GtkTreePath *path)
+thunar_shortcuts_model_add_shortcut_with_path (ThunarShortcutsModel *model,
+ ThunarShortcut *shortcut,
+ GtkTreePath *path)
{
- GtkTreeIter iter;
+ 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));
- _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));
/* we want to stay informed about changes to the file */
if (G_LIKELY (shortcut->file != NULL))
@@ -755,12 +854,36 @@ thunar_shortcuts_model_add_shortcut (ThunarShortcutsModel *model,
G_CALLBACK (thunar_shortcuts_model_file_destroy), model);
}
- /* insert the new shortcut to the shortcuts list */
- model->shortcuts = g_list_insert (model->shortcuts, shortcut, gtk_tree_path_get_indices (path)[0]);
+ 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);
}
@@ -825,7 +948,6 @@ static void
thunar_shortcuts_model_load (ThunarShortcutsModel *model)
{
ThunarShortcut *shortcut;
- GtkTreePath *path;
const gchar *user_special_dir = NULL;
ThunarFile *file;
GFile *file_path;
@@ -835,6 +957,7 @@ thunar_shortcuts_model_load (ThunarShortcutsModel *model)
gchar *name;
FILE *fp;
gint i;
+ gint sort_id;
home = thunar_g_file_new_for_home ();
@@ -845,8 +968,7 @@ thunar_shortcuts_model_load (ThunarShortcutsModel *model)
fp = fopen (bookmarks_path, "r");
if (G_LIKELY (fp != NULL))
{
- /* allocate a tree path for appending to the model */
- path = gtk_tree_path_new_from_indices (g_list_length (model->shortcuts), -1);
+ sort_id = 0;
while (fgets (line, sizeof (line), fp) != NULL)
{
@@ -867,34 +989,51 @@ thunar_shortcuts_model_load (ThunarShortcutsModel *model)
/* parse the URI */
file_path = g_file_new_for_uri (line);
- /* try to open the file corresponding to the uri */
- file = thunar_file_get (file_path, NULL);
- g_object_unref (file_path);
+ /* handle local and remove files differently */
+ if (g_file_has_uri_scheme (file_path, "file"))
+ {
+ /* try to open the file corresponding to the uri */
+ file = thunar_file_get (file_path, NULL);
+ g_object_unref (file_path);
- if (G_UNLIKELY (file == NULL))
- continue;
+ if (G_UNLIKELY (file == NULL))
+ continue;
- /* make sure the file refers to a directory */
- if (G_UNLIKELY (thunar_file_is_directory (file)))
+ /* 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_BOOKMARKS;
+ shortcut->file = file;
+ shortcut->sort_id = ++sort_id;
+ shortcut->name = (*name != '\0') ? g_strdup (name) : NULL;
+
+ /* 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->type = THUNAR_SHORTCUT_USER_DEFINED;
- shortcut->file = file;
+ shortcut->group = THUNAR_SHORTCUT_GROUP_BOOKMARKS;
+ shortcut->gicon = g_themed_icon_new ("folder-remote");
+ shortcut->location = file_path;
+ shortcut->sort_id = ++sort_id;
shortcut->name = (*name != '\0') ? g_strdup (name) : NULL;
/* append the shortcut to the list */
- thunar_shortcuts_model_add_shortcut (model, shortcut, path);
- gtk_tree_path_next (path);
- }
- else
- {
- g_object_unref (file);
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
}
+
}
/* clean up */
- gtk_tree_path_free (path);
fclose (fp);
}
else
@@ -917,7 +1056,6 @@ thunar_shortcuts_model_load (ThunarShortcutsModel *model)
setlocale (LC_MESSAGES, locale);
g_free (locale);
- path = gtk_tree_path_new_from_indices (g_list_length (model->shortcuts), -1);
for (i = G_USER_DIRECTORY_DESKTOP;
i < G_USER_N_DIRECTORIES && _thunar_user_directory_names[i] != NULL;
++i)
@@ -958,20 +1096,18 @@ thunar_shortcuts_model_load (ThunarShortcutsModel *model)
/* create the shortcut entry */
shortcut = g_slice_new0 (ThunarShortcut);
- shortcut->type = THUNAR_SHORTCUT_USER_DEFINED;
+ shortcut->group = THUNAR_SHORTCUT_GROUP_BOOKMARKS;
shortcut->file = file;
- shortcut->name = g_strdup (dgettext (XDG_USER_DIRS_PACKAGE,
+ shortcut->name = g_strdup (dgettext (XDG_USER_DIRS_PACKAGE,
(gchar *) _thunar_user_directory_names[i]));
/* append the shortcut to the list */
- thunar_shortcuts_model_add_shortcut (model, shortcut, path);
- gtk_tree_path_next (path);
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
}
/* restore the old locale */
setlocale (LC_MESSAGES, old_locale);
g_free(old_locale);
- gtk_tree_path_free (path);
/* we try to save the obtained new model */
thunar_shortcuts_model_save (model);
@@ -1010,11 +1146,11 @@ thunar_shortcuts_model_monitor (GFileMonitor *monitor,
lp = g_list_next (lp);
/* drop the shortcut if it is user-defined */
- if (shortcut->type == THUNAR_SHORTCUT_USER_DEFINED)
+ if (shortcut->group == THUNAR_SHORTCUT_GROUP_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);
@@ -1064,9 +1200,15 @@ thunar_shortcuts_model_save (ThunarShortcutsModel *model)
for (lp = model->shortcuts; lp != NULL; lp = lp->next)
{
shortcut = THUNAR_SHORTCUT (lp->data);
- if (shortcut->type == THUNAR_SHORTCUT_USER_DEFINED)
+ if (shortcut->group == THUNAR_SHORTCUT_GROUP_BOOKMARKS)
{
- uri = thunar_file_dup_uri (shortcut->file);
+ 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))
fprintf (fp, "%s %s\n", uri, shortcut->name);
else
@@ -1106,9 +1248,9 @@ thunar_shortcuts_model_file_changed (ThunarFile *file,
_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
+
+ /* 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)))
@@ -1168,10 +1310,10 @@ thunar_shortcuts_model_volume_changed (GVolumeMonitor *volume_monitor,
ThunarShortcutsModel *model)
{
ThunarShortcut *shortcut = NULL;
- GtkTreePath *path;
GtkTreeIter iter;
GList *lp;
gint idx;
+ GtkTreePath *path;
_thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
_thunar_return_if_fail (model->volume_monitor == volume_monitor);
@@ -1183,36 +1325,25 @@ thunar_shortcuts_model_volume_changed (GVolumeMonitor *volume_monitor,
if (lp != NULL)
{
/* check if we need to display the volume now */
- if (thunar_g_volume_is_removable (volume) && thunar_g_volume_is_present (volume))
+ if (thunar_g_volume_is_removable (volume))
{
/* remove the volume from the list of hidden volumes */
model->hidden_volumes = g_list_delete_link (model->hidden_volumes, lp);
- /* find the insert position */
- for (idx = 0, lp = model->shortcuts; lp != NULL; ++idx, lp = lp->next)
- {
- shortcut = THUNAR_SHORTCUT (lp->data);
- if (shortcut->type == THUNAR_SHORTCUT_SEPARATOR
- || shortcut->type == THUNAR_SHORTCUT_USER_DEFINED)
- break;
- }
-
/* allocate a new shortcut */
shortcut = g_slice_new0 (ThunarShortcut);
- shortcut->type = THUNAR_SHORTCUT_REMOVABLE_MEDIA;
+ shortcut->group = THUNAR_SHORTCUT_GROUP_VOLUMES;
shortcut->volume = volume;
/* the volume is present now, so we have to display it */
- path = gtk_tree_path_new_from_indices (idx, -1);
- thunar_shortcuts_model_add_shortcut (model, shortcut, path);
- gtk_tree_path_free (path);
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
}
}
else
{
/* lookup the shortcut that contains the given volume */
- for (idx = 0, lp = model->shortcuts;
- shortcut == NULL && lp != NULL;
+ for (idx = 0, lp = model->shortcuts;
+ shortcut == NULL && lp != NULL;
++idx, lp = lp->next)
{
if (THUNAR_SHORTCUT (lp->data)->volume == volume)
@@ -1224,10 +1355,10 @@ thunar_shortcuts_model_volume_changed (GVolumeMonitor *volume_monitor,
_thunar_assert (shortcut->volume == volume);
/* check if we need to hide the volume now */
- if (!thunar_g_volume_is_removable (volume) || !thunar_g_volume_is_present (volume))
+ if (!thunar_g_volume_is_removable (volume))
{
/* move the volume to the hidden list */
- model->hidden_volumes = g_list_prepend (model->hidden_volumes,
+ model->hidden_volumes = g_list_prepend (model->hidden_volumes,
g_object_ref (volume));
/* remove the shortcut from the user interface */
@@ -1278,7 +1409,7 @@ thunar_shortcuts_model_volume_removed (GVolumeMonitor *volume_monitor,
_thunar_return_if_fail (model->volume_monitor == volume_monitor);
_thunar_return_if_fail (G_IS_VOLUME (volume));
_thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model));
-
+
lp = g_list_find (model->hidden_volumes, volume);
if (G_LIKELY (lp != NULL))
{
@@ -1304,6 +1435,154 @@ thunar_shortcuts_model_volume_removed (GVolumeMonitor *volume_monitor,
+static gboolean
+thunar_shortcuts_model_has_location (ThunarShortcutsModel *model,
+ GFile *location)
+{
+ GList *lp;
+ ThunarShortcut *shortcut;
+
+ _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE);
+ _thunar_return_val_if_fail (G_IS_FILE (location), FALSE);
+
+ for (lp = model->shortcuts; lp != NULL; lp = lp->next)
+ {
+ shortcut = lp->data;
+
+ /* check if we have a location that matches */
+ if (shortcut->location != NULL
+ && g_file_equal (shortcut->location, location))
+ return TRUE;
+
+ /* check if we have a file that matches */
+ if (shortcut->file != NULL
+ && g_file_equal (thunar_file_get_file (shortcut->file), location))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+static void
+thunar_shortcuts_model_mount_changed (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ ThunarShortcutsModel *model)
+{
+ GList *lp;
+ guint idx;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+ _thunar_return_if_fail (model->volume_monitor == volume_monitor);
+ _thunar_return_if_fail (G_IS_MOUNT (mount));
+ _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model));
+
+ /* find mount */
+ for (lp = model->shortcuts, idx = 0; lp != NULL; lp = lp->next, idx++)
+ if (THUNAR_SHORTCUT (lp->data)->mount == mount)
+ break;
+
+ /* something is broken if we don't have a shortcut here */
+ _thunar_assert (lp != NULL);
+ _thunar_assert (THUNAR_SHORTCUT (lp->data)->mount == mount);
+
+ /* 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);
+}
+
+
+
+static void
+thunar_shortcuts_model_mount_added (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ ThunarShortcutsModel *model)
+{
+ GVolume *volume;
+ GFile *location;
+ ThunarShortcutGroup group;
+ ThunarShortcut *shortcut;
+
+ _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+ _thunar_return_if_fail (model->volume_monitor == volume_monitor);
+ _thunar_return_if_fail (G_IS_MOUNT (mount));
+ _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model));
+
+ /* never show shadowed mounts */
+ if (g_mount_is_shadowed (mount))
+ return;
+
+ /* skip mounts with a volume */
+ volume = g_mount_get_volume (mount);
+ if (volume != NULL)
+ {
+ g_object_unref (volume);
+ return;
+ }
+
+ location = g_mount_get_root (mount);
+
+ /* skip ghoto locations, since those also have a mount
+ * and igore locations already in the model */
+ if (g_file_has_uri_scheme (location, "gphoto2")
+ || thunar_shortcuts_model_has_location (model, location))
+ {
+ g_object_unref (location);
+ return;
+ }
+
+ if (g_file_has_uri_scheme (location, "file")
+ || g_file_has_uri_scheme (location, "archive"))
+ group = THUNAR_SHORTCUT_GROUP_MOUNTS;
+ else
+ group = THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS;
+
+ /* allocate a new shortcut */
+ shortcut = g_slice_new0 (ThunarShortcut);
+ shortcut->group = group;
+ shortcut->location = location;
+ shortcut->mount = g_object_ref (mount);
+
+ /* the mount is present now, so we have to display it */
+ thunar_shortcuts_model_add_shortcut (model, shortcut);
+}
+
+
+
+static void
+thunar_shortcuts_model_mount_removed (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ ThunarShortcutsModel *model)
+{
+ GList *lp;
+
+ _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+ _thunar_return_if_fail (model->volume_monitor == volume_monitor);
+ _thunar_return_if_fail (G_IS_MOUNT (mount));
+ _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model));
+
+ /* find mount */
+ for (lp = model->shortcuts; lp != NULL; lp = lp->next)
+ if (THUNAR_SHORTCUT (lp->data)->mount == mount)
+ break;
+
+ /* something is broken if we don't have a shortcut here */
+ _thunar_assert (lp != NULL);
+ _thunar_assert (THUNAR_SHORTCUT (lp->data)->mount == mount);
+
+ /* drop the shortcut from the model */
+ thunar_shortcuts_model_remove_shortcut (model, lp->data);
+}
+
+
+
static void
thunar_shortcut_free (ThunarShortcut *shortcut,
ThunarShortcutsModel *model)
@@ -1396,7 +1675,7 @@ thunar_shortcuts_model_iter_for_file (ThunarShortcutsModel *model,
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);
@@ -1508,12 +1787,19 @@ thunar_shortcuts_model_drop_possible (ThunarShortcutsModel *model,
/* 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 always possible */
+ /* append to the list is not possible */
if (G_LIKELY (shortcut == NULL))
- return TRUE;
+ return FALSE;
/* cannot drop before special shortcuts! */
- return (shortcut->type == THUNAR_SHORTCUT_USER_DEFINED);
+ if (shortcut->group == THUNAR_SHORTCUT_GROUP_BOOKMARKS)
+ return TRUE;
+
+ /* we can drop at the end of the bookmarks (before network header) */
+ if (shortcut->group == THUNAR_SHORTCUT_GROUP_NETWORK && shortcut->is_header)
+ return TRUE;
+
+ return FALSE;
}
@@ -1548,11 +1834,11 @@ thunar_shortcuts_model_add (ThunarShortcutsModel *model,
/* create the new shortcut that will be inserted */
shortcut = g_slice_new0 (ThunarShortcut);
- shortcut->type = THUNAR_SHORTCUT_USER_DEFINED;
+ shortcut->group = THUNAR_SHORTCUT_GROUP_BOOKMARKS;
shortcut->file = g_object_ref (G_OBJECT (file));
/* add the shortcut to the list at the given position */
- thunar_shortcuts_model_add_shortcut (model, shortcut, dst_path);
+ 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);
@@ -1606,6 +1892,8 @@ thunar_shortcuts_model_move (ThunarShortcutsModel *model,
for (; idx < index_dst; ++idx, lp = lp->next)
{
+ if (lp->next == NULL)
+ break;
lp->data = lp->next->data;
order[idx] = idx + 1;
}
@@ -1675,11 +1963,10 @@ thunar_shortcuts_model_remove (ThunarShortcutsModel *model,
shortcut = g_list_nth_data (model->shortcuts, gtk_tree_path_get_indices (path)[0]);
/* verify that the shortcut is removable */
- _thunar_assert (shortcut->type == THUNAR_SHORTCUT_USER_DEFINED);
- _thunar_assert (THUNAR_IS_FILE (shortcut->file));
+ _thunar_assert (shortcut->group == THUNAR_SHORTCUT_GROUP_BOOKMARKS);
/* remove the shortcut (using the file destroy handler) */
- thunar_shortcuts_model_file_destroy (shortcut->file, model);
+ thunar_shortcuts_model_remove_shortcut (model, shortcut);
}
@@ -1714,7 +2001,7 @@ thunar_shortcuts_model_rename (ThunarShortcutsModel *model,
shortcut = THUNAR_SHORTCUT (((GList *) iter->user_data)->data);
/* verify the shortcut */
- _thunar_assert (shortcut->type == THUNAR_SHORTCUT_USER_DEFINED);
+ _thunar_assert (shortcut->group == THUNAR_SHORTCUT_GROUP_BOOKMARKS);
_thunar_assert (THUNAR_IS_FILE (shortcut->file));
/* perform the rename */
diff --git a/thunar/thunar-shortcuts-model.h b/thunar/thunar-shortcuts-model.h
index 71e897c..7be3034 100644
--- a/thunar/thunar-shortcuts-model.h
+++ b/thunar/thunar-shortcuts-model.h
@@ -36,6 +36,7 @@ typedef struct _ThunarShortcutsModel ThunarShortcutsModel;
/**
* ThunarShortcutsModelColumn:
+ * @THUNAR_SHORTCUTS_MODEL_COLUMN_TYPE : #ThunarShortcutType.
* @THUNAR_SHORTCUTS_MODEL_COLUMN_NAME : the index of the name column.
* @THUNAR_SHORTCUTS_MODEL_COLUMN_FILE : the index of the file column.
* @THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION : file of the location.
@@ -50,17 +51,34 @@ typedef struct _ThunarShortcutsModel ThunarShortcutsModel;
**/
typedef enum
{
+ THUNAR_SHORTCUTS_MODEL_COLUMN_HEADER,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_NOT_HEADER,
THUNAR_SHORTCUTS_MODEL_COLUMN_NAME,
THUNAR_SHORTCUTS_MODEL_COLUMN_FILE,
THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION,
THUNAR_SHORTCUTS_MODEL_COLUMN_GICON,
THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_MOUNT,
THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE,
THUNAR_SHORTCUTS_MODEL_COLUMN_EJECT,
- THUNAR_SHORTCUTS_MODEL_COLUMN_SEPARATOR,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP,
THUNAR_SHORTCUTS_MODEL_N_COLUMNS,
} ThunarShortcutsModelColumn;
+typedef enum
+{
+ THUNAR_SHORTCUT_GROUP_DEVICES,
+ THUNAR_SHORTCUT_GROUP_VOLUMES,
+ THUNAR_SHORTCUT_GROUP_MOUNTS,
+ THUNAR_SHORTCUT_GROUP_PLACES,
+ THUNAR_SHORTCUT_GROUP_TRASH,
+ THUNAR_SHORTCUT_GROUP_BOOKMARKS,
+ THUNAR_SHORTCUT_GROUP_NETWORK,
+ THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS
+} ThunarShortcutGroup;
+
+
+
GType thunar_shortcuts_model_get_type (void) G_GNUC_CONST;
ThunarShortcutsModel *thunar_shortcuts_model_get_default (void);
diff --git a/thunar/thunar-shortcuts-view.c b/thunar/thunar-shortcuts-view.c
index 52103a1..afdb213 100644
--- a/thunar/thunar-shortcuts-view.c
+++ b/thunar/thunar-shortcuts-view.c
@@ -3,18 +3,18 @@
* Copyright (c) 2005-2007 Benedikt Meurer <benny at xfce.org>
* Copyright (c) 2009-2011 Jannis Pohlmann <jannis at xfce.org>
*
- * This program is free software; you can redistribute it and/or
+ * 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
+ * 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
+ * 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
+ * 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.
*/
@@ -128,11 +128,9 @@ static void thunar_shortcuts_view_open (Thunar
gboolean new_window);
static void thunar_shortcuts_view_open_in_new_window_clicked (ThunarShortcutsView *view);
static void thunar_shortcuts_view_empty_trash (ThunarShortcutsView *view);
-static void thunar_shortcuts_view_eject (ThunarShortcutsView *view);
+static void thunar_shortcuts_view_disconnect (ThunarShortcutsView *view);
static void thunar_shortcuts_view_mount (ThunarShortcutsView *view);
-static gboolean thunar_shortcuts_view_separator_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer user_data);
+static void thunar_shortcuts_view_unmount (ThunarShortcutsView *view);
@@ -146,7 +144,7 @@ struct _ThunarShortcutsView
GtkTreeView __parent__;
ThunarPreferences *preferences;
GtkCellRenderer *icon_renderer;
-
+
ThunarxProviderFactory *provider_factory;
/* the currently pressed mouse button, set in the
@@ -230,17 +228,34 @@ thunar_shortcuts_view_class_init (ThunarShortcutsViewClass *klass)
}
+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_HEADER, &is_header, -1);
+ return !is_header;
+}
+
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);
-
+
/* grab a reference on the provider factory */
view->provider_factory = thunarx_provider_factory_get_default ();
@@ -263,6 +278,27 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
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,
+ "weight-set", TRUE,
+ "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_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_NOT_HEADER,
+ 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);
@@ -270,8 +306,12 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
"gicon", THUNAR_SHORTCUTS_MODEL_COLUMN_GICON,
"file", THUNAR_SHORTCUTS_MODEL_COLUMN_FILE,
"volume", THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME,
+ "mount", THUNAR_SHORTCUTS_MODEL_COLUMN_MOUNT,
+ "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_NOT_HEADER,
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.
*/
@@ -288,6 +328,7 @@ thunar_shortcuts_view_init (ThunarShortcutsView *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_NOT_HEADER,
NULL);
/* allocate icon renderer for the eject symbol */
@@ -296,6 +337,7 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_column_set_attributes (column, renderer,
"icon-name", THUNAR_SHORTCUTS_MODEL_COLUMN_EJECT,
+ "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_NOT_HEADER,
NULL);
@@ -309,8 +351,8 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
gtk_drag_dest_set (GTK_WIDGET (view), 0, drop_targets, G_N_ELEMENTS (drop_targets),
GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_MOVE);
- /* setup a row separator function to tell GtkTreeView about the separator */
- gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (view), thunar_shortcuts_view_separator_func, NULL, NULL);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+ gtk_tree_selection_set_select_function (selection, thunar_shortcuts_view_selection_func, NULL, NULL);
}
@@ -398,7 +440,7 @@ thunar_shortcuts_view_button_press_event (GtkWidget *widget,
}
/*
- g_debug("thunar_shortcuts_view_button_press_event(): x: %f, y: %f; my width: %i, eject width: %i, eject: %i",
+ g_debug("thunar_shortcuts_view_button_press_event(): x: %f, y: %f; my width: %i, eject width: %i, eject: %i",
event->x, event->y, column_width, icon_width, view->pressed_eject_button);
*/
@@ -427,7 +469,7 @@ thunar_shortcuts_view_button_release_event (GtkWidget *widget,
if (G_LIKELY (view->pressed_button == (gint) event->button))
{
if (view->pressed_eject_button)
- thunar_shortcuts_view_eject (view);
+ thunar_shortcuts_view_disconnect (view);
/* check if we should simply open or open in new window */
if (G_LIKELY (event->button == 1))
@@ -712,6 +754,8 @@ thunar_shortcuts_view_drag_motion (GtkWidget *widget,
/* 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));
@@ -828,16 +872,19 @@ thunar_shortcuts_view_context_menu (ThunarShortcutsView *view,
GtkTreeModel *model,
GtkTreeIter *iter)
{
- GtkTreePath *path;
- ThunarFile *file;
- GtkWidget *image;
- GtkWidget *menu;
- GtkWidget *item;
- GtkWidget *window;
- gboolean mutable;
- GVolume *volume;
- GList *providers, *lp;
- GList *actions = NULL, *tmp;
+ GtkTreePath *path;
+ ThunarFile *file;
+ GtkWidget *image;
+ GtkWidget *menu;
+ GtkWidget *item;
+ GtkWidget *window;
+ gboolean mutable;
+ GVolume *volume;
+ GMount *mount;
+ GMount *volume_mount;
+ GList *providers, *lp;
+ GList *actions = NULL, *tmp;
+ ThunarShortcutGroup group;
/* determine the tree path for the given iter */
path = gtk_tree_model_get_path (model, iter);
@@ -848,7 +895,9 @@ thunar_shortcuts_view_context_menu (ThunarShortcutsView *view,
gtk_tree_model_get (model, iter,
THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, &file,
THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME, &volume,
- THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE, &mutable,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_MOUNT, &mount,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_MUTABLE, &mutable,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP, &group,
-1);
/* prepare the popup menu */
@@ -870,49 +919,70 @@ thunar_shortcuts_view_context_menu (ThunarShortcutsView *view,
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show (item);
- /* append a menu separator */
- item = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
-
/* check if we have a volume here */
- if (G_UNLIKELY (volume != NULL))
+ switch (group)
{
- /* append the "Mount Volume" menu action */
- item = gtk_image_menu_item_new_with_mnemonic (_("_Mount Volume"));
- gtk_widget_set_sensitive (item, !thunar_g_volume_is_mounted (volume));
- g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_mount), view);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
+ case THUNAR_SHORTCUT_GROUP_VOLUMES:
+ /* append a menu separator */
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
+
+ volume_mount = g_volume_get_mount (volume);
+
+ /* append the "Mount" item */
+ item = gtk_image_menu_item_new_with_mnemonic (_("_Mount"));
+ gtk_widget_set_visible (item, volume_mount == NULL && g_volume_can_mount (volume));
+ 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, volume_mount != NULL && g_mount_can_unmount (volume_mount));
+ 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 (_("Disconn_ect"));
+ gtk_widget_set_visible (item, (volume_mount != NULL && g_mount_can_eject (volume_mount)) || g_volume_can_eject (volume));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_disconnect), view);
+
+ if (volume_mount != NULL)
+ g_object_unref (volume_mount);
+ break;
- /* check if the volume is present and can be ejected */
- if (thunar_g_volume_is_present (volume) && thunar_g_volume_is_removable (volume))
- {
- /* append the "Eject Volume" menu action */
- item = gtk_image_menu_item_new_with_mnemonic (_("E_ject Volume"));
- 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);
- }
+ case THUNAR_SHORTCUT_GROUP_MOUNTS:
+ 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);
+
+ /* append the "Disconnect" item */
+ item = gtk_image_menu_item_new_with_mnemonic (_("Disconn_ect"));
+ g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_disconnect), view);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
+ break;
- /* append a menu separator */
- item = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
- }
- else if (G_UNLIKELY (file != NULL && thunar_file_is_trashed (file) && thunar_file_is_root (file)))
- {
- /* 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);
- /* append a menu separator */
- item = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
+ case THUNAR_SHORTCUT_GROUP_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 */
@@ -934,6 +1004,14 @@ thunar_shortcuts_view_context_menu (ThunarShortcutsView *view,
}
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)
{
@@ -945,43 +1023,43 @@ thunar_shortcuts_view_context_menu (ThunarShortcutsView *view,
g_object_unref (G_OBJECT (lp->data));
}
- /* add a separator to the end of the menu */
- if (G_LIKELY (lp != actions))
- {
- /* append a menu separator */
- item = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
- }
-
/* cleanup */
g_list_free (actions);
}
}
/* append the remove menu 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), view);
- gtk_widget_set_sensitive (item, mutable);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
+ if (group == THUNAR_SHORTCUT_GROUP_BOOKMARKS)
+ {
+ /* append a menu separator */
+ item = gtk_separator_menu_item_new ();
+ 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);
+ 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), view);
+ gtk_widget_set_sensitive (item, mutable);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
- /* 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);
+ /* 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);
+ }
/* 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,
@@ -992,6 +1070,8 @@ thunar_shortcuts_view_context_menu (ThunarShortcutsView *view,
g_object_unref (G_OBJECT (file));
if (G_UNLIKELY (volume != NULL))
g_object_unref (G_OBJECT (volume));
+ if (G_UNLIKELY (mount != NULL))
+ g_object_unref (G_OBJECT (mount));
gtk_tree_path_free (path);
}
@@ -1034,7 +1114,7 @@ thunar_shortcuts_view_rename_activated (GtkWidget *item,
/* 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, 1);
+ renderer = g_list_nth_data (renderers, 3);
/* make sure the text renderer is editable */
g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
@@ -1142,6 +1222,9 @@ thunar_shortcuts_view_compute_drop_actions (ThunarShortcutsView *view,
/* 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))
{
@@ -1176,7 +1259,7 @@ thunar_shortcuts_view_compute_drop_position (ThunarShortcutsView *view,
GtkTreeViewColumn *column;
GtkTreeModel *model;
GdkRectangle area;
- GtkTreePath *path;
+ GtkTreePath *path = NULL;
gint n_rows;
_thunar_return_val_if_fail (gtk_tree_view_get_model (GTK_TREE_VIEW (view)) != NULL, NULL);
@@ -1189,7 +1272,7 @@ thunar_shortcuts_view_compute_drop_position (ThunarShortcutsView *view,
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
+ /* 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);
@@ -1200,14 +1283,11 @@ thunar_shortcuts_view_compute_drop_position (ThunarShortcutsView *view,
for (; gtk_tree_path_get_indices (path)[0] < n_rows; gtk_tree_path_next (path))
if (thunar_shortcuts_model_drop_possible (THUNAR_SHORTCUTS_MODEL (model), path))
return path;
- }
- else
- {
- /* we'll append to the shortcuts list */
- path = gtk_tree_path_new_from_indices (n_rows, -1);
+
+ gtk_tree_path_free (path);
}
- return path;
+ return NULL;
}
@@ -1284,7 +1364,7 @@ thunar_shortcuts_view_poke_file_finish (ThunarBrowser *browser,
gboolean new_window = GPOINTER_TO_UINT (user_data);
_thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (browser));
- _thunar_return_if_fail (THUNAR_IS_FILE (file));
+ _thunar_return_if_fail (THUNAR_IS_FILE (target_file));
if (error == NULL)
{
@@ -1292,7 +1372,7 @@ thunar_shortcuts_view_poke_file_finish (ThunarBrowser *browser,
{
/* open a new window for the target folder */
application = thunar_application_get ();
- thunar_application_open_window (application, target_file,
+ thunar_application_open_window (application, target_file,
gtk_widget_get_screen (GTK_WIDGET (browser)), NULL);
g_object_unref (application);
}
@@ -1321,15 +1401,25 @@ thunar_shortcuts_view_poke_location_finish (ThunarBrowser *browser,
{
ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (browser);
GtkTreeModel *model;
+ gchar *name;
_thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (browser));
- _thunar_return_if_fail (THUNAR_IS_FILE (file));
+ _thunar_return_if_fail (G_IS_FILE (location));
/* sotre the new file in the shortcuts model */
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
- thunar_shortcuts_model_set_file (THUNAR_SHORTCUTS_MODEL (model), location, file);
+ if (error == NULL)
+ {
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+ thunar_shortcuts_model_set_file (THUNAR_SHORTCUTS_MODEL (model), location, file);
- thunar_shortcuts_view_poke_file_finish (browser, file, target_file, error, user_data);
+ thunar_shortcuts_view_poke_file_finish (browser, file, target_file, error, user_data);
+ }
+ else
+ {
+ name = thunar_g_file_get_display_name (location);
+ thunar_dialogs_show_error (GTK_WIDGET (browser), error, _("Failed to open \"%s\""), name);
+ g_free (name);
+ }
}
@@ -1356,7 +1446,7 @@ thunar_shortcuts_view_poke_volume_finish (ThunarBrowser *browser,
else
{
volume_name = g_volume_get_name (volume);
- thunar_dialogs_show_error (GTK_WIDGET (browser), error,
+ thunar_dialogs_show_error (GTK_WIDGET (browser), error,
_("Failed to mount \"%s\""), volume_name);
g_free (volume_name);
}
@@ -1387,7 +1477,7 @@ thunar_shortcuts_view_open (ThunarShortcutsView *view,
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,
+ gtk_tree_model_get (model, &iter,
THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, &file,
THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME, &volume,
THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION, &location,
@@ -1399,7 +1489,7 @@ thunar_shortcuts_view_open (ThunarShortcutsView *view,
thunar_shortcuts_view_poke_volume_finish,
GUINT_TO_POINTER (new_window));
}
- else if (file != NULL)
+ else if (file != NULL)
{
thunar_browser_poke_file (THUNAR_BROWSER (view), file, view,
thunar_shortcuts_view_poke_file_finish,
@@ -1450,9 +1540,9 @@ thunar_shortcuts_view_empty_trash (ThunarShortcutsView *view)
static void
-thunar_shortcuts_view_eject_finish (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+thunar_shortcuts_view_eject_volume_finish (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (user_data);
GtkWidget *window;
@@ -1491,6 +1581,47 @@ thunar_shortcuts_view_eject_finish (GObject *object,
static void
+thunar_shortcuts_view_eject_mount_finish (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (user_data);
+ GtkWidget *window;
+ GMount *mount = G_MOUNT (object);
+ GError *error = NULL;
+ gchar *mount_name;
+
+ _thunar_return_if_fail (G_IS_MOUNT (object));
+ _thunar_return_if_fail (G_IS_ASYNC_RESULT (result));
+ _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+
+ /* check if there was an error */
+ if (!g_mount_eject_with_operation_finish (mount, result, &error))
+ {
+ /* ignore GIO errors already handled */
+ if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_FAILED_HANDLED)
+ {
+ window = gtk_widget_get_toplevel (GTK_WIDGET (view));
+
+ /* display an error dialog to inform the user */
+ mount_name = g_mount_get_name (mount);
+ thunar_dialogs_show_error (window, error, _("Failed to eject \"%s\""), mount_name);
+ g_free (mount_name);
+
+ g_error_free (error);
+ }
+ }
+
+#ifdef HAVE_LIBNOTIFY
+ thunar_notify_unmount_finish (mount);
+#endif
+
+ g_object_unref (view);
+}
+
+
+
+static void
thunar_shortcuts_view_unmount_finish (GObject *object,
GAsyncResult *result,
gpointer user_data)
@@ -1532,13 +1663,14 @@ thunar_shortcuts_view_unmount_finish (GObject *object,
static void
-thunar_shortcuts_view_eject (ThunarShortcutsView *view)
+thunar_shortcuts_view_disconnect (ThunarShortcutsView *view)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
GVolume *volume;
GMount *mount;
+ GMount *volume_mount;
GMountOperation *mount_operation;
GtkWidget *window;
@@ -1546,52 +1678,109 @@ thunar_shortcuts_view_eject (ThunarShortcutsView *view)
/* determine the selected item */
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
- if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ /* determine the volume/mount for the shortcut at the given tree iterator */
+ gtk_tree_model_get (model, &iter,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME, &volume,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_MOUNT, &mount, -1);
+
+ _thunar_return_if_fail (volume == NULL || G_IS_VOLUME (volume));
+ _thunar_return_if_fail (mount == NULL || G_IS_MOUNT (mount));
+
+ /* prepare a mount operation */
+ window = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ mount_operation = gtk_mount_operation_new (GTK_WINDOW (window));
+
+ if (mount != NULL)
{
- /* determine the volume for the shortcut at the given tree iterator */
- gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME, &volume, -1);
- if (G_UNLIKELY (volume != NULL))
+ /* distinguish between ejectable and unmountable mounts */
+ if (g_mount_can_eject (mount))
{
- /* prepare a mount operation */
- window = gtk_widget_get_toplevel (GTK_WIDGET (view));
- mount_operation = gtk_mount_operation_new (GTK_WINDOW (window));
+#ifdef HAVE_LIBNOTIFY
+ thunar_notify_unmount (mount);
+#endif
- /* determine what the appropriate method is: eject or unmount */
- if (g_volume_can_eject (volume))
- {
+ /* try ejecting the mount */
+ g_mount_eject_with_operation (mount,
+ G_MOUNT_UNMOUNT_NONE,
+ mount_operation,
+ NULL,
+ thunar_shortcuts_view_eject_mount_finish,
+ g_object_ref (view));
+ }
+ else if (g_mount_can_unmount (mount))
+ {
#ifdef HAVE_LIBNOTIFY
- thunar_notify_eject (volume);
+ thunar_notify_unmount (mount);
#endif
- /* try to to eject the volume asynchronously */
- g_volume_eject_with_operation (volume, G_MOUNT_UNMOUNT_NONE, mount_operation, NULL,
- thunar_shortcuts_view_eject_finish,
- g_object_ref (view));
- }
- else
+ /* try unmounting the mount */
+ g_mount_unmount_with_operation (mount,
+ G_MOUNT_UNMOUNT_NONE,
+ mount_operation,
+ NULL,
+ thunar_shortcuts_view_unmount_finish,
+ g_object_ref (view));
+ }
+
+ g_object_unref (mount);
+ }
+ else if (volume != NULL)
+ {
+ if (g_volume_can_eject (volume))
+ {
+#ifdef HAVE_LIBNOTIFY
+ thunar_notify_eject (volume);
+#endif
+ /* try ejecting the volume */
+ g_volume_eject_with_operation (volume,
+ G_MOUNT_UNMOUNT_NONE,
+ mount_operation,
+ NULL,
+ thunar_shortcuts_view_eject_volume_finish,
+ g_object_ref (view));
+ }
+ else
+ {
+ volume_mount = g_volume_get_mount (volume);
+ if (volume_mount != NULL)
{
- /* determine the mount of the volume */
- mount = g_volume_get_mount (volume);
- if (G_LIKELY (mount != NULL))
+ /* distinguish between ejectable and unmountable mounts */
+ if (g_mount_can_eject (volume_mount))
+ {
+#ifdef HAVE_LIBNOTIFY
+ thunar_notify_unmount (volume_mount);
+#endif
+
+ g_mount_eject_with_operation (mount,
+ G_MOUNT_UNMOUNT_NONE,
+ mount_operation,
+ NULL,
+ thunar_shortcuts_view_eject_mount_finish,
+ g_object_ref (view));
+ }
+ else if (g_mount_can_unmount (volume_mount))
{
#ifdef HAVE_LIBNOTIFY
- thunar_notify_unmount (mount);
+ thunar_notify_unmount (volume_mount);
#endif
- /* the volume is mounted, try to unmount the mount */
- g_mount_unmount_with_operation (mount, G_MOUNT_UNMOUNT_NONE, mount_operation, NULL,
+ /* try unmounting the mount */
+ g_mount_unmount_with_operation (mount,
+ G_MOUNT_UNMOUNT_NONE,
+ mount_operation,
+ NULL,
thunar_shortcuts_view_unmount_finish,
g_object_ref (view));
-
- /* release the mount */
- g_object_unref (mount);
}
- }
- /* cleanup */
- g_object_unref (volume);
- g_object_unref (mount_operation);
+ g_object_unref (volume_mount);
+ }
}
+
+ g_object_unref (volume);
}
}
@@ -1612,7 +1801,7 @@ thunar_shortcuts_view_poke_volume_mount_finish (ThunarBrowser *browser,
if (error != NULL)
{
volume_name = g_volume_get_name (volume);
- thunar_dialogs_show_error (GTK_WIDGET (browser), error,
+ thunar_dialogs_show_error (GTK_WIDGET (browser), error,
_("Failed to mount \"%s\""), volume_name);
g_free (volume_name);
}
@@ -1641,8 +1830,8 @@ thunar_shortcuts_view_mount (ThunarShortcutsView *view)
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_VOLUME, &volume,
+ gtk_tree_model_get (model, &iter,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME, &volume,
-1);
if (G_LIKELY (volume != NULL))
@@ -1657,14 +1846,85 @@ thunar_shortcuts_view_mount (ThunarShortcutsView *view)
-static gboolean
-thunar_shortcuts_view_separator_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer user_data)
+static void
+thunar_shortcuts_view_unmount (ThunarShortcutsView *view)
{
- gboolean separator;
- gtk_tree_model_get (model, iter, THUNAR_SHORTCUTS_MODEL_COLUMN_SEPARATOR, &separator, -1);
- return separator;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GVolume *volume;
+ GMount *mount;
+ GMount *volume_mount;
+ GMountOperation *mount_operation;
+ GtkWidget *window;
+
+ _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 volume/mount for the shortcut at the given tree iterator */
+ gtk_tree_model_get (model, &iter,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME, &volume,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_MOUNT, &mount, -1);
+
+ _thunar_return_if_fail (volume == NULL || G_IS_VOLUME (volume));
+ _thunar_return_if_fail (mount == NULL || G_IS_MOUNT (mount));
+
+ /* prepare a mount operation */
+ window = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ mount_operation = gtk_mount_operation_new (GTK_WINDOW (window));
+
+ if (mount != NULL)
+ {
+ /* only handle mounts that can be unmounted here */
+ if (g_mount_can_unmount (mount))
+ {
+#ifdef HAVE_LIBNOTIFY
+ thunar_notify_unmount (mount);
+#endif
+
+ /* try unmounting the mount */
+ g_mount_unmount_with_operation (mount,
+ G_MOUNT_UNMOUNT_NONE,
+ mount_operation,
+ NULL,
+ thunar_shortcuts_view_unmount_finish,
+ g_object_ref (view));
+ }
+
+ g_object_unref (mount);
+ }
+ else if (volume != NULL)
+ {
+ volume_mount = g_volume_get_mount (volume);
+ if (volume_mount != NULL)
+ {
+ /* only handle mounts that can be unmounted here */
+ if (g_mount_can_unmount (volume_mount))
+ {
+#ifdef HAVE_LIBNOTIFY
+ thunar_notify_unmount (volume_mount);
+#endif
+
+ /* try unmounting the mount */
+ g_mount_unmount_with_operation (volume_mount,
+ G_MOUNT_UNMOUNT_NONE,
+ mount_operation,
+ NULL,
+ thunar_shortcuts_view_unmount_finish,
+ g_object_ref (view));
+ }
+
+ g_object_unref (volume_mount);
+ }
+
+ g_object_unref (volume);
+ }
+
+ g_object_unref (mount_operation);
+ }
}
More information about the Xfce4-commits
mailing list