summaryrefslogtreecommitdiffstats
path: root/plugins/filebrowser
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plugins/filebrowser/filebrowser.plugin.desktop.in12
-rw-r--r--plugins/filebrowser/gedit-file-bookmarks-store.c920
-rw-r--r--plugins/filebrowser/gedit-file-bookmarks-store.h91
-rw-r--r--plugins/filebrowser/gedit-file-browser-enum-register.c.template20
-rw-r--r--plugins/filebrowser/gedit-file-browser-enum-types-stage1.c.template45
-rw-r--r--plugins/filebrowser/gedit-file-browser-enum-types.h.template28
-rw-r--r--plugins/filebrowser/gedit-file-browser-error.h41
-rw-r--r--plugins/filebrowser/gedit-file-browser-messages.c1074
-rw-r--r--plugins/filebrowser/gedit-file-browser-messages.h33
-rw-r--r--plugins/filebrowser/gedit-file-browser-plugin.c943
-rw-r--r--plugins/filebrowser/gedit-file-browser-plugin.h70
-rw-r--r--plugins/filebrowser/gedit-file-browser-store.c3672
-rw-r--r--plugins/filebrowser/gedit-file-browser-store.h188
-rw-r--r--plugins/filebrowser/gedit-file-browser-utils.c223
-rw-r--r--plugins/filebrowser/gedit-file-browser-utils.h46
-rw-r--r--plugins/filebrowser/gedit-file-browser-view.c1364
-rw-r--r--plugins/filebrowser/gedit-file-browser-view.h84
-rw-r--r--plugins/filebrowser/gedit-file-browser-widget.c3152
-rw-r--r--plugins/filebrowser/gedit-file-browser-widget.h126
-rw-r--r--plugins/filebrowser/meson.build127
-rw-r--r--plugins/filebrowser/messages.xml47
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-activation.c105
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-activation.h69
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-add-filter.c162
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-add-filter.h69
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-extend-context-menu.c128
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-extend-context-menu.h70
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-get-root.c127
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-get-root.h69
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-get-view.c127
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-get-view.h69
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-id-location.c190
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-id-location.h70
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-id.c107
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-id.h69
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-set-emblem.c142
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-set-emblem.h69
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-set-markup.c143
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-set-markup.h70
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-set-root.c149
-rw-r--r--plugins/filebrowser/messages/gedit-file-browser-message-set-root.h69
-rw-r--r--plugins/filebrowser/messages/meson.build25
-rw-r--r--plugins/filebrowser/messages/messages.h16
-rw-r--r--plugins/filebrowser/org.gnome.gedit.plugins.filebrowser.gschema.xml55
-rw-r--r--plugins/filebrowser/resources/gedit-file-browser.gresource.xml7
-rw-r--r--plugins/filebrowser/resources/meson.build8
-rw-r--r--plugins/filebrowser/resources/ui/gedit-file-browser-menus.ui84
-rw-r--r--plugins/filebrowser/resources/ui/gedit-file-browser-widget.ui275
48 files changed, 14849 insertions, 0 deletions
diff --git a/plugins/filebrowser/filebrowser.plugin.desktop.in b/plugins/filebrowser/filebrowser.plugin.desktop.in
new file mode 100644
index 0000000..706168d
--- /dev/null
+++ b/plugins/filebrowser/filebrowser.plugin.desktop.in
@@ -0,0 +1,12 @@
+[Plugin]
+Loader=C
+Module=filebrowser
+IAge=3
+Name=File Browser Panel
+Description=Easy file access from the side panel.
+# TRANSLATORS: Do NOT translate or transliterate this text!
+# This is an icon file name.
+Icon=system-file-manager
+Authors=Jesse van den Kieboom <jesse@icecrew.nl>
+Copyright=Copyright © 2006 Jesse van den Kieboom
+Website=http://www.gedit.org
diff --git a/plugins/filebrowser/gedit-file-bookmarks-store.c b/plugins/filebrowser/gedit-file-bookmarks-store.c
new file mode 100644
index 0000000..df0968d
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-bookmarks-store.c
@@ -0,0 +1,920 @@
+/*
+ * gedit-file-bookmarks-store.c - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gedit/gedit-utils.h>
+
+#include "gedit-file-bookmarks-store.h"
+#include "gedit-file-browser-utils.h"
+
+struct _GeditFileBookmarksStorePrivate
+{
+ GVolumeMonitor *volume_monitor;
+ GFileMonitor *bookmarks_monitor;
+};
+
+static void remove_node (GtkTreeModel *model,
+ GtkTreeIter *iter);
+
+static void on_fs_changed (GVolumeMonitor *monitor,
+ GObject *object,
+ GeditFileBookmarksStore *model);
+
+static void on_bookmarks_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GeditFileBookmarksStore *model);
+static gboolean find_with_flags (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer obj,
+ guint flags,
+ guint notflags);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditFileBookmarksStore,
+ gedit_file_bookmarks_store,
+ GTK_TYPE_TREE_STORE,
+ 0,
+ G_ADD_PRIVATE_DYNAMIC (GeditFileBookmarksStore))
+
+static void
+gedit_file_bookmarks_store_dispose (GObject *object)
+{
+ GeditFileBookmarksStore *obj = GEDIT_FILE_BOOKMARKS_STORE (object);
+
+ if (obj->priv->volume_monitor != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (obj->priv->volume_monitor,
+ on_fs_changed,
+ obj);
+
+ g_object_unref (obj->priv->volume_monitor);
+ obj->priv->volume_monitor = NULL;
+ }
+
+ g_clear_object (&obj->priv->bookmarks_monitor);
+
+ G_OBJECT_CLASS (gedit_file_bookmarks_store_parent_class)->dispose (object);
+}
+
+static void
+gedit_file_bookmarks_store_class_init (GeditFileBookmarksStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gedit_file_bookmarks_store_dispose;
+}
+
+static void
+gedit_file_bookmarks_store_class_finalize (GeditFileBookmarksStoreClass *klass)
+{
+}
+
+static void
+gedit_file_bookmarks_store_init (GeditFileBookmarksStore *obj)
+{
+ obj->priv = gedit_file_bookmarks_store_get_instance_private (obj);
+}
+
+/* Private */
+static void
+add_node (GeditFileBookmarksStore *model,
+ GdkPixbuf *pixbuf,
+ const gchar *icon_name,
+ const gchar *name,
+ GObject *obj,
+ guint flags,
+ GtkTreeIter *iter)
+{
+ GtkTreeIter newiter;
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &newiter, NULL);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &newiter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON, pixbuf,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON_NAME, icon_name,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, name,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, obj,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, flags,
+ -1);
+
+ if (iter != NULL)
+ *iter = newiter;
+}
+
+static gboolean
+add_file (GeditFileBookmarksStore *model,
+ GFile *file,
+ const gchar *name,
+ guint flags,
+ GtkTreeIter *iter)
+{
+ gboolean native = g_file_is_native (file);
+ gchar *icon_name = NULL;
+ gchar *newname;
+
+ if (native && !g_file_query_exists (file, NULL))
+ return FALSE;
+
+ if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_HOME)
+ icon_name = g_strdup ("user-home-symbolic");
+ else if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP)
+ icon_name = g_strdup ("user-desktop-symbolic");
+ else if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT)
+ icon_name = g_strdup ("drive-harddisk-symbolic");
+ else
+ {
+ /* getting the icon is a sync get_info call, so we just do it for local files */
+ if (native)
+ icon_name = gedit_file_browser_utils_symbolic_icon_name_from_file (file);
+ else
+ icon_name = g_strdup ("folder-symbolic");
+ }
+
+ if (name == NULL)
+ newname = gedit_file_browser_utils_file_basename (file);
+ else
+ newname = g_strdup (name);
+
+ add_node (model, NULL, icon_name, newname, G_OBJECT (file), flags, iter);
+
+ g_free (icon_name);
+ g_free (newname);
+
+ return TRUE;
+}
+
+static void
+check_mount_separator (GeditFileBookmarksStore *model,
+ guint flags,
+ gboolean added)
+{
+ GtkTreeIter iter;
+ gboolean found = find_with_flags (GTK_TREE_MODEL (model), &iter, NULL,
+ flags | GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR,
+ 0);
+
+ if (added && !found)
+ {
+ /* Add the separator */
+ add_node (model, NULL, NULL, NULL, NULL,
+ flags | GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR,
+ NULL);
+ }
+ else if (!added && found)
+ {
+ remove_node (GTK_TREE_MODEL (model), &iter);
+ }
+}
+
+static void
+init_special_directories (GeditFileBookmarksStore *model)
+{
+ gchar const *path = g_get_home_dir ();
+ GFile *file;
+
+ if (path != NULL)
+ {
+ file = g_file_new_for_path (path);
+ add_file (model,
+ file,
+ _("Home"),
+ GEDIT_FILE_BOOKMARKS_STORE_IS_HOME | GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR,
+ NULL);
+ g_object_unref (file);
+ }
+
+#if defined(G_OS_WIN32) || defined(OS_OSX)
+ path = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
+ if (path != NULL)
+ {
+ file = g_file_new_for_path (path);
+ add_file (model,
+ file,
+ NULL,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP | GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR,
+ NULL);
+ g_object_unref (file);
+ }
+
+ path = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS);
+ if (path != NULL)
+ {
+ file = g_file_new_for_path (path);
+ add_file (model,
+ file,
+ NULL,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_DOCUMENTS | GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR,
+ NULL);
+ g_object_unref (file);
+ }
+#endif
+
+ file = g_file_new_for_uri ("file:///");
+ add_file (model, file, _("File System"), GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT, NULL);
+ g_object_unref (file);
+
+ check_mount_separator (model, GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT, TRUE);
+}
+
+static void
+get_fs_properties (gpointer fs,
+ gchar **name,
+ gchar **icon_name,
+ guint *flags)
+{
+ GIcon *icon = NULL;
+
+ *flags = GEDIT_FILE_BOOKMARKS_STORE_IS_FS;
+ *name = NULL;
+ *icon_name = NULL;
+
+ if (G_IS_DRIVE (fs))
+ {
+ icon = g_drive_get_symbolic_icon (G_DRIVE (fs));
+ *name = g_drive_get_name (G_DRIVE (fs));
+ *icon_name = gedit_file_browser_utils_name_from_themed_icon (icon);
+
+ *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_DRIVE;
+ }
+ else if (G_IS_VOLUME (fs))
+ {
+ icon = g_volume_get_symbolic_icon (G_VOLUME (fs));
+ *name = g_volume_get_name (G_VOLUME (fs));
+ *icon_name = gedit_file_browser_utils_name_from_themed_icon (icon);
+
+ *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_VOLUME;
+ }
+ else if (G_IS_MOUNT (fs))
+ {
+ icon = g_mount_get_symbolic_icon (G_MOUNT (fs));
+ *name = g_mount_get_name (G_MOUNT (fs));
+ *icon_name = gedit_file_browser_utils_name_from_themed_icon (icon);
+
+ *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT;
+ }
+
+ if (icon)
+ g_object_unref (icon);
+}
+
+static void
+add_fs (GeditFileBookmarksStore *model,
+ gpointer fs,
+ guint flags,
+ GtkTreeIter *iter)
+{
+ gchar *icon_name = NULL;
+ gchar *name = NULL;
+ guint fsflags;
+
+ get_fs_properties (fs, &name, &icon_name, &fsflags);
+ add_node (model, NULL, icon_name, name, fs, flags | fsflags, iter);
+
+ g_free (name);
+ g_free (icon_name);
+ check_mount_separator (model, GEDIT_FILE_BOOKMARKS_STORE_IS_FS, TRUE);
+}
+
+static void
+process_volume_cb (GVolume *volume,
+ GeditFileBookmarksStore *model)
+{
+ GMount *mount = g_volume_get_mount (volume);
+ guint flags = GEDIT_FILE_BOOKMARKS_STORE_NONE;
+
+ /* CHECK: should we use the LOCAL/REMOTE thing still? */
+ if (mount)
+ {
+ /* Show mounted volume */
+ add_fs (model, mount, flags, NULL);
+ g_object_unref (mount);
+ }
+ else if (g_volume_can_mount (volume))
+ {
+ /* We also show the unmounted volume here so users can
+ mount it if they want to access it */
+ add_fs (model, volume, flags, NULL);
+ }
+}
+
+static void
+process_drive_novolumes (GeditFileBookmarksStore *model,
+ GDrive *drive)
+{
+ if (g_drive_is_media_removable (drive) &&
+ !g_drive_is_media_check_automatic (drive) &&
+ g_drive_can_poll_for_media (drive))
+ {
+ /* This can be the case for floppy drives or other
+ drives where media detection fails. We show the
+ drive and poll for media when the user activates
+ it */
+ add_fs (model, drive, GEDIT_FILE_BOOKMARKS_STORE_NONE, NULL);
+ }
+}
+
+static void
+process_drive_cb (GDrive *drive,
+ GeditFileBookmarksStore *model)
+{
+ GList *volumes = g_drive_get_volumes (drive);
+
+ if (volumes)
+ {
+ /* Add all volumes for the drive */
+ g_list_foreach (volumes, (GFunc)process_volume_cb, model);
+ g_list_free (volumes);
+ }
+ else
+ {
+ process_drive_novolumes (model, drive);
+ }
+}
+
+static void
+init_drives (GeditFileBookmarksStore *model)
+{
+ GList *drives = g_volume_monitor_get_connected_drives (model->priv->volume_monitor);
+
+ g_list_foreach (drives, (GFunc)process_drive_cb, model);
+ g_list_free_full (drives, g_object_unref);
+}
+
+static void
+process_volume_nodrive_cb (GVolume *volume,
+ GeditFileBookmarksStore *model)
+{
+ GDrive *drive = g_volume_get_drive (volume);
+
+ if (drive)
+ {
+ g_object_unref (drive);
+ return;
+ }
+
+ process_volume_cb (volume, model);
+}
+
+static void
+init_volumes (GeditFileBookmarksStore *model)
+{
+ GList *volumes = g_volume_monitor_get_volumes (model->priv->volume_monitor);
+
+ g_list_foreach (volumes, (GFunc)process_volume_nodrive_cb, model);
+ g_list_free_full (volumes, g_object_unref);
+}
+
+static void
+process_mount_novolume_cb (GMount *mount,
+ GeditFileBookmarksStore *model)
+{
+ GVolume *volume = g_mount_get_volume (mount);
+
+ if (volume)
+ {
+ g_object_unref (volume);
+ }
+ else if (!g_mount_is_shadowed (mount))
+ {
+ /* Add the mount */
+ add_fs (model, mount, GEDIT_FILE_BOOKMARKS_STORE_NONE, NULL);
+ }
+}
+
+static void
+init_mounts (GeditFileBookmarksStore *model)
+{
+ GList *mounts = g_volume_monitor_get_mounts (model->priv->volume_monitor);
+
+ g_list_foreach (mounts, (GFunc)process_mount_novolume_cb, model);
+ g_list_free_full (mounts, g_object_unref);
+}
+
+static void
+init_fs (GeditFileBookmarksStore *model)
+{
+ if (model->priv->volume_monitor == NULL)
+ {
+ const gchar **ptr;
+ const gchar *signals[] = {
+ "drive-connected", "drive-changed", "drive-disconnected",
+ "volume-added", "volume-removed", "volume-changed",
+ "mount-added", "mount-removed", "mount-changed",
+ NULL
+ };
+
+ model->priv->volume_monitor = g_volume_monitor_get ();
+
+ /* Connect signals */
+ for (ptr = signals; *ptr != NULL; ++ptr)
+ {
+ g_signal_connect (model->priv->volume_monitor,
+ *ptr,
+ G_CALLBACK (on_fs_changed), model);
+ }
+ }
+
+ /* First go through all the connected drives */
+ init_drives (model);
+
+ /* Then add all volumes, not associated with a drive */
+ init_volumes (model);
+
+ /* Then finally add all mounts that have no volume */
+ init_mounts (model);
+}
+
+static gboolean
+add_bookmark (GeditFileBookmarksStore *model,
+ gchar const *name,
+ gchar const *uri)
+{
+ GFile *file = g_file_new_for_uri (uri);
+ guint flags = GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK;
+ GtkTreeIter iter;
+ gboolean ret;
+
+ if (g_file_is_native (file))
+ flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_LOCAL_BOOKMARK;
+ else
+ flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK;
+
+ ret = add_file (model, file, name, flags, &iter);
+
+ g_object_unref (file);
+ return ret;
+}
+
+static gchar *
+get_bookmarks_file (void)
+{
+ return g_build_filename (g_get_user_config_dir (), "gtk-3.0", "bookmarks", NULL);
+}
+
+static gchar *
+get_legacy_bookmarks_file (void)
+{
+ return g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
+}
+
+static gboolean
+parse_bookmarks_file (GeditFileBookmarksStore *model,
+ const gchar *bookmarks,
+ gboolean *added)
+{
+ GError *error = NULL;
+ gchar *contents;
+ gchar **lines;
+ gchar **line;
+
+ if (!g_file_get_contents (bookmarks, &contents, NULL, &error))
+ {
+ /* The bookmarks file doesn't exist (which is perfectly fine) */
+ g_error_free (error);
+
+ return FALSE;
+ }
+
+ lines = g_strsplit (contents, "\n", 0);
+
+ for (line = lines; *line; ++line)
+ {
+ if (**line)
+ {
+ GFile *location;
+
+ gchar *pos;
+ gchar *name;
+
+ /* CHECK: is this really utf8? */
+ pos = g_utf8_strchr (*line, -1, ' ');
+
+ if (pos != NULL)
+ {
+ *pos = '\0';
+ name = pos + 1;
+ }
+ else
+ {
+ name = NULL;
+ }
+
+ /* the bookmarks file should contain valid
+ * URIs, but paranoia is good */
+ location = g_file_new_for_uri (*line);
+ if (gedit_utils_is_valid_location (location))
+ {
+ *added |= add_bookmark (model, name, *line);
+ }
+ g_object_unref (location);
+ }
+ }
+
+ g_strfreev (lines);
+ g_free (contents);
+
+ /* Add a watch */
+ if (model->priv->bookmarks_monitor == NULL)
+ {
+ GFile *file = g_file_new_for_path (bookmarks);
+
+ model->priv->bookmarks_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
+ g_object_unref (file);
+
+ g_signal_connect (model->priv->bookmarks_monitor,
+ "changed",
+ G_CALLBACK (on_bookmarks_file_changed),
+ model);
+ }
+
+ return TRUE;
+}
+
+static void
+init_bookmarks (GeditFileBookmarksStore *model)
+{
+ gchar *bookmarks = get_bookmarks_file ();
+ gboolean added = FALSE;
+
+ if (!parse_bookmarks_file (model, bookmarks, &added))
+ {
+ g_free (bookmarks);
+
+ /* try the old location (gtk <= 3.4) */
+ bookmarks = get_legacy_bookmarks_file ();
+ parse_bookmarks_file (model, bookmarks, &added);
+ }
+
+ if (added)
+ {
+ /* Bookmarks separator */
+ add_node (model, NULL, NULL, NULL, NULL,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK | GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR,
+ NULL);
+ }
+
+ g_free (bookmarks);
+}
+
+static gint flags_order[] = {
+ GEDIT_FILE_BOOKMARKS_STORE_IS_HOME,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_FS,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK,
+ -1
+};
+
+static gint
+utf8_casecmp (gchar const *s1, const gchar *s2)
+{
+ gchar *n1;
+ gchar *n2;
+ gint result;
+
+ n1 = g_utf8_casefold (s1, -1);
+ n2 = g_utf8_casefold (s2, -1);
+
+ result = g_utf8_collate (n1, n2);
+
+ g_free (n1);
+ g_free (n2);
+
+ return result;
+}
+
+static gint
+bookmarks_compare_names (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b)
+{
+ gchar *n1;
+ gchar *n2;
+ gint result;
+ guint f1;
+ guint f2;
+
+ gtk_tree_model_get (model, a,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, &n1,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f1,
+ -1);
+ gtk_tree_model_get (model, b,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, &n2,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f2,
+ -1);
+
+ /* do not sort actual bookmarks to keep same order as in nautilus */
+ if ((f1 & GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK) &&
+ (f2 & GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK))
+ {
+ result = 0;
+ }
+ else if (n1 == NULL && n2 == NULL)
+ {
+ result = 0;
+ }
+ else if (n1 == NULL)
+ {
+ result = -1;
+ }
+ else if (n2 == NULL)
+ {
+ result = 1;
+ }
+ else
+ {
+ result = utf8_casecmp (n1, n2);
+ }
+
+ g_free (n1);
+ g_free (n2);
+
+ return result;
+}
+
+static gint
+bookmarks_compare_flags (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b)
+{
+ guint sep = GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR;
+ guint f1;
+ guint f2;
+ gint *flags;
+
+ gtk_tree_model_get (model, a,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f1,
+ -1);
+ gtk_tree_model_get (model, b,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f2,
+ -1);
+
+ for (flags = flags_order; *flags != -1; ++flags)
+ {
+ if ((f1 & *flags) != (f2 & *flags))
+ {
+ if (f1 & *flags)
+ return -1;
+ else
+ return 1;
+ }
+ else if ((f1 & *flags) && (f1 & sep) != (f2 & sep))
+ {
+ if (f1 & sep)
+ return -1;
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static gint
+bookmarks_compare_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gint result = bookmarks_compare_flags (model, a, b);
+
+ if (result == 0)
+ result = bookmarks_compare_names (model, a, b);
+
+ return result;
+}
+
+static gboolean
+find_with_flags (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer obj,
+ guint flags,
+ guint notflags)
+{
+ GtkTreeIter child;
+ guint childflags = 0;
+ GObject *childobj;
+ gboolean fequal;
+
+ if (!gtk_tree_model_get_iter_first (model, &child))
+ return FALSE;
+
+ do
+ {
+ gtk_tree_model_get (model,
+ &child,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, &childobj,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &childflags,
+ -1);
+
+ fequal = (obj == childobj);
+
+ if (childobj)
+ g_object_unref (childobj);
+
+ if ((obj == NULL || fequal) &&
+ (childflags & flags) == flags &&
+ !(childflags & notflags))
+ {
+ *iter = child;
+ return TRUE;
+ }
+ }
+ while (gtk_tree_model_iter_next (model, &child));
+
+ return FALSE;
+}
+
+static void
+remove_node (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ guint flags;
+
+ gtk_tree_model_get (model,
+ iter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!(flags & GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR) &&
+ flags & GEDIT_FILE_BOOKMARKS_STORE_IS_FS)
+ {
+ check_mount_separator (GEDIT_FILE_BOOKMARKS_STORE (model),
+ flags & GEDIT_FILE_BOOKMARKS_STORE_IS_FS,
+ FALSE);
+ }
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
+}
+
+static void
+remove_bookmarks (GeditFileBookmarksStore *model)
+{
+ GtkTreeIter iter;
+
+ while (find_with_flags (GTK_TREE_MODEL (model), &iter, NULL,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK,
+ 0))
+ {
+ remove_node (GTK_TREE_MODEL (model), &iter);
+ }
+}
+
+static void
+initialize_fill (GeditFileBookmarksStore *model)
+{
+ init_special_directories (model);
+ init_fs (model);
+ init_bookmarks (model);
+}
+
+/* Public */
+GeditFileBookmarksStore *
+gedit_file_bookmarks_store_new (void)
+{
+ GeditFileBookmarksStore *model;
+ GType column_types[] = {
+ GDK_TYPE_PIXBUF,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_OBJECT,
+ G_TYPE_UINT
+ };
+
+ model = g_object_new (GEDIT_TYPE_FILE_BOOKMARKS_STORE, NULL);
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (model),
+ GEDIT_FILE_BOOKMARKS_STORE_N_COLUMNS,
+ column_types);
+
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model),
+ bookmarks_compare_func,
+ NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+
+ initialize_fill (model);
+
+ return model;
+}
+
+GFile *
+gedit_file_bookmarks_store_get_location (GeditFileBookmarksStore *model,
+ GtkTreeIter *iter)
+{
+ GObject *obj;
+ GFile *file = NULL;
+ guint flags;
+ GFile * ret = NULL;
+ gboolean isfs;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BOOKMARKS_STORE (model), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (model),
+ iter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &flags,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, &obj,
+ -1);
+
+ if (obj == NULL)
+ return NULL;
+
+ isfs = (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_FS);
+
+ if (isfs && (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT))
+ file = g_mount_get_root (G_MOUNT (obj));
+ else if (!isfs)
+ file = (GFile *)g_object_ref (obj);
+
+ g_object_unref (obj);
+
+ if (file)
+ {
+ ret = g_file_dup (file);
+ g_object_unref (file);
+ }
+
+ return ret;
+}
+
+void
+gedit_file_bookmarks_store_refresh (GeditFileBookmarksStore *model)
+{
+ gtk_tree_store_clear (GTK_TREE_STORE (model));
+ initialize_fill (model);
+}
+
+static void
+on_fs_changed (GVolumeMonitor *monitor,
+ GObject *object,
+ GeditFileBookmarksStore *model)
+{
+ GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
+ guint flags = GEDIT_FILE_BOOKMARKS_STORE_IS_FS;
+ guint noflags = GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR;
+ GtkTreeIter iter;
+
+ /* clear all fs items */
+ while (find_with_flags (tree_model, &iter, NULL, flags, noflags))
+ remove_node (tree_model, &iter);
+
+ /* then reinitialize */
+ init_fs (model);
+}
+
+static void
+on_bookmarks_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GeditFileBookmarksStore *model)
+{
+ switch (event_type)
+ {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_CREATED:
+ /* Re-initialize bookmarks */
+ remove_bookmarks (model);
+ init_bookmarks (model);
+ break;
+ /* FIXME: shouldn't we also monitor the directory? */
+ case G_FILE_MONITOR_EVENT_DELETED:
+ /* Remove bookmarks */
+ remove_bookmarks (model);
+ g_object_unref (monitor);
+ model->priv->bookmarks_monitor = NULL;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+_gedit_file_bookmarks_store_register_type (GTypeModule *type_module)
+{
+ gedit_file_bookmarks_store_register_type (type_module);
+}
+
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-bookmarks-store.h b/plugins/filebrowser/gedit-file-bookmarks-store.h
new file mode 100644
index 0000000..19de53b
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-bookmarks-store.h
@@ -0,0 +1,91 @@
+/*
+ * gedit-file-bookmarks-store.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GEDIT_FILE_BOOKMARKS_STORE_H
+#define GEDIT_FILE_BOOKMARKS_STORE_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+#define GEDIT_TYPE_FILE_BOOKMARKS_STORE (gedit_file_bookmarks_store_get_type ())
+#define GEDIT_FILE_BOOKMARKS_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BOOKMARKS_STORE, GeditFileBookmarksStore))
+#define GEDIT_FILE_BOOKMARKS_STORE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BOOKMARKS_STORE, GeditFileBookmarksStore const))
+#define GEDIT_FILE_BOOKMARKS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FILE_BOOKMARKS_STORE, GeditFileBookmarksStoreClass))
+#define GEDIT_IS_FILE_BOOKMARKS_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FILE_BOOKMARKS_STORE))
+#define GEDIT_IS_FILE_BOOKMARKS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FILE_BOOKMARKS_STORE))
+#define GEDIT_FILE_BOOKMARKS_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FILE_BOOKMARKS_STORE, GeditFileBookmarksStoreClass))
+
+typedef struct _GeditFileBookmarksStore GeditFileBookmarksStore;
+typedef struct _GeditFileBookmarksStoreClass GeditFileBookmarksStoreClass;
+typedef struct _GeditFileBookmarksStorePrivate GeditFileBookmarksStorePrivate;
+
+enum
+{
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON = 0,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON_NAME,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS,
+ GEDIT_FILE_BOOKMARKS_STORE_N_COLUMNS
+};
+
+enum
+{
+ GEDIT_FILE_BOOKMARKS_STORE_NONE = 0,
+ GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR = 1 << 0, /* Separator item */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR = 1 << 1, /* Special user dir */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_HOME = 1 << 2, /* The special Home user directory */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP = 1 << 3, /* The special Desktop user directory */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_DOCUMENTS = 1 << 4, /* The special Documents user directory */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_FS = 1 << 5, /* A mount object */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT = 1 << 6, /* A mount object */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_VOLUME = 1 << 7, /* A volume object */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_DRIVE = 1 << 8, /* A drive object */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT = 1 << 9, /* The root file system (file:///) */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK = 1 << 10, /* A gtk bookmark */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK = 1 << 11, /* A remote gtk bookmark */
+ GEDIT_FILE_BOOKMARKS_STORE_IS_LOCAL_BOOKMARK = 1 << 12 /* A local gtk bookmark */
+};
+
+struct _GeditFileBookmarksStore
+{
+ GtkTreeStore parent;
+
+ GeditFileBookmarksStorePrivate *priv;
+};
+
+struct _GeditFileBookmarksStoreClass
+{
+ GtkTreeStoreClass parent_class;
+};
+
+GType gedit_file_bookmarks_store_get_type (void) G_GNUC_CONST;
+
+GeditFileBookmarksStore *gedit_file_bookmarks_store_new (void);
+GFile *gedit_file_bookmarks_store_get_location (GeditFileBookmarksStore *model,
+ GtkTreeIter *iter);
+void gedit_file_bookmarks_store_refresh (GeditFileBookmarksStore *model);
+
+void _gedit_file_bookmarks_store_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BOOKMARKS_STORE_H */
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-enum-register.c.template b/plugins/filebrowser/gedit-file-browser-enum-register.c.template
new file mode 100644
index 0000000..c97ffff
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-enum-register.c.template
@@ -0,0 +1,20 @@
+/*** BEGIN file-header ***/
+void
+gedit_file_browser_enum_and_flag_register_type (GTypeModule * module)
+{
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+ /* Enumerations from "@basename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN enumeration-production ***/
+ register_@enum_name@ (module);
+
+/*** END enumeration-production ***/
+
+/*** BEGIN file-tail ***/
+}
+
+/*** END file-tail ***/
diff --git a/plugins/filebrowser/gedit-file-browser-enum-types-stage1.c.template b/plugins/filebrowser/gedit-file-browser-enum-types-stage1.c.template
new file mode 100644
index 0000000..fd58866
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-enum-types-stage1.c.template
@@ -0,0 +1,45 @@
+/*** BEGIN file-header ***/
+#include "gedit-file-browser-enum-types.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+#include "@basename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+static GType @enum_name@_type = 0;
+
+static GType
+register_@enum_name@ (GTypeModule *module)
+{
+ static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@,
+ "@VALUENAME@",
+ "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+
+ @enum_name@_type =
+ g_type_module_register_@type@ (module,
+ "@EnumName@",
+ values);
+
+ return @enum_name@_type;
+}
+
+GType
+@enum_name@_get_type (void)
+{
+ return @enum_name@_type;
+}
+
+/*** END value-tail ***/
diff --git a/plugins/filebrowser/gedit-file-browser-enum-types.h.template b/plugins/filebrowser/gedit-file-browser-enum-types.h.template
new file mode 100644
index 0000000..c13167a
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-enum-types.h.template
@@ -0,0 +1,28 @@
+/*** BEGIN file-header ***/
+#ifndef __GEDIT_FILE_BROWSER_ENUM_TYPES_H__
+#define __GEDIT_FILE_BROWSER_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* Enumerations from "@basename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN enumeration-production ***/
+#define GEDIT_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+
+/*** END enumeration-production ***/
+
+/*** BEGIN file-tail ***/
+void gedit_file_browser_enum_and_flag_register_type (GTypeModule * module);
+
+G_END_DECLS
+
+#endif /* __GEDIT_FILE_BROWSER_ENUM_TYPES_H__ */
+/*** END file-tail ***/
diff --git a/plugins/filebrowser/gedit-file-browser-error.h b/plugins/filebrowser/gedit-file-browser-error.h
new file mode 100644
index 0000000..89e6ae3
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-error.h
@@ -0,0 +1,41 @@
+/*
+ * gedit-file-browser-error.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GEDIT_FILE_BROWSER_ERROR_H
+#define GEDIT_FILE_BROWSER_ERROR_H
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GEDIT_FILE_BROWSER_ERROR_NONE,
+ GEDIT_FILE_BROWSER_ERROR_RENAME,
+ GEDIT_FILE_BROWSER_ERROR_DELETE,
+ GEDIT_FILE_BROWSER_ERROR_NEW_FILE,
+ GEDIT_FILE_BROWSER_ERROR_NEW_DIRECTORY,
+ GEDIT_FILE_BROWSER_ERROR_OPEN_DIRECTORY,
+ GEDIT_FILE_BROWSER_ERROR_SET_ROOT,
+ GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY,
+ GEDIT_FILE_BROWSER_ERROR_NUM
+} GeditFileBrowserError;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_ERROR_H */
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-messages.c b/plugins/filebrowser/gedit-file-browser-messages.c
new file mode 100644
index 0000000..7f25424
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-messages.c
@@ -0,0 +1,1074 @@
+/*
+ * gedit-file-browser-messages.c
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gedit-file-browser-messages.h"
+#include "gedit-file-browser-store.h"
+#include "messages/messages.h"
+
+#include <gedit/gedit-message.h>
+
+#define MESSAGE_OBJECT_PATH "/plugins/filebrowser"
+#define WINDOW_DATA_KEY "GeditFileBrowserMessagesWindowData"
+
+#define BUS_CONNECT(bus, name, data) gedit_message_bus_connect(bus, MESSAGE_OBJECT_PATH, #name, (GeditMessageCallback) message_##name##_cb, data, NULL)
+#define BUS_DISCONNECT(bus, name, data) gedit_message_bus_disconnect_by_func(bus, MESSAGE_OBJECT_PATH, #name, (GeditMessageCallback) message_##name##_cb, data)
+
+typedef struct
+{
+ GeditWindow *window;
+ GeditMessage *message;
+} MessageCacheData;
+
+typedef struct
+{
+ guint row_inserted_id;
+ guint before_row_deleted_id;
+ guint root_changed_id;
+ guint begin_loading_id;
+ guint end_loading_id;
+
+ GeditMessageBus *bus;
+ GeditFileBrowserWidget *widget;
+ GHashTable *row_tracking;
+
+ GHashTable *filters;
+} WindowData;
+
+typedef struct
+{
+ gulong id;
+
+ GeditWindow *window;
+ GeditMessage *message;
+} FilterData;
+
+static WindowData *
+window_data_new (GeditWindow *window,
+ GeditFileBrowserWidget *widget)
+{
+ WindowData *data = g_slice_new (WindowData);
+
+ data->bus = gedit_window_get_message_bus (window);
+ data->widget = widget;
+ data->row_tracking = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)gtk_tree_row_reference_free);
+
+ data->filters = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ NULL);
+
+ g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data);
+
+ return data;
+}
+
+static WindowData *
+get_window_data (GeditWindow *window)
+{
+ return (WindowData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY));
+}
+
+static void
+window_data_free (GeditWindow *window)
+{
+ WindowData *data = get_window_data (window);
+
+ g_hash_table_destroy (data->row_tracking);
+ g_hash_table_destroy (data->filters);
+
+ g_slice_free (WindowData, data);
+
+ g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL);
+}
+
+static FilterData *
+filter_data_new (GeditWindow *window,
+ GeditMessage *message)
+{
+ FilterData *data = g_slice_new (FilterData);
+ WindowData *wdata;
+
+ data->window = window;
+ data->id = 0;
+ data->message = message;
+
+ wdata = get_window_data (window);
+
+ g_hash_table_insert (wdata->filters,
+ gedit_message_type_identifier (gedit_message_get_object_path (message),
+ gedit_message_get_method (message)),
+ data);
+
+ return data;
+}
+
+static void
+filter_data_free (FilterData *data)
+{
+ WindowData *wdata = get_window_data (data->window);
+ gchar *identifier;
+
+ identifier = gedit_message_type_identifier (gedit_message_get_object_path (data->message),
+ gedit_message_get_method (data->message));
+
+ g_hash_table_remove (wdata->filters, identifier);
+ g_free (identifier);
+
+ g_object_unref (data->message);
+ g_slice_free (FilterData, data);
+}
+
+static GtkTreePath *
+track_row_lookup (WindowData *data,
+ const gchar *id)
+{
+ GtkTreeRowReference *ref;
+
+ ref = (GtkTreeRowReference *)g_hash_table_lookup (data->row_tracking, id);
+
+ if (!ref)
+ return NULL;
+
+ return gtk_tree_row_reference_get_path (ref);
+}
+
+static void
+message_cache_data_free (MessageCacheData *data)
+{
+ g_object_unref (data->message);
+ g_slice_free (MessageCacheData, data);
+}
+
+static MessageCacheData *
+message_cache_data_new (GeditWindow *window,
+ GeditMessage *message)
+{
+ MessageCacheData *data = g_slice_new (MessageCacheData);
+
+ data->window = window;
+ data->message = message;
+
+ return data;
+}
+
+static void
+message_get_root_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ GeditFileBrowserStore *store;
+ GFile *location;
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+ location = gedit_file_browser_store_get_virtual_root (store);
+
+ if (location)
+ {
+ g_object_set (message, "location", location, NULL);
+ g_object_unref (location);
+ }
+}
+
+static void
+message_set_root_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ GFile *root;
+ GFile *virtual = NULL;
+
+ g_object_get (message, "location", &root, NULL);
+
+ if (!root)
+ {
+ return;
+ }
+
+ g_object_get (message, "virtual", &virtual, NULL);
+
+ if (virtual)
+ {
+ gedit_file_browser_widget_set_root_and_virtual_root (data->widget, root, virtual);
+ }
+ else
+ {
+ gedit_file_browser_widget_set_root (data->widget, root, TRUE);
+ }
+}
+
+static void
+message_set_emblem_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gchar *id = NULL;
+ gchar *emblem = NULL;
+ GtkTreePath *path;
+ GeditFileBrowserStore *store;
+
+ g_object_get (message, "id", &id, "emblem", &emblem, NULL);
+
+ if (!id)
+ {
+ g_free (id);
+ g_free (emblem);
+
+ return;
+ }
+
+ path = track_row_lookup (data, id);
+
+ if (path != NULL)
+ {
+ GtkTreeIter iter;
+ GValue value = G_VALUE_INIT;
+ GdkPixbuf *pixbuf = NULL;
+
+ if (emblem != NULL)
+ {
+ pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ emblem,
+ 10,
+ GTK_ICON_LOOKUP_FORCE_SIZE,
+ NULL);
+ }
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
+ {
+ g_value_init (&value, GDK_TYPE_PIXBUF);
+ g_value_set_object (&value, pixbuf);
+
+ gedit_file_browser_store_set_value (store,
+ &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM,
+ &value);
+
+ g_value_unset (&value);
+ }
+
+ if (pixbuf)
+ {
+ g_object_unref (pixbuf);
+ }
+ }
+
+ g_free (id);
+ g_free (emblem);
+}
+
+static void
+message_set_markup_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gchar *id = NULL;
+ gchar *markup = NULL;
+ GtkTreePath *path;
+ GeditFileBrowserStore *store;
+
+ g_object_get (message, "id", &id, "markup", &markup, NULL);
+
+ if (!id)
+ {
+ g_free (id);
+ g_free (markup);
+
+ return;
+ }
+
+ path = track_row_lookup (data, id);
+
+ if (path != NULL)
+ {
+ GtkTreeIter iter;
+ GValue value = G_VALUE_INIT;
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
+ {
+ if (markup == NULL)
+ {
+ gchar *name;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_NAME, &name,
+ -1);
+ markup = g_markup_escape_text (name, -1);
+
+ g_free (name);
+ }
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, markup);
+
+ gedit_file_browser_store_set_value (store,
+ &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP,
+ &value);
+
+ g_value_unset (&value);
+ }
+
+ gtk_tree_path_free (path);
+ }
+
+ g_free (id);
+ g_free (markup);
+}
+
+static gchar *
+item_id (const gchar *path,
+ GFile *location)
+{
+ gchar *uri;
+ gchar *id;
+
+ uri = g_file_get_uri (location);
+ id = g_strconcat (path, "::", uri, NULL);
+ g_free (uri);
+
+ return id;
+}
+
+static gchar *
+track_row (WindowData *data,
+ GeditFileBrowserStore *store,
+ GtkTreePath *path,
+ GFile *location)
+{
+ GtkTreeRowReference *ref;
+ gchar *id;
+ gchar *pathstr;
+
+ pathstr = gtk_tree_path_to_string (path);
+ id = item_id (pathstr, location);
+
+ ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
+ g_hash_table_insert (data->row_tracking, g_strdup (id), ref);
+
+ g_free (pathstr);
+
+ return id;
+}
+
+static void
+set_item_message (WindowData *data,
+ GtkTreeIter *iter,
+ GtkTreePath *path,
+ GeditMessage *message)
+{
+ GeditFileBrowserStore *store;
+ gchar *name;
+ GFile *location;
+ guint flags = 0;
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_NAME, &name,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (location)
+ {
+ gchar *track_id;
+
+ if (path && gtk_tree_path_get_depth (path) != 0)
+ {
+ track_id = track_row (data, store, path, location);
+ }
+ else
+ {
+ track_id = NULL;
+ }
+
+ g_object_set (message,
+ "id", track_id,
+ "location", location,
+ NULL);
+
+ if (gedit_message_has (message, "name"))
+ {
+ g_object_set (message,
+ "name", name,
+ NULL);
+ }
+
+ if (gedit_message_has (message, "is_directory"))
+ {
+ g_object_set (message,
+ "is_directory",
+ FILE_IS_DIR (flags),
+ NULL);
+ }
+
+ g_free (track_id);
+ g_object_unref (location);
+ }
+
+ g_free (name);
+}
+
+static gboolean
+custom_message_filter_func (GeditFileBrowserWidget *widget,
+ GeditFileBrowserStore *store,
+ GtkTreeIter *iter,
+ FilterData *data)
+{
+ WindowData *wdata = get_window_data (data->window);
+ GFile *location;
+ guint flags = 0;
+ gboolean filter = FALSE;
+ GtkTreePath *path;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!location || FILE_IS_DUMMY (flags))
+ return FALSE;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+ set_item_message (wdata, iter, path, data->message);
+ gtk_tree_path_free (path);
+
+ g_object_set (data->message, "filter", filter, NULL);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ g_object_get (data->message, "filter", &filter, NULL);
+
+ g_object_unref (location);
+
+ return !filter;
+}
+
+static void
+message_add_filter_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ GeditWindow *window)
+{
+ const gchar *object_path = NULL;
+ const gchar *method = NULL;
+ gulong id;
+ GeditMessage *cbmessage;
+ FilterData *filter_data;
+ WindowData *data;
+ GType message_type;
+
+ data = get_window_data (window);
+
+ object_path = gedit_message_get_object_path (message);
+ method = gedit_message_get_method (message);
+
+ message_type = gedit_message_bus_lookup (bus, object_path, method);
+
+ if (message_type == G_TYPE_INVALID)
+ {
+ return;
+ }
+
+ /* Check if the message type has the correct arguments */
+ if (!gedit_message_type_check (message_type, "id", G_TYPE_STRING) ||
+ !gedit_message_type_check (message_type, "location", G_TYPE_FILE) ||
+ !gedit_message_type_check (message_type, "is-directory", G_TYPE_BOOLEAN) ||
+ !gedit_message_type_check (message_type, "filter", G_TYPE_BOOLEAN))
+ {
+ return;
+ }
+
+ cbmessage = g_object_new (message_type,
+ "object-path", object_path,
+ "method", method,
+ "id", NULL,
+ "location", NULL,
+ "is-directory", FALSE,
+ "filter", FALSE,
+ NULL);
+
+ /* Register the custom filter on the widget */
+ filter_data = filter_data_new (window, cbmessage);
+
+ id = gedit_file_browser_widget_add_filter (data->widget,
+ (GeditFileBrowserWidgetFilterFunc)custom_message_filter_func,
+ filter_data,
+ (GDestroyNotify)filter_data_free);
+
+ filter_data->id = id;
+}
+
+static void
+message_remove_filter_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gulong id = 0;
+
+ g_object_get (message, "id", &id, NULL);
+
+ if (!id)
+ return;
+
+ gedit_file_browser_widget_remove_filter (data->widget, id);
+}
+
+static void
+message_extend_context_menu_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ GeditWindow *window)
+{
+ WindowData *data;
+ GeditMenuExtension *ext;
+
+ data = get_window_data (window);
+
+ ext = gedit_file_browser_widget_extend_context_menu (data->widget);
+
+ g_object_set (message, "extension", ext, NULL);
+ g_object_unref (ext);
+}
+
+static void
+message_up_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ GeditFileBrowserStore *store = gedit_file_browser_widget_get_browser_store (data->widget);
+
+ gedit_file_browser_store_set_virtual_root_up (store);
+}
+
+static void
+message_history_back_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_history_back (data->widget);
+}
+
+static void
+message_history_forward_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_history_forward (data->widget);
+}
+
+static void
+message_refresh_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_refresh (data->widget);
+}
+
+static void
+message_set_show_hidden_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gboolean active = FALSE;
+ GeditFileBrowserStore *store;
+ GeditFileBrowserStoreFilterMode mode;
+
+ g_object_get (message, "active", &active, NULL);
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+ mode = gedit_file_browser_store_get_filter_mode (store);
+
+ if (active)
+ mode &= ~GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN;
+ else
+ mode |= GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN;
+
+ gedit_file_browser_store_set_filter_mode (store, mode);
+}
+
+static void
+message_set_show_binary_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gboolean active = FALSE;
+ GeditFileBrowserStore *store;
+ GeditFileBrowserStoreFilterMode mode;
+
+ g_object_get (message, "active", &active, NULL);
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+ mode = gedit_file_browser_store_get_filter_mode (store);
+
+ if (active)
+ mode &= ~GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY;
+ else
+ mode |= GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY;
+
+ gedit_file_browser_store_set_filter_mode (store, mode);
+}
+
+static void
+message_show_bookmarks_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_show_bookmarks (data->widget);
+}
+
+static void
+message_show_files_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_show_files (data->widget);
+}
+
+static void
+message_get_view_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ GeditFileBrowserView *view;
+ view = gedit_file_browser_widget_get_browser_view (data->widget);
+
+ g_object_set (message, "view", view, NULL);
+}
+
+static void
+register_methods (GeditWindow *window,
+ GeditFileBrowserWidget *widget)
+{
+ GeditMessageBus *bus = gedit_window_get_message_bus (window);
+ WindowData *data = get_window_data (window);
+
+ /* Register method calls */
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_ROOT,
+ MESSAGE_OBJECT_PATH,
+ "get_root");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_ROOT,
+ MESSAGE_OBJECT_PATH,
+ "set_root");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_EMBLEM,
+ MESSAGE_OBJECT_PATH,
+ "set_emblem");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_MARKUP,
+ MESSAGE_OBJECT_PATH,
+ "set_markup");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ADD_FILTER,
+ MESSAGE_OBJECT_PATH,
+ "add_filter");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID,
+ MESSAGE_OBJECT_PATH,
+ "remove_filter");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU,
+ MESSAGE_OBJECT_PATH,
+ "extend_context_menu");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_MESSAGE,
+ MESSAGE_OBJECT_PATH,
+ "up");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_MESSAGE,
+ MESSAGE_OBJECT_PATH,
+ "history_back");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_MESSAGE,
+ MESSAGE_OBJECT_PATH,
+ "history_forward");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_MESSAGE,
+ MESSAGE_OBJECT_PATH,
+ "refresh");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION,
+ MESSAGE_OBJECT_PATH,
+ "set_show_hidden");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION,
+ MESSAGE_OBJECT_PATH,
+ "set_show_binary");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_MESSAGE,
+ MESSAGE_OBJECT_PATH,
+ "show_bookmarks");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_MESSAGE,
+ MESSAGE_OBJECT_PATH,
+ "show_files");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_VIEW,
+ MESSAGE_OBJECT_PATH,
+ "get_view");
+
+ BUS_CONNECT (bus, get_root, data);
+ BUS_CONNECT (bus, set_root, data);
+ BUS_CONNECT (bus, set_emblem, data);
+ BUS_CONNECT (bus, set_markup, data);
+ BUS_CONNECT (bus, add_filter, window);
+ BUS_CONNECT (bus, remove_filter, data);
+ BUS_CONNECT (bus, extend_context_menu, window);
+
+ BUS_CONNECT (bus, up, data);
+ BUS_CONNECT (bus, history_back, data);
+ BUS_CONNECT (bus, history_forward, data);
+
+ BUS_CONNECT (bus, refresh, data);
+
+ BUS_CONNECT (bus, set_show_hidden, data);
+ BUS_CONNECT (bus, set_show_binary, data);
+
+ BUS_CONNECT (bus, show_bookmarks, data);
+ BUS_CONNECT (bus, show_files, data);
+
+ BUS_CONNECT (bus, get_view, data);
+}
+
+static void
+store_row_inserted (GeditFileBrowserStore *store,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ MessageCacheData *data)
+{
+ guint flags = 0;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags))
+ {
+ WindowData *wdata = get_window_data (data->window);
+
+ set_item_message (wdata, iter, path, data->message);
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ }
+}
+
+static void
+store_before_row_deleted (GeditFileBrowserStore *store,
+ GtkTreePath *path,
+ MessageCacheData *data)
+{
+ GtkTreeIter iter;
+ guint flags = 0;
+
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags))
+ {
+ WindowData *wdata = get_window_data (data->window);
+ gchar *id;
+
+ set_item_message (wdata, &iter, path, data->message);
+
+ /* Must get the ID before the plugin can modify it */
+ g_object_get (data->message, "id", &id, NULL);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+
+ g_hash_table_remove (wdata->row_tracking, id);
+ g_free (id);
+ }
+}
+
+static void
+store_virtual_root_changed (GeditFileBrowserStore *store,
+ GParamSpec *spec,
+ MessageCacheData *data)
+{
+ WindowData *wdata = get_window_data (data->window);
+ GFile *vroot;
+
+ vroot = gedit_file_browser_store_get_virtual_root (store);
+
+ if (!vroot)
+ {
+ return;
+ }
+
+ g_object_set (data->message,
+ "location", vroot,
+ NULL);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+
+ g_object_unref (vroot);
+}
+
+static void
+store_begin_loading (GeditFileBrowserStore *store,
+ GtkTreeIter *iter,
+ MessageCacheData *data)
+{
+ GtkTreePath *path;
+ WindowData *wdata = get_window_data (data->window);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+
+ set_item_message (wdata, iter, path, data->message);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ gtk_tree_path_free (path);
+}
+
+static void
+store_end_loading (GeditFileBrowserStore *store,
+ GtkTreeIter *iter,
+ MessageCacheData *data)
+{
+ GtkTreePath *path;
+ WindowData *wdata = get_window_data (data->window);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+
+ set_item_message (wdata, iter, path, data->message);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ gtk_tree_path_free (path);
+}
+
+static void
+register_signals (GeditWindow *window,
+ GeditFileBrowserWidget *widget)
+{
+ GeditMessageBus *bus = gedit_window_get_message_bus (window);
+ GeditFileBrowserStore *store;
+
+ GeditMessage *message;
+ WindowData *data;
+
+ /* Register signals */
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ MESSAGE_OBJECT_PATH,
+ "root_changed");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ MESSAGE_OBJECT_PATH,
+ "begin_loading");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ MESSAGE_OBJECT_PATH,
+ "end_loading");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ MESSAGE_OBJECT_PATH,
+ "inserted");
+
+ gedit_message_bus_register (bus,
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ MESSAGE_OBJECT_PATH,
+ "deleted");
+
+ store = gedit_file_browser_widget_get_browser_store (widget);
+
+ message = g_object_new (GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ "object-path", MESSAGE_OBJECT_PATH,
+ "method", "inserted",
+ NULL);
+
+ data = get_window_data (window);
+
+ data->row_inserted_id =
+ g_signal_connect_data (store,
+ "row-inserted",
+ G_CALLBACK (store_row_inserted),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+
+ message = g_object_new (GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ "object-path", MESSAGE_OBJECT_PATH,
+ "method", "deleted",
+ NULL);
+
+ data->before_row_deleted_id =
+ g_signal_connect_data (store,
+ "before-row-deleted",
+ G_CALLBACK (store_before_row_deleted),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+
+ message = g_object_new (GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ "object-path", MESSAGE_OBJECT_PATH,
+ "method", "root_changed",
+ NULL);
+
+ data->root_changed_id =
+ g_signal_connect_data (store,
+ "notify::virtual-root",
+ G_CALLBACK (store_virtual_root_changed),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+
+ message = g_object_new (GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ "object-path", MESSAGE_OBJECT_PATH,
+ "method", "begin_loading",
+ NULL);
+
+ data->begin_loading_id =
+ g_signal_connect_data (store,
+ "begin_loading",
+ G_CALLBACK (store_begin_loading),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+
+ message = g_object_new (GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,
+ "object-path", MESSAGE_OBJECT_PATH,
+ "method", "end_loading",
+ NULL);
+
+ data->end_loading_id =
+ g_signal_connect_data (store,
+ "end_loading",
+ G_CALLBACK (store_end_loading),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+}
+
+static void
+message_unregistered (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditWindow *window)
+{
+ gchar *identifier;
+ FilterData *data;
+ WindowData *wdata;
+
+ wdata = get_window_data (window);
+
+ identifier = gedit_message_type_identifier (object_path, method);
+
+ data = g_hash_table_lookup (wdata->filters, identifier);
+
+ if (data)
+ {
+ gedit_file_browser_widget_remove_filter (wdata->widget,
+ data->id);
+ }
+
+ g_free (identifier);
+}
+
+void
+gedit_file_browser_messages_register (GeditWindow *window,
+ GeditFileBrowserWidget *widget)
+{
+ window_data_new (window, widget);
+
+ register_methods (window, widget);
+ register_signals (window, widget);
+
+ g_signal_connect (gedit_window_get_message_bus (window),
+ "unregistered",
+ G_CALLBACK (message_unregistered),
+ window);
+}
+
+static void
+cleanup_signals (GeditWindow *window)
+{
+ WindowData *data = get_window_data (window);
+ GeditFileBrowserStore *store;
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+
+ g_signal_handler_disconnect (store, data->row_inserted_id);
+ g_signal_handler_disconnect (store, data->before_row_deleted_id);
+ g_signal_handler_disconnect (store, data->root_changed_id);
+ g_signal_handler_disconnect (store, data->begin_loading_id);
+ g_signal_handler_disconnect (store, data->end_loading_id);
+
+ g_signal_handlers_disconnect_by_func (data->bus, message_unregistered, window);
+}
+
+void
+gedit_file_browser_messages_unregister (GeditWindow *window)
+{
+ GeditMessageBus *bus = gedit_window_get_message_bus (window);
+ WindowData *data = get_window_data (window);
+
+ cleanup_signals (window);
+
+ BUS_DISCONNECT (bus, get_root, data);
+ BUS_DISCONNECT (bus, set_root, data);
+ BUS_DISCONNECT (bus, set_emblem, data);
+ BUS_DISCONNECT (bus, set_markup, data);
+ BUS_DISCONNECT (bus, add_filter, window);
+ BUS_DISCONNECT (bus, remove_filter, data);
+
+ BUS_DISCONNECT (bus, up, data);
+ BUS_DISCONNECT (bus, history_back, data);
+ BUS_DISCONNECT (bus, history_forward, data);
+
+ BUS_DISCONNECT (bus, refresh, data);
+
+ BUS_DISCONNECT (bus, set_show_hidden, data);
+ BUS_DISCONNECT (bus, set_show_binary, data);
+
+ BUS_DISCONNECT (bus, show_bookmarks, data);
+ BUS_DISCONNECT (bus, show_files, data);
+
+ BUS_DISCONNECT (bus, get_view, data);
+
+ gedit_message_bus_unregister_all (bus, MESSAGE_OBJECT_PATH);
+
+ window_data_free (window);
+}
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-messages.h b/plugins/filebrowser/gedit-file-browser-messages.h
new file mode 100644
index 0000000..9fcb316
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-messages.h
@@ -0,0 +1,33 @@
+/*
+ * gedit-file-browser-messages.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2008 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGES_H
+#define GEDIT_FILE_BROWSER_MESSAGES_H
+
+#include <gedit/gedit-window.h>
+#include <gedit/gedit-message-bus.h>
+#include "gedit-file-browser-widget.h"
+
+void gedit_file_browser_messages_register (GeditWindow *window,
+ GeditFileBrowserWidget *widget);
+void gedit_file_browser_messages_unregister (GeditWindow *window);
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGES_H */
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-plugin.c b/plugins/filebrowser/gedit-file-browser-plugin.c
new file mode 100644
index 0000000..2e7b79f
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-plugin.c
@@ -0,0 +1,943 @@
+/*
+ * gedit-file-browser-plugin.c - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <gedit/gedit-app.h>
+#include <gedit/gedit-commands.h>
+#include <gedit/gedit-debug.h>
+#include <gedit/gedit-window.h>
+#include <gedit/gedit-window-activatable.h>
+#include <gedit/gedit-utils.h>
+#include <tepl/tepl.h>
+
+#include "gedit-file-browser-enum-types.h"
+#include "gedit-file-browser-plugin.h"
+#include "gedit-file-browser-utils.h"
+#include "gedit-file-browser-error.h"
+#include "gedit-file-browser-widget.h"
+#include "gedit-file-browser-messages.h"
+
+#define FILEBROWSER_BASE_SETTINGS "org.gnome.gedit.plugins.filebrowser"
+#define FILEBROWSER_TREE_VIEW "tree-view"
+#define FILEBROWSER_ROOT "root"
+#define FILEBROWSER_VIRTUAL_ROOT "virtual-root"
+#define FILEBROWSER_ENABLE_REMOTE "enable-remote"
+#define FILEBROWSER_OPEN_AT_FIRST_DOC "open-at-first-doc"
+#define FILEBROWSER_FILTER_MODE "filter-mode"
+#define FILEBROWSER_FILTER_PATTERN "filter-pattern"
+#define FILEBROWSER_BINARY_PATTERNS "binary-patterns"
+
+#define NAUTILUS_BASE_SETTINGS "org.gnome.nautilus.preferences"
+#define NAUTILUS_FALLBACK_SETTINGS "org.gnome.gedit.plugins.filebrowser.nautilus"
+#define NAUTILUS_CLICK_POLICY_KEY "click-policy"
+
+#define TERMINAL_BASE_SETTINGS "org.gnome.desktop.default-applications.terminal"
+#define TERMINAL_EXEC_KEY "exec"
+
+struct _GeditFileBrowserPluginPrivate
+{
+ GSettings *settings;
+ GSettings *nautilus_settings;
+ GSettings *terminal_settings;
+
+ GeditWindow *window;
+
+ GeditFileBrowserWidget *tree_widget;
+ gboolean auto_root;
+ gulong end_loading_handle;
+
+ guint click_policy_handle;
+};
+
+enum
+{
+ PROP_0,
+ PROP_WINDOW
+};
+
+static void gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface);
+
+static void on_location_activated_cb (GeditFileBrowserWidget *widget,
+ GFile *location,
+ GeditWindow *window);
+static void on_error_cb (GeditFileBrowserWidget *widget,
+ guint code,
+ gchar const *message,
+ GeditFileBrowserPlugin *plugin);
+static void on_model_set_cb (GeditFileBrowserView *widget,
+ GParamSpec *param,
+ GeditFileBrowserPlugin *plugin);
+static void on_virtual_root_changed_cb (GeditFileBrowserStore *model,
+ GParamSpec *param,
+ GeditFileBrowserPlugin *plugin);
+static void on_rename_cb (GeditFileBrowserStore *model,
+ GFile *oldfile,
+ GFile *newfile,
+ GeditWindow *window);
+static void on_tab_added_cb (GeditWindow *window,
+ GeditTab *tab,
+ GeditFileBrowserPlugin *plugin);
+static gboolean on_confirm_delete_cb (GeditFileBrowserWidget *widget,
+ GeditFileBrowserStore *store,
+ GList *rows,
+ GeditFileBrowserPlugin *plugin);
+static gboolean on_confirm_no_trash_cb (GeditFileBrowserWidget *widget,
+ GList *files,
+ GeditWindow *window);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditFileBrowserPlugin,
+ gedit_file_browser_plugin,
+ G_TYPE_OBJECT,
+ 0,
+ G_ADD_PRIVATE_DYNAMIC (GeditFileBrowserPlugin)
+ G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_WINDOW_ACTIVATABLE,
+ gedit_window_activatable_iface_init) \
+ \
+ gedit_file_browser_enum_and_flag_register_type (type_module); \
+ _gedit_file_bookmarks_store_register_type (type_module); \
+ _gedit_file_browser_store_register_type (type_module); \
+ _gedit_file_browser_view_register_type (type_module); \
+ _gedit_file_browser_widget_register_type (type_module); \
+)
+
+static GSettings *
+create_nautilus_gsettings (void)
+{
+ GSettings *nautilus_settings = NULL;
+
+ if (tepl_utils_can_use_gsettings_schema (NAUTILUS_BASE_SETTINGS))
+ {
+ nautilus_settings = g_settings_new (NAUTILUS_BASE_SETTINGS);
+
+ if (tepl_utils_can_use_gsettings_key (nautilus_settings, NAUTILUS_CLICK_POLICY_KEY))
+ {
+ return nautilus_settings;
+ }
+ }
+
+ g_clear_object (&nautilus_settings);
+ return g_settings_new (NAUTILUS_FALLBACK_SETTINGS);
+}
+
+static void
+gedit_file_browser_plugin_init (GeditFileBrowserPlugin *plugin)
+{
+ plugin->priv = gedit_file_browser_plugin_get_instance_private (plugin);
+
+ plugin->priv->settings = g_settings_new (FILEBROWSER_BASE_SETTINGS);
+ plugin->priv->terminal_settings = g_settings_new (TERMINAL_BASE_SETTINGS);
+ plugin->priv->nautilus_settings = create_nautilus_gsettings ();
+}
+
+static void
+gedit_file_browser_plugin_dispose (GObject *object)
+{
+ GeditFileBrowserPlugin *plugin = GEDIT_FILE_BROWSER_PLUGIN (object);
+
+ g_clear_object (&plugin->priv->settings);
+ g_clear_object (&plugin->priv->nautilus_settings);
+ g_clear_object (&plugin->priv->terminal_settings);
+ g_clear_object (&plugin->priv->window);
+
+ G_OBJECT_CLASS (gedit_file_browser_plugin_parent_class)->dispose (object);
+}
+
+static void
+gedit_file_browser_plugin_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserPlugin *plugin = GEDIT_FILE_BROWSER_PLUGIN (object);
+
+ switch (prop_id)
+ {
+ case PROP_WINDOW:
+ plugin->priv->window = GEDIT_WINDOW (g_value_dup_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_plugin_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserPlugin *plugin = GEDIT_FILE_BROWSER_PLUGIN (object);
+
+ switch (prop_id)
+ {
+ case PROP_WINDOW:
+ g_value_set_object (value, plugin->priv->window);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+on_end_loading_cb (GeditFileBrowserStore *store,
+ GtkTreeIter *iter,
+ GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+
+ /* Disconnect the signal */
+ g_signal_handler_disconnect (store, priv->end_loading_handle);
+ priv->end_loading_handle = 0;
+ priv->auto_root = FALSE;
+}
+
+static void
+prepare_auto_root (GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ GeditFileBrowserStore *store;
+
+ priv->auto_root = TRUE;
+
+ store = gedit_file_browser_widget_get_browser_store (priv->tree_widget);
+
+ if (priv->end_loading_handle != 0)
+ {
+ g_signal_handler_disconnect (store, priv->end_loading_handle);
+ priv->end_loading_handle = 0;
+ }
+
+ priv->end_loading_handle = g_signal_connect (store,
+ "end-loading",
+ G_CALLBACK (on_end_loading_cb),
+ plugin);
+}
+
+static void
+restore_default_location (GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ gchar *root;
+ gchar *virtual_root;
+ gboolean bookmarks;
+ gboolean remote;
+
+ bookmarks = !g_settings_get_boolean (priv->settings,
+ FILEBROWSER_TREE_VIEW);
+
+ if (bookmarks)
+ {
+ gedit_file_browser_widget_show_bookmarks (priv->tree_widget);
+ return;
+ }
+
+ root = g_settings_get_string (priv->settings,
+ FILEBROWSER_ROOT);
+ virtual_root = g_settings_get_string (priv->settings,
+ FILEBROWSER_VIRTUAL_ROOT);
+
+ remote = g_settings_get_boolean (priv->settings,
+ FILEBROWSER_ENABLE_REMOTE);
+
+ if (root != NULL && *root != '\0')
+ {
+ GFile *rootfile;
+ GFile *vrootfile;
+
+ rootfile = g_file_new_for_uri (root);
+ vrootfile = g_file_new_for_uri (virtual_root);
+
+ if (remote || g_file_is_native (rootfile))
+ {
+ if (virtual_root != NULL && *virtual_root != '\0')
+ {
+ prepare_auto_root (plugin);
+ gedit_file_browser_widget_set_root_and_virtual_root (priv->tree_widget,
+ rootfile,
+ vrootfile);
+ }
+ else
+ {
+ prepare_auto_root (plugin);
+ gedit_file_browser_widget_set_root (priv->tree_widget,
+ rootfile,
+ TRUE);
+ }
+ }
+
+ g_object_unref (rootfile);
+ g_object_unref (vrootfile);
+ }
+
+ g_free (root);
+ g_free (virtual_root);
+}
+
+static void
+on_click_policy_changed (GSettings *settings,
+ const gchar *key,
+ GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ GeditFileBrowserViewClickPolicy policy;
+ GeditFileBrowserView *view;
+
+ policy = g_settings_get_enum (settings, key);
+
+ view = gedit_file_browser_widget_get_browser_view (priv->tree_widget);
+ gedit_file_browser_view_set_click_policy (view, policy);
+}
+
+static void
+install_nautilus_prefs (GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ GeditFileBrowserViewClickPolicy policy;
+ GeditFileBrowserView *view;
+
+ /* Get click_policy */
+ policy = g_settings_get_enum (priv->nautilus_settings,
+ NAUTILUS_CLICK_POLICY_KEY);
+
+ view = gedit_file_browser_widget_get_browser_view (priv->tree_widget);
+ gedit_file_browser_view_set_click_policy (view, policy);
+
+ priv->click_policy_handle =
+ g_signal_connect (priv->nautilus_settings,
+ "changed::" NAUTILUS_CLICK_POLICY_KEY,
+ G_CALLBACK (on_click_policy_changed),
+ plugin);
+}
+
+static void
+set_root_from_doc (GeditFileBrowserPlugin *plugin,
+ GeditDocument *doc)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ GtkSourceFile *file;
+ GFile *location;
+ GFile *parent;
+
+ if (doc == NULL)
+ {
+ return;
+ }
+
+ file = gedit_document_get_file (doc);
+ location = gtk_source_file_get_location (file);
+ if (location == NULL)
+ {
+ return;
+ }
+
+ parent = g_file_get_parent (location);
+
+ if (parent != NULL)
+ {
+ gedit_file_browser_widget_set_root (priv->tree_widget,
+ parent,
+ TRUE);
+
+ g_object_unref (parent);
+ }
+}
+
+static void
+set_active_root (GeditFileBrowserWidget *widget,
+ GeditFileBrowserPlugin *plugin)
+{
+ set_root_from_doc (plugin,
+ gedit_window_get_active_document (plugin->priv->window));
+}
+
+static gchar *
+get_terminal (GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ gchar *terminal;
+
+ terminal = g_settings_get_string (priv->terminal_settings,
+ TERMINAL_EXEC_KEY);
+
+ if (terminal == NULL)
+ {
+ const gchar *term = g_getenv ("TERM");
+
+ if (term != NULL)
+ terminal = g_strdup (term);
+ else
+ terminal = g_strdup ("xterm");
+ }
+
+ return terminal;
+}
+
+static void
+open_in_terminal (GeditFileBrowserWidget *widget,
+ GFile *location,
+ GeditFileBrowserPlugin *plugin)
+{
+ if (location)
+ {
+ gchar *terminal;
+ gchar *local;
+ gchar *argv[2];
+
+ terminal = get_terminal (plugin);
+ local = g_file_get_path (location);
+
+ argv[0] = terminal;
+ argv[1] = NULL;
+
+ g_spawn_async (local,
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ g_free (terminal);
+ g_free (local);
+ }
+}
+
+static void
+gedit_file_browser_plugin_update_state (GeditWindowActivatable *activatable)
+{
+ GeditFileBrowserPluginPrivate *priv = GEDIT_FILE_BROWSER_PLUGIN (activatable)->priv;
+ GeditDocument *doc;
+ GFile *location = NULL;
+
+ doc = gedit_window_get_active_document (priv->window);
+
+ if (doc != NULL)
+ {
+ TeplFile *file;
+
+ file = tepl_buffer_get_file (TEPL_BUFFER (doc));
+ location = tepl_file_get_location (file);
+ }
+
+ gedit_file_browser_widget_set_active_root_enabled (priv->tree_widget, location != NULL);
+}
+
+static void
+gedit_file_browser_plugin_activate (GeditWindowActivatable *activatable)
+{
+ GeditFileBrowserPlugin *plugin = GEDIT_FILE_BROWSER_PLUGIN (activatable);
+ GeditFileBrowserPluginPrivate *priv;
+ GtkWidget *panel;
+ GeditFileBrowserStore *store;
+
+ priv = plugin->priv;
+
+ priv->tree_widget = GEDIT_FILE_BROWSER_WIDGET (gedit_file_browser_widget_new ());
+
+ g_signal_connect (priv->tree_widget,
+ "location-activated",
+ G_CALLBACK (on_location_activated_cb), priv->window);
+
+ g_signal_connect (priv->tree_widget,
+ "error", G_CALLBACK (on_error_cb), plugin);
+
+ g_signal_connect (priv->tree_widget,
+ "confirm-delete",
+ G_CALLBACK (on_confirm_delete_cb),
+ plugin);
+
+ g_signal_connect (priv->tree_widget,
+ "confirm-no-trash",
+ G_CALLBACK (on_confirm_no_trash_cb),
+ priv->window);
+
+ g_signal_connect (priv->tree_widget,
+ "open-in-terminal",
+ G_CALLBACK (open_in_terminal),
+ plugin);
+
+ g_signal_connect (priv->tree_widget,
+ "set-active-root",
+ G_CALLBACK (set_active_root),
+ plugin);
+
+ g_settings_bind (priv->settings,
+ FILEBROWSER_FILTER_PATTERN,
+ priv->tree_widget,
+ FILEBROWSER_FILTER_PATTERN,
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+
+ panel = gedit_window_get_side_panel (priv->window);
+
+ gtk_stack_add_titled (GTK_STACK (panel),
+ GTK_WIDGET (priv->tree_widget),
+ "GeditFileBrowserPanel",
+ _("File Browser"));
+
+ gtk_widget_show (GTK_WIDGET (priv->tree_widget));
+
+ /* Install nautilus preferences */
+ install_nautilus_prefs (plugin);
+
+ /* Connect signals to store the last visited location */
+ g_signal_connect (gedit_file_browser_widget_get_browser_view (priv->tree_widget),
+ "notify::model",
+ G_CALLBACK (on_model_set_cb),
+ plugin);
+
+ store = gedit_file_browser_widget_get_browser_store (priv->tree_widget);
+
+ g_settings_bind (priv->settings,
+ FILEBROWSER_FILTER_MODE,
+ store,
+ FILEBROWSER_FILTER_MODE,
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+
+ g_settings_bind (priv->settings,
+ FILEBROWSER_BINARY_PATTERNS,
+ store,
+ FILEBROWSER_BINARY_PATTERNS,
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+
+ g_signal_connect (store,
+ "notify::virtual-root",
+ G_CALLBACK (on_virtual_root_changed_cb),
+ plugin);
+
+ g_signal_connect (store,
+ "rename",
+ G_CALLBACK (on_rename_cb),
+ priv->window);
+
+ g_signal_connect (priv->window,
+ "tab-added",
+ G_CALLBACK (on_tab_added_cb),
+ plugin);
+
+ /* Register messages on the bus */
+ gedit_file_browser_messages_register (priv->window, priv->tree_widget);
+
+ gedit_file_browser_plugin_update_state (activatable);
+}
+
+static void
+gedit_file_browser_plugin_deactivate (GeditWindowActivatable *activatable)
+{
+ GeditFileBrowserPlugin *plugin = GEDIT_FILE_BROWSER_PLUGIN (activatable);
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ GtkWidget *panel;
+
+
+ /* Unregister messages from the bus */
+ gedit_file_browser_messages_unregister (priv->window);
+
+ /* Disconnect signals */
+ g_signal_handlers_disconnect_by_func (priv->window,
+ G_CALLBACK (on_tab_added_cb),
+ plugin);
+
+ if (priv->click_policy_handle)
+ {
+ g_signal_handler_disconnect (priv->nautilus_settings,
+ priv->click_policy_handle);
+ }
+
+ panel = gedit_window_get_side_panel (priv->window);
+ gtk_container_remove (GTK_CONTAINER (panel), GTK_WIDGET (priv->tree_widget));
+}
+
+static void
+gedit_file_browser_plugin_class_init (GeditFileBrowserPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gedit_file_browser_plugin_dispose;
+ object_class->set_property = gedit_file_browser_plugin_set_property;
+ object_class->get_property = gedit_file_browser_plugin_get_property;
+
+ g_object_class_override_property (object_class, PROP_WINDOW, "window");
+}
+
+static void
+gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface)
+{
+ iface->activate = gedit_file_browser_plugin_activate;
+ iface->deactivate = gedit_file_browser_plugin_deactivate;
+ iface->update_state = gedit_file_browser_plugin_update_state;
+}
+
+static void
+gedit_file_browser_plugin_class_finalize (GeditFileBrowserPluginClass *klass)
+{
+}
+
+/* Callbacks */
+static void
+on_location_activated_cb (GeditFileBrowserWidget *tree_widget,
+ GFile *location,
+ GeditWindow *window)
+{
+ gedit_commands_load_location (window, location, NULL, 0, 0);
+}
+
+static void
+on_error_cb (GeditFileBrowserWidget *tree_widget,
+ guint code,
+ gchar const *message,
+ GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ gchar *title;
+ GtkWidget *dlg;
+
+ /* Do not show the error when the root has been set automatically */
+ if (priv->auto_root && (code == GEDIT_FILE_BROWSER_ERROR_SET_ROOT ||
+ code == GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY))
+ {
+ /* Show bookmarks */
+ gedit_file_browser_widget_show_bookmarks (priv->tree_widget);
+ return;
+ }
+
+ switch (code)
+ {
+ case GEDIT_FILE_BROWSER_ERROR_NEW_DIRECTORY:
+ title = _("An error occurred while creating a new directory");
+ break;
+ case GEDIT_FILE_BROWSER_ERROR_NEW_FILE:
+ title = _("An error occurred while creating a new file");
+ break;
+ case GEDIT_FILE_BROWSER_ERROR_RENAME:
+ title = _("An error occurred while renaming a file or directory");
+ break;
+ case GEDIT_FILE_BROWSER_ERROR_DELETE:
+ title = _("An error occurred while deleting a file or directory");
+ break;
+ case GEDIT_FILE_BROWSER_ERROR_OPEN_DIRECTORY:
+ title = _("An error occurred while opening a directory in the file manager");
+ break;
+ case GEDIT_FILE_BROWSER_ERROR_SET_ROOT:
+ title = _("An error occurred while setting a root directory");
+ break;
+ case GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY:
+ title = _("An error occurred while loading a directory");
+ break;
+ default:
+ title = _("An error occurred");
+ break;
+ }
+
+ dlg = gtk_message_dialog_new (GTK_WINDOW (priv->window),
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "%s", title);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg),
+ "%s", message);
+
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+}
+
+static void
+on_model_set_cb (GeditFileBrowserView *widget,
+ GParamSpec *param,
+ GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ GtkTreeModel *model;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (gedit_file_browser_widget_get_browser_view (priv->tree_widget)));
+
+ if (model == NULL)
+ return;
+
+ g_settings_set_boolean (priv->settings,
+ FILEBROWSER_TREE_VIEW,
+ GEDIT_IS_FILE_BROWSER_STORE (model));
+}
+
+static void
+on_rename_cb (GeditFileBrowserStore *store,
+ GFile *oldfile,
+ GFile *newfile,
+ GeditWindow *window)
+{
+ GList *documents;
+ GList *item;
+
+ /* Find all documents and set its uri to newuri where it matches olduri */
+ documents = gedit_app_get_documents (GEDIT_APP (g_application_get_default ()));
+
+ for (item = documents; item; item = item->next)
+ {
+ GeditDocument *doc;
+ GtkSourceFile *source_file;
+ GFile *docfile;
+
+ doc = GEDIT_DOCUMENT (item->data);
+ source_file = gedit_document_get_file (doc);
+ docfile = gtk_source_file_get_location (source_file);
+
+ if (docfile == NULL)
+ {
+ continue;
+ }
+
+ if (g_file_equal (docfile, oldfile))
+ {
+ gtk_source_file_set_location (source_file, newfile);
+ }
+ else
+ {
+ gchar *relative;
+
+ relative = g_file_get_relative_path (oldfile, docfile);
+
+ if (relative != NULL)
+ {
+ /* Relative now contains the part in docfile without
+ the prefix oldfile */
+
+ docfile = g_file_get_child (newfile, relative);
+
+ gtk_source_file_set_location (source_file, docfile);
+
+ g_object_unref (docfile);
+ }
+
+ g_free (relative);
+ }
+ }
+
+ g_list_free (documents);
+}
+
+static void
+on_virtual_root_changed_cb (GeditFileBrowserStore *store,
+ GParamSpec *param,
+ GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ GFile *root;
+ GFile *virtual_root;
+ gchar *uri_root = NULL;
+
+ root = gedit_file_browser_store_get_root (store);
+
+ if (!root)
+ {
+ return;
+ }
+ else
+ {
+ uri_root = g_file_get_uri (root);
+ g_object_unref (root);
+ }
+
+ g_settings_set_string (priv->settings,
+ FILEBROWSER_ROOT,
+ uri_root);
+
+ virtual_root = gedit_file_browser_store_get_virtual_root (store);
+
+ if (!virtual_root)
+ {
+ /* Set virtual to same as root then */
+ g_settings_set_string (priv->settings,
+ FILEBROWSER_VIRTUAL_ROOT,
+ uri_root);
+ }
+ else
+ {
+ gchar *uri_vroot;
+
+ uri_vroot = g_file_get_uri (virtual_root);
+
+ g_settings_set_string (priv->settings,
+ FILEBROWSER_VIRTUAL_ROOT,
+ uri_vroot);
+ g_free (uri_vroot);
+ g_object_unref (virtual_root);
+ }
+
+ g_signal_handlers_disconnect_by_func (priv->window,
+ G_CALLBACK (on_tab_added_cb),
+ plugin);
+ g_free (uri_root);
+}
+
+static void
+on_tab_added_cb (GeditWindow *window,
+ GeditTab *tab,
+ GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ gboolean open;
+ gboolean load_default = TRUE;
+
+ open = g_settings_get_boolean (priv->settings,
+ FILEBROWSER_OPEN_AT_FIRST_DOC);
+
+ if (open)
+ {
+ GeditDocument *doc;
+ GtkSourceFile *file;
+ GFile *location;
+
+ doc = gedit_tab_get_document (tab);
+ file = gedit_document_get_file (doc);
+ location = gtk_source_file_get_location (file);
+
+ if (location != NULL)
+ {
+ if (g_file_has_uri_scheme (location, "file"))
+ {
+ prepare_auto_root (plugin);
+ set_root_from_doc (plugin, doc);
+ load_default = FALSE;
+ }
+ }
+ }
+
+ if (load_default)
+ restore_default_location (plugin);
+
+ /* Disconnect this signal, it's only called once */
+ g_signal_handlers_disconnect_by_func (window,
+ G_CALLBACK (on_tab_added_cb),
+ plugin);
+}
+
+static gchar *
+get_filename_from_path (GtkTreeModel *model,
+ GtkTreePath *path)
+{
+ GtkTreeIter iter;
+ GFile *location;
+ gchar *ret = NULL;
+
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ {
+ return NULL;
+ }
+
+ gtk_tree_model_get (model, &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ if (location)
+ {
+ ret = gedit_file_browser_utils_file_basename (location);
+ g_object_unref (location);
+ }
+
+ return ret;
+}
+
+static gboolean
+on_confirm_no_trash_cb (GeditFileBrowserWidget *widget,
+ GList *files,
+ GeditWindow *window)
+{
+ gchar *normal;
+ gchar *message;
+ gchar *secondary;
+ gboolean result;
+
+ message = _("Cannot move file to trash, do you\nwant to delete permanently?");
+
+ if (files->next == NULL)
+ {
+ normal = gedit_file_browser_utils_file_basename (G_FILE (files->data));
+ secondary = g_strdup_printf (_("The file “%s” cannot be moved to the trash."), normal);
+ g_free (normal);
+ }
+ else
+ {
+ secondary = g_strdup (_("The selected files cannot be moved to the trash."));
+ }
+
+ result = gedit_file_browser_utils_confirmation_dialog (window,
+ GTK_MESSAGE_QUESTION,
+ message,
+ secondary,
+ _("_Delete"));
+ g_free (secondary);
+
+ return result;
+}
+
+static gboolean
+on_confirm_delete_cb (GeditFileBrowserWidget *widget,
+ GeditFileBrowserStore *store,
+ GList *paths,
+ GeditFileBrowserPlugin *plugin)
+{
+ GeditFileBrowserPluginPrivate *priv = plugin->priv;
+ gchar *normal;
+ gchar *message;
+ gchar *secondary;
+ gboolean result;
+
+ if (paths->next == NULL)
+ {
+ normal = get_filename_from_path (GTK_TREE_MODEL (store), (GtkTreePath *)(paths->data));
+ message = g_strdup_printf (_("Are you sure you want to permanently delete “%s”?"), normal);
+ g_free (normal);
+ }
+ else
+ {
+ message = g_strdup (_("Are you sure you want to permanently delete the selected files?"));
+ }
+
+ secondary = _("If you delete an item, it is permanently lost.");
+
+ result = gedit_file_browser_utils_confirmation_dialog (priv->window,
+ GTK_MESSAGE_QUESTION,
+ message,
+ secondary,
+ _("_Delete"));
+
+ g_free (message);
+
+ return result;
+}
+
+G_MODULE_EXPORT void
+peas_register_types (PeasObjectModule *module)
+{
+ gedit_file_browser_plugin_register_type (G_TYPE_MODULE (module));
+
+ peas_object_module_register_extension_type (module,
+ GEDIT_TYPE_WINDOW_ACTIVATABLE,
+ GEDIT_TYPE_FILE_BROWSER_PLUGIN);
+}
+
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-plugin.h b/plugins/filebrowser/gedit-file-browser-plugin.h
new file mode 100644
index 0000000..27fe706
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-plugin.h
@@ -0,0 +1,70 @@
+/*
+ * gedit-file-browser-plugin.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GEDIT_FILE_BROWSER_PLUGIN_H
+#define GEDIT_FILE_BROWSER_PLUGIN_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libpeas/peas-extension-base.h>
+#include <libpeas/peas-object-module.h>
+
+G_BEGIN_DECLS
+/*
+ * Type checking and casting macros
+ */
+#define GEDIT_TYPE_FILE_BROWSER_PLUGIN (gedit_file_browser_plugin_get_type ())
+#define GEDIT_FILE_BROWSER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_FILE_BROWSER_PLUGIN, GeditFileBrowserPlugin))
+#define GEDIT_FILE_BROWSER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_FILE_BROWSER_PLUGIN, GeditFileBrowserPluginClass))
+#define GEDIT_IS_FILE_BROWSER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_FILE_BROWSER_PLUGIN))
+#define GEDIT_IS_FILE_BROWSER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_FILE_BROWSER_PLUGIN))
+#define GEDIT_FILE_BROWSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_FILE_BROWSER_PLUGIN, GeditFileBrowserPluginClass))
+
+/* Private structure type */
+typedef struct _GeditFileBrowserPluginPrivate GeditFileBrowserPluginPrivate;
+typedef struct _GeditFileBrowserPlugin GeditFileBrowserPlugin;
+typedef struct _GeditFileBrowserPluginClass GeditFileBrowserPluginClass;
+
+struct _GeditFileBrowserPlugin
+{
+ GObject parent_instance;
+
+ /* < private > */
+ GeditFileBrowserPluginPrivate *priv;
+};
+
+struct _GeditFileBrowserPluginClass
+{
+ GObjectClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType gedit_file_browser_plugin_get_type (void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module);
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_PLUGIN_H */
+
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-store.c b/plugins/filebrowser/gedit-file-browser-store.c
new file mode 100644
index 0000000..ef19b55
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-store.c
@@ -0,0 +1,3672 @@
+/*
+ * gedit-file-browser-store.c - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include <gedit/gedit-utils.h>
+
+#include "gedit-file-browser-store.h"
+#include "gedit-file-browser-enum-types.h"
+#include "gedit-file-browser-error.h"
+#include "gedit-file-browser-utils.h"
+
+#define NODE_IS_DIR(node) (FILE_IS_DIR((node)->flags))
+#define NODE_IS_HIDDEN(node) (FILE_IS_HIDDEN((node)->flags))
+#define NODE_IS_TEXT(node) (FILE_IS_TEXT((node)->flags))
+#define NODE_LOADED(node) (FILE_LOADED((node)->flags))
+#define NODE_IS_FILTERED(node) (FILE_IS_FILTERED((node)->flags))
+#define NODE_IS_DUMMY(node) (FILE_IS_DUMMY((node)->flags))
+
+#define FILE_BROWSER_NODE_DIR(node) ((FileBrowserNodeDir *)(node))
+
+#define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100
+#define STANDARD_ATTRIBUTE_TYPES G_FILE_ATTRIBUTE_STANDARD_TYPE "," \
+ G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," \
+ G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP "," \
+ G_FILE_ATTRIBUTE_STANDARD_NAME "," \
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
+ G_FILE_ATTRIBUTE_STANDARD_ICON
+
+typedef struct _FileBrowserNode FileBrowserNode;
+typedef struct _FileBrowserNodeDir FileBrowserNodeDir;
+typedef struct _AsyncData AsyncData;
+typedef struct _AsyncNode AsyncNode;
+
+typedef gint (*SortFunc) (FileBrowserNode *node1,
+ FileBrowserNode *node2);
+
+struct _AsyncData
+{
+ GeditFileBrowserStore *model;
+ GCancellable *cancellable;
+ gboolean trash;
+ GList *files;
+ GList *iter;
+ gboolean removed;
+};
+
+struct _AsyncNode
+{
+ FileBrowserNodeDir *dir;
+ GCancellable *cancellable;
+ GSList *original_children;
+};
+
+typedef struct {
+ GeditFileBrowserStore *model;
+ GFile *virtual_root;
+ GMountOperation *operation;
+ GCancellable *cancellable;
+} MountInfo;
+
+struct _FileBrowserNode
+{
+ GFile *file;
+ guint flags;
+ gchar *icon_name;
+ gchar *name;
+ gchar *markup;
+
+ GdkPixbuf *icon;
+ GdkPixbuf *emblem;
+
+ FileBrowserNode *parent;
+ gint pos;
+ gboolean inserted;
+};
+
+struct _FileBrowserNodeDir
+{
+ FileBrowserNode node;
+ GSList *children;
+
+ GCancellable *cancellable;
+ GFileMonitor *monitor;
+ GeditFileBrowserStore *model;
+};
+
+struct _GeditFileBrowserStorePrivate
+{
+ FileBrowserNode *root;
+ FileBrowserNode *virtual_root;
+ GType column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_NUM];
+
+ GeditFileBrowserStoreFilterMode filter_mode;
+ GeditFileBrowserStoreFilterFunc filter_func;
+ gpointer filter_user_data;
+
+ gchar **binary_patterns;
+ GPtrArray *binary_pattern_specs;
+
+ SortFunc sort_func;
+
+ GSList *async_handles;
+ MountInfo *mount_info;
+};
+
+static FileBrowserNode *model_find_node (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ GFile *uri);
+static void model_remove_node (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ GtkTreePath *path,
+ gboolean free_nodes);
+
+static void set_virtual_root_from_node (GeditFileBrowserStore *model,
+ FileBrowserNode *node);
+
+static void gedit_file_browser_store_iface_init (GtkTreeModelIface *iface);
+static GtkTreeModelFlags gedit_file_browser_store_get_flags (GtkTreeModel *tree_model);
+static gint gedit_file_browser_store_get_n_columns (GtkTreeModel *tree_model);
+static GType gedit_file_browser_store_get_column_type (GtkTreeModel *tree_model,
+ gint index);
+static gboolean gedit_file_browser_store_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
+static GtkTreePath *gedit_file_browser_store_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static void gedit_file_browser_store_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value);
+static gboolean gedit_file_browser_store_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean gedit_file_browser_store_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent);
+static gboolean gedit_file_browser_store_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gint gedit_file_browser_store_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean gedit_file_browser_store_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n);
+static gboolean gedit_file_browser_store_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child);
+static void gedit_file_browser_store_row_inserted (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ GtkTreeIter *iter);
+
+static void gedit_file_browser_store_drag_source_init (GtkTreeDragSourceIface *iface);
+static gboolean gedit_file_browser_store_row_draggable (GtkTreeDragSource *drag_source,
+ GtkTreePath *path);
+static gboolean gedit_file_browser_store_drag_data_delete (GtkTreeDragSource *drag_source,
+ GtkTreePath *path);
+static gboolean gedit_file_browser_store_drag_data_get (GtkTreeDragSource *drag_source,
+ GtkTreePath *path,
+ GtkSelectionData *selection_data);
+
+static void file_browser_node_free (GeditFileBrowserStore *model,
+ FileBrowserNode *node);
+static void model_add_node (GeditFileBrowserStore *model,
+ FileBrowserNode *child,
+ FileBrowserNode *parent);
+static void model_clear (GeditFileBrowserStore *model,
+ gboolean free_nodes);
+static gint model_sort_default (FileBrowserNode *node1,
+ FileBrowserNode *node2);
+static void model_check_dummy (GeditFileBrowserStore *model,
+ FileBrowserNode *node);
+static void next_files_async (GFileEnumerator *enumerator,
+ AsyncNode *async);
+
+static void delete_files (AsyncData *data);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditFileBrowserStore, gedit_file_browser_store,
+ G_TYPE_OBJECT,
+ 0,
+ G_ADD_PRIVATE_DYNAMIC (GeditFileBrowserStore)
+ G_IMPLEMENT_INTERFACE_DYNAMIC (GTK_TYPE_TREE_MODEL,
+ gedit_file_browser_store_iface_init)
+ G_IMPLEMENT_INTERFACE_DYNAMIC (GTK_TYPE_TREE_DRAG_SOURCE,
+ gedit_file_browser_store_drag_source_init))
+
+/* Properties */
+enum {
+ PROP_0,
+
+ PROP_ROOT,
+ PROP_VIRTUAL_ROOT,
+ PROP_FILTER_MODE,
+ PROP_BINARY_PATTERNS
+};
+
+/* Signals */
+enum
+{
+ BEGIN_LOADING,
+ END_LOADING,
+ ERROR,
+ NO_TRASH,
+ RENAME,
+ BEGIN_REFRESH,
+ END_REFRESH,
+ UNLOAD,
+ BEFORE_ROW_DELETED,
+ NUM_SIGNALS
+};
+
+static guint model_signals[NUM_SIGNALS] = { 0 };
+
+static void
+cancel_mount_operation (GeditFileBrowserStore *obj)
+{
+ if (obj->priv->mount_info != NULL)
+ {
+ obj->priv->mount_info->model = NULL;
+ g_cancellable_cancel (obj->priv->mount_info->cancellable);
+ obj->priv->mount_info = NULL;
+ }
+}
+
+static void
+gedit_file_browser_store_finalize (GObject *object)
+{
+ GeditFileBrowserStore *obj = GEDIT_FILE_BROWSER_STORE (object);
+
+ /* Free all the nodes */
+ file_browser_node_free (obj, obj->priv->root);
+
+ if (obj->priv->binary_patterns != NULL)
+ {
+ g_strfreev (obj->priv->binary_patterns);
+ g_ptr_array_unref (obj->priv->binary_pattern_specs);
+ }
+
+ /* Cancel any asynchronous operations */
+ for (GSList *item = obj->priv->async_handles; item; item = item->next)
+ {
+ AsyncData *data = (AsyncData *)(item->data);
+ g_cancellable_cancel (data->cancellable);
+
+ data->removed = TRUE;
+ }
+
+ cancel_mount_operation (obj);
+
+ g_slist_free (obj->priv->async_handles);
+ G_OBJECT_CLASS (gedit_file_browser_store_parent_class)->finalize (object);
+}
+
+static void
+set_gvalue_from_node (GValue *value,
+ FileBrowserNode *node)
+{
+ if (node == NULL)
+ g_value_set_object (value, NULL);
+ else
+ g_value_set_object (value, node->file);
+}
+
+static void
+gedit_file_browser_store_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserStore *obj = GEDIT_FILE_BROWSER_STORE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ set_gvalue_from_node (value, obj->priv->root);
+ break;
+ case PROP_VIRTUAL_ROOT:
+ set_gvalue_from_node (value, obj->priv->virtual_root);
+ break;
+ case PROP_FILTER_MODE:
+ g_value_set_flags (value, obj->priv->filter_mode);
+ break;
+ case PROP_BINARY_PATTERNS:
+ g_value_set_boxed (value, obj->priv->binary_patterns);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_store_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserStore *obj = GEDIT_FILE_BROWSER_STORE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ gedit_file_browser_store_set_root (obj, G_FILE (g_value_get_object (value)));
+ break;
+ case PROP_FILTER_MODE:
+ gedit_file_browser_store_set_filter_mode (obj, g_value_get_flags (value));
+ break;
+ case PROP_BINARY_PATTERNS:
+ gedit_file_browser_store_set_binary_patterns (obj, g_value_get_boxed (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_store_class_init (GeditFileBrowserStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gedit_file_browser_store_finalize;
+ object_class->get_property = gedit_file_browser_store_get_property;
+ object_class->set_property = gedit_file_browser_store_set_property;
+
+ g_object_class_install_property (object_class, PROP_ROOT,
+ g_param_spec_object ("root",
+ "Root",
+ "The root location",
+ G_TYPE_FILE,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROP_VIRTUAL_ROOT,
+ g_param_spec_object ("virtual-root",
+ "Virtual Root",
+ "The virtual root location",
+ G_TYPE_FILE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class, PROP_FILTER_MODE,
+ g_param_spec_flags ("filter-mode",
+ "Filter Mode",
+ "The filter mode",
+ GEDIT_TYPE_FILE_BROWSER_STORE_FILTER_MODE,
+ gedit_file_browser_store_filter_mode_get_default (),
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROP_BINARY_PATTERNS,
+ g_param_spec_boxed ("binary-patterns",
+ "Binary Patterns",
+ "The binary patterns",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
+
+ model_signals[BEGIN_LOADING] =
+ g_signal_new ("begin-loading",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, begin_loading),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER);
+ model_signals[END_LOADING] =
+ g_signal_new ("end-loading",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, end_loading),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER);
+ model_signals[ERROR] =
+ g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, error),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+ model_signals[NO_TRASH] =
+ g_signal_new ("no-trash", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, no_trash),
+ g_signal_accumulator_true_handled, NULL, NULL,
+ G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
+ model_signals[RENAME] =
+ g_signal_new ("rename",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, rename),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_FILE, G_TYPE_FILE);
+ model_signals[BEGIN_REFRESH] =
+ g_signal_new ("begin-refresh",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, begin_refresh),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+ model_signals[END_REFRESH] =
+ g_signal_new ("end-refresh",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, end_refresh),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+ model_signals[UNLOAD] =
+ g_signal_new ("unload",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, unload),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_FILE);
+ model_signals[BEFORE_ROW_DELETED] =
+ g_signal_new ("before-row-deleted",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserStoreClass, before_row_deleted),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE);
+}
+
+static void
+gedit_file_browser_store_class_finalize (GeditFileBrowserStoreClass *klass)
+{
+}
+
+static void
+gedit_file_browser_store_iface_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = gedit_file_browser_store_get_flags;
+ iface->get_n_columns = gedit_file_browser_store_get_n_columns;
+ iface->get_column_type = gedit_file_browser_store_get_column_type;
+ iface->get_iter = gedit_file_browser_store_get_iter;
+ iface->get_path = gedit_file_browser_store_get_path;
+ iface->get_value = gedit_file_browser_store_get_value;
+ iface->iter_next = gedit_file_browser_store_iter_next;
+ iface->iter_children = gedit_file_browser_store_iter_children;
+ iface->iter_has_child = gedit_file_browser_store_iter_has_child;
+ iface->iter_n_children = gedit_file_browser_store_iter_n_children;
+ iface->iter_nth_child = gedit_file_browser_store_iter_nth_child;
+ iface->iter_parent = gedit_file_browser_store_iter_parent;
+ iface->row_inserted = gedit_file_browser_store_row_inserted;
+}
+
+static void
+gedit_file_browser_store_drag_source_init (GtkTreeDragSourceIface *iface)
+{
+ iface->row_draggable = gedit_file_browser_store_row_draggable;
+ iface->drag_data_delete = gedit_file_browser_store_drag_data_delete;
+ iface->drag_data_get = gedit_file_browser_store_drag_data_get;
+}
+
+static void
+gedit_file_browser_store_init (GeditFileBrowserStore *obj)
+{
+ obj->priv = gedit_file_browser_store_get_instance_private (obj);
+
+ obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION] = G_TYPE_FILE;
+ obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP] = G_TYPE_STRING;
+ obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS] = G_TYPE_UINT;
+ obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_ICON] = GDK_TYPE_PIXBUF;
+ obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_ICON_NAME] = G_TYPE_STRING;
+ obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_NAME] = G_TYPE_STRING;
+ obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM] = GDK_TYPE_PIXBUF;
+
+ /* Default filter mode is hiding the hidden files */
+ obj->priv->filter_mode = gedit_file_browser_store_filter_mode_get_default ();
+ obj->priv->sort_func = model_sort_default;
+}
+
+static gboolean
+node_has_parent (FileBrowserNode *node,
+ FileBrowserNode *parent)
+{
+ if (node->parent == NULL)
+ return FALSE;
+
+ if (node->parent == parent)
+ return TRUE;
+
+ return node_has_parent (node->parent, parent);
+}
+
+static gboolean
+node_in_tree (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ return node_has_parent (node, model->priv->virtual_root);
+}
+
+static gboolean
+model_node_visibility (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ if (node == NULL)
+ return FALSE;
+
+ if (NODE_IS_DUMMY (node))
+ return !NODE_IS_HIDDEN (node);
+
+ if (node == model->priv->virtual_root)
+ return TRUE;
+
+ if (!node_has_parent (node, model->priv->virtual_root))
+ return FALSE;
+
+ return !NODE_IS_FILTERED (node);
+}
+
+static gboolean
+model_node_inserted (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ return node == model->priv->virtual_root ||
+ (model_node_visibility (model, node) && node->inserted);
+}
+
+/* Interface implementation */
+
+static GtkTreeModelFlags
+gedit_file_browser_store_get_flags (GtkTreeModel *tree_model)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), (GtkTreeModelFlags) 0);
+
+ return GTK_TREE_MODEL_ITERS_PERSIST;
+}
+
+static gint
+gedit_file_browser_store_get_n_columns (GtkTreeModel *tree_model)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), 0);
+
+ return GEDIT_FILE_BROWSER_STORE_COLUMN_NUM;
+}
+
+static GType
+gedit_file_browser_store_get_column_type (GtkTreeModel *tree_model,
+ gint idx)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), G_TYPE_INVALID);
+ g_return_val_if_fail (idx < GEDIT_FILE_BROWSER_STORE_COLUMN_NUM && idx >= 0, G_TYPE_INVALID);
+
+ return GEDIT_FILE_BROWSER_STORE (tree_model)->priv->column_types[idx];
+}
+
+static gboolean
+gedit_file_browser_store_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ GeditFileBrowserStore *model;
+ FileBrowserNode *node;
+ gint *indices, depth;
+
+ g_assert (GEDIT_IS_FILE_BROWSER_STORE (tree_model));
+ g_assert (path != NULL);
+
+ model = GEDIT_FILE_BROWSER_STORE (tree_model);
+ indices = gtk_tree_path_get_indices (path);
+ depth = gtk_tree_path_get_depth (path);
+ node = model->priv->virtual_root;
+
+ for (guint i = 0; i < depth; ++i)
+ {
+ GSList *item;
+ gint num = 0;
+
+ if (node == NULL)
+ return FALSE;
+
+ if (!NODE_IS_DIR (node))
+ return FALSE;
+
+ for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ {
+ FileBrowserNode *child = (FileBrowserNode *)(item->data);
+
+ if (model_node_inserted (model, child))
+ {
+ if (num == indices[i])
+ break;
+
+ num++;
+ }
+ }
+
+ if (item == NULL)
+ return FALSE;
+
+ node = (FileBrowserNode *)(item->data);
+ }
+
+ iter->user_data = node;
+ iter->user_data2 = NULL;
+ iter->user_data3 = NULL;
+
+ return node != NULL;
+}
+
+static GtkTreePath *
+gedit_file_browser_store_get_path_real (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ GtkTreePath *path = gtk_tree_path_new ();
+ gint num = 0;
+
+ while (node != model->priv->virtual_root)
+ {
+ if (node->parent == NULL)
+ {
+ gtk_tree_path_free (path);
+ return NULL;
+ }
+
+ num = 0;
+
+ for (GSList *item = FILE_BROWSER_NODE_DIR (node->parent)->children; item; item = item->next)
+ {
+ FileBrowserNode *check = (FileBrowserNode *)(item->data);
+
+ if (model_node_visibility (model, check) && (check == node || check->inserted))
+ {
+ if (check == node)
+ {
+ gtk_tree_path_prepend_index (path, num);
+ break;
+ }
+
+ ++num;
+ }
+ else if (check == node)
+ {
+ if (NODE_IS_DUMMY (node))
+ g_warning ("Dummy not visible???");
+
+ gtk_tree_path_free (path);
+ return NULL;
+ }
+ }
+
+ node = node->parent;
+ }
+
+ return path;
+}
+
+static GtkTreePath *
+gedit_file_browser_store_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (iter->user_data != NULL, NULL);
+
+ return gedit_file_browser_store_get_path_real (GEDIT_FILE_BROWSER_STORE (tree_model),
+ (FileBrowserNode *)(iter->user_data));
+}
+
+static void
+gedit_file_browser_store_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ FileBrowserNode *node;
+
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->user_data != NULL);
+
+ node = (FileBrowserNode *)(iter->user_data);
+
+ g_value_init (value, GEDIT_FILE_BROWSER_STORE (tree_model)->priv->column_types[column]);
+
+ switch (column)
+ {
+ case GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION:
+ set_gvalue_from_node (value, node);
+ break;
+ case GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP:
+ g_value_set_string (value, node->markup);
+ break;
+ case GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS:
+ g_value_set_uint (value, node->flags);
+ break;
+ case GEDIT_FILE_BROWSER_STORE_COLUMN_ICON:
+ g_value_set_object (value, node->icon);
+ break;
+ case GEDIT_FILE_BROWSER_STORE_COLUMN_ICON_NAME:
+ g_value_set_string (value, node->icon_name);
+ break;
+ case GEDIT_FILE_BROWSER_STORE_COLUMN_NAME:
+ g_value_set_string (value, node->name);
+ break;
+ case GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM:
+ g_value_set_object (value, node->emblem);
+ break;
+ default:
+ g_return_if_reached ();
+ }
+}
+
+static gboolean
+gedit_file_browser_store_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ GeditFileBrowserStore *model;
+ FileBrowserNode *node;
+ GSList *first;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+
+ model = GEDIT_FILE_BROWSER_STORE (tree_model);
+ node = (FileBrowserNode *)(iter->user_data);
+
+ if (node->parent == NULL)
+ return FALSE;
+
+ first = g_slist_next (g_slist_find (FILE_BROWSER_NODE_DIR (node->parent)->children, node));
+
+ for (GSList *item = first; item; item = item->next)
+ {
+ if (model_node_inserted (model, (FileBrowserNode *)(item->data)))
+ {
+ iter->user_data = item->data;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gedit_file_browser_store_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ FileBrowserNode *node;
+ GeditFileBrowserStore *model;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), FALSE);
+ g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
+
+ model = GEDIT_FILE_BROWSER_STORE (tree_model);
+
+ if (parent == NULL)
+ node = model->priv->virtual_root;
+ else
+ node = (FileBrowserNode *)(parent->user_data);
+
+ if (node == NULL)
+ return FALSE;
+
+ if (!NODE_IS_DIR (node))
+ return FALSE;
+
+ for (GSList *item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ {
+ if (model_node_inserted (model, (FileBrowserNode *)(item->data)))
+ {
+ iter->user_data = item->data;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+filter_tree_model_iter_has_child_real (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ if (!NODE_IS_DIR (node))
+ return FALSE;
+
+ for (GSList *item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ {
+ if (model_node_inserted (model, (FileBrowserNode *)(item->data)))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gedit_file_browser_store_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ FileBrowserNode *node;
+ GeditFileBrowserStore *model;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), FALSE);
+ g_return_val_if_fail (iter == NULL || iter->user_data != NULL, FALSE);
+
+ model = GEDIT_FILE_BROWSER_STORE (tree_model);
+
+ if (iter == NULL)
+ node = model->priv->virtual_root;
+ else
+ node = (FileBrowserNode *)(iter->user_data);
+
+ return filter_tree_model_iter_has_child_real (model, node);
+}
+
+static gint
+gedit_file_browser_store_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ FileBrowserNode *node;
+ GeditFileBrowserStore *model;
+ gint num = 0;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), FALSE);
+ g_return_val_if_fail (iter == NULL || iter->user_data != NULL, FALSE);
+
+ model = GEDIT_FILE_BROWSER_STORE (tree_model);
+
+ if (iter == NULL)
+ node = model->priv->virtual_root;
+ else
+ node = (FileBrowserNode *)(iter->user_data);
+
+ if (!NODE_IS_DIR (node))
+ return 0;
+
+ for (GSList *item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ {
+ if (model_node_inserted (model, (FileBrowserNode *)(item->data)))
+ ++num;
+ }
+
+ return num;
+}
+
+static gboolean
+gedit_file_browser_store_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ FileBrowserNode *node;
+ GeditFileBrowserStore *model;
+ gint num = 0;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), FALSE);
+ g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
+
+ model = GEDIT_FILE_BROWSER_STORE (tree_model);
+
+ if (parent == NULL)
+ node = model->priv->virtual_root;
+ else
+ node = (FileBrowserNode *)(parent->user_data);
+
+ if (!NODE_IS_DIR (node))
+ return FALSE;
+
+ for (GSList *item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ {
+ if (model_node_inserted (model, (FileBrowserNode *)(item->data)))
+ {
+ if (num == n)
+ {
+ iter->user_data = item->data;
+ return TRUE;
+ }
+
+ ++num;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gedit_file_browser_store_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ FileBrowserNode *node;
+ GeditFileBrowserStore *model;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), FALSE);
+ g_return_val_if_fail (child != NULL, FALSE);
+ g_return_val_if_fail (child->user_data != NULL, FALSE);
+
+ node = (FileBrowserNode *)(child->user_data);
+ model = GEDIT_FILE_BROWSER_STORE (tree_model);
+
+ if (!node_in_tree (model, node))
+ return FALSE;
+
+ if (node->parent == NULL)
+ return FALSE;
+
+ iter->user_data = node->parent;
+ return TRUE;
+}
+
+static void
+gedit_file_browser_store_row_inserted (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ GtkTreeIter *iter)
+{
+ FileBrowserNode *node = (FileBrowserNode *)(iter->user_data);
+
+ node->inserted = TRUE;
+}
+
+static gboolean
+gedit_file_browser_store_row_draggable (GtkTreeDragSource *drag_source,
+ GtkTreePath *path)
+{
+ GtkTreeIter iter;
+ GeditFileBrowserStoreFlag flags;
+
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), &iter, path))
+ return FALSE;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (drag_source), &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ return !FILE_IS_DUMMY (flags);
+}
+
+static gboolean
+gedit_file_browser_store_drag_data_delete (GtkTreeDragSource *drag_source,
+ GtkTreePath *path)
+{
+ return FALSE;
+}
+
+static gboolean
+gedit_file_browser_store_drag_data_get (GtkTreeDragSource *drag_source,
+ GtkTreePath *path,
+ GtkSelectionData *selection_data)
+{
+ GtkTreeIter iter;
+ GFile *location;
+ gchar *uris[2] = {0, };
+ gboolean ret;
+
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), &iter, path))
+ return FALSE;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (drag_source), &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ g_assert (location);
+
+ uris[0] = g_file_get_uri (location);
+ ret = gtk_selection_data_set_uris (selection_data, uris);
+
+ g_free (uris[0]);
+ g_object_unref (location);
+
+ return ret;
+}
+
+#define FILTER_HIDDEN(mode) (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN)
+#define FILTER_BINARY(mode) (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY)
+
+/* Private */
+static void
+model_begin_loading (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ GtkTreeIter iter;
+
+ iter.user_data = node;
+ g_signal_emit (model, model_signals[BEGIN_LOADING], 0, &iter);
+}
+
+static void
+model_end_loading (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ GtkTreeIter iter;
+
+ iter.user_data = node;
+ g_signal_emit (model, model_signals[END_LOADING], 0, &iter);
+}
+
+static void
+model_node_update_visibility (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ GtkTreeIter iter;
+
+ node->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED;
+
+ if (FILTER_HIDDEN (model->priv->filter_mode) &&
+ NODE_IS_HIDDEN (node))
+ {
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED;
+ return;
+ }
+
+ if (FILTER_BINARY (model->priv->filter_mode) && !NODE_IS_DIR (node))
+ {
+ if (!NODE_IS_TEXT (node))
+ {
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED;
+ return;
+ }
+ else if (model->priv->binary_patterns != NULL)
+ {
+ gssize name_length = strlen (node->name);
+ gchar *name_reversed = g_utf8_strreverse (node->name, name_length);
+
+ for (guint i = 0; i < model->priv->binary_pattern_specs->len; ++i)
+ {
+ GPatternSpec *spec = g_ptr_array_index (model->priv->binary_pattern_specs, i);
+
+ if (g_pattern_spec_match (spec, name_length, node->name, name_reversed))
+ {
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED;
+ g_free (name_reversed);
+ return;
+ }
+ }
+
+ g_free (name_reversed);
+ }
+ }
+
+ if (model->priv->filter_func)
+ {
+ iter.user_data = node;
+
+ if (!model->priv->filter_func (model, &iter, model->priv->filter_user_data))
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED;
+ }
+}
+
+static gint
+collate_nodes (FileBrowserNode *node1,
+ FileBrowserNode *node2)
+{
+ if (node1->name == NULL)
+ {
+ return -1;
+ }
+ else if (node2->name == NULL)
+ {
+ return 1;
+ }
+ else
+ {
+ gchar *k1 = g_utf8_collate_key_for_filename (node1->name, -1);
+ gchar *k2 = g_utf8_collate_key_for_filename (node2->name, -1);
+ gint result = strcmp (k1, k2);
+
+ g_free (k1);
+ g_free (k2);
+
+ return result;
+ }
+}
+
+static gint
+model_sort_default (FileBrowserNode *node1,
+ FileBrowserNode *node2)
+{
+ gint f1 = NODE_IS_DUMMY (node1);
+ gint f2 = NODE_IS_DUMMY (node2);
+
+ if (f1 && f2)
+ return 0;
+ else if (f1 || f2)
+ return f1 ? -1 : 1;
+
+ f1 = NODE_IS_DIR (node1);
+ f2 = NODE_IS_DIR (node2);
+
+ if (f1 != f2)
+ return f1 ? -1 : 1;
+
+ return collate_nodes (node1, node2);
+}
+
+static void
+model_resort_node (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (node->parent);
+
+ if (!model_node_visibility (model, node->parent))
+ {
+ /* Just sort the children of the parent */
+ dir->children = g_slist_sort (dir->children, (GCompareFunc)(model->priv->sort_func));
+ }
+ else
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gint *neworder;
+ gint pos = 0;
+
+ /* Store current positions */
+ for (GSList *item = dir->children; item; item = item->next)
+ {
+ FileBrowserNode *child = (FileBrowserNode *)(item->data);
+
+ if (model_node_visibility (model, child))
+ child->pos = pos++;
+ }
+
+ dir->children = g_slist_sort (dir->children, (GCompareFunc)(model->priv->sort_func));
+ neworder = g_new (gint, pos);
+ pos = 0;
+
+ /* Store the new positions */
+ for (GSList *item = dir->children; item; item = item->next)
+ {
+ FileBrowserNode *child = (FileBrowserNode *)(item->data);
+
+ if (model_node_visibility (model, child))
+ neworder[pos++] = child->pos;
+ }
+
+ iter.user_data = node->parent;
+ path = gedit_file_browser_store_get_path_real (model, node->parent);
+
+ gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model), path, &iter, neworder);
+
+ g_free (neworder);
+ gtk_tree_path_free (path);
+ }
+}
+
+static void
+row_changed (GeditFileBrowserStore *model,
+ GtkTreePath **path,
+ GtkTreeIter *iter)
+{
+ GtkTreeRowReference *ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), *path);
+
+ /* Insert a copy of the actual path here because the row-inserted
+ signal may alter the path */
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), *path, iter);
+ gtk_tree_path_free (*path);
+
+ *path = gtk_tree_row_reference_get_path (ref);
+ gtk_tree_row_reference_free (ref);
+}
+
+static void
+row_inserted (GeditFileBrowserStore *model,
+ GtkTreePath **path,
+ GtkTreeIter *iter)
+{
+ /* This function creates a row reference for the path because it's
+ uncertain what might change the actual model/view when we insert
+ a node, maybe another directory load is triggered for example.
+ Because functions that use this function rely on the notion that
+ the path remains pointed towards the inserted node, we use the
+ reference to keep track. */
+ GtkTreeRowReference *ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), *path);
+ GtkTreePath *copy = gtk_tree_path_copy (*path);
+
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), copy, iter);
+ gtk_tree_path_free (copy);
+
+ if (ref)
+ {
+ gtk_tree_path_free (*path);
+
+ /* To restore the path, we get the path from the reference. But, since
+ we inserted a row, the path will be one index further than the
+ actual path of our node. We therefore call gtk_tree_path_prev */
+ *path = gtk_tree_row_reference_get_path (ref);
+ gtk_tree_path_prev (*path);
+ }
+
+ gtk_tree_row_reference_free (ref);
+}
+
+static void
+row_deleted (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ const GtkTreePath *path)
+{
+ gboolean hidden;
+ GtkTreePath *copy;
+
+ /* We should always be called when the row is still inserted */
+ g_return_if_fail (node->inserted == TRUE || NODE_IS_DUMMY (node));
+
+ hidden = FILE_IS_HIDDEN (node->flags);
+ node->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+
+ /* Create temporary copies of the path as the signals may alter it */
+
+ copy = gtk_tree_path_copy (path);
+ g_signal_emit (model, model_signals[BEFORE_ROW_DELETED], 0, copy);
+ gtk_tree_path_free (copy);
+
+ node->inserted = FALSE;
+
+ if (hidden)
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+
+ copy = gtk_tree_path_copy (path);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), copy);
+ gtk_tree_path_free (copy);
+}
+
+static void
+model_refilter_node (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ GtkTreePath **path)
+{
+ gboolean old_visible;
+ gboolean new_visible;
+ FileBrowserNodeDir *dir;
+ GSList *item;
+ GtkTreeIter iter;
+ GtkTreePath *tmppath = NULL;
+ gboolean in_tree;
+
+ if (node == NULL)
+ return;
+
+ old_visible = model_node_visibility (model, node);
+ model_node_update_visibility (model, node);
+
+ in_tree = node_in_tree (model, node);
+
+ if (path == NULL)
+ {
+ if (in_tree)
+ tmppath = gedit_file_browser_store_get_path_real (model, node);
+ else
+ tmppath = gtk_tree_path_new_first ();
+
+ path = &tmppath;
+ }
+
+ if (NODE_IS_DIR (node))
+ {
+ if (in_tree)
+ gtk_tree_path_down (*path);
+
+ dir = FILE_BROWSER_NODE_DIR (node);
+
+ for (item = dir->children; item; item = item->next)
+ model_refilter_node (model, (FileBrowserNode *)(item->data), path);
+
+ if (in_tree)
+ gtk_tree_path_up (*path);
+ }
+
+ if (in_tree)
+ {
+ new_visible = model_node_visibility (model, node);
+
+ if (old_visible != new_visible)
+ {
+ if (old_visible)
+ {
+ row_deleted (model, node, *path);
+ }
+ else
+ {
+ iter.user_data = node;
+ row_inserted (model, path, &iter);
+ gtk_tree_path_next (*path);
+ }
+ }
+ else if (old_visible)
+ {
+ gtk_tree_path_next (*path);
+ }
+ }
+
+ model_check_dummy (model, node);
+
+ if (tmppath)
+ gtk_tree_path_free (tmppath);
+}
+
+static void
+model_refilter (GeditFileBrowserStore *model)
+{
+ model_refilter_node (model, model->priv->root, NULL);
+}
+
+static void
+file_browser_node_set_name (FileBrowserNode *node)
+{
+ g_free (node->name);
+ g_free (node->markup);
+
+ if (node->file)
+ node->name = gedit_file_browser_utils_file_basename (node->file);
+ else
+ node->name = NULL;
+
+ if (node->name)
+ node->markup = g_markup_escape_text (node->name, -1);
+ else
+ node->markup = NULL;
+}
+
+static void
+file_browser_node_init (FileBrowserNode *node,
+ GFile *file,
+ FileBrowserNode *parent)
+{
+ if (file != NULL)
+ {
+ node->file = g_object_ref (file);
+ file_browser_node_set_name (node);
+ }
+
+ node->parent = parent;
+}
+
+static FileBrowserNode *
+file_browser_node_new (GFile *file,
+ FileBrowserNode *parent)
+{
+ FileBrowserNode *node = g_slice_new0 (FileBrowserNode);
+
+ file_browser_node_init (node, file, parent);
+ return node;
+}
+
+static FileBrowserNode *
+file_browser_node_dir_new (GeditFileBrowserStore *model,
+ GFile *file,
+ FileBrowserNode *parent)
+{
+ FileBrowserNode *node = (FileBrowserNode *)g_slice_new0 (FileBrowserNodeDir);
+
+ file_browser_node_init (node, file, parent);
+
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY;
+
+ FILE_BROWSER_NODE_DIR (node)->model = model;
+
+ return node;
+}
+
+static void
+file_browser_node_free_children (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ if (node == NULL || !NODE_IS_DIR (node))
+ return;
+
+ for (GSList *item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ file_browser_node_free (model, (FileBrowserNode *)(item->data));
+
+ g_slist_free (FILE_BROWSER_NODE_DIR (node)->children);
+ FILE_BROWSER_NODE_DIR (node)->children = NULL;
+
+ /* This node is no longer loaded */
+ node->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_LOADED;
+}
+
+static void
+file_browser_node_free (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ if (node == NULL)
+ return;
+
+ if (NODE_IS_DIR (node))
+ {
+ FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (node);
+
+ if (dir->cancellable)
+ {
+ g_cancellable_cancel (dir->cancellable);
+ g_object_unref (dir->cancellable);
+
+ model_end_loading (model, node);
+ }
+
+ file_browser_node_free_children (model, node);
+
+ if (dir->monitor)
+ {
+ g_file_monitor_cancel (dir->monitor);
+ g_object_unref (dir->monitor);
+ }
+ }
+
+ if (node->file)
+ {
+ g_signal_emit (model, model_signals[UNLOAD], 0, node->file);
+ g_object_unref (node->file);
+ }
+
+ if (node->icon)
+ g_object_unref (node->icon);
+
+ if (node->emblem)
+ g_object_unref (node->emblem);
+
+ g_free (node->icon_name);
+ g_free (node->name);
+ g_free (node->markup);
+
+ if (NODE_IS_DIR (node))
+ g_slice_free (FileBrowserNodeDir, (FileBrowserNodeDir *)node);
+ else
+ g_slice_free (FileBrowserNode, (FileBrowserNode *)node);
+}
+
+/**
+ * model_remove_node_children:
+ * @model: the #GeditFileBrowserStore
+ * @node: the FileBrowserNode to remove
+ * @path: the path of the node, or NULL to let the path be calculated
+ * @free_nodes: whether to also remove the nodes from memory
+ *
+ * Removes all the children of node from the model. This function is used
+ * to remove the child nodes from the _model_. Don't use it to just free
+ * a node.
+ */
+static void
+model_remove_node_children (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ GtkTreePath *path,
+ gboolean free_nodes)
+{
+ FileBrowserNodeDir *dir;
+ GtkTreePath *path_child;
+ GSList *list;
+
+ if (node == NULL || !NODE_IS_DIR (node))
+ return;
+
+ dir = FILE_BROWSER_NODE_DIR (node);
+
+ if (dir->children == NULL)
+ return;
+
+ if (!model_node_visibility (model, node))
+ {
+ /* Node is invisible and therefore the children can just be freed */
+ if (free_nodes)
+ file_browser_node_free_children (model, node);
+
+ return;
+ }
+
+ if (path == NULL)
+ path_child = gedit_file_browser_store_get_path_real (model, node);
+ else
+ path_child = gtk_tree_path_copy (path);
+
+ gtk_tree_path_down (path_child);
+
+ list = g_slist_copy (dir->children);
+
+ for (GSList *item = list; item; item = item->next)
+ model_remove_node (model, (FileBrowserNode *)(item->data), path_child, free_nodes);
+
+ g_slist_free (list);
+ gtk_tree_path_free (path_child);
+}
+
+/**
+ * model_remove_node:
+ * @model: the #GeditFileBrowserStore
+ * @node: the FileBrowserNode to remove
+ * @path: the path to use to remove this node, or NULL to use the path
+ * calculated from the node itself
+ * @free_nodes: whether to also remove the nodes from memory
+ *
+ * Removes this node and all its children from the model. This function is used
+ * to remove the node from the _model_. Don't use it to just free
+ * a node.
+ */
+static void
+model_remove_node (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ GtkTreePath *path,
+ gboolean free_nodes)
+{
+ gboolean free_path = FALSE;
+ FileBrowserNode *parent;
+
+ if (path == NULL)
+ {
+ path = gedit_file_browser_store_get_path_real (model, node);
+ free_path = TRUE;
+ }
+
+ model_remove_node_children (model, node, path, free_nodes);
+
+ /* Only delete if the node is visible in the tree (but only when it's not the virtual root) */
+ if (model_node_visibility (model, node) && node != model->priv->virtual_root)
+ row_deleted (model, node, path);
+
+ if (free_path)
+ gtk_tree_path_free (path);
+
+ parent = node->parent;
+
+ /* Remove the node from the parents children list */
+ if (free_nodes && parent)
+ FILE_BROWSER_NODE_DIR (node->parent)->children =
+ g_slist_remove (FILE_BROWSER_NODE_DIR (node->parent)->children, node);
+
+ /* If this is the virtual root, than set the parent as the virtual root */
+ if (node == model->priv->virtual_root)
+ set_virtual_root_from_node (model, parent);
+ else if (parent && model_node_visibility (model, parent) && !(free_nodes && NODE_IS_DUMMY(node)))
+ model_check_dummy (model, parent);
+
+ /* Now free the node if necessary */
+ if (free_nodes)
+ file_browser_node_free (model, node);
+}
+
+/**
+ * model_clear:
+ * @model: the #GeditFileBrowserStore
+ * @free_nodes: whether to also remove the nodes from memory
+ *
+ * Removes all nodes from the model. This function is used
+ * to remove all the nodes from the _model_. Don't use it to just free the
+ * nodes in the model.
+ */
+static void
+model_clear (GeditFileBrowserStore *model,
+ gboolean free_nodes)
+{
+ GtkTreePath *path = gtk_tree_path_new ();
+
+ model_remove_node_children (model, model->priv->virtual_root, path, free_nodes);
+ gtk_tree_path_free (path);
+
+ /* Remove the dummy if there is one */
+ if (model->priv->virtual_root)
+ {
+ FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (model->priv->virtual_root);
+
+ if (dir->children != NULL)
+ {
+ FileBrowserNode *dummy = (FileBrowserNode *)(dir->children->data);
+
+ if (NODE_IS_DUMMY (dummy) && model_node_visibility (model, dummy))
+ {
+ path = gtk_tree_path_new_first ();
+ row_deleted (model, dummy, path);
+ gtk_tree_path_free (path);
+ }
+ }
+ }
+}
+
+static void
+file_browser_node_unload (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ gboolean remove_children)
+{
+ FileBrowserNodeDir *dir;
+
+ if (node == NULL)
+ return;
+
+ if (!NODE_IS_DIR (node) || !NODE_LOADED (node))
+ return;
+
+ dir = FILE_BROWSER_NODE_DIR (node);
+
+ if (remove_children)
+ model_remove_node_children (model, node, NULL, TRUE);
+
+ if (dir->cancellable)
+ {
+ g_cancellable_cancel (dir->cancellable);
+ g_object_unref (dir->cancellable);
+
+ model_end_loading (model, node);
+ dir->cancellable = NULL;
+ }
+
+ if (dir->monitor)
+ {
+ g_file_monitor_cancel (dir->monitor);
+ g_object_unref (dir->monitor);
+
+ dir->monitor = NULL;
+ }
+
+ node->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_LOADED;
+}
+
+static void
+model_recomposite_icon_real (GeditFileBrowserStore *tree_model,
+ FileBrowserNode *node,
+ GFileInfo *info)
+{
+ GdkPixbuf *icon;
+
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model));
+ g_return_if_fail (node != NULL);
+
+ if (node->file == NULL)
+ return;
+
+ if (info)
+ {
+ GIcon *gicon = g_file_info_get_icon (info);
+
+ if (gicon != NULL)
+ icon = gedit_file_browser_utils_pixbuf_from_icon (gicon, GTK_ICON_SIZE_MENU);
+ else
+ icon = NULL;
+ }
+ else
+ {
+ icon = gedit_file_browser_utils_pixbuf_from_file (node->file, GTK_ICON_SIZE_MENU, FALSE);
+ }
+
+ /* Fallback to the same icon as the file browser */
+ if (!icon)
+ icon = gedit_file_browser_utils_pixbuf_from_theme ("text-x-generic", GTK_ICON_SIZE_MENU);
+
+ if (node->icon)
+ g_object_unref (node->icon);
+
+ if (node->emblem)
+ {
+ gint icon_size;
+
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &icon_size);
+
+ if (icon == NULL)
+ {
+ node->icon = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (node->emblem),
+ gdk_pixbuf_get_has_alpha (node->emblem),
+ gdk_pixbuf_get_bits_per_sample (node->emblem),
+ icon_size,
+ icon_size);
+ }
+ else
+ {
+ node->icon = gdk_pixbuf_copy (icon);
+ g_object_unref (icon);
+ }
+
+ gdk_pixbuf_composite (node->emblem, node->icon,
+ icon_size - 10, icon_size - 10, 10,
+ 10, icon_size - 10, icon_size - 10,
+ 1, 1, GDK_INTERP_NEAREST, 255);
+ }
+ else
+ {
+ node->icon = icon;
+ }
+}
+
+static void
+model_recomposite_icon (GeditFileBrowserStore *tree_model,
+ GtkTreeIter *iter)
+{
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->user_data != NULL);
+
+ model_recomposite_icon_real (tree_model,
+ (FileBrowserNode *)(iter->user_data),
+ NULL);
+}
+
+static FileBrowserNode *
+model_create_dummy_node (GeditFileBrowserStore *model,
+ FileBrowserNode *parent)
+{
+ FileBrowserNode *dummy;
+
+ dummy = file_browser_node_new (NULL, parent);
+ dummy->name = g_strdup (_("(Empty)"));
+ dummy->markup = g_markup_escape_text (dummy->name, -1);
+
+ dummy->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_DUMMY;
+ dummy->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+
+ return dummy;
+}
+
+static FileBrowserNode *
+model_add_dummy_node (GeditFileBrowserStore *model,
+ FileBrowserNode *parent)
+{
+ FileBrowserNode *dummy;
+
+ dummy = model_create_dummy_node (model, parent);
+
+ if (model_node_visibility (model, parent))
+ dummy->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+
+ model_add_node (model, dummy, parent);
+
+ return dummy;
+}
+
+static void
+model_check_dummy (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ /* Hide the dummy child if needed */
+ if (NODE_IS_DIR (node))
+ {
+ FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (node);
+ FileBrowserNode *dummy;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ guint flags;
+
+ if (dir->children == NULL)
+ {
+ model_add_dummy_node (model, node);
+ return;
+ }
+
+ dummy = (FileBrowserNode *)(dir->children->data);
+
+ if (!NODE_IS_DUMMY (dummy))
+ {
+ dummy = model_create_dummy_node (model, node);
+ dir->children = g_slist_prepend (dir->children, dummy);
+ }
+
+ if (!model_node_visibility (model, node))
+ {
+ dummy->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+ return;
+ }
+
+ /* Temporarily set the node to invisible to check
+ for real children */
+ flags = dummy->flags;
+ dummy->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+
+ if (!filter_tree_model_iter_has_child_real (model, node))
+ {
+ dummy->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+
+ if (FILE_IS_HIDDEN (flags))
+ {
+ /* Was hidden, needs to be inserted */
+ iter.user_data = dummy;
+ path = gedit_file_browser_store_get_path_real (model, dummy);
+
+ row_inserted (model, &path, &iter);
+ gtk_tree_path_free (path);
+ }
+ }
+ else if (!FILE_IS_HIDDEN (flags))
+ {
+ /* Was shown, needs to be removed */
+
+ /* To get the path we need to set it to visible temporarily */
+ dummy->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+ path = gedit_file_browser_store_get_path_real (model, dummy);
+ dummy->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+
+ row_deleted (model, dummy, path);
+ gtk_tree_path_free (path);
+ }
+ }
+}
+
+static void
+insert_node_sorted (GeditFileBrowserStore *model,
+ FileBrowserNode *child,
+ FileBrowserNode *parent)
+{
+ FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (parent);
+
+ if (model->priv->sort_func == NULL)
+ dir->children = g_slist_append (dir->children, child);
+ else
+ dir->children = g_slist_insert_sorted (dir->children, child, (GCompareFunc)(model->priv->sort_func));
+}
+
+static void
+model_add_node (GeditFileBrowserStore *model,
+ FileBrowserNode *child,
+ FileBrowserNode *parent)
+{
+ /* Add child to parents children */
+ insert_node_sorted (model, child, parent);
+
+ if (model_node_visibility (model, parent) &&
+ model_node_visibility (model, child))
+ {
+ GtkTreePath *path = gedit_file_browser_store_get_path_real (model, child);
+ GtkTreeIter iter;
+
+ iter.user_data = child;
+
+ /* Emit row inserted */
+ row_inserted (model, &path, &iter);
+ gtk_tree_path_free (path);
+ }
+
+ model_check_dummy (model, parent);
+ model_check_dummy (model, child);
+}
+
+static void
+model_add_nodes_batch (GeditFileBrowserStore *model,
+ GSList *children,
+ FileBrowserNode *parent)
+{
+ FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (parent);
+ GSList *sorted_children = g_slist_sort (children, (GCompareFunc)model->priv->sort_func);
+ GSList *child = sorted_children;
+ GSList *prev = NULL;
+ GSList *l = dir->children;
+
+ model_check_dummy (model, parent);
+
+ while (child)
+ {
+ FileBrowserNode *node = child->data;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ /* Reached the end of the first list, just append the second */
+ if (l == NULL)
+ {
+ dir->children = g_slist_concat (dir->children, child);
+
+ for (l = child; l; l = l->next)
+ {
+ if (model_node_visibility (model, parent) &&
+ model_node_visibility (model, l->data))
+ {
+ iter.user_data = l->data;
+ path = gedit_file_browser_store_get_path_real (model, l->data);
+
+ /* Emit row inserted */
+ row_inserted (model, &path, &iter);
+ gtk_tree_path_free (path);
+ }
+
+ model_check_dummy (model, l->data);
+ }
+
+ break;
+ }
+
+ if (model->priv->sort_func (l->data, node) > 0)
+ {
+ GSList *next_child;
+
+ if (prev == NULL)
+ {
+ /* Prepend to the list */
+ dir->children = g_slist_prepend (dir->children, child);
+ }
+ else
+ {
+ prev->next = child;
+ }
+
+ next_child = child->next;
+ prev = child;
+ child->next = l;
+ child = next_child;
+
+ if (model_node_visibility (model, parent) &&
+ model_node_visibility (model, node))
+ {
+ iter.user_data = node;
+ path = gedit_file_browser_store_get_path_real (model, node);
+
+ /* Emit row inserted */
+ row_inserted (model, &path, &iter);
+ gtk_tree_path_free (path);
+ }
+
+ model_check_dummy (model, node);
+
+ /* Try again at the same l position with the next child */
+ }
+ else
+ {
+ /* Move to the next item in the list */
+ prev = l;
+ l = l->next;
+ }
+ }
+}
+
+static gchar const *
+backup_content_type (GFileInfo *info)
+{
+ gchar const *content;
+
+ if (!g_file_info_get_is_backup (info))
+ return NULL;
+
+ content = g_file_info_get_content_type (info);
+
+ if (!content || g_content_type_equals (content, "application/x-trash"))
+ return "text/plain";
+
+ return content;
+}
+
+static gboolean
+content_type_is_text (gchar const *content_type)
+{
+#ifdef G_OS_WIN32
+ gchar *mime;
+ gboolean ret;
+#endif
+
+ if (!content_type || g_content_type_is_unknown (content_type))
+ return TRUE;
+
+#ifndef G_OS_WIN32
+ return (g_content_type_is_a (content_type, "text/plain") ||
+ g_content_type_equals (content_type, "application/x-zerosize"));
+#else
+ if (g_content_type_is_a (content_type, "text"))
+ return TRUE;
+
+ /* This covers a rare case in which on Windows the PerceivedType is
+ not set to "text" but the Content Type is set to text/plain */
+ mime = g_content_type_get_mime_type (content_type);
+ ret = g_strcmp0 (mime, "text/plain") == 0;
+ g_free (mime);
+
+ return ret;
+#endif
+}
+
+static void
+file_browser_node_set_from_info (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ GFileInfo *info,
+ gboolean isadded)
+{
+ gchar const *content;
+ gboolean free_info = FALSE;
+ GtkTreePath *path;
+ gchar *uri;
+ GError *error = NULL;
+
+ if (info == NULL)
+ {
+ info = g_file_query_info (node->file,
+ STANDARD_ATTRIBUTE_TYPES,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ &error);
+
+ if (!info)
+ {
+ if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND))
+ {
+ uri = g_file_get_uri (node->file);
+ g_warning ("Could not get info for %s: %s", uri, error->message);
+ g_free (uri);
+ }
+
+ g_error_free (error);
+ return;
+ }
+
+ free_info = TRUE;
+ }
+
+ if (g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info))
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
+ {
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY;
+ }
+ else
+ {
+ if (!(content = backup_content_type (info)))
+ content = g_file_info_get_content_type (info);
+
+ if (content_type_is_text (content))
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_TEXT;
+ }
+
+ model_recomposite_icon_real (model, node, info);
+
+ if (free_info)
+ g_object_unref (info);
+
+ if (isadded)
+ {
+ path = gedit_file_browser_store_get_path_real (model, node);
+ model_refilter_node (model, node, &path);
+ gtk_tree_path_free (path);
+
+ model_check_dummy (model, node->parent);
+ }
+ else
+ {
+ model_node_update_visibility (model, node);
+ }
+}
+
+static FileBrowserNode *
+node_list_contains_file (GSList *children,
+ GFile *file)
+{
+ for (GSList *item = children; item; item = item->next)
+ {
+ FileBrowserNode *node = (FileBrowserNode *)(item->data);
+
+ if (node->file != NULL && g_file_equal (node->file, file))
+ return node;
+ }
+
+ return NULL;
+}
+
+static FileBrowserNode *
+model_add_node_from_file (GeditFileBrowserStore *model,
+ FileBrowserNode *parent,
+ GFile *file,
+ GFileInfo *info)
+{
+ FileBrowserNode *node;
+ gboolean free_info = FALSE;
+ GError *error = NULL;
+
+ if ((node = node_list_contains_file (FILE_BROWSER_NODE_DIR (parent)->children, file)) == NULL)
+ {
+ if (info == NULL)
+ {
+ info = g_file_query_info (file,
+ STANDARD_ATTRIBUTE_TYPES,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ &error);
+ free_info = TRUE;
+ }
+
+ if (!info)
+ {
+ g_warning ("Error querying file info: %s", error->message);
+ g_error_free (error);
+
+ /* FIXME: What to do now then... */
+ node = file_browser_node_new (file, parent);
+ }
+ else if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
+ {
+ node = file_browser_node_dir_new (model, file, parent);
+ }
+ else
+ {
+ node = file_browser_node_new (file, parent);
+ }
+
+ file_browser_node_set_from_info (model, node, info, FALSE);
+ model_add_node (model, node, parent);
+
+ if (info && free_info)
+ g_object_unref (info);
+ }
+
+ return node;
+}
+
+/* We pass in a copy of the list of parent->children so that we do
+ * not have to check if a file already exists among the ones we just
+ * added */
+static void
+model_add_nodes_from_files (GeditFileBrowserStore *model,
+ FileBrowserNode *parent,
+ GSList *original_children,
+ GList *files)
+{
+ GSList *nodes = NULL;
+
+ for (GList *item = files; item; item = item->next)
+ {
+ GFileInfo *info = G_FILE_INFO (item->data);
+ GFileType type = g_file_info_get_file_type (info);
+ gchar const *name;
+ GFile *file;
+ FileBrowserNode *node;
+
+ /* Skip all non regular, non directory files */
+ if (type != G_FILE_TYPE_REGULAR &&
+ type != G_FILE_TYPE_DIRECTORY &&
+ type != G_FILE_TYPE_SYMBOLIC_LINK)
+ {
+ g_object_unref (info);
+ continue;
+ }
+
+ name = g_file_info_get_name (info);
+
+ /* Skip '.' and '..' directories */
+ if (type == G_FILE_TYPE_DIRECTORY &&
+ (strcmp (name, ".") == 0 ||
+ strcmp (name, "..") == 0))
+ {
+ g_object_unref (info);
+ continue;
+ }
+
+ file = g_file_get_child (parent->file, name);
+ if (!(node = node_list_contains_file (original_children, file)))
+ {
+ if (type == G_FILE_TYPE_DIRECTORY)
+ node = file_browser_node_dir_new (model, file, parent);
+ else
+ node = file_browser_node_new (file, parent);
+
+ file_browser_node_set_from_info (model, node, info, FALSE);
+
+ nodes = g_slist_prepend (nodes, node);
+ }
+
+ g_object_unref (file);
+ g_object_unref (info);
+ }
+
+ if (nodes)
+ model_add_nodes_batch (model, nodes, parent);
+}
+
+static FileBrowserNode *
+model_add_node_from_dir (GeditFileBrowserStore *model,
+ FileBrowserNode *parent,
+ GFile *file)
+{
+ FileBrowserNode *node;
+
+ /* Check if it already exists */
+ if ((node = node_list_contains_file (FILE_BROWSER_NODE_DIR (parent)->children, file)) == NULL)
+ {
+ node = file_browser_node_dir_new (model, file, parent);
+ file_browser_node_set_from_info (model, node, NULL, FALSE);
+
+ if (node->name == NULL)
+ file_browser_node_set_name (node);
+
+ node->icon_name = g_strdup ("folder-symbolic");
+
+ model_add_node (model, node, parent);
+ }
+
+ return node;
+}
+
+static void
+on_directory_monitor_event (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ FileBrowserNode *parent)
+{
+ FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (parent);
+ FileBrowserNode *node;
+
+ switch (event_type)
+ {
+ case G_FILE_MONITOR_EVENT_DELETED:
+ node = node_list_contains_file (dir->children, file);
+
+ if (node != NULL)
+ model_remove_node (dir->model, node, NULL, TRUE);
+ break;
+ case G_FILE_MONITOR_EVENT_CREATED:
+ if (g_file_query_exists (file, NULL))
+ model_add_node_from_file (dir->model, parent, file, NULL);
+
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+async_node_free (AsyncNode *async)
+{
+ g_object_unref (async->cancellable);
+ g_slist_free (async->original_children);
+ g_slice_free (AsyncNode, async);
+}
+
+static void
+model_iterate_next_files_cb (GFileEnumerator *enumerator,
+ GAsyncResult *result,
+ AsyncNode *async)
+{
+ GError *error = NULL;
+ GList *files = g_file_enumerator_next_files_finish (enumerator, result, &error);
+ FileBrowserNodeDir *dir = async->dir;
+ FileBrowserNode *parent = (FileBrowserNode *)dir;
+
+ if (files == NULL)
+ {
+ g_file_enumerator_close (enumerator, NULL, NULL);
+ g_object_unref (enumerator);
+ async_node_free (async);
+
+ if (!error)
+ {
+ /* We're done loading */
+ g_object_unref (dir->cancellable);
+ dir->cancellable = NULL;
+
+/*
+ * FIXME: This is temporarly, it is a bug in gio:
+ * http://bugzilla.gnome.org/show_bug.cgi?id=565924
+ */
+#ifndef G_OS_WIN32
+ if (g_file_is_native (parent->file) && dir->monitor == NULL)
+ {
+ dir->monitor = g_file_monitor_directory (parent->file,
+ G_FILE_MONITOR_NONE,
+ NULL,
+ NULL);
+ if (dir->monitor != NULL)
+ {
+ g_signal_connect (dir->monitor,
+ "changed",
+ G_CALLBACK (on_directory_monitor_event),
+ parent);
+ }
+ }
+#endif
+
+ model_check_dummy (dir->model, parent);
+ model_end_loading (dir->model, parent);
+ }
+ else
+ {
+ /* Simply return if we were cancelled */
+ if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED)
+ return;
+
+ /* Otherwise handle the error appropriately */
+ g_signal_emit (dir->model,
+ model_signals[ERROR],
+ 0,
+ GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY,
+ error->message);
+
+ file_browser_node_unload (dir->model, (FileBrowserNode *)parent, TRUE);
+ g_error_free (error);
+ }
+ }
+ else if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ /* Check cancel state manually */
+ g_file_enumerator_close (enumerator, NULL, NULL);
+ g_object_unref (enumerator);
+ async_node_free (async);
+ }
+ else
+ {
+ model_add_nodes_from_files (dir->model, parent, async->original_children, files);
+
+ g_list_free (files);
+ next_files_async (enumerator, async);
+ }
+}
+
+static void
+next_files_async (GFileEnumerator *enumerator,
+ AsyncNode *async)
+{
+ g_file_enumerator_next_files_async (enumerator,
+ DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
+ G_PRIORITY_DEFAULT,
+ async->cancellable,
+ (GAsyncReadyCallback)model_iterate_next_files_cb,
+ async);
+}
+
+static void
+model_iterate_children_cb (GFile *file,
+ GAsyncResult *result,
+ AsyncNode *async)
+{
+ GError *error = NULL;
+ GFileEnumerator *enumerator;
+
+ if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ async_node_free (async);
+ return;
+ }
+
+ if (!(enumerator = g_file_enumerate_children_finish (file, result, &error)))
+ {
+ /* Simply return if we were cancelled or if the dir is not there */
+ FileBrowserNodeDir *dir = async->dir;
+
+ /* Otherwise handle the error appropriately */
+ g_signal_emit (dir->model,
+ model_signals[ERROR],
+ 0,
+ GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY,
+ error->message);
+
+ file_browser_node_unload (dir->model, (FileBrowserNode *)dir, TRUE);
+ g_error_free (error);
+ async_node_free (async);
+ }
+ else
+ {
+ next_files_async (enumerator, async);
+ }
+}
+
+static void
+model_load_directory (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ FileBrowserNodeDir *dir;
+ AsyncNode *async;
+
+ g_return_if_fail (NODE_IS_DIR (node));
+
+ dir = FILE_BROWSER_NODE_DIR (node);
+
+ /* Cancel a previous load */
+ if (dir->cancellable != NULL)
+ file_browser_node_unload (dir->model, node, TRUE);
+
+ node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_LOADED;
+ model_begin_loading (model, node);
+
+ dir->cancellable = g_cancellable_new ();
+
+ async = g_slice_new (AsyncNode);
+ async->dir = dir;
+ async->cancellable = g_object_ref (dir->cancellable);
+ async->original_children = g_slist_copy (dir->children);
+
+ /* Start loading async */
+ g_file_enumerate_children_async (node->file,
+ STANDARD_ATTRIBUTE_TYPES,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ async->cancellable,
+ (GAsyncReadyCallback)model_iterate_children_cb,
+ async);
+}
+
+static GList *
+get_parent_files (GeditFileBrowserStore *model,
+ GFile *file)
+{
+ GList *result = NULL;
+
+ result = g_list_prepend (result, g_object_ref (file));
+
+ while ((file = g_file_get_parent (file)))
+ {
+ if (g_file_equal (file, model->priv->root->file))
+ {
+ g_object_unref (file);
+ break;
+ }
+
+ result = g_list_prepend (result, file);
+ }
+
+ return result;
+}
+
+static void
+model_fill (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ GtkTreePath **path)
+{
+ gboolean free_path = FALSE;
+ GtkTreeIter iter = {0,};
+ GSList *item;
+ FileBrowserNode *child;
+
+ if (node == NULL)
+ {
+ node = model->priv->virtual_root;
+ *path = gtk_tree_path_new ();
+ free_path = TRUE;
+ }
+
+ if (*path == NULL)
+ {
+ *path = gedit_file_browser_store_get_path_real (model, node);
+ free_path = TRUE;
+ }
+
+ if (!model_node_visibility (model, node))
+ {
+ if (free_path)
+ gtk_tree_path_free (*path);
+
+ return;
+ }
+
+ if (node != model->priv->virtual_root)
+ {
+ /* Insert node */
+ iter.user_data = node;
+ row_inserted(model, path, &iter);
+ }
+
+ if (NODE_IS_DIR (node))
+ {
+ /* Go to the first child */
+ gtk_tree_path_down (*path);
+
+ for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ {
+ child = (FileBrowserNode *) (item->data);
+
+ if (model_node_visibility (model, child))
+ {
+ model_fill (model, child, path);
+
+ /* Increase path for next child */
+ gtk_tree_path_next (*path);
+ }
+ }
+
+ /* Move back up to node path */
+ gtk_tree_path_up (*path);
+ }
+
+ model_check_dummy (model, node);
+
+ if (free_path)
+ gtk_tree_path_free (*path);
+}
+
+static void
+set_virtual_root_from_node (GeditFileBrowserStore *model,
+ FileBrowserNode *node)
+{
+ FileBrowserNode *prev = node;
+ FileBrowserNode *next = prev->parent;
+ FileBrowserNode *check;
+ FileBrowserNodeDir *dir;
+ GSList *copy;
+ GtkTreePath *empty = NULL;
+
+ /* Free all the nodes below that we don't need in cache */
+ while (prev != model->priv->root)
+ {
+ dir = FILE_BROWSER_NODE_DIR (next);
+ copy = g_slist_copy (dir->children);
+
+ for (GSList *item = copy; item; item = item->next)
+ {
+ check = (FileBrowserNode *)(item->data);
+
+ if (prev == node)
+ {
+ /* Only free the children, keeping this depth in cache */
+ if (check != node)
+ {
+ file_browser_node_free_children (model, check);
+ file_browser_node_unload (model, check, FALSE);
+ }
+ }
+ else if (check != prev)
+ {
+ /* Only free when the node is not in the chain */
+ dir->children = g_slist_remove (dir->children, check);
+ file_browser_node_free (model, check);
+ }
+ }
+
+ if (prev != node)
+ file_browser_node_unload (model, next, FALSE);
+
+ g_slist_free (copy);
+ prev = next;
+ next = prev->parent;
+ }
+
+ /* Free all the nodes up that we don't need in cache */
+ for (GSList *item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ {
+ check = (FileBrowserNode *)(item->data);
+
+ if (NODE_IS_DIR (check))
+ {
+ for (copy = FILE_BROWSER_NODE_DIR (check)->children; copy; copy = copy->next)
+ {
+ file_browser_node_free_children (model, (FileBrowserNode*) (copy->data));
+ file_browser_node_unload (model, (FileBrowserNode*) (copy->data), FALSE);
+ }
+ }
+ else if (NODE_IS_DUMMY (check))
+ {
+ check->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN;
+ }
+ }
+
+ /* Now finally, set the virtual root, and load it up! */
+ model->priv->virtual_root = node;
+
+ /* Notify that the virtual-root has changed before loading up new nodes so that the
+ "root_changed" signal can be emitted before any "inserted" signals */
+ g_object_notify (G_OBJECT (model), "virtual-root");
+
+ model_fill (model, NULL, &empty);
+
+ if (!NODE_LOADED (node))
+ model_load_directory (model, node);
+}
+
+static void
+set_virtual_root_from_file (GeditFileBrowserStore *model,
+ GFile *file)
+{
+ GList *files;
+ FileBrowserNode *parent;
+ GFile *check;
+
+ /* Always clear the model before altering the nodes */
+ model_clear (model, FALSE);
+
+ /* Create the node path, get all the uri's */
+ files = get_parent_files (model, file);
+ parent = model->priv->root;
+
+ for (GList *item = files; item; item = item->next)
+ {
+ check = G_FILE (item->data);
+
+ parent = model_add_node_from_dir (model, parent, check);
+ g_object_unref (check);
+ }
+
+ g_list_free (files);
+ set_virtual_root_from_node (model, parent);
+}
+
+static FileBrowserNode *
+model_find_node_children (GeditFileBrowserStore *model,
+ FileBrowserNode *parent,
+ GFile *file)
+{
+ FileBrowserNodeDir *dir;
+ FileBrowserNode *child;
+ FileBrowserNode *result;
+
+ if (!NODE_IS_DIR (parent))
+ return NULL;
+
+ dir = FILE_BROWSER_NODE_DIR (parent);
+
+ for (GSList *children = dir->children; children; children = children->next)
+ {
+ child = (FileBrowserNode *)(children->data);
+
+ result = model_find_node (model, child, file);
+
+ if (result)
+ return result;
+ }
+
+ return NULL;
+}
+
+static FileBrowserNode *
+model_find_node (GeditFileBrowserStore *model,
+ FileBrowserNode *node,
+ GFile *file)
+{
+ if (node == NULL)
+ node = model->priv->root;
+
+ if (node->file && g_file_equal (node->file, file))
+ return node;
+
+ if (NODE_IS_DIR (node) && g_file_has_prefix (file, node->file))
+ return model_find_node_children (model, node, file);
+
+ return NULL;
+}
+
+static GQuark
+gedit_file_browser_store_error_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (quark == 0))
+ quark = g_quark_from_string ("gedit_file_browser_store_error");
+
+ return quark;
+}
+
+static GFile *
+unique_new_name (GFile *directory,
+ gchar const *name)
+{
+ GFile *newuri = NULL;
+ guint num = 0;
+ gchar *newname;
+
+ while (newuri == NULL || g_file_query_exists (newuri, NULL))
+ {
+ if (newuri != NULL)
+ g_object_unref (newuri);
+
+ if (num == 0)
+ newname = g_strdup (name);
+ else
+ newname = g_strdup_printf ("%s(%d)", name, num);
+
+ newuri = g_file_get_child (directory, newname);
+ g_free (newname);
+
+ ++num;
+ }
+
+ return newuri;
+}
+
+static GeditFileBrowserStoreResult
+model_root_mounted (GeditFileBrowserStore *model,
+ GFile *virtual_root)
+{
+ model_check_dummy (model, model->priv->root);
+ g_object_notify (G_OBJECT (model), "root");
+
+ if (virtual_root != NULL)
+ {
+ return gedit_file_browser_store_set_virtual_root_from_location
+ (model, virtual_root);
+ }
+ else
+ {
+ set_virtual_root_from_node (model, model->priv->root);
+ }
+
+ return GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+}
+
+static void
+handle_root_error (GeditFileBrowserStore *model,
+ GError *error)
+{
+ FileBrowserNode *root;
+
+ g_signal_emit (model,
+ model_signals[ERROR],
+ 0,
+ GEDIT_FILE_BROWSER_ERROR_SET_ROOT,
+ error->message);
+
+ /* Set the virtual root to the root */
+ root = model->priv->root;
+ model->priv->virtual_root = root;
+
+ /* Set the root to be loaded */
+ root->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_LOADED;
+
+ /* Check the dummy */
+ model_check_dummy (model, root);
+
+ g_object_notify (G_OBJECT (model), "root");
+ g_object_notify (G_OBJECT (model), "virtual-root");
+}
+
+static void
+mount_cb (GFile *file,
+ GAsyncResult *res,
+ MountInfo *mount_info)
+{
+ gboolean mounted;
+ GError *error = NULL;
+ GeditFileBrowserStore *model = mount_info->model;
+
+ mounted = g_file_mount_enclosing_volume_finish (file, res, &error);
+
+ if (mount_info->model)
+ {
+ model->priv->mount_info = NULL;
+ model_end_loading (model, model->priv->root);
+ }
+
+ if (!mount_info->model || g_cancellable_is_cancelled (mount_info->cancellable))
+ {
+ /* Reset because it might be reused? */
+ g_cancellable_reset (mount_info->cancellable);
+ }
+ else if (mounted)
+ {
+ model_root_mounted (model, mount_info->virtual_root);
+ }
+ else if (error->code != G_IO_ERROR_CANCELLED)
+ {
+ handle_root_error (model, error);
+ }
+
+ if (error)
+ g_error_free (error);
+
+ g_object_unref (mount_info->operation);
+ g_object_unref (mount_info->cancellable);
+
+ if (mount_info->virtual_root)
+ g_object_unref (mount_info->virtual_root);
+
+ g_slice_free (MountInfo, mount_info);
+}
+
+static GeditFileBrowserStoreResult
+model_mount_root (GeditFileBrowserStore *model,
+ GFile *virtual_root)
+{
+ GFileInfo *info;
+ GError *error = NULL;
+ MountInfo *mount_info;
+
+ info = g_file_query_info (model->priv->root->file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ &error);
+
+ if (!info)
+ {
+ if (error->code == G_IO_ERROR_NOT_MOUNTED)
+ {
+ /* Try to mount it */
+ FILE_BROWSER_NODE_DIR (model->priv->root)->cancellable = g_cancellable_new ();
+
+ mount_info = g_slice_new (MountInfo);
+ mount_info->model = model;
+ mount_info->virtual_root = g_file_dup (virtual_root);
+
+ /* FIXME: we should be setting the correct window */
+ mount_info->operation = gtk_mount_operation_new (NULL);
+ mount_info->cancellable = g_object_ref (FILE_BROWSER_NODE_DIR (model->priv->root)->cancellable);
+
+ model_begin_loading (model, model->priv->root);
+ g_file_mount_enclosing_volume (model->priv->root->file,
+ G_MOUNT_MOUNT_NONE,
+ mount_info->operation,
+ mount_info->cancellable,
+ (GAsyncReadyCallback)mount_cb,
+ mount_info);
+
+ model->priv->mount_info = mount_info;
+ return GEDIT_FILE_BROWSER_STORE_RESULT_MOUNTING;
+ }
+ else
+ {
+ handle_root_error (model, error);
+ }
+
+ g_error_free (error);
+ }
+ else
+ {
+ g_object_unref (info);
+
+ return model_root_mounted (model, virtual_root);
+ }
+
+ return GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+}
+
+/* Public */
+GeditFileBrowserStore *
+gedit_file_browser_store_new (GFile *root)
+{
+ return GEDIT_FILE_BROWSER_STORE (g_object_new (GEDIT_TYPE_FILE_BROWSER_STORE,
+ "root", root,
+ NULL));
+}
+
+void
+gedit_file_browser_store_set_value (GeditFileBrowserStore *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ gpointer data;
+ FileBrowserNode *node;
+ GtkTreePath *path;
+
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->user_data != NULL);
+
+ node = (FileBrowserNode *)(iter->user_data);
+
+ if (column == GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP)
+ {
+ g_return_if_fail (G_VALUE_HOLDS_STRING (value));
+
+ data = g_value_dup_string (value);
+
+ if (!data)
+ data = g_strdup (node->name);
+
+ g_free (node->markup);
+ node->markup = data;
+ }
+ else if (column == GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM)
+ {
+ g_return_if_fail (G_VALUE_HOLDS_OBJECT (value));
+
+ data = g_value_get_object (value);
+
+ g_return_if_fail (GDK_IS_PIXBUF (data) || data == NULL);
+
+ if (node->emblem)
+ g_object_unref (node->emblem);
+
+ if (data)
+ node->emblem = g_object_ref (GDK_PIXBUF (data));
+ else
+ node->emblem = NULL;
+
+ model_recomposite_icon (tree_model, iter);
+ }
+ else
+ {
+ g_return_if_fail (column == GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP ||
+ column == GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM);
+ }
+
+ if (model_node_visibility (tree_model, node))
+ {
+ path = gedit_file_browser_store_get_path (GTK_TREE_MODEL (tree_model), iter);
+ row_changed (tree_model, &path, iter);
+ gtk_tree_path_free (path);
+ }
+}
+
+GeditFileBrowserStoreResult
+gedit_file_browser_store_set_virtual_root (GeditFileBrowserStore *model,
+ GtkTreeIter *iter)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+ g_return_val_if_fail (iter != NULL, GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+ g_return_val_if_fail (iter->user_data != NULL, GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+
+ model_clear (model, FALSE);
+ set_virtual_root_from_node (model, (FileBrowserNode *)(iter->user_data));
+
+ return TRUE;
+}
+
+GeditFileBrowserStoreResult
+gedit_file_browser_store_set_virtual_root_from_location (GeditFileBrowserStore *model,
+ GFile *root)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+
+ if (root == NULL)
+ {
+ gchar *uri = g_file_get_uri (root);
+
+ g_warning ("Invalid uri (%s)", uri);
+ g_free (uri);
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+ }
+
+ /* Check if uri is already the virtual root */
+ if (model->priv->virtual_root && g_file_equal (model->priv->virtual_root->file, root))
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+
+ /* Check if uri is the root itself */
+ if (g_file_equal (model->priv->root->file, root))
+ {
+ /* Always clear the model before altering the nodes */
+ model_clear (model, FALSE);
+ set_virtual_root_from_node (model, model->priv->root);
+ return GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+ }
+
+ if (!g_file_has_prefix (root, model->priv->root->file))
+ {
+ gchar *str = g_file_get_parse_name (model->priv->root->file);
+ gchar *str1 = g_file_get_parse_name (root);
+
+ g_warning ("Virtual root (%s) is not below actual root (%s)", str1, str);
+
+ g_free (str);
+ g_free (str1);
+
+ return GEDIT_FILE_BROWSER_STORE_RESULT_ERROR;
+ }
+
+ set_virtual_root_from_file (model, root);
+
+ return GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+}
+
+GeditFileBrowserStoreResult
+gedit_file_browser_store_set_virtual_root_top (GeditFileBrowserStore *model)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+
+ if (model->priv->virtual_root == model->priv->root)
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+
+ model_clear (model, FALSE);
+ set_virtual_root_from_node (model, model->priv->root);
+
+ return GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+}
+
+GeditFileBrowserStoreResult
+gedit_file_browser_store_set_virtual_root_up (GeditFileBrowserStore *model)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+
+ if (model->priv->virtual_root == model->priv->root)
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+
+ model_clear (model, FALSE);
+ set_virtual_root_from_node (model, model->priv->virtual_root->parent);
+
+ return GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+}
+
+gboolean
+gedit_file_browser_store_get_iter_virtual_root (GeditFileBrowserStore *model,
+ GtkTreeIter *iter)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ if (model->priv->virtual_root == NULL)
+ return FALSE;
+
+ iter->user_data = model->priv->virtual_root;
+ return TRUE;
+}
+
+gboolean
+gedit_file_browser_store_get_iter_root (GeditFileBrowserStore *model,
+ GtkTreeIter *iter)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ iter->user_data = model->priv->root;
+ return TRUE;
+}
+
+gboolean
+gedit_file_browser_store_iter_equal (GeditFileBrowserStore *model,
+ GtkTreeIter *iter1,
+ GtkTreeIter *iter2)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE);
+ g_return_val_if_fail (iter1 != NULL, FALSE);
+ g_return_val_if_fail (iter2 != NULL, FALSE);
+ g_return_val_if_fail (iter1->user_data != NULL, FALSE);
+ g_return_val_if_fail (iter2->user_data != NULL, FALSE);
+
+ return (iter1->user_data == iter2->user_data);
+}
+
+void
+gedit_file_browser_store_cancel_mount_operation (GeditFileBrowserStore *store)
+{
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (store));
+
+ cancel_mount_operation (store);
+}
+
+GeditFileBrowserStoreResult
+gedit_file_browser_store_set_root_and_virtual_root (GeditFileBrowserStore *model,
+ GFile *root,
+ GFile *virtual_root)
+{
+ FileBrowserNode *node;
+ gboolean equal = FALSE;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+
+ if (root == NULL && model->priv->root == NULL)
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+
+ if (root != NULL && model->priv->root != NULL)
+ {
+ equal = g_file_equal (root, model->priv->root->file);
+
+ if (equal && virtual_root == NULL)
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+ }
+
+ if (virtual_root)
+ {
+ if (equal && g_file_equal (virtual_root, model->priv->virtual_root->file))
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+ }
+
+ /* Make sure to cancel any previous mount operations */
+ cancel_mount_operation (model);
+
+ /* Always clear the model before altering the nodes */
+ model_clear (model, TRUE);
+ file_browser_node_free (model, model->priv->root);
+
+ model->priv->root = NULL;
+ model->priv->virtual_root = NULL;
+
+ if (root != NULL)
+ {
+ /* Create the root node */
+ node = file_browser_node_dir_new (model, root, NULL);
+
+ model->priv->root = node;
+ return model_mount_root (model, virtual_root);
+ }
+ else
+ {
+ g_object_notify (G_OBJECT (model), "root");
+ g_object_notify (G_OBJECT (model), "virtual-root");
+ }
+
+ return GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+}
+
+GeditFileBrowserStoreResult
+gedit_file_browser_store_set_root (GeditFileBrowserStore *model,
+ GFile *root)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+
+ return gedit_file_browser_store_set_root_and_virtual_root (model, root, NULL);
+}
+
+GFile *
+gedit_file_browser_store_get_root (GeditFileBrowserStore *model)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), NULL);
+
+ if (model->priv->root == NULL || model->priv->root->file == NULL)
+ return NULL;
+ else
+ return g_file_dup (model->priv->root->file);
+}
+
+GFile *
+gedit_file_browser_store_get_virtual_root (GeditFileBrowserStore *model)
+{
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), NULL);
+
+ if (model->priv->virtual_root == NULL || model->priv->virtual_root->file == NULL)
+ return NULL;
+ else
+ return g_file_dup (model->priv->virtual_root->file);
+}
+
+void
+_gedit_file_browser_store_iter_expanded (GeditFileBrowserStore *model,
+ GtkTreeIter *iter)
+{
+ FileBrowserNode *node;
+
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->user_data != NULL);
+
+ node = (FileBrowserNode *)(iter->user_data);
+
+ if (NODE_IS_DIR (node) && !NODE_LOADED (node))
+ {
+ /* Load it now */
+ model_load_directory (model, node);
+ }
+}
+
+void
+_gedit_file_browser_store_iter_collapsed (GeditFileBrowserStore *model,
+ GtkTreeIter *iter)
+{
+ FileBrowserNode *node;
+
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->user_data != NULL);
+
+ node = (FileBrowserNode *)(iter->user_data);
+
+ if (NODE_IS_DIR (node) && NODE_LOADED (node))
+ {
+ /* Unload children of the children, keeping 1 depth in cache */
+
+ for (GSList *item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next)
+ {
+ node = (FileBrowserNode *)(item->data);
+
+ if (NODE_IS_DIR (node) && NODE_LOADED (node))
+ {
+ file_browser_node_unload (model, node, TRUE);
+ model_check_dummy (model, node);
+ }
+ }
+ }
+}
+
+GeditFileBrowserStoreFilterMode
+gedit_file_browser_store_get_filter_mode (GeditFileBrowserStore *model)
+{
+ return model->priv->filter_mode;
+}
+
+void
+gedit_file_browser_store_set_filter_mode (GeditFileBrowserStore *model,
+ GeditFileBrowserStoreFilterMode mode)
+{
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model));
+
+ if (model->priv->filter_mode == mode)
+ return;
+
+ model->priv->filter_mode = mode;
+ model_refilter (model);
+
+ g_object_notify (G_OBJECT (model), "filter-mode");
+}
+
+void
+gedit_file_browser_store_set_filter_func (GeditFileBrowserStore *model,
+ GeditFileBrowserStoreFilterFunc func,
+ gpointer user_data)
+{
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model));
+
+ model->priv->filter_func = func;
+ model->priv->filter_user_data = user_data;
+ model_refilter (model);
+}
+
+const gchar * const *
+gedit_file_browser_store_get_binary_patterns (GeditFileBrowserStore *model)
+{
+ return (const gchar * const *)model->priv->binary_patterns;
+}
+
+void
+gedit_file_browser_store_set_binary_patterns (GeditFileBrowserStore *model,
+ const gchar **binary_patterns)
+{
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model));
+
+ if (model->priv->binary_patterns != NULL)
+ {
+ g_strfreev (model->priv->binary_patterns);
+ g_ptr_array_unref (model->priv->binary_pattern_specs);
+ }
+
+ model->priv->binary_patterns = g_strdupv ((gchar **)binary_patterns);
+
+ if (binary_patterns == NULL)
+ {
+ model->priv->binary_pattern_specs = NULL;
+ }
+ else
+ {
+ gssize n_patterns = g_strv_length ((gchar **) binary_patterns);
+
+ model->priv->binary_pattern_specs = g_ptr_array_sized_new (n_patterns);
+ g_ptr_array_set_free_func (model->priv->binary_pattern_specs, (GDestroyNotify) g_pattern_spec_free);
+
+ for (guint i = 0; binary_patterns[i] != NULL; ++i)
+ g_ptr_array_add (model->priv->binary_pattern_specs, g_pattern_spec_new (binary_patterns[i]));
+ }
+
+ model_refilter (model);
+
+ g_object_notify (G_OBJECT (model), "binary-patterns");
+}
+
+void
+gedit_file_browser_store_refilter (GeditFileBrowserStore *model)
+{
+ model_refilter (model);
+}
+
+GeditFileBrowserStoreFilterMode
+gedit_file_browser_store_filter_mode_get_default (void)
+{
+ return GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN;
+}
+
+void
+gedit_file_browser_store_refresh (GeditFileBrowserStore *model)
+{
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model));
+
+ if (model->priv->root == NULL || model->priv->virtual_root == NULL)
+ return;
+
+ /* Clear the model */
+ g_signal_emit (model, model_signals[BEGIN_REFRESH], 0);
+ file_browser_node_unload (model, model->priv->virtual_root, TRUE);
+ model_load_directory (model, model->priv->virtual_root);
+ g_signal_emit (model, model_signals[END_REFRESH], 0);
+}
+
+static void
+reparent_node (FileBrowserNode *node,
+ gboolean reparent)
+{
+ if (!node->file)
+ return;
+
+ if (reparent)
+ {
+ GFile *parent = node->parent->file;
+ gchar *base = g_file_get_basename (node->file);
+
+ g_object_unref (node->file);
+
+ node->file = g_file_get_child (parent, base);
+ g_free (base);
+ }
+
+ if (NODE_IS_DIR (node))
+ {
+ FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (node);
+
+ for (GSList *child = dir->children; child; child = child->next)
+ reparent_node ((FileBrowserNode *)child->data, TRUE);
+ }
+}
+
+gboolean
+gedit_file_browser_store_rename (GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ const gchar *new_name,
+ GError **error)
+{
+ FileBrowserNode *node;
+ GFile *file;
+ GFile *parent;
+ GFile *previous;
+ GError *err = NULL;
+ GtkTreePath *path;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+
+ node = (FileBrowserNode *)(iter->user_data);
+
+ parent = g_file_get_parent (node->file);
+ g_return_val_if_fail (parent != NULL, FALSE);
+
+ file = g_file_get_child (parent, new_name);
+ g_object_unref (parent);
+
+ if (g_file_equal (node->file, file))
+ {
+ g_object_unref (file);
+ return TRUE;
+ }
+
+ if (g_file_move (node->file, file, G_FILE_COPY_NONE, NULL, NULL, NULL, &err))
+ {
+ previous = node->file;
+ node->file = file;
+
+ /* This makes sure the actual info for the node is requeried */
+ file_browser_node_set_name (node);
+ file_browser_node_set_from_info (model, node, NULL, TRUE);
+
+ reparent_node (node, FALSE);
+
+ if (model_node_visibility (model, node))
+ {
+ path = gedit_file_browser_store_get_path_real (model, node);
+ row_changed (model, &path, iter);
+ gtk_tree_path_free (path);
+
+ /* Reorder this item */
+ model_resort_node (model, node);
+ }
+ else
+ {
+ g_object_unref (previous);
+
+ if (error != NULL)
+ {
+ *error = g_error_new_literal (gedit_file_browser_store_error_quark (),
+ GEDIT_FILE_BROWSER_ERROR_RENAME,
+ _("The renamed file is currently filtered out. "
+ "You need to adjust your filter settings to "
+ "make the file visible"));
+ }
+
+ return FALSE;
+ }
+
+ g_signal_emit (model, model_signals[RENAME], 0, previous, node->file);
+
+ g_object_unref (previous);
+
+ return TRUE;
+ }
+ else
+ {
+ g_object_unref (file);
+
+ if (err)
+ {
+ if (error != NULL)
+ {
+ *error = g_error_new_literal (gedit_file_browser_store_error_quark (),
+ GEDIT_FILE_BROWSER_ERROR_RENAME,
+ err->message);
+ }
+
+ g_error_free (err);
+ }
+
+ return FALSE;
+ }
+}
+
+static void
+async_data_free (AsyncData *data)
+{
+ g_object_unref (data->cancellable);
+ g_list_free_full (data->files, g_object_unref);
+
+ if (!data->removed)
+ data->model->priv->async_handles = g_slist_remove (data->model->priv->async_handles, data);
+
+ g_slice_free (AsyncData, data);
+}
+
+static gboolean
+emit_no_trash (AsyncData *data)
+{
+ /* Emit the no trash error */
+ gboolean ret;
+
+ g_signal_emit (data->model, model_signals[NO_TRASH], 0, data->files, &ret);
+
+ return ret;
+}
+
+static void
+delete_file_finished (GFile *file,
+ GAsyncResult *res,
+ AsyncData *data)
+{
+ GError *error = NULL;
+ gboolean ok;
+
+ if (data->trash)
+ ok = g_file_trash_finish (file, res, &error);
+ else
+ ok = g_file_delete_finish (file, res, &error);
+
+ if (ok)
+ {
+ /* Remove the file from the model */
+ FileBrowserNode *node = model_find_node (data->model, NULL, file);
+
+ if (node != NULL)
+ model_remove_node (data->model, node, NULL, TRUE);
+
+ /* Process the next file */
+ data->iter = data->iter->next;
+ }
+ else if (!ok && error != NULL)
+ {
+ gint code = error->code;
+ g_error_free (error);
+
+ if (data->trash && code == G_IO_ERROR_NOT_SUPPORTED)
+ {
+ /* Trash is not supported on this system. Ask the user
+ * if he wants to delete completely the files instead.
+ */
+ if (emit_no_trash (data))
+ {
+ /* Changes this into a delete job */
+ data->trash = FALSE;
+ data->iter = data->files;
+ }
+ else
+ {
+ /* End the job */
+ async_data_free (data);
+ return;
+ }
+ }
+ else if (code == G_IO_ERROR_CANCELLED)
+ {
+ /* Job has been cancelled, end the job */
+ async_data_free (data);
+ return;
+ }
+ }
+
+ /* Continue the job */
+ delete_files (data);
+}
+
+static void
+delete_files (AsyncData *data)
+{
+ GFile *file;
+
+ /* Check if our job is done */
+ if (data->iter == NULL)
+ {
+ async_data_free (data);
+ return;
+ }
+
+ file = G_FILE (data->iter->data);
+
+ if (data->trash)
+ {
+ g_file_trash_async (file,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ (GAsyncReadyCallback)delete_file_finished,
+ data);
+ }
+ else
+ {
+ g_file_delete_async (file,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ (GAsyncReadyCallback)delete_file_finished,
+ data);
+ }
+}
+
+GeditFileBrowserStoreResult
+gedit_file_browser_store_delete_all (GeditFileBrowserStore *model,
+ GList *rows,
+ gboolean trash)
+{
+ FileBrowserNode *node;
+ AsyncData *data;
+ GList *files = NULL;
+ GList *row;
+ GtkTreeIter iter;
+ GtkTreePath *prev = NULL;
+ GtkTreePath *path;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+
+ if (rows == NULL)
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+
+ /* First we sort the paths so that we can later on remove any
+ files/directories that are actually subfiles/directories of
+ a directory that's also deleted */
+ rows = g_list_sort (g_list_copy (rows), (GCompareFunc)gtk_tree_path_compare);
+
+ for (row = rows; row; row = row->next)
+ {
+ path = (GtkTreePath *)(row->data);
+
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
+ continue;
+
+ /* Skip if the current path is actually a descendant of the
+ previous path */
+ if (prev != NULL && gtk_tree_path_is_descendant (path, prev))
+ continue;
+
+ prev = path;
+ node = (FileBrowserNode *)(iter.user_data);
+ files = g_list_prepend (files, g_object_ref (node->file));
+ }
+
+ data = g_slice_new (AsyncData);
+
+ data->model = model;
+ data->cancellable = g_cancellable_new ();
+ data->files = files;
+ data->trash = trash;
+ data->iter = files;
+ data->removed = FALSE;
+
+ model->priv->async_handles = g_slist_prepend (model->priv->async_handles, data);
+
+ delete_files (data);
+ g_list_free (rows);
+
+ return GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+}
+
+GeditFileBrowserStoreResult
+gedit_file_browser_store_delete (GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ gboolean trash)
+{
+ FileBrowserNode *node;
+ GList *rows = NULL;
+ GeditFileBrowserStoreResult result;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+ g_return_val_if_fail (iter != NULL, GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+ g_return_val_if_fail (iter->user_data != NULL, GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
+
+ node = (FileBrowserNode *)(iter->user_data);
+
+ if (NODE_IS_DUMMY (node))
+ return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE;
+
+ rows = g_list_append(NULL, gedit_file_browser_store_get_path_real (model, node));
+ result = gedit_file_browser_store_delete_all (model, rows, trash);
+
+ g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
+
+ return result;
+}
+
+gboolean
+gedit_file_browser_store_new_file (GeditFileBrowserStore *model,
+ GtkTreeIter *parent,
+ GtkTreeIter *iter)
+{
+ GFile *file;
+ GFileOutputStream *stream;
+ FileBrowserNodeDir *parent_node;
+ gboolean result = FALSE;
+ FileBrowserNode *node;
+ GError *error = NULL;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE);
+ g_return_val_if_fail (parent != NULL, FALSE);
+ g_return_val_if_fail (parent->user_data != NULL, FALSE);
+ g_return_val_if_fail (NODE_IS_DIR ((FileBrowserNode *) (parent->user_data)), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ parent_node = FILE_BROWSER_NODE_DIR (parent->user_data);
+ /* Translators: This is the default name of new files created by the file browser pane. */
+ file = unique_new_name (((FileBrowserNode *) parent_node)->file, _("Untitled File"));
+
+ stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
+
+ if (!stream)
+ {
+ g_signal_emit (model, model_signals[ERROR], 0,
+ GEDIT_FILE_BROWSER_ERROR_NEW_FILE,
+ error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ g_object_unref (stream);
+ node = model_add_node_from_file (model,
+ (FileBrowserNode *)parent_node,
+ file,
+ NULL);
+
+ if (model_node_visibility (model, node))
+ {
+ iter->user_data = node;
+ result = TRUE;
+ }
+ else
+ {
+ g_signal_emit (model, model_signals[ERROR], 0,
+ GEDIT_FILE_BROWSER_ERROR_NEW_FILE,
+ _("The new file is currently filtered out. "
+ "You need to adjust your filter "
+ "settings to make the file visible"));
+ }
+ }
+
+ g_object_unref (file);
+ return result;
+}
+
+gboolean
+gedit_file_browser_store_new_directory (GeditFileBrowserStore *model,
+ GtkTreeIter *parent,
+ GtkTreeIter *iter)
+{
+ GFile *file;
+ FileBrowserNodeDir *parent_node;
+ GError *error = NULL;
+ FileBrowserNode *node;
+ gboolean result = FALSE;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE);
+ g_return_val_if_fail (parent != NULL, FALSE);
+ g_return_val_if_fail (parent->user_data != NULL, FALSE);
+ g_return_val_if_fail (NODE_IS_DIR ((FileBrowserNode *)(parent->user_data)), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ parent_node = FILE_BROWSER_NODE_DIR (parent->user_data);
+ /* Translators: This is the default name of new directories created by the file browser pane. */
+ file = unique_new_name (((FileBrowserNode *) parent_node)->file, _("Untitled Folder"));
+
+ if (!g_file_make_directory (file, NULL, &error))
+ {
+ g_signal_emit (model, model_signals[ERROR], 0, GEDIT_FILE_BROWSER_ERROR_NEW_DIRECTORY, error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ node = model_add_node_from_file (model,
+ (FileBrowserNode *)parent_node,
+ file,
+ NULL);
+
+ if (model_node_visibility (model, node))
+ {
+ iter->user_data = node;
+ result = TRUE;
+ }
+ else
+ {
+ g_signal_emit (model, model_signals[ERROR], 0,
+ GEDIT_FILE_BROWSER_ERROR_NEW_FILE,
+ _("The new directory is currently filtered "
+ "out. You need to adjust your filter "
+ "settings to make the directory visible"));
+ }
+ }
+
+ g_object_unref (file);
+ return result;
+}
+
+void
+_gedit_file_browser_store_register_type (GTypeModule *type_module)
+{
+ gedit_file_browser_store_register_type (type_module);
+}
+
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-store.h b/plugins/filebrowser/gedit-file-browser-store.h
new file mode 100644
index 0000000..02df0cb
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-store.h
@@ -0,0 +1,188 @@
+/*
+ * gedit-file-browser-store.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GEDIT_FILE_BROWSER_STORE_H
+#define GEDIT_FILE_BROWSER_STORE_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+#define GEDIT_TYPE_FILE_BROWSER_STORE (gedit_file_browser_store_get_type ())
+#define GEDIT_FILE_BROWSER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_STORE, GeditFileBrowserStore))
+#define GEDIT_FILE_BROWSER_STORE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_STORE, GeditFileBrowserStore const))
+#define GEDIT_FILE_BROWSER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FILE_BROWSER_STORE, GeditFileBrowserStoreClass))
+#define GEDIT_IS_FILE_BROWSER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FILE_BROWSER_STORE))
+#define GEDIT_IS_FILE_BROWSER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FILE_BROWSER_STORE))
+#define GEDIT_FILE_BROWSER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FILE_BROWSER_STORE, GeditFileBrowserStoreClass))
+
+typedef enum
+{
+ GEDIT_FILE_BROWSER_STORE_COLUMN_ICON = 0,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_ICON_NAME,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS,
+
+ /* Columns not in common with GeditFileBookmarksStore */
+ GEDIT_FILE_BROWSER_STORE_COLUMN_NAME,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_NUM
+} GeditFileBrowserStoreColumn;
+
+typedef enum
+{
+ GEDIT_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY = 1 << 0,
+ GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN = 1 << 1,
+ GEDIT_FILE_BROWSER_STORE_FLAG_IS_TEXT = 1 << 2,
+ GEDIT_FILE_BROWSER_STORE_FLAG_LOADED = 1 << 3,
+ GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED = 1 << 4,
+ GEDIT_FILE_BROWSER_STORE_FLAG_IS_DUMMY = 1 << 5
+} GeditFileBrowserStoreFlag;
+
+typedef enum
+{
+ GEDIT_FILE_BROWSER_STORE_RESULT_OK,
+ GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE,
+ GEDIT_FILE_BROWSER_STORE_RESULT_ERROR,
+ GEDIT_FILE_BROWSER_STORE_RESULT_NO_TRASH,
+ GEDIT_FILE_BROWSER_STORE_RESULT_MOUNTING,
+ GEDIT_FILE_BROWSER_STORE_RESULT_NUM
+} GeditFileBrowserStoreResult;
+
+typedef enum
+{
+ GEDIT_FILE_BROWSER_STORE_FILTER_MODE_NONE = 0,
+ GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN = 1 << 0,
+ GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY = 1 << 1
+} GeditFileBrowserStoreFilterMode;
+
+#define FILE_IS_DIR(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY)
+#define FILE_IS_HIDDEN(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN)
+#define FILE_IS_TEXT(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_TEXT)
+#define FILE_LOADED(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_LOADED)
+#define FILE_IS_FILTERED(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED)
+#define FILE_IS_DUMMY(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_DUMMY)
+
+typedef struct _GeditFileBrowserStore GeditFileBrowserStore;
+typedef struct _GeditFileBrowserStoreClass GeditFileBrowserStoreClass;
+typedef struct _GeditFileBrowserStorePrivate GeditFileBrowserStorePrivate;
+
+typedef gboolean (*GeditFileBrowserStoreFilterFunc) (GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ gpointer user_data);
+
+struct _GeditFileBrowserStore
+{
+ GObject parent;
+
+ GeditFileBrowserStorePrivate *priv;
+};
+
+struct _GeditFileBrowserStoreClass {
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (* begin_loading) (GeditFileBrowserStore *model,
+ GtkTreeIter *iter);
+ void (* end_loading) (GeditFileBrowserStore *model,
+ GtkTreeIter *iter);
+ void (* error) (GeditFileBrowserStore *model,
+ guint code,
+ gchar *message);
+ gboolean (* no_trash) (GeditFileBrowserStore *model,
+ GList *files);
+ void (* rename) (GeditFileBrowserStore *model,
+ GFile *oldfile,
+ GFile *newfile);
+ void (* begin_refresh) (GeditFileBrowserStore *model);
+ void (* end_refresh) (GeditFileBrowserStore *model);
+ void (* unload) (GeditFileBrowserStore *model,
+ GFile *location);
+ void (* before_row_deleted) (GeditFileBrowserStore *model,
+ GtkTreePath *path);
+};
+
+GType gedit_file_browser_store_get_type (void) G_GNUC_CONST;
+
+GeditFileBrowserStore *gedit_file_browser_store_new (GFile *root);
+GeditFileBrowserStoreResult gedit_file_browser_store_set_root_and_virtual_root (GeditFileBrowserStore *model,
+ GFile *root,
+ GFile *virtual_root);
+GeditFileBrowserStoreResult gedit_file_browser_store_set_root (GeditFileBrowserStore *model,
+ GFile *root);
+GeditFileBrowserStoreResult gedit_file_browser_store_set_virtual_root (GeditFileBrowserStore *model,
+ GtkTreeIter *iter);
+GeditFileBrowserStoreResult gedit_file_browser_store_set_virtual_root_from_location (GeditFileBrowserStore *model,
+ GFile *root);
+GeditFileBrowserStoreResult gedit_file_browser_store_set_virtual_root_up (GeditFileBrowserStore *model);
+GeditFileBrowserStoreResult gedit_file_browser_store_set_virtual_root_top (GeditFileBrowserStore *model);
+gboolean gedit_file_browser_store_get_iter_virtual_root (GeditFileBrowserStore *model,
+ GtkTreeIter *iter);
+gboolean gedit_file_browser_store_get_iter_root (GeditFileBrowserStore *model,
+ GtkTreeIter *iter);
+GFile *gedit_file_browser_store_get_root (GeditFileBrowserStore *model);
+GFile *gedit_file_browser_store_get_virtual_root (GeditFileBrowserStore *model);
+gboolean gedit_file_browser_store_iter_equal (GeditFileBrowserStore *model,
+ GtkTreeIter *iter1,
+ GtkTreeIter *iter2);
+void gedit_file_browser_store_set_value (GeditFileBrowserStore *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value);
+void _gedit_file_browser_store_iter_expanded (GeditFileBrowserStore *model,
+ GtkTreeIter *iter);
+void _gedit_file_browser_store_iter_collapsed (GeditFileBrowserStore *model,
+ GtkTreeIter *iter);
+GeditFileBrowserStoreFilterMode gedit_file_browser_store_get_filter_mode (GeditFileBrowserStore *model);
+void gedit_file_browser_store_set_filter_mode (GeditFileBrowserStore *model,
+ GeditFileBrowserStoreFilterMode mode);
+void gedit_file_browser_store_set_filter_func (GeditFileBrowserStore *model,
+ GeditFileBrowserStoreFilterFunc func,
+ gpointer user_data);
+const gchar * const *gedit_file_browser_store_get_binary_patterns (GeditFileBrowserStore *model);
+void gedit_file_browser_store_set_binary_patterns (GeditFileBrowserStore *model,
+ const gchar **binary_patterns);
+void gedit_file_browser_store_refilter (GeditFileBrowserStore *model);
+GeditFileBrowserStoreFilterMode gedit_file_browser_store_filter_mode_get_default (void);
+void gedit_file_browser_store_refresh (GeditFileBrowserStore *model);
+gboolean gedit_file_browser_store_rename (GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ gchar const *new_name,
+ GError **error);
+GeditFileBrowserStoreResult gedit_file_browser_store_delete (GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ gboolean trash);
+GeditFileBrowserStoreResult gedit_file_browser_store_delete_all (GeditFileBrowserStore *model,
+ GList *rows,
+ gboolean trash);
+gboolean gedit_file_browser_store_new_file (GeditFileBrowserStore *model,
+ GtkTreeIter *parent,
+ GtkTreeIter *iter);
+gboolean gedit_file_browser_store_new_directory (GeditFileBrowserStore *model,
+ GtkTreeIter *parent,
+ GtkTreeIter *iter);
+void gedit_file_browser_store_cancel_mount_operation (GeditFileBrowserStore *store);
+
+void _gedit_file_browser_store_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_STORE_H */
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-utils.c b/plugins/filebrowser/gedit-file-browser-utils.c
new file mode 100644
index 0000000..dbca26a
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-utils.c
@@ -0,0 +1,223 @@
+/*
+ * gedit-file-bookmarks-utils.c - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gedit/gedit-utils.h>
+
+#include "gedit-file-browser-utils.h"
+
+static GdkPixbuf *
+process_icon_pixbuf (GdkPixbuf *pixbuf,
+ gchar const *name,
+ gint size,
+ GError *error)
+{
+ GdkPixbuf *scale;
+
+ if (error != NULL)
+ {
+ g_warning ("Could not load theme icon %s: %s",
+ name,
+ error->message);
+ g_error_free (error);
+ }
+
+ if (pixbuf && gdk_pixbuf_get_width (pixbuf) > size)
+ {
+ scale = gdk_pixbuf_scale_simple (pixbuf,
+ size,
+ size,
+ GDK_INTERP_BILINEAR);
+ g_object_unref (pixbuf);
+ pixbuf = scale;
+ }
+
+ return pixbuf;
+}
+
+GdkPixbuf *
+gedit_file_browser_utils_pixbuf_from_theme (gchar const *name,
+ GtkIconSize size)
+{
+ gint width;
+ GError *error = NULL;
+ GdkPixbuf *pixbuf;
+
+ gtk_icon_size_lookup (size, &width, NULL);
+
+ pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ name,
+ width,
+ 0,
+ &error);
+
+ pixbuf = process_icon_pixbuf (pixbuf, name, width, error);
+
+ return pixbuf;
+}
+
+GdkPixbuf *
+gedit_file_browser_utils_pixbuf_from_icon (GIcon *icon,
+ GtkIconSize size)
+{
+ GdkPixbuf *ret = NULL;
+ GtkIconTheme *theme;
+ GtkIconInfo *info;
+ gint width;
+
+ if (!icon)
+ return NULL;
+
+ theme = gtk_icon_theme_get_default ();
+ gtk_icon_size_lookup (size, &width, NULL);
+
+ info = gtk_icon_theme_lookup_by_gicon (theme,
+ icon,
+ width,
+ GTK_ICON_LOOKUP_USE_BUILTIN);
+
+ if (!info)
+ return NULL;
+
+ ret = gtk_icon_info_load_icon (info, NULL);
+ g_object_unref (info);
+
+ return ret;
+}
+
+GdkPixbuf *
+gedit_file_browser_utils_pixbuf_from_file (GFile *file,
+ GtkIconSize size,
+ gboolean use_symbolic)
+{
+ GIcon *icon;
+ GFileInfo *info;
+ GdkPixbuf *ret = NULL;
+ const char *attribute;
+
+ attribute = use_symbolic ? G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON :
+ G_FILE_ATTRIBUTE_STANDARD_ICON;
+
+ info = g_file_query_info (file,
+ attribute,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+
+ if (!info)
+ return NULL;
+
+ icon = use_symbolic ? g_file_info_get_symbolic_icon (info) :
+ g_file_info_get_icon (info);
+ if (icon != NULL)
+ ret = gedit_file_browser_utils_pixbuf_from_icon (icon, size);
+
+ g_object_unref (info);
+
+ return ret;
+}
+
+gchar *
+gedit_file_browser_utils_symbolic_icon_name_from_file (GFile *file)
+{
+ GFileInfo *info;
+ GIcon *icon;
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+
+ if (!info)
+ return NULL;
+
+ if ((icon = g_file_info_get_symbolic_icon (info)) && G_IS_THEMED_ICON (icon))
+ {
+ const gchar * const *names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+ return g_strdup (names[0]);
+ }
+
+ g_object_unref (info);
+ return NULL;
+}
+
+gchar *
+gedit_file_browser_utils_name_from_themed_icon (GIcon *icon)
+{
+ GtkIconTheme *theme;
+ const gchar * const *names;
+
+ if (!G_IS_THEMED_ICON (icon))
+ return NULL;
+
+ theme = gtk_icon_theme_get_default ();
+ names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+
+ if (gtk_icon_theme_has_icon (theme, names[0]))
+ return g_strdup (names[0]);
+
+ return NULL;
+}
+
+gchar *
+gedit_file_browser_utils_file_basename (GFile *file)
+{
+ return gedit_utils_basename_for_display (file);
+}
+
+gboolean
+gedit_file_browser_utils_confirmation_dialog (GeditWindow *window,
+ GtkMessageType type,
+ gchar const *message,
+ gchar const *secondary,
+ gchar const *button_label)
+{
+ GtkWidget *dlg;
+ gint ret;
+
+ dlg = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ type,
+ GTK_BUTTONS_NONE, "%s", message);
+
+ if (secondary)
+ {
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dlg), "%s", secondary);
+ }
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dlg),
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ button_label, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_CANCEL);
+
+ ret = gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+
+ return (ret == GTK_RESPONSE_OK);
+}
+
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-utils.h b/plugins/filebrowser/gedit-file-browser-utils.h
new file mode 100644
index 0000000..165f513
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-utils.h
@@ -0,0 +1,46 @@
+/*
+ * gedit-file-browser-utils.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GEDIT_FILE_BROWSER_UTILS_H
+#define GEDIT_FILE_BROWSER_UTILS_H
+
+#include <gedit/gedit-window.h>
+#include <gio/gio.h>
+
+gchar *gedit_file_browser_utils_name_from_themed_icon (GIcon *icon);
+GdkPixbuf *gedit_file_browser_utils_pixbuf_from_theme (gchar const *name,
+ GtkIconSize size);
+
+GdkPixbuf *gedit_file_browser_utils_pixbuf_from_icon (GIcon *icon,
+ GtkIconSize size);
+GdkPixbuf *gedit_file_browser_utils_pixbuf_from_file (GFile *file,
+ GtkIconSize size,
+ gboolean use_symbolic);
+gchar *gedit_file_browser_utils_symbolic_icon_name_from_file (GFile *file);
+gchar *gedit_file_browser_utils_file_basename (GFile *file);
+
+gboolean gedit_file_browser_utils_confirmation_dialog (GeditWindow *window,
+ GtkMessageType type,
+ gchar const *message,
+ gchar const *secondary,
+ gchar const *button_label);
+
+#endif /* GEDIT_FILE_BROWSER_UTILS_H */
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-view.c b/plugins/filebrowser/gedit-file-browser-view.c
new file mode 100644
index 0000000..a13f4d7
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-view.c
@@ -0,0 +1,1364 @@
+/*
+ * gedit-file-browser-view.c - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gedit-file-browser-store.h"
+#include "gedit-file-bookmarks-store.h"
+#include "gedit-file-browser-view.h"
+#include "gedit-file-browser-enum-types.h"
+
+struct _GeditFileBrowserViewPrivate
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *pixbuf_renderer;
+ GtkCellRenderer *text_renderer;
+
+ GtkTreeModel *model;
+
+ /* Used when renaming */
+ gchar *orig_markup;
+ GtkTreeRowReference *editable;
+
+ /* Click policy */
+ GeditFileBrowserViewClickPolicy click_policy;
+ /* Both clicks in a double click need to be on the same row */
+ GtkTreePath *double_click_path[2];
+ GtkTreePath *hover_path;
+ GdkCursor *hand_cursor;
+ gboolean ignore_release;
+ gboolean selected_on_button_down;
+ gint drag_button;
+ gboolean drag_started;
+
+ gboolean restore_expand_state;
+ gboolean is_refresh;
+ GHashTable *expand_state;
+};
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ PROP_CLICK_POLICY,
+ PROP_RESTORE_EXPAND_STATE
+};
+
+/* Signals */
+enum
+{
+ ERROR,
+ FILE_ACTIVATED,
+ DIRECTORY_ACTIVATED,
+ BOOKMARK_ACTIVATED,
+ NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS] = { 0 };
+
+static const GtkTargetEntry drag_source_targets[] = {
+ { "text/uri-list", 0, 0 }
+};
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditFileBrowserView,
+ gedit_file_browser_view,
+ GTK_TYPE_TREE_VIEW,
+ 0,
+ G_ADD_PRIVATE_DYNAMIC (GeditFileBrowserView))
+
+static void on_cell_edited (GtkCellRendererText *cell,
+ gchar *path,
+ gchar *new_text,
+ GeditFileBrowserView *tree_view);
+
+static void on_begin_refresh (GeditFileBrowserStore *model,
+ GeditFileBrowserView *view);
+static void on_end_refresh (GeditFileBrowserStore *model,
+ GeditFileBrowserView *view);
+
+static void on_unload (GeditFileBrowserStore *model,
+ GFile *location,
+ GeditFileBrowserView *view);
+
+static void on_row_inserted (GeditFileBrowserStore *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GeditFileBrowserView *view);
+
+static void
+gedit_file_browser_view_finalize (GObject *object)
+{
+ GeditFileBrowserView *obj = GEDIT_FILE_BROWSER_VIEW (object);
+
+ if (obj->priv->hand_cursor)
+ g_object_unref (obj->priv->hand_cursor);
+
+ if (obj->priv->hover_path)
+ gtk_tree_path_free (obj->priv->hover_path);
+
+ if (obj->priv->expand_state)
+ {
+ g_hash_table_destroy (obj->priv->expand_state);
+ obj->priv->expand_state = NULL;
+ }
+
+ G_OBJECT_CLASS (gedit_file_browser_view_parent_class)->finalize (object);
+}
+
+static void
+add_expand_state (GeditFileBrowserView *view,
+ GFile *location)
+{
+ if (!location)
+ return;
+
+ if (view->priv->expand_state)
+ g_hash_table_insert (view->priv->expand_state, location, g_object_ref (location));
+}
+
+static void
+remove_expand_state (GeditFileBrowserView *view,
+ GFile *location)
+{
+ if (!location)
+ return;
+
+ if (view->priv->expand_state)
+ g_hash_table_remove (view->priv->expand_state, location);
+}
+
+static void
+row_expanded (GtkTreeView *tree_view,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (tree_view);
+
+ if (GTK_TREE_VIEW_CLASS (gedit_file_browser_view_parent_class)->row_expanded)
+ GTK_TREE_VIEW_CLASS (gedit_file_browser_view_parent_class)->row_expanded (tree_view, iter, path);
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (view->priv->model))
+ return;
+
+ if (view->priv->restore_expand_state)
+ {
+ GFile *location;
+
+ gtk_tree_model_get (view->priv->model,
+ iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ add_expand_state (view, location);
+
+ if (location)
+ g_object_unref (location);
+ }
+
+ _gedit_file_browser_store_iter_expanded (GEDIT_FILE_BROWSER_STORE (view->priv->model),
+ iter);
+}
+
+static void
+row_collapsed (GtkTreeView *tree_view,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (tree_view);
+
+ if (GTK_TREE_VIEW_CLASS (gedit_file_browser_view_parent_class)->row_collapsed)
+ GTK_TREE_VIEW_CLASS (gedit_file_browser_view_parent_class)->row_collapsed (tree_view, iter, path);
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (view->priv->model))
+ return;
+
+ if (view->priv->restore_expand_state)
+ {
+ GFile *location;
+
+ gtk_tree_model_get (view->priv->model,
+ iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ remove_expand_state (view, location);
+
+ if (location)
+ g_object_unref (location);
+ }
+
+ _gedit_file_browser_store_iter_collapsed (GEDIT_FILE_BROWSER_STORE (view->priv->model),
+ iter);
+}
+
+static gboolean
+leave_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget);
+
+ if (view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE &&
+ view->priv->hover_path != NULL)
+ {
+ gtk_tree_path_free (view->priv->hover_path);
+ view->priv->hover_path = NULL;
+ }
+
+ /* Chainup */
+ return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->leave_notify_event (widget, event);
+}
+
+static gboolean
+enter_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget);
+
+ if (view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE)
+ {
+ if (view->priv->hover_path != NULL)
+ gtk_tree_path_free (view->priv->hover_path);
+
+ gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+ event->x, event->y,
+ &view->priv->hover_path,
+ NULL, NULL, NULL);
+
+ if (view->priv->hover_path != NULL)
+ {
+ gdk_window_set_cursor (gtk_widget_get_window (widget),
+ view->priv->hand_cursor);
+ }
+ }
+
+ /* Chainup */
+ return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->enter_notify_event (widget, event);
+}
+
+static gboolean
+motion_notify_event (GtkWidget *widget,
+ GdkEventMotion *event)
+{
+ GtkTreePath *old_hover_path;
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget);
+
+ if (view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE)
+ {
+ old_hover_path = view->priv->hover_path;
+ gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+ event->x, event->y,
+ &view->priv->hover_path,
+ NULL, NULL, NULL);
+
+ if ((old_hover_path != NULL) != (view->priv->hover_path != NULL))
+ {
+ if (view->priv->hover_path != NULL)
+ {
+ gdk_window_set_cursor (gtk_widget_get_window (widget),
+ view->priv->hand_cursor);
+ }
+ else
+ {
+ gdk_window_set_cursor (gtk_widget_get_window (widget),
+ NULL);
+ }
+ }
+
+ if (old_hover_path != NULL)
+ gtk_tree_path_free (old_hover_path);
+ }
+
+ /* Chainup */
+ return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->motion_notify_event (widget, event);
+}
+
+static void
+set_click_policy_property (GeditFileBrowserView *obj,
+ GeditFileBrowserViewClickPolicy click_policy)
+{
+ GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (obj));
+
+ obj->priv->click_policy = click_policy;
+
+ if (click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE)
+ {
+ if (obj->priv->hand_cursor == NULL)
+ obj->priv->hand_cursor = gdk_cursor_new_from_name (display, "pointer");
+ }
+ else if (click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE)
+ {
+ if (obj->priv->hover_path != NULL)
+ {
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (obj->priv->model),
+ &iter, obj->priv->hover_path))
+ {
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (obj->priv->model),
+ obj->priv->hover_path, &iter);
+ }
+
+ gtk_tree_path_free (obj->priv->hover_path);
+ obj->priv->hover_path = NULL;
+ }
+
+ if (gtk_widget_get_realized (GTK_WIDGET (obj)))
+ {
+ GdkWindow *win = gtk_widget_get_window (GTK_WIDGET (obj));
+
+ gdk_window_set_cursor (win, NULL);
+
+ if (display != NULL)
+ gdk_display_flush (display);
+ }
+
+ if (obj->priv->hand_cursor)
+ {
+ g_object_unref (obj->priv->hand_cursor);
+ obj->priv->hand_cursor = NULL;
+ }
+ }
+}
+
+static void
+directory_activated (GeditFileBrowserView *view,
+ GtkTreeIter *iter)
+{
+ gedit_file_browser_store_set_virtual_root (GEDIT_FILE_BROWSER_STORE (view->priv->model), iter);
+}
+
+static void
+activate_selected_files (GeditFileBrowserView *view)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (view);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
+ GList *rows = gtk_tree_selection_get_selected_rows (selection, &view->priv->model);
+ GList *row;
+ GtkTreePath *directory = NULL;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GeditFileBrowserStoreFlag flags;
+
+ for (row = rows; row; row = row->next)
+ {
+ path = (GtkTreePath *)(row->data);
+
+ /* Get iter from path */
+ if (!gtk_tree_model_get_iter (view->priv->model, &iter, path))
+ continue;
+
+ gtk_tree_model_get (view->priv->model, &iter, GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, -1);
+
+ if (FILE_IS_DIR (flags) && directory == NULL)
+ directory = path;
+ else if (!FILE_IS_DUMMY (flags))
+ g_signal_emit (view, signals[FILE_ACTIVATED], 0, &iter);
+ }
+
+ if (directory != NULL &&
+ gtk_tree_model_get_iter (view->priv->model, &iter, directory))
+ {
+ g_signal_emit (view, signals[DIRECTORY_ACTIVATED], 0, &iter);
+ }
+
+ g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
+}
+
+static void
+activate_selected_bookmark (GeditFileBrowserView *view)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (view);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (selection, &view->priv->model, &iter))
+ g_signal_emit (view, signals[BOOKMARK_ACTIVATED], 0, &iter);
+}
+
+static void
+activate_selected_items (GeditFileBrowserView *view)
+{
+ if (GEDIT_IS_FILE_BROWSER_STORE (view->priv->model))
+ activate_selected_files (view);
+ else if (GEDIT_IS_FILE_BOOKMARKS_STORE (view->priv->model))
+ activate_selected_bookmark (view);
+}
+
+static void
+expand_or_collapse_selected_item (GeditFileBrowserView *view,
+ gboolean collapse)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (view);
+ GtkTreePath *path = NULL;
+
+ gtk_tree_view_get_cursor (tree_view, &path, NULL);
+
+ if (path == NULL)
+ {
+ return;
+ }
+
+ if (collapse)
+ {
+ if (!gtk_tree_view_collapse_row (tree_view, path) &&
+ gtk_tree_path_get_depth (path) > 1 &&
+ gtk_tree_path_up (path))
+ {
+ gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
+ }
+ }
+ else
+ {
+ gtk_tree_view_expand_row (tree_view, path, FALSE);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+row_activated (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
+
+ /* Make sure the activated row is the only one selected */
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_selection_select_path (selection, path);
+
+ activate_selected_items (GEDIT_FILE_BROWSER_VIEW (tree_view));
+}
+
+static void
+toggle_hidden_filter (GeditFileBrowserView *view)
+{
+ GeditFileBrowserStoreFilterMode mode;
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (view->priv->model))
+ {
+ mode = gedit_file_browser_store_get_filter_mode (GEDIT_FILE_BROWSER_STORE (view->priv->model));
+ mode ^= GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN;
+ gedit_file_browser_store_set_filter_mode (GEDIT_FILE_BROWSER_STORE (view->priv->model), mode);
+ }
+}
+
+static gboolean
+button_event_modifies_selection (GdkEventButton *event)
+{
+ return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
+}
+
+static void
+drag_begin (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget);
+
+ view->priv->drag_button = 0;
+ view->priv->drag_started = TRUE;
+
+ /* Chain up */
+ GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->drag_begin (widget, context);
+}
+
+static void
+did_not_drag (GeditFileBrowserView *view,
+ GdkEventButton *event)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (view);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
+ GtkTreePath *path;
+
+ if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, NULL, NULL, NULL))
+ {
+ if ((view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) &&
+ !button_event_modifies_selection (event) &&
+ (event->button == 1 || event->button == 2))
+ {
+ /* Activate all selected items, and leave them selected */
+ activate_selected_items (view);
+ }
+ else if ((event->button == 1 || event->button == 2) &&
+ ((event->state & GDK_CONTROL_MASK) != 0 || (event->state & GDK_SHIFT_MASK) == 0) &&
+ view->priv->selected_on_button_down)
+ {
+ if (!button_event_modifies_selection (event))
+ {
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_selection_select_path (selection, path);
+ }
+ else
+ {
+ gtk_tree_selection_unselect_path (selection, path);
+ }
+ }
+
+ gtk_tree_path_free (path);
+ }
+}
+
+static gboolean
+button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget);
+
+ if (event->button == view->priv->drag_button)
+ {
+ view->priv->drag_button = 0;
+
+ if (!view->priv->drag_started && !view->priv->ignore_release)
+ did_not_drag (view, event);
+ }
+
+ /* Chain up */
+ return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->button_release_event (widget, event);
+}
+
+static gboolean
+button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GtkWidgetClass *widget_parent = GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class);
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
+ int double_click_time;
+ static int click_count = 0;
+ static guint32 last_click_time = 0;
+ GtkTreePath *path;
+ int expander_size;
+ int horizontal_separator;
+ gboolean on_expander;
+ gboolean call_parent;
+ gboolean selected;
+
+ /* Get double click time */
+ g_object_get (G_OBJECT (gtk_widget_get_settings (widget)),
+ "gtk-double-click-time", &double_click_time,
+ NULL);
+
+ /* Determine click count */
+ if (event->time - last_click_time < double_click_time)
+ click_count++;
+ else
+ click_count = 0;
+
+ last_click_time = event->time;
+
+ /* Ignore double click if we are in single click mode */
+ if (view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE &&
+ click_count >= 2)
+ {
+ return TRUE;
+ }
+
+ view->priv->ignore_release = FALSE;
+ call_parent = TRUE;
+
+ if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, NULL, NULL, NULL))
+ {
+ /* Keep track of path of last click so double clicks only happen
+ * on the same item */
+ if ((event->button == 1 || event->button == 2) &&
+ event->type == GDK_BUTTON_PRESS)
+ {
+ if (view->priv->double_click_path[1])
+ gtk_tree_path_free (view->priv->double_click_path[1]);
+
+ view->priv->double_click_path[1] = view->priv->double_click_path[0];
+ view->priv->double_click_path[0] = gtk_tree_path_copy (path);
+ }
+
+ if (event->type == GDK_2BUTTON_PRESS)
+ {
+ /* Do not chain up. The row-activated signal is normally
+ * already sent, which will activate the selected item
+ * and open the file.
+ */
+ }
+ else
+ {
+ /* We're going to filter out some situations where
+ * we can't let the default code run because all
+ * but one row would be deselected. We don't
+ * want that; we want the right click menu or single
+ * click to apply to everything that's currently selected. */
+ selected = gtk_tree_selection_path_is_selected (selection, path);
+
+ if (event->button == GDK_BUTTON_SECONDARY && selected)
+ call_parent = FALSE;
+
+ if ((event->button == 1 || event->button == 2) &&
+ ((event->state & GDK_CONTROL_MASK) != 0 ||
+ (event->state & GDK_SHIFT_MASK) == 0))
+ {
+ gtk_widget_style_get (widget,
+ "expander-size", &expander_size,
+ "horizontal-separator", &horizontal_separator,
+ NULL);
+ on_expander = (event->x <= horizontal_separator / 2 +
+ gtk_tree_path_get_depth (path) * expander_size);
+
+ view->priv->selected_on_button_down = selected;
+
+ if (selected)
+ {
+ call_parent = on_expander || gtk_tree_selection_count_selected_rows (selection) == 1;
+ view->priv->ignore_release = call_parent && view->priv->click_policy != GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE;
+ }
+ else if ((event->state & GDK_CONTROL_MASK) != 0)
+ {
+ call_parent = FALSE;
+ gtk_tree_selection_select_path (selection, path);
+ }
+ else
+ {
+ view->priv->ignore_release = on_expander;
+ }
+ }
+
+ if (call_parent)
+ {
+ /* Chain up */
+ widget_parent->button_press_event (widget, event);
+ }
+ else if (selected)
+ {
+ gtk_widget_grab_focus (widget);
+ }
+
+ if ((event->button == 1 || event->button == 2) &&
+ event->type == GDK_BUTTON_PRESS)
+ {
+ view->priv->drag_started = FALSE;
+ view->priv->drag_button = event->button;
+ }
+ }
+
+ gtk_tree_path_free (path);
+ }
+ else
+ {
+ if ((event->button == 1 || event->button == 2) &&
+ event->type == GDK_BUTTON_PRESS)
+ {
+ if (view->priv->double_click_path[1])
+ gtk_tree_path_free (view->priv->double_click_path[1]);
+
+ view->priv->double_click_path[1] = view->priv->double_click_path[0];
+ view->priv->double_click_path[0] = NULL;
+ }
+
+ gtk_tree_selection_unselect_all (selection);
+ /* Chain up */
+ widget_parent->button_press_event (widget, event);
+ }
+
+ /* We already chained up if nescessary, so just return TRUE */
+ return TRUE;
+}
+
+static gboolean
+key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget);
+ guint modifiers = gtk_accelerator_get_default_mod_mask ();
+ gboolean handled = FALSE;
+
+ switch (event->keyval)
+ {
+ case GDK_KEY_space:
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ handled = FALSE;
+ break;
+ }
+ if (!gtk_widget_has_focus (widget))
+ {
+ handled = FALSE;
+ break;
+ }
+
+ activate_selected_items (view);
+ handled = TRUE;
+ break;
+
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ activate_selected_items (view);
+ handled = TRUE;
+ break;
+
+ case GDK_KEY_h:
+ if ((event->state & modifiers) == GDK_CONTROL_MASK)
+ {
+ toggle_hidden_filter (view);
+ handled = TRUE;
+ }
+ break;
+
+ case GDK_KEY_Left:
+ expand_or_collapse_selected_item (view, TRUE);
+ handled = TRUE;
+ break;
+
+ case GDK_KEY_Right:
+ expand_or_collapse_selected_item (view, FALSE);
+ handled = TRUE;
+ break;
+
+ default:
+ handled = FALSE;
+ break;
+ }
+
+ /* Chain up */
+ if (!handled)
+ return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->key_press_event (widget, event);
+
+ return TRUE;
+}
+
+static void
+fill_expand_state (GeditFileBrowserView *view,
+ GtkTreeIter *iter)
+{
+ GtkTreePath *path;
+ GtkTreeIter child;
+
+ if (!gtk_tree_model_iter_has_child (view->priv->model, iter))
+ return;
+
+ path = gtk_tree_model_get_path (view->priv->model, iter);
+
+ if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), path))
+ {
+ GFile *location;
+
+ gtk_tree_model_get (view->priv->model,
+ iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ add_expand_state (view, location);
+
+ if (location)
+ g_object_unref (location);
+ }
+
+ if (gtk_tree_model_iter_children (view->priv->model, &child, iter))
+ {
+ do
+ {
+ fill_expand_state (view, &child);
+ }
+ while (gtk_tree_model_iter_next (view->priv->model, &child));
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+uninstall_restore_signals (GeditFileBrowserView *tree_view,
+ GtkTreeModel *model)
+{
+ g_signal_handlers_disconnect_by_func (model, on_begin_refresh, tree_view);
+ g_signal_handlers_disconnect_by_func (model, on_end_refresh, tree_view);
+ g_signal_handlers_disconnect_by_func (model, on_unload, tree_view);
+ g_signal_handlers_disconnect_by_func (model, on_row_inserted, tree_view);
+}
+
+static void
+install_restore_signals (GeditFileBrowserView *tree_view,
+ GtkTreeModel *model)
+{
+ g_signal_connect (model, "begin-refresh", G_CALLBACK (on_begin_refresh), tree_view);
+ g_signal_connect (model, "end-refresh", G_CALLBACK (on_end_refresh), tree_view);
+ g_signal_connect (model, "unload", G_CALLBACK (on_unload), tree_view);
+ g_signal_connect_after (model, "row-inserted", G_CALLBACK (on_row_inserted), tree_view);
+}
+
+static void
+set_restore_expand_state (GeditFileBrowserView *view,
+ gboolean state)
+{
+ if (state == view->priv->restore_expand_state)
+ return;
+
+ if (view->priv->expand_state)
+ {
+ g_hash_table_destroy (view->priv->expand_state);
+ view->priv->expand_state = NULL;
+ }
+
+ if (state)
+ {
+ view->priv->expand_state = g_hash_table_new_full (g_file_hash,
+ (GEqualFunc)g_file_equal,
+ g_object_unref,
+ NULL);
+
+ if (view->priv->model && GEDIT_IS_FILE_BROWSER_STORE (view->priv->model))
+ {
+ fill_expand_state (view, NULL);
+ install_restore_signals (view, view->priv->model);
+ }
+ }
+ else if (view->priv->model && GEDIT_IS_FILE_BROWSER_STORE (view->priv->model))
+ {
+ uninstall_restore_signals (view, view->priv->model);
+ }
+
+ view->priv->restore_expand_state = state;
+}
+
+static void
+get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserView *obj = GEDIT_FILE_BROWSER_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_CLICK_POLICY:
+ g_value_set_enum (value, obj->priv->click_policy);
+ break;
+ case PROP_RESTORE_EXPAND_STATE:
+ g_value_set_boolean (value, obj->priv->restore_expand_state);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserView *obj = GEDIT_FILE_BROWSER_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_CLICK_POLICY:
+ set_click_policy_property (obj, g_value_get_enum (value));
+ break;
+ case PROP_RESTORE_EXPAND_STATE:
+ set_restore_expand_state (obj, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_view_class_init (GeditFileBrowserViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkTreeViewClass *tree_view_class = GTK_TREE_VIEW_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = gedit_file_browser_view_finalize;
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+
+ /* Event handlers */
+ widget_class->motion_notify_event = motion_notify_event;
+ widget_class->enter_notify_event = enter_notify_event;
+ widget_class->leave_notify_event = leave_notify_event;
+ widget_class->button_press_event = button_press_event;
+ widget_class->button_release_event = button_release_event;
+ widget_class->drag_begin = drag_begin;
+ widget_class->key_press_event = key_press_event;
+
+ /* Tree view handlers */
+ tree_view_class->row_activated = row_activated;
+ tree_view_class->row_expanded = row_expanded;
+ tree_view_class->row_collapsed = row_collapsed;
+
+ /* Default handlers */
+ klass->directory_activated = directory_activated;
+
+ g_object_class_install_property (object_class, PROP_CLICK_POLICY,
+ g_param_spec_enum ("click-policy",
+ "Click Policy",
+ "The click policy",
+ GEDIT_TYPE_FILE_BROWSER_VIEW_CLICK_POLICY,
+ GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_RESTORE_EXPAND_STATE,
+ g_param_spec_boolean ("restore-expand-state",
+ "Restore Expand State",
+ "Restore expanded state of loaded directories",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ signals[ERROR] =
+ g_signal_new ("error",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserViewClass, error),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+ signals[FILE_ACTIVATED] =
+ g_signal_new ("file-activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserViewClass, file_activated),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER);
+ signals[DIRECTORY_ACTIVATED] =
+ g_signal_new ("directory-activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserViewClass, directory_activated),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER);
+ signals[BOOKMARK_ACTIVATED] =
+ g_signal_new ("bookmark-activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserViewClass, bookmark_activated),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER);
+}
+
+static void
+gedit_file_browser_view_class_finalize (GeditFileBrowserViewClass *klass)
+{
+}
+
+static void
+cell_data_cb (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GeditFileBrowserView *obj)
+{
+ GtkTreePath *path = gtk_tree_model_get_path (tree_model, iter);
+ PangoUnderline underline = PANGO_UNDERLINE_NONE;
+ gboolean editable = FALSE;
+
+ if (obj->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE &&
+ obj->priv->hover_path != NULL &&
+ gtk_tree_path_compare (path, obj->priv->hover_path) == 0)
+ {
+ underline = PANGO_UNDERLINE_SINGLE;
+ }
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (tree_model) &&
+ obj->priv->editable != NULL &&
+ gtk_tree_row_reference_valid (obj->priv->editable))
+ {
+ GtkTreePath *edpath = gtk_tree_row_reference_get_path (obj->priv->editable);
+
+ editable = edpath && gtk_tree_path_compare (path, edpath) == 0;
+
+ gtk_tree_path_free (edpath);
+ }
+
+ gtk_tree_path_free (path);
+ g_object_set (cell, "editable", editable, "underline", underline, NULL);
+}
+
+static void
+icon_renderer_cb (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GeditFileBrowserView *obj)
+{
+ GdkPixbuf *pixbuf;
+ gchar *icon_name;
+ gboolean set_pixbuf = FALSE;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_ICON_NAME, &icon_name,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_ICON, &pixbuf,
+ -1);
+
+ if (pixbuf != NULL && (GEDIT_IS_FILE_BROWSER_STORE (tree_model) || icon_name == NULL))
+ set_pixbuf = TRUE;
+
+ if (set_pixbuf)
+ g_object_set (cell, "pixbuf", pixbuf, NULL);
+ else
+ g_object_set (cell, "icon-name", icon_name, NULL);
+
+ g_clear_object (&pixbuf);
+ g_free (icon_name);
+}
+
+static void
+gedit_file_browser_view_init (GeditFileBrowserView *obj)
+{
+ obj->priv = gedit_file_browser_view_get_instance_private (obj);
+
+ obj->priv->column = gtk_tree_view_column_new ();
+
+ obj->priv->pixbuf_renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (obj->priv->column,
+ obj->priv->pixbuf_renderer,
+ FALSE);
+
+ gtk_tree_view_column_set_cell_data_func (obj->priv->column,
+ obj->priv->pixbuf_renderer,
+ (GtkTreeCellDataFunc)icon_renderer_cb,
+ obj,
+ NULL);
+
+ obj->priv->text_renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (obj->priv->column,
+ obj->priv->text_renderer, TRUE);
+ gtk_tree_view_column_add_attribute (obj->priv->column,
+ obj->priv->text_renderer,
+ "markup",
+ GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP);
+
+ g_signal_connect (obj->priv->text_renderer, "edited",
+ G_CALLBACK (on_cell_edited), obj);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (obj),
+ obj->priv->column);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (obj), FALSE);
+
+ gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (obj),
+ GDK_BUTTON1_MASK,
+ drag_source_targets,
+ G_N_ELEMENTS (drag_source_targets),
+ GDK_ACTION_COPY);
+}
+
+static gboolean
+bookmarks_separator_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ guint flags;
+
+ gtk_tree_model_get (model,
+ iter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ return (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR);
+}
+
+/* Public */
+GtkWidget *
+gedit_file_browser_view_new (void)
+{
+ GeditFileBrowserView *obj = GEDIT_FILE_BROWSER_VIEW (g_object_new (GEDIT_TYPE_FILE_BROWSER_VIEW, NULL));
+
+ return GTK_WIDGET (obj);
+}
+
+void
+gedit_file_browser_view_set_model (GeditFileBrowserView *tree_view,
+ GtkTreeModel *model)
+{
+ GtkTreeSelection *selection;
+ gint search_column;
+
+ if (tree_view->priv->model == model)
+ return;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ if (GEDIT_IS_FILE_BOOKMARKS_STORE (model))
+ {
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+ gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (tree_view), bookmarks_separator_func, NULL, NULL);
+ gtk_tree_view_column_set_cell_data_func (tree_view->priv->column,
+ tree_view->priv->text_renderer,
+ (GtkTreeCellDataFunc)cell_data_cb,
+ tree_view, NULL);
+ search_column = GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME;
+ }
+ else
+ {
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (tree_view), NULL, NULL, NULL);
+ gtk_tree_view_column_set_cell_data_func (tree_view->priv->column,
+ tree_view->priv->text_renderer,
+ (GtkTreeCellDataFunc)cell_data_cb,
+ tree_view, NULL);
+ search_column = GEDIT_FILE_BROWSER_STORE_COLUMN_NAME;
+
+ if (tree_view->priv->restore_expand_state)
+ install_restore_signals (tree_view, model);
+
+ }
+
+ if (tree_view->priv->hover_path != NULL)
+ {
+ gtk_tree_path_free (tree_view->priv->hover_path);
+ tree_view->priv->hover_path = NULL;
+ }
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (tree_view->priv->model) &&
+ tree_view->priv->restore_expand_state)
+ {
+ uninstall_restore_signals (tree_view, tree_view->priv->model);
+ }
+
+ tree_view->priv->model = model;
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (tree_view), search_column);
+}
+
+void
+gedit_file_browser_view_start_rename (GeditFileBrowserView *tree_view,
+ GtkTreeIter *iter)
+{
+ gchar *name;
+ gchar *markup;
+ guint flags;
+ GValue name_escaped = G_VALUE_INIT;
+ GtkTreeRowReference *rowref;
+ GtkTreePath *path;
+
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_VIEW (tree_view));
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_view->priv->model));
+ g_return_if_fail (iter != NULL);
+
+ gtk_tree_model_get (tree_view->priv->model,
+ iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_NAME, &name,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP, &markup,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!(FILE_IS_DIR (flags) || !FILE_IS_DUMMY (flags)))
+ {
+ g_free (name);
+ g_free (markup);
+ return;
+ }
+
+ /* Restore the markup to the original
+ * name, a plugin might have changed the markup.
+ */
+ g_value_init (&name_escaped, G_TYPE_STRING);
+ g_value_take_string (&name_escaped, g_markup_escape_text (name, -1));
+ gedit_file_browser_store_set_value (GEDIT_FILE_BROWSER_STORE (tree_view->priv->model),
+ iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP, &name_escaped);
+
+ path = gtk_tree_model_get_path (tree_view->priv->model, iter);
+ rowref = gtk_tree_row_reference_new (tree_view->priv->model, path);
+
+ /* Start editing */
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+
+ if (gtk_tree_path_up (path))
+ gtk_tree_view_expand_to_path (GTK_TREE_VIEW (tree_view), path);
+
+ gtk_tree_path_free (path);
+
+ tree_view->priv->orig_markup = markup;
+ tree_view->priv->editable = rowref;
+
+ /* grab focus on the text cell which is editable */
+ gtk_tree_view_column_focus_cell (tree_view->priv->column, tree_view->priv->text_renderer);
+
+ path = gtk_tree_row_reference_get_path (tree_view->priv->editable),
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), path, tree_view->priv->column, TRUE);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view),
+ path, tree_view->priv->column,
+ FALSE, 0.0, 0.0);
+
+ gtk_tree_path_free (path);
+ g_value_unset (&name_escaped);
+ g_free (name);
+}
+
+void
+gedit_file_browser_view_set_click_policy (GeditFileBrowserView *tree_view,
+ GeditFileBrowserViewClickPolicy policy)
+{
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_VIEW (tree_view));
+
+ set_click_policy_property (tree_view, policy);
+
+ g_object_notify (G_OBJECT (tree_view), "click-policy");
+}
+
+void
+gedit_file_browser_view_set_restore_expand_state (GeditFileBrowserView *tree_view,
+ gboolean restore_expand_state)
+{
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_VIEW (tree_view));
+
+ set_restore_expand_state (tree_view, restore_expand_state);
+ g_object_notify (G_OBJECT (tree_view), "restore-expand-state");
+}
+
+/* Signal handlers */
+static void
+on_cell_edited (GtkCellRendererText *cell,
+ gchar *path,
+ gchar *new_text,
+ GeditFileBrowserView *tree_view)
+{
+ GtkTreePath *treepath = gtk_tree_path_new_from_string (path);
+ GtkTreeIter iter;
+ gboolean ret;
+ GValue orig_markup = G_VALUE_INIT;
+ GError *error = NULL;
+
+ ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model), &iter, treepath);
+ gtk_tree_path_free (treepath);
+
+ if (ret)
+ {
+ /* Restore the original markup */
+ g_value_init (&orig_markup, G_TYPE_STRING);
+ g_value_set_string (&orig_markup, tree_view->priv->orig_markup);
+ gedit_file_browser_store_set_value (GEDIT_FILE_BROWSER_STORE (tree_view->priv->model), &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_MARKUP, &orig_markup);
+
+ if (new_text != NULL && *new_text != '\0' &&
+ gedit_file_browser_store_rename (GEDIT_FILE_BROWSER_STORE (tree_view->priv->model),
+ &iter,
+ new_text,
+ &error))
+ {
+ treepath = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_view->priv->model), &iter);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view),
+ treepath, NULL,
+ FALSE, 0.0, 0.0);
+ gtk_tree_path_free (treepath);
+ }
+ else if (error)
+ {
+ g_signal_emit (tree_view, signals[ERROR], 0, error->code, error->message);
+ g_error_free (error);
+ }
+
+ g_value_unset (&orig_markup);
+ }
+
+ g_free (tree_view->priv->orig_markup);
+ tree_view->priv->orig_markup = NULL;
+
+ gtk_tree_row_reference_free (tree_view->priv->editable);
+ tree_view->priv->editable = NULL;
+}
+
+static void
+on_begin_refresh (GeditFileBrowserStore *model,
+ GeditFileBrowserView *view)
+{
+ /* Store the refresh state, so we can handle unloading of nodes while
+ refreshing properly */
+ view->priv->is_refresh = TRUE;
+}
+
+static void
+on_end_refresh (GeditFileBrowserStore *model,
+ GeditFileBrowserView *view)
+{
+ /* Store the refresh state, so we can handle unloading of nodes while
+ refreshing properly */
+ view->priv->is_refresh = FALSE;
+}
+
+static void
+on_unload (GeditFileBrowserStore *model,
+ GFile *location,
+ GeditFileBrowserView *view)
+{
+ /* Don't remove the expand state if we are refreshing */
+ if (!view->priv->restore_expand_state || view->priv->is_refresh)
+ return;
+
+ remove_expand_state (view, location);
+}
+
+static void
+restore_expand_state (GeditFileBrowserView *view,
+ GeditFileBrowserStore *model,
+ GtkTreeIter *iter)
+{
+ GFile *location;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (model),
+ iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ if (location)
+ {
+ GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
+
+ if (g_hash_table_lookup (view->priv->expand_state, location))
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (view), path, FALSE);
+
+ gtk_tree_path_free (path);
+ g_object_unref (location);
+ }
+}
+
+static void
+on_row_inserted (GeditFileBrowserStore *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GeditFileBrowserView *view)
+{
+ GtkTreeIter parent;
+ GtkTreePath *copy;
+
+ if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (model), iter))
+ restore_expand_state (view, model, iter);
+
+ copy = gtk_tree_path_copy (path);
+
+ if (gtk_tree_path_up (copy) &&
+ (gtk_tree_path_get_depth (copy) != 0) &&
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &parent, copy))
+ {
+ restore_expand_state (view, model, &parent);
+ }
+
+ gtk_tree_path_free (copy);
+}
+
+void
+_gedit_file_browser_view_register_type (GTypeModule *type_module)
+{
+ gedit_file_browser_view_register_type (type_module);
+}
+
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-view.h b/plugins/filebrowser/gedit-file-browser-view.h
new file mode 100644
index 0000000..8c2efc8
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-view.h
@@ -0,0 +1,84 @@
+/*
+ * gedit-file-browser-view.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GEDIT_FILE_BROWSER_VIEW_H
+#define GEDIT_FILE_BROWSER_VIEW_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+#define GEDIT_TYPE_FILE_BROWSER_VIEW (gedit_file_browser_view_get_type ())
+#define GEDIT_FILE_BROWSER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserView))
+#define GEDIT_FILE_BROWSER_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserView const))
+#define GEDIT_FILE_BROWSER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserViewClass))
+#define GEDIT_IS_FILE_BROWSER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FILE_BROWSER_VIEW))
+#define GEDIT_IS_FILE_BROWSER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FILE_BROWSER_VIEW))
+#define GEDIT_FILE_BROWSER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserViewClass))
+
+typedef struct _GeditFileBrowserView GeditFileBrowserView;
+typedef struct _GeditFileBrowserViewClass GeditFileBrowserViewClass;
+typedef struct _GeditFileBrowserViewPrivate GeditFileBrowserViewPrivate;
+
+typedef enum {
+ GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE,
+ GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE
+} GeditFileBrowserViewClickPolicy;
+
+struct _GeditFileBrowserView
+{
+ GtkTreeView parent;
+
+ GeditFileBrowserViewPrivate *priv;
+};
+
+struct _GeditFileBrowserViewClass
+{
+ GtkTreeViewClass parent_class;
+
+ /* Signals */
+ void (* error) (GeditFileBrowserView *filetree,
+ guint code,
+ gchar const *message);
+ void (* file_activated) (GeditFileBrowserView *filetree,
+ GtkTreeIter *iter);
+ void (* directory_activated) (GeditFileBrowserView *filetree,
+ GtkTreeIter *iter);
+ void (* bookmark_activated) (GeditFileBrowserView *filetree,
+ GtkTreeIter *iter);
+};
+
+GType gedit_file_browser_view_get_type (void) G_GNUC_CONST;
+
+GtkWidget *gedit_file_browser_view_new (void);
+void gedit_file_browser_view_set_model (GeditFileBrowserView *tree_view,
+ GtkTreeModel *model);
+void gedit_file_browser_view_start_rename (GeditFileBrowserView *tree_view,
+ GtkTreeIter *iter);
+void gedit_file_browser_view_set_click_policy (GeditFileBrowserView *tree_view,
+ GeditFileBrowserViewClickPolicy policy);
+void gedit_file_browser_view_set_restore_expand_state (GeditFileBrowserView *tree_view,
+ gboolean restore_expand_state);
+
+void _gedit_file_browser_view_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_VIEW_H */
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-widget.c b/plugins/filebrowser/gedit-file-browser-widget.c
new file mode 100644
index 0000000..00585b4
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-widget.c
@@ -0,0 +1,3152 @@
+/*
+ * gedit-file-browser-widget.c - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gedit/gedit-utils.h>
+
+#include "gedit-file-browser-utils.h"
+#include "gedit-file-browser-error.h"
+#include "gedit-file-browser-widget.h"
+#include "gedit-file-browser-view.h"
+#include "gedit-file-browser-store.h"
+#include "gedit-file-bookmarks-store.h"
+#include "gedit-file-browser-enum-types.h"
+
+#define LOCATION_DATA_KEY "gedit-file-browser-widget-location"
+
+enum
+{
+ BOOKMARKS_ID,
+ SEPARATOR_CUSTOM_ID,
+ SEPARATOR_ID,
+ PATH_ID,
+ NUM_DEFAULT_IDS
+};
+
+enum
+{
+ COLUMN_ICON,
+ COLUMN_ICON_NAME,
+ COLUMN_NAME,
+ COLUMN_FILE,
+ COLUMN_ID,
+ N_COLUMNS
+};
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ PROP_FILTER_PATTERN,
+};
+
+/* Signals */
+enum
+{
+ LOCATION_ACTIVATED,
+ ERROR,
+ CONFIRM_DELETE,
+ CONFIRM_NO_TRASH,
+ OPEN_IN_TERMINAL,
+ SET_ACTIVE_ROOT,
+ NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS] = { 0 };
+
+typedef struct _SignalNode
+{
+ GObject *object;
+ gulong id;
+} SignalNode;
+
+typedef struct
+{
+ gulong id;
+ GeditFileBrowserWidgetFilterFunc func;
+ gpointer user_data;
+ GDestroyNotify destroy_notify;
+} FilterFunc;
+
+typedef struct
+{
+ GFile *root;
+ GFile *virtual_root;
+} Location;
+
+typedef struct
+{
+ gchar *name;
+ gchar *icon_name;
+ GdkPixbuf *icon;
+} NameIcon;
+
+struct _GeditFileBrowserWidgetPrivate
+{
+ GeditFileBrowserView *treeview;
+ GeditFileBrowserStore *file_store;
+ GeditFileBookmarksStore *bookmarks_store;
+
+ GHashTable *bookmarks_hash;
+
+ GMenuModel *dir_menu;
+ GMenuModel *bookmarks_menu;
+
+ GtkWidget *previous_button;
+ GtkWidget *next_button;
+
+ GtkWidget *locations_button;
+ GtkWidget *locations_popover;
+ GtkWidget *locations_treeview;
+ GtkTreeViewColumn *treeview_icon_column;
+ GtkCellRenderer *treeview_icon_renderer;
+ GtkTreeSelection *locations_treeview_selection;
+ GtkWidget *locations_button_arrow;
+ GtkWidget *locations_cellview;
+ GtkListStore *locations_model;
+
+ GtkWidget *location_entry;
+
+ GtkWidget *filter_entry_revealer;
+ GtkWidget *filter_entry;
+
+ GSimpleActionGroup *action_group;
+
+ GSList *signal_pool;
+
+ GSList *filter_funcs;
+ gulong filter_id;
+ gulong glob_filter_id;
+ GPatternSpec *filter_pattern;
+ gchar *filter_pattern_str;
+
+ GList *locations;
+ GList *current_location;
+ gboolean changing_location;
+ GtkWidget *location_previous_menu;
+ GtkWidget *location_next_menu;
+ GtkWidget *current_location_menu_item;
+
+ GCancellable *cancellable;
+
+ GdkCursor *busy_cursor;
+};
+
+static void on_model_set (GObject *gobject,
+ GParamSpec *arg1,
+ GeditFileBrowserWidget *obj);
+static void on_treeview_error (GeditFileBrowserView *tree_view,
+ guint code,
+ gchar *message,
+ GeditFileBrowserWidget *obj);
+static void on_file_store_error (GeditFileBrowserStore *store,
+ guint code,
+ gchar *message,
+ GeditFileBrowserWidget *obj);
+static gboolean on_file_store_no_trash (GeditFileBrowserStore *store,
+ GList *files,
+ GeditFileBrowserWidget *obj);
+static gboolean on_location_button_press_event (GtkWidget *button,
+ GdkEventButton *event,
+ GeditFileBrowserWidget *obj);
+static void on_location_entry_activate (GtkEntry *entry,
+ GeditFileBrowserWidget *obj);
+static gboolean
+ on_location_entry_focus_out_event (GtkWidget *entry,
+ GdkEvent *event,
+ GeditFileBrowserWidget *obj);
+static gboolean
+ on_location_entry_key_press_event (GtkWidget *entry,
+ GdkEventKey *event,
+ GeditFileBrowserWidget *obj);
+static gboolean on_treeview_popup_menu (GeditFileBrowserView *treeview,
+ GeditFileBrowserWidget *obj);
+static gboolean on_treeview_button_press_event (GeditFileBrowserView *treeview,
+ GdkEventButton *event,
+ GeditFileBrowserWidget *obj);
+static gboolean on_treeview_key_press_event (GeditFileBrowserView *treeview,
+ GdkEventKey *event,
+ GeditFileBrowserWidget *obj);
+static void on_selection_changed (GtkTreeSelection *selection,
+ GeditFileBrowserWidget *obj);
+
+static void on_virtual_root_changed (GeditFileBrowserStore *model,
+ GParamSpec *param,
+ GeditFileBrowserWidget *obj);
+
+static gboolean on_entry_filter_activate (GeditFileBrowserWidget *obj);
+static void on_location_jump_activate (GtkMenuItem *item,
+ GeditFileBrowserWidget *obj);
+static void on_bookmarks_row_changed (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GeditFileBrowserWidget *obj);
+static void on_bookmarks_row_deleted (GtkTreeModel *model,
+ GtkTreePath *path,
+ GeditFileBrowserWidget *obj);
+static void on_filter_mode_changed (GeditFileBrowserStore *model,
+ GParamSpec *param,
+ GeditFileBrowserWidget *obj);
+static void previous_location_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void next_location_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void up_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void home_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void new_folder_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void open_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void new_file_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void rename_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void delete_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void move_to_trash_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void refresh_view_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void view_folder_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void change_show_hidden_state (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data);
+static void change_show_binary_state (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data);
+static void change_show_match_filename (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data);
+static void open_in_terminal_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void set_active_root_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+static void on_locations_treeview_selection_changed (GtkTreeSelection *treeselection,
+ GeditFileBrowserWidget *obj);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditFileBrowserWidget,
+ gedit_file_browser_widget,
+ GTK_TYPE_GRID,
+ 0,
+ G_ADD_PRIVATE_DYNAMIC (GeditFileBrowserWidget))
+
+static void
+free_name_icon (gpointer data)
+{
+ NameIcon *item = (NameIcon *)(data);
+
+ if (item == NULL)
+ return;
+
+ g_free (item->icon_name);
+ g_free (item->name);
+
+ if (item->icon)
+ g_object_unref (item->icon);
+
+ g_slice_free (NameIcon, item);
+}
+
+static FilterFunc *
+filter_func_new (GeditFileBrowserWidget *obj,
+ GeditFileBrowserWidgetFilterFunc func,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ FilterFunc *result = g_slice_new (FilterFunc);
+
+ result->id = ++obj->priv->filter_id;
+ result->func = func;
+ result->user_data = user_data;
+ result->destroy_notify = notify;
+ return result;
+}
+
+static void
+location_free (Location *loc)
+{
+ if (loc->root)
+ g_object_unref (loc->root);
+
+ if (loc->virtual_root)
+ g_object_unref (loc->virtual_root);
+
+ g_slice_free (Location, loc);
+}
+
+static gboolean
+locations_find_by_id (GeditFileBrowserWidget *obj,
+ guint id,
+ GtkTreeIter *iter)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (obj->priv->locations_model);
+ guint checkid;
+
+ if (iter == NULL)
+ return FALSE;
+
+ if (gtk_tree_model_get_iter_first (model, iter))
+ {
+ do
+ {
+ gtk_tree_model_get (model,
+ iter,
+ COLUMN_ID, &checkid,
+ -1);
+
+ if (checkid == id)
+ return TRUE;
+ }
+ while (gtk_tree_model_iter_next (model, iter));
+ }
+
+ return FALSE;
+}
+
+static void
+cancel_async_operation (GeditFileBrowserWidget *widget)
+{
+ if (!widget->priv->cancellable)
+ return;
+
+ g_cancellable_cancel (widget->priv->cancellable);
+ g_object_unref (widget->priv->cancellable);
+
+ widget->priv->cancellable = NULL;
+}
+
+static void
+filter_func_free (FilterFunc *func)
+{
+ g_slice_free (FilterFunc, func);
+}
+
+static void
+gedit_file_browser_widget_finalize (GObject *object)
+{
+ GeditFileBrowserWidgetPrivate *priv = GEDIT_FILE_BROWSER_WIDGET (object)->priv;
+
+ g_free (priv->filter_pattern_str);
+
+ G_OBJECT_CLASS (gedit_file_browser_widget_parent_class)->finalize (object);
+}
+
+static void
+clear_signals (GeditFileBrowserWidget *obj)
+{
+ GSList *item = obj->priv->signal_pool;
+ SignalNode *node;
+
+ while (item != NULL)
+ {
+ node = (SignalNode *) (item->data);
+ item = g_slist_delete_link (item, item);
+
+ g_signal_handler_disconnect (node->object, node->id);
+ g_slice_free (SignalNode, node);
+ }
+
+ obj->priv->signal_pool = NULL;
+}
+
+static void
+gedit_file_browser_widget_dispose (GObject *object)
+{
+ GeditFileBrowserWidget *obj = GEDIT_FILE_BROWSER_WIDGET (object);
+ GeditFileBrowserWidgetPrivate *priv = obj->priv;
+
+ clear_signals (obj);
+ g_clear_object (&priv->file_store);
+ g_clear_object (&priv->bookmarks_store);
+
+ g_slist_free_full (priv->filter_funcs, (GDestroyNotify)filter_func_free);
+ g_list_free_full (priv->locations, (GDestroyNotify)location_free);
+
+ if (priv->bookmarks_hash != NULL)
+ {
+ g_hash_table_unref (priv->bookmarks_hash);
+ priv->bookmarks_hash = NULL;
+ }
+
+ cancel_async_operation (obj);
+
+ g_clear_object (&obj->priv->current_location_menu_item);
+ g_clear_object (&priv->busy_cursor);
+ g_clear_object (&priv->dir_menu);
+ g_clear_object (&priv->bookmarks_menu);
+
+ G_OBJECT_CLASS (gedit_file_browser_widget_parent_class)->dispose (object);
+}
+
+static void
+gedit_file_browser_widget_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserWidget *obj = GEDIT_FILE_BROWSER_WIDGET (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILTER_PATTERN:
+ g_value_set_string (value, obj->priv->filter_pattern_str);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_widget_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserWidget *obj = GEDIT_FILE_BROWSER_WIDGET (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILTER_PATTERN:
+ gedit_file_browser_widget_set_filter_pattern (obj,
+ g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_widget_class_init (GeditFileBrowserWidgetClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = gedit_file_browser_widget_finalize;
+ object_class->dispose = gedit_file_browser_widget_dispose;
+
+ object_class->get_property = gedit_file_browser_widget_get_property;
+ object_class->set_property = gedit_file_browser_widget_set_property;
+
+ g_object_class_install_property (object_class, PROP_FILTER_PATTERN,
+ g_param_spec_string ("filter-pattern",
+ "Filter Pattern",
+ "The filter pattern",
+ "",
+ G_PARAM_READWRITE));
+
+ signals[LOCATION_ACTIVATED] =
+ g_signal_new ("location-activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, location_activated),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_FILE);
+
+ signals[ERROR] =
+ g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, error),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+
+ signals[CONFIRM_DELETE] =
+ g_signal_new ("confirm-delete", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, confirm_delete),
+ g_signal_accumulator_true_handled, NULL, NULL,
+ G_TYPE_BOOLEAN, 2, G_TYPE_OBJECT, G_TYPE_POINTER);
+
+ signals[CONFIRM_NO_TRASH] =
+ g_signal_new ("confirm-no-trash", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, confirm_no_trash),
+ g_signal_accumulator_true_handled, NULL, NULL,
+ G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
+
+ signals[OPEN_IN_TERMINAL] =
+ g_signal_new ("open-in-terminal",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, open_in_terminal),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_FILE);
+
+ signals[SET_ACTIVE_ROOT] =
+ g_signal_new ("set-active-root",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, set_active_root),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
+ /* Bind class to template */
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/gedit/plugins/file-browser/ui/gedit-file-browser-widget.ui");
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, previous_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, next_button);
+
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, locations_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, locations_popover);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, locations_treeview);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, locations_treeview_selection);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, treeview_icon_column);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, treeview_icon_renderer);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, locations_cellview);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, locations_button_arrow);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, locations_model);
+
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, location_entry);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, treeview);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, filter_entry_revealer);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, filter_entry);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, location_previous_menu);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditFileBrowserWidget, location_next_menu);
+}
+
+static void
+gedit_file_browser_widget_class_finalize (GeditFileBrowserWidgetClass *klass)
+{
+}
+
+static void
+add_signal (GeditFileBrowserWidget *obj,
+ gpointer object,
+ gulong id)
+{
+ SignalNode *node = g_slice_new (SignalNode);
+
+ node->object = G_OBJECT (object);
+ node->id = id;
+
+ obj->priv->signal_pool = g_slist_prepend (obj->priv->signal_pool, node);
+}
+
+static gboolean
+separator_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ guint id;
+
+ gtk_tree_model_get (model, iter, COLUMN_ID, &id, -1);
+
+ return (id == SEPARATOR_ID);
+}
+
+static gboolean
+get_from_bookmark_file (GeditFileBrowserWidget *obj,
+ GFile *file,
+ gchar **name,
+ gchar **icon_name,
+ GdkPixbuf **icon)
+{
+ NameIcon *item = (NameIcon *)g_hash_table_lookup (obj->priv->bookmarks_hash, file);
+
+ if (item == NULL)
+ return FALSE;
+
+ *name = g_strdup (item->name);
+ *icon_name = g_strdup (item->icon_name);
+
+ if (icon != NULL && item->icon != NULL)
+ {
+ *icon = g_object_ref (item->icon);
+ }
+
+ return TRUE;
+}
+
+static void
+insert_path_item (GeditFileBrowserWidget *obj,
+ GFile *file,
+ GtkTreeIter *after,
+ GtkTreeIter *iter)
+{
+ gchar *unescape = NULL;
+ gchar *icon_name = NULL;
+ GdkPixbuf *icon = NULL;
+
+ /* Try to get the icon and name from the bookmarks hash */
+ if (!get_from_bookmark_file (obj, file, &unescape, &icon_name, &icon))
+ {
+ /* It's not a bookmark, fetch the name and the icon ourselves */
+ unescape = gedit_file_browser_utils_file_basename (file);
+
+ /* Get the icon */
+ icon_name = gedit_file_browser_utils_symbolic_icon_name_from_file (file);
+ }
+
+ gtk_list_store_insert_after (obj->priv->locations_model, iter, after);
+
+ gtk_list_store_set (obj->priv->locations_model,
+ iter,
+ COLUMN_ICON, icon,
+ COLUMN_ICON_NAME, icon_name,
+ COLUMN_NAME, unescape,
+ COLUMN_FILE, file,
+ COLUMN_ID, PATH_ID,
+ -1);
+
+ if (icon)
+ g_object_unref (icon);
+
+ g_free (icon_name);
+ g_free (unescape);
+}
+
+static void
+insert_separator_item (GeditFileBrowserWidget *obj)
+{
+ GtkTreeIter iter;
+
+ gtk_list_store_insert (obj->priv->locations_model, &iter, 1);
+ gtk_list_store_set (obj->priv->locations_model, &iter,
+ COLUMN_ICON, NULL,
+ COLUMN_ICON_NAME, NULL,
+ COLUMN_NAME, NULL,
+ COLUMN_ID, SEPARATOR_ID, -1);
+}
+
+static void
+insert_location_path (GeditFileBrowserWidget *obj)
+{
+ GeditFileBrowserWidgetPrivate *priv = obj->priv;
+ Location *loc;
+ GFile *current = NULL;
+ GFile *tmp;
+ GtkTreeIter separator;
+ GtkTreeIter iter;
+
+ if (!priv->current_location)
+ {
+ g_message ("insert_location_path: no current location");
+ return;
+ }
+
+ loc = (Location *)(priv->current_location->data);
+
+ current = loc->virtual_root;
+ locations_find_by_id (obj, SEPARATOR_ID, &separator);
+
+ while (current != NULL)
+ {
+ insert_path_item (obj, current, &separator, &iter);
+
+ if (current == loc->virtual_root)
+ {
+
+ g_signal_handlers_block_by_func (priv->locations_treeview,
+ on_locations_treeview_selection_changed,
+ obj);
+
+ gtk_tree_selection_select_iter (priv->locations_treeview_selection, &iter);
+
+ g_signal_handlers_unblock_by_func (priv->locations_treeview,
+ on_locations_treeview_selection_changed,
+ obj);
+ }
+
+ if (g_file_equal (current, loc->root) ||
+ !g_file_has_parent (current, NULL))
+ {
+ if (current != loc->virtual_root)
+ g_object_unref (current);
+ break;
+ }
+
+ tmp = g_file_get_parent (current);
+
+ if (current != loc->virtual_root)
+ g_object_unref (current);
+
+ current = tmp;
+ }
+}
+
+static void
+remove_path_items (GeditFileBrowserWidget *obj)
+{
+ GtkTreeIter iter;
+
+ while (locations_find_by_id (obj, PATH_ID, &iter))
+ {
+ gtk_list_store_remove (obj->priv->locations_model, &iter);
+ }
+}
+
+static void
+check_current_item (GeditFileBrowserWidget *obj,
+ gboolean show_path)
+{
+ GtkTreeIter separator;
+ gboolean has_sep;
+
+ remove_path_items (obj);
+ has_sep = locations_find_by_id (obj, SEPARATOR_ID, &separator);
+
+ if (show_path)
+ {
+ if (!has_sep)
+ insert_separator_item (obj);
+
+ insert_location_path (obj);
+ }
+ else if (has_sep)
+ {
+ gtk_list_store_remove (obj->priv->locations_model, &separator);
+ }
+}
+
+static void
+fill_locations_model (GeditFileBrowserWidget *obj)
+{
+ GeditFileBrowserWidgetPrivate *priv = obj->priv;
+ GtkTreeIter iter;
+
+ gtk_list_store_append (priv->locations_model, &iter);
+ gtk_list_store_set (priv->locations_model,
+ &iter,
+ COLUMN_ICON, NULL,
+ COLUMN_ICON_NAME, "user-bookmarks-symbolic",
+ COLUMN_NAME, _("Bookmarks"),
+ COLUMN_ID, BOOKMARKS_ID, -1);
+
+ gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (priv->locations_treeview),
+ separator_func,
+ obj,
+ NULL);
+
+ gtk_tree_selection_select_iter (priv->locations_treeview_selection, &iter);
+
+ on_locations_treeview_selection_changed (priv->locations_treeview_selection, obj);
+ gedit_file_browser_widget_show_bookmarks (obj);
+}
+
+static gboolean
+filter_real (GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ GeditFileBrowserWidget *obj)
+{
+ GSList *item;
+
+ for (item = obj->priv->filter_funcs; item; item = item->next)
+ {
+ FilterFunc *func = (FilterFunc *)(item->data);
+
+ if (!func->func (obj, model, iter, func->user_data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+add_bookmark_hash (GeditFileBrowserWidget *obj,
+ GtkTreeIter *iter)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (obj->priv->bookmarks_store);
+ GdkPixbuf *pixbuf;
+ gchar *name;
+ gchar *icon_name;
+ GFile *location;
+ NameIcon *item;
+
+ if (!(location = gedit_file_bookmarks_store_get_location (obj->priv->bookmarks_store, iter)))
+ return;
+
+ gtk_tree_model_get (model,
+ iter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON, &pixbuf,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON_NAME, &icon_name,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, &name,
+ -1);
+
+ item = g_slice_new (NameIcon);
+ item->name = name;
+ item->icon_name = icon_name;
+ item->icon = pixbuf;
+
+ g_hash_table_insert (obj->priv->bookmarks_hash,
+ location,
+ item);
+}
+
+static void
+init_bookmarks_hash (GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (obj->priv->bookmarks_store);
+ GtkTreeIter iter;
+
+ if (!gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ do
+ {
+ add_bookmark_hash (obj, &iter);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+
+ g_signal_connect (obj->priv->bookmarks_store,
+ "row-changed",
+ G_CALLBACK (on_bookmarks_row_changed),
+ obj);
+
+ g_signal_connect (obj->priv->bookmarks_store,
+ "row-deleted",
+ G_CALLBACK (on_bookmarks_row_deleted),
+ obj);
+}
+
+static void
+on_begin_loading (GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ GeditFileBrowserWidget *obj)
+{
+ if (!GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview))))
+ return;
+
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (obj)),
+ obj->priv->busy_cursor);
+}
+
+static void
+on_end_loading (GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ GeditFileBrowserWidget *obj)
+{
+ if (!GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview))))
+ return;
+
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (obj)), NULL);
+}
+
+static void
+on_locations_treeview_row_activated (GtkTreeView *locations_treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ GeditFileBrowserWidget *obj)
+{
+ GeditFileBrowserWidgetPrivate *priv = obj->priv;
+ GtkTreeIter iter;
+ guint id = G_MAXUINT;
+ GFile *file;
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->locations_model), &iter, path))
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->locations_model), &iter, COLUMN_ID, &id, -1);
+ }
+
+ if (id == BOOKMARKS_ID)
+ {
+ gedit_file_browser_widget_show_bookmarks (obj);
+ }
+ else if (id == PATH_ID)
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->locations_model),
+ &iter,
+ COLUMN_FILE, &file,
+ -1);
+
+ gedit_file_browser_store_set_virtual_root_from_location (priv->file_store, file);
+
+ g_object_unref (file);
+ gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (priv->locations_cellview), path);
+ }
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->locations_button), FALSE);
+}
+
+static GActionEntry browser_entries[] = {
+ { "open", open_activated },
+ { "set_active_root", set_active_root_activated },
+ { "new_folder", new_folder_activated },
+ { "new_file", new_file_activated },
+ { "rename", rename_activated },
+ { "move_to_trash", move_to_trash_activated },
+ { "delete", delete_activated },
+ { "refresh_view", refresh_view_activated },
+ { "view_folder", view_folder_activated },
+ { "open_in_terminal", open_in_terminal_activated },
+ { "show_hidden", NULL, NULL, "false", change_show_hidden_state },
+ { "show_binary", NULL, NULL, "false", change_show_binary_state },
+ { "show_match_filename", NULL, NULL, "false", change_show_match_filename },
+ { "previous_location", previous_location_activated },
+ { "next_location", next_location_activated },
+ { "up", up_activated },
+ { "home", home_activated }
+};
+
+static void
+locations_icon_renderer_cb (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GeditFileBrowserWidget *obj)
+{
+ GdkPixbuf *pixbuf;
+ gchar *icon_name;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON_NAME, &icon_name,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON, &pixbuf,
+ -1);
+
+ if (icon_name != NULL)
+ g_object_set (cell, "icon-name", icon_name, NULL);
+ else
+ g_object_set (cell, "pixbuf", pixbuf, NULL);
+
+ g_clear_object (&pixbuf);
+ g_free (icon_name);
+}
+
+static void
+gedit_file_browser_widget_init (GeditFileBrowserWidget *obj)
+{
+ GtkBuilder *builder;
+ GdkDisplay *display;
+ GAction *action;
+ GError *error = NULL;
+
+ obj->priv = gedit_file_browser_widget_get_instance_private (obj);
+
+ obj->priv->filter_pattern_str = g_strdup ("");
+ obj->priv->bookmarks_hash = g_hash_table_new_full (g_file_hash,
+ (GEqualFunc)g_file_equal,
+ g_object_unref,
+ free_name_icon);
+
+ display = gtk_widget_get_display (GTK_WIDGET (obj));
+ obj->priv->busy_cursor = gdk_cursor_new_from_name (display, "progress");
+
+ builder = gtk_builder_new ();
+ if (!gtk_builder_add_from_resource (builder,
+ "/org/gnome/gedit/plugins/file-browser/ui/gedit-file-browser-menus.ui",
+ &error))
+ {
+ g_warning ("loading menu builder file: %s", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ obj->priv->dir_menu = G_MENU_MODEL (g_object_ref (gtk_builder_get_object (builder, "dir-menu")));
+ obj->priv->bookmarks_menu = G_MENU_MODEL (g_object_ref (gtk_builder_get_object (builder, "bookmarks-menu")));
+ }
+
+ g_object_unref (builder);
+
+ obj->priv->action_group = g_simple_action_group_new ();
+ g_action_map_add_action_entries (G_ACTION_MAP (obj->priv->action_group),
+ browser_entries,
+ G_N_ELEMENTS (browser_entries),
+ obj);
+
+ /* set initial sensitivity */
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "previous_location");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "next_location");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+
+ gtk_widget_insert_action_group (GTK_WIDGET (obj),
+ "browser",
+ G_ACTION_GROUP (obj->priv->action_group));
+
+ gtk_widget_init_template (GTK_WIDGET (obj));
+
+ g_signal_connect (obj->priv->previous_button, "button-press-event",
+ G_CALLBACK (on_location_button_press_event), obj);
+ g_signal_connect (obj->priv->next_button, "button-press-event",
+ G_CALLBACK (on_location_button_press_event), obj);
+
+ /* locations popover */
+ gtk_tree_selection_set_mode (obj->priv->locations_treeview_selection, GTK_SELECTION_SINGLE);
+ gtk_tree_view_column_set_cell_data_func (obj->priv->treeview_icon_column,
+ obj->priv->treeview_icon_renderer,
+ (GtkTreeCellDataFunc)locations_icon_renderer_cb,
+ obj,
+ NULL);
+ fill_locations_model (obj);
+
+ g_signal_connect (obj->priv->locations_treeview_selection, "changed",
+ G_CALLBACK (on_locations_treeview_selection_changed), obj);
+ g_signal_connect (obj->priv->locations_treeview, "row-activated",
+ G_CALLBACK (on_locations_treeview_row_activated), obj);
+
+ g_signal_connect (obj->priv->location_entry, "activate",
+ G_CALLBACK (on_location_entry_activate), obj);
+ g_signal_connect (obj->priv->location_entry, "focus-out-event",
+ G_CALLBACK (on_location_entry_focus_out_event), obj);
+ g_signal_connect (obj->priv->location_entry, "key-press-event",
+ G_CALLBACK (on_location_entry_key_press_event), obj);
+
+ /* tree view */
+ obj->priv->file_store = gedit_file_browser_store_new (NULL);
+ obj->priv->bookmarks_store = gedit_file_bookmarks_store_new ();
+
+ gedit_file_browser_view_set_restore_expand_state (obj->priv->treeview, TRUE);
+
+ gedit_file_browser_store_set_filter_mode (obj->priv->file_store,
+ GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN |
+ GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY);
+ gedit_file_browser_store_set_filter_func (obj->priv->file_store,
+ (GeditFileBrowserStoreFilterFunc) filter_real,
+ obj);
+
+ g_signal_connect (obj->priv->treeview, "notify::model",
+ G_CALLBACK (on_model_set), obj);
+ g_signal_connect (obj->priv->treeview, "error",
+ G_CALLBACK (on_treeview_error), obj);
+ g_signal_connect (obj->priv->treeview, "popup-menu",
+ G_CALLBACK (on_treeview_popup_menu), obj);
+ g_signal_connect (obj->priv->treeview, "button-press-event",
+ G_CALLBACK (on_treeview_button_press_event),
+ obj);
+ g_signal_connect (obj->priv->treeview, "key-press-event",
+ G_CALLBACK (on_treeview_key_press_event), obj);
+
+ g_signal_connect (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (obj->priv->treeview)), "changed",
+ G_CALLBACK (on_selection_changed), obj);
+ g_signal_connect (obj->priv->file_store, "notify::filter-mode",
+ G_CALLBACK (on_filter_mode_changed), obj);
+
+ g_signal_connect (obj->priv->file_store, "notify::virtual-root",
+ G_CALLBACK (on_virtual_root_changed), obj);
+
+ g_signal_connect (obj->priv->file_store, "begin-loading",
+ G_CALLBACK (on_begin_loading), obj);
+
+ g_signal_connect (obj->priv->file_store, "end-loading",
+ G_CALLBACK (on_end_loading), obj);
+
+ g_signal_connect (obj->priv->file_store, "error",
+ G_CALLBACK (on_file_store_error), obj);
+
+ init_bookmarks_hash (obj);
+
+ /* filter */
+ g_signal_connect_swapped (obj->priv->filter_entry, "activate",
+ G_CALLBACK (on_entry_filter_activate),
+ obj);
+ g_signal_connect_swapped (obj->priv->filter_entry, "focus_out_event",
+ G_CALLBACK (on_entry_filter_activate),
+ obj);
+}
+
+/* Private */
+
+static void
+update_sensitivity (GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+ GAction *action;
+ gint mode;
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ {
+ mode = gedit_file_browser_store_get_filter_mode (GEDIT_FILE_BROWSER_STORE (model));
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "show_hidden");
+
+ g_action_change_state (action,
+ g_variant_new_boolean (!(mode &
+ GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN)));
+
+ /* sensitivity */
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "up");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "home");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "show_hidden");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "show_binary");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "show_match_filename");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+ }
+ else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model))
+ {
+ /* Set the filter toggle to normal up state, just for visual pleasure */
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "show_hidden");
+
+ g_action_change_state (action, g_variant_new_boolean (FALSE));
+
+ /* sensitivity */
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "up");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "home");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "show_hidden");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "show_binary");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group),
+ "show_match_filename");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+ }
+
+ on_selection_changed (gtk_tree_view_get_selection
+ GTK_TREE_VIEW (obj->priv->treeview),
+ obj);
+}
+
+static gboolean
+gedit_file_browser_widget_get_first_selected (GeditFileBrowserWidget *obj,
+ GtkTreeIter *iter)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview));
+ GtkTreeModel *model;
+ GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
+ gboolean result;
+
+ if (!rows)
+ return FALSE;
+
+ result = gtk_tree_model_get_iter (model, iter, (GtkTreePath *)(rows->data));
+
+ g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
+
+ return result;
+}
+
+static gboolean
+popup_menu (GeditFileBrowserWidget *obj,
+ GtkTreeView *treeview,
+ GdkEventButton *event,
+ GtkTreeModel *model)
+{
+ GtkWidget *menu;
+ GMenuModel *menu_model;
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ menu_model = obj->priv->dir_menu;
+ else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model))
+ menu_model = obj->priv->bookmarks_menu;
+ else
+ return FALSE;
+
+ menu = gtk_menu_new_from_model (menu_model);
+ gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (obj), NULL);
+
+ if (event != NULL)
+ {
+ GtkTreeSelection *selection;
+ selection = gtk_tree_view_get_selection (treeview);
+
+ if (gtk_tree_selection_count_selected_rows (selection) <= 1)
+ {
+ GtkTreePath *path;
+
+ if (gtk_tree_view_get_path_at_pos (treeview,
+ (gint)event->x, (gint)event->y,
+ &path, NULL, NULL, NULL))
+ {
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+ }
+ }
+
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *)event);
+ }
+ else
+ {
+ GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (treeview));
+ GdkGravity rect_gravity = GDK_GRAVITY_EAST;
+ GdkGravity menu_gravity = GDK_GRAVITY_NORTH_WEST;
+ GdkRectangle rect;
+
+ if (gedit_utils_menu_position_under_tree_view (treeview, &rect))
+ {
+ if (gtk_widget_get_direction (GTK_WIDGET (treeview)) == GTK_TEXT_DIR_RTL)
+ {
+ rect_gravity = GDK_GRAVITY_WEST;
+ menu_gravity = GDK_GRAVITY_NORTH_EAST;
+ }
+
+ gtk_menu_popup_at_rect (GTK_MENU (menu), window, &rect, rect_gravity, menu_gravity, NULL);
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+filter_glob (GeditFileBrowserWidget *obj,
+ GeditFileBrowserStore *store,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ gchar *name;
+ gboolean result;
+ guint flags;
+
+ if (obj->priv->filter_pattern == NULL)
+ return TRUE;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_NAME, &name,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (FILE_IS_DIR (flags) || FILE_IS_DUMMY (flags))
+ result = TRUE;
+ else
+ result = g_pattern_spec_match_string (obj->priv->filter_pattern, name);
+
+ g_free (name);
+ return result;
+}
+
+static void
+rename_selected_file (GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+ GtkTreeIter iter;
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return;
+
+ if (gedit_file_browser_widget_get_first_selected (obj, &iter))
+ gedit_file_browser_view_start_rename (obj->priv->treeview, &iter);
+}
+
+static GList *
+get_deletable_files (GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview));
+ GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
+ GList *row;
+ GList *paths = NULL;
+
+ for (row = rows; row; row = row->next)
+ {
+ GtkTreePath *path = (GtkTreePath *)(row->data);
+ GtkTreeIter iter;
+ guint flags;
+
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ continue;
+
+ gtk_tree_model_get (model,
+ &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (FILE_IS_DUMMY (flags))
+ continue;
+
+ paths = g_list_append (paths, gtk_tree_path_copy (path));
+ }
+
+ g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
+
+ return paths;
+}
+
+static gboolean
+delete_selected_files (GeditFileBrowserWidget *obj,
+ gboolean trash)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+ gboolean confirm;
+ GeditFileBrowserStoreResult result;
+ GList *rows;
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return FALSE;
+
+ if (!(rows = get_deletable_files (obj)))
+ return FALSE;
+
+ if (!trash)
+ {
+ g_signal_emit (obj, signals[CONFIRM_DELETE], 0, model, rows, &confirm);
+
+ if (!confirm)
+ return FALSE;
+ }
+
+ result = gedit_file_browser_store_delete_all (GEDIT_FILE_BROWSER_STORE (model),
+ rows,
+ trash);
+
+ g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
+
+ return result == GEDIT_FILE_BROWSER_STORE_RESULT_OK;
+}
+
+static void
+show_location_entry (GeditFileBrowserWidget *obj,
+ const gchar *location)
+{
+ g_warn_if_fail (location != NULL);
+
+ gtk_entry_set_text (GTK_ENTRY (obj->priv->location_entry), location);
+
+ gtk_widget_show (obj->priv->location_entry);
+ gtk_widget_grab_focus (obj->priv->location_entry);
+
+ /* grab_focus() causes the entry's text to become
+ * selected so, unselect it and move the cursor to the end.
+ */
+ gtk_editable_set_position (GTK_EDITABLE (obj->priv->location_entry), -1);
+}
+
+static gboolean
+on_file_store_no_trash (GeditFileBrowserStore *store,
+ GList *files,
+ GeditFileBrowserWidget *obj)
+{
+ gboolean confirm = FALSE;
+
+ g_signal_emit (obj, signals[CONFIRM_NO_TRASH], 0, files, &confirm);
+
+ return confirm;
+}
+
+static GFile *
+get_topmost_file (GFile *file)
+{
+ GFile *current = g_object_ref (file);
+ GFile *tmp;
+
+ while ((tmp = g_file_get_parent (current)) != NULL)
+ {
+ g_object_unref (current);
+ current = tmp;
+ }
+
+ return current;
+}
+
+static GtkWidget *
+create_goto_menu_item (GeditFileBrowserWidget *obj,
+ GList *item)
+{
+ Location *loc = (Location *) (item->data);
+ GtkWidget *result;
+ gchar *icon_name = NULL;
+ gchar *unescape = NULL;
+
+ if (!get_from_bookmark_file (obj, loc->virtual_root, &unescape, &icon_name, NULL))
+ unescape = gedit_file_browser_utils_file_basename (loc->virtual_root);
+
+ result = gtk_menu_item_new_with_label (unescape);
+
+ g_object_set_data (G_OBJECT (result), LOCATION_DATA_KEY, item);
+ g_signal_connect (result, "activate",
+ G_CALLBACK (on_location_jump_activate), obj);
+
+ gtk_widget_show (result);
+
+ g_free (icon_name);
+ g_free (unescape);
+
+ return result;
+}
+
+static GList *
+list_next_iterator (GList *list)
+{
+ if (!list)
+ return NULL;
+
+ return list->next;
+}
+
+static GList *
+list_prev_iterator (GList *list)
+{
+ if (!list)
+ return NULL;
+
+ return list->prev;
+}
+
+static void
+jump_to_location (GeditFileBrowserWidget *obj,
+ GList *item,
+ gboolean previous)
+{
+ Location *loc;
+ GtkWidget *widget;
+ GList *children;
+ GList *child;
+ GList *(*iter_func) (GList *);
+ GtkWidget *menu_from;
+ GtkWidget *menu_to;
+
+ if (!obj->priv->locations)
+ return;
+
+ if (previous)
+ {
+ iter_func = list_next_iterator;
+ menu_from = obj->priv->location_previous_menu;
+ menu_to = obj->priv->location_next_menu;
+ }
+ else
+ {
+ iter_func = list_prev_iterator;
+ menu_from = obj->priv->location_next_menu;
+ menu_to = obj->priv->location_previous_menu;
+ }
+
+ children = gtk_container_get_children (GTK_CONTAINER (menu_from));
+ child = children;
+
+ /* This is the menuitem for the current location, which is the first
+ to be added to the menu */
+ widget = obj->priv->current_location_menu_item;
+
+ while (obj->priv->current_location != item)
+ {
+ if (widget)
+ {
+ /* Prepend the menu item to the menu */
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu_to), widget);
+ g_object_unref (widget);
+ }
+
+ widget = GTK_WIDGET (child->data);
+
+ /* Make sure the widget isn't destroyed when removed */
+ g_object_ref (widget);
+ gtk_container_remove (GTK_CONTAINER (menu_from), widget);
+
+ obj->priv->current_location_menu_item = widget;
+
+ if (obj->priv->current_location == NULL)
+ {
+ obj->priv->current_location = obj->priv->locations;
+
+ if (obj->priv->current_location == item)
+ break;
+ }
+ else
+ {
+ obj->priv->current_location = iter_func (obj->priv->current_location);
+ }
+
+ child = child->next;
+ }
+
+ g_list_free (children);
+
+ obj->priv->changing_location = TRUE;
+
+ loc = (Location *) (obj->priv->current_location->data);
+
+ /* Set the new root + virtual root */
+ gedit_file_browser_widget_set_root_and_virtual_root (obj,
+ loc->root,
+ loc->virtual_root);
+
+ obj->priv->changing_location = FALSE;
+}
+
+static void
+clear_next_locations (GeditFileBrowserWidget *obj)
+{
+ GAction *action;
+ GList *children;
+ GList *item;
+
+ if (obj->priv->current_location == NULL)
+ return;
+
+ while (obj->priv->current_location->prev)
+ {
+ location_free ((Location *) (obj->priv->current_location->prev->data));
+ obj->priv->locations = g_list_remove_link (obj->priv->locations,
+ obj->priv->current_location->prev);
+ }
+
+ children = gtk_container_get_children (GTK_CONTAINER (obj->priv->location_next_menu));
+
+ for (item = children; item; item = item->next)
+ {
+ gtk_container_remove (GTK_CONTAINER
+ (obj->priv->location_next_menu),
+ GTK_WIDGET (item->data));
+ }
+
+ g_list_free (children);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "next_location");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+}
+
+static void
+update_filter_mode (GeditFileBrowserWidget *obj,
+ GSimpleAction *action,
+ GVariant *state,
+ GeditFileBrowserStoreFilterMode mode)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ {
+ gint now = gedit_file_browser_store_get_filter_mode (GEDIT_FILE_BROWSER_STORE (model));
+
+ if (g_variant_get_boolean(state))
+ now &= ~mode;
+ else
+ now |= mode;
+
+ gedit_file_browser_store_set_filter_mode (GEDIT_FILE_BROWSER_STORE (model), now);
+
+ }
+
+ g_simple_action_set_state (action, state);
+}
+
+static void
+set_filter_pattern_real (GeditFileBrowserWidget *obj,
+ gchar const *pattern,
+ gboolean update_entry)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+
+ if (pattern != NULL && *pattern == '\0')
+ pattern = NULL;
+
+ if (pattern == NULL && *obj->priv->filter_pattern_str == '\0')
+ return;
+
+ if (pattern != NULL && strcmp (pattern, obj->priv->filter_pattern_str) == 0)
+ return;
+
+ /* Free the old pattern */
+ g_free (obj->priv->filter_pattern_str);
+
+ if (pattern == NULL)
+ obj->priv->filter_pattern_str = g_strdup ("");
+ else
+ obj->priv->filter_pattern_str = g_strdup (pattern);
+
+ if (obj->priv->filter_pattern)
+ {
+ g_pattern_spec_free (obj->priv->filter_pattern);
+ obj->priv->filter_pattern = NULL;
+ }
+
+ if (pattern == NULL)
+ {
+ if (obj->priv->glob_filter_id != 0)
+ {
+ gedit_file_browser_widget_remove_filter (obj, obj->priv->glob_filter_id);
+ obj->priv->glob_filter_id = 0;
+ }
+ }
+ else
+ {
+ obj->priv->filter_pattern = g_pattern_spec_new (pattern);
+
+ if (obj->priv->glob_filter_id == 0)
+ obj->priv->glob_filter_id = gedit_file_browser_widget_add_filter (obj,
+ filter_glob,
+ NULL,
+ NULL);
+ }
+
+ if (update_entry)
+ gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), obj->priv->filter_pattern_str);
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ gedit_file_browser_store_refilter (GEDIT_FILE_BROWSER_STORE (model));
+
+ g_object_notify (G_OBJECT (obj), "filter-pattern");
+}
+
+
+/* Public */
+
+GtkWidget *
+gedit_file_browser_widget_new (void)
+{
+ GeditFileBrowserWidget *obj = g_object_new (GEDIT_TYPE_FILE_BROWSER_WIDGET, NULL);
+
+ gedit_file_browser_widget_show_bookmarks (obj);
+
+ return GTK_WIDGET (obj);
+}
+
+void
+gedit_file_browser_widget_show_bookmarks (GeditFileBrowserWidget *obj)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ gtk_widget_set_sensitive (obj->priv->locations_button, FALSE);
+ gtk_widget_hide (obj->priv->locations_button_arrow);
+ locations_find_by_id (obj, BOOKMARKS_ID, &iter);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (obj->priv->locations_model), &iter);
+ gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (obj->priv->locations_cellview), path);
+ gtk_tree_path_free (path);
+
+ gedit_file_browser_view_set_model (obj->priv->treeview,
+ GTK_TREE_MODEL (obj->priv->bookmarks_store));
+}
+
+static void
+show_files_real (GeditFileBrowserWidget *obj,
+ gboolean do_root_changed)
+{
+ gtk_widget_set_sensitive (obj->priv->locations_button, TRUE);
+ gtk_widget_show (obj->priv->locations_button_arrow);
+
+ gedit_file_browser_view_set_model (obj->priv->treeview,
+ GTK_TREE_MODEL (obj->priv->file_store));
+
+ if (do_root_changed)
+ on_virtual_root_changed (obj->priv->file_store, NULL, obj);
+}
+
+void
+gedit_file_browser_widget_show_files (GeditFileBrowserWidget *obj)
+{
+ show_files_real (obj, TRUE);
+}
+
+void
+gedit_file_browser_widget_set_root_and_virtual_root (GeditFileBrowserWidget *obj,
+ GFile *root,
+ GFile *virtual_root)
+{
+ GeditFileBrowserStoreResult result;
+
+ if (!virtual_root)
+ result = gedit_file_browser_store_set_root_and_virtual_root (obj->priv->file_store,
+ root,
+ root);
+ else
+ result = gedit_file_browser_store_set_root_and_virtual_root (obj->priv->file_store,
+ root,
+ virtual_root);
+
+ if (result == GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE)
+ show_files_real (obj, TRUE);
+}
+
+void
+gedit_file_browser_widget_set_root (GeditFileBrowserWidget *obj,
+ GFile *root,
+ gboolean virtual_root)
+{
+ GFile *parent;
+
+ if (!virtual_root)
+ {
+ gedit_file_browser_widget_set_root_and_virtual_root (obj,
+ root,
+ NULL);
+ return;
+ }
+
+ if (!root)
+ return;
+
+ parent = get_topmost_file (root);
+ gedit_file_browser_widget_set_root_and_virtual_root (obj, parent, root);
+ g_object_unref (parent);
+}
+
+GeditFileBrowserStore *
+gedit_file_browser_widget_get_browser_store (GeditFileBrowserWidget *obj)
+{
+ return obj->priv->file_store;
+}
+
+GeditFileBookmarksStore *
+gedit_file_browser_widget_get_bookmarks_store (GeditFileBrowserWidget *obj)
+{
+ return obj->priv->bookmarks_store;
+}
+
+GeditFileBrowserView *
+gedit_file_browser_widget_get_browser_view (GeditFileBrowserWidget *obj)
+{
+ return obj->priv->treeview;
+}
+
+GtkWidget *
+gedit_file_browser_widget_get_filter_entry (GeditFileBrowserWidget *obj)
+{
+ return obj->priv->filter_entry;
+}
+
+gulong
+gedit_file_browser_widget_add_filter (GeditFileBrowserWidget *obj,
+ GeditFileBrowserWidgetFilterFunc func,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ FilterFunc *f = filter_func_new (obj, func, user_data, notify);;
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+
+ obj->priv->filter_funcs = g_slist_append (obj->priv->filter_funcs, f);
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ gedit_file_browser_store_refilter (GEDIT_FILE_BROWSER_STORE (model));
+
+ return f->id;
+}
+
+void
+gedit_file_browser_widget_remove_filter (GeditFileBrowserWidget *obj,
+ gulong id)
+{
+ GSList *item;
+
+ for (item = obj->priv->filter_funcs; item; item = item->next)
+ {
+ FilterFunc *func = (FilterFunc *) (item->data);
+
+ if (func->id == id)
+ {
+ if (func->destroy_notify)
+ func->destroy_notify (func->user_data);
+
+ obj->priv->filter_funcs = g_slist_remove_link (obj->priv->filter_funcs, item);
+
+ filter_func_free (func);
+ break;
+ }
+ }
+}
+
+void
+gedit_file_browser_widget_set_filter_pattern (GeditFileBrowserWidget *obj,
+ gchar const *pattern)
+{
+ gboolean show;
+ GAction *action;
+
+ /* if pattern is not null, reveal the entry */
+ show = pattern != NULL && *pattern != '\0';
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "show_match_filename");
+ g_action_change_state (action, g_variant_new_boolean (show));
+
+ set_filter_pattern_real (obj, pattern, TRUE);
+}
+
+gboolean
+gedit_file_browser_widget_get_selected_directory (GeditFileBrowserWidget *obj,
+ GtkTreeIter *iter)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+ GtkTreeIter parent;
+ guint flags;
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return FALSE;
+
+ if (!gedit_file_browser_widget_get_first_selected (obj, iter) &&
+ !gedit_file_browser_store_get_iter_virtual_root
+ (GEDIT_FILE_BROWSER_STORE (model), iter))
+ {
+ return FALSE;
+ }
+
+ gtk_tree_model_get (model, iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!FILE_IS_DIR (flags))
+ {
+ /* Get the parent, because the selection is a file */
+ gtk_tree_model_iter_parent (model, &parent, iter);
+ *iter = parent;
+ }
+
+ return TRUE;
+}
+
+void
+gedit_file_browser_widget_set_active_root_enabled (GeditFileBrowserWidget *widget,
+ gboolean enabled)
+{
+ GAction *action;
+
+ g_return_if_fail (GEDIT_IS_FILE_BROWSER_WIDGET (widget));
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (widget->priv->action_group), "set_active_root");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
+}
+
+static guint
+gedit_file_browser_widget_get_num_selected_files_or_directories (GeditFileBrowserWidget *obj,
+ guint *files,
+ guint *dirs)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview));
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+ GList *rows, *row;
+ guint result = 0;
+
+ if (GEDIT_IS_FILE_BOOKMARKS_STORE (model))
+ return 0;
+
+ rows = gtk_tree_selection_get_selected_rows (selection, &model);
+
+ for (row = rows; row; row = row->next)
+ {
+ GtkTreePath *path = (GtkTreePath *)(row->data);
+ GeditFileBrowserStoreFlag flags;
+ GtkTreeIter iter;
+
+ /* Get iter from path */
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ continue;
+
+ gtk_tree_model_get (model, &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!FILE_IS_DUMMY (flags))
+ {
+ if (!FILE_IS_DIR (flags))
+ ++(*files);
+ else
+ ++(*dirs);
+
+ ++result;
+ }
+ }
+
+ g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
+
+ return result;
+}
+
+typedef struct
+{
+ GeditFileBrowserWidget *widget;
+ GCancellable *cancellable;
+} AsyncData;
+
+static AsyncData *
+async_data_new (GeditFileBrowserWidget *widget)
+{
+ AsyncData *ret = g_slice_new (AsyncData);
+
+ ret->widget = widget;
+
+ cancel_async_operation (widget);
+ widget->priv->cancellable = g_cancellable_new ();
+
+ ret->cancellable = g_object_ref (widget->priv->cancellable);
+
+ return ret;
+}
+
+static void
+async_free (AsyncData *async)
+{
+ g_object_unref (async->cancellable);
+ g_slice_free (AsyncData, async);
+}
+
+static void
+set_busy (GeditFileBrowserWidget *obj,
+ gboolean busy)
+{
+ GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview));
+
+ if (!GDK_IS_WINDOW (window))
+ return;
+
+ if (busy)
+ {
+ GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (obj));
+ GdkCursor *cursor= gdk_cursor_new_from_name (display, "progress");
+
+ gdk_window_set_cursor (window, cursor);
+ g_clear_object (&cursor);
+ }
+ else
+ {
+ gdk_window_set_cursor (window, NULL);
+ }
+}
+
+static void try_mount_volume (GeditFileBrowserWidget *widget, GVolume *volume);
+
+static void
+activate_mount (GeditFileBrowserWidget *widget,
+ GVolume *volume,
+ GMount *mount)
+{
+ GFile *root;
+
+ if (!mount)
+ {
+ gchar *name = g_volume_get_name (volume);
+ gchar *message = g_strdup_printf (_("No mount object for mounted volume: %s"), name);
+
+ g_signal_emit (widget,
+ signals[ERROR],
+ 0,
+ GEDIT_FILE_BROWSER_ERROR_SET_ROOT,
+ message);
+
+ g_free (name);
+ g_free (message);
+ return;
+ }
+
+ root = g_mount_get_root (mount);
+
+ gedit_file_browser_widget_set_root (widget, root, FALSE);
+
+ g_object_unref (root);
+}
+
+static void
+try_activate_drive (GeditFileBrowserWidget *widget,
+ GDrive *drive)
+{
+ GList *volumes = g_drive_get_volumes (drive);
+ GVolume *volume = G_VOLUME (volumes->data);
+ GMount *mount = g_volume_get_mount (volume);
+
+ if (mount)
+ {
+ /* try set the root of the mount */
+ activate_mount (widget, volume, mount);
+ g_object_unref (mount);
+ }
+ else
+ {
+ /* try to mount it then? */
+ try_mount_volume (widget, volume);
+ }
+
+ g_list_free_full (volumes, g_object_unref);
+}
+
+static void
+poll_for_media_cb (GDrive *drive,
+ GAsyncResult *res,
+ AsyncData *async)
+{
+ GError *error = NULL;
+
+ /* check for cancelled state */
+ if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ async_free (async);
+ return;
+ }
+
+ /* finish poll operation */
+ set_busy (async->widget, FALSE);
+
+ if (g_drive_poll_for_media_finish (drive, res, &error) &&
+ g_drive_has_media (drive) &&
+ g_drive_has_volumes (drive))
+ {
+ try_activate_drive (async->widget, drive);
+ }
+ else
+ {
+ gchar *name = g_drive_get_name (drive);
+ gchar *message = g_strdup_printf (_("Could not open media: %s"), name);
+
+ g_signal_emit (async->widget,
+ signals[ERROR],
+ 0,
+ GEDIT_FILE_BROWSER_ERROR_SET_ROOT,
+ message);
+
+ g_free (name);
+ g_free (message);
+
+ g_error_free (error);
+ }
+
+ async_free (async);
+}
+
+static void
+mount_volume_cb (GVolume *volume,
+ GAsyncResult *res,
+ AsyncData *async)
+{
+ GError *error = NULL;
+
+ /* check for cancelled state */
+ if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ async_free (async);
+ return;
+ }
+
+ if (g_volume_mount_finish (volume, res, &error))
+ {
+ GMount *mount = g_volume_get_mount (volume);
+
+ activate_mount (async->widget, volume, mount);
+
+ if (mount)
+ g_object_unref (mount);
+ }
+ else
+ {
+ gchar *name = g_volume_get_name (volume);
+ gchar *message = g_strdup_printf (_("Could not mount volume: %s"), name);
+
+ g_signal_emit (async->widget,
+ signals[ERROR],
+ 0,
+ GEDIT_FILE_BROWSER_ERROR_SET_ROOT,
+ message);
+
+ g_free (name);
+ g_free (message);
+
+ g_error_free (error);
+ }
+
+ set_busy (async->widget, FALSE);
+ async_free (async);
+}
+
+static void
+activate_drive (GeditFileBrowserWidget *obj,
+ GtkTreeIter *iter)
+{
+ GDrive *drive;
+ AsyncData *async;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->bookmarks_store),
+ iter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, &drive,
+ -1);
+
+ /* most common use case is a floppy drive, we'll poll for media and
+ go from there */
+ async = async_data_new (obj);
+ g_drive_poll_for_media (drive,
+ async->cancellable,
+ (GAsyncReadyCallback)poll_for_media_cb,
+ async);
+
+ g_object_unref (drive);
+ set_busy (obj, TRUE);
+}
+
+static void
+try_mount_volume (GeditFileBrowserWidget *widget,
+ GVolume *volume)
+{
+ GMountOperation *operation = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget))));
+ AsyncData *async = async_data_new (widget);
+
+ g_volume_mount (volume,
+ G_MOUNT_MOUNT_NONE,
+ operation,
+ async->cancellable,
+ (GAsyncReadyCallback)mount_volume_cb,
+ async);
+
+ g_object_unref (operation);
+ set_busy (widget, TRUE);
+}
+
+static void
+activate_volume (GeditFileBrowserWidget *obj,
+ GtkTreeIter *iter)
+{
+ GVolume *volume;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->bookmarks_store),
+ iter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, &volume,
+ -1);
+
+ /* see if we can mount the volume */
+ try_mount_volume (obj, volume);
+ g_object_unref (volume);
+}
+
+void
+gedit_file_browser_widget_refresh (GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ {
+ gedit_file_browser_store_refresh (GEDIT_FILE_BROWSER_STORE (model));
+ }
+ else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model))
+ {
+ g_hash_table_ref (obj->priv->bookmarks_hash);
+ g_hash_table_destroy (obj->priv->bookmarks_hash);
+
+ gedit_file_bookmarks_store_refresh (GEDIT_FILE_BOOKMARKS_STORE (model));
+ }
+}
+
+GeditMenuExtension *
+gedit_file_browser_widget_extend_context_menu (GeditFileBrowserWidget *obj)
+{
+ guint i, n_items;
+ GMenuModel *section = NULL;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_WIDGET (obj), NULL);
+
+ n_items = g_menu_model_get_n_items (obj->priv->dir_menu);
+
+ for (i = 0; i < n_items && !section; i++)
+ {
+ gchar *id = NULL;
+
+ if (g_menu_model_get_item_attribute (obj->priv->dir_menu, i, "id", "s", &id) &&
+ strcmp (id, "extension-section") == 0)
+ {
+ section = g_menu_model_get_item_link (obj->priv->dir_menu, i, G_MENU_LINK_SECTION);
+ }
+
+ g_free (id);
+ }
+
+ return section != NULL ? gedit_menu_extension_new (G_MENU (section)) : NULL;
+}
+
+void
+gedit_file_browser_widget_history_back (GeditFileBrowserWidget *obj)
+{
+ if (obj->priv->locations)
+ {
+ if (obj->priv->current_location)
+ jump_to_location (obj, obj->priv->current_location->next, TRUE);
+ else
+ jump_to_location (obj, obj->priv->locations, TRUE);
+ }
+}
+
+void
+gedit_file_browser_widget_history_forward (GeditFileBrowserWidget *obj)
+{
+ if (obj->priv->locations)
+ jump_to_location (obj, obj->priv->current_location->prev, FALSE);
+}
+
+static void
+bookmark_open (GeditFileBrowserWidget *obj,
+ GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ GFile *location;
+ gint flags;
+
+ gtk_tree_model_get (model,
+ iter,
+ GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_DRIVE)
+ {
+ /* handle a drive node */
+ gedit_file_browser_store_cancel_mount_operation (obj->priv->file_store);
+ activate_drive (obj, iter);
+ return;
+ }
+ else if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_VOLUME)
+ {
+ /* handle a volume node */
+ gedit_file_browser_store_cancel_mount_operation (obj->priv->file_store);
+ activate_volume (obj, iter);
+ return;
+ }
+
+ if ((location = gedit_file_bookmarks_store_get_location (GEDIT_FILE_BOOKMARKS_STORE (model), iter)))
+ {
+ /* here we check if the bookmark is a mount point, or if it
+ is a remote bookmark. If that's the case, we will set the
+ root to the uri of the bookmark and not try to set the
+ topmost parent as root (since that may as well not be the
+ mount point anymore) */
+ if ((flags & GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT) ||
+ (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK))
+ {
+ gedit_file_browser_widget_set_root (obj, location, FALSE);
+ }
+ else
+ {
+ gedit_file_browser_widget_set_root (obj, location, TRUE);
+ }
+
+ g_object_unref (location);
+ }
+ else
+ {
+ g_warning ("No uri!");
+ }
+}
+
+static void
+file_open (GeditFileBrowserWidget *obj,
+ GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ GFile *location;
+ gint flags;
+
+ gtk_tree_model_get (model, iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ if (!FILE_IS_DIR (flags) && !FILE_IS_DUMMY (flags))
+ g_signal_emit (obj, signals[LOCATION_ACTIVATED], 0, location);
+
+ if (location)
+ g_object_unref (location);
+}
+
+static gboolean
+directory_open (GeditFileBrowserWidget *obj,
+ GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ gboolean result = FALSE;
+ GError *error = NULL;
+ GFile *location;
+ GeditFileBrowserStoreFlag flags;
+
+ gtk_tree_model_get (model, iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ if (FILE_IS_DIR (flags) && location)
+ {
+ gchar *uri = g_file_get_uri (location);
+ GtkWindow *window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (obj)));
+
+ result = TRUE;
+
+ if (!gtk_show_uri_on_window (window, uri, GDK_CURRENT_TIME, &error))
+ {
+ g_signal_emit (obj, signals[ERROR], 0,
+ GEDIT_FILE_BROWSER_ERROR_OPEN_DIRECTORY,
+ error->message);
+
+ g_error_free (error);
+ error = NULL;
+ }
+
+ g_free (uri);
+ g_object_unref (location);
+ }
+
+ return result;
+}
+
+static void
+on_bookmark_activated (GeditFileBrowserView *tree_view,
+ GtkTreeIter *iter,
+ GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+
+ bookmark_open (obj, model, iter);
+}
+
+static void
+on_file_activated (GeditFileBrowserView *tree_view,
+ GtkTreeIter *iter,
+ GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+
+ file_open (obj, model, iter);
+}
+
+static gboolean
+virtual_root_is_root (GeditFileBrowserWidget *obj,
+ GeditFileBrowserStore *model)
+{
+ GtkTreeIter root;
+ GtkTreeIter virtual_root;
+
+ if (!gedit_file_browser_store_get_iter_root (model, &root))
+ return TRUE;
+
+ if (!gedit_file_browser_store_get_iter_virtual_root (model, &virtual_root))
+ return TRUE;
+
+ return gedit_file_browser_store_iter_equal (model, &root, &virtual_root);
+}
+
+static void
+on_virtual_root_changed (GeditFileBrowserStore *model,
+ GParamSpec *param,
+ GeditFileBrowserWidget *obj)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)) !=
+ GTK_TREE_MODEL (obj->priv->file_store))
+ {
+ show_files_real (obj, FALSE);
+ }
+
+ if (gedit_file_browser_store_get_iter_virtual_root (model, &iter))
+ {
+ GFile *location;
+ GtkTreeIter root;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (model),
+ &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &location,
+ -1);
+
+ if (gedit_file_browser_store_get_iter_root (model, &root))
+ {
+ GAction *action;
+
+ if (!obj->priv->changing_location)
+ {
+ Location *loc;
+
+ /* Remove all items from obj->priv->current_location on */
+ if (obj->priv->current_location)
+ clear_next_locations (obj);
+
+ loc = g_slice_new (Location);
+ loc->root = gedit_file_browser_store_get_root (model);
+ loc->virtual_root = g_object_ref (location);
+
+ if (obj->priv->current_location)
+ {
+ /* Add current location to the menu so we can go back
+ to it later */
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (obj->priv->location_previous_menu),
+ obj->priv->current_location_menu_item);
+ }
+
+ obj->priv->locations = g_list_prepend (obj->priv->locations, loc);
+
+ obj->priv->current_location = obj->priv->locations;
+ obj->priv->current_location_menu_item = create_goto_menu_item (obj,
+ obj->priv->current_location);
+
+ g_object_ref_sink (obj->priv->current_location_menu_item);
+ }
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "up");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), !virtual_root_is_root (obj, model));
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "previous_location");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ obj->priv->current_location != NULL &&
+ obj->priv->current_location->next != NULL);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "next_location");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ obj->priv->current_location != NULL &&
+ obj->priv->current_location->prev != NULL);
+ }
+
+ check_current_item (obj, TRUE);
+
+ if (location)
+ g_object_unref (location);
+ }
+ else
+ {
+ g_message ("NO!");
+ }
+}
+
+static void
+on_model_set (GObject *gobject,
+ GParamSpec *arg1,
+ GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (gobject));
+
+ clear_signals (obj);
+
+ if (GEDIT_IS_FILE_BOOKMARKS_STORE (model))
+ {
+ clear_next_locations (obj);
+
+ /* Add the current location to the back menu */
+ if (obj->priv->current_location)
+ {
+ GAction *action;
+
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (obj->priv->location_previous_menu),
+ obj->priv->current_location_menu_item);
+
+ g_object_unref (obj->priv->current_location_menu_item);
+ obj->priv->current_location = NULL;
+ obj->priv->current_location_menu_item = NULL;
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "previous_location");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+ }
+
+ gtk_widget_hide (obj->priv->filter_entry_revealer);
+
+ add_signal (obj,
+ gobject,
+ g_signal_connect (gobject, "bookmark-activated",
+ G_CALLBACK (on_bookmark_activated),
+ obj));
+ }
+ else if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ {
+ /* make sure any async operation is cancelled */
+ cancel_async_operation (obj);
+
+ add_signal (obj,
+ gobject,
+ g_signal_connect (gobject, "file-activated",
+ G_CALLBACK (on_file_activated),
+ obj));
+
+ add_signal (obj,
+ model,
+ g_signal_connect (model, "no-trash",
+ G_CALLBACK (on_file_store_no_trash),
+ obj));
+
+ gtk_widget_show (obj->priv->filter_entry_revealer);
+ }
+
+ update_sensitivity (obj);
+}
+
+static void
+on_file_store_error (GeditFileBrowserStore *store,
+ guint code,
+ gchar *message,
+ GeditFileBrowserWidget *obj)
+{
+ g_signal_emit (obj, signals[ERROR], 0, code, message);
+}
+
+static void
+on_treeview_error (GeditFileBrowserView *tree_view,
+ guint code,
+ gchar *message,
+ GeditFileBrowserWidget *obj)
+{
+ g_signal_emit (obj, signals[ERROR], 0, code, message);
+}
+
+static gboolean
+on_location_button_press_event (GtkWidget *button,
+ GdkEventButton *event,
+ GeditFileBrowserWidget *obj)
+{
+ GtkWidget *menu;
+
+ if (event->button != GDK_BUTTON_SECONDARY)
+ return FALSE;
+
+ if (button == obj->priv->previous_button)
+ menu = obj->priv->location_previous_menu;
+ else
+ menu = obj->priv->location_next_menu;
+
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *)event);
+
+ return TRUE;
+}
+
+static void
+on_locations_treeview_selection_changed (GtkTreeSelection *treeview_selection,
+ GeditFileBrowserWidget *obj)
+{
+ GeditFileBrowserWidgetPrivate *priv = obj->priv;
+ GtkTreeModel *model = GTK_TREE_MODEL (priv->locations_model);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ if (!gtk_tree_selection_get_selected (treeview_selection, &model, &iter))
+ return;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (obj->priv->locations_model), &iter);
+ gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (obj->priv->locations_cellview), path);
+ gtk_tree_path_free (path);
+}
+
+static void
+on_location_entry_activate (GtkEntry *entry,
+ GeditFileBrowserWidget *obj)
+{
+ gchar *location = g_strdup (gtk_entry_get_text (entry));
+ GFile *root;
+ gchar *cwd;
+ GFile *new_root;
+
+ if (g_str_has_prefix (location, "~/"))
+ {
+ gchar *tmp = location;
+
+ location = g_strdup_printf ("%s/%s", g_get_home_dir (), tmp + strlen ("~/"));
+
+ g_free (tmp);
+ }
+
+ root = gedit_file_browser_store_get_virtual_root (obj->priv->file_store);
+ cwd = g_file_get_path (root);
+
+ if (cwd == NULL)
+ cwd = g_file_get_uri (root);
+
+ new_root = g_file_new_for_commandline_arg_and_cwd (location, cwd);
+
+ if (g_file_query_file_type (new_root, G_FILE_QUERY_INFO_NONE, NULL) != G_FILE_TYPE_DIRECTORY)
+ {
+ gchar *display_name = g_file_get_parse_name (new_root);
+ gchar *msg = g_strdup_printf (_("Error when loading “%s”: No such directory"), display_name);
+
+ g_signal_emit (obj, signals[ERROR], 0, GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY, msg);
+
+ g_free (msg);
+ g_free (display_name);
+ }
+ else
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (obj->priv->treeview));
+ gtk_widget_hide (obj->priv->location_entry);
+
+ gedit_file_browser_widget_set_root (obj, new_root, TRUE);
+ }
+
+ g_object_unref (new_root);
+ g_free (cwd);
+ g_object_unref (root);
+ g_free (location);
+}
+
+static gboolean
+on_location_entry_focus_out_event (GtkWidget *entry,
+ GdkEvent *event,
+ GeditFileBrowserWidget *obj)
+{
+ gtk_widget_hide (entry);
+ return FALSE;
+}
+
+static gboolean
+on_location_entry_key_press_event (GtkWidget *entry,
+ GdkEventKey *event,
+ GeditFileBrowserWidget *obj)
+{
+ guint modifiers = gtk_accelerator_get_default_mod_mask ();
+
+ if (event->keyval == GDK_KEY_Escape &&
+ (event->state & modifiers) == 0)
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (obj->priv->treeview));
+ gtk_widget_hide (entry);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+on_treeview_popup_menu (GeditFileBrowserView *treeview,
+ GeditFileBrowserWidget *obj)
+{
+ return popup_menu (obj, GTK_TREE_VIEW (treeview), NULL, gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
+}
+
+static gboolean
+on_treeview_button_press_event (GeditFileBrowserView *treeview,
+ GdkEventButton *event,
+ GeditFileBrowserWidget *obj)
+{
+ if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_SECONDARY)
+ return popup_menu (obj,
+ GTK_TREE_VIEW (treeview),
+ event,
+ gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
+
+ return FALSE;
+}
+
+static gboolean
+do_change_directory (GeditFileBrowserWidget *obj,
+ GdkEventKey *event)
+{
+ GAction *action = NULL;
+
+ if ((event->state &
+ (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK & ~GDK_MOD1_MASK)) ==
+ event->state && event->keyval == GDK_KEY_BackSpace)
+ {
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "previous_location");
+ }
+ else if (!((event->state & GDK_MOD1_MASK) &&
+ (event->state & (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK)) == event->state))
+ {
+ return FALSE;
+ }
+
+ switch (event->keyval)
+ {
+ case GDK_KEY_Home:
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "home");
+ break;
+ case GDK_KEY_Left:
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "previous_location");
+ break;
+ case GDK_KEY_Right:
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "next_location");
+ break;
+ case GDK_KEY_Up:
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "up");
+ break;
+ default:
+ break;
+ }
+
+ if (action != NULL)
+ {
+ g_action_activate (action, NULL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+on_treeview_key_press_event (GeditFileBrowserView *treeview,
+ GdkEventKey *event,
+ GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model;
+ guint modifiers;
+
+ if (do_change_directory (obj, event))
+ return TRUE;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return FALSE;
+
+ modifiers = gtk_accelerator_get_default_mod_mask ();
+
+ if (event->keyval == GDK_KEY_Delete ||
+ event->keyval == GDK_KEY_KP_Delete)
+ {
+
+ if ((event->state & modifiers) == GDK_SHIFT_MASK)
+ {
+ delete_selected_files (obj, FALSE);
+ return TRUE;
+ }
+ else if ((event->state & modifiers) == 0)
+ {
+ delete_selected_files (obj, TRUE);
+ return TRUE;
+ }
+ }
+
+ if ((event->keyval == GDK_KEY_F2) && (event->state & modifiers) == 0)
+ {
+ rename_selected_file (obj);
+ return TRUE;
+ }
+
+ if (event->keyval == GDK_KEY_l &&
+ (event->state & modifiers) == GDK_CONTROL_MASK)
+ {
+ show_location_entry (obj, "");
+ return TRUE;
+ }
+
+ if (event->keyval == GDK_KEY_slash ||
+ event->keyval == GDK_KEY_KP_Divide ||
+#ifdef G_OS_WIN32
+ event->keyval == GDK_KEY_backslash ||
+#endif
+ event->keyval == GDK_KEY_asciitilde)
+ {
+ gchar location[2] = {'\0', '\0'};
+
+ location[0] = gdk_keyval_to_unicode (event->keyval);
+
+ show_location_entry (obj, location);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+on_selection_changed (GtkTreeSelection *selection,
+ GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+ GAction *action;
+ guint selected = 0;
+ guint files = 0;
+ guint dirs = 0;
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ selected = gedit_file_browser_widget_get_num_selected_files_or_directories (obj, &files, &dirs);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "move_to_trash");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selected > 0);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "delete");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selected > 0);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "open");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), (selected > 0) && (selected == files));
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "rename");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selected == 1);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "open_in_terminal");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selected == 1);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "new_folder");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selected <= 1);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "new_file");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selected <= 1);
+}
+
+static gboolean
+on_entry_filter_activate (GeditFileBrowserWidget *obj)
+{
+ gchar const *text = gtk_entry_get_text (GTK_ENTRY (obj->priv->filter_entry));
+ set_filter_pattern_real (obj, text, FALSE);
+
+ return FALSE;
+}
+
+static void
+on_location_jump_activate (GtkMenuItem *item,
+ GeditFileBrowserWidget *obj)
+{
+ GList *location = g_object_get_data (G_OBJECT (item), LOCATION_DATA_KEY);
+
+ if (obj->priv->current_location)
+ {
+ jump_to_location (obj, location,
+ g_list_position (obj->priv->locations, location) >
+ g_list_position (obj->priv->locations, obj->priv->current_location));
+ }
+ else
+ {
+ jump_to_location (obj, location, TRUE);
+ }
+}
+
+static void
+on_bookmarks_row_changed (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GeditFileBrowserWidget *obj)
+{
+ add_bookmark_hash (obj, iter);
+}
+
+static void
+on_bookmarks_row_deleted (GtkTreeModel *model,
+ GtkTreePath *path,
+ GeditFileBrowserWidget *obj)
+{
+ GtkTreeIter iter;
+ GFile *location;
+
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return;
+
+ if (!(location = gedit_file_bookmarks_store_get_location (obj->priv->bookmarks_store, &iter)))
+ return;
+
+ g_hash_table_remove (obj->priv->bookmarks_hash, location);
+
+ g_object_unref (location);
+}
+
+static void
+on_filter_mode_changed (GeditFileBrowserStore *model,
+ GParamSpec *param,
+ GeditFileBrowserWidget *obj)
+{
+ gint mode = gedit_file_browser_store_get_filter_mode (model);
+ GAction *action;
+ GVariant *variant;
+ gboolean active;
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "show_hidden");
+ active = !(mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN);
+ variant = g_action_get_state (action);
+
+ if (active != g_variant_get_boolean (variant))
+ g_action_change_state (action, g_variant_new_boolean (active));
+
+ g_variant_unref (variant);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (obj->priv->action_group), "show_binary");
+ active = !(mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY);
+ variant = g_action_get_state (action);
+
+ if (active != g_variant_get_boolean (variant))
+ g_action_change_state (action, g_variant_new_boolean (active));
+
+ g_variant_unref (variant);
+}
+
+static void
+next_location_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ gedit_file_browser_widget_history_forward (GEDIT_FILE_BROWSER_WIDGET (user_data));
+}
+
+static void
+previous_location_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ gedit_file_browser_widget_history_back (GEDIT_FILE_BROWSER_WIDGET (user_data));
+}
+
+static void
+up_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return;
+
+ gedit_file_browser_store_set_virtual_root_up (GEDIT_FILE_BROWSER_STORE (model));
+}
+
+static void
+home_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
+ GFile *home_location;
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return;
+
+ home_location = g_file_new_for_path (g_get_home_dir ());
+ gedit_file_browser_widget_set_root (widget, home_location, TRUE);
+
+ g_object_unref (home_location);
+}
+
+static void
+new_folder_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
+ GtkTreeIter parent;
+ GtkTreeIter iter;
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return;
+
+ if (!gedit_file_browser_widget_get_selected_directory (widget, &parent))
+ return;
+
+ if (gedit_file_browser_store_new_directory (GEDIT_FILE_BROWSER_STORE (model), &parent, &iter))
+ gedit_file_browser_view_start_rename (widget->priv->treeview, &iter);
+}
+
+static void
+open_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview));
+ GList *rows;
+ GList *row;
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return;
+
+ rows = gtk_tree_selection_get_selected_rows (selection, &model);
+ for (row = rows; row; row = row->next)
+ {
+ GtkTreePath *path = (GtkTreePath *)(row->data);
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (model, &iter, path))
+ file_open (widget, model, &iter);
+
+ gtk_tree_path_free (path);
+ }
+
+ g_list_free (rows);
+}
+
+static void
+new_file_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
+ GtkTreeIter parent;
+ GtkTreeIter iter;
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return;
+
+ if (!gedit_file_browser_widget_get_selected_directory (widget, &parent))
+ return;
+
+ if (gedit_file_browser_store_new_file (GEDIT_FILE_BROWSER_STORE (model), &parent, &iter))
+ gedit_file_browser_view_start_rename (widget->priv->treeview, &iter);
+}
+
+static void
+rename_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+
+ rename_selected_file (widget);
+}
+
+static void
+delete_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+
+ delete_selected_files (widget, FALSE);
+}
+
+static void
+move_to_trash_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+
+ delete_selected_files (widget, TRUE);
+}
+
+static void
+refresh_view_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+
+ gedit_file_browser_widget_refresh (widget);
+}
+
+static void
+view_folder_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview));
+ GtkTreeIter iter;
+ GList *rows;
+ GList *row;
+ gboolean directory_opened = FALSE;
+
+ if (!GEDIT_IS_FILE_BROWSER_STORE (model))
+ return;
+
+ rows = gtk_tree_selection_get_selected_rows (selection, &model);
+ for (row = rows; row; row = row->next)
+ {
+ GtkTreePath *path = (GtkTreePath *)(row->data);
+
+ if (gtk_tree_model_get_iter (model, &iter, path))
+ directory_opened |= directory_open (widget, model, &iter);
+
+ gtk_tree_path_free (path);
+ }
+
+ if (!directory_opened && gedit_file_browser_widget_get_selected_directory (widget, &iter))
+ directory_open (widget, model, &iter);
+
+ g_list_free (rows);
+}
+
+static void
+change_show_hidden_state (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+
+ update_filter_mode (widget,
+ action,
+ state,
+ GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN);
+}
+
+static void
+change_show_binary_state (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+
+ update_filter_mode (widget,
+ action,
+ state,
+ GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY);
+}
+
+static void
+change_show_match_filename (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+ gboolean visible = g_variant_get_boolean (state);
+
+ gtk_revealer_set_reveal_child (GTK_REVEALER (widget->priv->filter_entry_revealer), visible);
+
+ if (visible)
+ gtk_widget_grab_focus (widget->priv->filter_entry);
+ else
+ /* clear the filter */
+ set_filter_pattern_real (widget, NULL, TRUE);
+
+ g_simple_action_set_state (action, state);
+}
+
+static void
+open_in_terminal_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+ GtkTreeIter iter;
+ GFile *file;
+
+ /* Get the current directory */
+ if (!gedit_file_browser_widget_get_selected_directory (widget, &iter))
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->file_store),
+ &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_LOCATION, &file,
+ -1);
+
+ g_signal_emit (widget, signals[OPEN_IN_TERMINAL], 0, file);
+
+ g_object_unref (file);
+}
+
+static void
+set_active_root_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GeditFileBrowserWidget *widget = GEDIT_FILE_BROWSER_WIDGET (user_data);
+
+ g_signal_emit (widget, signals[SET_ACTIVE_ROOT], 0);
+}
+
+void
+_gedit_file_browser_widget_register_type (GTypeModule *type_module)
+{
+ gedit_file_browser_widget_register_type (type_module);
+}
+
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/gedit-file-browser-widget.h b/plugins/filebrowser/gedit-file-browser-widget.h
new file mode 100644
index 0000000..8da8312
--- /dev/null
+++ b/plugins/filebrowser/gedit-file-browser-widget.h
@@ -0,0 +1,126 @@
+/*
+ * gedit-file-browser-widget.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2006 - Jesse van den Kieboom <jesse@icecrew.nl>
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GEDIT_FILE_BROWSER_WIDGET_H
+#define GEDIT_FILE_BROWSER_WIDGET_H
+
+#include <gtk/gtk.h>
+#include <gedit/gedit-menu-extension.h>
+#include "gedit-file-browser-store.h"
+#include "gedit-file-bookmarks-store.h"
+#include "gedit-file-browser-view.h"
+
+G_BEGIN_DECLS
+#define GEDIT_TYPE_FILE_BROWSER_WIDGET (gedit_file_browser_widget_get_type ())
+#define GEDIT_FILE_BROWSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_WIDGET, GeditFileBrowserWidget))
+#define GEDIT_FILE_BROWSER_WIDGET_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_WIDGET, GeditFileBrowserWidget const))
+#define GEDIT_FILE_BROWSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FILE_BROWSER_WIDGET, GeditFileBrowserWidgetClass))
+#define GEDIT_IS_FILE_BROWSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FILE_BROWSER_WIDGET))
+#define GEDIT_IS_FILE_BROWSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FILE_BROWSER_WIDGET))
+#define GEDIT_FILE_BROWSER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FILE_BROWSER_WIDGET, GeditFileBrowserWidgetClass))
+
+typedef struct _GeditFileBrowserWidget GeditFileBrowserWidget;
+typedef struct _GeditFileBrowserWidgetClass GeditFileBrowserWidgetClass;
+typedef struct _GeditFileBrowserWidgetPrivate GeditFileBrowserWidgetPrivate;
+
+typedef
+gboolean (*GeditFileBrowserWidgetFilterFunc) (GeditFileBrowserWidget *obj,
+ GeditFileBrowserStore *model,
+ GtkTreeIter *iter,
+ gpointer user_data);
+
+struct _GeditFileBrowserWidget
+{
+ GtkBox parent;
+
+ GeditFileBrowserWidgetPrivate *priv;
+};
+
+struct _GeditFileBrowserWidgetClass
+{
+ GtkBoxClass parent_class;
+
+ /* Signals */
+ void (* location_activated) (GeditFileBrowserWidget *widget,
+ GFile *location);
+ void (* error) (GeditFileBrowserWidget *widget,
+ guint code,
+ gchar const *message);
+ gboolean (* confirm_delete) (GeditFileBrowserWidget *widget,
+ GeditFileBrowserStore *model,
+ GList *list);
+ gboolean (* confirm_no_trash) (GeditFileBrowserWidget *widget,
+ GList *list);
+ void (* open_in_terminal) (GeditFileBrowserWidget *widget,
+ GFile *location);
+ void (* set_active_root) (GeditFileBrowserWidget *widget);
+};
+
+GType gedit_file_browser_widget_get_type (void) G_GNUC_CONST;
+
+GtkWidget *gedit_file_browser_widget_new (void);
+
+void gedit_file_browser_widget_show_bookmarks (GeditFileBrowserWidget *obj);
+void gedit_file_browser_widget_show_files (GeditFileBrowserWidget *obj);
+
+void gedit_file_browser_widget_set_root (GeditFileBrowserWidget *obj,
+ GFile *root,
+ gboolean virtual_root);
+void gedit_file_browser_widget_set_root_and_virtual_root
+ (GeditFileBrowserWidget *obj,
+ GFile *root,
+ GFile *virtual_root);
+
+gboolean gedit_file_browser_widget_get_selected_directory
+ (GeditFileBrowserWidget *obj,
+ GtkTreeIter *iter);
+
+void gedit_file_browser_widget_set_active_root_enabled (GeditFileBrowserWidget *widget,
+ gboolean enabled);
+
+GeditFileBrowserStore *
+gedit_file_browser_widget_get_browser_store (GeditFileBrowserWidget *obj);
+GeditFileBookmarksStore *
+gedit_file_browser_widget_get_bookmarks_store (GeditFileBrowserWidget *obj);
+GeditFileBrowserView *
+gedit_file_browser_widget_get_browser_view (GeditFileBrowserWidget *obj);
+GtkWidget *
+gedit_file_browser_widget_get_filter_entry (GeditFileBrowserWidget *obj);
+
+gulong gedit_file_browser_widget_add_filter (GeditFileBrowserWidget *obj,
+ GeditFileBrowserWidgetFilterFunc func,
+ gpointer user_data,
+ GDestroyNotify notify);
+void gedit_file_browser_widget_remove_filter (GeditFileBrowserWidget *obj,
+ gulong id);
+void gedit_file_browser_widget_set_filter_pattern (GeditFileBrowserWidget *obj,
+ gchar const *pattern);
+GeditMenuExtension *
+ gedit_file_browser_widget_extend_context_menu (GeditFileBrowserWidget *obj);
+void gedit_file_browser_widget_refresh (GeditFileBrowserWidget *obj);
+void gedit_file_browser_widget_history_back (GeditFileBrowserWidget *obj);
+void gedit_file_browser_widget_history_forward (GeditFileBrowserWidget *obj);
+
+void _gedit_file_browser_widget_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_WIDGET_H */
+/* ex:set ts=8 noet: */
diff --git a/plugins/filebrowser/meson.build b/plugins/filebrowser/meson.build
new file mode 100644
index 0000000..ba66652
--- /dev/null
+++ b/plugins/filebrowser/meson.build
@@ -0,0 +1,127 @@
+libfilebrowser_public_h = files(
+ 'gedit-file-bookmarks-store.h',
+ 'gedit-file-browser-error.h',
+ 'gedit-file-browser-store.h',
+ 'gedit-file-browser-view.h',
+ 'gedit-file-browser-widget.h',
+ 'gedit-file-browser-utils.h',
+ 'gedit-file-browser-plugin.h',
+ 'gedit-file-browser-messages.h',
+)
+
+libfilebrowser_sources = files(
+ 'gedit-file-bookmarks-store.c',
+ 'gedit-file-browser-messages.c',
+ 'gedit-file-browser-plugin.c',
+ 'gedit-file-browser-store.c',
+ 'gedit-file-browser-utils.c',
+ 'gedit-file-browser-view.c',
+ 'gedit-file-browser-widget.c',
+)
+
+libfilebrowser_deps = [
+ libgedit_dep,
+]
+
+subdir('messages')
+
+libfilebrowser_register_enums = gnome.mkenums(
+ 'gedit-file-browser-enum-register',
+ sources: libfilebrowser_public_h,
+ c_template: 'gedit-file-browser-enum-register.c.template',
+)
+
+libfilebrowser_type_enums = gnome.mkenums(
+ 'gedit-file-browser-enum-types',
+ depends : [libfilebrowser_register_enums],
+ sources: libfilebrowser_public_h,
+ h_template: 'gedit-file-browser-enum-types.h.template',
+ c_template: 'gedit-file-browser-enum-types-stage1.c.template',
+)
+
+# cat won't work on Windows so this
+# will need to be reimplemented as a script
+cat = find_program('cat')
+
+# Combine the 2 C mkenums templates together before compiling
+libfilebrowser_enums_c = custom_target('libfilebrowser_enums_c',
+ input: [libfilebrowser_type_enums.get(0),
+ libfilebrowser_register_enums],
+ output: 'gedit-file-browser-enum-types.c',
+ command: [cat, '@INPUT0@', '@INPUT1@'],
+ # redirects the command output since we can't use >> here
+ capture: true,
+)
+
+libfilebrowser_sources += [
+ libfilebrowser_enums_c,
+ libfilebrowser_type_enums.get(1),
+]
+
+subdir('resources')
+
+libfilebrowser_sha = shared_module(
+ 'filebrowser',
+ sources: libfilebrowser_sources,
+ include_directories: root_include_dir,
+ dependencies: libfilebrowser_deps,
+ install: true,
+ install_dir: join_paths(
+ pkglibdir,
+ 'plugins',
+ ),
+ name_suffix: module_suffix,
+)
+
+# FIXME: https://github.com/mesonbuild/meson/issues/1687
+custom_target(
+ 'org.gnome.gedit.plugins.filebrowser.enums.xml',
+ input : libfilebrowser_sources + libfilebrowser_public_h,
+ output: 'org.gnome.gedit.plugins.filebrowser.enums.xml',
+ capture: true,
+ command: [
+ 'glib-mkenums',
+ '--comments', '<!-- @comment@ -->',
+ '--fhead', '<schemalist>',
+ '--vhead', ' <@type@ id="org.gnome.gedit.plugins.filebrowser.@EnumName@">',
+ '--vprod', ' <value nick="@valuenick@" value="@valuenum@"/>',
+ '--vtail', ' </@type@>',
+ '--ftail', '</schemalist>',
+ '@INPUT@'
+ ],
+ install: true,
+ install_dir: join_paths(
+ glibdir,
+ 'schemas',
+ )
+)
+
+filebrowser_gschema_file = files('org.gnome.gedit.plugins.filebrowser.gschema.xml')
+install_data(
+ filebrowser_gschema_file,
+ install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'glib-2.0/schemas')
+)
+
+if xmllint.found()
+ test(
+ 'validate-filebrowser-gschema',
+ xmllint,
+ args: [
+ '--noout',
+ '--dtdvalid', gschema_dtd,
+ filebrowser_gschema_file,
+ ]
+ )
+endif
+
+custom_target(
+ 'filebrowser.plugin',
+ input: 'filebrowser.plugin.desktop.in',
+ output: 'filebrowser.plugin',
+ command: msgfmt_plugin_cmd,
+ install: true,
+ install_dir: join_paths(
+ pkglibdir,
+ 'plugins',
+ )
+)
diff --git a/plugins/filebrowser/messages.xml b/plugins/filebrowser/messages.xml
new file mode 100644
index 0000000..e2b7137
--- /dev/null
+++ b/plugins/filebrowser/messages.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<messages>
+ <message namespace="Gedit" name="FileBrowserMessageGetRoot">
+ <include>gio/gio.h</include>
+ <property name="location" type="object" gtype="G_TYPE_FILE"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageSetRoot">
+ <include>gio/gio.h</include>
+ <property name="location" type="object" gtype="G_TYPE_FILE"/>
+ <property name="virtual" type="string"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageSetEmblem">
+ <property name="id" type="string"/>
+ <property name="emblem" type="string"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageSetMarkup">
+ <property name="id" type="string"/>
+ <property name="markup" type="string"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageAddFilter">
+ <property name="object_path" type="string"/>
+ <property name="method" type="string"/>
+ <property name="id" type="uint"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageId">
+ <property name="id" type="uint"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageExtendContextMenu">
+ <include system="yes">gedit/gedit-menu-extension.h</include>
+ <property name="extension" type="object" gtype="GEDIT_TYPE_MENU_EXTENSION"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageActivation">
+ <property name="active" type="boolean"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageGetView">
+ <include>plugins/filebrowser/gedit-file-browser-view.h</include>
+ <property name="view" type="object" gtype="GEDIT_TYPE_FILE_BROWSER_VIEW"/>
+ </message>
+ <message namespace="Gedit" name="FileBrowserMessageIdLocation">
+ <include>gio/gio.h</include>
+ <property name="id" type="string"/>
+ <property name="name" type="string"/>
+ <property name="location" type="object" gtype="G_TYPE_FILE"/>
+ <property name="is-directory" type="boolean"/>
+ </message>
+</messages>
+<!-- vi:ex:ts=2:et -->
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-activation.c b/plugins/filebrowser/messages/gedit-file-browser-message-activation.c
new file mode 100644
index 0000000..0138e0d
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-activation.c
@@ -0,0 +1,105 @@
+
+/*
+ * gedit-file-browser-message-activation.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-activation.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_ACTIVE,
+};
+
+struct _GeditFileBrowserMessageActivationPrivate
+{
+ gboolean active;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageActivation,
+ gedit_file_browser_message_activation,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageActivation))
+
+static void
+gedit_file_browser_message_activation_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageActivation *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ACTIVE:
+ g_value_set_boolean (value, msg->priv->active);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_activation_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageActivation *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ACTIVE:
+ msg->priv->active = g_value_get_boolean (value);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_activation_class_init (GeditFileBrowserMessageActivationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->get_property = gedit_file_browser_message_activation_get_property;
+ object_class->set_property = gedit_file_browser_message_activation_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ACTIVE,
+ g_param_spec_boolean ("active",
+ "Active",
+ "Active",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_activation_init (GeditFileBrowserMessageActivation *message)
+{
+ message->priv = gedit_file_browser_message_activation_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-activation.h b/plugins/filebrowser/messages/gedit-file-browser-message-activation.h
new file mode 100644
index 0000000..bd3b1ed
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-activation.h
@@ -0,0 +1,69 @@
+
+/*
+ * gedit-file-browser-message-activation.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION_H
+#define GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION (gedit_file_browser_message_activation_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION,\
+ GeditFileBrowserMessageActivation))
+#define GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION,\
+ GeditFileBrowserMessageActivation const))
+#define GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION,\
+ GeditFileBrowserMessageActivationClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_ACTIVATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_ACTIVATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION))
+#define GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ACTIVATION,\
+ GeditFileBrowserMessageActivationClass))
+
+typedef struct _GeditFileBrowserMessageActivation GeditFileBrowserMessageActivation;
+typedef struct _GeditFileBrowserMessageActivationClass GeditFileBrowserMessageActivationClass;
+typedef struct _GeditFileBrowserMessageActivationPrivate GeditFileBrowserMessageActivationPrivate;
+
+struct _GeditFileBrowserMessageActivation
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageActivationPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageActivationClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_activation_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_ACTIVATION_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-add-filter.c b/plugins/filebrowser/messages/gedit-file-browser-message-add-filter.c
new file mode 100644
index 0000000..f66a32d
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-add-filter.c
@@ -0,0 +1,162 @@
+
+/*
+ * gedit-file-browser-message-add-filter.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-add-filter.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_OBJECT_PATH,
+ PROP_METHOD,
+ PROP_ID,
+};
+
+struct _GeditFileBrowserMessageAddFilterPrivate
+{
+ gchar *object_path;
+ gchar *method;
+ guint id;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageAddFilter,
+ gedit_file_browser_message_add_filter,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageAddFilter))
+
+static void
+gedit_file_browser_message_add_filter_finalize (GObject *obj)
+{
+ GeditFileBrowserMessageAddFilter *msg = GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER (obj);
+
+ g_free (msg->priv->object_path);
+ g_free (msg->priv->method);
+
+ G_OBJECT_CLASS (gedit_file_browser_message_add_filter_parent_class)->finalize (obj);
+}
+
+static void
+gedit_file_browser_message_add_filter_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageAddFilter *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER (obj);
+
+ switch (prop_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, msg->priv->object_path);
+ break;
+ case PROP_METHOD:
+ g_value_set_string (value, msg->priv->method);
+ break;
+ case PROP_ID:
+ g_value_set_uint (value, msg->priv->id);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_add_filter_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageAddFilter *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER (obj);
+
+ switch (prop_id)
+ {
+ case PROP_OBJECT_PATH:
+ {
+ g_free (msg->priv->object_path);
+ msg->priv->object_path = g_value_dup_string (value);
+ break;
+ }
+ case PROP_METHOD:
+ {
+ g_free (msg->priv->method);
+ msg->priv->method = g_value_dup_string (value);
+ break;
+ }
+ case PROP_ID:
+ msg->priv->id = g_value_get_uint (value);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_add_filter_class_init (GeditFileBrowserMessageAddFilterClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_file_browser_message_add_filter_finalize;
+
+ object_class->get_property = gedit_file_browser_message_add_filter_get_property;
+ object_class->set_property = gedit_file_browser_message_add_filter_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_OBJECT_PATH,
+ g_param_spec_string ("object-path",
+ "Object Path",
+ "Object Path",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_METHOD,
+ g_param_spec_string ("method",
+ "Method",
+ "Method",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_uint ("id",
+ "Id",
+ "Id",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_add_filter_init (GeditFileBrowserMessageAddFilter *message)
+{
+ message->priv = gedit_file_browser_message_add_filter_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-add-filter.h b/plugins/filebrowser/messages/gedit-file-browser-message-add-filter.h
new file mode 100644
index 0000000..4a5b35c
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-add-filter.h
@@ -0,0 +1,69 @@
+
+/*
+ * gedit-file-browser-message-add-filter.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER_H
+#define GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_ADD_FILTER (gedit_file_browser_message_add_filter_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ADD_FILTER,\
+ GeditFileBrowserMessageAddFilter))
+#define GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ADD_FILTER,\
+ GeditFileBrowserMessageAddFilter const))
+#define GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ADD_FILTER,\
+ GeditFileBrowserMessageAddFilterClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_ADD_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ADD_FILTER))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_ADD_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ADD_FILTER))
+#define GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ADD_FILTER,\
+ GeditFileBrowserMessageAddFilterClass))
+
+typedef struct _GeditFileBrowserMessageAddFilter GeditFileBrowserMessageAddFilter;
+typedef struct _GeditFileBrowserMessageAddFilterClass GeditFileBrowserMessageAddFilterClass;
+typedef struct _GeditFileBrowserMessageAddFilterPrivate GeditFileBrowserMessageAddFilterPrivate;
+
+struct _GeditFileBrowserMessageAddFilter
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageAddFilterPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageAddFilterClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_add_filter_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_ADD_FILTER_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-extend-context-menu.c b/plugins/filebrowser/messages/gedit-file-browser-message-extend-context-menu.c
new file mode 100644
index 0000000..4bb8682
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-extend-context-menu.c
@@ -0,0 +1,128 @@
+
+/*
+ * gedit-file-browser-message-extend-context-menu.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Paolo Borelli
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-extend-context-menu.h"
+#include <gedit/gedit-menu-extension.h>
+
+enum
+{
+ PROP_0,
+
+ PROP_EXTENSION,
+};
+
+struct _GeditFileBrowserMessageExtendContextMenuPrivate
+{
+ GeditMenuExtension *extension;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageExtendContextMenu,
+ gedit_file_browser_message_extend_context_menu,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageExtendContextMenu))
+
+static void
+gedit_file_browser_message_extend_context_menu_finalize (GObject *obj)
+{
+ GeditFileBrowserMessageExtendContextMenu *msg = GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU (obj);
+
+ if (msg->priv->extension)
+ {
+ g_object_unref (msg->priv->extension);
+ }
+
+ G_OBJECT_CLASS (gedit_file_browser_message_extend_context_menu_parent_class)->finalize (obj);
+}
+
+static void
+gedit_file_browser_message_extend_context_menu_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageExtendContextMenu *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU (obj);
+
+ switch (prop_id)
+ {
+ case PROP_EXTENSION:
+ g_value_set_object (value, msg->priv->extension);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_extend_context_menu_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageExtendContextMenu *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU (obj);
+
+ switch (prop_id)
+ {
+ case PROP_EXTENSION:
+ {
+ if (msg->priv->extension)
+ {
+ g_object_unref (msg->priv->extension);
+ }
+ msg->priv->extension = g_value_dup_object (value);
+ break;
+ }
+ }
+}
+
+static void
+gedit_file_browser_message_extend_context_menu_class_init (GeditFileBrowserMessageExtendContextMenuClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_file_browser_message_extend_context_menu_finalize;
+
+ object_class->get_property = gedit_file_browser_message_extend_context_menu_get_property;
+ object_class->set_property = gedit_file_browser_message_extend_context_menu_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EXTENSION,
+ g_param_spec_object ("extension",
+ "Extension",
+ "Extension",
+ GEDIT_TYPE_MENU_EXTENSION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_extend_context_menu_init (GeditFileBrowserMessageExtendContextMenu *message)
+{
+ message->priv = gedit_file_browser_message_extend_context_menu_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-extend-context-menu.h b/plugins/filebrowser/messages/gedit-file-browser-message-extend-context-menu.h
new file mode 100644
index 0000000..643485d
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-extend-context-menu.h
@@ -0,0 +1,70 @@
+
+/*
+ * gedit-file-browser-message-extend-context-menu.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Paolo Borelli
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU_H
+#define GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU (gedit_file_browser_message_extend_context_menu_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU,\
+ GeditFileBrowserMessageExtendContextMenu))
+#define GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU,\
+ GeditFileBrowserMessageExtendContextMenu const))
+#define GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU,\
+ GeditFileBrowserMessageExtendContextMenuClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU))
+#define GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU,\
+ GeditFileBrowserMessageExtendContextMenuClass))
+
+typedef struct _GeditFileBrowserMessageExtendContextMenu GeditFileBrowserMessageExtendContextMenu;
+typedef struct _GeditFileBrowserMessageExtendContextMenuClass GeditFileBrowserMessageExtendContextMenuClass;
+typedef struct _GeditFileBrowserMessageExtendContextMenuPrivate GeditFileBrowserMessageExtendContextMenuPrivate;
+
+struct _GeditFileBrowserMessageExtendContextMenu
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageExtendContextMenuPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageExtendContextMenuClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_extend_context_menu_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_EXTEND_CONTEXT_MENU_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-get-root.c b/plugins/filebrowser/messages/gedit-file-browser-message-get-root.c
new file mode 100644
index 0000000..b766ac1
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-get-root.c
@@ -0,0 +1,127 @@
+
+/*
+ * gedit-file-browser-message-get-root.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-get-root.h"
+#include "gio/gio.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_LOCATION,
+};
+
+struct _GeditFileBrowserMessageGetRootPrivate
+{
+ GFile *location;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageGetRoot,
+ gedit_file_browser_message_get_root,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageGetRoot))
+
+static void
+gedit_file_browser_message_get_root_finalize (GObject *obj)
+{
+ GeditFileBrowserMessageGetRoot *msg = GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT (obj);
+
+ if (msg->priv->location)
+ {
+ g_object_unref (msg->priv->location);
+ }
+
+ G_OBJECT_CLASS (gedit_file_browser_message_get_root_parent_class)->finalize (obj);
+}
+
+static void
+gedit_file_browser_message_get_root_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageGetRoot *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT (obj);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ g_value_set_object (value, msg->priv->location);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_get_root_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageGetRoot *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT (obj);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ {
+ if (msg->priv->location)
+ {
+ g_object_unref (msg->priv->location);
+ }
+ msg->priv->location = g_value_dup_object (value);
+ break;
+ }
+ }
+}
+
+static void
+gedit_file_browser_message_get_root_class_init (GeditFileBrowserMessageGetRootClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_file_browser_message_get_root_finalize;
+
+ object_class->get_property = gedit_file_browser_message_get_root_get_property;
+ object_class->set_property = gedit_file_browser_message_get_root_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_LOCATION,
+ g_param_spec_object ("location",
+ "Location",
+ "Location",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_get_root_init (GeditFileBrowserMessageGetRoot *message)
+{
+ message->priv = gedit_file_browser_message_get_root_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-get-root.h b/plugins/filebrowser/messages/gedit-file-browser-message-get-root.h
new file mode 100644
index 0000000..8cc114d
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-get-root.h
@@ -0,0 +1,69 @@
+
+/*
+ * gedit-file-browser-message-get-root.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT_H
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_ROOT (gedit_file_browser_message_get_root_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_ROOT,\
+ GeditFileBrowserMessageGetRoot))
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_ROOT,\
+ GeditFileBrowserMessageGetRoot const))
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_ROOT,\
+ GeditFileBrowserMessageGetRootClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_GET_ROOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_ROOT))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_GET_ROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_ROOT))
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_ROOT,\
+ GeditFileBrowserMessageGetRootClass))
+
+typedef struct _GeditFileBrowserMessageGetRoot GeditFileBrowserMessageGetRoot;
+typedef struct _GeditFileBrowserMessageGetRootClass GeditFileBrowserMessageGetRootClass;
+typedef struct _GeditFileBrowserMessageGetRootPrivate GeditFileBrowserMessageGetRootPrivate;
+
+struct _GeditFileBrowserMessageGetRoot
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageGetRootPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageGetRootClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_get_root_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_GET_ROOT_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-get-view.c b/plugins/filebrowser/messages/gedit-file-browser-message-get-view.c
new file mode 100644
index 0000000..17fe757
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-get-view.c
@@ -0,0 +1,127 @@
+
+/*
+ * gedit-file-browser-message-get-view.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-get-view.h"
+#include "plugins/filebrowser/gedit-file-browser-view.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_VIEW,
+};
+
+struct _GeditFileBrowserMessageGetViewPrivate
+{
+ GeditFileBrowserView *view;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageGetView,
+ gedit_file_browser_message_get_view,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageGetView))
+
+static void
+gedit_file_browser_message_get_view_finalize (GObject *obj)
+{
+ GeditFileBrowserMessageGetView *msg = GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW (obj);
+
+ if (msg->priv->view)
+ {
+ g_object_unref (msg->priv->view);
+ }
+
+ G_OBJECT_CLASS (gedit_file_browser_message_get_view_parent_class)->finalize (obj);
+}
+
+static void
+gedit_file_browser_message_get_view_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageGetView *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW (obj);
+
+ switch (prop_id)
+ {
+ case PROP_VIEW:
+ g_value_set_object (value, msg->priv->view);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_get_view_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageGetView *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW (obj);
+
+ switch (prop_id)
+ {
+ case PROP_VIEW:
+ {
+ if (msg->priv->view)
+ {
+ g_object_unref (msg->priv->view);
+ }
+ msg->priv->view = g_value_dup_object (value);
+ break;
+ }
+ }
+}
+
+static void
+gedit_file_browser_message_get_view_class_init (GeditFileBrowserMessageGetViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_file_browser_message_get_view_finalize;
+
+ object_class->get_property = gedit_file_browser_message_get_view_get_property;
+ object_class->set_property = gedit_file_browser_message_get_view_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_VIEW,
+ g_param_spec_object ("view",
+ "View",
+ "View",
+ GEDIT_TYPE_FILE_BROWSER_VIEW,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_get_view_init (GeditFileBrowserMessageGetView *message)
+{
+ message->priv = gedit_file_browser_message_get_view_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-get-view.h b/plugins/filebrowser/messages/gedit-file-browser-message-get-view.h
new file mode 100644
index 0000000..452abbc
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-get-view.h
@@ -0,0 +1,69 @@
+
+/*
+ * gedit-file-browser-message-get-view.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW_H
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_VIEW (gedit_file_browser_message_get_view_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_VIEW,\
+ GeditFileBrowserMessageGetView))
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_VIEW,\
+ GeditFileBrowserMessageGetView const))
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_VIEW,\
+ GeditFileBrowserMessageGetViewClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_GET_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_VIEW))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_GET_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_VIEW))
+#define GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_GET_VIEW,\
+ GeditFileBrowserMessageGetViewClass))
+
+typedef struct _GeditFileBrowserMessageGetView GeditFileBrowserMessageGetView;
+typedef struct _GeditFileBrowserMessageGetViewClass GeditFileBrowserMessageGetViewClass;
+typedef struct _GeditFileBrowserMessageGetViewPrivate GeditFileBrowserMessageGetViewPrivate;
+
+struct _GeditFileBrowserMessageGetView
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageGetViewPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageGetViewClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_get_view_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_GET_VIEW_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-id-location.c b/plugins/filebrowser/messages/gedit-file-browser-message-id-location.c
new file mode 100644
index 0000000..36c33c5
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-id-location.c
@@ -0,0 +1,190 @@
+
+/*
+ * gedit-file-browser-message-id-location.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2013 - Garrett Regier
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-id-location.h"
+#include "gio/gio.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_ID,
+ PROP_NAME,
+ PROP_LOCATION,
+ PROP_IS_DIRECTORY,
+};
+
+struct _GeditFileBrowserMessageIdLocationPrivate
+{
+ gchar *id;
+ gchar *name;
+ GFile *location;
+ gboolean is_directory;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageIdLocation,
+ gedit_file_browser_message_id_location,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageIdLocation))
+
+static void
+gedit_file_browser_message_id_location_finalize (GObject *obj)
+{
+ GeditFileBrowserMessageIdLocation *msg = GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION (obj);
+
+ g_free (msg->priv->id);
+ g_free (msg->priv->name);
+ if (msg->priv->location)
+ {
+ g_object_unref (msg->priv->location);
+ }
+
+ G_OBJECT_CLASS (gedit_file_browser_message_id_location_parent_class)->finalize (obj);
+}
+
+static void
+gedit_file_browser_message_id_location_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageIdLocation *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ g_value_set_string (value, msg->priv->id);
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, msg->priv->name);
+ break;
+ case PROP_LOCATION:
+ g_value_set_object (value, msg->priv->location);
+ break;
+ case PROP_IS_DIRECTORY:
+ g_value_set_boolean (value, msg->priv->is_directory);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_id_location_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageIdLocation *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ {
+ g_free (msg->priv->id);
+ msg->priv->id = g_value_dup_string (value);
+ break;
+ }
+ case PROP_NAME:
+ {
+ g_free (msg->priv->name);
+ msg->priv->name = g_value_dup_string (value);
+ break;
+ }
+ case PROP_LOCATION:
+ {
+ if (msg->priv->location)
+ {
+ g_object_unref (msg->priv->location);
+ }
+ msg->priv->location = g_value_dup_object (value);
+ break;
+ }
+ case PROP_IS_DIRECTORY:
+ msg->priv->is_directory = g_value_get_boolean (value);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_id_location_class_init (GeditFileBrowserMessageIdLocationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_file_browser_message_id_location_finalize;
+
+ object_class->get_property = gedit_file_browser_message_id_location_get_property;
+ object_class->set_property = gedit_file_browser_message_id_location_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_string ("id",
+ "Id",
+ "Id",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "Name",
+ "Name",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_LOCATION,
+ g_param_spec_object ("location",
+ "Location",
+ "Location",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_IS_DIRECTORY,
+ g_param_spec_boolean ("is-directory",
+ "Is Directory",
+ "Is Directory",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_id_location_init (GeditFileBrowserMessageIdLocation *message)
+{
+ message->priv = gedit_file_browser_message_id_location_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-id-location.h b/plugins/filebrowser/messages/gedit-file-browser-message-id-location.h
new file mode 100644
index 0000000..0af4c77
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-id-location.h
@@ -0,0 +1,70 @@
+
+/*
+ * gedit-file-browser-message-id-location.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2013 - Garrett Regier
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION_H
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION (gedit_file_browser_message_id_location_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,\
+ GeditFileBrowserMessageIdLocation))
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,\
+ GeditFileBrowserMessageIdLocation const))
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,\
+ GeditFileBrowserMessageIdLocationClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_ID_LOCATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_ID_LOCATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION))
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID_LOCATION,\
+ GeditFileBrowserMessageIdLocationClass))
+
+typedef struct _GeditFileBrowserMessageIdLocation GeditFileBrowserMessageIdLocation;
+typedef struct _GeditFileBrowserMessageIdLocationClass GeditFileBrowserMessageIdLocationClass;
+typedef struct _GeditFileBrowserMessageIdLocationPrivate GeditFileBrowserMessageIdLocationPrivate;
+
+struct _GeditFileBrowserMessageIdLocation
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageIdLocationPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageIdLocationClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_id_location_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_ID_LOCATION_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-id.c b/plugins/filebrowser/messages/gedit-file-browser-message-id.c
new file mode 100644
index 0000000..fec490f
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-id.c
@@ -0,0 +1,107 @@
+
+/*
+ * gedit-file-browser-message-id.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-id.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_ID,
+};
+
+struct _GeditFileBrowserMessageIdPrivate
+{
+ guint id;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageId,
+ gedit_file_browser_message_id,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageId))
+
+static void
+gedit_file_browser_message_id_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageId *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_ID (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ g_value_set_uint (value, msg->priv->id);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_id_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageId *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_ID (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ msg->priv->id = g_value_get_uint (value);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_id_class_init (GeditFileBrowserMessageIdClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->get_property = gedit_file_browser_message_id_get_property;
+ object_class->set_property = gedit_file_browser_message_id_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_uint ("id",
+ "Id",
+ "Id",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_id_init (GeditFileBrowserMessageId *message)
+{
+ message->priv = gedit_file_browser_message_id_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-id.h b/plugins/filebrowser/messages/gedit-file-browser-message-id.h
new file mode 100644
index 0000000..8351c3b
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-id.h
@@ -0,0 +1,69 @@
+
+/*
+ * gedit-file-browser-message-id.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_ID_H
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID (gedit_file_browser_message_id_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_ID(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID,\
+ GeditFileBrowserMessageId))
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID,\
+ GeditFileBrowserMessageId const))
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID,\
+ GeditFileBrowserMessageIdClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_ID(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_ID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID))
+#define GEDIT_FILE_BROWSER_MESSAGE_ID_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_ID,\
+ GeditFileBrowserMessageIdClass))
+
+typedef struct _GeditFileBrowserMessageId GeditFileBrowserMessageId;
+typedef struct _GeditFileBrowserMessageIdClass GeditFileBrowserMessageIdClass;
+typedef struct _GeditFileBrowserMessageIdPrivate GeditFileBrowserMessageIdPrivate;
+
+struct _GeditFileBrowserMessageId
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageIdPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageIdClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_id_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_ID_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-set-emblem.c b/plugins/filebrowser/messages/gedit-file-browser-message-set-emblem.c
new file mode 100644
index 0000000..8e63042
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-set-emblem.c
@@ -0,0 +1,142 @@
+
+/*
+ * gedit-file-browser-message-set-emblem.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-set-emblem.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_ID,
+ PROP_EMBLEM,
+};
+
+struct _GeditFileBrowserMessageSetEmblemPrivate
+{
+ gchar *id;
+ gchar *emblem;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageSetEmblem,
+ gedit_file_browser_message_set_emblem,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageSetEmblem))
+
+static void
+gedit_file_browser_message_set_emblem_finalize (GObject *obj)
+{
+ GeditFileBrowserMessageSetEmblem *msg = GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM (obj);
+
+ g_free (msg->priv->id);
+ g_free (msg->priv->emblem);
+
+ G_OBJECT_CLASS (gedit_file_browser_message_set_emblem_parent_class)->finalize (obj);
+}
+
+static void
+gedit_file_browser_message_set_emblem_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageSetEmblem *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ g_value_set_string (value, msg->priv->id);
+ break;
+ case PROP_EMBLEM:
+ g_value_set_string (value, msg->priv->emblem);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_set_emblem_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageSetEmblem *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ {
+ g_free (msg->priv->id);
+ msg->priv->id = g_value_dup_string (value);
+ break;
+ }
+ case PROP_EMBLEM:
+ {
+ g_free (msg->priv->emblem);
+ msg->priv->emblem = g_value_dup_string (value);
+ break;
+ }
+ }
+}
+
+static void
+gedit_file_browser_message_set_emblem_class_init (GeditFileBrowserMessageSetEmblemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_file_browser_message_set_emblem_finalize;
+
+ object_class->get_property = gedit_file_browser_message_set_emblem_get_property;
+ object_class->set_property = gedit_file_browser_message_set_emblem_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_string ("id",
+ "Id",
+ "Id",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_EMBLEM,
+ g_param_spec_string ("emblem",
+ "Emblem",
+ "Emblem",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_set_emblem_init (GeditFileBrowserMessageSetEmblem *message)
+{
+ message->priv = gedit_file_browser_message_set_emblem_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-set-emblem.h b/plugins/filebrowser/messages/gedit-file-browser-message-set-emblem.h
new file mode 100644
index 0000000..6daa795
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-set-emblem.h
@@ -0,0 +1,69 @@
+
+/*
+ * gedit-file-browser-message-set-emblem.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM_H
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_EMBLEM (gedit_file_browser_message_set_emblem_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_EMBLEM,\
+ GeditFileBrowserMessageSetEmblem))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_EMBLEM,\
+ GeditFileBrowserMessageSetEmblem const))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_EMBLEM,\
+ GeditFileBrowserMessageSetEmblemClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_SET_EMBLEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_EMBLEM))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_SET_EMBLEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_EMBLEM))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_EMBLEM,\
+ GeditFileBrowserMessageSetEmblemClass))
+
+typedef struct _GeditFileBrowserMessageSetEmblem GeditFileBrowserMessageSetEmblem;
+typedef struct _GeditFileBrowserMessageSetEmblemClass GeditFileBrowserMessageSetEmblemClass;
+typedef struct _GeditFileBrowserMessageSetEmblemPrivate GeditFileBrowserMessageSetEmblemPrivate;
+
+struct _GeditFileBrowserMessageSetEmblem
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageSetEmblemPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageSetEmblemClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_set_emblem_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_SET_EMBLEM_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-set-markup.c b/plugins/filebrowser/messages/gedit-file-browser-message-set-markup.c
new file mode 100644
index 0000000..3b14d16
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-set-markup.c
@@ -0,0 +1,143 @@
+
+/*
+ * gedit-file-browser-message-set-markup.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2013 - Garrett Regier
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-set-markup.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_ID,
+ PROP_MARKUP,
+};
+
+struct _GeditFileBrowserMessageSetMarkupPrivate
+{
+ gchar *id;
+ gchar *markup;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageSetMarkup,
+ gedit_file_browser_message_set_markup,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageSetMarkup))
+
+static void
+gedit_file_browser_message_set_markup_finalize (GObject *obj)
+{
+ GeditFileBrowserMessageSetMarkup *msg = GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP (obj);
+
+ g_free (msg->priv->id);
+ g_free (msg->priv->markup);
+
+ G_OBJECT_CLASS (gedit_file_browser_message_set_markup_parent_class)->finalize (obj);
+}
+
+static void
+gedit_file_browser_message_set_markup_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageSetMarkup *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ g_value_set_string (value, msg->priv->id);
+ break;
+ case PROP_MARKUP:
+ g_value_set_string (value, msg->priv->markup);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_set_markup_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageSetMarkup *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP (obj);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ {
+ g_free (msg->priv->id);
+ msg->priv->id = g_value_dup_string (value);
+ break;
+ }
+ case PROP_MARKUP:
+ {
+ g_free (msg->priv->markup);
+ msg->priv->markup = g_value_dup_string (value);
+ break;
+ }
+ }
+}
+
+static void
+gedit_file_browser_message_set_markup_class_init (GeditFileBrowserMessageSetMarkupClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_file_browser_message_set_markup_finalize;
+
+ object_class->get_property = gedit_file_browser_message_set_markup_get_property;
+ object_class->set_property = gedit_file_browser_message_set_markup_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_string ("id",
+ "Id",
+ "Id",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_MARKUP,
+ g_param_spec_string ("markup",
+ "Markup",
+ "Markup",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_set_markup_init (GeditFileBrowserMessageSetMarkup *message)
+{
+ message->priv = gedit_file_browser_message_set_markup_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-set-markup.h b/plugins/filebrowser/messages/gedit-file-browser-message-set-markup.h
new file mode 100644
index 0000000..ab9a1dc
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-set-markup.h
@@ -0,0 +1,70 @@
+
+/*
+ * gedit-file-browser-message-set-markup.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2013 - Garrett Regier
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP_H
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_MARKUP (gedit_file_browser_message_set_markup_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_MARKUP,\
+ GeditFileBrowserMessageSetMarkup))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_MARKUP,\
+ GeditFileBrowserMessageSetMarkup const))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_MARKUP,\
+ GeditFileBrowserMessageSetMarkupClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_SET_MARKUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_MARKUP))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_SET_MARKUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_MARKUP))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_MARKUP,\
+ GeditFileBrowserMessageSetMarkupClass))
+
+typedef struct _GeditFileBrowserMessageSetMarkup GeditFileBrowserMessageSetMarkup;
+typedef struct _GeditFileBrowserMessageSetMarkupClass GeditFileBrowserMessageSetMarkupClass;
+typedef struct _GeditFileBrowserMessageSetMarkupPrivate GeditFileBrowserMessageSetMarkupPrivate;
+
+struct _GeditFileBrowserMessageSetMarkup
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageSetMarkupPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageSetMarkupClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_set_markup_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_SET_MARKUP_H */
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-set-root.c b/plugins/filebrowser/messages/gedit-file-browser-message-set-root.c
new file mode 100644
index 0000000..cb3891b
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-set-root.c
@@ -0,0 +1,149 @@
+
+/*
+ * gedit-file-browser-message-set-root.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "gedit-file-browser-message-set-root.h"
+#include "gio/gio.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_LOCATION,
+ PROP_VIRTUAL,
+};
+
+struct _GeditFileBrowserMessageSetRootPrivate
+{
+ GFile *location;
+ gchar *virtual;
+};
+
+G_DEFINE_TYPE_EXTENDED (GeditFileBrowserMessageSetRoot,
+ gedit_file_browser_message_set_root,
+ GEDIT_TYPE_MESSAGE,
+ 0,
+ G_ADD_PRIVATE (GeditFileBrowserMessageSetRoot))
+
+static void
+gedit_file_browser_message_set_root_finalize (GObject *obj)
+{
+ GeditFileBrowserMessageSetRoot *msg = GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT (obj);
+
+ if (msg->priv->location)
+ {
+ g_object_unref (msg->priv->location);
+ }
+ g_free (msg->priv->virtual);
+
+ G_OBJECT_CLASS (gedit_file_browser_message_set_root_parent_class)->finalize (obj);
+}
+
+static void
+gedit_file_browser_message_set_root_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageSetRoot *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT (obj);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ g_value_set_object (value, msg->priv->location);
+ break;
+ case PROP_VIRTUAL:
+ g_value_set_string (value, msg->priv->virtual);
+ break;
+ }
+}
+
+static void
+gedit_file_browser_message_set_root_set_property (GObject *obj,
+ guint prop_id,
+ GValue const *value,
+ GParamSpec *pspec)
+{
+ GeditFileBrowserMessageSetRoot *msg;
+
+ msg = GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT (obj);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ {
+ if (msg->priv->location)
+ {
+ g_object_unref (msg->priv->location);
+ }
+ msg->priv->location = g_value_dup_object (value);
+ break;
+ }
+ case PROP_VIRTUAL:
+ {
+ g_free (msg->priv->virtual);
+ msg->priv->virtual = g_value_dup_string (value);
+ break;
+ }
+ }
+}
+
+static void
+gedit_file_browser_message_set_root_class_init (GeditFileBrowserMessageSetRootClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_file_browser_message_set_root_finalize;
+
+ object_class->get_property = gedit_file_browser_message_set_root_get_property;
+ object_class->set_property = gedit_file_browser_message_set_root_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_LOCATION,
+ g_param_spec_object ("location",
+ "Location",
+ "Location",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_VIRTUAL,
+ g_param_spec_string ("virtual",
+ "Virtual",
+ "Virtual",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gedit_file_browser_message_set_root_init (GeditFileBrowserMessageSetRoot *message)
+{
+ message->priv = gedit_file_browser_message_set_root_get_instance_private (message);
+}
diff --git a/plugins/filebrowser/messages/gedit-file-browser-message-set-root.h b/plugins/filebrowser/messages/gedit-file-browser-message-set-root.h
new file mode 100644
index 0000000..8b61c50
--- /dev/null
+++ b/plugins/filebrowser/messages/gedit-file-browser-message-set-root.h
@@ -0,0 +1,69 @@
+
+/*
+ * gedit-file-browser-message-set-root.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT_H
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT_H
+
+#include <gedit/gedit-message.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_ROOT (gedit_file_browser_message_set_root_get_type ())
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_ROOT,\
+ GeditFileBrowserMessageSetRoot))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_ROOT,\
+ GeditFileBrowserMessageSetRoot const))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_ROOT,\
+ GeditFileBrowserMessageSetRootClass))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_SET_ROOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_ROOT))
+#define GEDIT_IS_FILE_BROWSER_MESSAGE_SET_ROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_ROOT))
+#define GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GEDIT_TYPE_FILE_BROWSER_MESSAGE_SET_ROOT,\
+ GeditFileBrowserMessageSetRootClass))
+
+typedef struct _GeditFileBrowserMessageSetRoot GeditFileBrowserMessageSetRoot;
+typedef struct _GeditFileBrowserMessageSetRootClass GeditFileBrowserMessageSetRootClass;
+typedef struct _GeditFileBrowserMessageSetRootPrivate GeditFileBrowserMessageSetRootPrivate;
+
+struct _GeditFileBrowserMessageSetRoot
+{
+ GeditMessage parent;
+
+ GeditFileBrowserMessageSetRootPrivate *priv;
+};
+
+struct _GeditFileBrowserMessageSetRootClass
+{
+ GeditMessageClass parent_class;
+};
+
+GType gedit_file_browser_message_set_root_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GEDIT_FILE_BROWSER_MESSAGE_SET_ROOT_H */
diff --git a/plugins/filebrowser/messages/meson.build b/plugins/filebrowser/messages/meson.build
new file mode 100644
index 0000000..ec4fb84
--- /dev/null
+++ b/plugins/filebrowser/messages/meson.build
@@ -0,0 +1,25 @@
+libfilebrowser_public_h += files(
+ 'gedit-file-browser-message-activation.h',
+ 'gedit-file-browser-message-add-filter.h',
+ 'gedit-file-browser-message-extend-context-menu.h',
+ 'gedit-file-browser-message-get-root.h',
+ 'gedit-file-browser-message-get-view.h',
+ 'gedit-file-browser-message-id.h',
+ 'gedit-file-browser-message-id-location.h',
+ 'gedit-file-browser-message-set-emblem.h',
+ 'gedit-file-browser-message-set-markup.h',
+ 'gedit-file-browser-message-set-root.h',
+)
+
+libfilebrowser_sources += files(
+ 'gedit-file-browser-message-activation.c',
+ 'gedit-file-browser-message-add-filter.c',
+ 'gedit-file-browser-message-extend-context-menu.c',
+ 'gedit-file-browser-message-get-root.c',
+ 'gedit-file-browser-message-get-view.c',
+ 'gedit-file-browser-message-id.c',
+ 'gedit-file-browser-message-id-location.c',
+ 'gedit-file-browser-message-set-emblem.c',
+ 'gedit-file-browser-message-set-markup.c',
+ 'gedit-file-browser-message-set-root.c',
+)
diff --git a/plugins/filebrowser/messages/messages.h b/plugins/filebrowser/messages/messages.h
new file mode 100644
index 0000000..4dc0f51
--- /dev/null
+++ b/plugins/filebrowser/messages/messages.h
@@ -0,0 +1,16 @@
+#ifndef GEDIT_FILE_BROWER_MESSAGES_MESSAGES_H
+#define GEDIT_FILE_BROWER_MESSAGES_MESSAGES_H
+
+#include "gedit-file-browser-message-activation.h"
+#include "gedit-file-browser-message-add-filter.h"
+#include "gedit-file-browser-message-extend-context-menu.h"
+#include "gedit-file-browser-message-get-root.h"
+#include "gedit-file-browser-message-get-view.h"
+#include "gedit-file-browser-message-id.h"
+#include "gedit-file-browser-message-id-location.h"
+#include "gedit-file-browser-message-set-emblem.h"
+#include "gedit-file-browser-message-set-markup.h"
+#include "gedit-file-browser-message-set-root.h"
+
+#endif /* GEDIT_FILE_BROWER_MESSAGES_MESSAGES_H */
+
diff --git a/plugins/filebrowser/org.gnome.gedit.plugins.filebrowser.gschema.xml b/plugins/filebrowser/org.gnome.gedit.plugins.filebrowser.gschema.xml
new file mode 100644
index 0000000..8198802
--- /dev/null
+++ b/plugins/filebrowser/org.gnome.gedit.plugins.filebrowser.gschema.xml
@@ -0,0 +1,55 @@
+<schemalist gettext-domain="gedit">
+ <schema id="org.gnome.gedit.plugins.filebrowser" path="/org/gnome/gedit/plugins/filebrowser/">
+ <key name="tree-view" type="b">
+ <default>true</default>
+ <summary>Open With Tree View</summary>
+ <description>Open the tree view when the file browser plugin gets loaded instead of the bookmarks view</description>
+ </key>
+ <key name="root" type="s">
+ <default>''</default>
+ <summary>File Browser Root Directory</summary>
+ <description>The file browser root directory to use when loading the file browser plugin and onload/tree_view is TRUE.</description>
+ </key>
+ <key name="virtual-root" type="s">
+ <default>''</default>
+ <summary>File Browser Virtual Root Directory</summary>
+ <description>The file browser virtual root directory to use when loading the file browser plugin when onload/tree_view is TRUE. The virtual root must always be below the actual root.</description>
+ </key>
+ <key name="enable-remote" type="b">
+ <default>false</default>
+ <summary>Enable Restore of Remote Locations</summary>
+ <description>Sets whether to enable restoring of remote locations.</description>
+ </key>
+ <key name="open-at-first-doc" type="b">
+ <default>true</default>
+ <summary>Set Location to First Document</summary>
+ <description>If TRUE the file browser plugin will view the directory of the first opened document given that the file browser hasn’t been used yet. (Thus this generally applies to opening a document from the command line or opening it with Nautilus, etc.)</description>
+ </key>
+ <key name="filter-mode" flags="org.gnome.gedit.plugins.filebrowser.GeditFileBrowserStoreFilterMode">
+ <default>['hide-hidden', 'hide-binary']</default>
+ <summary>File Browser Filter Mode</summary>
+ <description>This value determines what files get filtered from the file browser. Valid values are: none (filter nothing), hide-hidden (filter hidden files) and hide-binary (filter binary files).</description>
+ </key>
+ <key name="filter-pattern" type="s">
+ <default>''</default>
+ <summary>File Browser Filter Pattern</summary>
+ <description>The filter pattern to filter the file browser with. This filter works on top of the filter_mode.</description>
+ </key>
+ <key name="binary-patterns" type="as">
+ <default>['*.la', '*.lo']</default>
+ <summary>File Browser Binary Patterns</summary>
+ <description>The supplemental patterns to use when filtering binary files.</description>
+ </key>
+ </schema>
+
+ <enum id="org.gnome.gedit.plugins.filebrowser.nautilus.ClickPolicy">
+ <value value="0" nick="single"/>
+ <value value="1" nick="double"/>
+ </enum>
+
+ <schema id="org.gnome.gedit.plugins.filebrowser.nautilus" path="/org/gnome/gedit/plugins/filebrowser/nautilus/">
+ <key name="click-policy" enum="org.gnome.gedit.plugins.filebrowser.nautilus.ClickPolicy">
+ <default>'double'</default>
+ </key>
+ </schema>
+</schemalist>
diff --git a/plugins/filebrowser/resources/gedit-file-browser.gresource.xml b/plugins/filebrowser/resources/gedit-file-browser.gresource.xml
new file mode 100644
index 0000000..273bd26
--- /dev/null
+++ b/plugins/filebrowser/resources/gedit-file-browser.gresource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/gedit/plugins/file-browser">
+ <file preprocess="xml-stripblanks">ui/gedit-file-browser-menus.ui</file>
+ <file preprocess="xml-stripblanks">ui/gedit-file-browser-widget.ui</file>
+ </gresource>
+</gresources>
diff --git a/plugins/filebrowser/resources/meson.build b/plugins/filebrowser/resources/meson.build
new file mode 100644
index 0000000..da2b577
--- /dev/null
+++ b/plugins/filebrowser/resources/meson.build
@@ -0,0 +1,8 @@
+libfilebrowser_res = gnome.compile_resources(
+ 'gedit-file-browser-resources',
+ 'gedit-file-browser.gresource.xml',
+)
+
+libfilebrowser_sources += [
+ libfilebrowser_res.get(0),
+]
diff --git a/plugins/filebrowser/resources/ui/gedit-file-browser-menus.ui b/plugins/filebrowser/resources/ui/gedit-file-browser-menus.ui
new file mode 100644
index 0000000..9134268
--- /dev/null
+++ b/plugins/filebrowser/resources/ui/gedit-file-browser-menus.ui
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <menu id="dir-menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Open</attribute>
+ <attribute name="action">browser.open</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Set Root to Active Document</attribute>
+ <attribute name="action">browser.set_active_root</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_New Folder</attribute>
+ <attribute name="action">browser.new_folder</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">New F_ile</attribute>
+ <attribute name="action">browser.new_file</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Rename…</attribute>
+ <attribute name="action">browser.rename</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Move to Trash</attribute>
+ <attribute name="action">browser.move_to_trash</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Delete</attribute>
+ <attribute name="action">browser.delete</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">Re_fresh View</attribute>
+ <attribute name="action">browser.refresh_view</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_View Folder</attribute>
+ <attribute name="action">browser.view_folder</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Open in Terminal</attribute>
+ <attribute name="action">browser.open_in_terminal</attribute>
+ </item>
+ </section>
+ <submenu>
+ <attribute name="label" translatable="yes">_Filter</attribute>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">Show _Hidden</attribute>
+ <attribute name="action">browser.show_hidden</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Show _Binary</attribute>
+ <attribute name="action">browser.show_binary</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Match Filename</attribute>
+ <attribute name="action">browser.show_match_filename</attribute>
+ </item>
+ </section>
+ </submenu>
+ <section>
+ <attribute name="id">extension-section</attribute>
+ </section>
+ </menu>
+ <menu id="bookmarks-menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Set Root to Active Document</attribute>
+ <attribute name="action">browser.set_active_root</attribute>
+ </item>
+ </section>
+ </menu>
+</interface>
diff --git a/plugins/filebrowser/resources/ui/gedit-file-browser-widget.ui b/plugins/filebrowser/resources/ui/gedit-file-browser-widget.ui
new file mode 100644
index 0000000..e4fb300
--- /dev/null
+++ b/plugins/filebrowser/resources/ui/gedit-file-browser-widget.ui
@@ -0,0 +1,275 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.6 -->
+ <object class="GtkListStore" id="locations_model">
+ <columns>
+ <!-- column-name icon -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name icon name -->
+ <column type="gchararray"/>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ <!-- column-name file -->
+ <column type="GFile"/>
+ <!-- column-name id -->
+ <column type="guint"/>
+ </columns>
+ </object>
+ <object class="GtkPopover" id="locations_popover">
+ <property name="can_focus">True</property>
+ <property name="visible">True</property>
+ <property name="width-request">300</property>
+ <property name="height-request">300</property>
+ <child>
+ <object class="GtkScrolledWindow" id="locations_scrolledwindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <property name="margin">6</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkTreeView" id="locations_treeview">
+ <property name="visible">True</property>
+ <property name="headers_visible">False</property>
+ <property name="can_focus">True</property>
+ <property name="model">locations_model</property>
+ <property name="activate-on-single-click">True</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeview_icon_column">
+ <child>
+ <object class="GtkCellRendererPixbuf" id="treeview_icon_renderer"/>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeview_name_column">
+ <child>
+ <object class="GtkCellRendererText" id="treeview_name_renderer">
+ <property name="ellipsize">end</property>
+ </object>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="locations_treeview_selection"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkMenu" id="location_previous_menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <object class="GtkMenu" id="location_next_menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <template class="GeditFileBrowserWidget" parent="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox" id="toolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin">3</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="previous_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">browser.previous_location</property>
+ <property name="image">previous_image</property>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="next_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">browser.next_location</property>
+ <property name="image">next_image</property>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ </child>
+ <style>
+ <class name="linked"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="button3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">browser.up</property>
+ <property name="image">up_image</property>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="locations_button">
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="use_popover">True</property>
+ <property name="popover">locations_popover</property>
+ <style>
+ <class name="text-button"/>
+ <class name="image-button"/>
+ <class name="small-button"/>
+ </style>
+ <child>
+ <object class="GtkBox" id="locations_button_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="has_focus">False</property>
+ <property name="is_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCellView" id="locations_cellview">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">locations_model</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellview_icon_renderer"/>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="cellview_name_renderer">
+ <property name="ellipsize">end</property>
+ </object>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage" id="locations_button_arrow">
+ <property name="visible">True</property>
+ <property name="valign">baseline</property>
+ <property name="icon_name">pan-down-symbolic</property>
+ </object>
+ <packing>
+ <property name="pack-type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="locations_button_a11y">
+ <property name="accessible-name" translatable="yes">History</property>
+ <property name="accessible-description" translatable="yes">Open history menu</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSearchEntry" id="location_entry">
+ <property name="visible">False</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="primary_icon_name">folder-symbolic</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GeditFileBrowserView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection1"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRevealer" id="filter_entry_revealer">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="reveal_child">False</property>
+ <property name="valign">start</property>
+ <child>
+ <object class="GtkEntry" id="filter_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="placeholder_text">Match Filename</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </template>
+ <object class="GtkImage" id="previous_image">
+ <property name="visible">True</property>
+ <property name="icon_name">go-previous-symbolic</property>
+ <property name="icon-size">2</property>
+ </object>
+ <object class="GtkImage" id="next_image">
+ <property name="visible">True</property>
+ <property name="icon_name">go-next-symbolic</property>
+ <property name="icon-size">2</property>
+ </object>
+ <object class="GtkImage" id="up_image">
+ <property name="visible">True</property>
+ <property name="icon_name">go-up-symbolic</property>
+ <property name="icon-size">2</property>
+ </object>
+</interface>