Inserts a separator row (IS_SEPARATOR column) between local and remote bookmarks in the shortcuts model; the progress renderer draws it as a line. This is what thunar 4.20.2-1~bpo24.04+usagebars1 was built from.
2529 lines
77 KiB
C
2529 lines
77 KiB
C
/* 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 "thunar/thunar-device-monitor.h"
|
|
#include "thunar/thunar-file.h"
|
|
#include "thunar/thunar-preferences.h"
|
|
#include "thunar/thunar-private.h"
|
|
#include "thunar/thunar-shortcuts-model.h"
|
|
#include "thunar/thunar-util.h"
|
|
|
|
#include <glib.h>
|
|
#include <glib/gstdio.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 (ThunarShortcut *shortcut,
|
|
ThunarShortcutsModel *model);
|
|
static gboolean
|
|
thunar_shortcuts_model_load_bookmarks (gpointer data);
|
|
static void
|
|
thunar_shortcuts_model_save_bookmarks (ThunarShortcutsModel *model);
|
|
static void
|
|
thunar_shortcuts_model_monitor_bookmarks_file (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
gpointer user_data);
|
|
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_shortcuts_model_file_changed (ThunarFile *file,
|
|
ThunarShortcutsModel *model);
|
|
static void
|
|
thunar_shortcuts_model_file_destroyed (ThunarFile *file,
|
|
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;
|
|
|
|
gboolean bookmark_separator_added;
|
|
};
|
|
|
|
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;
|
|
guint is_separator : 1;
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
ThunarShortcutsModel *model;
|
|
ThunarShortcut *shortcut;
|
|
gboolean update_visibility;
|
|
} ThunarShortcutFileGetData;
|
|
|
|
|
|
|
|
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,
|
|
TRUE,
|
|
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 ();
|
|
g_object_bind_property (model->preferences, "hidden-bookmarks",
|
|
model, "hidden-bookmarks",
|
|
G_BINDING_SYNC_CREATE);
|
|
|
|
/* binary file size */
|
|
g_object_bind_property (model->preferences, "misc-file-size-binary",
|
|
model, "file-size-binary",
|
|
G_BINDING_SYNC_CREATE);
|
|
|
|
/* 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) (void (*) (void)) 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_by_data (model->device_monitor, 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;
|
|
|
|
case THUNAR_SHORTCUTS_MODEL_COLUMN_HIDDEN:
|
|
return G_TYPE_BOOLEAN;
|
|
|
|
case THUNAR_SHORTCUTS_MODEL_COLUMN_USAGE_PERCENT:
|
|
return G_TYPE_INT;
|
|
|
|
case THUNAR_SHORTCUTS_MODEL_COLUMN_IS_SEPARATOR:
|
|
return G_TYPE_BOOLEAN;
|
|
}
|
|
|
|
_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;
|
|
GFile *file;
|
|
gboolean can_eject;
|
|
gboolean file_size_binary;
|
|
gchar *disk_usage;
|
|
gchar *device_name;
|
|
gchar *device_id;
|
|
gchar *location;
|
|
gchar *tooltip;
|
|
guint32 trash_items;
|
|
gchar *parse_name;
|
|
|
|
_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)
|
|
{
|
|
/* get Unix device path */
|
|
if (shortcut->device != NULL)
|
|
device_id = thunar_device_get_identifier_unix (shortcut->device);
|
|
else
|
|
device_id = NULL;
|
|
|
|
/* get device root directory */
|
|
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)
|
|
{
|
|
if (g_file_has_uri_scheme (file, "file") && thunar_g_file_is_root (file))
|
|
location = g_strdup (_("Browse the file system"));
|
|
else if (!g_file_has_uri_scheme (file, "file"))
|
|
location = g_file_get_uri (file);
|
|
else
|
|
location = thunar_g_file_get_location (file);
|
|
|
|
if (device_id != NULL)
|
|
{
|
|
gchar *tmp = g_strdup_printf ("%s (%s)", location, device_id);
|
|
g_free (location);
|
|
g_free (device_id);
|
|
location = tmp;
|
|
}
|
|
|
|
file_size_binary = THUNAR_SHORTCUTS_MODEL (tree_model)->file_size_binary;
|
|
disk_usage = thunar_g_file_get_free_space_string (file, file_size_binary);
|
|
|
|
if (disk_usage != NULL)
|
|
tooltip = g_strdup_printf ("%s\n%s", location, disk_usage);
|
|
else
|
|
tooltip = g_strdup_printf ("%s", location);
|
|
|
|
g_value_take_string (value, tooltip);
|
|
|
|
g_free (location);
|
|
g_free (disk_usage);
|
|
|
|
g_object_unref (file);
|
|
}
|
|
else
|
|
{
|
|
if (device_id != NULL)
|
|
{
|
|
device_name = thunar_device_get_name (shortcut->device);
|
|
tooltip = g_strdup_printf (_("Mount and open %s (%s)"), device_name, device_id);
|
|
g_value_take_string (value, tooltip);
|
|
g_free (device_name);
|
|
g_free (device_id);
|
|
}
|
|
}
|
|
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
|
|
{
|
|
tooltip = g_strdup_printf (ngettext ("Trash contains %d file",
|
|
"Trash contains %d files",
|
|
trash_items),
|
|
trash_items);
|
|
g_value_take_string (value, tooltip);
|
|
}
|
|
break;
|
|
}
|
|
else if (shortcut->tooltip == NULL)
|
|
{
|
|
if (shortcut->device != NULL)
|
|
{
|
|
file = thunar_device_get_root (shortcut->device);
|
|
if (G_LIKELY (file != NULL))
|
|
{
|
|
shortcut->tooltip = g_file_get_uri (file);
|
|
g_object_unref (file);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
|
|
case THUNAR_SHORTCUTS_MODEL_COLUMN_HIDDEN:
|
|
g_value_init (value, G_TYPE_BOOLEAN);
|
|
g_value_set_boolean (value, FALSE);
|
|
break;
|
|
|
|
case THUNAR_SHORTCUTS_MODEL_COLUMN_IS_SEPARATOR:
|
|
g_value_init (value, G_TYPE_BOOLEAN);
|
|
g_value_set_boolean (value, shortcut->is_separator);
|
|
break;
|
|
|
|
case THUNAR_SHORTCUTS_MODEL_COLUMN_USAGE_PERCENT:
|
|
g_value_init (value, G_TYPE_INT);
|
|
if ((shortcut->group & THUNAR_SHORTCUT_GROUP_DEVICES) != 0
|
|
&& (shortcut->group & THUNAR_SHORTCUT_GROUP_HEADER) == 0)
|
|
{
|
|
guint64 fs_free = 0, fs_total = 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
|
|
&& thunar_g_file_get_free_space (file, &fs_free, &fs_total)
|
|
&& fs_total > 0)
|
|
{
|
|
g_value_set_int (value, (gint) ((fs_total - fs_free) * 100 / fs_total));
|
|
}
|
|
else
|
|
{
|
|
g_value_set_int (value, -1);
|
|
}
|
|
|
|
if (file != NULL)
|
|
g_object_unref (file);
|
|
}
|
|
else
|
|
{
|
|
g_value_set_int (value, -1);
|
|
}
|
|
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->tooltip = g_strdup (_("Browse the 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);
|
|
|
|
/* append the browse network entry if it is supported */
|
|
if (thunar_g_vfs_is_uri_scheme_supported ("network"))
|
|
{
|
|
shortcut = g_slice_new0 (ThunarShortcut);
|
|
shortcut->group = THUNAR_SHORTCUT_GROUP_NETWORK_DEFAULT;
|
|
shortcut->name = g_strdup (_("Browse Network"));
|
|
shortcut->tooltip = g_strdup (_("Browse local network connections"));
|
|
shortcut->location = thunar_g_file_new_for_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->tooltip = g_strdup (_("Open the home folder"));
|
|
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->tooltip = g_strdup (_("Open the desktop folder"));
|
|
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->name = g_strdup (_("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_bookmarks_file), model);
|
|
}
|
|
|
|
/* read the Gtk+ bookmarks file */
|
|
if (model->bookmarks_idle_id == 0)
|
|
model->bookmarks_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT, thunar_shortcuts_model_load_bookmarks, model, NULL);
|
|
|
|
/* append the computer icon if browsing the computer is supported */
|
|
if (thunar_g_vfs_is_uri_scheme_supported ("computer"))
|
|
{
|
|
shortcut = g_slice_new0 (ThunarShortcut);
|
|
shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_COMPUTER;
|
|
shortcut->name = g_strdup (_("Computer"));
|
|
shortcut->tooltip = g_strdup (_("Browse the computer"));
|
|
shortcut->location = thunar_g_file_new_for_computer ();
|
|
shortcut->gicon = g_themed_icon_new ("computer");
|
|
shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut);
|
|
thunar_shortcuts_model_add_shortcut (model, shortcut);
|
|
}
|
|
|
|
/* append the recent icon if browsing recent is supported */
|
|
if (thunar_g_vfs_is_uri_scheme_supported ("recent"))
|
|
{
|
|
shortcut = g_slice_new0 (ThunarShortcut);
|
|
shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_RECENT;
|
|
shortcut->name = g_strdup (_("Recent"));
|
|
shortcut->tooltip = g_strdup (_("Browse recently used files"));
|
|
shortcut->location = thunar_g_file_new_for_recent ();
|
|
shortcut->gicon = g_themed_icon_new ("document-open-recent");
|
|
shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut);
|
|
thunar_shortcuts_model_add_shortcut (model, shortcut);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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
|
|
{
|
|
g_warn_if_reached ();
|
|
return FALSE;
|
|
}
|
|
|
|
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;
|
|
|
|
if (a->device != NULL && b->device != NULL)
|
|
return thunar_device_compare_by_name (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));
|
|
|
|
if (G_LIKELY (shortcut->file != NULL))
|
|
{
|
|
/* enable monitoring for the file */
|
|
thunar_file_watch (shortcut->file);
|
|
|
|
/* subscribe to relevant signals */
|
|
g_signal_connect (G_OBJECT (shortcut->file), "destroy", G_CALLBACK (thunar_shortcuts_model_file_destroyed), model);
|
|
g_signal_connect (G_OBJECT (shortcut->file), "changed", G_CALLBACK (thunar_shortcuts_model_file_changed), 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 (ThunarShortcut *shortcut,
|
|
ThunarShortcutsModel *model)
|
|
{
|
|
GtkTreePath *path;
|
|
gint idx;
|
|
|
|
/* 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);
|
|
|
|
/* actually free the shortcut */
|
|
thunar_shortcut_free (shortcut, 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));
|
|
|
|
/* insert a separator before the first remote bookmark */
|
|
if (!thunar_shortcuts_model_local_file (file_path)
|
|
&& !model->bookmark_separator_added)
|
|
{
|
|
ThunarShortcut *sep = g_slice_new0 (ThunarShortcut);
|
|
sep->group = THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS;
|
|
sep->is_separator = TRUE;
|
|
sep->sort_id = row_num;
|
|
thunar_shortcuts_model_add_shortcut (model, sep);
|
|
model->bookmark_separator_added = TRUE;
|
|
}
|
|
|
|
shortcut = g_slice_new0 (ThunarShortcut);
|
|
shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS;
|
|
shortcut->location = g_object_ref (file_path);
|
|
|
|
/* handle local and remote files differently */
|
|
/* If we dont have a thunar-file, we need to set the gicon manually */
|
|
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))
|
|
shortcut->gicon = g_themed_icon_new ("folder");
|
|
else
|
|
shortcut->file = file;
|
|
}
|
|
else
|
|
{
|
|
shortcut->gicon = g_themed_icon_new ("folder-remote");
|
|
}
|
|
|
|
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_bookmarks (gpointer data)
|
|
{
|
|
ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (data);
|
|
|
|
_thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE);
|
|
|
|
/* 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);
|
|
|
|
model->bookmarks_idle_id = 0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
thunar_shortcuts_model_reload_bookmarks (gpointer data)
|
|
{
|
|
ThunarShortcutsModel *model = THUNAR_SHORTCUTS_MODEL (data);
|
|
GList *lp;
|
|
GList *places_bookmarks = NULL;
|
|
|
|
_thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE);
|
|
|
|
/* reset separator flag */
|
|
model->bookmark_separator_added = FALSE;
|
|
|
|
/* Find all user-defined shortcuts (bookmarks) */
|
|
for (lp = model->shortcuts; lp != NULL; lp = lp->next)
|
|
{
|
|
ThunarShortcut *shortcut = THUNAR_SHORTCUT (lp->data);
|
|
if (shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS)
|
|
places_bookmarks = g_list_append (places_bookmarks, shortcut);
|
|
}
|
|
|
|
/* drop them from the model */
|
|
g_list_foreach (places_bookmarks, (GFunc) (void (*) (void)) thunar_shortcuts_model_remove_shortcut, model);
|
|
g_list_free (places_bookmarks);
|
|
|
|
/* reload them from the bookmarks file */
|
|
thunar_shortcuts_model_load_bookmarks (model);
|
|
|
|
/* reset the idle ID */
|
|
model->bookmarks_idle_id = 0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
thunar_shortcuts_model_monitor_bookmarks_file (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 bookmarks when idle */
|
|
if (model->bookmarks_idle_id == 0)
|
|
model->bookmarks_idle_id = g_idle_add (thunar_shortcuts_model_reload_bookmarks, model);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
thunar_shortcuts_model_save_bookmarks (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_device_added_callback (GFile *location,
|
|
ThunarFile *file,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
ThunarShortcutFileGetData *data = user_data;
|
|
ThunarShortcut *shortcut = data->shortcut;
|
|
ThunarShortcutsModel *model = data->model;
|
|
|
|
if (error == NULL)
|
|
{
|
|
shortcut->file = g_object_ref (file);
|
|
|
|
/* insert in the model */
|
|
thunar_shortcuts_model_add_shortcut (model, shortcut);
|
|
|
|
if (data->update_visibility)
|
|
thunar_shortcuts_model_header_visibility (model);
|
|
}
|
|
|
|
g_object_unref (location);
|
|
g_object_unref (model);
|
|
g_slice_free (ThunarShortcutFileGetData, data);
|
|
}
|
|
|
|
static void
|
|
thunar_shortcuts_model_device_added (ThunarDeviceMonitor *device_monitor,
|
|
ThunarDevice *device,
|
|
ThunarShortcutsModel *model)
|
|
{
|
|
ThunarShortcut *shortcut;
|
|
ThunarShortcutFileGetData *data;
|
|
GFile *mount_point;
|
|
|
|
_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;
|
|
}
|
|
|
|
/* header visibility if call is from monitor */
|
|
gboolean update_visibility = (device_monitor != NULL && !shortcut->hidden);
|
|
|
|
mount_point = thunar_device_get_root (device);
|
|
if (mount_point != NULL)
|
|
{
|
|
data = g_slice_new0 (ThunarShortcutFileGetData);
|
|
data->shortcut = shortcut;
|
|
data->model = g_object_ref (model);
|
|
data->update_visibility = update_visibility;
|
|
|
|
thunar_file_get_async (mount_point, NULL, &thunar_shortcuts_model_device_added_callback, data);
|
|
}
|
|
else /* some devices (e.g. usb flashdrives) do not have a mountpoint */
|
|
{
|
|
/* insert in the model */
|
|
thunar_shortcuts_model_add_shortcut (model, shortcut);
|
|
|
|
if (update_visibility)
|
|
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 */
|
|
if (lp == NULL)
|
|
{
|
|
g_warning ("No shortcut found for device '%s'", thunar_device_get_name (device));
|
|
return;
|
|
}
|
|
|
|
_thunar_assert (THUNAR_SHORTCUT (lp->data)->device == device);
|
|
|
|
/* drop the shortcut from the model */
|
|
if (G_LIKELY (lp != NULL))
|
|
thunar_shortcuts_model_remove_shortcut (lp->data, model);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
thunar_shortcuts_model_device_changed (ThunarDeviceMonitor *device_monitor,
|
|
ThunarDevice *device,
|
|
ThunarShortcutsModel *model)
|
|
{
|
|
GtkTreeIter iter;
|
|
GList *lp;
|
|
gint idx;
|
|
GtkTreePath *path;
|
|
ThunarShortcut *shortcut;
|
|
GFile *mount_point;
|
|
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 */
|
|
if (lp == NULL)
|
|
{
|
|
g_warning ("No shortcut found for device '%s'", thunar_device_get_name (device));
|
|
return;
|
|
}
|
|
|
|
_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;
|
|
|
|
if (shortcut->file == NULL)
|
|
{
|
|
mount_point = thunar_device_get_root (device);
|
|
if (mount_point != NULL)
|
|
{
|
|
shortcut->file = thunar_file_get (mount_point, NULL);
|
|
|
|
/* enable monitoring for the file */
|
|
if (shortcut->file != NULL)
|
|
thunar_file_watch (shortcut->file);
|
|
|
|
g_object_unref (mount_point);
|
|
}
|
|
}
|
|
|
|
/* 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_shortcuts_model_file_destroyed (ThunarFile *file,
|
|
ThunarShortcutsModel *model)
|
|
{
|
|
GtkTreeIter iter;
|
|
GList *lp;
|
|
gint idx;
|
|
GtkTreePath *path;
|
|
|
|
/* find the shortcut */
|
|
for (lp = model->shortcuts, idx = 0; lp != NULL; lp = lp->next, idx++)
|
|
{
|
|
ThunarShortcut *shortcut = THUNAR_SHORTCUT (lp->data);
|
|
if (shortcut->file == file)
|
|
{
|
|
/* Disconnect from relevant signals */
|
|
thunar_file_unwatch (file);
|
|
g_signal_handlers_disconnect_by_data (shortcut->file, model);
|
|
g_object_unref (shortcut->file);
|
|
shortcut->file = NULL;
|
|
|
|
/* remove the thunar file from the list and set the g_file instead */
|
|
if (shortcut->location == NULL)
|
|
{
|
|
shortcut->location = g_object_ref (thunar_file_get_file (file)) ;
|
|
}
|
|
|
|
if (shortcut->gicon == NULL)
|
|
{
|
|
if (thunar_shortcuts_model_local_file (shortcut->location))
|
|
shortcut->gicon = g_themed_icon_new ("folder");
|
|
else
|
|
shortcut->gicon = g_themed_icon_new ("folder-remote");
|
|
}
|
|
|
|
/* generate an iterator for the path */
|
|
GTK_TREE_ITER_INIT (iter, model->stamp, lp);
|
|
|
|
/* tell the view that the file 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);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
thunar_shortcuts_model_file_changed (ThunarFile *file,
|
|
ThunarShortcutsModel *model)
|
|
{
|
|
GtkTreeIter iter;
|
|
GList *lp;
|
|
gint idx;
|
|
GtkTreePath *path;
|
|
|
|
_thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model));
|
|
_thunar_return_if_fail (THUNAR_IS_FILE (file));
|
|
|
|
|
|
for (lp = model->shortcuts, idx = 0; lp != NULL; lp = lp->next, idx++)
|
|
{
|
|
ThunarShortcut *shortcut = THUNAR_SHORTCUT (lp->data);
|
|
|
|
if (shortcut->file != file)
|
|
continue;
|
|
|
|
GFile *g_file = thunar_file_get_file (file);
|
|
|
|
/* Only update the shortcut if trash has changed or the related g_file has changed (rename) */
|
|
if (thunar_file_is_trash (file) || (shortcut->location != NULL && g_file_equal (g_file, shortcut->location) == FALSE))
|
|
{
|
|
/* generate an iterator for the path */
|
|
GTK_TREE_ITER_INIT (iter, model->stamp, lp);
|
|
|
|
/* tell the view that the file 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);
|
|
|
|
/* If the changed shortcut is a bookmark, save the changes */
|
|
if (shortcut->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS)
|
|
thunar_shortcuts_model_save_bookmarks (model);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
thunar_shortcut_free (ThunarShortcut *shortcut,
|
|
ThunarShortcutsModel *model)
|
|
{
|
|
if (G_LIKELY (shortcut->file != NULL))
|
|
{
|
|
/* disable monitoring for the file */
|
|
thunar_file_unwatch (shortcut->file);
|
|
g_signal_handlers_disconnect_by_data (shortcut->file, model);
|
|
g_object_unref (shortcut->file);
|
|
shortcut->file = NULL;
|
|
}
|
|
|
|
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 devices header) */
|
|
if (shortcut->group == THUNAR_SHORTCUT_GROUP_DEVICES_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;
|
|
GList *lp;
|
|
guint position = 0;
|
|
|
|
_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;
|
|
shortcut->location = G_FILE (g_object_ref (G_OBJECT (location)));
|
|
|
|
if (thunar_shortcuts_model_local_file (location))
|
|
shortcut->file = thunar_file_get (location, NULL);
|
|
else
|
|
shortcut->gicon = g_themed_icon_new ("folder-remote");
|
|
|
|
/* if no position was given, place the shortcut at the bottom */
|
|
if (dst_path == NULL)
|
|
{
|
|
for (lp = model->shortcuts; lp != NULL; lp = lp->next)
|
|
if (THUNAR_SHORTCUT (lp->data)->group == THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS)
|
|
position++;
|
|
|
|
shortcut->sort_id = ++position;
|
|
}
|
|
|
|
/* 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_bookmarks (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_bookmarks (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 (shortcut, model);
|
|
|
|
/* the bookmark list was changed, so write the gtk bookmarks file */
|
|
thunar_shortcuts_model_save_bookmarks (model);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* 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_bookmarks (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
|
|
{
|
|
g_warn_if_reached ();
|
|
return;
|
|
}
|
|
|
|
/* 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);
|
|
}
|