From 5ded9cba8563f336939400303d6a841d5089b107 Mon Sep 17 00:00:00 2001 From: Perberos Date: Mon, 7 Nov 2011 19:52:18 -0300 Subject: renaming from gedit to pluma --- plugins/filebrowser/Makefile.am | 84 +- .../filebrowser.gedit-plugin.desktop.in | 10 - .../filebrowser.pluma-plugin.desktop.in | 10 + plugins/filebrowser/gedit-file-bookmarks-store.c | 879 ----- plugins/filebrowser/gedit-file-bookmarks-store.h | 90 - .../gedit-file-browser-enum-register.c.template | 20 - .../gedit-file-browser-enum-types.c.template | 45 - .../gedit-file-browser-enum-types.h.template | 29 - plugins/filebrowser/gedit-file-browser-error.h | 41 - .../filebrowser/gedit-file-browser-marshal.list | 5 - plugins/filebrowser/gedit-file-browser-messages.c | 1033 ------ plugins/filebrowser/gedit-file-browser-messages.h | 35 - plugins/filebrowser/gedit-file-browser-plugin.c | 1254 ------- plugins/filebrowser/gedit-file-browser-plugin.h | 71 - plugins/filebrowser/gedit-file-browser-store.c | 3625 -------------------- plugins/filebrowser/gedit-file-browser-store.h | 200 -- plugins/filebrowser/gedit-file-browser-utils.c | 198 -- plugins/filebrowser/gedit-file-browser-utils.h | 27 - plugins/filebrowser/gedit-file-browser-view.c | 1256 ------- plugins/filebrowser/gedit-file-browser-view.h | 84 - .../filebrowser/gedit-file-browser-widget-ui.xml | 54 - plugins/filebrowser/gedit-file-browser-widget.c | 3143 ----------------- plugins/filebrowser/gedit-file-browser-widget.h | 121 - plugins/filebrowser/gedit-file-browser.schemas.in | 97 - plugins/filebrowser/pluma-file-bookmarks-store.c | 879 +++++ plugins/filebrowser/pluma-file-bookmarks-store.h | 90 + .../pluma-file-browser-enum-register.c.template | 20 + .../pluma-file-browser-enum-types.c.template | 45 + .../pluma-file-browser-enum-types.h.template | 29 + plugins/filebrowser/pluma-file-browser-error.h | 41 + .../filebrowser/pluma-file-browser-marshal.list | 5 + plugins/filebrowser/pluma-file-browser-messages.c | 1033 ++++++ plugins/filebrowser/pluma-file-browser-messages.h | 35 + plugins/filebrowser/pluma-file-browser-plugin.c | 1254 +++++++ plugins/filebrowser/pluma-file-browser-plugin.h | 71 + plugins/filebrowser/pluma-file-browser-store.c | 3625 ++++++++++++++++++++ plugins/filebrowser/pluma-file-browser-store.h | 200 ++ plugins/filebrowser/pluma-file-browser-utils.c | 198 ++ plugins/filebrowser/pluma-file-browser-utils.h | 27 + plugins/filebrowser/pluma-file-browser-view.c | 1256 +++++++ plugins/filebrowser/pluma-file-browser-view.h | 84 + .../filebrowser/pluma-file-browser-widget-ui.xml | 54 + plugins/filebrowser/pluma-file-browser-widget.c | 3143 +++++++++++++++++ plugins/filebrowser/pluma-file-browser-widget.h | 121 + plugins/filebrowser/pluma-file-browser.schemas.in | 97 + 45 files changed, 12359 insertions(+), 12359 deletions(-) delete mode 100755 plugins/filebrowser/filebrowser.gedit-plugin.desktop.in create mode 100755 plugins/filebrowser/filebrowser.pluma-plugin.desktop.in delete mode 100755 plugins/filebrowser/gedit-file-bookmarks-store.c delete mode 100755 plugins/filebrowser/gedit-file-bookmarks-store.h delete mode 100755 plugins/filebrowser/gedit-file-browser-enum-register.c.template delete mode 100755 plugins/filebrowser/gedit-file-browser-enum-types.c.template delete mode 100755 plugins/filebrowser/gedit-file-browser-enum-types.h.template delete mode 100755 plugins/filebrowser/gedit-file-browser-error.h delete mode 100755 plugins/filebrowser/gedit-file-browser-marshal.list delete mode 100755 plugins/filebrowser/gedit-file-browser-messages.c delete mode 100755 plugins/filebrowser/gedit-file-browser-messages.h delete mode 100755 plugins/filebrowser/gedit-file-browser-plugin.c delete mode 100755 plugins/filebrowser/gedit-file-browser-plugin.h delete mode 100755 plugins/filebrowser/gedit-file-browser-store.c delete mode 100755 plugins/filebrowser/gedit-file-browser-store.h delete mode 100755 plugins/filebrowser/gedit-file-browser-utils.c delete mode 100755 plugins/filebrowser/gedit-file-browser-utils.h delete mode 100755 plugins/filebrowser/gedit-file-browser-view.c delete mode 100755 plugins/filebrowser/gedit-file-browser-view.h delete mode 100755 plugins/filebrowser/gedit-file-browser-widget-ui.xml delete mode 100755 plugins/filebrowser/gedit-file-browser-widget.c delete mode 100755 plugins/filebrowser/gedit-file-browser-widget.h delete mode 100755 plugins/filebrowser/gedit-file-browser.schemas.in create mode 100755 plugins/filebrowser/pluma-file-bookmarks-store.c create mode 100755 plugins/filebrowser/pluma-file-bookmarks-store.h create mode 100755 plugins/filebrowser/pluma-file-browser-enum-register.c.template create mode 100755 plugins/filebrowser/pluma-file-browser-enum-types.c.template create mode 100755 plugins/filebrowser/pluma-file-browser-enum-types.h.template create mode 100755 plugins/filebrowser/pluma-file-browser-error.h create mode 100755 plugins/filebrowser/pluma-file-browser-marshal.list create mode 100755 plugins/filebrowser/pluma-file-browser-messages.c create mode 100755 plugins/filebrowser/pluma-file-browser-messages.h create mode 100755 plugins/filebrowser/pluma-file-browser-plugin.c create mode 100755 plugins/filebrowser/pluma-file-browser-plugin.h create mode 100755 plugins/filebrowser/pluma-file-browser-store.c create mode 100755 plugins/filebrowser/pluma-file-browser-store.h create mode 100755 plugins/filebrowser/pluma-file-browser-utils.c create mode 100755 plugins/filebrowser/pluma-file-browser-utils.h create mode 100755 plugins/filebrowser/pluma-file-browser-view.c create mode 100755 plugins/filebrowser/pluma-file-browser-view.h create mode 100755 plugins/filebrowser/pluma-file-browser-widget-ui.xml create mode 100755 plugins/filebrowser/pluma-file-browser-widget.c create mode 100755 plugins/filebrowser/pluma-file-browser-widget.h create mode 100755 plugins/filebrowser/pluma-file-browser.schemas.in (limited to 'plugins/filebrowser') diff --git a/plugins/filebrowser/Makefile.am b/plugins/filebrowser/Makefile.am index 22301d5b..6791255a 100755 --- a/plugins/filebrowser/Makefile.am +++ b/plugins/filebrowser/Makefile.am @@ -1,72 +1,72 @@ # filebrowser -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) BUILT_SOURCES = \ - gedit-file-browser-enum-types.h \ - gedit-file-browser-enum-types.c \ - gedit-file-browser-marshal.h \ - gedit-file-browser-marshal.c + pluma-file-browser-enum-types.h \ + pluma-file-browser-enum-types.c \ + pluma-file-browser-marshal.h \ + pluma-file-browser-marshal.c plugin_LTLIBRARIES = libfilebrowser.la NOINST_H_FILES = \ - gedit-file-bookmarks-store.h \ - gedit-file-browser-store.h \ - gedit-file-browser-view.h \ - gedit-file-browser-widget.h \ - gedit-file-browser-error.h \ - gedit-file-browser-utils.h \ - gedit-file-browser-plugin.h \ - gedit-file-browser-messages.h + pluma-file-bookmarks-store.h \ + pluma-file-browser-store.h \ + pluma-file-browser-view.h \ + pluma-file-browser-widget.h \ + pluma-file-browser-error.h \ + pluma-file-browser-utils.h \ + pluma-file-browser-plugin.h \ + pluma-file-browser-messages.h libfilebrowser_la_SOURCES = \ $(BUILT_SOURCES) \ - gedit-file-bookmarks-store.c \ - gedit-file-browser-store.c \ - gedit-file-browser-view.c \ - gedit-file-browser-widget.c \ - gedit-file-browser-utils.c \ - gedit-file-browser-plugin.c \ - gedit-file-browser-messages.c \ + pluma-file-bookmarks-store.c \ + pluma-file-browser-store.c \ + pluma-file-browser-view.c \ + pluma-file-browser-widget.c \ + pluma-file-browser-utils.c \ + pluma-file-browser-plugin.c \ + pluma-file-browser-messages.c \ $(NOINST_H_FILES) libfilebrowser_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libfilebrowser_la_LIBADD = $(GEDIT_LIBS) +libfilebrowser_la_LIBADD = $(PLUMA_LIBS) # UI files (if you use ui for your plugin, list those files here) -uidir = $(GEDIT_PLUGINS_DATA_DIR)/filebrowser -ui_DATA = gedit-file-browser-widget-ui.xml +uidir = $(PLUMA_PLUGINS_DATA_DIR)/filebrowser +ui_DATA = pluma-file-browser-widget-ui.xml -plugin_in_files = filebrowser.gedit-plugin.desktop.in +plugin_in_files = filebrowser.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -gedit-file-browser-enum-types.h: gedit-file-browser-enum-types.h.template $(NOINST_H_FILES) $(GLIB_MKENUMS) - (cd $(srcdir) && $(GLIB_MKENUMS) --template gedit-file-browser-enum-types.h.template $(NOINST_H_FILES)) > $@ +pluma-file-browser-enum-types.h: pluma-file-browser-enum-types.h.template $(NOINST_H_FILES) $(GLIB_MKENUMS) + (cd $(srcdir) && $(GLIB_MKENUMS) --template pluma-file-browser-enum-types.h.template $(NOINST_H_FILES)) > $@ -gedit-file-browser-enum-types.c: gedit-file-browser-enum-types.c.template gedit-file-browser-enum-register.c.template $(NOINST_H_FILES) $(GLIB_MKENUMS) +pluma-file-browser-enum-types.c: pluma-file-browser-enum-types.c.template pluma-file-browser-enum-register.c.template $(NOINST_H_FILES) $(GLIB_MKENUMS) $(AM_V_GEN) (cd $(srcdir) && \ - $(GLIB_MKENUMS) --template gedit-file-browser-enum-types.c.template $(NOINST_H_FILES) && \ - $(GLIB_MKENUMS) --template gedit-file-browser-enum-register.c.template $(NOINST_H_FILES)) > $@ + $(GLIB_MKENUMS) --template pluma-file-browser-enum-types.c.template $(NOINST_H_FILES) && \ + $(GLIB_MKENUMS) --template pluma-file-browser-enum-register.c.template $(NOINST_H_FILES)) > $@ -gedit-file-browser-marshal.h: gedit-file-browser-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=gedit_file_browser_marshal > $@ +pluma-file-browser-marshal.h: pluma-file-browser-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=pluma_file_browser_marshal > $@ -gedit-file-browser-marshal.c: gedit-file-browser-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) echo "#include \"gedit-file-browser-marshal.h\"" > $@ && \ - $(GLIB_GENMARSHAL) $< --body --prefix=gedit_file_browser_marshal >> $@ +pluma-file-browser-marshal.c: pluma-file-browser-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN) echo "#include \"pluma-file-browser-marshal.h\"" > $@ && \ + $(GLIB_GENMARSHAL) $< --body --prefix=pluma_file_browser_marshal >> $@ -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) schemasdir = $(MATECONF_SCHEMA_FILE_DIR) -schemas_in_files = gedit-file-browser.schemas.in +schemas_in_files = pluma-file-browser.schemas.in schemas_DATA = $(schemas_in_files:.schemas.in=.schemas) @INTLTOOL_SCHEMAS_RULE@ @@ -86,10 +86,10 @@ EXTRA_DIST = \ $(ui_DATA) \ $(plugin_in_files) \ $(schemas_in_files) \ - gedit-file-browser-enum-types.h.template \ - gedit-file-browser-enum-types.c.template \ - gedit-file-browser-enum-register.c.template \ - gedit-file-browser-marshal.list + pluma-file-browser-enum-types.h.template \ + pluma-file-browser-enum-types.c.template \ + pluma-file-browser-enum-register.c.template \ + pluma-file-browser-marshal.list CLEANFILES = \ $(plugin_DATA) \ diff --git a/plugins/filebrowser/filebrowser.gedit-plugin.desktop.in b/plugins/filebrowser/filebrowser.gedit-plugin.desktop.in deleted file mode 100755 index 808816c5..00000000 --- a/plugins/filebrowser/filebrowser.gedit-plugin.desktop.in +++ /dev/null @@ -1,10 +0,0 @@ -[Gedit Plugin] -Loader=C -Module=filebrowser -IAge=2 -_Name=File Browser Pane -_Description=Easy file access from the side pane -Icon=system-file-manager -Authors=Jesse van den Kieboom -Copyright=Copyright © 2006 Jesse van den Kieboom -Website=http://www.gedit.org diff --git a/plugins/filebrowser/filebrowser.pluma-plugin.desktop.in b/plugins/filebrowser/filebrowser.pluma-plugin.desktop.in new file mode 100755 index 00000000..bf328f7a --- /dev/null +++ b/plugins/filebrowser/filebrowser.pluma-plugin.desktop.in @@ -0,0 +1,10 @@ +[Pluma Plugin] +Loader=C +Module=filebrowser +IAge=2 +_Name=File Browser Pane +_Description=Easy file access from the side pane +Icon=system-file-manager +Authors=Jesse van den Kieboom +Copyright=Copyright © 2006 Jesse van den Kieboom +Website=http://www.pluma.org diff --git a/plugins/filebrowser/gedit-file-bookmarks-store.c b/plugins/filebrowser/gedit-file-bookmarks-store.c deleted file mode 100755 index 86e7f0c8..00000000 --- a/plugins/filebrowser/gedit-file-bookmarks-store.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * gedit-file-bookmarks-store.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include - -#include "gedit-file-bookmarks-store.h" -#include "gedit-file-browser-utils.h" - -#define GEDIT_FILE_BOOKMARKS_STORE_GET_PRIVATE(object)( \ - G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_FILE_BOOKMARKS_STORE, \ - GeditFileBookmarksStorePrivate)) - -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); - -GEDIT_PLUGIN_DEFINE_TYPE(GeditFileBookmarksStore, gedit_file_bookmarks_store, GTK_TYPE_TREE_STORE) - -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; - } - - if (obj->priv->bookmarks_monitor != NULL) { - g_object_unref (obj->priv->bookmarks_monitor); - obj->priv->bookmarks_monitor = NULL; - } - - G_OBJECT_CLASS (gedit_file_bookmarks_store_parent_class)->dispose (object); -} - -static void -gedit_file_bookmarks_store_finalize (GObject * object) -{ - G_OBJECT_CLASS (gedit_file_bookmarks_store_parent_class)->finalize (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; - object_class->finalize = gedit_file_bookmarks_store_finalize; - - g_type_class_add_private (object_class, sizeof (GeditFileBookmarksStorePrivate)); -} - -static void -gedit_file_bookmarks_store_init (GeditFileBookmarksStore * obj) -{ - obj->priv = GEDIT_FILE_BOOKMARKS_STORE_GET_PRIVATE (obj); -} - -/* Private */ -static void -add_node (GeditFileBookmarksStore *model, - GdkPixbuf *pixbuf, - 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_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) -{ - GdkPixbuf *pixbuf = NULL; - gboolean native; - gchar *newname; - - native = g_file_is_native (file); - - if (native && !g_file_query_exists (file, NULL)) { - return FALSE; - } - - if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_HOME) - pixbuf = gedit_file_browser_utils_pixbuf_from_theme ("user-home", GTK_ICON_SIZE_MENU); - else if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP) - pixbuf = gedit_file_browser_utils_pixbuf_from_theme ("user-desktop", GTK_ICON_SIZE_MENU); - else if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT) - pixbuf = gedit_file_browser_utils_pixbuf_from_theme ("drive-harddisk", GTK_ICON_SIZE_MENU); - - if (pixbuf == NULL) { - /* getting the icon is a sync get_info call, so we just do it for local files */ - if (native) { - pixbuf = gedit_file_browser_utils_pixbuf_from_file (file, GTK_ICON_SIZE_MENU); - } else { - pixbuf = gedit_file_browser_utils_pixbuf_from_theme ("folder", GTK_ICON_SIZE_MENU); - } - } - - if (name == NULL) { - newname = gedit_file_browser_utils_file_basename (file); - } else { - newname = g_strdup (name); - } - - add_node (model, pixbuf, newname, G_OBJECT (file), flags, iter); - - if (pixbuf) - g_object_unref (pixbuf); - - g_free (newname); - - return TRUE; -} - -static void -check_mount_separator (GeditFileBookmarksStore * model, guint flags, - gboolean added) -{ - GtkTreeIter iter; - gboolean found; - - 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, - 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; - GFile * file; - - path = g_get_home_dir (); - if (path != NULL) - { - file = g_file_new_for_path (path); - add_file (model, file, NULL, GEDIT_FILE_BOOKMARKS_STORE_IS_HOME | - GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); - g_object_unref (file); - } - - 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); - } - - 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, - GdkPixbuf **pixbuf, - guint *flags) -{ - GIcon *icon = NULL; - - *flags = GEDIT_FILE_BOOKMARKS_STORE_IS_FS; - *name = NULL; - *pixbuf = NULL; - - if (G_IS_DRIVE (fs)) - { - icon = g_drive_get_icon (G_DRIVE (fs)); - *name = g_drive_get_name (G_DRIVE (fs)); - - *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_DRIVE; - } - else if (G_IS_VOLUME (fs)) - { - icon = g_volume_get_icon (G_VOLUME (fs)); - *name = g_volume_get_name (G_VOLUME (fs)); - - *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_VOLUME; - } - else if (G_IS_MOUNT (fs)) - { - icon = g_mount_get_icon (G_MOUNT (fs)); - *name = g_mount_get_name (G_MOUNT (fs)); - - *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT; - } - - if (icon) - { - *pixbuf = gedit_file_browser_utils_pixbuf_from_icon (icon, GTK_ICON_SIZE_MENU); - g_object_unref (icon); - } -} - - -static void -add_fs (GeditFileBookmarksStore *model, - gpointer fs, - guint flags, - GtkTreeIter *iter) -{ - gchar *name; - GdkPixbuf *pixbuf; - guint fsflags; - - get_fs_properties (fs, &name, &pixbuf, &fsflags); - add_node (model, pixbuf, name, fs, flags | fsflags, iter); - - if (pixbuf) - g_object_unref (pixbuf); - - g_free (name); - check_mount_separator (model, GEDIT_FILE_BOOKMARKS_STORE_IS_FS, TRUE); -} - -static void -process_volume_cb (GVolume *volume, - GeditFileBookmarksStore *model) -{ - GMount *mount; - guint flags = GEDIT_FILE_BOOKMARKS_STORE_NONE; - mount = g_volume_get_mount (volume); - - /* 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; - - 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; - - drives = g_volume_monitor_get_connected_drives (model->priv->volume_monitor); - - g_list_foreach (drives, (GFunc)process_drive_cb, model); - g_list_foreach (drives, (GFunc)g_object_unref, NULL); - g_list_free (drives); -} - -static void -process_volume_nodrive_cb (GVolume *volume, - GeditFileBookmarksStore *model) -{ - GDrive *drive; - - 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; - - volumes = g_volume_monitor_get_volumes (model->priv->volume_monitor); - - g_list_foreach (volumes, (GFunc)process_volume_nodrive_cb, model); - g_list_foreach (volumes, (GFunc)g_object_unref, NULL); - g_list_free (volumes); -} - -static void -process_mount_novolume_cb (GMount *mount, - GeditFileBookmarksStore *model) -{ - GVolume *volume; - - 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; - - mounts = g_volume_monitor_get_mounts (model->priv->volume_monitor); - - g_list_foreach (mounts, (GFunc)process_mount_novolume_cb, model); - g_list_foreach (mounts, (GFunc)g_object_unref, NULL); - g_list_free (mounts); -} - -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; 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; - gboolean ret; - guint flags = GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK; - GtkTreeIter iter; - - file = g_file_new_for_uri (uri); - - 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 void -init_bookmarks (GeditFileBookmarksStore * model) -{ - gchar *bookmarks; - GError *error = NULL; - gchar *contents; - gchar **lines; - gchar **line; - gboolean added = FALSE; - - /* Read the bookmarks file */ - bookmarks = g_build_filename (g_get_home_dir (), - ".gtk-bookmarks", - NULL); - - if (g_file_get_contents (bookmarks, &contents, NULL, &error)) { - lines = g_strsplit (contents, "\n", 0); - - for (line = lines; *line; ++line) { - if (**line) { - 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 */ - if (gedit_utils_is_valid_uri (*line)) { - added |= add_bookmark (model, name, *line); - } - } - } - - g_strfreev (lines); - g_free (contents); - - /* Add a watch */ - if (model->priv->bookmarks_monitor == NULL) { - GFile * file; - - 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", - (GCallback)on_bookmarks_file_changed, - model); - } - } else { - /* The bookmarks file doesn't exist (which is perfectly fine) */ - g_error_free (error); - } - - if (added) { - /* Bookmarks separator */ - add_node (model, 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 caja */ - 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 f1; - guint f2; - gint *flags; - guint sep; - - sep = GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR; - - 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; - - 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)) { - if (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_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; -} - -gchar * -gedit_file_bookmarks_store_get_uri (GeditFileBookmarksStore * model, - GtkTreeIter * iter) -{ - GObject * obj; - GFile * file = NULL; - guint flags; - gchar * 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 = g_object_ref (obj); - } - - g_object_unref (obj); - - if (file) - { - ret = g_file_get_uri (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; - case G_FILE_MONITOR_EVENT_DELETED: // FIXME: shouldn't we also monitor the directory? - /* Remove bookmarks */ - remove_bookmarks (model); - g_object_unref (monitor); - model->priv->bookmarks_monitor = NULL; - break; - default: - break; - } -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-bookmarks-store.h b/plugins/filebrowser/gedit-file-bookmarks-store.h deleted file mode 100755 index bd20911e..00000000 --- a/plugins/filebrowser/gedit-file-bookmarks-store.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * gedit-file-bookmarks-store.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BOOKMARKS_STORE_H__ -#define __GEDIT_FILE_BOOKMARKS_STORE_H__ - -#include - -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_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; -GType gedit_file_bookmarks_store_register_type (GTypeModule * module); - -GeditFileBookmarksStore *gedit_file_bookmarks_store_new (void); -gchar *gedit_file_bookmarks_store_get_uri (GeditFileBookmarksStore * model, - GtkTreeIter * iter); -void gedit_file_bookmarks_store_refresh (GeditFileBookmarksStore * model); - -G_END_DECLS -#endif /* __GEDIT_FILE_BOOKMARKS_STORE_H__ */ - -// ex: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 deleted file mode 100755 index 63a9c562..00000000 --- a/plugins/filebrowser/gedit-file-browser-enum-register.c.template +++ /dev/null @@ -1,20 +0,0 @@ -/*** BEGIN file-header ***/ -void -gedit_file_browser_enum_and_flag_register_type (GTypeModule * module) -{ -/*** END file-header ***/ - -/*** BEGIN file-production ***/ - /* Enumerations from "@filename@" */ - -/*** 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.c.template b/plugins/filebrowser/gedit-file-browser-enum-types.c.template deleted file mode 100755 index 4e89370d..00000000 --- a/plugins/filebrowser/gedit-file-browser-enum-types.c.template +++ /dev/null @@ -1,45 +0,0 @@ -/*** BEGIN file-header ***/ -#include "gedit-file-browser-enum-types.h" - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -/* enumerations from "@filename@" */ -#include "@filename@" - -/*** 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 deleted file mode 100755 index aea4fad9..00000000 --- a/plugins/filebrowser/gedit-file-browser-enum-types.h.template +++ /dev/null @@ -1,29 +0,0 @@ -/*** BEGIN file-header ***/ -#ifndef __GEDIT_FILE_BROWSER_ENUM_TYPES_H__ -#define __GEDIT_FILE_BROWSER_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -/* Enumerations from "@filename@" */ - -/*** 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 deleted file mode 100755 index ec5b8618..00000000 --- a/plugins/filebrowser/gedit-file-browser-error.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * gedit-file-browser-error.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#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__ */ diff --git a/plugins/filebrowser/gedit-file-browser-marshal.list b/plugins/filebrowser/gedit-file-browser-marshal.list deleted file mode 100755 index 5fa72c8b..00000000 --- a/plugins/filebrowser/gedit-file-browser-marshal.list +++ /dev/null @@ -1,5 +0,0 @@ -VOID:UINT,STRING -VOID:STRING,STRING -BOOL:OBJECT,POINTER -BOOL:POINTER -BOOL:VOID diff --git a/plugins/filebrowser/gedit-file-browser-messages.c b/plugins/filebrowser/gedit-file-browser-messages.c deleted file mode 100755 index b587edf1..00000000 --- a/plugins/filebrowser/gedit-file-browser-messages.c +++ /dev/null @@ -1,1033 +0,0 @@ -#include "gedit-file-browser-messages.h" -#include "gedit-file-browser-store.h" -#include - -#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) - -typedef struct -{ - GeditWindow *window; - GeditMessage *message; -} MessageCacheData; - -typedef struct -{ - guint row_inserted_id; - guint row_deleted_id; - guint root_changed_id; - guint begin_loading_id; - guint end_loading_id; - - GList *merge_ids; - GtkActionGroup *merged_actions; - - 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); - GtkUIManager *manager; - GList *groups; - - 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); - - manager = gedit_file_browser_widget_get_ui_manager (widget); - - data->merge_ids = NULL; - data->merged_actions = gtk_action_group_new ("MessageMergedActions"); - - groups = gtk_ui_manager_get_action_groups (manager); - gtk_ui_manager_insert_action_group (manager, data->merged_actions, g_list_length (groups)); - - 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); - GtkUIManager *manager; - GList *item; - - g_hash_table_destroy (data->row_tracking); - g_hash_table_destroy (data->filters); - - manager = gedit_file_browser_widget_get_ui_manager (data->widget); - gtk_ui_manager_remove_action_group (manager, data->merged_actions); - - for (item = data->merge_ids; item; item = item->next) - gtk_ui_manager_remove_ui (manager, GPOINTER_TO_INT (item->data)); - - g_list_free (data->merge_ids); - g_object_unref (data->merged_actions); - - 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; - gchar *uri; - - store = gedit_file_browser_widget_get_browser_store (data->widget); - uri = gedit_file_browser_store_get_virtual_root (store); - - gedit_message_set (message, "uri", uri, NULL); - g_free (uri); -} - -static void -message_set_root_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gchar *root = NULL; - gchar *virtual = NULL; - - gedit_message_get (message, "uri", &root, NULL); - - if (!root) - return; - - if (gedit_message_has_key (message, "virtual")) - gedit_message_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); - - g_free (root); - g_free (virtual); -} - -static void -message_set_emblem_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gchar *id = NULL; - gchar *emblem = NULL; - GtkTreePath *path; - GeditFileBrowserStore *store; - - gedit_message_get (message, "id", &id, "emblem", &emblem, NULL); - - if (!id || !emblem) - { - g_free (id); - g_free (emblem); - - return; - } - - path = track_row_lookup (data, id); - - if (path != NULL) - { - GError *error = NULL; - GdkPixbuf *pixbuf; - - pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), - emblem, - 10, - 0, - &error); - - if (pixbuf) - { - GValue value = { 0, }; - GtkTreeIter iter; - - 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); - } - - g_object_unref (pixbuf); - } - - if (error) - g_error_free (error); - } - - g_free (id); - g_free (emblem); -} - -static gchar * -item_id (const gchar *path, - const gchar *uri) -{ - return g_strconcat (path, "::", uri, NULL); -} - -static gchar * -track_row (WindowData *data, - GeditFileBrowserStore *store, - GtkTreePath *path, - const gchar *uri) -{ - GtkTreeRowReference *ref; - gchar *id; - gchar *pathstr; - - pathstr = gtk_tree_path_to_string (path); - id = item_id (pathstr, uri); - - 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 *uri = NULL; - guint flags = 0; - gchar *track_id; - - store = gedit_file_browser_widget_get_browser_store (data->widget); - - gtk_tree_model_get (GTK_TREE_MODEL (store), iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!uri) - return; - - if (path && gtk_tree_path_get_depth (path) != 0) - track_id = track_row (data, store, path, uri); - else - track_id = NULL; - - gedit_message_set (message, - "id", track_id, - "uri", uri, - NULL); - - if (gedit_message_has_key (message, "is_directory")) - { - gedit_message_set (message, - "is_directory", FILE_IS_DIR (flags), - NULL); - } - - g_free (uri); - g_free (track_id); -} - -static gboolean -custom_message_filter_func (GeditFileBrowserWidget *widget, - GeditFileBrowserStore *store, - GtkTreeIter *iter, - FilterData *data) -{ - WindowData *wdata = get_window_data (data->window); - gchar *uri = NULL; - guint flags = 0; - gboolean filter = FALSE; - GtkTreePath *path; - - gtk_tree_model_get (GTK_TREE_MODEL (store), iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!uri || FILE_IS_DUMMY (flags)) - { - g_free (uri); - 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); - - gedit_message_set (data->message, "filter", filter, NULL); - - gedit_message_bus_send_message_sync (wdata->bus, data->message); - gedit_message_get (data->message, "filter", &filter, NULL); - - return !filter; -} - -static void -message_add_filter_cb (GeditMessageBus *bus, - GeditMessage *message, - GeditWindow *window) -{ - gchar *object_path = NULL; - gchar *method = NULL; - gulong id; - GeditMessageType *message_type; - GeditMessage *cbmessage; - FilterData *filter_data; - WindowData *data = get_window_data (window); - - gedit_message_get (message, - "object_path", &object_path, - "method", &method, - NULL); - - // Check if there exists such a 'callback' message - if (!object_path || !method) - { - g_free (object_path); - g_free (method); - - return; - } - - message_type = gedit_message_bus_lookup (bus, object_path, method); - - if (!message_type) - { - g_free (object_path); - g_free (method); - - return; - } - - // Check if the message type has the correct arguments - if (gedit_message_type_lookup (message_type, "id") != G_TYPE_STRING || - gedit_message_type_lookup (message_type, "uri") != G_TYPE_STRING || - gedit_message_type_lookup (message_type, "is_directory") != G_TYPE_BOOLEAN || - gedit_message_type_lookup (message_type, "filter") != G_TYPE_BOOLEAN) - { - return; - } - - cbmessage = gedit_message_type_instantiate (message_type, - "id", NULL, - "uri", 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; - - gedit_message_get (message, "id", &id, NULL); - - if (!id) - return; - - gedit_file_browser_widget_remove_filter (data->widget, id); -} - -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; - - gedit_message_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; - - gedit_message_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_add_context_item_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - GtkAction *action = NULL; - gchar *path = NULL; - gchar *name; - GtkUIManager *manager; - guint merge_id; - - gedit_message_get (message, - "action", &action, - "path", &path, - NULL); - - if (!action || !path) - { - if (action) - g_object_unref (action); - - g_free (path); - return; - } - - gtk_action_group_add_action (data->merged_actions, action); - manager = gedit_file_browser_widget_get_ui_manager (data->widget); - name = g_strconcat (gtk_action_get_name (action), "MenuItem", NULL); - merge_id = gtk_ui_manager_new_merge_id (manager); - - gtk_ui_manager_add_ui (manager, - merge_id, - path, - name, - gtk_action_get_name (action), - GTK_UI_MANAGER_AUTO, - FALSE); - - if (gtk_ui_manager_get_widget (manager, path)) - { - data->merge_ids = g_list_prepend (data->merge_ids, GINT_TO_POINTER (merge_id)); - gedit_message_set (message, "id", merge_id, NULL); - } - else - { - gedit_message_set (message, "id", 0, NULL); - } - - g_object_unref (action); - g_free (path); - g_free (name); -} - -static void -message_remove_context_item_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - guint merge_id = 0; - GtkUIManager *manager; - - gedit_message_get (message, "id", &merge_id, NULL); - - if (merge_id == 0) - return; - - manager = gedit_file_browser_widget_get_ui_manager (data->widget); - - data->merge_ids = g_list_remove (data->merge_ids, GINT_TO_POINTER (merge_id)); - gtk_ui_manager_remove_ui (manager, merge_id); -} - -static void -message_get_view_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - GeditFileBrowserView *view; - view = gedit_file_browser_widget_get_browser_view (data->widget); - - gedit_message_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, - MESSAGE_OBJECT_PATH, "get_root", - 1, - "uri", G_TYPE_STRING, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "set_root", - 1, - "uri", G_TYPE_STRING, - "virtual", G_TYPE_STRING, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "set_emblem", - 0, - "id", G_TYPE_STRING, - "emblem", G_TYPE_STRING, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "add_filter", - 1, - "object_path", G_TYPE_STRING, - "method", G_TYPE_STRING, - "id", G_TYPE_ULONG, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "remove_filter", - 0, - "id", G_TYPE_ULONG, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "add_context_item", - 1, - "action", GTK_TYPE_ACTION, - "path", G_TYPE_STRING, - "id", G_TYPE_UINT, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "remove_context_item", - 0, - "id", G_TYPE_UINT, - NULL); - - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "up", 0, NULL); - - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_back", 0, NULL); - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_forward", 0, NULL); - - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "refresh", 0, NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "set_show_hidden", - 0, - "active", G_TYPE_BOOLEAN, - NULL); - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "set_show_binary", - 0, - "active", G_TYPE_BOOLEAN, - NULL); - - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_bookmarks", 0, NULL); - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_files", 0, NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "get_view", - 1, - "view", GEDIT_TYPE_FILE_BROWSER_VIEW, - NULL); - - BUS_CONNECT (bus, get_root, data); - BUS_CONNECT (bus, set_root, data); - BUS_CONNECT (bus, set_emblem, data); - BUS_CONNECT (bus, add_filter, window); - BUS_CONNECT (bus, remove_filter, data); - - BUS_CONNECT (bus, add_context_item, data); - BUS_CONNECT (bus, remove_context_item, data); - - 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) -{ - gchar *uri = NULL; - guint flags = 0; - - gtk_tree_model_get (GTK_TREE_MODEL (store), iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - 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); - } - - g_free (uri); -} - -static void -store_row_deleted (GeditFileBrowserStore *store, - GtkTreePath *path, - MessageCacheData *data) -{ - GtkTreeIter iter; - gchar *uri = NULL; - 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_URI, &uri, - 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); - } - - g_free (uri); -} - -static void -store_virtual_root_changed (GeditFileBrowserStore *store, - GParamSpec *spec, - MessageCacheData *data) -{ - WindowData *wdata = get_window_data (data->window); - gchar *uri; - - uri = gedit_file_browser_store_get_virtual_root (store); - - if (!uri) - return; - - gedit_message_set (data->message, - "uri", uri, - NULL); - - gedit_message_bus_send_message_sync (wdata->bus, data->message); - - g_free (uri); -} - -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; - GeditMessageType *inserted_type; - GeditMessageType *deleted_type; - GeditMessageType *begin_loading_type; - GeditMessageType *end_loading_type; - GeditMessageType *root_changed_type; - - GeditMessage *message; - WindowData *data; - - /* Register signals */ - root_changed_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "root_changed", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - NULL); - - begin_loading_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "begin_loading", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - NULL); - - end_loading_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "end_loading", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - NULL); - - inserted_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "inserted", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - "is_directory", G_TYPE_BOOLEAN, - NULL); - - deleted_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "deleted", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - "is_directory", G_TYPE_BOOLEAN, - NULL); - - store = gedit_file_browser_widget_get_browser_store (widget); - - message = gedit_message_type_instantiate (inserted_type, - "id", NULL, - "uri", NULL, - "is_directory", FALSE, - 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 = gedit_message_type_instantiate (deleted_type, - "id", NULL, - "uri", NULL, - "is_directory", FALSE, - NULL); - data->row_deleted_id = - g_signal_connect_data (store, - "row-deleted", - G_CALLBACK (store_row_deleted), - message_cache_data_new (window, message), - (GClosureNotify)message_cache_data_free, - 0); - - message = gedit_message_type_instantiate (root_changed_type, - "id", NULL, - "uri", NULL, - 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 = gedit_message_type_instantiate (begin_loading_type, - "id", NULL, - "uri", NULL, - 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 = gedit_message_type_instantiate (end_loading_type, - "id", NULL, - "uri", NULL, - 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, - GeditMessageType *message_type, - GeditWindow *window) -{ - gchar *identifier = gedit_message_type_identifier (gedit_message_type_get_object_path (message_type), - gedit_message_type_get_method (message_type)); - FilterData *data; - WindowData *wdata = get_window_data (window); - - 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->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); - - cleanup_signals (window); - gedit_message_bus_unregister_all (bus, MESSAGE_OBJECT_PATH); - - window_data_free (window); -} diff --git a/plugins/filebrowser/gedit-file-browser-messages.h b/plugins/filebrowser/gedit-file-browser-messages.h deleted file mode 100755 index e62094e8..00000000 --- a/plugins/filebrowser/gedit-file-browser-messages.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * gedit-file-browser-messages.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2008 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_MESSAGES_H__ -#define __GEDIT_FILE_BROWSER_MESSAGES_H__ - -#include -#include -#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:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-plugin.c b/plugins/filebrowser/gedit-file-browser-plugin.c deleted file mode 100755 index f2da19f5..00000000 --- a/plugins/filebrowser/gedit-file-browser-plugin.c +++ /dev/null @@ -1,1254 +0,0 @@ -/* - * gedit-file-browser-plugin.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#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 WINDOW_DATA_KEY "GeditFileBrowserPluginWindowData" -#define FILE_BROWSER_BASE_KEY "/apps/gedit-2/plugins/filebrowser" -#define CAJA_CLICK_POLICY_BASE_KEY "/apps/caja/preferences" -#define CAJA_CLICK_POLICY_KEY "click_policy" -#define CAJA_ENABLE_DELETE_KEY "enable_delete" -#define CAJA_CONFIRM_TRASH_KEY "confirm_trash" -#define TERMINAL_EXEC_KEY "/desktop/mate/applications/terminal/exec" - -#define GEDIT_FILE_BROWSER_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_FILE_BROWSER_PLUGIN, GeditFileBrowserPluginPrivate)) - -struct _GeditFileBrowserPluginPrivate -{ - gpointer dummy; -}; - -typedef struct _GeditFileBrowserPluginData -{ - GeditFileBrowserWidget * tree_widget; - gulong merge_id; - GtkActionGroup * action_group; - GtkActionGroup * single_selection_action_group; - gboolean auto_root; - gulong end_loading_handle; - gboolean confirm_trash; - - guint click_policy_handle; - guint enable_delete_handle; - guint confirm_trash_handle; -} GeditFileBrowserPluginData; - -static void on_uri_activated_cb (GeditFileBrowserWidget * widget, - gchar const *uri, - GeditWindow * window); -static void on_error_cb (GeditFileBrowserWidget * widget, - guint code, - gchar const *message, - GeditWindow * window); -static void on_model_set_cb (GeditFileBrowserView * widget, - GParamSpec *arg1, - GeditWindow * window); -static void on_virtual_root_changed_cb (GeditFileBrowserStore * model, - GParamSpec * param, - GeditWindow * window); -static void on_filter_mode_changed_cb (GeditFileBrowserStore * model, - GParamSpec * param, - GeditWindow * window); -static void on_rename_cb (GeditFileBrowserStore * model, - const gchar * olduri, - const gchar * newuri, - GeditWindow * window); -static void on_filter_pattern_changed_cb (GeditFileBrowserWidget * widget, - GParamSpec * param, - GeditWindow * window); -static void on_tab_added_cb (GeditWindow * window, - GeditTab * tab, - GeditFileBrowserPluginData * data); -static gboolean on_confirm_delete_cb (GeditFileBrowserWidget * widget, - GeditFileBrowserStore * store, - GList * rows, - GeditWindow * window); -static gboolean on_confirm_no_trash_cb (GeditFileBrowserWidget * widget, - GList * files, - GeditWindow * window); - -GEDIT_PLUGIN_REGISTER_TYPE_WITH_CODE (GeditFileBrowserPlugin, filetree_plugin, \ - gedit_file_browser_enum_and_flag_register_type (type_module); \ - gedit_file_browser_store_register_type (type_module); \ - gedit_file_bookmarks_store_register_type (type_module); \ - gedit_file_browser_view_register_type (type_module); \ - gedit_file_browser_widget_register_type (type_module); \ -) - - -static void -filetree_plugin_init (GeditFileBrowserPlugin * plugin) -{ - plugin->priv = GEDIT_FILE_BROWSER_PLUGIN_GET_PRIVATE (plugin); -} - -static void -filetree_plugin_finalize (GObject * object) -{ - //GeditFileBrowserPlugin * plugin = GEDIT_FILE_BROWSER_PLUGIN (object); - - G_OBJECT_CLASS (filetree_plugin_parent_class)->finalize (object); -} - -static GeditFileBrowserPluginData * -get_plugin_data (GeditWindow * window) -{ - return (GeditFileBrowserPluginData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY)); -} - -static void -on_end_loading_cb (GeditFileBrowserStore * store, - GtkTreeIter * iter, - GeditFileBrowserPluginData * data) -{ - /* Disconnect the signal */ - g_signal_handler_disconnect (store, data->end_loading_handle); - data->end_loading_handle = 0; - data->auto_root = FALSE; -} - -static void -prepare_auto_root (GeditFileBrowserPluginData *data) -{ - GeditFileBrowserStore *store; - - data->auto_root = TRUE; - - store = gedit_file_browser_widget_get_browser_store (data->tree_widget); - - if (data->end_loading_handle != 0) { - g_signal_handler_disconnect (store, data->end_loading_handle); - data->end_loading_handle = 0; - } - - data->end_loading_handle = g_signal_connect (store, - "end-loading", - G_CALLBACK (on_end_loading_cb), - data); -} - -static void -restore_default_location (GeditFileBrowserPluginData *data) -{ - gchar * root; - gchar * virtual_root; - gboolean bookmarks; - gboolean remote; - MateConfClient * client; - - client = mateconf_client_get_default (); - if (!client) - return; - - bookmarks = !mateconf_client_get_bool (client, - FILE_BROWSER_BASE_KEY "/on_load/tree_view", - NULL); - - if (bookmarks) { - g_object_unref (client); - gedit_file_browser_widget_show_bookmarks (data->tree_widget); - return; - } - - root = mateconf_client_get_string (client, - FILE_BROWSER_BASE_KEY "/on_load/root", - NULL); - virtual_root = mateconf_client_get_string (client, - FILE_BROWSER_BASE_KEY "/on_load/virtual_root", - NULL); - - remote = mateconf_client_get_bool (client, - FILE_BROWSER_BASE_KEY "/on_load/enable_remote", - NULL); - - if (root != NULL && *root != '\0') { - GFile *file; - - file = g_file_new_for_uri (root); - - if (remote || g_file_is_native (file)) { - if (virtual_root != NULL && *virtual_root != '\0') { - prepare_auto_root (data); - gedit_file_browser_widget_set_root_and_virtual_root (data->tree_widget, - root, - virtual_root); - } else { - prepare_auto_root (data); - gedit_file_browser_widget_set_root (data->tree_widget, - root, - TRUE); - } - } - - g_object_unref (file); - } - - g_object_unref (client); - g_free (root); - g_free (virtual_root); -} - -static void -restore_filter (GeditFileBrowserPluginData * data) -{ - MateConfClient * client; - gchar *filter_mode; - GeditFileBrowserStoreFilterMode mode; - gchar *pattern; - - client = mateconf_client_get_default (); - if (!client) - return; - - /* Get filter_mode */ - filter_mode = mateconf_client_get_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - NULL); - - /* Filter mode */ - mode = gedit_file_browser_store_filter_mode_get_default (); - - if (filter_mode != NULL) { - if (strcmp (filter_mode, "hidden") == 0) { - mode = GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; - } else if (strcmp (filter_mode, "binary") == 0) { - mode = GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; - } else if (strcmp (filter_mode, "hidden_and_binary") == 0 || - strcmp (filter_mode, "binary_and_hidden") == 0) { - mode = GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN | - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; - } else if (strcmp (filter_mode, "none") == 0 || - *filter_mode == '\0') { - mode = GEDIT_FILE_BROWSER_STORE_FILTER_MODE_NONE; - } - } - - /* Set the filter mode */ - gedit_file_browser_store_set_filter_mode ( - gedit_file_browser_widget_get_browser_store (data->tree_widget), - mode); - - pattern = mateconf_client_get_string (client, - FILE_BROWSER_BASE_KEY "/filter_pattern", - NULL); - - gedit_file_browser_widget_set_filter_pattern (data->tree_widget, - pattern); - - g_object_unref (client); - g_free (filter_mode); - g_free (pattern); -} - -static GeditFileBrowserViewClickPolicy -click_policy_from_string (gchar const *click_policy) -{ - if (click_policy && strcmp (click_policy, "single") == 0) - return GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE; - else - return GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE; -} - -static void -on_click_policy_changed (MateConfClient *client, - guint cnxn_id, - MateConfEntry *entry, - gpointer user_data) -{ - MateConfValue *value; - GeditFileBrowserPluginData * data; - gchar const *click_policy; - GeditFileBrowserViewClickPolicy policy = GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE; - GeditFileBrowserView *view; - - data = (GeditFileBrowserPluginData *)(user_data); - value = mateconf_entry_get_value (entry); - - if (value && value->type == MATECONF_VALUE_STRING) { - click_policy = mateconf_value_get_string (value); - - policy = click_policy_from_string (click_policy); - } - - view = gedit_file_browser_widget_get_browser_view (data->tree_widget); - gedit_file_browser_view_set_click_policy (view, policy); -} - -static void -on_enable_delete_changed (MateConfClient *client, - guint cnxn_id, - MateConfEntry *entry, - gpointer user_data) -{ - MateConfValue *value; - GeditFileBrowserPluginData *data; - gboolean enable = FALSE; - - data = (GeditFileBrowserPluginData *)(user_data); - value = mateconf_entry_get_value (entry); - - if (value && value->type == MATECONF_VALUE_BOOL) - enable = mateconf_value_get_bool (value); - - g_object_set (G_OBJECT (data->tree_widget), "enable-delete", enable, NULL); -} - -static void -on_confirm_trash_changed (MateConfClient *client, - guint cnxn_id, - MateConfEntry *entry, - gpointer user_data) -{ - MateConfValue *value; - GeditFileBrowserPluginData *data; - gboolean enable = FALSE; - - data = (GeditFileBrowserPluginData *)(user_data); - value = mateconf_entry_get_value (entry); - - if (value && value->type == MATECONF_VALUE_BOOL) - enable = mateconf_value_get_bool (value); - - data->confirm_trash = enable; -} - -static void -install_caja_prefs (GeditFileBrowserPluginData *data) -{ - MateConfClient *client; - gchar *pref; - gboolean prefb; - GeditFileBrowserViewClickPolicy policy; - GeditFileBrowserView *view; - - client = mateconf_client_get_default (); - if (!client) - return; - - mateconf_client_add_dir (client, - CAJA_CLICK_POLICY_BASE_KEY, - MATECONF_CLIENT_PRELOAD_NONE, - NULL); - - /* Get click_policy */ - pref = mateconf_client_get_string (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CLICK_POLICY_KEY, - NULL); - - policy = click_policy_from_string (pref); - - view = gedit_file_browser_widget_get_browser_view (data->tree_widget); - gedit_file_browser_view_set_click_policy (view, policy); - - if (pref) { - data->click_policy_handle = - mateconf_client_notify_add (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CLICK_POLICY_KEY, - on_click_policy_changed, - data, - NULL, - NULL); - g_free (pref); - } - - /* Get enable_delete */ - prefb = mateconf_client_get_bool (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_ENABLE_DELETE_KEY, - NULL); - - g_object_set (G_OBJECT (data->tree_widget), "enable-delete", prefb, NULL); - - data->enable_delete_handle = - mateconf_client_notify_add (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_ENABLE_DELETE_KEY, - on_enable_delete_changed, - data, - NULL, - NULL); - - /* Get confirm_trash */ - prefb = mateconf_client_get_bool (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CONFIRM_TRASH_KEY, - NULL); - - data->confirm_trash = prefb; - - data->confirm_trash_handle = - mateconf_client_notify_add (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CONFIRM_TRASH_KEY, - on_confirm_trash_changed, - data, - NULL, - NULL); - g_object_unref (client); -} - -static void -set_root_from_doc (GeditFileBrowserPluginData * data, - GeditDocument * doc) -{ - GFile *file; - GFile *parent; - - if (doc == NULL) - return; - - file = gedit_document_get_location (doc); - if (file == NULL) - return; - - parent = g_file_get_parent (file); - - if (parent != NULL) { - gchar * root; - - root = g_file_get_uri (parent); - - gedit_file_browser_widget_set_root (data->tree_widget, - root, - TRUE); - - g_object_unref (parent); - g_free (root); - } - - g_object_unref (file); -} - -static void -on_action_set_active_root (GtkAction * action, - GeditWindow * window) -{ - GeditFileBrowserPluginData *data; - - data = get_plugin_data (window); - set_root_from_doc (data, - gedit_window_get_active_document (window)); -} - -static gchar * -get_terminal (void) -{ - MateConfClient * client; - gchar * terminal; - - client = mateconf_client_get_default (); - terminal = mateconf_client_get_string (client, - TERMINAL_EXEC_KEY, - NULL); - g_object_unref (client); - - 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 -on_action_open_terminal (GtkAction * action, - GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - gchar * terminal; - gchar * wd = NULL; - gchar * local; - gchar * argv[2]; - GFile * file; - - GtkTreeIter iter; - GeditFileBrowserStore * store; - - data = get_plugin_data (window); - - /* Get the current directory */ - if (!gedit_file_browser_widget_get_selected_directory (data->tree_widget, &iter)) - return; - - store = gedit_file_browser_widget_get_browser_store (data->tree_widget); - gtk_tree_model_get (GTK_TREE_MODEL (store), - &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &wd, - -1); - - if (wd == NULL) - return; - - terminal = get_terminal (); - - file = g_file_new_for_uri (wd); - local = g_file_get_path (file); - g_object_unref (file); - - 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 (wd); - g_free (local); -} - -static void -on_selection_changed_cb (GtkTreeSelection *selection, - GeditWindow *window) -{ - GeditFileBrowserPluginData * data; - GtkTreeView * tree_view; - GtkTreeModel * model; - GtkTreeIter iter; - gboolean sensitive; - gchar * uri; - - data = get_plugin_data (window); - - tree_view = GTK_TREE_VIEW (gedit_file_browser_widget_get_browser_view (data->tree_widget)); - model = gtk_tree_view_get_model (tree_view); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - sensitive = gedit_file_browser_widget_get_selected_directory (data->tree_widget, &iter); - - if (sensitive) { - gtk_tree_model_get (model, &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, -1); - - sensitive = gedit_utils_uri_has_file_scheme (uri); - g_free (uri); - } - - gtk_action_set_sensitive ( - gtk_action_group_get_action (data->single_selection_action_group, - "OpenTerminal"), - sensitive); -} - -#define POPUP_UI "" \ -"" \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -"" - -static GtkActionEntry extra_actions[] = -{ - {"SetActiveRoot", GTK_STOCK_JUMP_TO, N_("_Set root to active document"), - NULL, - N_("Set the root to the active document location"), - G_CALLBACK (on_action_set_active_root)} -}; - -static GtkActionEntry extra_single_selection_actions[] = { - {"OpenTerminal", "utilities-terminal", N_("_Open terminal here"), - NULL, - N_("Open a terminal at the currently opened directory"), - G_CALLBACK (on_action_open_terminal)} -}; - -static void -add_popup_ui (GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - GtkUIManager * manager; - GtkActionGroup * action_group; - GError * error = NULL; - - data = get_plugin_data (window); - manager = gedit_file_browser_widget_get_ui_manager (data->tree_widget); - - action_group = gtk_action_group_new ("FileBrowserPluginExtra"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - extra_actions, - G_N_ELEMENTS (extra_actions), - window); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - data->action_group = action_group; - - action_group = gtk_action_group_new ("FileBrowserPluginSingleSelectionExtra"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - extra_single_selection_actions, - G_N_ELEMENTS (extra_single_selection_actions), - window); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - data->single_selection_action_group = action_group; - - data->merge_id = gtk_ui_manager_add_ui_from_string (manager, - POPUP_UI, - -1, - &error); - - if (data->merge_id == 0) { - g_warning("Unable to merge UI: %s", error->message); - g_error_free(error); - } -} - -static void -remove_popup_ui (GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - GtkUIManager * manager; - - data = get_plugin_data (window); - manager = gedit_file_browser_widget_get_ui_manager (data->tree_widget); - gtk_ui_manager_remove_ui (manager, data->merge_id); - - gtk_ui_manager_remove_action_group (manager, data->action_group); - g_object_unref (data->action_group); - - gtk_ui_manager_remove_action_group (manager, data->single_selection_action_group); - g_object_unref (data->single_selection_action_group); -} - -static void -impl_updateui (GeditPlugin * plugin, GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - GeditDocument * doc; - - data = get_plugin_data (window); - - doc = gedit_window_get_active_document (window); - - gtk_action_set_sensitive (gtk_action_group_get_action (data->action_group, - "SetActiveRoot"), - doc != NULL && - !gedit_document_is_untitled (doc)); -} - -static void -impl_activate (GeditPlugin * plugin, GeditWindow * window) -{ - GeditPanel * panel; - GeditFileBrowserPluginData * data; - GtkWidget * image; - GdkPixbuf * pixbuf; - GeditFileBrowserStore * store; - gchar *data_dir; - - data = g_new0 (GeditFileBrowserPluginData, 1); - - data_dir = gedit_plugin_get_data_dir (plugin); - data->tree_widget = GEDIT_FILE_BROWSER_WIDGET (gedit_file_browser_widget_new (data_dir)); - g_free (data_dir); - - g_signal_connect (data->tree_widget, - "uri-activated", - G_CALLBACK (on_uri_activated_cb), window); - - g_signal_connect (data->tree_widget, - "error", G_CALLBACK (on_error_cb), window); - - g_signal_connect (data->tree_widget, - "notify::filter-pattern", - G_CALLBACK (on_filter_pattern_changed_cb), - window); - - g_signal_connect (data->tree_widget, - "confirm-delete", - G_CALLBACK (on_confirm_delete_cb), - window); - - g_signal_connect (data->tree_widget, - "confirm-no-trash", - G_CALLBACK (on_confirm_no_trash_cb), - window); - - g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW - (gedit_file_browser_widget_get_browser_view - (data->tree_widget))), - "changed", - G_CALLBACK (on_selection_changed_cb), - window); - - panel = gedit_window_get_side_panel (window); - pixbuf = gedit_file_browser_utils_pixbuf_from_theme("system-file-manager", - GTK_ICON_SIZE_MENU); - - if (pixbuf) { - image = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - } else { - image = gtk_image_new_from_stock(GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU); - } - - gtk_widget_show(image); - gedit_panel_add_item (panel, - GTK_WIDGET (data->tree_widget), - _("File Browser"), - image); - gtk_widget_show (GTK_WIDGET (data->tree_widget)); - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data); - - add_popup_ui (window); - - /* Restore filter options */ - restore_filter (data); - - /* Install caja preferences */ - install_caja_prefs (data); - - /* Connect signals to store the last visited location */ - g_signal_connect (gedit_file_browser_widget_get_browser_view (data->tree_widget), - "notify::model", - G_CALLBACK (on_model_set_cb), - window); - - store = gedit_file_browser_widget_get_browser_store (data->tree_widget); - g_signal_connect (store, - "notify::virtual-root", - G_CALLBACK (on_virtual_root_changed_cb), - window); - - g_signal_connect (store, - "notify::filter-mode", - G_CALLBACK (on_filter_mode_changed_cb), - window); - - g_signal_connect (store, - "rename", - G_CALLBACK (on_rename_cb), - window); - - g_signal_connect (window, - "tab-added", - G_CALLBACK (on_tab_added_cb), - data); - - /* Register messages on the bus */ - gedit_file_browser_messages_register (window, data->tree_widget); - - impl_updateui (plugin, window); -} - -static void -impl_deactivate (GeditPlugin * plugin, GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - GeditPanel * panel; - MateConfClient *client; - - data = get_plugin_data (window); - - /* Unregister messages from the bus */ - gedit_file_browser_messages_unregister (window); - - /* Disconnect signals */ - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (on_tab_added_cb), - data); - - client = mateconf_client_get_default (); - mateconf_client_remove_dir (client, CAJA_CLICK_POLICY_BASE_KEY, NULL); - - if (data->click_policy_handle) - mateconf_client_notify_remove (client, data->click_policy_handle); - - if (data->enable_delete_handle) - mateconf_client_notify_remove (client, data->enable_delete_handle); - - if (data->confirm_trash_handle) - mateconf_client_notify_remove (client, data->confirm_trash_handle); - - g_object_unref (client); - remove_popup_ui (window); - - panel = gedit_window_get_side_panel (window); - gedit_panel_remove_item (panel, GTK_WIDGET (data->tree_widget)); - - g_free (data); - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); -} - -static void -filetree_plugin_class_init (GeditFileBrowserPluginClass * klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass * plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = filetree_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_updateui; - - g_type_class_add_private (object_class, - sizeof (GeditFileBrowserPluginPrivate)); -} - -/* Callbacks */ -static void -on_uri_activated_cb (GeditFileBrowserWidget * tree_widget, - gchar const *uri, GeditWindow * window) -{ - gedit_commands_load_uri (window, uri, NULL, 0); -} - -static void -on_error_cb (GeditFileBrowserWidget * tree_widget, - guint code, gchar const *message, GeditWindow * window) -{ - gchar * title; - GtkWidget * dlg; - GeditFileBrowserPluginData * data; - - data = get_plugin_data (window); - - /* Do not show the error when the root has been set automatically */ - if (data->auto_root && (code == GEDIT_FILE_BROWSER_ERROR_SET_ROOT || - code == GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY)) - { - /* Show bookmarks */ - gedit_file_browser_widget_show_bookmarks (data->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 (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 *arg1, - GeditWindow * window) -{ - GeditFileBrowserPluginData * data = get_plugin_data (window); - GtkTreeModel * model; - MateConfClient * client; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (gedit_file_browser_widget_get_browser_view (data->tree_widget))); - - if (model == NULL) - return; - - client = mateconf_client_get_default (); - mateconf_client_set_bool (client, - FILE_BROWSER_BASE_KEY "/on_load/tree_view", - GEDIT_IS_FILE_BROWSER_STORE (model), - NULL); - g_object_unref (client); -} - -static void -on_filter_mode_changed_cb (GeditFileBrowserStore * model, - GParamSpec * param, - GeditWindow * window) -{ - MateConfClient * client; - GeditFileBrowserStoreFilterMode mode; - - client = mateconf_client_get_default (); - - if (!client) - return; - - mode = gedit_file_browser_store_get_filter_mode (model); - - if ((mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) && - (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY)) { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - "hidden_and_binary", - NULL); - } else if (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - "hidden", - NULL); - } else if (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY) { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - "binary", - NULL); - } else { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - "none", - NULL); - } - - g_object_unref (client); - -} - -static void -on_rename_cb (GeditFileBrowserStore * store, - const gchar * olduri, - const gchar * newuri, - GeditWindow * window) -{ - GeditApp * app; - GList * documents; - GList * item; - GeditDocument * doc; - GFile * docfile; - GFile * oldfile; - GFile * newfile; - gchar * uri; - - /* Find all documents and set its uri to newuri where it matches olduri */ - app = gedit_app_get_default (); - documents = gedit_app_get_documents (app); - - oldfile = g_file_new_for_uri (olduri); - newfile = g_file_new_for_uri (newuri); - - for (item = documents; item; item = item->next) { - doc = GEDIT_DOCUMENT (item->data); - uri = gedit_document_get_uri (doc); - - if (!uri) - continue; - - docfile = g_file_new_for_uri (uri); - - if (g_file_equal (docfile, oldfile)) { - gedit_document_set_uri (doc, newuri); - } else { - gchar *relative; - - relative = g_file_get_relative_path (oldfile, docfile); - - if (relative) { - /* relative now contains the part in docfile without - the prefix oldfile */ - - g_object_unref (docfile); - g_free (uri); - - docfile = g_file_get_child (newfile, relative); - uri = g_file_get_uri (docfile); - - gedit_document_set_uri (doc, uri); - } - - g_free (relative); - } - - g_free (uri); - g_object_unref (docfile); - } - - g_object_unref (oldfile); - g_object_unref (newfile); - - g_list_free (documents); -} - -static void -on_filter_pattern_changed_cb (GeditFileBrowserWidget * widget, - GParamSpec * param, - GeditWindow * window) -{ - MateConfClient * client; - gchar * pattern; - - client = mateconf_client_get_default (); - - if (!client) - return; - - g_object_get (G_OBJECT (widget), "filter-pattern", &pattern, NULL); - - if (pattern == NULL) - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_pattern", - "", - NULL); - else - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_pattern", - pattern, - NULL); - - g_free (pattern); -} - -static void -on_virtual_root_changed_cb (GeditFileBrowserStore * store, - GParamSpec * param, - GeditWindow * window) -{ - GeditFileBrowserPluginData * data = get_plugin_data (window); - gchar * root; - gchar * virtual_root; - MateConfClient * client; - - root = gedit_file_browser_store_get_root (store); - - if (!root) - return; - - client = mateconf_client_get_default (); - - if (!client) - return; - - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/on_load/root", - root, - NULL); - - virtual_root = gedit_file_browser_store_get_virtual_root (store); - - if (!virtual_root) { - /* Set virtual to same as root then */ - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/on_load/virtual_root", - root, - NULL); - } else { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/on_load/virtual_root", - virtual_root, - NULL); - } - - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (on_tab_added_cb), - data); - - g_object_unref (client); - g_free (root); - g_free (virtual_root); -} - -static void -on_tab_added_cb (GeditWindow * window, - GeditTab * tab, - GeditFileBrowserPluginData * data) -{ - MateConfClient *client; - gboolean open; - gboolean load_default = TRUE; - - client = mateconf_client_get_default (); - - if (!client) - return; - - open = mateconf_client_get_bool (client, - FILE_BROWSER_BASE_KEY "/open_at_first_doc", - NULL); - - if (open) { - GeditDocument *doc; - gchar *uri; - - doc = gedit_tab_get_document (tab); - - uri = gedit_document_get_uri (doc); - - if (uri != NULL && gedit_utils_uri_has_file_scheme (uri)) { - prepare_auto_root (data); - set_root_from_doc (data, doc); - load_default = FALSE; - } - - g_free (uri); - } - - if (load_default) - restore_default_location (data); - - g_object_unref (client); - - /* Disconnect this signal, it's only called once */ - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (on_tab_added_cb), - data); -} - -static gchar * -get_filename_from_path (GtkTreeModel *model, GtkTreePath *path) -{ - GtkTreeIter iter; - gchar *uri; - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - -1); - - return gedit_file_browser_utils_uri_basename (uri); -} - -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, - GTK_STOCK_DELETE, - NULL); - g_free (secondary); - - return result; -} - -static gboolean -on_confirm_delete_cb (GeditFileBrowserWidget *widget, - GeditFileBrowserStore *store, - GList *paths, - GeditWindow *window) -{ - gchar *normal; - gchar *message; - gchar *secondary; - gboolean result; - GeditFileBrowserPluginData *data; - - data = get_plugin_data (window); - - if (!data->confirm_trash) - return TRUE; - - 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 (window, - GTK_MESSAGE_QUESTION, - message, - secondary, - GTK_STOCK_DELETE, - NULL); - - g_free (message); - - return result; -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-plugin.h b/plugins/filebrowser/gedit-file-browser-plugin.h deleted file mode 100755 index 19ca86bf..00000000 --- a/plugins/filebrowser/gedit-file-browser-plugin.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * gedit-file-browser-plugin.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_PLUGIN_H__ -#define __GEDIT_FILE_BROWSER_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_FILE_BROWSER_PLUGIN (filetree_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 -{ - GeditPlugin parent_instance; - - /*< private > */ - GeditFileBrowserPluginPrivate *priv; -}; - - - -struct _GeditFileBrowserPluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType filetree_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule * module); - -G_END_DECLS -#endif /* __GEDIT_FILE_BROWSER_PLUGIN_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-store.c b/plugins/filebrowser/gedit-file-browser-store.c deleted file mode 100755 index 6c4f5b51..00000000 --- a/plugins/filebrowser/gedit-file-browser-store.c +++ /dev/null @@ -1,3625 +0,0 @@ -/* - * gedit-file-browser-store.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "gedit-file-browser-store.h" -#include "gedit-file-browser-marshal.h" -#include "gedit-file-browser-enum-types.h" -#include "gedit-file-browser-error.h" -#include "gedit-file-browser-utils.h" - -#define GEDIT_FILE_BROWSER_STORE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ - GEDIT_TYPE_FILE_BROWSER_STORE, \ - GeditFileBrowserStorePrivate)) - -#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; - gchar * virtual_root; - GMountOperation * operation; - GCancellable * cancellable; -} MountInfo; - -struct _FileBrowserNode -{ - GFile *file; - guint flags; - gchar *name; - - GdkPixbuf *icon; - GdkPixbuf *emblem; - - FileBrowserNode *parent; - gint pos; - gboolean inserted; -}; - -struct _FileBrowserNodeDir -{ - FileBrowserNode node; - GSList *children; - GHashTable *hidden_file_hash; - - 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; - - 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); - -GEDIT_PLUGIN_DEFINE_TYPE_WITH_CODE (GeditFileBrowserStore, gedit_file_browser_store, - G_TYPE_OBJECT, - GEDIT_PLUGIN_IMPLEMENT_INTERFACE (gedit_file_browser_store_tree_model, - GTK_TYPE_TREE_MODEL, - gedit_file_browser_store_iface_init) - GEDIT_PLUGIN_IMPLEMENT_INTERFACE (gedit_file_browser_store_drag_source, - GTK_TYPE_TREE_DRAG_SOURCE, - gedit_file_browser_store_drag_source_init)) - -/* Properties */ -enum { - PROP_0, - - PROP_ROOT, - PROP_VIRTUAL_ROOT, - PROP_FILTER_MODE -}; - -/* Signals */ -enum -{ - BEGIN_LOADING, - END_LOADING, - ERROR, - NO_TRASH, - RENAME, - BEGIN_REFRESH, - END_REFRESH, - UNLOAD, - 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); - GSList *item; - - /* Free all the nodes */ - file_browser_node_free (obj, obj->priv->root); - - /* Cancel any asynchronous operations */ - for (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) -{ - gchar * uri; - - if (node == NULL || !node->file) { - g_value_set_string (value, NULL); - } else { - uri = g_file_get_uri (node->file); - g_value_take_string (value, uri); - } -} - -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; - 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_FILTER_MODE: - gedit_file_browser_store_set_filter_mode (obj, - g_value_get_flags (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_string ("root", - "Root", - "The root uri", - NULL, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_VIRTUAL_ROOT, - g_param_spec_string ("virtual-root", - "Virtual Root", - "The virtual root uri", - NULL, - 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)); - - 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, - g_cclosure_marshal_VOID__BOXED, 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, - g_cclosure_marshal_VOID__BOXED, 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, - gedit_file_browser_marshal_VOID__UINT_STRING, - 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, - gedit_file_browser_marshal_BOOL__POINTER, - 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, - gedit_file_browser_marshal_VOID__STRING_STRING, - G_TYPE_NONE, 2, - G_TYPE_STRING, - G_TYPE_STRING); - 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, - g_cclosure_marshal_VOID__VOID, - 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, - g_cclosure_marshal_VOID__VOID, - 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, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - - g_type_class_add_private (object_class, - sizeof (GeditFileBrowserStorePrivate)); -} - -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_PRIVATE (obj); - - obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_URI] = - 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_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_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) -{ - gint * indices, depth, i; - FileBrowserNode * node; - GeditFileBrowserStore * model; - gint num; - - 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 (i = 0; i < depth; ++i) { - GSList * item; - - if (node == NULL) - return FALSE; - - num = 0; - - if (!NODE_IS_DIR (node)) - return FALSE; - - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) { - FileBrowserNode * child; - - child = (FileBrowserNode *) (item->data); - - if (model_node_inserted (model, child)) { - if (num == indices[i]) { - node = child; - 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; - gint num = 0; - - path = gtk_tree_path_new (); - - while (node != model->priv->virtual_root) { - GSList *item; - - if (node->parent == NULL) { - gtk_tree_path_free (path); - return NULL; - } - - num = 0; - - for (item = FILE_BROWSER_NODE_DIR (node->parent)->children; item; item = item->next) { - FileBrowserNode *check; - - 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_URI: - set_gvalue_from_node (value, node); - break; - case GEDIT_FILE_BROWSER_STORE_COLUMN_NAME: - g_value_set_string (value, node->name); - 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_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 * item; - 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 (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; - GSList * item; - - 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 (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) -{ - GSList *item; - - if (!NODE_IS_DIR (node)) - return FALSE; - - for (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; - GSList *item; - 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 (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; - GSList *item; - 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 (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; - gchar *uri; - 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_URI, &uri, - -1); - - g_assert (uri); - - uris[0] = uri; - ret = gtk_selection_data_set_uris (selection_data, uris); - - g_free (uri); - - 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; - else if (FILTER_BINARY (model->priv->filter_mode) && - (!NODE_IS_TEXT (node) && !NODE_IS_DIR (node))) - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED; - else 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, *k2; - gint result; - - k1 = g_utf8_collate_key_for_filename (node1->name, -1); - k2 = g_utf8_collate_key_for_filename (node2->name, -1); - - result = strcmp (k1, k2); - - g_free (k1); - g_free (k2); - - return result; - } -} - -static gint -model_sort_default (FileBrowserNode * node1, FileBrowserNode * node2) -{ - gint f1; - gint f2; - - f1 = NODE_IS_DUMMY (node1); - 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; - } - - f1 = NODE_IS_HIDDEN (node1); - f2 = NODE_IS_HIDDEN (node2); - - if (f1 != f2) - { - return f2 ? -1 : 1; - } - - return collate_nodes (node1, node2); -} - -static void -model_resort_node (GeditFileBrowserStore * model, FileBrowserNode * node) -{ - FileBrowserNodeDir *dir; - GSList *item; - FileBrowserNode *child; - gint pos = 0; - GtkTreeIter iter; - GtkTreePath *path; - gint *neworder; - - 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 { - /* Store current positions */ - for (item = dir->children; item; item = item->next) { - 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 (item = dir->children; item; item = item->next) { - 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, - const GtkTreePath * path) -{ - GtkTreePath *copy = gtk_tree_path_copy (path); - - /* Delete a copy of the actual path here because the row-deleted - signal may alter the 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) { - node->inserted = FALSE; - row_deleted (model, *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); - - if (node->file) { - node->name = gedit_file_browser_utils_file_basename (node->file); - } else { - node->name = 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) -{ - GSList *item; - - if (node == NULL) - return; - - if (NODE_IS_DIR (node)) { - for (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) -{ - gchar *uri; - - if (node == NULL) - return; - - if (NODE_IS_DIR (node)) - { - FileBrowserNodeDir *dir; - - 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 (dir->hidden_file_hash) - g_hash_table_destroy (dir->hidden_file_hash); - } - - if (node->file) - { - uri = g_file_get_uri (node->file); - g_signal_emit (model, model_signals[UNLOAD], 0, uri); - - g_free (uri); - g_object_unref (node->file); - } - - if (node->icon) - g_object_unref (node->icon); - - if (node->emblem) - g_object_unref (node->emblem); - - g_free (node->name); - - 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; - GSList *item; - - 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 (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) - { - node->inserted = FALSE; - row_deleted (model, path); - } - - if (free_path) - gtk_tree_path_free (path); - - parent = node->parent; - - if (free_nodes) { - /* Remove the node from the parents children list */ - if (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; - FileBrowserNodeDir *dir; - FileBrowserNode *dummy; - - 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) { - dir = FILE_BROWSER_NODE_DIR (model->priv->virtual_root); - - if (dir->children != NULL) { - dummy = (FileBrowserNode *) (dir->children->data); - - if (NODE_IS_DUMMY (dummy) - && model_node_visibility (model, dummy)) { - path = gtk_tree_path_new_first (); - - dummy->inserted = FALSE; - row_deleted (model, 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); - } - - 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->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)) { - FileBrowserNode *dummy; - GtkTreeIter iter; - GtkTreePath *path; - guint flags; - FileBrowserNodeDir *dir; - - dir = FILE_BROWSER_NODE_DIR (node); - - 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; - - dummy->inserted = FALSE; - row_deleted (model, path); - gtk_tree_path_free (path); - } - } - } -} - -static void -insert_node_sorted (GeditFileBrowserStore * model, - FileBrowserNode * child, - FileBrowserNode * parent) -{ - FileBrowserNodeDir *dir; - - 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)) { - GtkTreeIter iter; - GtkTreePath *path; - - iter.user_data = child; - path = gedit_file_browser_store_get_path_real (model, 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) -{ - GSList *sorted_children; - GSList *child; - GSList *prev; - GSList *l; - FileBrowserNodeDir *dir; - - dir = FILE_BROWSER_NODE_DIR (parent); - - sorted_children = g_slist_sort (children, (GCompareFunc) model->priv->sort_func); - - child = sorted_children; - l = dir->children; - prev = NULL; - - 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 void -file_browser_node_set_from_info (GeditFileBrowserStore * model, - FileBrowserNode * node, - GFileInfo * info, - gboolean isadded) -{ - FileBrowserNodeDir * dir; - gchar const * content; - gchar const * name; - 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; - } - - dir = FILE_BROWSER_NODE_DIR (node->parent); - name = g_file_info_get_name (info); - - if (g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info)) - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - else if (dir != NULL && dir->hidden_file_hash != NULL && - g_hash_table_lookup (dir->hidden_file_hash, name) != NULL) - 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 || - g_content_type_is_unknown (content) || - g_content_type_is_a (content, "text/plain")) - 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) -{ - GSList *item; - - for (item = children; item; item = item->next) { - FileBrowserNode *node; - - 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) -{ - GList *item; - GSList *nodes = NULL; - - for (item = files; item; item = item->next) { - GFileInfo *info = G_FILE_INFO (item->data); - GFileType type; - gchar const * name; - GFile * file; - FileBrowserNode *node; - - type = g_file_info_get_file_type (info); - - /* 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)) { - continue; - } - - file = g_file_get_child (parent->file, name); - - if ((node = node_list_contains_file (original_children, file)) == NULL) { - - 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); - - 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); - } - - if (node->icon == NULL) { - node->icon = gedit_file_browser_utils_pixbuf_from_theme ("folder", GTK_ICON_SIZE_MENU); - } - - model_add_node (model, node, parent); - } - - return node; -} - -/* Read is sync, but we only do it for local files */ -static void -parse_dot_hidden_file (FileBrowserNode *directory) -{ - gsize file_size; - char *file_contents; - GFile *child; - GFileInfo *info; - GFileType type; - int i; - FileBrowserNodeDir * dir = FILE_BROWSER_NODE_DIR (directory); - - /* FIXME: We only support .hidden on file: uri's for the moment. - * Need to figure out if we should do this async or sync to extend - * it to all types of uris. - */ - if (directory->file == NULL || !g_file_is_native (directory->file)) { - return; - } - - child = g_file_get_child (directory->file, ".hidden"); - info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL); - - type = info ? g_file_info_get_file_type (info) : G_FILE_TYPE_UNKNOWN; - - if (info) - g_object_unref (info); - - if (type != G_FILE_TYPE_REGULAR) { - g_object_unref (child); - - return; - } - - if (!g_file_load_contents (child, NULL, &file_contents, &file_size, NULL, NULL)) { - g_object_unref (child); - return; - } - - g_object_unref (child); - - if (dir->hidden_file_hash == NULL) { - dir->hidden_file_hash = - g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - } - - /* Now parse the data */ - i = 0; - while (i < file_size) { - int start; - - start = i; - while (i < file_size && file_contents[i] != '\n') { - i++; - } - - if (i > start) { - char *hidden_filename; - - hidden_filename = g_strndup (file_contents + start, i - start); - g_hash_table_insert (dir->hidden_file_hash, - hidden_filename, hidden_filename); - } - - i++; - - } - - g_free (file_contents); -} - -static void -on_directory_monitor_event (GFileMonitor * monitor, - GFile * file, - GFile * other_file, - GFileMonitorEvent event_type, - FileBrowserNode * parent) -{ - FileBrowserNode *node; - FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (parent); - - 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_free (async); -} - -static void -model_iterate_next_files_cb (GFileEnumerator * enumerator, - GAsyncResult * result, - AsyncNode * async) -{ - GList * files; - GError * error = NULL; - FileBrowserNodeDir * dir = async->dir; - FileBrowserNode * parent = (FileBrowserNode *)dir; - - files = g_file_enumerator_next_files_finish (enumerator, result, &error); - - if (files == NULL) { - g_file_enumerator_close (enumerator, NULL, NULL); - 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.mate.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); - 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; - } - - enumerator = g_file_enumerate_children_finish (file, result, &error); - - if (enumerator == NULL) { - /* 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); - - /* Read the '.hidden' file first (if any) */ - parse_dot_hidden_file (node); - - dir->cancellable = g_cancellable_new (); - - async = g_new (AsyncNode, 1); - 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 *next; - FileBrowserNode *prev; - FileBrowserNode *check; - FileBrowserNodeDir *dir; - GSList *item; - GSList *copy; - GtkTreePath *empty = NULL; - - prev = node; - next = prev->parent; - - /* 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 (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 (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; - GList * item; - 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 (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; - GSList *children; - - if (!NODE_IS_DIR (parent)) - return NULL; - - dir = FILE_BROWSER_NODE_DIR (parent); - - for (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, gchar const * 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_string - (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); - g_free (mount_info->virtual_root); - - g_free (mount_info); -} - -static GeditFileBrowserStoreResult -model_mount_root (GeditFileBrowserStore * model, gchar const * 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_new(MountInfo, 1); - mount_info->model = model; - mount_info->virtual_root = g_strdup (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 (gchar const *root) -{ - GeditFileBrowserStore *obj = - GEDIT_FILE_BROWSER_STORE (g_object_new - (GEDIT_TYPE_FILE_BROWSER_STORE, - NULL)); - - gedit_file_browser_store_set_root (obj, root); - return obj; -} - -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 (column == - GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM); - g_return_if_fail (G_VALUE_HOLDS_OBJECT (value)); - g_return_if_fail (iter != NULL); - g_return_if_fail (iter->user_data != NULL); - - data = g_value_get_object (value); - - if (data) - g_return_if_fail (GDK_IS_PIXBUF (data)); - - node = (FileBrowserNode *) (iter->user_data); - - 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); - - 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_string - (GeditFileBrowserStore * model, gchar const *root) { - GFile *file; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - - file = g_file_new_for_uri (root); - if (file == NULL) { - g_warning ("Invalid uri (%s)", root); - 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, file)) { - g_object_unref (file); - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - } - - /* Check if uri is the root itself */ - if (g_file_equal (model->priv->root->file, file)) { - g_object_unref (file); - - /* 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 (file, model->priv->root->file)) { - gchar *str, *str1; - - str = g_file_get_parse_name (model->priv->root->file); - str1 = g_file_get_parse_name (file); - - g_warning - ("Virtual root (%s) is not below actual root (%s)", - str1, str); - - g_free (str); - g_free (str1); - - g_object_unref (file); - return GEDIT_FILE_BROWSER_STORE_RESULT_ERROR; - } - - set_virtual_root_from_file (model, file); - g_object_unref (file); - - 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, - gchar const *root, - gchar const *virtual_root) -{ - GFile * file = NULL; - GFile * vfile = NULL; - 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) { - file = g_file_new_for_uri (root); - } - - if (root != NULL && model->priv->root != NULL) { - equal = g_file_equal (file, model->priv->root->file); - - if (equal && virtual_root == NULL) { - g_object_unref (file); - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - } - } - - if (virtual_root) { - vfile = g_file_new_for_uri (virtual_root); - - if (equal && g_file_equal (vfile, model->priv->virtual_root->file)) { - if (file) - g_object_unref (file); - - g_object_unref (vfile); - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - } - - g_object_unref (vfile); - } - - /* 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 (file != NULL) { - /* Create the root node */ - node = file_browser_node_dir_new (model, file, NULL); - - g_object_unref (file); - - 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, - gchar const *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); -} - -gchar * -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_get_uri (model->priv->root->file); -} - -gchar * -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_get_uri (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; - GSList *item; - - 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 (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); -} - -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) -{ - FileBrowserNodeDir * dir; - GSList * child; - GFile * parent; - gchar * base; - - if (!node->file) { - return; - } - - if (reparent) { - parent = node->parent->file; - 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)) { - dir = FILE_BROWSER_NODE_DIR (node); - - for (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; - gchar * olduri; - gchar * newuri; - 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; - } - - olduri = g_file_get_uri (previous); - newuri = g_file_get_uri (node->file); - - g_signal_emit (model, model_signals[RENAME], 0, olduri, newuri); - - g_object_unref (previous); - g_free (olduri); - g_free (newuri); - - 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_foreach (data->files, (GFunc)g_object_unref, NULL); - g_list_free (data->files); - - if (!data->removed) - data->model->priv->async_handles = g_slist_remove (data->model->priv->async_handles, data); - - g_free (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; -} - -typedef struct { - GeditFileBrowserStore * model; - GFile * file; -} IdleDelete; - -static gboolean -file_deleted (IdleDelete * data) -{ - FileBrowserNode * node; - node = model_find_node (data->model, NULL, data->file); - - if (node != NULL) - model_remove_node (data->model, node, NULL, TRUE); - - return FALSE; -} - -static gboolean -delete_files (GIOSchedulerJob * job, - GCancellable * cancellable, - AsyncData * data) -{ - GFile * file; - GError * error = NULL; - gboolean ret; - gint code; - IdleDelete delete; - - /* Check if our job is done */ - if (!data->iter) - return FALSE; - - /* Move a file to the trash */ - file = G_FILE (data->iter->data); - - if (data->trash) - ret = g_file_trash (file, cancellable, &error); - else - ret = g_file_delete (file, cancellable, &error); - - if (ret) { - delete.model = data->model; - delete.file = file; - - /* Remove the file from the model in the main loop */ - g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc)file_deleted, &delete, NULL); - } else if (!ret && error) { - code = error->code; - g_error_free (error); - - if (data->trash && code == G_IO_ERROR_NOT_SUPPORTED) { - /* Trash is not supported on this system ... */ - if (g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc)emit_no_trash, data, NULL)) - { - /* Changes this into a delete job */ - data->trash = FALSE; - data->iter = data->files; - - return TRUE; - } - - /* End the job */ - return FALSE; - } else if (code == G_IO_ERROR_CANCELLED) { - /* Job has been cancelled, just let the job end */ - return FALSE; - } - } - - /* Process the next item */ - data->iter = data->iter->next; - return TRUE; -} - -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_new (AsyncData, 1); - - 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); - - g_io_scheduler_push_job ((GIOSchedulerJobFunc)delete_files, - data, - (GDestroyNotify)async_data_free, - G_PRIORITY_DEFAULT, - data->cancellable); - 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_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - 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, _("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, _("directory")); - - 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; -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-store.h b/plugins/filebrowser/gedit-file-browser-store.h deleted file mode 100755 index f31da327..00000000 --- a/plugins/filebrowser/gedit-file-browser-store.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * gedit-file-browser-store.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_STORE_H__ -#define __GEDIT_FILE_BROWSER_STORE_H__ - -#include - -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_NAME, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, - 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, - const gchar * olduri, - const gchar * newuri); - void (*begin_refresh) (GeditFileBrowserStore * model); - void (*end_refresh) (GeditFileBrowserStore * model); - void (*unload) (GeditFileBrowserStore * model, - const gchar * uri); -}; - -GType gedit_file_browser_store_get_type (void) G_GNUC_CONST; -GType gedit_file_browser_store_register_type (GTypeModule * module); - -GeditFileBrowserStore *gedit_file_browser_store_new (gchar const *root); - -GeditFileBrowserStoreResult -gedit_file_browser_store_set_root_and_virtual_root (GeditFileBrowserStore * model, - gchar const *root, - gchar const *virtual_root); -GeditFileBrowserStoreResult -gedit_file_browser_store_set_root (GeditFileBrowserStore * model, - gchar const *root); -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root (GeditFileBrowserStore * model, - GtkTreeIter * iter); -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root_from_string (GeditFileBrowserStore * model, - gchar const *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); -gchar * gedit_file_browser_store_get_root (GeditFileBrowserStore * model); -gchar * 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); -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); - -G_END_DECLS -#endif /* __GEDIT_FILE_BROWSER_STORE_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-utils.c b/plugins/filebrowser/gedit-file-browser-utils.c deleted file mode 100755 index d8f4028a..00000000 --- a/plugins/filebrowser/gedit-file-browser-utils.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * gedit-file-bookmarks-store.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "gedit-file-browser-utils.h" -#include - -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); - gtk_icon_info_free (info); - - return ret; -} - -GdkPixbuf * -gedit_file_browser_utils_pixbuf_from_file (GFile * file, - GtkIconSize size) -{ - GIcon * icon; - GFileInfo * info; - GdkPixbuf * ret = NULL; - - info = g_file_query_info (file, - G_FILE_ATTRIBUTE_STANDARD_ICON, - G_FILE_QUERY_INFO_NONE, - NULL, - NULL); - - if (!info) - return NULL; - - icon = 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_file_basename (GFile * file) -{ - gchar *uri; - gchar *ret; - - uri = g_file_get_uri (file); - ret = gedit_file_browser_utils_uri_basename (uri); - g_free (uri); - - return ret; -} - -gchar * -gedit_file_browser_utils_uri_basename (gchar const * uri) -{ - return gedit_utils_basename_for_display (uri); -} - -gboolean -gedit_file_browser_utils_confirmation_dialog (GeditWindow * window, - GtkMessageType type, - gchar const *message, - gchar const *secondary, - gchar const * button_stock, - gchar const * button_label) -{ - GtkWidget *dlg; - gint ret; - GtkWidget *button; - - 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); - - /* Add a cancel button */ - button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); - gtk_widget_show (button); - - GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); - gtk_dialog_add_action_widget (GTK_DIALOG (dlg), - button, - GTK_RESPONSE_CANCEL); - - /* Add custom button */ - button = gtk_button_new_from_stock (button_stock); - - if (button_label) { - gtk_button_set_use_stock (GTK_BUTTON (button), FALSE); - gtk_button_set_label (GTK_BUTTON (button), button_label); - } - - gtk_widget_show (button); - GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); - gtk_dialog_add_action_widget (GTK_DIALOG (dlg), - button, - GTK_RESPONSE_OK); - - ret = gtk_dialog_run (GTK_DIALOG (dlg)); - gtk_widget_destroy (dlg); - - return (ret == GTK_RESPONSE_OK); -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-utils.h b/plugins/filebrowser/gedit-file-browser-utils.h deleted file mode 100755 index fc9acbce..00000000 --- a/plugins/filebrowser/gedit-file-browser-utils.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __GEDIT_FILE_BROWSER_UTILS_H__ -#define __GEDIT_FILE_BROWSER_UTILS_H__ - -#include -#include - -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); - -gchar * gedit_file_browser_utils_file_basename (GFile * file); -gchar * gedit_file_browser_utils_uri_basename (gchar const * uri); - -gboolean gedit_file_browser_utils_confirmation_dialog (GeditWindow * window, - GtkMessageType type, - gchar const *message, - gchar const *secondary, - gchar const * button_stock, - gchar const * button_label); - -#endif /* __GEDIT_FILE_BROWSER_UTILS_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-view.c b/plugins/filebrowser/gedit-file-browser-view.c deleted file mode 100755 index 05733da1..00000000 --- a/plugins/filebrowser/gedit-file-browser-view.c +++ /dev/null @@ -1,1256 +0,0 @@ -/* - * gedit-file-browser-view.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include - -#include "gedit-file-browser-store.h" -#include "gedit-file-bookmarks-store.h" -#include "gedit-file-browser-view.h" -#include "gedit-file-browser-marshal.h" -#include "gedit-file-browser-enum-types.h" - -#define GEDIT_FILE_BROWSER_VIEW_GET_PRIVATE(object)( \ - G_TYPE_INSTANCE_GET_PRIVATE((object), \ - GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserViewPrivate)) - -struct _GeditFileBrowserViewPrivate -{ - GtkTreeViewColumn *column; - GtkCellRenderer *pixbuf_renderer; - GtkCellRenderer *text_renderer; - - GtkTreeModel *model; - GtkTreeRowReference *editable; - - GdkCursor *busy_cursor; - - /* CLick policy */ - GeditFileBrowserViewClickPolicy click_policy; - GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */ - 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 } -}; - -GEDIT_PLUGIN_DEFINE_TYPE (GeditFileBrowserView, gedit_file_browser_view, - GTK_TYPE_TREE_VIEW) - -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, - gchar const * uri, - 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) - gdk_cursor_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; - } - - gdk_cursor_unref (obj->priv->busy_cursor); - - G_OBJECT_CLASS (gedit_file_browser_view_parent_class)-> - finalize (object); -} - -static void -add_expand_state (GeditFileBrowserView * view, - gchar const * uri) -{ - GFile * file; - - if (!uri) - return; - - file = g_file_new_for_uri (uri); - - if (view->priv->expand_state) - g_hash_table_insert (view->priv->expand_state, file, file); - else - g_object_unref (file); -} - -static void -remove_expand_state (GeditFileBrowserView * view, - gchar const * uri) -{ - GFile * file; - - if (!uri) - return; - - file = g_file_new_for_uri (uri); - - if (view->priv->expand_state) - g_hash_table_remove (view->priv->expand_state, file); - - g_object_unref (file); -} - -static void -row_expanded (GtkTreeView * tree_view, - GtkTreeIter * iter, - GtkTreePath * path) -{ - GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (tree_view); - gchar * uri; - - 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) - { - gtk_tree_model_get (view->priv->model, - iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, - -1); - - add_expand_state (view, uri); - g_free (uri); - } - - _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); - gchar * uri; - - 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) - { - gtk_tree_model_get (view->priv->model, - iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, - -1); - - remove_expand_state (view, uri); - g_free (uri); - } - - _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) -{ - GtkTreeIter iter; - GdkDisplay *display; - GdkWindow *win; - - 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(GDK_HAND2); - } else if (click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE) { - if (obj->priv->hover_path != NULL) { - 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_REALIZED (GTK_WIDGET (obj))) { - win = gtk_widget_get_window (GTK_WIDGET (obj)); - gdk_window_set_cursor (win, NULL); - - display = gtk_widget_get_display (GTK_WIDGET (obj)); - - if (display != NULL) - gdk_display_flush (display); - } - - if (obj->priv->hand_cursor) { - gdk_cursor_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, *row; - GtkTreePath *directory = NULL; - GtkTreePath *path; - GtkTreeIter iter; - GeditFileBrowserStoreFlag flags; - - rows = gtk_tree_selection_get_selected_rows (selection, &view->priv->model); - - 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)) { - if (directory == NULL) - directory = path; - - } else if (!FILE_IS_DUMMY (flags)) { - g_signal_emit (view, signals[FILE_ACTIVATED], 0, &iter); - } - } - - if (directory != NULL) { - if (gtk_tree_model_get_iter (view->priv->model, &iter, directory)) - g_signal_emit (view, signals[DIRECTORY_ACTIVATED], 0, &iter); - } - - g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); -} - -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 -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; - GtkTreeSelection *selection; - GtkTreePath *path; - - tree_view = GTK_TREE_VIEW (view); - selection = gtk_tree_view_get_selection (tree_view); - - 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) -{ - int double_click_time; - static int click_count = 0; - static guint32 last_click_time = 0; - GeditFileBrowserView *view; - GtkTreeView *tree_view; - GtkTreeSelection *selection; - GtkTreePath *path; - int expander_size; - int horizontal_separator; - gboolean on_expander; - gboolean call_parent; - gboolean selected; - GtkWidgetClass *widget_parent = GTK_WIDGET_CLASS(gedit_file_browser_view_parent_class); - - tree_view = GTK_TREE_VIEW (widget); - view = GEDIT_FILE_BROWSER_VIEW (widget); - selection = gtk_tree_view_get_selection (tree_view); - - /* 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) { - if (view->priv->double_click_path[1] && - gtk_tree_path_compare (view->priv->double_click_path[0], view->priv->double_click_path[1]) == 0) - activate_selected_items (view); - - /* Chain up */ - widget_parent->button_press_event (widget, event); - } 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 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 == 3 && 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; - guint modifiers; - gboolean handled; - - view = GEDIT_FILE_BROWSER_VIEW (widget); - handled = FALSE; - - modifiers = gtk_accelerator_get_default_mod_mask (); - - switch (event->keyval) { - case GDK_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_Return: - case GDK_KP_Enter: - activate_selected_items (view); - handled = TRUE; - break; - - case GDK_h: - if ((event->state & modifiers) == GDK_CONTROL_MASK) { - toggle_hidden_filter (view); - handled = TRUE; - break; - } - - default: - handled = FALSE; - } - - /* 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; - gchar * uri; - - 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)) - { - gtk_tree_model_get (view->priv->model, - iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, - -1); - - add_expand_state (view, uri); - g_free (uri); - } - - 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_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, - gedit_file_browser_marshal_VOID__UINT_STRING, - 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, - g_cclosure_marshal_VOID__BOXED, - 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, - g_cclosure_marshal_VOID__BOXED, - 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, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); - - g_type_class_add_private (object_class, - sizeof (GeditFileBrowserViewPrivate)); -} - -static void -cell_data_cb (GtkTreeViewColumn * tree_column, GtkCellRenderer * cell, - GtkTreeModel * tree_model, GtkTreeIter * iter, - GeditFileBrowserView * obj) -{ - GtkTreePath *path; - PangoUnderline underline = PANGO_UNDERLINE_NONE; - gboolean editable = FALSE; - - path = gtk_tree_model_get_path (tree_model, iter); - - if (obj->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { - if (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)) - { - if (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 (path); - g_object_set (cell, "editable", editable, "underline", underline, NULL); -} - -static void -gedit_file_browser_view_init (GeditFileBrowserView * obj) -{ - obj->priv = GEDIT_FILE_BROWSER_VIEW_GET_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_add_attribute (obj->priv->column, - obj->priv->pixbuf_renderer, - "pixbuf", - GEDIT_FILE_BROWSER_STORE_COLUMN_ICON); - - 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, - "text", - GEDIT_FILE_BROWSER_STORE_COLUMN_NAME); - - 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); - - obj->priv->busy_cursor = gdk_cursor_new (GDK_WATCH); -} - -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; - - 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); - } 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); - - 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)) { - if (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); -} - -void -gedit_file_browser_view_start_rename (GeditFileBrowserView * tree_view, - GtkTreeIter * iter) -{ - guint flags; - 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_FLAGS, &flags, - -1); - - if (!(FILE_IS_DIR (flags) || !FILE_IS_DUMMY (flags))) - return; - - 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->editable = rowref; - - gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), - gtk_tree_row_reference_get_path (tree_view->priv->editable), - tree_view->priv->column, TRUE); - - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), - gtk_tree_row_reference_get_path (tree_view->priv->editable), - tree_view->priv->column, - FALSE, 0.0, 0.0); -} - -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; - GtkTreeIter iter; - gboolean ret; - GError * error = NULL; - - gtk_tree_row_reference_free (tree_view->priv->editable); - tree_view->priv->editable = NULL; - - if (new_text == NULL || *new_text == '\0') - return; - - treepath = gtk_tree_path_new_from_string (path); - ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model), &iter, treepath); - gtk_tree_path_free (treepath); - - if (ret) { - if (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); - } - } - } -} - -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, - gchar const * uri, - 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, uri); -} - -static void -restore_expand_state (GeditFileBrowserView * view, - GeditFileBrowserStore * model, - GtkTreeIter * iter) -{ - gchar * uri; - GFile * file; - GtkTreePath * path; - - gtk_tree_model_get (GTK_TREE_MODEL (model), - iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, - -1); - - if (!uri) - return; - - file = g_file_new_for_uri (uri); - path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); - - if (g_hash_table_lookup (view->priv->expand_state, file)) - { - gtk_tree_view_expand_row (GTK_TREE_VIEW (view), - path, - FALSE); - } - - gtk_tree_path_free (path); - - g_object_unref (file); - g_free (uri); -} - -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); -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-view.h b/plugins/filebrowser/gedit-file-browser-view.h deleted file mode 100755 index a5ada255..00000000 --- a/plugins/filebrowser/gedit-file-browser-view.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * gedit-file-browser-view.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_VIEW_H__ -#define __GEDIT_FILE_BROWSER_VIEW_H__ - -#include - -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_DOUBLE, - GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE -} 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; -GType gedit_file_browser_view_register_type (GTypeModule * module); - -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); - -G_END_DECLS -#endif /* __GEDIT_FILE_BROWSER_VIEW_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-widget-ui.xml b/plugins/filebrowser/gedit-file-browser-widget-ui.xml deleted file mode 100755 index 472fd185..00000000 --- a/plugins/filebrowser/gedit-file-browser-widget-ui.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/filebrowser/gedit-file-browser-widget.c b/plugins/filebrowser/gedit-file-browser-widget.c deleted file mode 100755 index e8a73cce..00000000 --- a/plugins/filebrowser/gedit-file-browser-widget.c +++ /dev/null @@ -1,3143 +0,0 @@ -/* - * gedit-file-browser-widget.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#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-marshal.h" -#include "gedit-file-browser-enum-types.h" - -#define GEDIT_FILE_BROWSER_WIDGET_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ - GEDIT_TYPE_FILE_BROWSER_WIDGET, \ - GeditFileBrowserWidgetPrivate)) - -#define XML_UI_FILE "gedit-file-browser-widget-ui.xml" -#define LOCATION_DATA_KEY "gedit-file-browser-widget-location" - -enum -{ - BOOKMARKS_ID, - SEPARATOR_CUSTOM_ID, - SEPARATOR_ID, - PATH_ID, - NUM_DEFAULT_IDS -}; - -enum -{ - COLUMN_INDENT, - COLUMN_ICON, - COLUMN_NAME, - COLUMN_FILE, - COLUMN_ID, - N_COLUMNS -}; - -/* Properties */ -enum -{ - PROP_0, - - PROP_FILTER_PATTERN, - PROP_ENABLE_DELETE -}; - -/* Signals */ -enum -{ - URI_ACTIVATED, - ERROR, - CONFIRM_DELETE, - CONFIRM_NO_TRASH, - 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; - GdkPixbuf *icon; -} NameIcon; - -struct _GeditFileBrowserWidgetPrivate -{ - GeditFileBrowserView *treeview; - GeditFileBrowserStore *file_store; - GeditFileBookmarksStore *bookmarks_store; - - GHashTable *bookmarks_hash; - - GtkWidget *combo; - GtkTreeStore *combo_model; - - GtkWidget *filter_expander; - GtkWidget *filter_entry; - - GtkUIManager *manager; - GtkActionGroup *action_group; - GtkActionGroup *action_group_selection; - GtkActionGroup *action_group_file_selection; - GtkActionGroup *action_group_single_selection; - GtkActionGroup *action_group_single_most_selection; - GtkActionGroup *action_group_sensitive; - GtkActionGroup *bookmark_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; - - gboolean enable_delete; - - GCancellable *cancellable; - - GdkCursor *busy_cursor; -}; - -static void set_enable_delete (GeditFileBrowserWidget *obj, - gboolean enable); -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 void on_combo_changed (GtkComboBox * combo, - 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 on_action_directory_previous (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_next (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_up (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_new (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_open (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_new (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_rename (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_delete (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_move_to_trash (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_refresh (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_open (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_filter_hidden (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_filter_binary (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_bookmark_open (GtkAction * action, - GeditFileBrowserWidget * obj); - -GEDIT_PLUGIN_DEFINE_TYPE (GeditFileBrowserWidget, gedit_file_browser_widget, - GTK_TYPE_VBOX) - -static void -free_name_icon (gpointer data) -{ - NameIcon * item; - - if (data == NULL) - return; - - item = (NameIcon *)(data); - - g_free (item->name); - - if (item->icon) - g_object_unref (item->icon); - - g_free (item); -} - -static FilterFunc * -filter_func_new (GeditFileBrowserWidget * obj, - GeditFileBrowserWidgetFilterFunc func, - gpointer user_data, - GDestroyNotify notify) -{ - FilterFunc *result; - - result = g_new (FilterFunc, 1); - - 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_free (loc); -} - -static gboolean -combo_find_by_id (GeditFileBrowserWidget * obj, guint id, - GtkTreeIter * iter) -{ - guint checkid; - GtkTreeModel *model = GTK_TREE_MODEL (obj->priv->combo_model); - - 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 -remove_path_items (GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - - while (combo_find_by_id (obj, PATH_ID, &iter)) - gtk_tree_store_remove (obj->priv->combo_model, &iter); -} - -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 -gedit_file_browser_widget_finalize (GObject * object) -{ - GeditFileBrowserWidget *obj = GEDIT_FILE_BROWSER_WIDGET (object); - GList *loc; - - remove_path_items (obj); - gedit_file_browser_store_set_filter_func (obj->priv->file_store, - NULL, NULL); - - g_object_unref (obj->priv->manager); - g_object_unref (obj->priv->file_store); - g_object_unref (obj->priv->bookmarks_store); - g_object_unref (obj->priv->combo_model); - - g_slist_foreach (obj->priv->filter_funcs, (GFunc) g_free, NULL); - g_slist_free (obj->priv->filter_funcs); - - for (loc = obj->priv->locations; loc; loc = loc->next) - location_free ((Location *) (loc->data)); - - if (obj->priv->current_location_menu_item) - g_object_unref (obj->priv->current_location_menu_item); - - g_list_free (obj->priv->locations); - - g_hash_table_destroy (obj->priv->bookmarks_hash); - - cancel_async_operation (obj); - - gdk_cursor_unref (obj->priv->busy_cursor); - - G_OBJECT_CLASS (gedit_file_browser_widget_parent_class)->finalize (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; - case PROP_ENABLE_DELETE: - g_value_set_boolean (value, obj->priv->enable_delete); - 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; - case PROP_ENABLE_DELETE: - set_enable_delete (obj, g_value_get_boolean (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); - - object_class->finalize = gedit_file_browser_widget_finalize; - - 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", - NULL, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, PROP_ENABLE_DELETE, - g_param_spec_boolean ("enable-delete", - "Enable delete", - "Enable permanently deleting items", - TRUE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - signals[URI_ACTIVATED] = - g_signal_new ("uri-activated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, - uri_activated), NULL, NULL, - g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, - G_TYPE_STRING); - signals[ERROR] = - g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, - error), NULL, NULL, - gedit_file_browser_marshal_VOID__UINT_STRING, - 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, - gedit_file_browser_marshal_BOOL__OBJECT_POINTER, - 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, - gedit_file_browser_marshal_BOOL__POINTER, - G_TYPE_BOOLEAN, - 1, - G_TYPE_POINTER); - - g_type_class_add_private (object_class, - sizeof (GeditFileBrowserWidgetPrivate)); -} - -static void -add_signal (GeditFileBrowserWidget * obj, gpointer object, gulong id) -{ - SignalNode *node = g_new (SignalNode, 1); - - node->object = G_OBJECT (object); - node->id = id; - - obj->priv->signal_pool = - g_slist_prepend (obj->priv->signal_pool, node); -} - -static void -clear_signals (GeditFileBrowserWidget * obj) -{ - GSList *item; - SignalNode *node; - - for (item = obj->priv->signal_pool; item; item = item->next) { - node = (SignalNode *) (item->data); - - g_signal_handler_disconnect (node->object, node->id); - g_free (item->data); - } - - g_slist_free (obj->priv->signal_pool); - obj->priv->signal_pool = NULL; -} - -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, GdkPixbuf ** icon) -{ - gpointer data; - NameIcon * item; - - data = g_hash_table_lookup (obj->priv->bookmarks_hash, file); - - if (data == NULL) - return FALSE; - - item = (NameIcon *)data; - - *name = g_strdup (item->name); - *icon = item->icon; - - if (item->icon != NULL) - { - g_object_ref (item->icon); - } - - return TRUE; -} - -static void -insert_path_item (GeditFileBrowserWidget * obj, - GFile * file, - GtkTreeIter * after, - GtkTreeIter * iter, - guint indent) -{ - gchar * unescape; - GdkPixbuf * icon = NULL; - - /* Try to get the icon and name from the bookmarks hash */ - if (!get_from_bookmark_file (obj, file, &unescape, &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 = gedit_file_browser_utils_pixbuf_from_file (file, GTK_ICON_SIZE_MENU); - } - - gtk_tree_store_insert_after (obj->priv->combo_model, iter, NULL, - after); - - gtk_tree_store_set (obj->priv->combo_model, - iter, - COLUMN_INDENT, indent, - COLUMN_ICON, icon, - COLUMN_NAME, unescape, - COLUMN_FILE, file, - COLUMN_ID, PATH_ID, - -1); - - if (icon) - g_object_unref (icon); - - g_free (unescape); -} - -static void -insert_separator_item (GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - - gtk_tree_store_insert (obj->priv->combo_model, &iter, NULL, 1); - gtk_tree_store_set (obj->priv->combo_model, &iter, - COLUMN_ICON, NULL, - COLUMN_NAME, NULL, - COLUMN_ID, SEPARATOR_ID, -1); -} - -static void -combo_set_active_by_id (GeditFileBrowserWidget * obj, guint id) -{ - GtkTreeIter iter; - - if (combo_find_by_id (obj, id, &iter)) - gtk_combo_box_set_active_iter (GTK_COMBO_BOX - (obj->priv->combo), &iter); -} - -static guint -uri_num_parents (GFile * from, GFile * to) -{ - /* Determine the number of 'levels' to get from #from to #to. */ - guint parents = 0; - GFile * parent; - - if (from == NULL) - return 0; - - g_object_ref (from); - - while ((parent = g_file_get_parent (from)) && !(to && g_file_equal (from, to))) { - g_object_unref (from); - from = parent; - - ++parents; - } - - g_object_unref (from); - return parents; -} - -static void -insert_location_path (GeditFileBrowserWidget * obj) -{ - Location *loc; - GFile *current = NULL; - GFile * tmp; - GtkTreeIter separator; - GtkTreeIter iter; - guint indent; - - if (!obj->priv->current_location) { - g_message ("insert_location_path: no current location"); - return; - } - - loc = (Location *) (obj->priv->current_location->data); - - current = loc->virtual_root; - combo_find_by_id (obj, SEPARATOR_ID, &separator); - - indent = uri_num_parents (loc->virtual_root, loc->root); - - while (current != NULL) { - insert_path_item (obj, current, &separator, &iter, indent--); - - if (current == loc->virtual_root) { - g_signal_handlers_block_by_func (obj->priv->combo, - on_combo_changed, - obj); - gtk_combo_box_set_active_iter (GTK_COMBO_BOX - (obj->priv->combo), - &iter); - g_signal_handlers_unblock_by_func (obj->priv-> - combo, - on_combo_changed, - obj); - } - - if (g_file_equal (current, loc->root) || !gedit_utils_file_has_parent (current)) { - 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 -check_current_item (GeditFileBrowserWidget * obj, gboolean show_path) -{ - GtkTreeIter separator; - gboolean has_sep; - - remove_path_items (obj); - has_sep = combo_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_tree_store_remove (obj->priv->combo_model, &separator); -} - -static void -fill_combo_model (GeditFileBrowserWidget * obj) -{ - GtkTreeStore *store = obj->priv->combo_model; - GtkTreeIter iter; - GdkPixbuf *icon; - - icon = gedit_file_browser_utils_pixbuf_from_theme (GTK_STOCK_HOME, GTK_ICON_SIZE_MENU); - - gtk_tree_store_append (store, &iter, NULL); - gtk_tree_store_set (store, &iter, - COLUMN_ICON, icon, - COLUMN_NAME, _("Bookmarks"), - COLUMN_ID, BOOKMARKS_ID, -1); - g_object_unref (icon); - - gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (obj->priv->combo), - separator_func, obj, NULL); - gtk_combo_box_set_active (GTK_COMBO_BOX (obj->priv->combo), 0); -} - -static void -indent_cell_data_func (GtkCellLayout * cell_layout, - GtkCellRenderer * cell, - GtkTreeModel * model, - GtkTreeIter * iter, - gpointer data) -{ - gchar * indent; - guint num; - - gtk_tree_model_get (model, iter, COLUMN_INDENT, &num, -1); - - if (num == 0) - g_object_set (cell, "text", "", NULL); - else { - indent = g_strnfill (num * 2, ' '); - - g_object_set (cell, "text", indent, NULL); - g_free (indent); - } -} - -static void -create_combo (GeditFileBrowserWidget * obj) -{ - GtkCellRenderer *renderer; - - obj->priv->combo_model = gtk_tree_store_new (N_COLUMNS, - G_TYPE_UINT, - GDK_TYPE_PIXBUF, - G_TYPE_STRING, - G_TYPE_FILE, - G_TYPE_UINT); - obj->priv->combo = - gtk_combo_box_new_with_model (GTK_TREE_MODEL - (obj->priv->combo_model)); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, FALSE); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT - (obj->priv->combo), renderer, - indent_cell_data_func, obj, NULL); - - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, FALSE); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, "pixbuf", COLUMN_ICON); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, TRUE); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, "text", COLUMN_NAME); - - g_object_set (renderer, "ellipsize-set", TRUE, - "ellipsize", PANGO_ELLIPSIZE_END, NULL); - - gtk_box_pack_start (GTK_BOX (obj), GTK_WIDGET (obj->priv->combo), - FALSE, FALSE, 0); - - fill_combo_model (obj); - g_signal_connect (obj->priv->combo, "changed", - G_CALLBACK (on_combo_changed), obj); - - gtk_widget_show (obj->priv->combo); -} - -static GtkActionEntry toplevel_actions[] = -{ - {"FilterMenuAction", NULL, N_("_Filter")} -}; - -static const GtkActionEntry tree_actions_selection[] = -{ - {"FileMoveToTrash", "mate-stock-trash", N_("_Move to Trash"), NULL, - N_("Move selected file or folder to trash"), - G_CALLBACK (on_action_file_move_to_trash)}, - {"FileDelete", GTK_STOCK_DELETE, N_("_Delete"), NULL, - N_("Delete selected file or folder"), - G_CALLBACK (on_action_file_delete)} -}; - -static const GtkActionEntry tree_actions_file_selection[] = -{ - {"FileOpen", GTK_STOCK_OPEN, NULL, NULL, - N_("Open selected file"), - G_CALLBACK (on_action_file_open)} -}; - -static const GtkActionEntry tree_actions[] = -{ - {"DirectoryUp", GTK_STOCK_GO_UP, N_("Up"), NULL, - N_("Open the parent folder"), G_CALLBACK (on_action_directory_up)} -}; - -static const GtkActionEntry tree_actions_single_most_selection[] = -{ - {"DirectoryNew", GTK_STOCK_ADD, N_("_New Folder"), NULL, - N_("Add new empty folder"), - G_CALLBACK (on_action_directory_new)}, - {"FileNew", GTK_STOCK_NEW, N_("New F_ile"), NULL, - N_("Add new empty file"), G_CALLBACK (on_action_file_new)} -}; - -static const GtkActionEntry tree_actions_single_selection[] = -{ - {"FileRename", NULL, N_("_Rename"), NULL, - N_("Rename selected file or folder"), - G_CALLBACK (on_action_file_rename)} -}; - -static const GtkActionEntry tree_actions_sensitive[] = -{ - {"DirectoryPrevious", GTK_STOCK_GO_BACK, N_("_Previous Location"), - NULL, - N_("Go to the previous visited location"), - G_CALLBACK (on_action_directory_previous)}, - {"DirectoryNext", GTK_STOCK_GO_FORWARD, N_("_Next Location"), NULL, - N_("Go to the next visited location"), G_CALLBACK (on_action_directory_next)}, - {"DirectoryRefresh", GTK_STOCK_REFRESH, N_("Re_fresh View"), NULL, - N_("Refresh the view"), G_CALLBACK (on_action_directory_refresh)}, - {"DirectoryOpen", GTK_STOCK_OPEN, N_("_View Folder"), NULL, - N_("View folder in file manager"), - G_CALLBACK (on_action_directory_open)} -}; - -static const GtkToggleActionEntry tree_actions_toggle[] = -{ - {"FilterHidden", GTK_STOCK_DIALOG_AUTHENTICATION, - N_("Show _Hidden"), NULL, - N_("Show hidden files and folders"), - G_CALLBACK (on_action_filter_hidden), FALSE}, - {"FilterBinary", NULL, N_("Show _Binary"), NULL, - N_("Show binary files"), G_CALLBACK (on_action_filter_binary), - FALSE} -}; - -static const GtkActionEntry bookmark_actions[] = -{ - {"BookmarkOpen", GTK_STOCK_OPEN, N_("_View Folder"), NULL, - N_("View folder in file manager"), G_CALLBACK (on_action_bookmark_open)} -}; - -static void -create_toolbar (GeditFileBrowserWidget * obj, - const gchar *data_dir) -{ - GtkUIManager *manager; - GError *error = NULL; - GtkActionGroup *action_group; - GtkWidget *toolbar; - GtkWidget *widget; - GtkAction *action; - gchar *ui_file; - - manager = gtk_ui_manager_new (); - obj->priv->manager = manager; - - ui_file = g_build_filename (data_dir, XML_UI_FILE, NULL); - gtk_ui_manager_add_ui_from_file (manager, ui_file, &error); - - g_free (ui_file); - - if (error != NULL) { - g_warning ("Error in adding ui from file %s: %s", - XML_UI_FILE, error->message); - g_error_free (error); - return; - } - - action_group = gtk_action_group_new ("FileBrowserWidgetActionGroupToplevel"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - toplevel_actions, - G_N_ELEMENTS (toplevel_actions), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - - action_group = gtk_action_group_new ("FileBrowserWidgetActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions, - G_N_ELEMENTS (tree_actions), - obj); - gtk_action_group_add_toggle_actions (action_group, - tree_actions_toggle, - G_N_ELEMENTS (tree_actions_toggle), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetSelectionActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_selection, - G_N_ELEMENTS (tree_actions_selection), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_selection = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetFileSelectionActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_file_selection, - G_N_ELEMENTS (tree_actions_file_selection), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_file_selection = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetSingleSelectionActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_single_selection, - G_N_ELEMENTS (tree_actions_single_selection), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_single_selection = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetSingleMostSelectionActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_single_most_selection, - G_N_ELEMENTS (tree_actions_single_most_selection), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_single_most_selection = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetSensitiveActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_sensitive, - G_N_ELEMENTS (tree_actions_sensitive), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_sensitive = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetBookmarkActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - bookmark_actions, - G_N_ELEMENTS (bookmark_actions), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->bookmark_action_group = action_group; - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryPrevious"); - gtk_action_set_sensitive (action, FALSE); - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryNext"); - gtk_action_set_sensitive (action, FALSE); - - toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar"); - gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU); - - /* Previous directory menu tool item */ - obj->priv->location_previous_menu = gtk_menu_new (); - gtk_widget_show (obj->priv->location_previous_menu); - - widget = GTK_WIDGET (gtk_menu_tool_button_new_from_stock (GTK_STOCK_GO_BACK)); - gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), - obj->priv->location_previous_menu); - - g_object_set (widget, "label", _("Previous location"), NULL); - gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (widget), - _("Go to previous location")); - gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (widget), - _("Go to a previously opened location")); - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryPrevious"); - g_object_set (action, "is_important", TRUE, "short_label", - _("Previous location"), NULL); - gtk_action_connect_proxy (action, widget); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget), 0); - - /* Next directory menu tool item */ - obj->priv->location_next_menu = gtk_menu_new (); - gtk_widget_show (obj->priv->location_next_menu); - - widget = GTK_WIDGET (gtk_menu_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD)); - gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), - obj->priv->location_next_menu); - - g_object_set (widget, "label", _("Next location"), NULL); - gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (widget), - _("Go to next location")); - gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (widget), - _("Go to a previously opened location")); - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryNext"); - g_object_set (action, "is_important", TRUE, "short_label", - _("Previous location"), NULL); - gtk_action_connect_proxy (action, widget); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget), 1); - - gtk_box_pack_start (GTK_BOX (obj), toolbar, FALSE, FALSE, 0); - gtk_widget_show (toolbar); - - set_enable_delete (obj, obj->priv->enable_delete); -} - -static void -set_enable_delete (GeditFileBrowserWidget *obj, - gboolean enable) -{ - GtkAction *action; - obj->priv->enable_delete = enable; - - if (obj->priv->action_group_selection == NULL) - return; - - action = - gtk_action_group_get_action (obj->priv->action_group_selection, - "FileDelete"); - - g_object_set (action, "visible", enable, "sensitive", enable, NULL); -} - -static gboolean -filter_real (GeditFileBrowserStore * model, GtkTreeIter * iter, - GeditFileBrowserWidget * obj) -{ - GSList *item; - FilterFunc *func; - - for (item = obj->priv->filter_funcs; item; item = item->next) { - 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; - GdkPixbuf * pixbuf; - gchar * name; - gchar * uri; - GFile * file; - NameIcon * item; - - model = GTK_TREE_MODEL (obj->priv->bookmarks_store); - - uri = gedit_file_bookmarks_store_get_uri (obj->priv-> - bookmarks_store, - iter); - - if (uri == NULL) - return; - - file = g_file_new_for_uri (uri); - g_free (uri); - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON, - &pixbuf, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, - &name, -1); - - item = g_new (NameIcon, 1); - item->name = name; - item->icon = pixbuf; - - g_hash_table_insert (obj->priv->bookmarks_hash, - file, - item); -} - -static void -init_bookmarks_hash (GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - GtkTreeModel *model; - - model = GTK_TREE_MODEL (obj->priv->bookmarks_store); - - 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 -create_tree (GeditFileBrowserWidget * obj) -{ - GtkWidget *sw; - - obj->priv->file_store = gedit_file_browser_store_new (NULL); - obj->priv->bookmarks_store = gedit_file_bookmarks_store_new (); - obj->priv->treeview = - GEDIT_FILE_BROWSER_VIEW (gedit_file_browser_view_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); - - sw = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), - GTK_SHADOW_ETCHED_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_container_add (GTK_CONTAINER (sw), - GTK_WIDGET (obj->priv->treeview)); - gtk_box_pack_start (GTK_BOX (obj), sw, TRUE, TRUE, 0); - - 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); - - gtk_widget_show (sw); - gtk_widget_show (GTK_WIDGET (obj->priv->treeview)); -} - -static void -create_filter (GeditFileBrowserWidget * obj) -{ - GtkWidget *expander; - GtkWidget *vbox; - GtkWidget *entry; - - expander = gtk_expander_new_with_mnemonic (_("_Match Filename")); - gtk_widget_show (expander); - gtk_box_pack_start (GTK_BOX (obj), expander, FALSE, FALSE, 0); - - vbox = gtk_vbox_new (FALSE, 3); - gtk_widget_show (vbox); - - obj->priv->filter_expander = expander; - - entry = gtk_entry_new (); - gtk_widget_show (entry); - - obj->priv->filter_entry = entry; - - g_signal_connect_swapped (entry, "activate", - G_CALLBACK (on_entry_filter_activate), - obj); - g_signal_connect_swapped (entry, "focus_out_event", - G_CALLBACK (on_entry_filter_activate), - obj); - - gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); - gtk_container_add (GTK_CONTAINER (expander), vbox); -} - -static void -gedit_file_browser_widget_init (GeditFileBrowserWidget * obj) -{ - obj->priv = GEDIT_FILE_BROWSER_WIDGET_GET_PRIVATE (obj); - - obj->priv->bookmarks_hash = g_hash_table_new_full (g_file_hash, - (GEqualFunc)g_file_equal, - g_object_unref, - free_name_icon); - - gtk_box_set_spacing (GTK_BOX (obj), 3); - - obj->priv->busy_cursor = gdk_cursor_new (GDK_WATCH); -} - -/* Private */ - -static void -update_sensitivity (GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - GtkAction *action; - gint mode; - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) { - gtk_action_group_set_sensitive (obj->priv->action_group, - TRUE); - gtk_action_group_set_sensitive (obj->priv->bookmark_action_group, - FALSE); - - mode = - gedit_file_browser_store_get_filter_mode - (GEDIT_FILE_BROWSER_STORE (model)); - - action = - gtk_action_group_get_action (obj->priv->action_group, - "FilterHidden"); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), - !(mode & - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN)); - } else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) { - gtk_action_group_set_sensitive (obj->priv->action_group, - FALSE); - gtk_action_group_set_sensitive (obj->priv->bookmark_action_group, - TRUE); - - /* Set the filter toggle to normal up state, just for visual pleasure */ - action = - gtk_action_group_get_action (obj->priv->action_group, - "FilterHidden"); - gtk_toggle_action_set_active (GTK_TOGGLE_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_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return result; -} - -static gboolean -popup_menu (GeditFileBrowserWidget * obj, GdkEventButton * event, GtkTreeModel * model) -{ - GtkWidget *menu; - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) - menu = gtk_ui_manager_get_widget (obj->priv->manager, "/FilePopup"); - else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) - menu = gtk_ui_manager_get_widget (obj->priv->manager, "/BookmarkPopup"); - else - return FALSE; - - g_return_val_if_fail (menu != NULL, FALSE); - - if (event != NULL) { - GtkTreeSelection *selection; - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - - if (gtk_tree_selection_count_selected_rows (selection) <= 1) { - GtkTreePath *path; - - if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (obj->priv->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 (GTK_MENU (menu), NULL, NULL, NULL, NULL, - event->button, event->time); - } else { - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, - gedit_utils_menu_position_under_tree_view, - obj->priv->treeview, 0, - gtk_get_current_event_time ()); - 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_match_string (obj->priv->filter_pattern, - name); - - g_free (name); - - return result; -} - -static void -rename_selected_file (GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - 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) { - GtkTreeSelection *selection; - GtkTreeModel *model; - GList *rows; - GList *row; - GList *paths = NULL; - guint flags; - GtkTreeIter iter; - GtkTreePath *path; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - /* Get all selected files */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - 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_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return paths; -} - -static gboolean -delete_selected_files (GeditFileBrowserWidget * obj, gboolean trash) -{ - GtkTreeModel *model; - gboolean confirm; - GeditFileBrowserStoreResult result; - GList *rows; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return FALSE; - - rows = get_deletable_files (obj); - - if (!rows) - 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_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return result == GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -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 * tmp; - GFile * current; - - current = g_object_ref (file); - - 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, - GdkPixbuf * icon) -{ - GtkWidget *result; - GtkWidget *image; - gchar *unescape; - GdkPixbuf *pixbuf = NULL; - Location *loc; - - loc = (Location *) (item->data); - - if (!get_from_bookmark_file (obj, loc->virtual_root, &unescape, &pixbuf)) { - unescape = gedit_file_browser_utils_file_basename (loc->virtual_root); - - if (icon) - pixbuf = g_object_ref (icon); - } - - if (pixbuf) { - image = gtk_image_new_from_pixbuf (pixbuf); - g_object_unref (pixbuf); - - gtk_widget_show (image); - - result = gtk_image_menu_item_new_with_label (unescape); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (result), - image); - } else { - 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 (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; - gchar *root; - gchar *virtual_root; - - 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 */ - root = g_file_get_uri (loc->root); - virtual_root = g_file_get_uri (loc->virtual_root); - - gedit_file_browser_widget_set_root_and_virtual_root (obj, - root, - virtual_root); - - g_free (root); - g_free (virtual_root); - - obj->priv->changing_location = FALSE; -} - -static void -clear_next_locations (GeditFileBrowserWidget * obj) -{ - 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); - - gtk_action_set_sensitive (gtk_action_group_get_action - (obj->priv->action_group_sensitive, - "DirectoryNext"), FALSE); -} - -static void -update_filter_mode (GeditFileBrowserWidget * obj, - GtkAction * action, - GeditFileBrowserStoreFilterMode mode) -{ - gboolean active = - gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); - GtkTreeModel *model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - gint now; - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) { - now = - gedit_file_browser_store_get_filter_mode - (GEDIT_FILE_BROWSER_STORE (model)); - - if (active) - now &= ~mode; - else - now |= mode; - - gedit_file_browser_store_set_filter_mode - (GEDIT_FILE_BROWSER_STORE (model), now); - } -} - -static void -set_filter_pattern_real (GeditFileBrowserWidget * obj, - gchar const * pattern, - gboolean update_entry) -{ - GtkTreeModel *model; - - 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 == NULL) - return; - - if (pattern != NULL && obj->priv->filter_pattern_str != NULL && - strcmp (pattern, obj->priv->filter_pattern_str) == 0) - return; - - /* Free the old pattern */ - g_free (obj->priv->filter_pattern_str); - 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) { - if (obj->priv->filter_pattern_str == NULL) - gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), - ""); - else { - gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), - obj->priv->filter_pattern_str); - - gtk_expander_set_expanded (GTK_EXPANDER (obj->priv->filter_expander), - TRUE); - } - } - - 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 (const gchar *data_dir) -{ - GeditFileBrowserWidget *obj = - g_object_new (GEDIT_TYPE_FILE_BROWSER_WIDGET, NULL); - - create_toolbar (obj, data_dir); - create_combo (obj); - create_tree (obj); - create_filter (obj); - - gedit_file_browser_widget_show_bookmarks (obj); - - return GTK_WIDGET (obj); -} - -void -gedit_file_browser_widget_show_bookmarks (GeditFileBrowserWidget * obj) -{ - /* Select bookmarks in the combo box */ - g_signal_handlers_block_by_func (obj->priv->combo, - on_combo_changed, obj); - combo_set_active_by_id (obj, BOOKMARKS_ID); - g_signal_handlers_unblock_by_func (obj->priv->combo, - on_combo_changed, obj); - - check_current_item (obj, FALSE); - - 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) -{ - 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, - gchar const *root, - gchar const *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, - gchar const *root, - gboolean virtual_root) -{ - GFile *file; - GFile *parent; - gchar *str; - - if (!virtual_root) { - gedit_file_browser_widget_set_root_and_virtual_root (obj, - root, - NULL); - return; - } - - if (!root) - return; - - file = g_file_new_for_uri (root); - parent = get_topmost_file (file); - str = g_file_get_uri (parent); - - gedit_file_browser_widget_set_root_and_virtual_root - (obj, str, root); - - g_free (str); - - g_object_unref (file); - 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; -} - -GtkUIManager * -gedit_file_browser_widget_get_ui_manager (GeditFileBrowserWidget * obj) -{ - return obj->priv->manager; -} - -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; - GtkTreeModel *model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - f = filter_func_new (obj, func, user_data, notify); - 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; - FilterFunc *func; - - for (item = obj->priv->filter_funcs; item; item = item->next) - { - 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); - g_free (func); - break; - } - } -} - -void -gedit_file_browser_widget_set_filter_pattern (GeditFileBrowserWidget * obj, - gchar const *pattern) -{ - 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)) { - if (!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; -} - -static guint -gedit_file_browser_widget_get_num_selected_files_or_directories (GeditFileBrowserWidget *obj, - guint *files, - guint *dirs) -{ - GList *rows, *row; - GtkTreePath *path; - GtkTreeIter iter; - GeditFileBrowserStoreFlag flags; - guint result = 0; - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - 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) { - path = (GtkTreePath *)(row->data); - - /* 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_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return result; -} - -typedef struct -{ - GeditFileBrowserWidget *widget; - GCancellable *cancellable; -} AsyncData; - -static AsyncData * -async_data_new (GeditFileBrowserWidget *widget) -{ - AsyncData *ret; - - ret = g_new (AsyncData, 1); - 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_free (async); -} - -static void -set_busy (GeditFileBrowserWidget *obj, gboolean busy) -{ - GdkCursor *cursor; - GdkWindow *window; - - window = gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview)); - - if (!GDK_IS_WINDOW (window)) - return; - - if (busy) - { - cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (window, cursor); - gdk_cursor_unref (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; - gchar *uri; - - if (!mount) - { - gchar *message; - gchar *name; - - name = g_volume_get_name (volume); - 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); - uri = g_file_get_uri (root); - - gedit_file_browser_widget_set_root (widget, uri, FALSE); - - g_free (uri); - g_object_unref (root); -} - -static void -try_activate_drive (GeditFileBrowserWidget *widget, - GDrive *drive) -{ - GList *volumes; - GVolume *volume; - GMount *mount; - - volumes = g_drive_get_volumes (drive); - - volume = G_VOLUME (volumes->data); - 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_foreach (volumes, (GFunc)g_object_unref, NULL); - g_list_free (volumes); -} - -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 *message; - gchar *name; - - name = g_drive_get_name (drive); - 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; - - mount = g_volume_get_mount (volume); - activate_mount (async->widget, volume, mount); - - if (mount) - g_object_unref (mount); - } - else - { - gchar *message; - gchar *name; - - name = g_volume_get_name (volume); - 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; - AsyncData *async; - - operation = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)))); - 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)); - } -} - -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) -{ - gchar *uri; - 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; - } - - uri = - gedit_file_bookmarks_store_get_uri - (GEDIT_FILE_BOOKMARKS_STORE (model), iter); - - if (uri) { - /* 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, - uri, - FALSE); - } else { - gedit_file_browser_widget_set_root (obj, - uri, - TRUE); - } - } else { - g_warning ("No uri!"); - } - - g_free (uri); -} - -static void -file_open (GeditFileBrowserWidget *obj, - GtkTreeModel *model, - GtkTreeIter *iter) -{ - gchar *uri; - gint flags; - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - -1); - - if (!FILE_IS_DIR (flags) && !FILE_IS_DUMMY (flags)) { - g_signal_emit (obj, signals[URI_ACTIVATED], 0, uri); - } - - g_free (uri); -} - -static gboolean -directory_open (GeditFileBrowserWidget *obj, - GtkTreeModel *model, - GtkTreeIter *iter) -{ - gboolean result = FALSE; - GError *error = NULL; - gchar *uri = NULL; - GeditFileBrowserStoreFlag flags; - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - -1); - - if (FILE_IS_DIR (flags)) { - result = TRUE; - - if (!gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (obj)), 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); - - 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; - gchar *uri; - gchar *root_uri; - GtkTreeIter root; - GtkAction *action; - Location *loc; - GdkPixbuf *pixbuf; - - 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)) { - gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, -1); - - if (gedit_file_browser_store_get_iter_root (model, &root)) { - if (!obj->priv->changing_location) { - /* Remove all items from obj->priv->current_location on */ - if (obj->priv->current_location) - clear_next_locations (obj); - - root_uri = - gedit_file_browser_store_get_root - (model); - - loc = g_new (Location, 1); - loc->root = g_file_new_for_uri (root_uri); - loc->virtual_root = g_file_new_for_uri (uri); - g_free (root_uri); - - 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); - - gtk_tree_model_get (GTK_TREE_MODEL (model), - &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_ICON, - &pixbuf, -1); - - obj->priv->current_location = - obj->priv->locations; - obj->priv->current_location_menu_item = - create_goto_menu_item (obj, - obj->priv-> - current_location, - pixbuf); - - g_object_ref_sink (obj->priv-> - current_location_menu_item); - - if (pixbuf) - g_object_unref (pixbuf); - - } - - action = - gtk_action_group_get_action (obj->priv-> - action_group, - "DirectoryUp"); - gtk_action_set_sensitive (action, - !virtual_root_is_root (obj, model)); - - action = - gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryPrevious"); - gtk_action_set_sensitive (action, - obj->priv-> - current_location != NULL - && obj->priv-> - current_location->next != - NULL); - - action = - gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryNext"); - gtk_action_set_sensitive (action, - obj->priv-> - current_location != NULL - && obj->priv-> - current_location->prev != - NULL); - } - - check_current_item (obj, TRUE); - g_free (uri); - } 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) { - GtkAction *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 = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryPrevious"); - gtk_action_set_sensitive (action, TRUE); - } - - gtk_widget_set_sensitive (obj->priv->filter_expander, FALSE); - - 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_set_sensitive (obj->priv->filter_expander, TRUE); - } - - 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 void -on_combo_changed (GtkComboBox * combo, GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - guint id; - gchar * uri; - GFile * file; - - if (!gtk_combo_box_get_active_iter (combo, &iter)) - return; - - gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->combo_model), &iter, - COLUMN_ID, &id, -1); - - switch (id) { - case BOOKMARKS_ID: - gedit_file_browser_widget_show_bookmarks (obj); - break; - - case PATH_ID: - gtk_tree_model_get (GTK_TREE_MODEL - (obj->priv->combo_model), &iter, - COLUMN_FILE, &file, -1); - - uri = g_file_get_uri (file); - gedit_file_browser_store_set_virtual_root_from_string - (obj->priv->file_store, uri); - - g_free (uri); - g_object_unref (file); - break; - } -} - -static gboolean -on_treeview_popup_menu (GeditFileBrowserView * treeview, - GeditFileBrowserWidget * obj) -{ - return popup_menu (obj, 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 == 3) { - return popup_menu (obj, event, - gtk_tree_view_get_model (GTK_TREE_VIEW (treeview))); - } - - return FALSE; -} - -static gboolean -do_change_directory (GeditFileBrowserWidget * obj, - GdkEventKey * event) -{ - GtkAction * action = NULL; - - if ((event->state & - (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK & ~GDK_MOD1_MASK)) == - event->state && event->keyval == GDK_BackSpace) - action = gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryPrevious"); - else if (!((event->state & GDK_MOD1_MASK) && - (event->state & (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK)) == event->state)) - return FALSE; - - switch (event->keyval) { - case GDK_Left: - action = gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryPrevious"); - break; - case GDK_Right: - action = gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryNext"); - break; - case GDK_Up: - action = gtk_action_group_get_action (obj->priv-> - action_group, - "DirectoryUp"); - break; - default: - break; - } - - if (action != NULL) { - gtk_action_activate (action); - return TRUE; - } - - return FALSE; -} - -static gboolean -on_treeview_key_press_event (GeditFileBrowserView * treeview, - GdkEventKey * event, - GeditFileBrowserWidget * obj) -{ - guint modifiers; - - if (do_change_directory (obj, event)) - return TRUE; - - if (!GEDIT_IS_FILE_BROWSER_STORE - (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)))) - return FALSE; - - modifiers = gtk_accelerator_get_default_mod_mask (); - - if (event->keyval == GDK_Delete - || event->keyval == GDK_KP_Delete) { - - if ((event->state & modifiers) == GDK_SHIFT_MASK) { - if (obj->priv->enable_delete) { - delete_selected_files (obj, FALSE); - return TRUE; - } - } else if ((event->state & modifiers) == 0) { - delete_selected_files (obj, TRUE); - return TRUE; - } - } - - if ((event->keyval == GDK_F2) - && (event->state & modifiers) == 0) { - rename_selected_file (obj); - - return TRUE; - } - - return FALSE; -} - -static void -on_selection_changed (GtkTreeSelection * selection, - GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - guint selected = 0; - guint files = 0; - guint dirs = 0; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) - { - selected = gedit_file_browser_widget_get_num_selected_files_or_directories (obj, - &files, - &dirs); - } - - gtk_action_group_set_sensitive (obj->priv->action_group_selection, - selected > 0); - gtk_action_group_set_sensitive (obj->priv->action_group_file_selection, - (selected > 0) && (selected == files)); - gtk_action_group_set_sensitive (obj->priv->action_group_single_selection, - selected == 1); - gtk_action_group_set_sensitive (obj->priv->action_group_single_most_selection, - selected <= 1); -} - -static gboolean -on_entry_filter_activate (GeditFileBrowserWidget * obj) -{ - gchar const *text; - - 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; - - 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; - gchar * uri; - GFile * file; - - if (!gtk_tree_model_get_iter (model, &iter, path)) - return; - - uri = gedit_file_bookmarks_store_get_uri (obj->priv->bookmarks_store, &iter); - - if (!uri) - return; - - file = g_file_new_for_uri (uri); - g_hash_table_remove (obj->priv->bookmarks_hash, file); - - g_object_unref (file); - g_free (uri); -} - -static void -on_filter_mode_changed (GeditFileBrowserStore * model, - GParamSpec * param, - GeditFileBrowserWidget * obj) -{ - gint mode; - GtkToggleAction * action; - gboolean active; - - mode = gedit_file_browser_store_get_filter_mode (model); - - action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (obj->priv->action_group, - "FilterHidden")); - active = !(mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN); - - if (active != gtk_toggle_action_get_active (action)) - gtk_toggle_action_set_active (action, active); - - action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (obj->priv->action_group, - "FilterBinary")); - active = !(mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); - - if (active != gtk_toggle_action_get_active (action)) - gtk_toggle_action_set_active (action, active); -} - -static void -on_action_directory_next (GtkAction * action, GeditFileBrowserWidget * obj) -{ - gedit_file_browser_widget_history_forward (obj); -} - -static void -on_action_directory_previous (GtkAction * action, - GeditFileBrowserWidget * obj) -{ - gedit_file_browser_widget_history_back (obj); -} - -static void -on_action_directory_up (GtkAction * action, - GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->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 -on_action_directory_new (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeIter parent; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - if (!gedit_file_browser_widget_get_selected_directory (obj, &parent)) - return; - - if (gedit_file_browser_store_new_directory - (GEDIT_FILE_BROWSER_STORE (model), &parent, &iter)) { - gedit_file_browser_view_start_rename (obj->priv->treeview, - &iter); - } -} - -static void -on_action_file_open (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GList *rows; - GList *row; - GtkTreeIter iter; - GtkTreePath *path; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - if (gtk_tree_model_get_iter (model, &iter, path)) - file_open (obj, model, &iter); - - gtk_tree_path_free (path); - } - - g_list_free (rows); -} - -static void -on_action_file_new (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeIter parent; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - if (!gedit_file_browser_widget_get_selected_directory (obj, &parent)) - return; - - if (gedit_file_browser_store_new_file - (GEDIT_FILE_BROWSER_STORE (model), &parent, &iter)) { - gedit_file_browser_view_start_rename (obj->priv->treeview, - &iter); - } -} - -static void -on_action_file_rename (GtkAction * action, GeditFileBrowserWidget * obj) -{ - rename_selected_file (obj); -} - -static void -on_action_file_delete (GtkAction * action, GeditFileBrowserWidget * obj) -{ - delete_selected_files (obj, FALSE); -} - -static void -on_action_file_move_to_trash (GtkAction * action, GeditFileBrowserWidget * obj) -{ - delete_selected_files (obj, TRUE); -} - -static void -on_action_directory_refresh (GtkAction * action, - GeditFileBrowserWidget * obj) -{ - gedit_file_browser_widget_refresh (obj); -} - -static void -on_action_directory_open (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GList *rows; - GList *row; - gboolean directory_opened = FALSE; - GtkTreeIter iter; - GtkTreePath *path; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - if (gtk_tree_model_get_iter (model, &iter, path)) - directory_opened |= directory_open (obj, model, &iter); - - gtk_tree_path_free (path); - } - - if (!directory_opened) { - if (gedit_file_browser_widget_get_selected_directory (obj, &iter)) - directory_open (obj, model, &iter); - } - - g_list_free (rows); -} - -static void -on_action_filter_hidden (GtkAction * action, GeditFileBrowserWidget * obj) -{ - update_filter_mode (obj, - action, - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN); -} - -static void -on_action_filter_binary (GtkAction * action, GeditFileBrowserWidget * obj) -{ - update_filter_mode (obj, - action, - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); -} - -static void -on_action_bookmark_open (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BOOKMARKS_STORE (model)) - return; - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - bookmark_open (obj, model, &iter); -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-widget.h b/plugins/filebrowser/gedit-file-browser-widget.h deleted file mode 100755 index e9cc2a0e..00000000 --- a/plugins/filebrowser/gedit-file-browser-widget.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * gedit-file-browser-widget.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_WIDGET_H__ -#define __GEDIT_FILE_BROWSER_WIDGET_H__ - -#include -#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 -{ - GtkVBox parent; - - GeditFileBrowserWidgetPrivate *priv; -}; - -struct _GeditFileBrowserWidgetClass -{ - GtkVBoxClass parent_class; - - /* Signals */ - void (*uri_activated) (GeditFileBrowserWidget * widget, - gchar const *uri); - 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); -}; - -GType gedit_file_browser_widget_get_type (void) G_GNUC_CONST; -GType gedit_file_browser_widget_register_type (GTypeModule * module); - -GtkWidget *gedit_file_browser_widget_new (const gchar *data_dir); - -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, - gchar const *root, - gboolean virtual_root); -void -gedit_file_browser_widget_set_root_and_virtual_root (GeditFileBrowserWidget * obj, - gchar const *root, - gchar const *virtual_root); - -gboolean -gedit_file_browser_widget_get_selected_directory (GeditFileBrowserWidget * obj, - GtkTreeIter * iter); - -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); - -GtkUIManager * -gedit_file_browser_widget_get_ui_manager (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); - -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); - -G_END_DECLS -#endif /* __GEDIT_FILE_BROWSER_WIDGET_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser.schemas.in b/plugins/filebrowser/gedit-file-browser.schemas.in deleted file mode 100755 index c80c8eec..00000000 --- a/plugins/filebrowser/gedit-file-browser.schemas.in +++ /dev/null @@ -1,97 +0,0 @@ - - - - /schemas/apps/gedit-2/plugins/filebrowser/on_load/tree_view - /apps/gedit-2/plugins/filebrowser/on_load/tree_view - gedit - bool - TRUE - - Open With Tree View - Open the tree view when the file browser plugin gets loaded instead of the bookmarks view - - - - - /schemas/apps/gedit-2/plugins/filebrowser/on_load/root - /apps/gedit-2/plugins/filebrowser/on_load/root - gedit - string - - - File Browser Root Directory - The file browser root directory to use when loading the file - browser plugin and onload/tree_view is TRUE. - - - - - /schemas/apps/gedit-2/plugins/filebrowser/on_load/virtual_root - /apps/gedit-2/plugins/filebrowser/on_load/virtual_root - gedit - string - - - File Browser Virtual Root Directory - 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. - - - - - /schemas/apps/gedit-2/plugins/filebrowser/on_load/enable_remote - /apps/gedit-2/plugins/filebrowser/on_load/enable_remote - gedit - bool - FALSE - - Enable Restore of Remote Locations - Sets whether to enable restoring of remote locations. - - - - - /schemas/apps/gedit-2/plugins/filebrowser/open_at_first_doc - /apps/gedit-2/plugins/filebrowser/open_at_first_doc - gedit - bool - TRUE - - Set Location to First Document - 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 Caja, etc.) - - - - - /schemas/apps/gedit-2/plugins/filebrowser/filter_mode - /apps/gedit-2/plugins/filebrowser/filter_mode - gedit - string - hidden_and_binary - - File Browser Filter Mode - This value determines what files get filtered from the file - browser. Valid values are: none (filter nothing), - hidden (filter hidden files), binary (filter binary files) and - hidden_and_binary (filter both hidden and binary files). - - - - - /schemas/apps/gedit-2/plugins/filebrowser/filter_pattern - /apps/gedit-2/plugins/filebrowser/filter_pattern - gedit - string - - - File Browser Filter Pattern - The filter pattern to filter the file browser with. This filter - works on top of the filter_mode. - - - - diff --git a/plugins/filebrowser/pluma-file-bookmarks-store.c b/plugins/filebrowser/pluma-file-bookmarks-store.c new file mode 100755 index 00000000..19def257 --- /dev/null +++ b/plugins/filebrowser/pluma-file-bookmarks-store.c @@ -0,0 +1,879 @@ +/* + * pluma-file-bookmarks-store.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include "pluma-file-bookmarks-store.h" +#include "pluma-file-browser-utils.h" + +#define PLUMA_FILE_BOOKMARKS_STORE_GET_PRIVATE(object)( \ + G_TYPE_INSTANCE_GET_PRIVATE((object), PLUMA_TYPE_FILE_BOOKMARKS_STORE, \ + PlumaFileBookmarksStorePrivate)) + +struct _PlumaFileBookmarksStorePrivate +{ + GVolumeMonitor * volume_monitor; + GFileMonitor * bookmarks_monitor; +}; + +static void remove_node (GtkTreeModel * model, + GtkTreeIter * iter); + +static void on_fs_changed (GVolumeMonitor *monitor, + GObject *object, + PlumaFileBookmarksStore *model); + +static void on_bookmarks_file_changed (GFileMonitor * monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + PlumaFileBookmarksStore * model); +static gboolean find_with_flags (GtkTreeModel * model, + GtkTreeIter * iter, + gpointer obj, + guint flags, + guint notflags); + +PLUMA_PLUGIN_DEFINE_TYPE(PlumaFileBookmarksStore, pluma_file_bookmarks_store, GTK_TYPE_TREE_STORE) + +static void +pluma_file_bookmarks_store_dispose (GObject * object) +{ + PlumaFileBookmarksStore *obj = PLUMA_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; + } + + if (obj->priv->bookmarks_monitor != NULL) { + g_object_unref (obj->priv->bookmarks_monitor); + obj->priv->bookmarks_monitor = NULL; + } + + G_OBJECT_CLASS (pluma_file_bookmarks_store_parent_class)->dispose (object); +} + +static void +pluma_file_bookmarks_store_finalize (GObject * object) +{ + G_OBJECT_CLASS (pluma_file_bookmarks_store_parent_class)->finalize (object); +} + +static void +pluma_file_bookmarks_store_class_init (PlumaFileBookmarksStoreClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = pluma_file_bookmarks_store_dispose; + object_class->finalize = pluma_file_bookmarks_store_finalize; + + g_type_class_add_private (object_class, sizeof (PlumaFileBookmarksStorePrivate)); +} + +static void +pluma_file_bookmarks_store_init (PlumaFileBookmarksStore * obj) +{ + obj->priv = PLUMA_FILE_BOOKMARKS_STORE_GET_PRIVATE (obj); +} + +/* Private */ +static void +add_node (PlumaFileBookmarksStore *model, + GdkPixbuf *pixbuf, + 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, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_ICON, pixbuf, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, name, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, obj, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, flags, + -1); + + if (iter != NULL) + *iter = newiter; +} + +static gboolean +add_file (PlumaFileBookmarksStore *model, + GFile *file, + const gchar *name, + guint flags, + GtkTreeIter *iter) +{ + GdkPixbuf *pixbuf = NULL; + gboolean native; + gchar *newname; + + native = g_file_is_native (file); + + if (native && !g_file_query_exists (file, NULL)) { + return FALSE; + } + + if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_HOME) + pixbuf = pluma_file_browser_utils_pixbuf_from_theme ("user-home", GTK_ICON_SIZE_MENU); + else if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_DESKTOP) + pixbuf = pluma_file_browser_utils_pixbuf_from_theme ("user-desktop", GTK_ICON_SIZE_MENU); + else if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT) + pixbuf = pluma_file_browser_utils_pixbuf_from_theme ("drive-harddisk", GTK_ICON_SIZE_MENU); + + if (pixbuf == NULL) { + /* getting the icon is a sync get_info call, so we just do it for local files */ + if (native) { + pixbuf = pluma_file_browser_utils_pixbuf_from_file (file, GTK_ICON_SIZE_MENU); + } else { + pixbuf = pluma_file_browser_utils_pixbuf_from_theme ("folder", GTK_ICON_SIZE_MENU); + } + } + + if (name == NULL) { + newname = pluma_file_browser_utils_file_basename (file); + } else { + newname = g_strdup (name); + } + + add_node (model, pixbuf, newname, G_OBJECT (file), flags, iter); + + if (pixbuf) + g_object_unref (pixbuf); + + g_free (newname); + + return TRUE; +} + +static void +check_mount_separator (PlumaFileBookmarksStore * model, guint flags, + gboolean added) +{ + GtkTreeIter iter; + gboolean found; + + found = + find_with_flags (GTK_TREE_MODEL (model), &iter, NULL, + flags | + PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR, 0); + + if (added && !found) { + /* Add the separator */ + add_node (model, NULL, NULL, NULL, + flags | PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR, + NULL); + } else if (!added && found) { + remove_node (GTK_TREE_MODEL (model), &iter); + } +} + +static void +init_special_directories (PlumaFileBookmarksStore * model) +{ + gchar const *path; + GFile * file; + + path = g_get_home_dir (); + if (path != NULL) + { + file = g_file_new_for_path (path); + add_file (model, file, NULL, PLUMA_FILE_BOOKMARKS_STORE_IS_HOME | + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); + g_object_unref (file); + } + + 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, PLUMA_FILE_BOOKMARKS_STORE_IS_DESKTOP | + PLUMA_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, PLUMA_FILE_BOOKMARKS_STORE_IS_DOCUMENTS | + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); + g_object_unref (file); + } + + file = g_file_new_for_uri ("file:///"); + add_file (model, file, _("File System"), PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT, NULL); + g_object_unref (file); + + check_mount_separator (model, PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT, TRUE); +} + +static void +get_fs_properties (gpointer fs, + gchar **name, + GdkPixbuf **pixbuf, + guint *flags) +{ + GIcon *icon = NULL; + + *flags = PLUMA_FILE_BOOKMARKS_STORE_IS_FS; + *name = NULL; + *pixbuf = NULL; + + if (G_IS_DRIVE (fs)) + { + icon = g_drive_get_icon (G_DRIVE (fs)); + *name = g_drive_get_name (G_DRIVE (fs)); + + *flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_DRIVE; + } + else if (G_IS_VOLUME (fs)) + { + icon = g_volume_get_icon (G_VOLUME (fs)); + *name = g_volume_get_name (G_VOLUME (fs)); + + *flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_VOLUME; + } + else if (G_IS_MOUNT (fs)) + { + icon = g_mount_get_icon (G_MOUNT (fs)); + *name = g_mount_get_name (G_MOUNT (fs)); + + *flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_MOUNT; + } + + if (icon) + { + *pixbuf = pluma_file_browser_utils_pixbuf_from_icon (icon, GTK_ICON_SIZE_MENU); + g_object_unref (icon); + } +} + + +static void +add_fs (PlumaFileBookmarksStore *model, + gpointer fs, + guint flags, + GtkTreeIter *iter) +{ + gchar *name; + GdkPixbuf *pixbuf; + guint fsflags; + + get_fs_properties (fs, &name, &pixbuf, &fsflags); + add_node (model, pixbuf, name, fs, flags | fsflags, iter); + + if (pixbuf) + g_object_unref (pixbuf); + + g_free (name); + check_mount_separator (model, PLUMA_FILE_BOOKMARKS_STORE_IS_FS, TRUE); +} + +static void +process_volume_cb (GVolume *volume, + PlumaFileBookmarksStore *model) +{ + GMount *mount; + guint flags = PLUMA_FILE_BOOKMARKS_STORE_NONE; + mount = g_volume_get_mount (volume); + + /* 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 (PlumaFileBookmarksStore *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, PLUMA_FILE_BOOKMARKS_STORE_NONE, NULL); + } +} + +static void +process_drive_cb (GDrive *drive, + PlumaFileBookmarksStore *model) +{ + GList *volumes; + + 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 (PlumaFileBookmarksStore *model) +{ + GList *drives; + + drives = g_volume_monitor_get_connected_drives (model->priv->volume_monitor); + + g_list_foreach (drives, (GFunc)process_drive_cb, model); + g_list_foreach (drives, (GFunc)g_object_unref, NULL); + g_list_free (drives); +} + +static void +process_volume_nodrive_cb (GVolume *volume, + PlumaFileBookmarksStore *model) +{ + GDrive *drive; + + drive = g_volume_get_drive (volume); + + if (drive) + { + g_object_unref (drive); + return; + } + + process_volume_cb (volume, model); +} + +static void +init_volumes (PlumaFileBookmarksStore *model) +{ + GList *volumes; + + volumes = g_volume_monitor_get_volumes (model->priv->volume_monitor); + + g_list_foreach (volumes, (GFunc)process_volume_nodrive_cb, model); + g_list_foreach (volumes, (GFunc)g_object_unref, NULL); + g_list_free (volumes); +} + +static void +process_mount_novolume_cb (GMount *mount, + PlumaFileBookmarksStore *model) +{ + GVolume *volume; + + 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, PLUMA_FILE_BOOKMARKS_STORE_NONE, NULL); + } +} + +static void +init_mounts (PlumaFileBookmarksStore *model) +{ + GList *mounts; + + mounts = g_volume_monitor_get_mounts (model->priv->volume_monitor); + + g_list_foreach (mounts, (GFunc)process_mount_novolume_cb, model); + g_list_foreach (mounts, (GFunc)g_object_unref, NULL); + g_list_free (mounts); +} + +static void +init_fs (PlumaFileBookmarksStore * 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; 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 (PlumaFileBookmarksStore * model, + gchar const * name, + gchar const * uri) +{ + GFile * file; + gboolean ret; + guint flags = PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK; + GtkTreeIter iter; + + file = g_file_new_for_uri (uri); + + if (g_file_is_native (file)) { + flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_LOCAL_BOOKMARK; + } else { + flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK; + } + + ret = add_file (model, file, name, flags, &iter); + + g_object_unref (file); + + return ret; +} + +static void +init_bookmarks (PlumaFileBookmarksStore * model) +{ + gchar *bookmarks; + GError *error = NULL; + gchar *contents; + gchar **lines; + gchar **line; + gboolean added = FALSE; + + /* Read the bookmarks file */ + bookmarks = g_build_filename (g_get_home_dir (), + ".gtk-bookmarks", + NULL); + + if (g_file_get_contents (bookmarks, &contents, NULL, &error)) { + lines = g_strsplit (contents, "\n", 0); + + for (line = lines; *line; ++line) { + if (**line) { + 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 */ + if (pluma_utils_is_valid_uri (*line)) { + added |= add_bookmark (model, name, *line); + } + } + } + + g_strfreev (lines); + g_free (contents); + + /* Add a watch */ + if (model->priv->bookmarks_monitor == NULL) { + GFile * file; + + 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", + (GCallback)on_bookmarks_file_changed, + model); + } + } else { + /* The bookmarks file doesn't exist (which is perfectly fine) */ + g_error_free (error); + } + + if (added) { + /* Bookmarks separator */ + add_node (model, NULL, NULL, NULL, + PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK | + PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR, NULL); + } + + g_free (bookmarks); +} + +static gint flags_order[] = { + PLUMA_FILE_BOOKMARKS_STORE_IS_HOME, + PLUMA_FILE_BOOKMARKS_STORE_IS_DESKTOP, + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, + PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT, + PLUMA_FILE_BOOKMARKS_STORE_IS_FS, + PLUMA_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, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, &n1, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f1, + -1); + gtk_tree_model_get (model, b, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, &n2, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f2, + -1); + + /* do not sort actual bookmarks to keep same order as in caja */ + if ((f1 & PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK) && + (f2 & PLUMA_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 f1; + guint f2; + gint *flags; + guint sep; + + sep = PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR; + + gtk_tree_model_get (model, a, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f1, + -1); + gtk_tree_model_get (model, b, + PLUMA_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; + + 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, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + &childobj, + PLUMA_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, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!(flags & PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR)) { + if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_FS) { + check_mount_separator (PLUMA_FILE_BOOKMARKS_STORE (model), + flags & PLUMA_FILE_BOOKMARKS_STORE_IS_FS, + FALSE); + } + } + + gtk_tree_store_remove (GTK_TREE_STORE (model), iter); +} + +static void +remove_bookmarks (PlumaFileBookmarksStore * model) +{ + GtkTreeIter iter; + + while (find_with_flags (GTK_TREE_MODEL (model), &iter, NULL, + PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK, + 0)) { + remove_node (GTK_TREE_MODEL (model), &iter); + } +} + +static void +initialize_fill (PlumaFileBookmarksStore * model) +{ + init_special_directories (model); + init_fs (model); + init_bookmarks (model); +} + +/* Public */ +PlumaFileBookmarksStore * +pluma_file_bookmarks_store_new (void) +{ + PlumaFileBookmarksStore *model; + GType column_types[] = { + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_OBJECT, + G_TYPE_UINT + }; + + model = g_object_new (PLUMA_TYPE_FILE_BOOKMARKS_STORE, NULL); + gtk_tree_store_set_column_types (GTK_TREE_STORE (model), + PLUMA_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; +} + +gchar * +pluma_file_bookmarks_store_get_uri (PlumaFileBookmarksStore * model, + GtkTreeIter * iter) +{ + GObject * obj; + GFile * file = NULL; + guint flags; + gchar * ret = NULL; + gboolean isfs; + + g_return_val_if_fail (PLUMA_IS_FILE_BOOKMARKS_STORE (model), NULL); + g_return_val_if_fail (iter != NULL, NULL); + + gtk_tree_model_get (GTK_TREE_MODEL (model), iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + &flags, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + &obj, + -1); + + if (obj == NULL) + return NULL; + + isfs = (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_FS); + + if (isfs && (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_MOUNT)) + { + file = g_mount_get_root (G_MOUNT (obj)); + } + else if (!isfs) + { + file = g_object_ref (obj); + } + + g_object_unref (obj); + + if (file) + { + ret = g_file_get_uri (file); + g_object_unref (file); + } + + return ret; +} + +void +pluma_file_bookmarks_store_refresh (PlumaFileBookmarksStore * model) +{ + gtk_tree_store_clear (GTK_TREE_STORE (model)); + initialize_fill (model); +} + +static void +on_fs_changed (GVolumeMonitor *monitor, + GObject *object, + PlumaFileBookmarksStore *model) +{ + GtkTreeModel *tree_model = GTK_TREE_MODEL (model); + guint flags = PLUMA_FILE_BOOKMARKS_STORE_IS_FS; + guint noflags = PLUMA_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, + PlumaFileBookmarksStore * 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; + case G_FILE_MONITOR_EVENT_DELETED: // FIXME: shouldn't we also monitor the directory? + /* Remove bookmarks */ + remove_bookmarks (model); + g_object_unref (monitor); + model->priv->bookmarks_monitor = NULL; + break; + default: + break; + } +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-bookmarks-store.h b/plugins/filebrowser/pluma-file-bookmarks-store.h new file mode 100755 index 00000000..c811f588 --- /dev/null +++ b/plugins/filebrowser/pluma-file-bookmarks-store.h @@ -0,0 +1,90 @@ +/* + * pluma-file-bookmarks-store.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BOOKMARKS_STORE_H__ +#define __PLUMA_FILE_BOOKMARKS_STORE_H__ + +#include + +G_BEGIN_DECLS +#define PLUMA_TYPE_FILE_BOOKMARKS_STORE (pluma_file_bookmarks_store_get_type ()) +#define PLUMA_FILE_BOOKMARKS_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BOOKMARKS_STORE, PlumaFileBookmarksStore)) +#define PLUMA_FILE_BOOKMARKS_STORE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BOOKMARKS_STORE, PlumaFileBookmarksStore const)) +#define PLUMA_FILE_BOOKMARKS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_FILE_BOOKMARKS_STORE, PlumaFileBookmarksStoreClass)) +#define PLUMA_IS_FILE_BOOKMARKS_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_FILE_BOOKMARKS_STORE)) +#define PLUMA_IS_FILE_BOOKMARKS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_FILE_BOOKMARKS_STORE)) +#define PLUMA_FILE_BOOKMARKS_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_FILE_BOOKMARKS_STORE, PlumaFileBookmarksStoreClass)) + +typedef struct _PlumaFileBookmarksStore PlumaFileBookmarksStore; +typedef struct _PlumaFileBookmarksStoreClass PlumaFileBookmarksStoreClass; +typedef struct _PlumaFileBookmarksStorePrivate PlumaFileBookmarksStorePrivate; + +enum +{ + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_ICON = 0, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + PLUMA_FILE_BOOKMARKS_STORE_N_COLUMNS +}; + +enum +{ + PLUMA_FILE_BOOKMARKS_STORE_NONE = 0, + PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR = 1 << 0, /* Separator item */ + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR = 1 << 1, /* Special user dir */ + PLUMA_FILE_BOOKMARKS_STORE_IS_HOME = 1 << 2, /* The special Home user directory */ + PLUMA_FILE_BOOKMARKS_STORE_IS_DESKTOP = 1 << 3, /* The special Desktop user directory */ + PLUMA_FILE_BOOKMARKS_STORE_IS_DOCUMENTS = 1 << 4, /* The special Documents user directory */ + PLUMA_FILE_BOOKMARKS_STORE_IS_FS = 1 << 5, /* A mount object */ + PLUMA_FILE_BOOKMARKS_STORE_IS_MOUNT = 1 << 6, /* A mount object */ + PLUMA_FILE_BOOKMARKS_STORE_IS_VOLUME = 1 << 7, /* A volume object */ + PLUMA_FILE_BOOKMARKS_STORE_IS_DRIVE = 1 << 8, /* A drive object */ + PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT = 1 << 9, /* The root file system (file:///) */ + PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK = 1 << 10, /* A gtk bookmark */ + PLUMA_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK = 1 << 11, /* A remote gtk bookmark */ + PLUMA_FILE_BOOKMARKS_STORE_IS_LOCAL_BOOKMARK = 1 << 12 /* A local gtk bookmark */ +}; + +struct _PlumaFileBookmarksStore +{ + GtkTreeStore parent; + + PlumaFileBookmarksStorePrivate *priv; +}; + +struct _PlumaFileBookmarksStoreClass +{ + GtkTreeStoreClass parent_class; +}; + +GType pluma_file_bookmarks_store_get_type (void) G_GNUC_CONST; +GType pluma_file_bookmarks_store_register_type (GTypeModule * module); + +PlumaFileBookmarksStore *pluma_file_bookmarks_store_new (void); +gchar *pluma_file_bookmarks_store_get_uri (PlumaFileBookmarksStore * model, + GtkTreeIter * iter); +void pluma_file_bookmarks_store_refresh (PlumaFileBookmarksStore * model); + +G_END_DECLS +#endif /* __PLUMA_FILE_BOOKMARKS_STORE_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-enum-register.c.template b/plugins/filebrowser/pluma-file-browser-enum-register.c.template new file mode 100755 index 00000000..0bbd1018 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-enum-register.c.template @@ -0,0 +1,20 @@ +/*** BEGIN file-header ***/ +void +pluma_file_browser_enum_and_flag_register_type (GTypeModule * module) +{ +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + /* Enumerations from "@filename@" */ + +/*** END file-production ***/ + +/*** BEGIN enumeration-production ***/ + register_@enum_name@ (module); + +/*** END enumeration-production ***/ + +/*** BEGIN file-tail ***/ +} + +/*** END file-tail ***/ diff --git a/plugins/filebrowser/pluma-file-browser-enum-types.c.template b/plugins/filebrowser/pluma-file-browser-enum-types.c.template new file mode 100755 index 00000000..dc1ac9ea --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-enum-types.c.template @@ -0,0 +1,45 @@ +/*** BEGIN file-header ***/ +#include "pluma-file-browser-enum-types.h" + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ +#include "@filename@" + +/*** 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/pluma-file-browser-enum-types.h.template b/plugins/filebrowser/pluma-file-browser-enum-types.h.template new file mode 100755 index 00000000..4f09901e --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-enum-types.h.template @@ -0,0 +1,29 @@ +/*** BEGIN file-header ***/ +#ifndef __PLUMA_FILE_BROWSER_ENUM_TYPES_H__ +#define __PLUMA_FILE_BROWSER_ENUM_TYPES_H__ + +#include + +G_BEGIN_DECLS + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* Enumerations from "@filename@" */ + +/*** END file-production ***/ + +/*** BEGIN enumeration-production ***/ +#define PLUMA_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) +GType @enum_name@_get_type (void) G_GNUC_CONST; + +/*** END enumeration-production ***/ + +/*** BEGIN file-tail ***/ +void pluma_file_browser_enum_and_flag_register_type (GTypeModule * module); + +G_END_DECLS + +#endif /* __PLUMA_FILE_BROWSER_ENUM_TYPES_H__ */ +/*** END file-tail ***/ + diff --git a/plugins/filebrowser/pluma-file-browser-error.h b/plugins/filebrowser/pluma-file-browser-error.h new file mode 100755 index 00000000..59f01e2a --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-error.h @@ -0,0 +1,41 @@ +/* + * pluma-file-browser-error.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_ERROR_H__ +#define __PLUMA_FILE_BROWSER_ERROR_H__ + +G_BEGIN_DECLS + +typedef enum { + PLUMA_FILE_BROWSER_ERROR_NONE, + PLUMA_FILE_BROWSER_ERROR_RENAME, + PLUMA_FILE_BROWSER_ERROR_DELETE, + PLUMA_FILE_BROWSER_ERROR_NEW_FILE, + PLUMA_FILE_BROWSER_ERROR_NEW_DIRECTORY, + PLUMA_FILE_BROWSER_ERROR_OPEN_DIRECTORY, + PLUMA_FILE_BROWSER_ERROR_SET_ROOT, + PLUMA_FILE_BROWSER_ERROR_LOAD_DIRECTORY, + PLUMA_FILE_BROWSER_ERROR_NUM +} PlumaFileBrowserError; + +G_END_DECLS + +#endif /* __PLUMA_FILE_BROWSER_ERROR_H__ */ diff --git a/plugins/filebrowser/pluma-file-browser-marshal.list b/plugins/filebrowser/pluma-file-browser-marshal.list new file mode 100755 index 00000000..5fa72c8b --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-marshal.list @@ -0,0 +1,5 @@ +VOID:UINT,STRING +VOID:STRING,STRING +BOOL:OBJECT,POINTER +BOOL:POINTER +BOOL:VOID diff --git a/plugins/filebrowser/pluma-file-browser-messages.c b/plugins/filebrowser/pluma-file-browser-messages.c new file mode 100755 index 00000000..f4b20d05 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-messages.c @@ -0,0 +1,1033 @@ +#include "pluma-file-browser-messages.h" +#include "pluma-file-browser-store.h" +#include + +#define MESSAGE_OBJECT_PATH "/plugins/filebrowser" +#define WINDOW_DATA_KEY "PlumaFileBrowserMessagesWindowData" + +#define BUS_CONNECT(bus, name, data) pluma_message_bus_connect(bus, MESSAGE_OBJECT_PATH, #name, (PlumaMessageCallback) message_##name##_cb, data, NULL) + +typedef struct +{ + PlumaWindow *window; + PlumaMessage *message; +} MessageCacheData; + +typedef struct +{ + guint row_inserted_id; + guint row_deleted_id; + guint root_changed_id; + guint begin_loading_id; + guint end_loading_id; + + GList *merge_ids; + GtkActionGroup *merged_actions; + + PlumaMessageBus *bus; + PlumaFileBrowserWidget *widget; + GHashTable *row_tracking; + + GHashTable *filters; +} WindowData; + +typedef struct +{ + gulong id; + + PlumaWindow *window; + PlumaMessage *message; +} FilterData; + +static WindowData * +window_data_new (PlumaWindow *window, + PlumaFileBrowserWidget *widget) +{ + WindowData *data = g_slice_new (WindowData); + GtkUIManager *manager; + GList *groups; + + data->bus = pluma_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); + + manager = pluma_file_browser_widget_get_ui_manager (widget); + + data->merge_ids = NULL; + data->merged_actions = gtk_action_group_new ("MessageMergedActions"); + + groups = gtk_ui_manager_get_action_groups (manager); + gtk_ui_manager_insert_action_group (manager, data->merged_actions, g_list_length (groups)); + + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data); + + return data; +} + +static WindowData * +get_window_data (PlumaWindow * window) +{ + return (WindowData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY)); +} + +static void +window_data_free (PlumaWindow *window) +{ + WindowData *data = get_window_data (window); + GtkUIManager *manager; + GList *item; + + g_hash_table_destroy (data->row_tracking); + g_hash_table_destroy (data->filters); + + manager = pluma_file_browser_widget_get_ui_manager (data->widget); + gtk_ui_manager_remove_action_group (manager, data->merged_actions); + + for (item = data->merge_ids; item; item = item->next) + gtk_ui_manager_remove_ui (manager, GPOINTER_TO_INT (item->data)); + + g_list_free (data->merge_ids); + g_object_unref (data->merged_actions); + + g_slice_free (WindowData, data); + + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); +} + +static FilterData * +filter_data_new (PlumaWindow *window, + PlumaMessage *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, + pluma_message_type_identifier (pluma_message_get_object_path (message), + pluma_message_get_method (message)), + data); + + return data; +} + +static void +filter_data_free (FilterData *data) +{ + WindowData *wdata = get_window_data (data->window); + gchar *identifier; + + identifier = pluma_message_type_identifier (pluma_message_get_object_path (data->message), + pluma_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 (PlumaWindow *window, + PlumaMessage *message) +{ + MessageCacheData *data = g_slice_new (MessageCacheData); + + data->window = window; + data->message = message; + + return data; +} + +static void +message_get_root_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + PlumaFileBrowserStore *store; + gchar *uri; + + store = pluma_file_browser_widget_get_browser_store (data->widget); + uri = pluma_file_browser_store_get_virtual_root (store); + + pluma_message_set (message, "uri", uri, NULL); + g_free (uri); +} + +static void +message_set_root_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gchar *root = NULL; + gchar *virtual = NULL; + + pluma_message_get (message, "uri", &root, NULL); + + if (!root) + return; + + if (pluma_message_has_key (message, "virtual")) + pluma_message_get (message, "virtual", &virtual, NULL); + + if (virtual) + pluma_file_browser_widget_set_root_and_virtual_root (data->widget, root, virtual); + else + pluma_file_browser_widget_set_root (data->widget, root, TRUE); + + g_free (root); + g_free (virtual); +} + +static void +message_set_emblem_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gchar *id = NULL; + gchar *emblem = NULL; + GtkTreePath *path; + PlumaFileBrowserStore *store; + + pluma_message_get (message, "id", &id, "emblem", &emblem, NULL); + + if (!id || !emblem) + { + g_free (id); + g_free (emblem); + + return; + } + + path = track_row_lookup (data, id); + + if (path != NULL) + { + GError *error = NULL; + GdkPixbuf *pixbuf; + + pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), + emblem, + 10, + 0, + &error); + + if (pixbuf) + { + GValue value = { 0, }; + GtkTreeIter iter; + + store = pluma_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); + + pluma_file_browser_store_set_value (store, + &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM, + &value); + + g_value_unset (&value); + } + + g_object_unref (pixbuf); + } + + if (error) + g_error_free (error); + } + + g_free (id); + g_free (emblem); +} + +static gchar * +item_id (const gchar *path, + const gchar *uri) +{ + return g_strconcat (path, "::", uri, NULL); +} + +static gchar * +track_row (WindowData *data, + PlumaFileBrowserStore *store, + GtkTreePath *path, + const gchar *uri) +{ + GtkTreeRowReference *ref; + gchar *id; + gchar *pathstr; + + pathstr = gtk_tree_path_to_string (path); + id = item_id (pathstr, uri); + + 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, + PlumaMessage *message) +{ + PlumaFileBrowserStore *store; + gchar *uri = NULL; + guint flags = 0; + gchar *track_id; + + store = pluma_file_browser_widget_get_browser_store (data->widget); + + gtk_tree_model_get (GTK_TREE_MODEL (store), iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!uri) + return; + + if (path && gtk_tree_path_get_depth (path) != 0) + track_id = track_row (data, store, path, uri); + else + track_id = NULL; + + pluma_message_set (message, + "id", track_id, + "uri", uri, + NULL); + + if (pluma_message_has_key (message, "is_directory")) + { + pluma_message_set (message, + "is_directory", FILE_IS_DIR (flags), + NULL); + } + + g_free (uri); + g_free (track_id); +} + +static gboolean +custom_message_filter_func (PlumaFileBrowserWidget *widget, + PlumaFileBrowserStore *store, + GtkTreeIter *iter, + FilterData *data) +{ + WindowData *wdata = get_window_data (data->window); + gchar *uri = NULL; + guint flags = 0; + gboolean filter = FALSE; + GtkTreePath *path; + + gtk_tree_model_get (GTK_TREE_MODEL (store), iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!uri || FILE_IS_DUMMY (flags)) + { + g_free (uri); + 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); + + pluma_message_set (data->message, "filter", filter, NULL); + + pluma_message_bus_send_message_sync (wdata->bus, data->message); + pluma_message_get (data->message, "filter", &filter, NULL); + + return !filter; +} + +static void +message_add_filter_cb (PlumaMessageBus *bus, + PlumaMessage *message, + PlumaWindow *window) +{ + gchar *object_path = NULL; + gchar *method = NULL; + gulong id; + PlumaMessageType *message_type; + PlumaMessage *cbmessage; + FilterData *filter_data; + WindowData *data = get_window_data (window); + + pluma_message_get (message, + "object_path", &object_path, + "method", &method, + NULL); + + // Check if there exists such a 'callback' message + if (!object_path || !method) + { + g_free (object_path); + g_free (method); + + return; + } + + message_type = pluma_message_bus_lookup (bus, object_path, method); + + if (!message_type) + { + g_free (object_path); + g_free (method); + + return; + } + + // Check if the message type has the correct arguments + if (pluma_message_type_lookup (message_type, "id") != G_TYPE_STRING || + pluma_message_type_lookup (message_type, "uri") != G_TYPE_STRING || + pluma_message_type_lookup (message_type, "is_directory") != G_TYPE_BOOLEAN || + pluma_message_type_lookup (message_type, "filter") != G_TYPE_BOOLEAN) + { + return; + } + + cbmessage = pluma_message_type_instantiate (message_type, + "id", NULL, + "uri", NULL, + "is_directory", FALSE, + "filter", FALSE, + NULL); + + // Register the custom filter on the widget + filter_data = filter_data_new (window, cbmessage); + id = pluma_file_browser_widget_add_filter (data->widget, + (PlumaFileBrowserWidgetFilterFunc)custom_message_filter_func, + filter_data, + (GDestroyNotify)filter_data_free); + + filter_data->id = id; +} + +static void +message_remove_filter_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gulong id = 0; + + pluma_message_get (message, "id", &id, NULL); + + if (!id) + return; + + pluma_file_browser_widget_remove_filter (data->widget, id); +} + +static void +message_up_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + PlumaFileBrowserStore *store = pluma_file_browser_widget_get_browser_store (data->widget); + + pluma_file_browser_store_set_virtual_root_up (store); +} + +static void +message_history_back_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_history_back (data->widget); +} + +static void +message_history_forward_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_history_forward (data->widget); +} + +static void +message_refresh_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_refresh (data->widget); +} + +static void +message_set_show_hidden_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gboolean active = FALSE; + PlumaFileBrowserStore *store; + PlumaFileBrowserStoreFilterMode mode; + + pluma_message_get (message, "active", &active, NULL); + + store = pluma_file_browser_widget_get_browser_store (data->widget); + mode = pluma_file_browser_store_get_filter_mode (store); + + if (active) + mode &= ~PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; + else + mode |= PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; + + pluma_file_browser_store_set_filter_mode (store, mode); +} + +static void +message_set_show_binary_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gboolean active = FALSE; + PlumaFileBrowserStore *store; + PlumaFileBrowserStoreFilterMode mode; + + pluma_message_get (message, "active", &active, NULL); + + store = pluma_file_browser_widget_get_browser_store (data->widget); + mode = pluma_file_browser_store_get_filter_mode (store); + + if (active) + mode &= ~PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; + else + mode |= PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; + + pluma_file_browser_store_set_filter_mode (store, mode); +} + +static void +message_show_bookmarks_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_show_bookmarks (data->widget); +} + +static void +message_show_files_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_show_files (data->widget); +} + +static void +message_add_context_item_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + GtkAction *action = NULL; + gchar *path = NULL; + gchar *name; + GtkUIManager *manager; + guint merge_id; + + pluma_message_get (message, + "action", &action, + "path", &path, + NULL); + + if (!action || !path) + { + if (action) + g_object_unref (action); + + g_free (path); + return; + } + + gtk_action_group_add_action (data->merged_actions, action); + manager = pluma_file_browser_widget_get_ui_manager (data->widget); + name = g_strconcat (gtk_action_get_name (action), "MenuItem", NULL); + merge_id = gtk_ui_manager_new_merge_id (manager); + + gtk_ui_manager_add_ui (manager, + merge_id, + path, + name, + gtk_action_get_name (action), + GTK_UI_MANAGER_AUTO, + FALSE); + + if (gtk_ui_manager_get_widget (manager, path)) + { + data->merge_ids = g_list_prepend (data->merge_ids, GINT_TO_POINTER (merge_id)); + pluma_message_set (message, "id", merge_id, NULL); + } + else + { + pluma_message_set (message, "id", 0, NULL); + } + + g_object_unref (action); + g_free (path); + g_free (name); +} + +static void +message_remove_context_item_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + guint merge_id = 0; + GtkUIManager *manager; + + pluma_message_get (message, "id", &merge_id, NULL); + + if (merge_id == 0) + return; + + manager = pluma_file_browser_widget_get_ui_manager (data->widget); + + data->merge_ids = g_list_remove (data->merge_ids, GINT_TO_POINTER (merge_id)); + gtk_ui_manager_remove_ui (manager, merge_id); +} + +static void +message_get_view_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + PlumaFileBrowserView *view; + view = pluma_file_browser_widget_get_browser_view (data->widget); + + pluma_message_set (message, "view", view, NULL); +} + +static void +register_methods (PlumaWindow *window, + PlumaFileBrowserWidget *widget) +{ + PlumaMessageBus *bus = pluma_window_get_message_bus (window); + WindowData *data = get_window_data (window); + + /* Register method calls */ + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "get_root", + 1, + "uri", G_TYPE_STRING, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "set_root", + 1, + "uri", G_TYPE_STRING, + "virtual", G_TYPE_STRING, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "set_emblem", + 0, + "id", G_TYPE_STRING, + "emblem", G_TYPE_STRING, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "add_filter", + 1, + "object_path", G_TYPE_STRING, + "method", G_TYPE_STRING, + "id", G_TYPE_ULONG, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "remove_filter", + 0, + "id", G_TYPE_ULONG, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "add_context_item", + 1, + "action", GTK_TYPE_ACTION, + "path", G_TYPE_STRING, + "id", G_TYPE_UINT, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "remove_context_item", + 0, + "id", G_TYPE_UINT, + NULL); + + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "up", 0, NULL); + + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_back", 0, NULL); + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_forward", 0, NULL); + + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "refresh", 0, NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "set_show_hidden", + 0, + "active", G_TYPE_BOOLEAN, + NULL); + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "set_show_binary", + 0, + "active", G_TYPE_BOOLEAN, + NULL); + + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_bookmarks", 0, NULL); + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_files", 0, NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "get_view", + 1, + "view", PLUMA_TYPE_FILE_BROWSER_VIEW, + NULL); + + BUS_CONNECT (bus, get_root, data); + BUS_CONNECT (bus, set_root, data); + BUS_CONNECT (bus, set_emblem, data); + BUS_CONNECT (bus, add_filter, window); + BUS_CONNECT (bus, remove_filter, data); + + BUS_CONNECT (bus, add_context_item, data); + BUS_CONNECT (bus, remove_context_item, data); + + 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 (PlumaFileBrowserStore *store, + GtkTreePath *path, + GtkTreeIter *iter, + MessageCacheData *data) +{ + gchar *uri = NULL; + guint flags = 0; + + gtk_tree_model_get (GTK_TREE_MODEL (store), iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + PLUMA_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); + pluma_message_bus_send_message_sync (wdata->bus, data->message); + } + + g_free (uri); +} + +static void +store_row_deleted (PlumaFileBrowserStore *store, + GtkTreePath *path, + MessageCacheData *data) +{ + GtkTreeIter iter; + gchar *uri = NULL; + 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, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + PLUMA_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); + pluma_message_bus_send_message_sync (wdata->bus, data->message); + } + + g_free (uri); +} + +static void +store_virtual_root_changed (PlumaFileBrowserStore *store, + GParamSpec *spec, + MessageCacheData *data) +{ + WindowData *wdata = get_window_data (data->window); + gchar *uri; + + uri = pluma_file_browser_store_get_virtual_root (store); + + if (!uri) + return; + + pluma_message_set (data->message, + "uri", uri, + NULL); + + pluma_message_bus_send_message_sync (wdata->bus, data->message); + + g_free (uri); +} + +static void +store_begin_loading (PlumaFileBrowserStore *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); + + pluma_message_bus_send_message_sync (wdata->bus, data->message); + gtk_tree_path_free (path); +} + +static void +store_end_loading (PlumaFileBrowserStore *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); + + pluma_message_bus_send_message_sync (wdata->bus, data->message); + gtk_tree_path_free (path); +} + +static void +register_signals (PlumaWindow *window, + PlumaFileBrowserWidget *widget) +{ + PlumaMessageBus *bus = pluma_window_get_message_bus (window); + PlumaFileBrowserStore *store; + PlumaMessageType *inserted_type; + PlumaMessageType *deleted_type; + PlumaMessageType *begin_loading_type; + PlumaMessageType *end_loading_type; + PlumaMessageType *root_changed_type; + + PlumaMessage *message; + WindowData *data; + + /* Register signals */ + root_changed_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "root_changed", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + NULL); + + begin_loading_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "begin_loading", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + NULL); + + end_loading_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "end_loading", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + NULL); + + inserted_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "inserted", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + "is_directory", G_TYPE_BOOLEAN, + NULL); + + deleted_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "deleted", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + "is_directory", G_TYPE_BOOLEAN, + NULL); + + store = pluma_file_browser_widget_get_browser_store (widget); + + message = pluma_message_type_instantiate (inserted_type, + "id", NULL, + "uri", NULL, + "is_directory", FALSE, + 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 = pluma_message_type_instantiate (deleted_type, + "id", NULL, + "uri", NULL, + "is_directory", FALSE, + NULL); + data->row_deleted_id = + g_signal_connect_data (store, + "row-deleted", + G_CALLBACK (store_row_deleted), + message_cache_data_new (window, message), + (GClosureNotify)message_cache_data_free, + 0); + + message = pluma_message_type_instantiate (root_changed_type, + "id", NULL, + "uri", NULL, + 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 = pluma_message_type_instantiate (begin_loading_type, + "id", NULL, + "uri", NULL, + 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 = pluma_message_type_instantiate (end_loading_type, + "id", NULL, + "uri", NULL, + 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 (PlumaMessageBus *bus, + PlumaMessageType *message_type, + PlumaWindow *window) +{ + gchar *identifier = pluma_message_type_identifier (pluma_message_type_get_object_path (message_type), + pluma_message_type_get_method (message_type)); + FilterData *data; + WindowData *wdata = get_window_data (window); + + data = g_hash_table_lookup (wdata->filters, identifier); + + if (data) + pluma_file_browser_widget_remove_filter (wdata->widget, data->id); + + g_free (identifier); +} + +void +pluma_file_browser_messages_register (PlumaWindow *window, + PlumaFileBrowserWidget *widget) +{ + window_data_new (window, widget); + + register_methods (window, widget); + register_signals (window, widget); + + g_signal_connect (pluma_window_get_message_bus (window), + "unregistered", + G_CALLBACK (message_unregistered), + window); +} + +static void +cleanup_signals (PlumaWindow *window) +{ + WindowData *data = get_window_data (window); + PlumaFileBrowserStore *store; + + store = pluma_file_browser_widget_get_browser_store (data->widget); + + g_signal_handler_disconnect (store, data->row_inserted_id); + g_signal_handler_disconnect (store, data->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 +pluma_file_browser_messages_unregister (PlumaWindow *window) +{ + PlumaMessageBus *bus = pluma_window_get_message_bus (window); + + cleanup_signals (window); + pluma_message_bus_unregister_all (bus, MESSAGE_OBJECT_PATH); + + window_data_free (window); +} diff --git a/plugins/filebrowser/pluma-file-browser-messages.h b/plugins/filebrowser/pluma-file-browser-messages.h new file mode 100755 index 00000000..8f5c2ba4 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-messages.h @@ -0,0 +1,35 @@ +/* + * pluma-file-browser-messages.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2008 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_MESSAGES_H__ +#define __PLUMA_FILE_BROWSER_MESSAGES_H__ + +#include +#include +#include "pluma-file-browser-widget.h" + +void pluma_file_browser_messages_register (PlumaWindow *window, + PlumaFileBrowserWidget *widget); +void pluma_file_browser_messages_unregister (PlumaWindow *window); + +#endif /* __PLUMA_FILE_BROWSER_MESSAGES_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-plugin.c b/plugins/filebrowser/pluma-file-browser-plugin.c new file mode 100755 index 00000000..b9ac96d3 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-plugin.c @@ -0,0 +1,1254 @@ +/* + * pluma-file-browser-plugin.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "pluma-file-browser-enum-types.h" +#include "pluma-file-browser-plugin.h" +#include "pluma-file-browser-utils.h" +#include "pluma-file-browser-error.h" +#include "pluma-file-browser-widget.h" +#include "pluma-file-browser-messages.h" + +#define WINDOW_DATA_KEY "PlumaFileBrowserPluginWindowData" +#define FILE_BROWSER_BASE_KEY "/apps/pluma-2/plugins/filebrowser" +#define CAJA_CLICK_POLICY_BASE_KEY "/apps/caja/preferences" +#define CAJA_CLICK_POLICY_KEY "click_policy" +#define CAJA_ENABLE_DELETE_KEY "enable_delete" +#define CAJA_CONFIRM_TRASH_KEY "confirm_trash" +#define TERMINAL_EXEC_KEY "/desktop/mate/applications/terminal/exec" + +#define PLUMA_FILE_BROWSER_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), PLUMA_TYPE_FILE_BROWSER_PLUGIN, PlumaFileBrowserPluginPrivate)) + +struct _PlumaFileBrowserPluginPrivate +{ + gpointer dummy; +}; + +typedef struct _PlumaFileBrowserPluginData +{ + PlumaFileBrowserWidget * tree_widget; + gulong merge_id; + GtkActionGroup * action_group; + GtkActionGroup * single_selection_action_group; + gboolean auto_root; + gulong end_loading_handle; + gboolean confirm_trash; + + guint click_policy_handle; + guint enable_delete_handle; + guint confirm_trash_handle; +} PlumaFileBrowserPluginData; + +static void on_uri_activated_cb (PlumaFileBrowserWidget * widget, + gchar const *uri, + PlumaWindow * window); +static void on_error_cb (PlumaFileBrowserWidget * widget, + guint code, + gchar const *message, + PlumaWindow * window); +static void on_model_set_cb (PlumaFileBrowserView * widget, + GParamSpec *arg1, + PlumaWindow * window); +static void on_virtual_root_changed_cb (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaWindow * window); +static void on_filter_mode_changed_cb (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaWindow * window); +static void on_rename_cb (PlumaFileBrowserStore * model, + const gchar * olduri, + const gchar * newuri, + PlumaWindow * window); +static void on_filter_pattern_changed_cb (PlumaFileBrowserWidget * widget, + GParamSpec * param, + PlumaWindow * window); +static void on_tab_added_cb (PlumaWindow * window, + PlumaTab * tab, + PlumaFileBrowserPluginData * data); +static gboolean on_confirm_delete_cb (PlumaFileBrowserWidget * widget, + PlumaFileBrowserStore * store, + GList * rows, + PlumaWindow * window); +static gboolean on_confirm_no_trash_cb (PlumaFileBrowserWidget * widget, + GList * files, + PlumaWindow * window); + +PLUMA_PLUGIN_REGISTER_TYPE_WITH_CODE (PlumaFileBrowserPlugin, filetree_plugin, \ + pluma_file_browser_enum_and_flag_register_type (type_module); \ + pluma_file_browser_store_register_type (type_module); \ + pluma_file_bookmarks_store_register_type (type_module); \ + pluma_file_browser_view_register_type (type_module); \ + pluma_file_browser_widget_register_type (type_module); \ +) + + +static void +filetree_plugin_init (PlumaFileBrowserPlugin * plugin) +{ + plugin->priv = PLUMA_FILE_BROWSER_PLUGIN_GET_PRIVATE (plugin); +} + +static void +filetree_plugin_finalize (GObject * object) +{ + //PlumaFileBrowserPlugin * plugin = PLUMA_FILE_BROWSER_PLUGIN (object); + + G_OBJECT_CLASS (filetree_plugin_parent_class)->finalize (object); +} + +static PlumaFileBrowserPluginData * +get_plugin_data (PlumaWindow * window) +{ + return (PlumaFileBrowserPluginData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY)); +} + +static void +on_end_loading_cb (PlumaFileBrowserStore * store, + GtkTreeIter * iter, + PlumaFileBrowserPluginData * data) +{ + /* Disconnect the signal */ + g_signal_handler_disconnect (store, data->end_loading_handle); + data->end_loading_handle = 0; + data->auto_root = FALSE; +} + +static void +prepare_auto_root (PlumaFileBrowserPluginData *data) +{ + PlumaFileBrowserStore *store; + + data->auto_root = TRUE; + + store = pluma_file_browser_widget_get_browser_store (data->tree_widget); + + if (data->end_loading_handle != 0) { + g_signal_handler_disconnect (store, data->end_loading_handle); + data->end_loading_handle = 0; + } + + data->end_loading_handle = g_signal_connect (store, + "end-loading", + G_CALLBACK (on_end_loading_cb), + data); +} + +static void +restore_default_location (PlumaFileBrowserPluginData *data) +{ + gchar * root; + gchar * virtual_root; + gboolean bookmarks; + gboolean remote; + MateConfClient * client; + + client = mateconf_client_get_default (); + if (!client) + return; + + bookmarks = !mateconf_client_get_bool (client, + FILE_BROWSER_BASE_KEY "/on_load/tree_view", + NULL); + + if (bookmarks) { + g_object_unref (client); + pluma_file_browser_widget_show_bookmarks (data->tree_widget); + return; + } + + root = mateconf_client_get_string (client, + FILE_BROWSER_BASE_KEY "/on_load/root", + NULL); + virtual_root = mateconf_client_get_string (client, + FILE_BROWSER_BASE_KEY "/on_load/virtual_root", + NULL); + + remote = mateconf_client_get_bool (client, + FILE_BROWSER_BASE_KEY "/on_load/enable_remote", + NULL); + + if (root != NULL && *root != '\0') { + GFile *file; + + file = g_file_new_for_uri (root); + + if (remote || g_file_is_native (file)) { + if (virtual_root != NULL && *virtual_root != '\0') { + prepare_auto_root (data); + pluma_file_browser_widget_set_root_and_virtual_root (data->tree_widget, + root, + virtual_root); + } else { + prepare_auto_root (data); + pluma_file_browser_widget_set_root (data->tree_widget, + root, + TRUE); + } + } + + g_object_unref (file); + } + + g_object_unref (client); + g_free (root); + g_free (virtual_root); +} + +static void +restore_filter (PlumaFileBrowserPluginData * data) +{ + MateConfClient * client; + gchar *filter_mode; + PlumaFileBrowserStoreFilterMode mode; + gchar *pattern; + + client = mateconf_client_get_default (); + if (!client) + return; + + /* Get filter_mode */ + filter_mode = mateconf_client_get_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + NULL); + + /* Filter mode */ + mode = pluma_file_browser_store_filter_mode_get_default (); + + if (filter_mode != NULL) { + if (strcmp (filter_mode, "hidden") == 0) { + mode = PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; + } else if (strcmp (filter_mode, "binary") == 0) { + mode = PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; + } else if (strcmp (filter_mode, "hidden_and_binary") == 0 || + strcmp (filter_mode, "binary_and_hidden") == 0) { + mode = PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN | + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; + } else if (strcmp (filter_mode, "none") == 0 || + *filter_mode == '\0') { + mode = PLUMA_FILE_BROWSER_STORE_FILTER_MODE_NONE; + } + } + + /* Set the filter mode */ + pluma_file_browser_store_set_filter_mode ( + pluma_file_browser_widget_get_browser_store (data->tree_widget), + mode); + + pattern = mateconf_client_get_string (client, + FILE_BROWSER_BASE_KEY "/filter_pattern", + NULL); + + pluma_file_browser_widget_set_filter_pattern (data->tree_widget, + pattern); + + g_object_unref (client); + g_free (filter_mode); + g_free (pattern); +} + +static PlumaFileBrowserViewClickPolicy +click_policy_from_string (gchar const *click_policy) +{ + if (click_policy && strcmp (click_policy, "single") == 0) + return PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE; + else + return PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE; +} + +static void +on_click_policy_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer user_data) +{ + MateConfValue *value; + PlumaFileBrowserPluginData * data; + gchar const *click_policy; + PlumaFileBrowserViewClickPolicy policy = PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE; + PlumaFileBrowserView *view; + + data = (PlumaFileBrowserPluginData *)(user_data); + value = mateconf_entry_get_value (entry); + + if (value && value->type == MATECONF_VALUE_STRING) { + click_policy = mateconf_value_get_string (value); + + policy = click_policy_from_string (click_policy); + } + + view = pluma_file_browser_widget_get_browser_view (data->tree_widget); + pluma_file_browser_view_set_click_policy (view, policy); +} + +static void +on_enable_delete_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer user_data) +{ + MateConfValue *value; + PlumaFileBrowserPluginData *data; + gboolean enable = FALSE; + + data = (PlumaFileBrowserPluginData *)(user_data); + value = mateconf_entry_get_value (entry); + + if (value && value->type == MATECONF_VALUE_BOOL) + enable = mateconf_value_get_bool (value); + + g_object_set (G_OBJECT (data->tree_widget), "enable-delete", enable, NULL); +} + +static void +on_confirm_trash_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer user_data) +{ + MateConfValue *value; + PlumaFileBrowserPluginData *data; + gboolean enable = FALSE; + + data = (PlumaFileBrowserPluginData *)(user_data); + value = mateconf_entry_get_value (entry); + + if (value && value->type == MATECONF_VALUE_BOOL) + enable = mateconf_value_get_bool (value); + + data->confirm_trash = enable; +} + +static void +install_caja_prefs (PlumaFileBrowserPluginData *data) +{ + MateConfClient *client; + gchar *pref; + gboolean prefb; + PlumaFileBrowserViewClickPolicy policy; + PlumaFileBrowserView *view; + + client = mateconf_client_get_default (); + if (!client) + return; + + mateconf_client_add_dir (client, + CAJA_CLICK_POLICY_BASE_KEY, + MATECONF_CLIENT_PRELOAD_NONE, + NULL); + + /* Get click_policy */ + pref = mateconf_client_get_string (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CLICK_POLICY_KEY, + NULL); + + policy = click_policy_from_string (pref); + + view = pluma_file_browser_widget_get_browser_view (data->tree_widget); + pluma_file_browser_view_set_click_policy (view, policy); + + if (pref) { + data->click_policy_handle = + mateconf_client_notify_add (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CLICK_POLICY_KEY, + on_click_policy_changed, + data, + NULL, + NULL); + g_free (pref); + } + + /* Get enable_delete */ + prefb = mateconf_client_get_bool (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_ENABLE_DELETE_KEY, + NULL); + + g_object_set (G_OBJECT (data->tree_widget), "enable-delete", prefb, NULL); + + data->enable_delete_handle = + mateconf_client_notify_add (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_ENABLE_DELETE_KEY, + on_enable_delete_changed, + data, + NULL, + NULL); + + /* Get confirm_trash */ + prefb = mateconf_client_get_bool (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CONFIRM_TRASH_KEY, + NULL); + + data->confirm_trash = prefb; + + data->confirm_trash_handle = + mateconf_client_notify_add (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CONFIRM_TRASH_KEY, + on_confirm_trash_changed, + data, + NULL, + NULL); + g_object_unref (client); +} + +static void +set_root_from_doc (PlumaFileBrowserPluginData * data, + PlumaDocument * doc) +{ + GFile *file; + GFile *parent; + + if (doc == NULL) + return; + + file = pluma_document_get_location (doc); + if (file == NULL) + return; + + parent = g_file_get_parent (file); + + if (parent != NULL) { + gchar * root; + + root = g_file_get_uri (parent); + + pluma_file_browser_widget_set_root (data->tree_widget, + root, + TRUE); + + g_object_unref (parent); + g_free (root); + } + + g_object_unref (file); +} + +static void +on_action_set_active_root (GtkAction * action, + PlumaWindow * window) +{ + PlumaFileBrowserPluginData *data; + + data = get_plugin_data (window); + set_root_from_doc (data, + pluma_window_get_active_document (window)); +} + +static gchar * +get_terminal (void) +{ + MateConfClient * client; + gchar * terminal; + + client = mateconf_client_get_default (); + terminal = mateconf_client_get_string (client, + TERMINAL_EXEC_KEY, + NULL); + g_object_unref (client); + + 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 +on_action_open_terminal (GtkAction * action, + PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + gchar * terminal; + gchar * wd = NULL; + gchar * local; + gchar * argv[2]; + GFile * file; + + GtkTreeIter iter; + PlumaFileBrowserStore * store; + + data = get_plugin_data (window); + + /* Get the current directory */ + if (!pluma_file_browser_widget_get_selected_directory (data->tree_widget, &iter)) + return; + + store = pluma_file_browser_widget_get_browser_store (data->tree_widget); + gtk_tree_model_get (GTK_TREE_MODEL (store), + &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &wd, + -1); + + if (wd == NULL) + return; + + terminal = get_terminal (); + + file = g_file_new_for_uri (wd); + local = g_file_get_path (file); + g_object_unref (file); + + 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 (wd); + g_free (local); +} + +static void +on_selection_changed_cb (GtkTreeSelection *selection, + PlumaWindow *window) +{ + PlumaFileBrowserPluginData * data; + GtkTreeView * tree_view; + GtkTreeModel * model; + GtkTreeIter iter; + gboolean sensitive; + gchar * uri; + + data = get_plugin_data (window); + + tree_view = GTK_TREE_VIEW (pluma_file_browser_widget_get_browser_view (data->tree_widget)); + model = gtk_tree_view_get_model (tree_view); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + sensitive = pluma_file_browser_widget_get_selected_directory (data->tree_widget, &iter); + + if (sensitive) { + gtk_tree_model_get (model, &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, -1); + + sensitive = pluma_utils_uri_has_file_scheme (uri); + g_free (uri); + } + + gtk_action_set_sensitive ( + gtk_action_group_get_action (data->single_selection_action_group, + "OpenTerminal"), + sensitive); +} + +#define POPUP_UI "" \ +"" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +"" + +static GtkActionEntry extra_actions[] = +{ + {"SetActiveRoot", GTK_STOCK_JUMP_TO, N_("_Set root to active document"), + NULL, + N_("Set the root to the active document location"), + G_CALLBACK (on_action_set_active_root)} +}; + +static GtkActionEntry extra_single_selection_actions[] = { + {"OpenTerminal", "utilities-terminal", N_("_Open terminal here"), + NULL, + N_("Open a terminal at the currently opened directory"), + G_CALLBACK (on_action_open_terminal)} +}; + +static void +add_popup_ui (PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + GtkUIManager * manager; + GtkActionGroup * action_group; + GError * error = NULL; + + data = get_plugin_data (window); + manager = pluma_file_browser_widget_get_ui_manager (data->tree_widget); + + action_group = gtk_action_group_new ("FileBrowserPluginExtra"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + extra_actions, + G_N_ELEMENTS (extra_actions), + window); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + data->action_group = action_group; + + action_group = gtk_action_group_new ("FileBrowserPluginSingleSelectionExtra"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + extra_single_selection_actions, + G_N_ELEMENTS (extra_single_selection_actions), + window); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + data->single_selection_action_group = action_group; + + data->merge_id = gtk_ui_manager_add_ui_from_string (manager, + POPUP_UI, + -1, + &error); + + if (data->merge_id == 0) { + g_warning("Unable to merge UI: %s", error->message); + g_error_free(error); + } +} + +static void +remove_popup_ui (PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + GtkUIManager * manager; + + data = get_plugin_data (window); + manager = pluma_file_browser_widget_get_ui_manager (data->tree_widget); + gtk_ui_manager_remove_ui (manager, data->merge_id); + + gtk_ui_manager_remove_action_group (manager, data->action_group); + g_object_unref (data->action_group); + + gtk_ui_manager_remove_action_group (manager, data->single_selection_action_group); + g_object_unref (data->single_selection_action_group); +} + +static void +impl_updateui (PlumaPlugin * plugin, PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + PlumaDocument * doc; + + data = get_plugin_data (window); + + doc = pluma_window_get_active_document (window); + + gtk_action_set_sensitive (gtk_action_group_get_action (data->action_group, + "SetActiveRoot"), + doc != NULL && + !pluma_document_is_untitled (doc)); +} + +static void +impl_activate (PlumaPlugin * plugin, PlumaWindow * window) +{ + PlumaPanel * panel; + PlumaFileBrowserPluginData * data; + GtkWidget * image; + GdkPixbuf * pixbuf; + PlumaFileBrowserStore * store; + gchar *data_dir; + + data = g_new0 (PlumaFileBrowserPluginData, 1); + + data_dir = pluma_plugin_get_data_dir (plugin); + data->tree_widget = PLUMA_FILE_BROWSER_WIDGET (pluma_file_browser_widget_new (data_dir)); + g_free (data_dir); + + g_signal_connect (data->tree_widget, + "uri-activated", + G_CALLBACK (on_uri_activated_cb), window); + + g_signal_connect (data->tree_widget, + "error", G_CALLBACK (on_error_cb), window); + + g_signal_connect (data->tree_widget, + "notify::filter-pattern", + G_CALLBACK (on_filter_pattern_changed_cb), + window); + + g_signal_connect (data->tree_widget, + "confirm-delete", + G_CALLBACK (on_confirm_delete_cb), + window); + + g_signal_connect (data->tree_widget, + "confirm-no-trash", + G_CALLBACK (on_confirm_no_trash_cb), + window); + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW + (pluma_file_browser_widget_get_browser_view + (data->tree_widget))), + "changed", + G_CALLBACK (on_selection_changed_cb), + window); + + panel = pluma_window_get_side_panel (window); + pixbuf = pluma_file_browser_utils_pixbuf_from_theme("system-file-manager", + GTK_ICON_SIZE_MENU); + + if (pixbuf) { + image = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + } else { + image = gtk_image_new_from_stock(GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU); + } + + gtk_widget_show(image); + pluma_panel_add_item (panel, + GTK_WIDGET (data->tree_widget), + _("File Browser"), + image); + gtk_widget_show (GTK_WIDGET (data->tree_widget)); + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data); + + add_popup_ui (window); + + /* Restore filter options */ + restore_filter (data); + + /* Install caja preferences */ + install_caja_prefs (data); + + /* Connect signals to store the last visited location */ + g_signal_connect (pluma_file_browser_widget_get_browser_view (data->tree_widget), + "notify::model", + G_CALLBACK (on_model_set_cb), + window); + + store = pluma_file_browser_widget_get_browser_store (data->tree_widget); + g_signal_connect (store, + "notify::virtual-root", + G_CALLBACK (on_virtual_root_changed_cb), + window); + + g_signal_connect (store, + "notify::filter-mode", + G_CALLBACK (on_filter_mode_changed_cb), + window); + + g_signal_connect (store, + "rename", + G_CALLBACK (on_rename_cb), + window); + + g_signal_connect (window, + "tab-added", + G_CALLBACK (on_tab_added_cb), + data); + + /* Register messages on the bus */ + pluma_file_browser_messages_register (window, data->tree_widget); + + impl_updateui (plugin, window); +} + +static void +impl_deactivate (PlumaPlugin * plugin, PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + PlumaPanel * panel; + MateConfClient *client; + + data = get_plugin_data (window); + + /* Unregister messages from the bus */ + pluma_file_browser_messages_unregister (window); + + /* Disconnect signals */ + g_signal_handlers_disconnect_by_func (window, + G_CALLBACK (on_tab_added_cb), + data); + + client = mateconf_client_get_default (); + mateconf_client_remove_dir (client, CAJA_CLICK_POLICY_BASE_KEY, NULL); + + if (data->click_policy_handle) + mateconf_client_notify_remove (client, data->click_policy_handle); + + if (data->enable_delete_handle) + mateconf_client_notify_remove (client, data->enable_delete_handle); + + if (data->confirm_trash_handle) + mateconf_client_notify_remove (client, data->confirm_trash_handle); + + g_object_unref (client); + remove_popup_ui (window); + + panel = pluma_window_get_side_panel (window); + pluma_panel_remove_item (panel, GTK_WIDGET (data->tree_widget)); + + g_free (data); + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); +} + +static void +filetree_plugin_class_init (PlumaFileBrowserPluginClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass * plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = filetree_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_updateui; + + g_type_class_add_private (object_class, + sizeof (PlumaFileBrowserPluginPrivate)); +} + +/* Callbacks */ +static void +on_uri_activated_cb (PlumaFileBrowserWidget * tree_widget, + gchar const *uri, PlumaWindow * window) +{ + pluma_commands_load_uri (window, uri, NULL, 0); +} + +static void +on_error_cb (PlumaFileBrowserWidget * tree_widget, + guint code, gchar const *message, PlumaWindow * window) +{ + gchar * title; + GtkWidget * dlg; + PlumaFileBrowserPluginData * data; + + data = get_plugin_data (window); + + /* Do not show the error when the root has been set automatically */ + if (data->auto_root && (code == PLUMA_FILE_BROWSER_ERROR_SET_ROOT || + code == PLUMA_FILE_BROWSER_ERROR_LOAD_DIRECTORY)) + { + /* Show bookmarks */ + pluma_file_browser_widget_show_bookmarks (data->tree_widget); + return; + } + + switch (code) { + case PLUMA_FILE_BROWSER_ERROR_NEW_DIRECTORY: + title = + _("An error occurred while creating a new directory"); + break; + case PLUMA_FILE_BROWSER_ERROR_NEW_FILE: + title = _("An error occurred while creating a new file"); + break; + case PLUMA_FILE_BROWSER_ERROR_RENAME: + title = + _ + ("An error occurred while renaming a file or directory"); + break; + case PLUMA_FILE_BROWSER_ERROR_DELETE: + title = + _ + ("An error occurred while deleting a file or directory"); + break; + case PLUMA_FILE_BROWSER_ERROR_OPEN_DIRECTORY: + title = + _ + ("An error occurred while opening a directory in the file manager"); + break; + case PLUMA_FILE_BROWSER_ERROR_SET_ROOT: + title = + _("An error occurred while setting a root directory"); + break; + case PLUMA_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 (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 (PlumaFileBrowserView * widget, + GParamSpec *arg1, + PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data = get_plugin_data (window); + GtkTreeModel * model; + MateConfClient * client; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (pluma_file_browser_widget_get_browser_view (data->tree_widget))); + + if (model == NULL) + return; + + client = mateconf_client_get_default (); + mateconf_client_set_bool (client, + FILE_BROWSER_BASE_KEY "/on_load/tree_view", + PLUMA_IS_FILE_BROWSER_STORE (model), + NULL); + g_object_unref (client); +} + +static void +on_filter_mode_changed_cb (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaWindow * window) +{ + MateConfClient * client; + PlumaFileBrowserStoreFilterMode mode; + + client = mateconf_client_get_default (); + + if (!client) + return; + + mode = pluma_file_browser_store_get_filter_mode (model); + + if ((mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) && + (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY)) { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + "hidden_and_binary", + NULL); + } else if (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + "hidden", + NULL); + } else if (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY) { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + "binary", + NULL); + } else { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + "none", + NULL); + } + + g_object_unref (client); + +} + +static void +on_rename_cb (PlumaFileBrowserStore * store, + const gchar * olduri, + const gchar * newuri, + PlumaWindow * window) +{ + PlumaApp * app; + GList * documents; + GList * item; + PlumaDocument * doc; + GFile * docfile; + GFile * oldfile; + GFile * newfile; + gchar * uri; + + /* Find all documents and set its uri to newuri where it matches olduri */ + app = pluma_app_get_default (); + documents = pluma_app_get_documents (app); + + oldfile = g_file_new_for_uri (olduri); + newfile = g_file_new_for_uri (newuri); + + for (item = documents; item; item = item->next) { + doc = PLUMA_DOCUMENT (item->data); + uri = pluma_document_get_uri (doc); + + if (!uri) + continue; + + docfile = g_file_new_for_uri (uri); + + if (g_file_equal (docfile, oldfile)) { + pluma_document_set_uri (doc, newuri); + } else { + gchar *relative; + + relative = g_file_get_relative_path (oldfile, docfile); + + if (relative) { + /* relative now contains the part in docfile without + the prefix oldfile */ + + g_object_unref (docfile); + g_free (uri); + + docfile = g_file_get_child (newfile, relative); + uri = g_file_get_uri (docfile); + + pluma_document_set_uri (doc, uri); + } + + g_free (relative); + } + + g_free (uri); + g_object_unref (docfile); + } + + g_object_unref (oldfile); + g_object_unref (newfile); + + g_list_free (documents); +} + +static void +on_filter_pattern_changed_cb (PlumaFileBrowserWidget * widget, + GParamSpec * param, + PlumaWindow * window) +{ + MateConfClient * client; + gchar * pattern; + + client = mateconf_client_get_default (); + + if (!client) + return; + + g_object_get (G_OBJECT (widget), "filter-pattern", &pattern, NULL); + + if (pattern == NULL) + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_pattern", + "", + NULL); + else + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_pattern", + pattern, + NULL); + + g_free (pattern); +} + +static void +on_virtual_root_changed_cb (PlumaFileBrowserStore * store, + GParamSpec * param, + PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data = get_plugin_data (window); + gchar * root; + gchar * virtual_root; + MateConfClient * client; + + root = pluma_file_browser_store_get_root (store); + + if (!root) + return; + + client = mateconf_client_get_default (); + + if (!client) + return; + + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/on_load/root", + root, + NULL); + + virtual_root = pluma_file_browser_store_get_virtual_root (store); + + if (!virtual_root) { + /* Set virtual to same as root then */ + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/on_load/virtual_root", + root, + NULL); + } else { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/on_load/virtual_root", + virtual_root, + NULL); + } + + g_signal_handlers_disconnect_by_func (window, + G_CALLBACK (on_tab_added_cb), + data); + + g_object_unref (client); + g_free (root); + g_free (virtual_root); +} + +static void +on_tab_added_cb (PlumaWindow * window, + PlumaTab * tab, + PlumaFileBrowserPluginData * data) +{ + MateConfClient *client; + gboolean open; + gboolean load_default = TRUE; + + client = mateconf_client_get_default (); + + if (!client) + return; + + open = mateconf_client_get_bool (client, + FILE_BROWSER_BASE_KEY "/open_at_first_doc", + NULL); + + if (open) { + PlumaDocument *doc; + gchar *uri; + + doc = pluma_tab_get_document (tab); + + uri = pluma_document_get_uri (doc); + + if (uri != NULL && pluma_utils_uri_has_file_scheme (uri)) { + prepare_auto_root (data); + set_root_from_doc (data, doc); + load_default = FALSE; + } + + g_free (uri); + } + + if (load_default) + restore_default_location (data); + + g_object_unref (client); + + /* Disconnect this signal, it's only called once */ + g_signal_handlers_disconnect_by_func (window, + G_CALLBACK (on_tab_added_cb), + data); +} + +static gchar * +get_filename_from_path (GtkTreeModel *model, GtkTreePath *path) +{ + GtkTreeIter iter; + gchar *uri; + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + -1); + + return pluma_file_browser_utils_uri_basename (uri); +} + +static gboolean +on_confirm_no_trash_cb (PlumaFileBrowserWidget * widget, + GList * files, + PlumaWindow * 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 = pluma_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 = pluma_file_browser_utils_confirmation_dialog (window, + GTK_MESSAGE_QUESTION, + message, + secondary, + GTK_STOCK_DELETE, + NULL); + g_free (secondary); + + return result; +} + +static gboolean +on_confirm_delete_cb (PlumaFileBrowserWidget *widget, + PlumaFileBrowserStore *store, + GList *paths, + PlumaWindow *window) +{ + gchar *normal; + gchar *message; + gchar *secondary; + gboolean result; + PlumaFileBrowserPluginData *data; + + data = get_plugin_data (window); + + if (!data->confirm_trash) + return TRUE; + + 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 = pluma_file_browser_utils_confirmation_dialog (window, + GTK_MESSAGE_QUESTION, + message, + secondary, + GTK_STOCK_DELETE, + NULL); + + g_free (message); + + return result; +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-plugin.h b/plugins/filebrowser/pluma-file-browser-plugin.h new file mode 100755 index 00000000..634c56af --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-plugin.h @@ -0,0 +1,71 @@ +/* + * pluma-file-browser-plugin.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_PLUGIN_H__ +#define __PLUMA_FILE_BROWSER_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_FILE_BROWSER_PLUGIN (filetree_plugin_get_type ()) +#define PLUMA_FILE_BROWSER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_FILE_BROWSER_PLUGIN, PlumaFileBrowserPlugin)) +#define PLUMA_FILE_BROWSER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_FILE_BROWSER_PLUGIN, PlumaFileBrowserPluginClass)) +#define PLUMA_IS_FILE_BROWSER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_FILE_BROWSER_PLUGIN)) +#define PLUMA_IS_FILE_BROWSER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_FILE_BROWSER_PLUGIN)) +#define PLUMA_FILE_BROWSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_FILE_BROWSER_PLUGIN, PlumaFileBrowserPluginClass)) + +/* Private structure type */ +typedef struct _PlumaFileBrowserPluginPrivate PlumaFileBrowserPluginPrivate; +typedef struct _PlumaFileBrowserPlugin PlumaFileBrowserPlugin; +typedef struct _PlumaFileBrowserPluginClass PlumaFileBrowserPluginClass; + +struct _PlumaFileBrowserPlugin +{ + PlumaPlugin parent_instance; + + /*< private > */ + PlumaFileBrowserPluginPrivate *priv; +}; + + + +struct _PlumaFileBrowserPluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType filetree_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule * module); + +G_END_DECLS +#endif /* __PLUMA_FILE_BROWSER_PLUGIN_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-store.c b/plugins/filebrowser/pluma-file-browser-store.c new file mode 100755 index 00000000..a046fe42 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-store.c @@ -0,0 +1,3625 @@ +/* + * pluma-file-browser-store.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "pluma-file-browser-store.h" +#include "pluma-file-browser-marshal.h" +#include "pluma-file-browser-enum-types.h" +#include "pluma-file-browser-error.h" +#include "pluma-file-browser-utils.h" + +#define PLUMA_FILE_BROWSER_STORE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ + PLUMA_TYPE_FILE_BROWSER_STORE, \ + PlumaFileBrowserStorePrivate)) + +#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 +{ + PlumaFileBrowserStore * model; + GCancellable * cancellable; + gboolean trash; + GList * files; + GList * iter; + gboolean removed; +}; + +struct _AsyncNode +{ + FileBrowserNodeDir *dir; + GCancellable *cancellable; + GSList *original_children; +}; + +typedef struct { + PlumaFileBrowserStore * model; + gchar * virtual_root; + GMountOperation * operation; + GCancellable * cancellable; +} MountInfo; + +struct _FileBrowserNode +{ + GFile *file; + guint flags; + gchar *name; + + GdkPixbuf *icon; + GdkPixbuf *emblem; + + FileBrowserNode *parent; + gint pos; + gboolean inserted; +}; + +struct _FileBrowserNodeDir +{ + FileBrowserNode node; + GSList *children; + GHashTable *hidden_file_hash; + + GCancellable *cancellable; + GFileMonitor *monitor; + PlumaFileBrowserStore *model; +}; + +struct _PlumaFileBrowserStorePrivate +{ + FileBrowserNode *root; + FileBrowserNode *virtual_root; + GType column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_NUM]; + + PlumaFileBrowserStoreFilterMode filter_mode; + PlumaFileBrowserStoreFilterFunc filter_func; + gpointer filter_user_data; + + SortFunc sort_func; + + GSList *async_handles; + MountInfo *mount_info; +}; + +static FileBrowserNode *model_find_node (PlumaFileBrowserStore *model, + FileBrowserNode *node, + GFile *uri); +static void model_remove_node (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GtkTreePath * path, + gboolean free_nodes); + +static void set_virtual_root_from_node (PlumaFileBrowserStore * model, + FileBrowserNode * node); + +static void pluma_file_browser_store_iface_init (GtkTreeModelIface * iface); +static GtkTreeModelFlags pluma_file_browser_store_get_flags (GtkTreeModel * tree_model); +static gint pluma_file_browser_store_get_n_columns (GtkTreeModel * tree_model); +static GType pluma_file_browser_store_get_column_type (GtkTreeModel * tree_model, + gint index); +static gboolean pluma_file_browser_store_get_iter (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreePath * path); +static GtkTreePath *pluma_file_browser_store_get_path (GtkTreeModel * tree_model, + GtkTreeIter * iter); +static void pluma_file_browser_store_get_value (GtkTreeModel * tree_model, + GtkTreeIter * iter, + gint column, + GValue * value); +static gboolean pluma_file_browser_store_iter_next (GtkTreeModel * tree_model, + GtkTreeIter * iter); +static gboolean pluma_file_browser_store_iter_children (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * parent); +static gboolean pluma_file_browser_store_iter_has_child (GtkTreeModel * tree_model, + GtkTreeIter * iter); +static gint pluma_file_browser_store_iter_n_children (GtkTreeModel * tree_model, + GtkTreeIter * iter); +static gboolean pluma_file_browser_store_iter_nth_child (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * parent, + gint n); +static gboolean pluma_file_browser_store_iter_parent (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * child); +static void pluma_file_browser_store_row_inserted (GtkTreeModel * tree_model, + GtkTreePath * path, + GtkTreeIter * iter); + +static void pluma_file_browser_store_drag_source_init (GtkTreeDragSourceIface * iface); +static gboolean pluma_file_browser_store_row_draggable (GtkTreeDragSource * drag_source, + GtkTreePath * path); +static gboolean pluma_file_browser_store_drag_data_delete (GtkTreeDragSource * drag_source, + GtkTreePath * path); +static gboolean pluma_file_browser_store_drag_data_get (GtkTreeDragSource * drag_source, + GtkTreePath * path, + GtkSelectionData * selection_data); + +static void file_browser_node_free (PlumaFileBrowserStore * model, + FileBrowserNode * node); +static void model_add_node (PlumaFileBrowserStore * model, + FileBrowserNode * child, + FileBrowserNode * parent); +static void model_clear (PlumaFileBrowserStore * model, + gboolean free_nodes); +static gint model_sort_default (FileBrowserNode * node1, + FileBrowserNode * node2); +static void model_check_dummy (PlumaFileBrowserStore * model, + FileBrowserNode * node); +static void next_files_async (GFileEnumerator * enumerator, + AsyncNode * async); + +PLUMA_PLUGIN_DEFINE_TYPE_WITH_CODE (PlumaFileBrowserStore, pluma_file_browser_store, + G_TYPE_OBJECT, + PLUMA_PLUGIN_IMPLEMENT_INTERFACE (pluma_file_browser_store_tree_model, + GTK_TYPE_TREE_MODEL, + pluma_file_browser_store_iface_init) + PLUMA_PLUGIN_IMPLEMENT_INTERFACE (pluma_file_browser_store_drag_source, + GTK_TYPE_TREE_DRAG_SOURCE, + pluma_file_browser_store_drag_source_init)) + +/* Properties */ +enum { + PROP_0, + + PROP_ROOT, + PROP_VIRTUAL_ROOT, + PROP_FILTER_MODE +}; + +/* Signals */ +enum +{ + BEGIN_LOADING, + END_LOADING, + ERROR, + NO_TRASH, + RENAME, + BEGIN_REFRESH, + END_REFRESH, + UNLOAD, + NUM_SIGNALS +}; + +static guint model_signals[NUM_SIGNALS] = { 0 }; + +static void +cancel_mount_operation (PlumaFileBrowserStore *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 +pluma_file_browser_store_finalize (GObject * object) +{ + PlumaFileBrowserStore *obj = PLUMA_FILE_BROWSER_STORE (object); + GSList *item; + + /* Free all the nodes */ + file_browser_node_free (obj, obj->priv->root); + + /* Cancel any asynchronous operations */ + for (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 (pluma_file_browser_store_parent_class)->finalize (object); +} + +static void +set_gvalue_from_node (GValue *value, + FileBrowserNode *node) +{ + gchar * uri; + + if (node == NULL || !node->file) { + g_value_set_string (value, NULL); + } else { + uri = g_file_get_uri (node->file); + g_value_take_string (value, uri); + } +} + +static void +pluma_file_browser_store_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserStore *obj = PLUMA_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; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_store_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserStore *obj = PLUMA_FILE_BROWSER_STORE (object); + + switch (prop_id) + { + case PROP_FILTER_MODE: + pluma_file_browser_store_set_filter_mode (obj, + g_value_get_flags (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_store_class_init (PlumaFileBrowserStoreClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = pluma_file_browser_store_finalize; + + object_class->get_property = pluma_file_browser_store_get_property; + object_class->set_property = pluma_file_browser_store_set_property; + + g_object_class_install_property (object_class, PROP_ROOT, + g_param_spec_string ("root", + "Root", + "The root uri", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_VIRTUAL_ROOT, + g_param_spec_string ("virtual-root", + "Virtual Root", + "The virtual root uri", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_FILTER_MODE, + g_param_spec_flags ("filter-mode", + "Filter Mode", + "The filter mode", + PLUMA_TYPE_FILE_BROWSER_STORE_FILTER_MODE, + pluma_file_browser_store_filter_mode_get_default (), + 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 (PlumaFileBrowserStoreClass, + begin_loading), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, 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 (PlumaFileBrowserStoreClass, + end_loading), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, 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 (PlumaFileBrowserStoreClass, + error), NULL, NULL, + pluma_file_browser_marshal_VOID__UINT_STRING, + 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 (PlumaFileBrowserStoreClass, + no_trash), g_signal_accumulator_true_handled, NULL, + pluma_file_browser_marshal_BOOL__POINTER, + 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 (PlumaFileBrowserStoreClass, + rename), NULL, NULL, + pluma_file_browser_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_STRING); + model_signals[BEGIN_REFRESH] = + g_signal_new ("begin-refresh", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + begin_refresh), NULL, NULL, + g_cclosure_marshal_VOID__VOID, + 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 (PlumaFileBrowserStoreClass, + end_refresh), NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + model_signals[UNLOAD] = + g_signal_new ("unload", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + unload), NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + g_type_class_add_private (object_class, + sizeof (PlumaFileBrowserStorePrivate)); +} + +static void +pluma_file_browser_store_iface_init (GtkTreeModelIface * iface) +{ + iface->get_flags = pluma_file_browser_store_get_flags; + iface->get_n_columns = pluma_file_browser_store_get_n_columns; + iface->get_column_type = pluma_file_browser_store_get_column_type; + iface->get_iter = pluma_file_browser_store_get_iter; + iface->get_path = pluma_file_browser_store_get_path; + iface->get_value = pluma_file_browser_store_get_value; + iface->iter_next = pluma_file_browser_store_iter_next; + iface->iter_children = pluma_file_browser_store_iter_children; + iface->iter_has_child = pluma_file_browser_store_iter_has_child; + iface->iter_n_children = pluma_file_browser_store_iter_n_children; + iface->iter_nth_child = pluma_file_browser_store_iter_nth_child; + iface->iter_parent = pluma_file_browser_store_iter_parent; + iface->row_inserted = pluma_file_browser_store_row_inserted; +} + +static void +pluma_file_browser_store_drag_source_init (GtkTreeDragSourceIface * iface) +{ + iface->row_draggable = pluma_file_browser_store_row_draggable; + iface->drag_data_delete = pluma_file_browser_store_drag_data_delete; + iface->drag_data_get = pluma_file_browser_store_drag_data_get; +} + +static void +pluma_file_browser_store_init (PlumaFileBrowserStore * obj) +{ + obj->priv = PLUMA_FILE_BROWSER_STORE_GET_PRIVATE (obj); + + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_URI] = + G_TYPE_STRING; + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_NAME] = + G_TYPE_STRING; + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS] = + G_TYPE_UINT; + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_ICON] = + GDK_TYPE_PIXBUF; + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM] = + GDK_TYPE_PIXBUF; + + // Default filter mode is hiding the hidden files + obj->priv->filter_mode = pluma_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 (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + return node_has_parent (node, model->priv->virtual_root); +} + +static gboolean +model_node_visibility (PlumaFileBrowserStore * 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 (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + return node == model->priv->virtual_root || (model_node_visibility (model, node) && node->inserted); +} + +/* Interface implementation */ + +static GtkTreeModelFlags +pluma_file_browser_store_get_flags (GtkTreeModel * tree_model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + (GtkTreeModelFlags) 0); + + return GTK_TREE_MODEL_ITERS_PERSIST; +} + +static gint +pluma_file_browser_store_get_n_columns (GtkTreeModel * tree_model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), 0); + + return PLUMA_FILE_BROWSER_STORE_COLUMN_NUM; +} + +static GType +pluma_file_browser_store_get_column_type (GtkTreeModel * tree_model, gint idx) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + G_TYPE_INVALID); + g_return_val_if_fail (idx < PLUMA_FILE_BROWSER_STORE_COLUMN_NUM && + idx >= 0, G_TYPE_INVALID); + + return PLUMA_FILE_BROWSER_STORE (tree_model)->priv->column_types[idx]; +} + +static gboolean +pluma_file_browser_store_get_iter (GtkTreeModel * tree_model, + GtkTreeIter * iter, GtkTreePath * path) +{ + gint * indices, depth, i; + FileBrowserNode * node; + PlumaFileBrowserStore * model; + gint num; + + g_assert (PLUMA_IS_FILE_BROWSER_STORE (tree_model)); + g_assert (path != NULL); + + model = PLUMA_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 (i = 0; i < depth; ++i) { + GSList * item; + + if (node == NULL) + return FALSE; + + num = 0; + + if (!NODE_IS_DIR (node)) + return FALSE; + + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) { + FileBrowserNode * child; + + child = (FileBrowserNode *) (item->data); + + if (model_node_inserted (model, child)) { + if (num == indices[i]) { + node = child; + 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 * +pluma_file_browser_store_get_path_real (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + GtkTreePath *path; + gint num = 0; + + path = gtk_tree_path_new (); + + while (node != model->priv->virtual_root) { + GSList *item; + + if (node->parent == NULL) { + gtk_tree_path_free (path); + return NULL; + } + + num = 0; + + for (item = FILE_BROWSER_NODE_DIR (node->parent)->children; item; item = item->next) { + FileBrowserNode *check; + + 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 * +pluma_file_browser_store_get_path (GtkTreeModel * tree_model, + GtkTreeIter * iter) +{ + g_return_val_if_fail (PLUMA_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 pluma_file_browser_store_get_path_real (PLUMA_FILE_BROWSER_STORE (tree_model), + (FileBrowserNode *) (iter->user_data)); +} + +static void +pluma_file_browser_store_get_value (GtkTreeModel * tree_model, + GtkTreeIter * iter, + gint column, + GValue * value) +{ + FileBrowserNode *node; + + g_return_if_fail (PLUMA_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, PLUMA_FILE_BROWSER_STORE (tree_model)->priv->column_types[column]); + + switch (column) { + case PLUMA_FILE_BROWSER_STORE_COLUMN_URI: + set_gvalue_from_node (value, node); + break; + case PLUMA_FILE_BROWSER_STORE_COLUMN_NAME: + g_value_set_string (value, node->name); + break; + case PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS: + g_value_set_uint (value, node->flags); + break; + case PLUMA_FILE_BROWSER_STORE_COLUMN_ICON: + g_value_set_object (value, node->icon); + break; + case PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM: + g_value_set_object (value, node->emblem); + break; + default: + g_return_if_reached (); + } +} + +static gboolean +pluma_file_browser_store_iter_next (GtkTreeModel * tree_model, + GtkTreeIter * iter) +{ + PlumaFileBrowserStore * model; + FileBrowserNode * node; + GSList * item; + GSList * first; + + g_return_val_if_fail (PLUMA_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 = PLUMA_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 (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 +pluma_file_browser_store_iter_children (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * parent) +{ + FileBrowserNode * node; + PlumaFileBrowserStore * model; + GSList * item; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (parent == NULL + || parent->user_data != NULL, FALSE); + + model = PLUMA_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 (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 (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + GSList *item; + + if (!NODE_IS_DIR (node)) + return FALSE; + + for (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 +pluma_file_browser_store_iter_has_child (GtkTreeModel * tree_model, + GtkTreeIter * iter) +{ + FileBrowserNode *node; + PlumaFileBrowserStore *model; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (iter == NULL + || iter->user_data != NULL, FALSE); + + model = PLUMA_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 +pluma_file_browser_store_iter_n_children (GtkTreeModel * tree_model, + GtkTreeIter * iter) +{ + FileBrowserNode *node; + PlumaFileBrowserStore *model; + GSList *item; + gint num = 0; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (iter == NULL + || iter->user_data != NULL, FALSE); + + model = PLUMA_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 (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) + if (model_node_inserted (model, (FileBrowserNode *) (item->data))) + ++num; + + return num; +} + +static gboolean +pluma_file_browser_store_iter_nth_child (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * parent, gint n) +{ + FileBrowserNode *node; + PlumaFileBrowserStore *model; + GSList *item; + gint num = 0; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (parent == NULL + || parent->user_data != NULL, FALSE); + + model = PLUMA_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 (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 +pluma_file_browser_store_iter_parent (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * child) +{ + FileBrowserNode *node; + PlumaFileBrowserStore *model; + + g_return_val_if_fail (PLUMA_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 = PLUMA_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 +pluma_file_browser_store_row_inserted (GtkTreeModel * tree_model, + GtkTreePath * path, + GtkTreeIter * iter) +{ + FileBrowserNode * node = (FileBrowserNode *)(iter->user_data); + + node->inserted = TRUE; +} + +static gboolean +pluma_file_browser_store_row_draggable (GtkTreeDragSource * drag_source, + GtkTreePath * path) +{ + GtkTreeIter iter; + PlumaFileBrowserStoreFlag 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, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + return !FILE_IS_DUMMY(flags); +} + +static gboolean +pluma_file_browser_store_drag_data_delete (GtkTreeDragSource * drag_source, + GtkTreePath * path) +{ + return FALSE; +} + +static gboolean +pluma_file_browser_store_drag_data_get (GtkTreeDragSource * drag_source, + GtkTreePath * path, + GtkSelectionData * selection_data) +{ + GtkTreeIter iter; + gchar *uri; + 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, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + -1); + + g_assert (uri); + + uris[0] = uri; + ret = gtk_selection_data_set_uris (selection_data, uris); + + g_free (uri); + + return ret; +} + +#define FILTER_HIDDEN(mode) (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) +#define FILTER_BINARY(mode) (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY) + +/* Private */ +static void +model_begin_loading (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + GtkTreeIter iter; + + iter.user_data = node; + g_signal_emit (model, model_signals[BEGIN_LOADING], 0, &iter); +} + +static void +model_end_loading (PlumaFileBrowserStore * 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 (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + GtkTreeIter iter; + + node->flags &= ~PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED; + + if (FILTER_HIDDEN (model->priv->filter_mode) && + NODE_IS_HIDDEN (node)) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED; + else if (FILTER_BINARY (model->priv->filter_mode) && + (!NODE_IS_TEXT (node) && !NODE_IS_DIR (node))) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED; + else if (model->priv->filter_func) { + iter.user_data = node; + + if (!model->priv-> + filter_func (model, &iter, + model->priv->filter_user_data)) + node->flags |= + PLUMA_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, *k2; + gint result; + + k1 = g_utf8_collate_key_for_filename (node1->name, -1); + k2 = g_utf8_collate_key_for_filename (node2->name, -1); + + result = strcmp (k1, k2); + + g_free (k1); + g_free (k2); + + return result; + } +} + +static gint +model_sort_default (FileBrowserNode * node1, FileBrowserNode * node2) +{ + gint f1; + gint f2; + + f1 = NODE_IS_DUMMY (node1); + 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; + } + + f1 = NODE_IS_HIDDEN (node1); + f2 = NODE_IS_HIDDEN (node2); + + if (f1 != f2) + { + return f2 ? -1 : 1; + } + + return collate_nodes (node1, node2); +} + +static void +model_resort_node (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + FileBrowserNodeDir *dir; + GSList *item; + FileBrowserNode *child; + gint pos = 0; + GtkTreeIter iter; + GtkTreePath *path; + gint *neworder; + + 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 { + /* Store current positions */ + for (item = dir->children; item; item = item->next) { + 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 (item = dir->children; item; item = item->next) { + child = (FileBrowserNode *) (item->data); + + if (model_node_visibility (model, child)) + neworder[pos++] = child->pos; + } + + iter.user_data = node->parent; + path = + pluma_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 (PlumaFileBrowserStore * 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 (PlumaFileBrowserStore * 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 (PlumaFileBrowserStore * model, + const GtkTreePath * path) +{ + GtkTreePath *copy = gtk_tree_path_copy (path); + + /* Delete a copy of the actual path here because the row-deleted + signal may alter the path */ + gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), copy); + gtk_tree_path_free (copy); +} + +static void +model_refilter_node (PlumaFileBrowserStore * 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 = pluma_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) { + node->inserted = FALSE; + row_deleted (model, *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 (PlumaFileBrowserStore * model) +{ + model_refilter_node (model, model->priv->root, NULL); +} + +static void +file_browser_node_set_name (FileBrowserNode * node) +{ + g_free (node->name); + + if (node->file) { + node->name = pluma_file_browser_utils_file_basename (node->file); + } else { + node->name = 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 (PlumaFileBrowserStore * model, + GFile * file, FileBrowserNode * parent) +{ + FileBrowserNode *node = + (FileBrowserNode *) g_slice_new0 (FileBrowserNodeDir); + + file_browser_node_init (node, file, parent); + + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY; + + FILE_BROWSER_NODE_DIR (node)->model = model; + + return node; +} + +static void +file_browser_node_free_children (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + GSList *item; + + if (node == NULL) + return; + + if (NODE_IS_DIR (node)) { + for (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 &= ~PLUMA_FILE_BROWSER_STORE_FLAG_LOADED; + } +} + +static void +file_browser_node_free (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + gchar *uri; + + if (node == NULL) + return; + + if (NODE_IS_DIR (node)) + { + FileBrowserNodeDir *dir; + + 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 (dir->hidden_file_hash) + g_hash_table_destroy (dir->hidden_file_hash); + } + + if (node->file) + { + uri = g_file_get_uri (node->file); + g_signal_emit (model, model_signals[UNLOAD], 0, uri); + + g_free (uri); + g_object_unref (node->file); + } + + if (node->icon) + g_object_unref (node->icon); + + if (node->emblem) + g_object_unref (node->emblem); + + g_free (node->name); + + if (NODE_IS_DIR (node)) + g_slice_free (FileBrowserNodeDir, (FileBrowserNodeDir *)node); + else + g_slice_free (FileBrowserNode, (FileBrowserNode *)node); +} + +/** + * model_remove_node_children: + * @model: the #PlumaFileBrowserStore + * @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 (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GtkTreePath * path, + gboolean free_nodes) +{ + FileBrowserNodeDir *dir; + GtkTreePath *path_child; + GSList *list; + GSList *item; + + 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 = + pluma_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 (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 #PlumaFileBrowserStore + * @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 (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GtkTreePath * path, + gboolean free_nodes) +{ + gboolean free_path = FALSE; + FileBrowserNode *parent; + + if (path == NULL) { + path = + pluma_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) + { + node->inserted = FALSE; + row_deleted (model, path); + } + + if (free_path) + gtk_tree_path_free (path); + + parent = node->parent; + + if (free_nodes) { + /* Remove the node from the parents children list */ + if (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 #PlumaFileBrowserStore + * @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 (PlumaFileBrowserStore * model, gboolean free_nodes) +{ + GtkTreePath *path; + FileBrowserNodeDir *dir; + FileBrowserNode *dummy; + + 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) { + dir = FILE_BROWSER_NODE_DIR (model->priv->virtual_root); + + if (dir->children != NULL) { + dummy = (FileBrowserNode *) (dir->children->data); + + if (NODE_IS_DUMMY (dummy) + && model_node_visibility (model, dummy)) { + path = gtk_tree_path_new_first (); + + dummy->inserted = FALSE; + row_deleted (model, path); + gtk_tree_path_free (path); + } + } + } +} + +static void +file_browser_node_unload (PlumaFileBrowserStore * 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 &= ~PLUMA_FILE_BROWSER_STORE_FLAG_LOADED; +} + +static void +model_recomposite_icon_real (PlumaFileBrowserStore * tree_model, + FileBrowserNode * node, + GFileInfo * info) +{ + GdkPixbuf *icon; + + g_return_if_fail (PLUMA_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 = pluma_file_browser_utils_pixbuf_from_icon (gicon, GTK_ICON_SIZE_MENU); + else + icon = NULL; + } else { + icon = pluma_file_browser_utils_pixbuf_from_file (node->file, 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 (PlumaFileBrowserStore * tree_model, + GtkTreeIter * iter) +{ + g_return_if_fail (PLUMA_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 (PlumaFileBrowserStore * model, + FileBrowserNode * parent) +{ + FileBrowserNode *dummy; + + dummy = file_browser_node_new (NULL, parent); + dummy->name = g_strdup (_("(Empty)")); + + dummy->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_DUMMY; + dummy->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + return dummy; +} + +static FileBrowserNode * +model_add_dummy_node (PlumaFileBrowserStore * model, + FileBrowserNode * parent) +{ + FileBrowserNode *dummy; + + dummy = model_create_dummy_node (model, parent); + + if (model_node_visibility (model, parent)) + dummy->flags &= ~PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + model_add_node (model, dummy, parent); + + return dummy; +} + +static void +model_check_dummy (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + // Hide the dummy child if needed + if (NODE_IS_DIR (node)) { + FileBrowserNode *dummy; + GtkTreeIter iter; + GtkTreePath *path; + guint flags; + FileBrowserNodeDir *dir; + + dir = FILE_BROWSER_NODE_DIR (node); + + 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 |= + PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + return; + } + + /* Temporarily set the node to invisible to check + * for real children */ + flags = dummy->flags; + dummy->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + if (!filter_tree_model_iter_has_child_real (model, node)) { + dummy->flags &= + ~PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + if (FILE_IS_HIDDEN (flags)) { + // Was hidden, needs to be inserted + iter.user_data = dummy; + path = + pluma_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 &= + ~PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + path = + pluma_file_browser_store_get_path_real + (model, dummy); + dummy->flags |= + PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + dummy->inserted = FALSE; + row_deleted (model, path); + gtk_tree_path_free (path); + } + } + } +} + +static void +insert_node_sorted (PlumaFileBrowserStore * model, + FileBrowserNode * child, + FileBrowserNode * parent) +{ + FileBrowserNodeDir *dir; + + 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 (PlumaFileBrowserStore * 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)) { + GtkTreeIter iter; + GtkTreePath *path; + + iter.user_data = child; + path = pluma_file_browser_store_get_path_real (model, 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 (PlumaFileBrowserStore * model, + GSList * children, + FileBrowserNode * parent) +{ + GSList *sorted_children; + GSList *child; + GSList *prev; + GSList *l; + FileBrowserNodeDir *dir; + + dir = FILE_BROWSER_NODE_DIR (parent); + + sorted_children = g_slist_sort (children, (GCompareFunc) model->priv->sort_func); + + child = sorted_children; + l = dir->children; + prev = NULL; + + 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 = pluma_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 = pluma_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 void +file_browser_node_set_from_info (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GFileInfo * info, + gboolean isadded) +{ + FileBrowserNodeDir * dir; + gchar const * content; + gchar const * name; + 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; + } + + dir = FILE_BROWSER_NODE_DIR (node->parent); + name = g_file_info_get_name (info); + + if (g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info)) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + else if (dir != NULL && dir->hidden_file_hash != NULL && + g_hash_table_lookup (dir->hidden_file_hash, name) != NULL) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY; + else { + if (!(content = backup_content_type (info))) + content = g_file_info_get_content_type (info); + + if (!content || + g_content_type_is_unknown (content) || + g_content_type_is_a (content, "text/plain")) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_TEXT; + } + + model_recomposite_icon_real (model, node, info); + + if (free_info) + g_object_unref (info); + + if (isadded) { + path = pluma_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) +{ + GSList *item; + + for (item = children; item; item = item->next) { + FileBrowserNode *node; + + 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 (PlumaFileBrowserStore * 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 (PlumaFileBrowserStore * model, + FileBrowserNode * parent, + GSList * original_children, + GList * files) +{ + GList *item; + GSList *nodes = NULL; + + for (item = files; item; item = item->next) { + GFileInfo *info = G_FILE_INFO (item->data); + GFileType type; + gchar const * name; + GFile * file; + FileBrowserNode *node; + + type = g_file_info_get_file_type (info); + + /* 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)) { + continue; + } + + file = g_file_get_child (parent->file, name); + + if ((node = node_list_contains_file (original_children, file)) == NULL) { + + 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); + + 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 (PlumaFileBrowserStore * 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); + } + + if (node->icon == NULL) { + node->icon = pluma_file_browser_utils_pixbuf_from_theme ("folder", GTK_ICON_SIZE_MENU); + } + + model_add_node (model, node, parent); + } + + return node; +} + +/* Read is sync, but we only do it for local files */ +static void +parse_dot_hidden_file (FileBrowserNode *directory) +{ + gsize file_size; + char *file_contents; + GFile *child; + GFileInfo *info; + GFileType type; + int i; + FileBrowserNodeDir * dir = FILE_BROWSER_NODE_DIR (directory); + + /* FIXME: We only support .hidden on file: uri's for the moment. + * Need to figure out if we should do this async or sync to extend + * it to all types of uris. + */ + if (directory->file == NULL || !g_file_is_native (directory->file)) { + return; + } + + child = g_file_get_child (directory->file, ".hidden"); + info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL); + + type = info ? g_file_info_get_file_type (info) : G_FILE_TYPE_UNKNOWN; + + if (info) + g_object_unref (info); + + if (type != G_FILE_TYPE_REGULAR) { + g_object_unref (child); + + return; + } + + if (!g_file_load_contents (child, NULL, &file_contents, &file_size, NULL, NULL)) { + g_object_unref (child); + return; + } + + g_object_unref (child); + + if (dir->hidden_file_hash == NULL) { + dir->hidden_file_hash = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + } + + /* Now parse the data */ + i = 0; + while (i < file_size) { + int start; + + start = i; + while (i < file_size && file_contents[i] != '\n') { + i++; + } + + if (i > start) { + char *hidden_filename; + + hidden_filename = g_strndup (file_contents + start, i - start); + g_hash_table_insert (dir->hidden_file_hash, + hidden_filename, hidden_filename); + } + + i++; + + } + + g_free (file_contents); +} + +static void +on_directory_monitor_event (GFileMonitor * monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + FileBrowserNode * parent) +{ + FileBrowserNode *node; + FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (parent); + + 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_free (async); +} + +static void +model_iterate_next_files_cb (GFileEnumerator * enumerator, + GAsyncResult * result, + AsyncNode * async) +{ + GList * files; + GError * error = NULL; + FileBrowserNodeDir * dir = async->dir; + FileBrowserNode * parent = (FileBrowserNode *)dir; + + files = g_file_enumerator_next_files_finish (enumerator, result, &error); + + if (files == NULL) { + g_file_enumerator_close (enumerator, NULL, NULL); + 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, + PLUMA_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); + 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; + } + + enumerator = g_file_enumerate_children_finish (file, result, &error); + + if (enumerator == NULL) { + /* 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, + PLUMA_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 (PlumaFileBrowserStore * 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 |= PLUMA_FILE_BROWSER_STORE_FLAG_LOADED; + model_begin_loading (model, node); + + /* Read the '.hidden' file first (if any) */ + parse_dot_hidden_file (node); + + dir->cancellable = g_cancellable_new (); + + async = g_new (AsyncNode, 1); + 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 (PlumaFileBrowserStore * 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 (PlumaFileBrowserStore * 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 = + pluma_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 (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + FileBrowserNode *next; + FileBrowserNode *prev; + FileBrowserNode *check; + FileBrowserNodeDir *dir; + GSList *item; + GSList *copy; + GtkTreePath *empty = NULL; + + prev = node; + next = prev->parent; + + /* 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 (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 (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 |= + PLUMA_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 (PlumaFileBrowserStore * model, + GFile * file) +{ + GList * files; + GList * item; + 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 (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 (PlumaFileBrowserStore * model, + FileBrowserNode * parent, + GFile * file) +{ + FileBrowserNodeDir *dir; + FileBrowserNode *child; + FileBrowserNode *result; + GSList *children; + + if (!NODE_IS_DIR (parent)) + return NULL; + + dir = FILE_BROWSER_NODE_DIR (parent); + + for (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 (PlumaFileBrowserStore * 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 +pluma_file_browser_store_error_quark (void) +{ + static GQuark quark = 0; + + if (G_UNLIKELY (quark == 0)) { + quark = g_quark_from_string ("pluma_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 PlumaFileBrowserStoreResult +model_root_mounted (PlumaFileBrowserStore * model, gchar const * virtual_root) +{ + model_check_dummy (model, model->priv->root); + g_object_notify (G_OBJECT (model), "root"); + + if (virtual_root != NULL) + return + pluma_file_browser_store_set_virtual_root_from_string + (model, virtual_root); + else + set_virtual_root_from_node (model, + model->priv->root); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +static void +handle_root_error (PlumaFileBrowserStore * model, GError *error) +{ + FileBrowserNode * root; + + g_signal_emit (model, + model_signals[ERROR], + 0, + PLUMA_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 |= PLUMA_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; + PlumaFileBrowserStore * 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); + g_free (mount_info->virtual_root); + + g_free (mount_info); +} + +static PlumaFileBrowserStoreResult +model_mount_root (PlumaFileBrowserStore * model, gchar const * 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_new(MountInfo, 1); + mount_info->model = model; + mount_info->virtual_root = g_strdup (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 PLUMA_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 PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +/* Public */ +PlumaFileBrowserStore * +pluma_file_browser_store_new (gchar const *root) +{ + PlumaFileBrowserStore *obj = + PLUMA_FILE_BROWSER_STORE (g_object_new + (PLUMA_TYPE_FILE_BROWSER_STORE, + NULL)); + + pluma_file_browser_store_set_root (obj, root); + return obj; +} + +void +pluma_file_browser_store_set_value (PlumaFileBrowserStore * tree_model, + GtkTreeIter * iter, gint column, + GValue * value) +{ + gpointer data; + FileBrowserNode *node; + GtkTreePath *path; + + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model)); + g_return_if_fail (column == + PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM); + g_return_if_fail (G_VALUE_HOLDS_OBJECT (value)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->user_data != NULL); + + data = g_value_get_object (value); + + if (data) + g_return_if_fail (GDK_IS_PIXBUF (data)); + + node = (FileBrowserNode *) (iter->user_data); + + 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); + + if (model_node_visibility (tree_model, node)) { + path = pluma_file_browser_store_get_path (GTK_TREE_MODEL (tree_model), + iter); + row_changed (tree_model, &path, iter); + gtk_tree_path_free (path); + } +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + g_return_val_if_fail (iter != NULL, + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + g_return_val_if_fail (iter->user_data != NULL, + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + model_clear (model, FALSE); + set_virtual_root_from_node (model, + (FileBrowserNode *) (iter->user_data)); + + return TRUE; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_from_string + (PlumaFileBrowserStore * model, gchar const *root) { + GFile *file; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + file = g_file_new_for_uri (root); + if (file == NULL) { + g_warning ("Invalid uri (%s)", root); + return PLUMA_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, file)) { + g_object_unref (file); + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + } + + /* Check if uri is the root itself */ + if (g_file_equal (model->priv->root->file, file)) { + g_object_unref (file); + + /* Always clear the model before altering the nodes */ + model_clear (model, FALSE); + set_virtual_root_from_node (model, model->priv->root); + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; + } + + if (!g_file_has_prefix (file, model->priv->root->file)) { + gchar *str, *str1; + + str = g_file_get_parse_name (model->priv->root->file); + str1 = g_file_get_parse_name (file); + + g_warning + ("Virtual root (%s) is not below actual root (%s)", + str1, str); + + g_free (str); + g_free (str1); + + g_object_unref (file); + return PLUMA_FILE_BROWSER_STORE_RESULT_ERROR; + } + + set_virtual_root_from_file (model, file); + g_object_unref (file); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_top (PlumaFileBrowserStore * + model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + if (model->priv->virtual_root == model->priv->root) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + model_clear (model, FALSE); + set_virtual_root_from_node (model, model->priv->root); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_up (PlumaFileBrowserStore * + model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + if (model->priv->virtual_root == model->priv->root) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + model_clear (model, FALSE); + set_virtual_root_from_node (model, + model->priv->virtual_root->parent); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +gboolean +pluma_file_browser_store_get_iter_virtual_root (PlumaFileBrowserStore * + model, GtkTreeIter * iter) +{ + g_return_val_if_fail (PLUMA_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 +pluma_file_browser_store_get_iter_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + g_return_val_if_fail (PLUMA_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 +pluma_file_browser_store_iter_equal (PlumaFileBrowserStore * model, + GtkTreeIter * iter1, + GtkTreeIter * iter2) +{ + g_return_val_if_fail (PLUMA_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 +pluma_file_browser_store_cancel_mount_operation (PlumaFileBrowserStore *store) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (store)); + + cancel_mount_operation (store); +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_root_and_virtual_root (PlumaFileBrowserStore * + model, + gchar const *root, + gchar const *virtual_root) +{ + GFile * file = NULL; + GFile * vfile = NULL; + FileBrowserNode * node; + gboolean equal = FALSE; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + if (root == NULL && model->priv->root == NULL) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + if (root != NULL) { + file = g_file_new_for_uri (root); + } + + if (root != NULL && model->priv->root != NULL) { + equal = g_file_equal (file, model->priv->root->file); + + if (equal && virtual_root == NULL) { + g_object_unref (file); + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + } + } + + if (virtual_root) { + vfile = g_file_new_for_uri (virtual_root); + + if (equal && g_file_equal (vfile, model->priv->virtual_root->file)) { + if (file) + g_object_unref (file); + + g_object_unref (vfile); + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + } + + g_object_unref (vfile); + } + + /* 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 (file != NULL) { + /* Create the root node */ + node = file_browser_node_dir_new (model, file, NULL); + + g_object_unref (file); + + 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 PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_root (PlumaFileBrowserStore * model, + gchar const *root) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + return pluma_file_browser_store_set_root_and_virtual_root (model, + root, + NULL); +} + +gchar * +pluma_file_browser_store_get_root (PlumaFileBrowserStore * model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), NULL); + + if (model->priv->root == NULL || model->priv->root->file == NULL) + return NULL; + else + return g_file_get_uri (model->priv->root->file); +} + +gchar * +pluma_file_browser_store_get_virtual_root (PlumaFileBrowserStore * model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), NULL); + + if (model->priv->virtual_root == NULL || model->priv->virtual_root->file == NULL) + return NULL; + else + return g_file_get_uri (model->priv->virtual_root->file); +} + +void +_pluma_file_browser_store_iter_expanded (PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + FileBrowserNode *node; + + g_return_if_fail (PLUMA_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 +_pluma_file_browser_store_iter_collapsed (PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + FileBrowserNode *node; + GSList *item; + + g_return_if_fail (PLUMA_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 (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); + } + } + } +} + +PlumaFileBrowserStoreFilterMode +pluma_file_browser_store_get_filter_mode (PlumaFileBrowserStore * model) +{ + return model->priv->filter_mode; +} + +void +pluma_file_browser_store_set_filter_mode (PlumaFileBrowserStore * model, + PlumaFileBrowserStoreFilterMode + mode) +{ + g_return_if_fail (PLUMA_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 +pluma_file_browser_store_set_filter_func (PlumaFileBrowserStore * model, + PlumaFileBrowserStoreFilterFunc + func, gpointer user_data) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model)); + + model->priv->filter_func = func; + model->priv->filter_user_data = user_data; + model_refilter (model); +} + +void +pluma_file_browser_store_refilter (PlumaFileBrowserStore * model) +{ + model_refilter (model); +} + +PlumaFileBrowserStoreFilterMode +pluma_file_browser_store_filter_mode_get_default (void) +{ + return PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; +} + +void +pluma_file_browser_store_refresh (PlumaFileBrowserStore * model) +{ + g_return_if_fail (PLUMA_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) +{ + FileBrowserNodeDir * dir; + GSList * child; + GFile * parent; + gchar * base; + + if (!node->file) { + return; + } + + if (reparent) { + parent = node->parent->file; + 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)) { + dir = FILE_BROWSER_NODE_DIR (node); + + for (child = dir->children; child; child = child->next) { + reparent_node ((FileBrowserNode *)child->data, TRUE); + } + } +} + +gboolean +pluma_file_browser_store_rename (PlumaFileBrowserStore * model, + GtkTreeIter * iter, + const gchar * new_name, + GError ** error) +{ + FileBrowserNode *node; + GFile * file; + GFile * parent; + GFile * previous; + GError * err = NULL; + gchar * olduri; + gchar * newuri; + GtkTreePath *path; + + g_return_val_if_fail (PLUMA_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 = pluma_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 (pluma_file_browser_store_error_quark (), + PLUMA_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; + } + + olduri = g_file_get_uri (previous); + newuri = g_file_get_uri (node->file); + + g_signal_emit (model, model_signals[RENAME], 0, olduri, newuri); + + g_object_unref (previous); + g_free (olduri); + g_free (newuri); + + return TRUE; + } else { + g_object_unref (file); + + if (err) { + if (error != NULL) { + *error = + g_error_new_literal + (pluma_file_browser_store_error_quark (), + PLUMA_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_foreach (data->files, (GFunc)g_object_unref, NULL); + g_list_free (data->files); + + if (!data->removed) + data->model->priv->async_handles = g_slist_remove (data->model->priv->async_handles, data); + + g_free (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; +} + +typedef struct { + PlumaFileBrowserStore * model; + GFile * file; +} IdleDelete; + +static gboolean +file_deleted (IdleDelete * data) +{ + FileBrowserNode * node; + node = model_find_node (data->model, NULL, data->file); + + if (node != NULL) + model_remove_node (data->model, node, NULL, TRUE); + + return FALSE; +} + +static gboolean +delete_files (GIOSchedulerJob * job, + GCancellable * cancellable, + AsyncData * data) +{ + GFile * file; + GError * error = NULL; + gboolean ret; + gint code; + IdleDelete delete; + + /* Check if our job is done */ + if (!data->iter) + return FALSE; + + /* Move a file to the trash */ + file = G_FILE (data->iter->data); + + if (data->trash) + ret = g_file_trash (file, cancellable, &error); + else + ret = g_file_delete (file, cancellable, &error); + + if (ret) { + delete.model = data->model; + delete.file = file; + + /* Remove the file from the model in the main loop */ + g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc)file_deleted, &delete, NULL); + } else if (!ret && error) { + code = error->code; + g_error_free (error); + + if (data->trash && code == G_IO_ERROR_NOT_SUPPORTED) { + /* Trash is not supported on this system ... */ + if (g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc)emit_no_trash, data, NULL)) + { + /* Changes this into a delete job */ + data->trash = FALSE; + data->iter = data->files; + + return TRUE; + } + + /* End the job */ + return FALSE; + } else if (code == G_IO_ERROR_CANCELLED) { + /* Job has been cancelled, just let the job end */ + return FALSE; + } + } + + /* Process the next item */ + data->iter = data->iter->next; + return TRUE; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_delete_all (PlumaFileBrowserStore *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 (PLUMA_IS_FILE_BROWSER_STORE (model), PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + if (rows == NULL) + return PLUMA_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_new (AsyncData, 1); + + 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); + + g_io_scheduler_push_job ((GIOSchedulerJobFunc)delete_files, + data, + (GDestroyNotify)async_data_free, + G_PRIORITY_DEFAULT, + data->cancellable); + g_list_free (rows); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_delete (PlumaFileBrowserStore * model, + GtkTreeIter * iter, gboolean trash) +{ + FileBrowserNode *node; + GList *rows = NULL; + PlumaFileBrowserStoreResult result; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + g_return_val_if_fail (iter != NULL, PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + g_return_val_if_fail (iter->user_data != NULL, PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + node = (FileBrowserNode *) (iter->user_data); + + if (NODE_IS_DUMMY (node)) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + rows = g_list_append(NULL, pluma_file_browser_store_get_path_real (model, node)); + result = pluma_file_browser_store_delete_all (model, rows, trash); + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return result; +} + +gboolean +pluma_file_browser_store_new_file (PlumaFileBrowserStore * 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 (PLUMA_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, _("file")); + + stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error); + + if (!stream) + { + g_signal_emit (model, model_signals[ERROR], 0, + PLUMA_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, + PLUMA_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 +pluma_file_browser_store_new_directory (PlumaFileBrowserStore * model, + GtkTreeIter * parent, + GtkTreeIter * iter) +{ + GFile * file; + FileBrowserNodeDir *parent_node; + GError * error = NULL; + FileBrowserNode *node; + gboolean result = FALSE; + + g_return_val_if_fail (PLUMA_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, _("directory")); + + if (!g_file_make_directory (file, NULL, &error)) { + g_signal_emit (model, model_signals[ERROR], 0, + PLUMA_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, + PLUMA_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; +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-store.h b/plugins/filebrowser/pluma-file-browser-store.h new file mode 100755 index 00000000..65b75e08 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-store.h @@ -0,0 +1,200 @@ +/* + * pluma-file-browser-store.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_STORE_H__ +#define __PLUMA_FILE_BROWSER_STORE_H__ + +#include + +G_BEGIN_DECLS +#define PLUMA_TYPE_FILE_BROWSER_STORE (pluma_file_browser_store_get_type ()) +#define PLUMA_FILE_BROWSER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_STORE, PlumaFileBrowserStore)) +#define PLUMA_FILE_BROWSER_STORE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_STORE, PlumaFileBrowserStore const)) +#define PLUMA_FILE_BROWSER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_FILE_BROWSER_STORE, PlumaFileBrowserStoreClass)) +#define PLUMA_IS_FILE_BROWSER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_FILE_BROWSER_STORE)) +#define PLUMA_IS_FILE_BROWSER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_FILE_BROWSER_STORE)) +#define PLUMA_FILE_BROWSER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_FILE_BROWSER_STORE, PlumaFileBrowserStoreClass)) + +typedef enum +{ + PLUMA_FILE_BROWSER_STORE_COLUMN_ICON = 0, + PLUMA_FILE_BROWSER_STORE_COLUMN_NAME, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, + PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM, + PLUMA_FILE_BROWSER_STORE_COLUMN_NUM +} PlumaFileBrowserStoreColumn; + +typedef enum +{ + PLUMA_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY = 1 << 0, + PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN = 1 << 1, + PLUMA_FILE_BROWSER_STORE_FLAG_IS_TEXT = 1 << 2, + PLUMA_FILE_BROWSER_STORE_FLAG_LOADED = 1 << 3, + PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED = 1 << 4, + PLUMA_FILE_BROWSER_STORE_FLAG_IS_DUMMY = 1 << 5 +} PlumaFileBrowserStoreFlag; + +typedef enum +{ + PLUMA_FILE_BROWSER_STORE_RESULT_OK, + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE, + PLUMA_FILE_BROWSER_STORE_RESULT_ERROR, + PLUMA_FILE_BROWSER_STORE_RESULT_NO_TRASH, + PLUMA_FILE_BROWSER_STORE_RESULT_MOUNTING, + PLUMA_FILE_BROWSER_STORE_RESULT_NUM +} PlumaFileBrowserStoreResult; + +typedef enum +{ + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_NONE = 0, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN = 1 << 0, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY = 1 << 1 +} PlumaFileBrowserStoreFilterMode; + +#define FILE_IS_DIR(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY) +#define FILE_IS_HIDDEN(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN) +#define FILE_IS_TEXT(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_TEXT) +#define FILE_LOADED(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_LOADED) +#define FILE_IS_FILTERED(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED) +#define FILE_IS_DUMMY(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_DUMMY) + +typedef struct _PlumaFileBrowserStore PlumaFileBrowserStore; +typedef struct _PlumaFileBrowserStoreClass PlumaFileBrowserStoreClass; +typedef struct _PlumaFileBrowserStorePrivate PlumaFileBrowserStorePrivate; + +typedef gboolean (*PlumaFileBrowserStoreFilterFunc) (PlumaFileBrowserStore + * model, + GtkTreeIter * iter, + gpointer user_data); + +struct _PlumaFileBrowserStore +{ + GObject parent; + + PlumaFileBrowserStorePrivate *priv; +}; + +struct _PlumaFileBrowserStoreClass { + GObjectClass parent_class; + + /* Signals */ + void (*begin_loading) (PlumaFileBrowserStore * model, + GtkTreeIter * iter); + void (*end_loading) (PlumaFileBrowserStore * model, + GtkTreeIter * iter); + void (*error) (PlumaFileBrowserStore * model, + guint code, + gchar * message); + gboolean (*no_trash) (PlumaFileBrowserStore * model, + GList * files); + void (*rename) (PlumaFileBrowserStore * model, + const gchar * olduri, + const gchar * newuri); + void (*begin_refresh) (PlumaFileBrowserStore * model); + void (*end_refresh) (PlumaFileBrowserStore * model); + void (*unload) (PlumaFileBrowserStore * model, + const gchar * uri); +}; + +GType pluma_file_browser_store_get_type (void) G_GNUC_CONST; +GType pluma_file_browser_store_register_type (GTypeModule * module); + +PlumaFileBrowserStore *pluma_file_browser_store_new (gchar const *root); + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_root_and_virtual_root (PlumaFileBrowserStore * model, + gchar const *root, + gchar const *virtual_root); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_root (PlumaFileBrowserStore * model, + gchar const *root); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_from_string (PlumaFileBrowserStore * model, + gchar const *root); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_up (PlumaFileBrowserStore * model); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_top (PlumaFileBrowserStore * model); + +gboolean +pluma_file_browser_store_get_iter_virtual_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter); +gboolean pluma_file_browser_store_get_iter_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter); +gchar * pluma_file_browser_store_get_root (PlumaFileBrowserStore * model); +gchar * pluma_file_browser_store_get_virtual_root (PlumaFileBrowserStore * model); + +gboolean pluma_file_browser_store_iter_equal (PlumaFileBrowserStore * model, + GtkTreeIter * iter1, + GtkTreeIter * iter2); + +void pluma_file_browser_store_set_value (PlumaFileBrowserStore * tree_model, + GtkTreeIter * iter, + gint column, + GValue * value); + +void _pluma_file_browser_store_iter_expanded (PlumaFileBrowserStore * model, + GtkTreeIter * iter); +void _pluma_file_browser_store_iter_collapsed (PlumaFileBrowserStore * model, + GtkTreeIter * iter); + +PlumaFileBrowserStoreFilterMode +pluma_file_browser_store_get_filter_mode (PlumaFileBrowserStore * model); +void pluma_file_browser_store_set_filter_mode (PlumaFileBrowserStore * model, + PlumaFileBrowserStoreFilterMode mode); +void pluma_file_browser_store_set_filter_func (PlumaFileBrowserStore * model, + PlumaFileBrowserStoreFilterFunc func, + gpointer user_data); +void pluma_file_browser_store_refilter (PlumaFileBrowserStore * model); +PlumaFileBrowserStoreFilterMode +pluma_file_browser_store_filter_mode_get_default (void); + +void pluma_file_browser_store_refresh (PlumaFileBrowserStore * model); +gboolean pluma_file_browser_store_rename (PlumaFileBrowserStore * model, + GtkTreeIter * iter, + gchar const *new_name, + GError ** error); +PlumaFileBrowserStoreResult +pluma_file_browser_store_delete (PlumaFileBrowserStore * model, + GtkTreeIter * iter, + gboolean trash); +PlumaFileBrowserStoreResult +pluma_file_browser_store_delete_all (PlumaFileBrowserStore * model, + GList *rows, + gboolean trash); + +gboolean pluma_file_browser_store_new_file (PlumaFileBrowserStore * model, + GtkTreeIter * parent, + GtkTreeIter * iter); +gboolean pluma_file_browser_store_new_directory (PlumaFileBrowserStore * model, + GtkTreeIter * parent, + GtkTreeIter * iter); + +void pluma_file_browser_store_cancel_mount_operation (PlumaFileBrowserStore *store); + +G_END_DECLS +#endif /* __PLUMA_FILE_BROWSER_STORE_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-utils.c b/plugins/filebrowser/pluma-file-browser-utils.c new file mode 100755 index 00000000..6949486d --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-utils.c @@ -0,0 +1,198 @@ +/* + * pluma-file-bookmarks-store.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "pluma-file-browser-utils.h" +#include + +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 * +pluma_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 * +pluma_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); + gtk_icon_info_free (info); + + return ret; +} + +GdkPixbuf * +pluma_file_browser_utils_pixbuf_from_file (GFile * file, + GtkIconSize size) +{ + GIcon * icon; + GFileInfo * info; + GdkPixbuf * ret = NULL; + + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_ICON, + G_FILE_QUERY_INFO_NONE, + NULL, + NULL); + + if (!info) + return NULL; + + icon = g_file_info_get_icon (info); + if (icon != NULL) + ret = pluma_file_browser_utils_pixbuf_from_icon (icon, size); + + g_object_unref (info); + + return ret; +} + +gchar * +pluma_file_browser_utils_file_basename (GFile * file) +{ + gchar *uri; + gchar *ret; + + uri = g_file_get_uri (file); + ret = pluma_file_browser_utils_uri_basename (uri); + g_free (uri); + + return ret; +} + +gchar * +pluma_file_browser_utils_uri_basename (gchar const * uri) +{ + return pluma_utils_basename_for_display (uri); +} + +gboolean +pluma_file_browser_utils_confirmation_dialog (PlumaWindow * window, + GtkMessageType type, + gchar const *message, + gchar const *secondary, + gchar const * button_stock, + gchar const * button_label) +{ + GtkWidget *dlg; + gint ret; + GtkWidget *button; + + 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); + + /* Add a cancel button */ + button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + gtk_widget_show (button); + + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_dialog_add_action_widget (GTK_DIALOG (dlg), + button, + GTK_RESPONSE_CANCEL); + + /* Add custom button */ + button = gtk_button_new_from_stock (button_stock); + + if (button_label) { + gtk_button_set_use_stock (GTK_BUTTON (button), FALSE); + gtk_button_set_label (GTK_BUTTON (button), button_label); + } + + gtk_widget_show (button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_dialog_add_action_widget (GTK_DIALOG (dlg), + button, + GTK_RESPONSE_OK); + + ret = gtk_dialog_run (GTK_DIALOG (dlg)); + gtk_widget_destroy (dlg); + + return (ret == GTK_RESPONSE_OK); +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-utils.h b/plugins/filebrowser/pluma-file-browser-utils.h new file mode 100755 index 00000000..0ac4296a --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-utils.h @@ -0,0 +1,27 @@ +#ifndef __PLUMA_FILE_BROWSER_UTILS_H__ +#define __PLUMA_FILE_BROWSER_UTILS_H__ + +#include +#include + +GdkPixbuf *pluma_file_browser_utils_pixbuf_from_theme (gchar const *name, + GtkIconSize size); + +GdkPixbuf *pluma_file_browser_utils_pixbuf_from_icon (GIcon * icon, + GtkIconSize size); +GdkPixbuf *pluma_file_browser_utils_pixbuf_from_file (GFile * file, + GtkIconSize size); + +gchar * pluma_file_browser_utils_file_basename (GFile * file); +gchar * pluma_file_browser_utils_uri_basename (gchar const * uri); + +gboolean pluma_file_browser_utils_confirmation_dialog (PlumaWindow * window, + GtkMessageType type, + gchar const *message, + gchar const *secondary, + gchar const * button_stock, + gchar const * button_label); + +#endif /* __PLUMA_FILE_BROWSER_UTILS_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-view.c b/plugins/filebrowser/pluma-file-browser-view.c new file mode 100755 index 00000000..64e90c28 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-view.c @@ -0,0 +1,1256 @@ +/* + * pluma-file-browser-view.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +#include "pluma-file-browser-store.h" +#include "pluma-file-bookmarks-store.h" +#include "pluma-file-browser-view.h" +#include "pluma-file-browser-marshal.h" +#include "pluma-file-browser-enum-types.h" + +#define PLUMA_FILE_BROWSER_VIEW_GET_PRIVATE(object)( \ + G_TYPE_INSTANCE_GET_PRIVATE((object), \ + PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserViewPrivate)) + +struct _PlumaFileBrowserViewPrivate +{ + GtkTreeViewColumn *column; + GtkCellRenderer *pixbuf_renderer; + GtkCellRenderer *text_renderer; + + GtkTreeModel *model; + GtkTreeRowReference *editable; + + GdkCursor *busy_cursor; + + /* CLick policy */ + PlumaFileBrowserViewClickPolicy click_policy; + GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */ + 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 } +}; + +PLUMA_PLUGIN_DEFINE_TYPE (PlumaFileBrowserView, pluma_file_browser_view, + GTK_TYPE_TREE_VIEW) + +static void on_cell_edited (GtkCellRendererText * cell, + gchar * path, + gchar * new_text, + PlumaFileBrowserView * tree_view); + +static void on_begin_refresh (PlumaFileBrowserStore * model, + PlumaFileBrowserView * view); +static void on_end_refresh (PlumaFileBrowserStore * model, + PlumaFileBrowserView * view); + +static void on_unload (PlumaFileBrowserStore * model, + gchar const * uri, + PlumaFileBrowserView * view); + +static void on_row_inserted (PlumaFileBrowserStore * model, + GtkTreePath * path, + GtkTreeIter * iter, + PlumaFileBrowserView * view); + +static void +pluma_file_browser_view_finalize (GObject * object) +{ + PlumaFileBrowserView *obj = PLUMA_FILE_BROWSER_VIEW(object); + + if (obj->priv->hand_cursor) + gdk_cursor_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; + } + + gdk_cursor_unref (obj->priv->busy_cursor); + + G_OBJECT_CLASS (pluma_file_browser_view_parent_class)-> + finalize (object); +} + +static void +add_expand_state (PlumaFileBrowserView * view, + gchar const * uri) +{ + GFile * file; + + if (!uri) + return; + + file = g_file_new_for_uri (uri); + + if (view->priv->expand_state) + g_hash_table_insert (view->priv->expand_state, file, file); + else + g_object_unref (file); +} + +static void +remove_expand_state (PlumaFileBrowserView * view, + gchar const * uri) +{ + GFile * file; + + if (!uri) + return; + + file = g_file_new_for_uri (uri); + + if (view->priv->expand_state) + g_hash_table_remove (view->priv->expand_state, file); + + g_object_unref (file); +} + +static void +row_expanded (GtkTreeView * tree_view, + GtkTreeIter * iter, + GtkTreePath * path) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (tree_view); + gchar * uri; + + if (GTK_TREE_VIEW_CLASS (pluma_file_browser_view_parent_class)->row_expanded) + GTK_TREE_VIEW_CLASS (pluma_file_browser_view_parent_class)->row_expanded (tree_view, iter, path); + + if (!PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + return; + + if (view->priv->restore_expand_state) + { + gtk_tree_model_get (view->priv->model, + iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, + -1); + + add_expand_state (view, uri); + g_free (uri); + } + + _pluma_file_browser_store_iter_expanded (PLUMA_FILE_BROWSER_STORE (view->priv->model), + iter); +} + +static void +row_collapsed (GtkTreeView * tree_view, + GtkTreeIter * iter, + GtkTreePath * path) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (tree_view); + gchar * uri; + + if (GTK_TREE_VIEW_CLASS (pluma_file_browser_view_parent_class)->row_collapsed) + GTK_TREE_VIEW_CLASS (pluma_file_browser_view_parent_class)->row_collapsed (tree_view, iter, path); + + if (!PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + return; + + if (view->priv->restore_expand_state) + { + gtk_tree_model_get (view->priv->model, + iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, + -1); + + remove_expand_state (view, uri); + g_free (uri); + } + + _pluma_file_browser_store_iter_collapsed (PLUMA_FILE_BROWSER_STORE (view->priv->model), + iter); +} + +static gboolean +leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + if (view->priv->click_policy == PLUMA_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 (pluma_file_browser_view_parent_class)->leave_notify_event (widget, event); +} + +static gboolean +enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + if (view->priv->click_policy == PLUMA_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 (pluma_file_browser_view_parent_class)->enter_notify_event (widget, event); +} + +static gboolean +motion_notify_event (GtkWidget * widget, + GdkEventMotion * event) +{ + GtkTreePath *old_hover_path; + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + if (view->priv->click_policy == PLUMA_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 (pluma_file_browser_view_parent_class)->motion_notify_event (widget, event); +} + +static void +set_click_policy_property (PlumaFileBrowserView *obj, + PlumaFileBrowserViewClickPolicy click_policy) +{ + GtkTreeIter iter; + GdkDisplay *display; + GdkWindow *win; + + obj->priv->click_policy = click_policy; + + if (click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { + if (obj->priv->hand_cursor == NULL) + obj->priv->hand_cursor = gdk_cursor_new(GDK_HAND2); + } else if (click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE) { + if (obj->priv->hover_path != NULL) { + 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_REALIZED (GTK_WIDGET (obj))) { + win = gtk_widget_get_window (GTK_WIDGET (obj)); + gdk_window_set_cursor (win, NULL); + + display = gtk_widget_get_display (GTK_WIDGET (obj)); + + if (display != NULL) + gdk_display_flush (display); + } + + if (obj->priv->hand_cursor) { + gdk_cursor_unref (obj->priv->hand_cursor); + obj->priv->hand_cursor = NULL; + } + } +} + +static void +directory_activated (PlumaFileBrowserView *view, + GtkTreeIter *iter) +{ + pluma_file_browser_store_set_virtual_root (PLUMA_FILE_BROWSER_STORE (view->priv->model), iter); +} + +static void +activate_selected_files (PlumaFileBrowserView *view) { + GtkTreeView *tree_view = GTK_TREE_VIEW (view); + GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view); + GList *rows, *row; + GtkTreePath *directory = NULL; + GtkTreePath *path; + GtkTreeIter iter; + PlumaFileBrowserStoreFlag flags; + + rows = gtk_tree_selection_get_selected_rows (selection, &view->priv->model); + + 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, PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, -1); + + if (FILE_IS_DIR (flags)) { + if (directory == NULL) + directory = path; + + } else if (!FILE_IS_DUMMY (flags)) { + g_signal_emit (view, signals[FILE_ACTIVATED], 0, &iter); + } + } + + if (directory != NULL) { + if (gtk_tree_model_get_iter (view->priv->model, &iter, directory)) + g_signal_emit (view, signals[DIRECTORY_ACTIVATED], 0, &iter); + } + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); +} + +static void +activate_selected_bookmark (PlumaFileBrowserView *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 (PlumaFileBrowserView *view) +{ + if (PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + activate_selected_files (view); + else if (PLUMA_IS_FILE_BOOKMARKS_STORE (view->priv->model)) + activate_selected_bookmark (view); +} + +static void +toggle_hidden_filter (PlumaFileBrowserView *view) +{ + PlumaFileBrowserStoreFilterMode mode; + + if (PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + { + mode = pluma_file_browser_store_get_filter_mode + (PLUMA_FILE_BROWSER_STORE (view->priv->model)); + mode ^= PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; + pluma_file_browser_store_set_filter_mode + (PLUMA_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) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + view->priv->drag_button = 0; + view->priv->drag_started = TRUE; + + /* Chain up */ + GTK_WIDGET_CLASS (pluma_file_browser_view_parent_class)->drag_begin (widget, context); +} + +static void +did_not_drag (PlumaFileBrowserView *view, + GdkEventButton *event) +{ + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreePath *path; + + tree_view = GTK_TREE_VIEW (view); + selection = gtk_tree_view_get_selection (tree_view); + + if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, + &path, NULL, NULL, NULL)) { + if ((view->priv->click_policy == PLUMA_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) +{ + PlumaFileBrowserView *view = PLUMA_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 (pluma_file_browser_view_parent_class)->button_release_event (widget, event); +} + +static gboolean +button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + int double_click_time; + static int click_count = 0; + static guint32 last_click_time = 0; + PlumaFileBrowserView *view; + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreePath *path; + int expander_size; + int horizontal_separator; + gboolean on_expander; + gboolean call_parent; + gboolean selected; + GtkWidgetClass *widget_parent = GTK_WIDGET_CLASS(pluma_file_browser_view_parent_class); + + tree_view = GTK_TREE_VIEW (widget); + view = PLUMA_FILE_BROWSER_VIEW (widget); + selection = gtk_tree_view_get_selection (tree_view); + + /* 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 == PLUMA_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) { + if (view->priv->double_click_path[1] && + gtk_tree_path_compare (view->priv->double_click_path[0], view->priv->double_click_path[1]) == 0) + activate_selected_items (view); + + /* Chain up */ + widget_parent->button_press_event (widget, event); + } 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 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 == 3 && 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 != PLUMA_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) +{ + PlumaFileBrowserView *view; + guint modifiers; + gboolean handled; + + view = PLUMA_FILE_BROWSER_VIEW (widget); + handled = FALSE; + + modifiers = gtk_accelerator_get_default_mod_mask (); + + switch (event->keyval) { + case GDK_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_Return: + case GDK_KP_Enter: + activate_selected_items (view); + handled = TRUE; + break; + + case GDK_h: + if ((event->state & modifiers) == GDK_CONTROL_MASK) { + toggle_hidden_filter (view); + handled = TRUE; + break; + } + + default: + handled = FALSE; + } + + /* Chain up */ + if (!handled) + return GTK_WIDGET_CLASS (pluma_file_browser_view_parent_class)->key_press_event (widget, event); + + return TRUE; +} + +static void +fill_expand_state (PlumaFileBrowserView * view, GtkTreeIter * iter) +{ + GtkTreePath * path; + GtkTreeIter child; + gchar * uri; + + 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)) + { + gtk_tree_model_get (view->priv->model, + iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, + -1); + + add_expand_state (view, uri); + g_free (uri); + } + + 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 (PlumaFileBrowserView * 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 (PlumaFileBrowserView * 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 (PlumaFileBrowserView * 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 && PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + { + fill_expand_state (view, NULL); + + install_restore_signals (view, view->priv->model); + } + } + else if (view->priv->model && PLUMA_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) +{ + PlumaFileBrowserView *obj = PLUMA_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) +{ + PlumaFileBrowserView *obj = PLUMA_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 +pluma_file_browser_view_class_init (PlumaFileBrowserViewClass * 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 = pluma_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_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", + PLUMA_TYPE_FILE_BROWSER_VIEW_CLICK_POLICY, + PLUMA_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 (PlumaFileBrowserViewClass, + error), NULL, NULL, + pluma_file_browser_marshal_VOID__UINT_STRING, + 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 (PlumaFileBrowserViewClass, + file_activated), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + 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 (PlumaFileBrowserViewClass, + directory_activated), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + 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 (PlumaFileBrowserViewClass, + bookmark_activated), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); + + g_type_class_add_private (object_class, + sizeof (PlumaFileBrowserViewPrivate)); +} + +static void +cell_data_cb (GtkTreeViewColumn * tree_column, GtkCellRenderer * cell, + GtkTreeModel * tree_model, GtkTreeIter * iter, + PlumaFileBrowserView * obj) +{ + GtkTreePath *path; + PangoUnderline underline = PANGO_UNDERLINE_NONE; + gboolean editable = FALSE; + + path = gtk_tree_model_get_path (tree_model, iter); + + if (obj->priv->click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { + if (obj->priv->hover_path != NULL && + gtk_tree_path_compare (path, obj->priv->hover_path) == 0) + underline = PANGO_UNDERLINE_SINGLE; + } + + if (PLUMA_IS_FILE_BROWSER_STORE (tree_model)) + { + if (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 (path); + g_object_set (cell, "editable", editable, "underline", underline, NULL); +} + +static void +pluma_file_browser_view_init (PlumaFileBrowserView * obj) +{ + obj->priv = PLUMA_FILE_BROWSER_VIEW_GET_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_add_attribute (obj->priv->column, + obj->priv->pixbuf_renderer, + "pixbuf", + PLUMA_FILE_BROWSER_STORE_COLUMN_ICON); + + 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, + "text", + PLUMA_FILE_BROWSER_STORE_COLUMN_NAME); + + 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); + + obj->priv->busy_cursor = gdk_cursor_new (GDK_WATCH); +} + +static gboolean +bookmarks_separator_func (GtkTreeModel * model, GtkTreeIter * iter, + gpointer user_data) +{ + guint flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + &flags, -1); + + return (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR); +} + +/* Public */ +GtkWidget * +pluma_file_browser_view_new (void) +{ + PlumaFileBrowserView *obj = + PLUMA_FILE_BROWSER_VIEW (g_object_new + (PLUMA_TYPE_FILE_BROWSER_VIEW, NULL)); + + return GTK_WIDGET (obj); +} + +void +pluma_file_browser_view_set_model (PlumaFileBrowserView * tree_view, + GtkTreeModel * model) +{ + GtkTreeSelection *selection; + + if (tree_view->priv->model == model) + return; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + if (PLUMA_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); + } 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); + + 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 (PLUMA_IS_FILE_BROWSER_STORE (tree_view->priv->model)) { + if (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); +} + +void +pluma_file_browser_view_start_rename (PlumaFileBrowserView * tree_view, + GtkTreeIter * iter) +{ + guint flags; + GtkTreeRowReference *rowref; + GtkTreePath *path; + + g_return_if_fail (PLUMA_IS_FILE_BROWSER_VIEW (tree_view)); + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE + (tree_view->priv->model)); + g_return_if_fail (iter != NULL); + + gtk_tree_model_get (tree_view->priv->model, iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!(FILE_IS_DIR (flags) || !FILE_IS_DUMMY (flags))) + return; + + 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->editable = rowref; + + gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), + gtk_tree_row_reference_get_path (tree_view->priv->editable), + tree_view->priv->column, TRUE); + + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), + gtk_tree_row_reference_get_path (tree_view->priv->editable), + tree_view->priv->column, + FALSE, 0.0, 0.0); +} + +void +pluma_file_browser_view_set_click_policy (PlumaFileBrowserView *tree_view, + PlumaFileBrowserViewClickPolicy policy) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_VIEW (tree_view)); + + set_click_policy_property (tree_view, policy); + + g_object_notify (G_OBJECT (tree_view), "click-policy"); +} + +void +pluma_file_browser_view_set_restore_expand_state (PlumaFileBrowserView * tree_view, + gboolean restore_expand_state) +{ + g_return_if_fail (PLUMA_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, + PlumaFileBrowserView * tree_view) +{ + GtkTreePath * treepath; + GtkTreeIter iter; + gboolean ret; + GError * error = NULL; + + gtk_tree_row_reference_free (tree_view->priv->editable); + tree_view->priv->editable = NULL; + + if (new_text == NULL || *new_text == '\0') + return; + + treepath = gtk_tree_path_new_from_string (path); + ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model), &iter, treepath); + gtk_tree_path_free (treepath); + + if (ret) { + if (pluma_file_browser_store_rename (PLUMA_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); + } + } + } +} + +static void +on_begin_refresh (PlumaFileBrowserStore * model, + PlumaFileBrowserView * 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 (PlumaFileBrowserStore * model, + PlumaFileBrowserView * view) +{ + /* Store the refresh state, so we can handle unloading of nodes while + refreshing properly */ + view->priv->is_refresh = FALSE; +} + +static void +on_unload (PlumaFileBrowserStore * model, + gchar const * uri, + PlumaFileBrowserView * 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, uri); +} + +static void +restore_expand_state (PlumaFileBrowserView * view, + PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + gchar * uri; + GFile * file; + GtkTreePath * path; + + gtk_tree_model_get (GTK_TREE_MODEL (model), + iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, + -1); + + if (!uri) + return; + + file = g_file_new_for_uri (uri); + path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); + + if (g_hash_table_lookup (view->priv->expand_state, file)) + { + gtk_tree_view_expand_row (GTK_TREE_VIEW (view), + path, + FALSE); + } + + gtk_tree_path_free (path); + + g_object_unref (file); + g_free (uri); +} + +static void +on_row_inserted (PlumaFileBrowserStore * model, + GtkTreePath * path, + GtkTreeIter * iter, + PlumaFileBrowserView * 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); +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-view.h b/plugins/filebrowser/pluma-file-browser-view.h new file mode 100755 index 00000000..04e64953 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-view.h @@ -0,0 +1,84 @@ +/* + * pluma-file-browser-view.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_VIEW_H__ +#define __PLUMA_FILE_BROWSER_VIEW_H__ + +#include + +G_BEGIN_DECLS +#define PLUMA_TYPE_FILE_BROWSER_VIEW (pluma_file_browser_view_get_type ()) +#define PLUMA_FILE_BROWSER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserView)) +#define PLUMA_FILE_BROWSER_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserView const)) +#define PLUMA_FILE_BROWSER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserViewClass)) +#define PLUMA_IS_FILE_BROWSER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_FILE_BROWSER_VIEW)) +#define PLUMA_IS_FILE_BROWSER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_FILE_BROWSER_VIEW)) +#define PLUMA_FILE_BROWSER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserViewClass)) + +typedef struct _PlumaFileBrowserView PlumaFileBrowserView; +typedef struct _PlumaFileBrowserViewClass PlumaFileBrowserViewClass; +typedef struct _PlumaFileBrowserViewPrivate PlumaFileBrowserViewPrivate; + +typedef enum { + PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE, + PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE +} PlumaFileBrowserViewClickPolicy; + +struct _PlumaFileBrowserView +{ + GtkTreeView parent; + + PlumaFileBrowserViewPrivate *priv; +}; + +struct _PlumaFileBrowserViewClass +{ + GtkTreeViewClass parent_class; + + /* Signals */ + void (*error) (PlumaFileBrowserView * filetree, + guint code, + gchar const *message); + void (*file_activated) (PlumaFileBrowserView * filetree, + GtkTreeIter *iter); + void (*directory_activated) (PlumaFileBrowserView * filetree, + GtkTreeIter *iter); + void (*bookmark_activated) (PlumaFileBrowserView * filetree, + GtkTreeIter *iter); +}; + +GType pluma_file_browser_view_get_type (void) G_GNUC_CONST; +GType pluma_file_browser_view_register_type (GTypeModule * module); + +GtkWidget *pluma_file_browser_view_new (void); +void pluma_file_browser_view_set_model (PlumaFileBrowserView * tree_view, + GtkTreeModel * model); +void pluma_file_browser_view_start_rename (PlumaFileBrowserView * tree_view, + GtkTreeIter * iter); +void pluma_file_browser_view_set_click_policy (PlumaFileBrowserView * tree_view, + PlumaFileBrowserViewClickPolicy policy); +void pluma_file_browser_view_set_restore_expand_state (PlumaFileBrowserView * tree_view, + gboolean restore_expand_state); + +G_END_DECLS +#endif /* __PLUMA_FILE_BROWSER_VIEW_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-widget-ui.xml b/plugins/filebrowser/pluma-file-browser-widget-ui.xml new file mode 100755 index 00000000..472fd185 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-widget-ui.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/filebrowser/pluma-file-browser-widget.c b/plugins/filebrowser/pluma-file-browser-widget.c new file mode 100755 index 00000000..969c2ae4 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-widget.c @@ -0,0 +1,3143 @@ +/* + * pluma-file-browser-widget.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pluma-file-browser-utils.h" +#include "pluma-file-browser-error.h" +#include "pluma-file-browser-widget.h" +#include "pluma-file-browser-view.h" +#include "pluma-file-browser-store.h" +#include "pluma-file-bookmarks-store.h" +#include "pluma-file-browser-marshal.h" +#include "pluma-file-browser-enum-types.h" + +#define PLUMA_FILE_BROWSER_WIDGET_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ + PLUMA_TYPE_FILE_BROWSER_WIDGET, \ + PlumaFileBrowserWidgetPrivate)) + +#define XML_UI_FILE "pluma-file-browser-widget-ui.xml" +#define LOCATION_DATA_KEY "pluma-file-browser-widget-location" + +enum +{ + BOOKMARKS_ID, + SEPARATOR_CUSTOM_ID, + SEPARATOR_ID, + PATH_ID, + NUM_DEFAULT_IDS +}; + +enum +{ + COLUMN_INDENT, + COLUMN_ICON, + COLUMN_NAME, + COLUMN_FILE, + COLUMN_ID, + N_COLUMNS +}; + +/* Properties */ +enum +{ + PROP_0, + + PROP_FILTER_PATTERN, + PROP_ENABLE_DELETE +}; + +/* Signals */ +enum +{ + URI_ACTIVATED, + ERROR, + CONFIRM_DELETE, + CONFIRM_NO_TRASH, + NUM_SIGNALS +}; + +static guint signals[NUM_SIGNALS] = { 0 }; + +typedef struct _SignalNode +{ + GObject *object; + gulong id; +} SignalNode; + +typedef struct +{ + gulong id; + PlumaFileBrowserWidgetFilterFunc func; + gpointer user_data; + GDestroyNotify destroy_notify; +} FilterFunc; + +typedef struct +{ + GFile *root; + GFile *virtual_root; +} Location; + +typedef struct +{ + gchar *name; + GdkPixbuf *icon; +} NameIcon; + +struct _PlumaFileBrowserWidgetPrivate +{ + PlumaFileBrowserView *treeview; + PlumaFileBrowserStore *file_store; + PlumaFileBookmarksStore *bookmarks_store; + + GHashTable *bookmarks_hash; + + GtkWidget *combo; + GtkTreeStore *combo_model; + + GtkWidget *filter_expander; + GtkWidget *filter_entry; + + GtkUIManager *manager; + GtkActionGroup *action_group; + GtkActionGroup *action_group_selection; + GtkActionGroup *action_group_file_selection; + GtkActionGroup *action_group_single_selection; + GtkActionGroup *action_group_single_most_selection; + GtkActionGroup *action_group_sensitive; + GtkActionGroup *bookmark_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; + + gboolean enable_delete; + + GCancellable *cancellable; + + GdkCursor *busy_cursor; +}; + +static void set_enable_delete (PlumaFileBrowserWidget *obj, + gboolean enable); +static void on_model_set (GObject * gobject, + GParamSpec * arg1, + PlumaFileBrowserWidget * obj); +static void on_treeview_error (PlumaFileBrowserView * tree_view, + guint code, + gchar * message, + PlumaFileBrowserWidget * obj); +static void on_file_store_error (PlumaFileBrowserStore * store, + guint code, + gchar * message, + PlumaFileBrowserWidget * obj); +static gboolean on_file_store_no_trash (PlumaFileBrowserStore * store, + GList * files, + PlumaFileBrowserWidget * obj); +static void on_combo_changed (GtkComboBox * combo, + PlumaFileBrowserWidget * obj); +static gboolean on_treeview_popup_menu (PlumaFileBrowserView * treeview, + PlumaFileBrowserWidget * obj); +static gboolean on_treeview_button_press_event (PlumaFileBrowserView * treeview, + GdkEventButton * event, + PlumaFileBrowserWidget * obj); +static gboolean on_treeview_key_press_event (PlumaFileBrowserView * treeview, + GdkEventKey * event, + PlumaFileBrowserWidget * obj); +static void on_selection_changed (GtkTreeSelection * selection, + PlumaFileBrowserWidget * obj); + +static void on_virtual_root_changed (PlumaFileBrowserStore * model, + GParamSpec *param, + PlumaFileBrowserWidget * obj); + +static gboolean on_entry_filter_activate (PlumaFileBrowserWidget * obj); +static void on_location_jump_activate (GtkMenuItem * item, + PlumaFileBrowserWidget * obj); +static void on_bookmarks_row_changed (GtkTreeModel * model, + GtkTreePath * path, + GtkTreeIter * iter, + PlumaFileBrowserWidget * obj); +static void on_bookmarks_row_deleted (GtkTreeModel * model, + GtkTreePath * path, + PlumaFileBrowserWidget * obj); +static void on_filter_mode_changed (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaFileBrowserWidget * obj); +static void on_action_directory_previous (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_next (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_up (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_new (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_open (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_new (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_rename (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_delete (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_move_to_trash (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_refresh (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_open (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_filter_hidden (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_filter_binary (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_bookmark_open (GtkAction * action, + PlumaFileBrowserWidget * obj); + +PLUMA_PLUGIN_DEFINE_TYPE (PlumaFileBrowserWidget, pluma_file_browser_widget, + GTK_TYPE_VBOX) + +static void +free_name_icon (gpointer data) +{ + NameIcon * item; + + if (data == NULL) + return; + + item = (NameIcon *)(data); + + g_free (item->name); + + if (item->icon) + g_object_unref (item->icon); + + g_free (item); +} + +static FilterFunc * +filter_func_new (PlumaFileBrowserWidget * obj, + PlumaFileBrowserWidgetFilterFunc func, + gpointer user_data, + GDestroyNotify notify) +{ + FilterFunc *result; + + result = g_new (FilterFunc, 1); + + 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_free (loc); +} + +static gboolean +combo_find_by_id (PlumaFileBrowserWidget * obj, guint id, + GtkTreeIter * iter) +{ + guint checkid; + GtkTreeModel *model = GTK_TREE_MODEL (obj->priv->combo_model); + + 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 +remove_path_items (PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + + while (combo_find_by_id (obj, PATH_ID, &iter)) + gtk_tree_store_remove (obj->priv->combo_model, &iter); +} + +static void +cancel_async_operation (PlumaFileBrowserWidget *widget) +{ + if (!widget->priv->cancellable) + return; + + g_cancellable_cancel (widget->priv->cancellable); + g_object_unref (widget->priv->cancellable); + + widget->priv->cancellable = NULL; +} + +static void +pluma_file_browser_widget_finalize (GObject * object) +{ + PlumaFileBrowserWidget *obj = PLUMA_FILE_BROWSER_WIDGET (object); + GList *loc; + + remove_path_items (obj); + pluma_file_browser_store_set_filter_func (obj->priv->file_store, + NULL, NULL); + + g_object_unref (obj->priv->manager); + g_object_unref (obj->priv->file_store); + g_object_unref (obj->priv->bookmarks_store); + g_object_unref (obj->priv->combo_model); + + g_slist_foreach (obj->priv->filter_funcs, (GFunc) g_free, NULL); + g_slist_free (obj->priv->filter_funcs); + + for (loc = obj->priv->locations; loc; loc = loc->next) + location_free ((Location *) (loc->data)); + + if (obj->priv->current_location_menu_item) + g_object_unref (obj->priv->current_location_menu_item); + + g_list_free (obj->priv->locations); + + g_hash_table_destroy (obj->priv->bookmarks_hash); + + cancel_async_operation (obj); + + gdk_cursor_unref (obj->priv->busy_cursor); + + G_OBJECT_CLASS (pluma_file_browser_widget_parent_class)->finalize (object); +} + +static void +pluma_file_browser_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserWidget *obj = PLUMA_FILE_BROWSER_WIDGET (object); + + switch (prop_id) + { + case PROP_FILTER_PATTERN: + g_value_set_string (value, obj->priv->filter_pattern_str); + break; + case PROP_ENABLE_DELETE: + g_value_set_boolean (value, obj->priv->enable_delete); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserWidget *obj = PLUMA_FILE_BROWSER_WIDGET (object); + + switch (prop_id) + { + case PROP_FILTER_PATTERN: + pluma_file_browser_widget_set_filter_pattern (obj, + g_value_get_string (value)); + break; + case PROP_ENABLE_DELETE: + set_enable_delete (obj, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_widget_class_init (PlumaFileBrowserWidgetClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = pluma_file_browser_widget_finalize; + + object_class->get_property = pluma_file_browser_widget_get_property; + object_class->set_property = pluma_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", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_ENABLE_DELETE, + g_param_spec_boolean ("enable-delete", + "Enable delete", + "Enable permanently deleting items", + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[URI_ACTIVATED] = + g_signal_new ("uri-activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserWidgetClass, + uri_activated), NULL, NULL, + g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, + G_TYPE_STRING); + signals[ERROR] = + g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserWidgetClass, + error), NULL, NULL, + pluma_file_browser_marshal_VOID__UINT_STRING, + 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 (PlumaFileBrowserWidgetClass, + confirm_delete), + g_signal_accumulator_true_handled, + NULL, + pluma_file_browser_marshal_BOOL__OBJECT_POINTER, + 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 (PlumaFileBrowserWidgetClass, + confirm_no_trash), + g_signal_accumulator_true_handled, + NULL, + pluma_file_browser_marshal_BOOL__POINTER, + G_TYPE_BOOLEAN, + 1, + G_TYPE_POINTER); + + g_type_class_add_private (object_class, + sizeof (PlumaFileBrowserWidgetPrivate)); +} + +static void +add_signal (PlumaFileBrowserWidget * obj, gpointer object, gulong id) +{ + SignalNode *node = g_new (SignalNode, 1); + + node->object = G_OBJECT (object); + node->id = id; + + obj->priv->signal_pool = + g_slist_prepend (obj->priv->signal_pool, node); +} + +static void +clear_signals (PlumaFileBrowserWidget * obj) +{ + GSList *item; + SignalNode *node; + + for (item = obj->priv->signal_pool; item; item = item->next) { + node = (SignalNode *) (item->data); + + g_signal_handler_disconnect (node->object, node->id); + g_free (item->data); + } + + g_slist_free (obj->priv->signal_pool); + obj->priv->signal_pool = NULL; +} + +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 (PlumaFileBrowserWidget * obj, GFile * file, + gchar ** name, GdkPixbuf ** icon) +{ + gpointer data; + NameIcon * item; + + data = g_hash_table_lookup (obj->priv->bookmarks_hash, file); + + if (data == NULL) + return FALSE; + + item = (NameIcon *)data; + + *name = g_strdup (item->name); + *icon = item->icon; + + if (item->icon != NULL) + { + g_object_ref (item->icon); + } + + return TRUE; +} + +static void +insert_path_item (PlumaFileBrowserWidget * obj, + GFile * file, + GtkTreeIter * after, + GtkTreeIter * iter, + guint indent) +{ + gchar * unescape; + GdkPixbuf * icon = NULL; + + /* Try to get the icon and name from the bookmarks hash */ + if (!get_from_bookmark_file (obj, file, &unescape, &icon)) { + /* It's not a bookmark, fetch the name and the icon ourselves */ + unescape = pluma_file_browser_utils_file_basename (file); + + /* Get the icon */ + icon = pluma_file_browser_utils_pixbuf_from_file (file, GTK_ICON_SIZE_MENU); + } + + gtk_tree_store_insert_after (obj->priv->combo_model, iter, NULL, + after); + + gtk_tree_store_set (obj->priv->combo_model, + iter, + COLUMN_INDENT, indent, + COLUMN_ICON, icon, + COLUMN_NAME, unescape, + COLUMN_FILE, file, + COLUMN_ID, PATH_ID, + -1); + + if (icon) + g_object_unref (icon); + + g_free (unescape); +} + +static void +insert_separator_item (PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + + gtk_tree_store_insert (obj->priv->combo_model, &iter, NULL, 1); + gtk_tree_store_set (obj->priv->combo_model, &iter, + COLUMN_ICON, NULL, + COLUMN_NAME, NULL, + COLUMN_ID, SEPARATOR_ID, -1); +} + +static void +combo_set_active_by_id (PlumaFileBrowserWidget * obj, guint id) +{ + GtkTreeIter iter; + + if (combo_find_by_id (obj, id, &iter)) + gtk_combo_box_set_active_iter (GTK_COMBO_BOX + (obj->priv->combo), &iter); +} + +static guint +uri_num_parents (GFile * from, GFile * to) +{ + /* Determine the number of 'levels' to get from #from to #to. */ + guint parents = 0; + GFile * parent; + + if (from == NULL) + return 0; + + g_object_ref (from); + + while ((parent = g_file_get_parent (from)) && !(to && g_file_equal (from, to))) { + g_object_unref (from); + from = parent; + + ++parents; + } + + g_object_unref (from); + return parents; +} + +static void +insert_location_path (PlumaFileBrowserWidget * obj) +{ + Location *loc; + GFile *current = NULL; + GFile * tmp; + GtkTreeIter separator; + GtkTreeIter iter; + guint indent; + + if (!obj->priv->current_location) { + g_message ("insert_location_path: no current location"); + return; + } + + loc = (Location *) (obj->priv->current_location->data); + + current = loc->virtual_root; + combo_find_by_id (obj, SEPARATOR_ID, &separator); + + indent = uri_num_parents (loc->virtual_root, loc->root); + + while (current != NULL) { + insert_path_item (obj, current, &separator, &iter, indent--); + + if (current == loc->virtual_root) { + g_signal_handlers_block_by_func (obj->priv->combo, + on_combo_changed, + obj); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX + (obj->priv->combo), + &iter); + g_signal_handlers_unblock_by_func (obj->priv-> + combo, + on_combo_changed, + obj); + } + + if (g_file_equal (current, loc->root) || !pluma_utils_file_has_parent (current)) { + 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 +check_current_item (PlumaFileBrowserWidget * obj, gboolean show_path) +{ + GtkTreeIter separator; + gboolean has_sep; + + remove_path_items (obj); + has_sep = combo_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_tree_store_remove (obj->priv->combo_model, &separator); +} + +static void +fill_combo_model (PlumaFileBrowserWidget * obj) +{ + GtkTreeStore *store = obj->priv->combo_model; + GtkTreeIter iter; + GdkPixbuf *icon; + + icon = pluma_file_browser_utils_pixbuf_from_theme (GTK_STOCK_HOME, GTK_ICON_SIZE_MENU); + + gtk_tree_store_append (store, &iter, NULL); + gtk_tree_store_set (store, &iter, + COLUMN_ICON, icon, + COLUMN_NAME, _("Bookmarks"), + COLUMN_ID, BOOKMARKS_ID, -1); + g_object_unref (icon); + + gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (obj->priv->combo), + separator_func, obj, NULL); + gtk_combo_box_set_active (GTK_COMBO_BOX (obj->priv->combo), 0); +} + +static void +indent_cell_data_func (GtkCellLayout * cell_layout, + GtkCellRenderer * cell, + GtkTreeModel * model, + GtkTreeIter * iter, + gpointer data) +{ + gchar * indent; + guint num; + + gtk_tree_model_get (model, iter, COLUMN_INDENT, &num, -1); + + if (num == 0) + g_object_set (cell, "text", "", NULL); + else { + indent = g_strnfill (num * 2, ' '); + + g_object_set (cell, "text", indent, NULL); + g_free (indent); + } +} + +static void +create_combo (PlumaFileBrowserWidget * obj) +{ + GtkCellRenderer *renderer; + + obj->priv->combo_model = gtk_tree_store_new (N_COLUMNS, + G_TYPE_UINT, + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_FILE, + G_TYPE_UINT); + obj->priv->combo = + gtk_combo_box_new_with_model (GTK_TREE_MODEL + (obj->priv->combo_model)); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, FALSE); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT + (obj->priv->combo), renderer, + indent_cell_data_func, obj, NULL); + + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, "pixbuf", COLUMN_ICON); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, "text", COLUMN_NAME); + + g_object_set (renderer, "ellipsize-set", TRUE, + "ellipsize", PANGO_ELLIPSIZE_END, NULL); + + gtk_box_pack_start (GTK_BOX (obj), GTK_WIDGET (obj->priv->combo), + FALSE, FALSE, 0); + + fill_combo_model (obj); + g_signal_connect (obj->priv->combo, "changed", + G_CALLBACK (on_combo_changed), obj); + + gtk_widget_show (obj->priv->combo); +} + +static GtkActionEntry toplevel_actions[] = +{ + {"FilterMenuAction", NULL, N_("_Filter")} +}; + +static const GtkActionEntry tree_actions_selection[] = +{ + {"FileMoveToTrash", "mate-stock-trash", N_("_Move to Trash"), NULL, + N_("Move selected file or folder to trash"), + G_CALLBACK (on_action_file_move_to_trash)}, + {"FileDelete", GTK_STOCK_DELETE, N_("_Delete"), NULL, + N_("Delete selected file or folder"), + G_CALLBACK (on_action_file_delete)} +}; + +static const GtkActionEntry tree_actions_file_selection[] = +{ + {"FileOpen", GTK_STOCK_OPEN, NULL, NULL, + N_("Open selected file"), + G_CALLBACK (on_action_file_open)} +}; + +static const GtkActionEntry tree_actions[] = +{ + {"DirectoryUp", GTK_STOCK_GO_UP, N_("Up"), NULL, + N_("Open the parent folder"), G_CALLBACK (on_action_directory_up)} +}; + +static const GtkActionEntry tree_actions_single_most_selection[] = +{ + {"DirectoryNew", GTK_STOCK_ADD, N_("_New Folder"), NULL, + N_("Add new empty folder"), + G_CALLBACK (on_action_directory_new)}, + {"FileNew", GTK_STOCK_NEW, N_("New F_ile"), NULL, + N_("Add new empty file"), G_CALLBACK (on_action_file_new)} +}; + +static const GtkActionEntry tree_actions_single_selection[] = +{ + {"FileRename", NULL, N_("_Rename"), NULL, + N_("Rename selected file or folder"), + G_CALLBACK (on_action_file_rename)} +}; + +static const GtkActionEntry tree_actions_sensitive[] = +{ + {"DirectoryPrevious", GTK_STOCK_GO_BACK, N_("_Previous Location"), + NULL, + N_("Go to the previous visited location"), + G_CALLBACK (on_action_directory_previous)}, + {"DirectoryNext", GTK_STOCK_GO_FORWARD, N_("_Next Location"), NULL, + N_("Go to the next visited location"), G_CALLBACK (on_action_directory_next)}, + {"DirectoryRefresh", GTK_STOCK_REFRESH, N_("Re_fresh View"), NULL, + N_("Refresh the view"), G_CALLBACK (on_action_directory_refresh)}, + {"DirectoryOpen", GTK_STOCK_OPEN, N_("_View Folder"), NULL, + N_("View folder in file manager"), + G_CALLBACK (on_action_directory_open)} +}; + +static const GtkToggleActionEntry tree_actions_toggle[] = +{ + {"FilterHidden", GTK_STOCK_DIALOG_AUTHENTICATION, + N_("Show _Hidden"), NULL, + N_("Show hidden files and folders"), + G_CALLBACK (on_action_filter_hidden), FALSE}, + {"FilterBinary", NULL, N_("Show _Binary"), NULL, + N_("Show binary files"), G_CALLBACK (on_action_filter_binary), + FALSE} +}; + +static const GtkActionEntry bookmark_actions[] = +{ + {"BookmarkOpen", GTK_STOCK_OPEN, N_("_View Folder"), NULL, + N_("View folder in file manager"), G_CALLBACK (on_action_bookmark_open)} +}; + +static void +create_toolbar (PlumaFileBrowserWidget * obj, + const gchar *data_dir) +{ + GtkUIManager *manager; + GError *error = NULL; + GtkActionGroup *action_group; + GtkWidget *toolbar; + GtkWidget *widget; + GtkAction *action; + gchar *ui_file; + + manager = gtk_ui_manager_new (); + obj->priv->manager = manager; + + ui_file = g_build_filename (data_dir, XML_UI_FILE, NULL); + gtk_ui_manager_add_ui_from_file (manager, ui_file, &error); + + g_free (ui_file); + + if (error != NULL) { + g_warning ("Error in adding ui from file %s: %s", + XML_UI_FILE, error->message); + g_error_free (error); + return; + } + + action_group = gtk_action_group_new ("FileBrowserWidgetActionGroupToplevel"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + toplevel_actions, + G_N_ELEMENTS (toplevel_actions), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + + action_group = gtk_action_group_new ("FileBrowserWidgetActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions, + G_N_ELEMENTS (tree_actions), + obj); + gtk_action_group_add_toggle_actions (action_group, + tree_actions_toggle, + G_N_ELEMENTS (tree_actions_toggle), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetSelectionActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_selection, + G_N_ELEMENTS (tree_actions_selection), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_selection = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetFileSelectionActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_file_selection, + G_N_ELEMENTS (tree_actions_file_selection), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_file_selection = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetSingleSelectionActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_single_selection, + G_N_ELEMENTS (tree_actions_single_selection), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_single_selection = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetSingleMostSelectionActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_single_most_selection, + G_N_ELEMENTS (tree_actions_single_most_selection), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_single_most_selection = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetSensitiveActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_sensitive, + G_N_ELEMENTS (tree_actions_sensitive), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_sensitive = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetBookmarkActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + bookmark_actions, + G_N_ELEMENTS (bookmark_actions), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->bookmark_action_group = action_group; + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryPrevious"); + gtk_action_set_sensitive (action, FALSE); + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryNext"); + gtk_action_set_sensitive (action, FALSE); + + toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar"); + gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU); + + /* Previous directory menu tool item */ + obj->priv->location_previous_menu = gtk_menu_new (); + gtk_widget_show (obj->priv->location_previous_menu); + + widget = GTK_WIDGET (gtk_menu_tool_button_new_from_stock (GTK_STOCK_GO_BACK)); + gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), + obj->priv->location_previous_menu); + + g_object_set (widget, "label", _("Previous location"), NULL); + gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (widget), + _("Go to previous location")); + gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (widget), + _("Go to a previously opened location")); + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryPrevious"); + g_object_set (action, "is_important", TRUE, "short_label", + _("Previous location"), NULL); + gtk_action_connect_proxy (action, widget); + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget), 0); + + /* Next directory menu tool item */ + obj->priv->location_next_menu = gtk_menu_new (); + gtk_widget_show (obj->priv->location_next_menu); + + widget = GTK_WIDGET (gtk_menu_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD)); + gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), + obj->priv->location_next_menu); + + g_object_set (widget, "label", _("Next location"), NULL); + gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (widget), + _("Go to next location")); + gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (widget), + _("Go to a previously opened location")); + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryNext"); + g_object_set (action, "is_important", TRUE, "short_label", + _("Previous location"), NULL); + gtk_action_connect_proxy (action, widget); + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget), 1); + + gtk_box_pack_start (GTK_BOX (obj), toolbar, FALSE, FALSE, 0); + gtk_widget_show (toolbar); + + set_enable_delete (obj, obj->priv->enable_delete); +} + +static void +set_enable_delete (PlumaFileBrowserWidget *obj, + gboolean enable) +{ + GtkAction *action; + obj->priv->enable_delete = enable; + + if (obj->priv->action_group_selection == NULL) + return; + + action = + gtk_action_group_get_action (obj->priv->action_group_selection, + "FileDelete"); + + g_object_set (action, "visible", enable, "sensitive", enable, NULL); +} + +static gboolean +filter_real (PlumaFileBrowserStore * model, GtkTreeIter * iter, + PlumaFileBrowserWidget * obj) +{ + GSList *item; + FilterFunc *func; + + for (item = obj->priv->filter_funcs; item; item = item->next) { + func = (FilterFunc *) (item->data); + + if (!func->func (obj, model, iter, func->user_data)) + return FALSE; + } + + return TRUE; +} + +static void +add_bookmark_hash (PlumaFileBrowserWidget * obj, + GtkTreeIter * iter) +{ + GtkTreeModel *model; + GdkPixbuf * pixbuf; + gchar * name; + gchar * uri; + GFile * file; + NameIcon * item; + + model = GTK_TREE_MODEL (obj->priv->bookmarks_store); + + uri = pluma_file_bookmarks_store_get_uri (obj->priv-> + bookmarks_store, + iter); + + if (uri == NULL) + return; + + file = g_file_new_for_uri (uri); + g_free (uri); + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_ICON, + &pixbuf, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, + &name, -1); + + item = g_new (NameIcon, 1); + item->name = name; + item->icon = pixbuf; + + g_hash_table_insert (obj->priv->bookmarks_hash, + file, + item); +} + +static void +init_bookmarks_hash (PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + model = GTK_TREE_MODEL (obj->priv->bookmarks_store); + + 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 (PlumaFileBrowserStore *model, + GtkTreeIter *iter, + PlumaFileBrowserWidget *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 (PlumaFileBrowserStore *model, + GtkTreeIter *iter, + PlumaFileBrowserWidget *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 +create_tree (PlumaFileBrowserWidget * obj) +{ + GtkWidget *sw; + + obj->priv->file_store = pluma_file_browser_store_new (NULL); + obj->priv->bookmarks_store = pluma_file_bookmarks_store_new (); + obj->priv->treeview = + PLUMA_FILE_BROWSER_VIEW (pluma_file_browser_view_new ()); + + pluma_file_browser_view_set_restore_expand_state (obj->priv->treeview, TRUE); + + pluma_file_browser_store_set_filter_mode (obj->priv->file_store, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN + | + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); + pluma_file_browser_store_set_filter_func (obj->priv->file_store, + (PlumaFileBrowserStoreFilterFunc) + filter_real, obj); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), + GTK_SHADOW_ETCHED_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_container_add (GTK_CONTAINER (sw), + GTK_WIDGET (obj->priv->treeview)); + gtk_box_pack_start (GTK_BOX (obj), sw, TRUE, TRUE, 0); + + 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); + + gtk_widget_show (sw); + gtk_widget_show (GTK_WIDGET (obj->priv->treeview)); +} + +static void +create_filter (PlumaFileBrowserWidget * obj) +{ + GtkWidget *expander; + GtkWidget *vbox; + GtkWidget *entry; + + expander = gtk_expander_new_with_mnemonic (_("_Match Filename")); + gtk_widget_show (expander); + gtk_box_pack_start (GTK_BOX (obj), expander, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 3); + gtk_widget_show (vbox); + + obj->priv->filter_expander = expander; + + entry = gtk_entry_new (); + gtk_widget_show (entry); + + obj->priv->filter_entry = entry; + + g_signal_connect_swapped (entry, "activate", + G_CALLBACK (on_entry_filter_activate), + obj); + g_signal_connect_swapped (entry, "focus_out_event", + G_CALLBACK (on_entry_filter_activate), + obj); + + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (expander), vbox); +} + +static void +pluma_file_browser_widget_init (PlumaFileBrowserWidget * obj) +{ + obj->priv = PLUMA_FILE_BROWSER_WIDGET_GET_PRIVATE (obj); + + obj->priv->bookmarks_hash = g_hash_table_new_full (g_file_hash, + (GEqualFunc)g_file_equal, + g_object_unref, + free_name_icon); + + gtk_box_set_spacing (GTK_BOX (obj), 3); + + obj->priv->busy_cursor = gdk_cursor_new (GDK_WATCH); +} + +/* Private */ + +static void +update_sensitivity (PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + GtkAction *action; + gint mode; + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) { + gtk_action_group_set_sensitive (obj->priv->action_group, + TRUE); + gtk_action_group_set_sensitive (obj->priv->bookmark_action_group, + FALSE); + + mode = + pluma_file_browser_store_get_filter_mode + (PLUMA_FILE_BROWSER_STORE (model)); + + action = + gtk_action_group_get_action (obj->priv->action_group, + "FilterHidden"); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + !(mode & + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN)); + } else if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) { + gtk_action_group_set_sensitive (obj->priv->action_group, + FALSE); + gtk_action_group_set_sensitive (obj->priv->bookmark_action_group, + TRUE); + + /* Set the filter toggle to normal up state, just for visual pleasure */ + action = + gtk_action_group_get_action (obj->priv->action_group, + "FilterHidden"); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + FALSE); + } + + on_selection_changed (gtk_tree_view_get_selection + (GTK_TREE_VIEW (obj->priv->treeview)), obj); +} + +static gboolean +pluma_file_browser_widget_get_first_selected (PlumaFileBrowserWidget *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_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return result; +} + +static gboolean +popup_menu (PlumaFileBrowserWidget * obj, GdkEventButton * event, GtkTreeModel * model) +{ + GtkWidget *menu; + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + menu = gtk_ui_manager_get_widget (obj->priv->manager, "/FilePopup"); + else if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) + menu = gtk_ui_manager_get_widget (obj->priv->manager, "/BookmarkPopup"); + else + return FALSE; + + g_return_val_if_fail (menu != NULL, FALSE); + + if (event != NULL) { + GtkTreeSelection *selection; + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + + if (gtk_tree_selection_count_selected_rows (selection) <= 1) { + GtkTreePath *path; + + if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (obj->priv->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 (GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button, event->time); + } else { + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, + pluma_utils_menu_position_under_tree_view, + obj->priv->treeview, 0, + gtk_get_current_event_time ()); + gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE); + } + + return TRUE; +} + +static gboolean +filter_glob (PlumaFileBrowserWidget * obj, PlumaFileBrowserStore * 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, + PLUMA_FILE_BROWSER_STORE_COLUMN_NAME, &name, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (FILE_IS_DIR (flags) || FILE_IS_DUMMY (flags)) + result = TRUE; + else + result = + g_pattern_match_string (obj->priv->filter_pattern, + name); + + g_free (name); + + return result; +} + +static void +rename_selected_file (PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + if (pluma_file_browser_widget_get_first_selected (obj, &iter)) + pluma_file_browser_view_start_rename (obj->priv->treeview, + &iter); +} + +static GList * +get_deletable_files (PlumaFileBrowserWidget *obj) { + GtkTreeSelection *selection; + GtkTreeModel *model; + GList *rows; + GList *row; + GList *paths = NULL; + guint flags; + GtkTreeIter iter; + GtkTreePath *path; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + /* Get all selected files */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + rows = gtk_tree_selection_get_selected_rows (selection, &model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + if (!gtk_tree_model_get_iter (model, &iter, path)) + continue; + + gtk_tree_model_get (model, &iter, + PLUMA_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_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return paths; +} + +static gboolean +delete_selected_files (PlumaFileBrowserWidget * obj, gboolean trash) +{ + GtkTreeModel *model; + gboolean confirm; + PlumaFileBrowserStoreResult result; + GList *rows; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return FALSE; + + rows = get_deletable_files (obj); + + if (!rows) + return FALSE; + + if (!trash) { + g_signal_emit (obj, signals[CONFIRM_DELETE], 0, model, rows, &confirm); + + if (!confirm) + return FALSE; + } + + result = pluma_file_browser_store_delete_all (PLUMA_FILE_BROWSER_STORE (model), + rows, trash); + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return result == PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +static gboolean +on_file_store_no_trash (PlumaFileBrowserStore * store, + GList * files, + PlumaFileBrowserWidget * 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 * tmp; + GFile * current; + + current = g_object_ref (file); + + while ((tmp = g_file_get_parent (current)) != NULL) { + g_object_unref (current); + current = tmp; + } + + return current; +} + +static GtkWidget * +create_goto_menu_item (PlumaFileBrowserWidget * obj, GList * item, + GdkPixbuf * icon) +{ + GtkWidget *result; + GtkWidget *image; + gchar *unescape; + GdkPixbuf *pixbuf = NULL; + Location *loc; + + loc = (Location *) (item->data); + + if (!get_from_bookmark_file (obj, loc->virtual_root, &unescape, &pixbuf)) { + unescape = pluma_file_browser_utils_file_basename (loc->virtual_root); + + if (icon) + pixbuf = g_object_ref (icon); + } + + if (pixbuf) { + image = gtk_image_new_from_pixbuf (pixbuf); + g_object_unref (pixbuf); + + gtk_widget_show (image); + + result = gtk_image_menu_item_new_with_label (unescape); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (result), + image); + } else { + 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 (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 (PlumaFileBrowserWidget * obj, GList * item, + gboolean previous) +{ + Location *loc; + GtkWidget *widget; + GList *children; + GList *child; + GList *(*iter_func) (GList *); + GtkWidget *menu_from; + GtkWidget *menu_to; + gchar *root; + gchar *virtual_root; + + 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 */ + root = g_file_get_uri (loc->root); + virtual_root = g_file_get_uri (loc->virtual_root); + + pluma_file_browser_widget_set_root_and_virtual_root (obj, + root, + virtual_root); + + g_free (root); + g_free (virtual_root); + + obj->priv->changing_location = FALSE; +} + +static void +clear_next_locations (PlumaFileBrowserWidget * obj) +{ + 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); + + gtk_action_set_sensitive (gtk_action_group_get_action + (obj->priv->action_group_sensitive, + "DirectoryNext"), FALSE); +} + +static void +update_filter_mode (PlumaFileBrowserWidget * obj, + GtkAction * action, + PlumaFileBrowserStoreFilterMode mode) +{ + gboolean active = + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + gint now; + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) { + now = + pluma_file_browser_store_get_filter_mode + (PLUMA_FILE_BROWSER_STORE (model)); + + if (active) + now &= ~mode; + else + now |= mode; + + pluma_file_browser_store_set_filter_mode + (PLUMA_FILE_BROWSER_STORE (model), now); + } +} + +static void +set_filter_pattern_real (PlumaFileBrowserWidget * obj, + gchar const * pattern, + gboolean update_entry) +{ + GtkTreeModel *model; + + 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 == NULL) + return; + + if (pattern != NULL && obj->priv->filter_pattern_str != NULL && + strcmp (pattern, obj->priv->filter_pattern_str) == 0) + return; + + /* Free the old pattern */ + g_free (obj->priv->filter_pattern_str); + 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) { + pluma_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 = + pluma_file_browser_widget_add_filter (obj, + filter_glob, + NULL, + NULL); + } + + if (update_entry) { + if (obj->priv->filter_pattern_str == NULL) + gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), + ""); + else { + gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), + obj->priv->filter_pattern_str); + + gtk_expander_set_expanded (GTK_EXPANDER (obj->priv->filter_expander), + TRUE); + } + } + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + pluma_file_browser_store_refilter (PLUMA_FILE_BROWSER_STORE + (model)); + + g_object_notify (G_OBJECT (obj), "filter-pattern"); +} + + +/* Public */ + +GtkWidget * +pluma_file_browser_widget_new (const gchar *data_dir) +{ + PlumaFileBrowserWidget *obj = + g_object_new (PLUMA_TYPE_FILE_BROWSER_WIDGET, NULL); + + create_toolbar (obj, data_dir); + create_combo (obj); + create_tree (obj); + create_filter (obj); + + pluma_file_browser_widget_show_bookmarks (obj); + + return GTK_WIDGET (obj); +} + +void +pluma_file_browser_widget_show_bookmarks (PlumaFileBrowserWidget * obj) +{ + /* Select bookmarks in the combo box */ + g_signal_handlers_block_by_func (obj->priv->combo, + on_combo_changed, obj); + combo_set_active_by_id (obj, BOOKMARKS_ID); + g_signal_handlers_unblock_by_func (obj->priv->combo, + on_combo_changed, obj); + + check_current_item (obj, FALSE); + + pluma_file_browser_view_set_model (obj->priv->treeview, + GTK_TREE_MODEL (obj->priv-> + bookmarks_store)); +} + +static void +show_files_real (PlumaFileBrowserWidget *obj, + gboolean do_root_changed) +{ + pluma_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 +pluma_file_browser_widget_show_files (PlumaFileBrowserWidget * obj) +{ + show_files_real (obj, TRUE); +} + +void +pluma_file_browser_widget_set_root_and_virtual_root (PlumaFileBrowserWidget *obj, + gchar const *root, + gchar const *virtual_root) +{ + PlumaFileBrowserStoreResult result; + + if (!virtual_root) + result = + pluma_file_browser_store_set_root_and_virtual_root + (obj->priv->file_store, root, root); + else + result = + pluma_file_browser_store_set_root_and_virtual_root + (obj->priv->file_store, root, virtual_root); + + if (result == PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE) + show_files_real (obj, TRUE); +} + +void +pluma_file_browser_widget_set_root (PlumaFileBrowserWidget * obj, + gchar const *root, + gboolean virtual_root) +{ + GFile *file; + GFile *parent; + gchar *str; + + if (!virtual_root) { + pluma_file_browser_widget_set_root_and_virtual_root (obj, + root, + NULL); + return; + } + + if (!root) + return; + + file = g_file_new_for_uri (root); + parent = get_topmost_file (file); + str = g_file_get_uri (parent); + + pluma_file_browser_widget_set_root_and_virtual_root + (obj, str, root); + + g_free (str); + + g_object_unref (file); + g_object_unref (parent); +} + +PlumaFileBrowserStore * +pluma_file_browser_widget_get_browser_store (PlumaFileBrowserWidget * obj) +{ + return obj->priv->file_store; +} + +PlumaFileBookmarksStore * +pluma_file_browser_widget_get_bookmarks_store (PlumaFileBrowserWidget * obj) +{ + return obj->priv->bookmarks_store; +} + +PlumaFileBrowserView * +pluma_file_browser_widget_get_browser_view (PlumaFileBrowserWidget * obj) +{ + return obj->priv->treeview; +} + +GtkUIManager * +pluma_file_browser_widget_get_ui_manager (PlumaFileBrowserWidget * obj) +{ + return obj->priv->manager; +} + +GtkWidget * +pluma_file_browser_widget_get_filter_entry (PlumaFileBrowserWidget * obj) +{ + return obj->priv->filter_entry; +} + +gulong +pluma_file_browser_widget_add_filter (PlumaFileBrowserWidget * obj, + PlumaFileBrowserWidgetFilterFunc func, + gpointer user_data, + GDestroyNotify notify) +{ + FilterFunc *f; + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + f = filter_func_new (obj, func, user_data, notify); + obj->priv->filter_funcs = + g_slist_append (obj->priv->filter_funcs, f); + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + pluma_file_browser_store_refilter (PLUMA_FILE_BROWSER_STORE + (model)); + + return f->id; +} + +void +pluma_file_browser_widget_remove_filter (PlumaFileBrowserWidget * obj, + gulong id) +{ + GSList *item; + FilterFunc *func; + + for (item = obj->priv->filter_funcs; item; item = item->next) + { + 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); + g_free (func); + break; + } + } +} + +void +pluma_file_browser_widget_set_filter_pattern (PlumaFileBrowserWidget * obj, + gchar const *pattern) +{ + set_filter_pattern_real (obj, pattern, TRUE); +} + +gboolean +pluma_file_browser_widget_get_selected_directory (PlumaFileBrowserWidget * obj, + GtkTreeIter * iter) +{ + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + GtkTreeIter parent; + guint flags; + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return FALSE; + + if (!pluma_file_browser_widget_get_first_selected (obj, iter)) { + if (!pluma_file_browser_store_get_iter_virtual_root + (PLUMA_FILE_BROWSER_STORE (model), iter)) + return FALSE; + } + + gtk_tree_model_get (model, iter, + PLUMA_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; +} + +static guint +pluma_file_browser_widget_get_num_selected_files_or_directories (PlumaFileBrowserWidget *obj, + guint *files, + guint *dirs) +{ + GList *rows, *row; + GtkTreePath *path; + GtkTreeIter iter; + PlumaFileBrowserStoreFlag flags; + guint result = 0; + GtkTreeSelection *selection; + GtkTreeModel *model; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) + return 0; + + rows = gtk_tree_selection_get_selected_rows (selection, &model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + /* Get iter from path */ + if (!gtk_tree_model_get_iter (model, &iter, path)) + continue; + + gtk_tree_model_get (model, &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!FILE_IS_DUMMY (flags)) { + if (!FILE_IS_DIR (flags)) + ++(*files); + else + ++(*dirs); + + ++result; + } + } + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return result; +} + +typedef struct +{ + PlumaFileBrowserWidget *widget; + GCancellable *cancellable; +} AsyncData; + +static AsyncData * +async_data_new (PlumaFileBrowserWidget *widget) +{ + AsyncData *ret; + + ret = g_new (AsyncData, 1); + 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_free (async); +} + +static void +set_busy (PlumaFileBrowserWidget *obj, gboolean busy) +{ + GdkCursor *cursor; + GdkWindow *window; + + window = gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview)); + + if (!GDK_IS_WINDOW (window)) + return; + + if (busy) + { + cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (window, cursor); + gdk_cursor_unref (cursor); + } + else + { + gdk_window_set_cursor (window, NULL); + } +} + +static void try_mount_volume (PlumaFileBrowserWidget *widget, GVolume *volume); + +static void +activate_mount (PlumaFileBrowserWidget *widget, + GVolume *volume, + GMount *mount) +{ + GFile *root; + gchar *uri; + + if (!mount) + { + gchar *message; + gchar *name; + + name = g_volume_get_name (volume); + message = g_strdup_printf (_("No mount object for mounted volume: %s"), name); + + g_signal_emit (widget, + signals[ERROR], + 0, + PLUMA_FILE_BROWSER_ERROR_SET_ROOT, + message); + + g_free (name); + g_free (message); + return; + } + + root = g_mount_get_root (mount); + uri = g_file_get_uri (root); + + pluma_file_browser_widget_set_root (widget, uri, FALSE); + + g_free (uri); + g_object_unref (root); +} + +static void +try_activate_drive (PlumaFileBrowserWidget *widget, + GDrive *drive) +{ + GList *volumes; + GVolume *volume; + GMount *mount; + + volumes = g_drive_get_volumes (drive); + + volume = G_VOLUME (volumes->data); + 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_foreach (volumes, (GFunc)g_object_unref, NULL); + g_list_free (volumes); +} + +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 *message; + gchar *name; + + name = g_drive_get_name (drive); + message = g_strdup_printf (_("Could not open media: %s"), name); + + g_signal_emit (async->widget, + signals[ERROR], + 0, + PLUMA_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; + + mount = g_volume_get_mount (volume); + activate_mount (async->widget, volume, mount); + + if (mount) + g_object_unref (mount); + } + else + { + gchar *message; + gchar *name; + + name = g_volume_get_name (volume); + message = g_strdup_printf (_("Could not mount volume: %s"), name); + + g_signal_emit (async->widget, + signals[ERROR], + 0, + PLUMA_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 (PlumaFileBrowserWidget *obj, + GtkTreeIter *iter) +{ + GDrive *drive; + AsyncData *async; + + gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->bookmarks_store), iter, + PLUMA_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 (PlumaFileBrowserWidget *widget, + GVolume *volume) +{ + GMountOperation *operation; + AsyncData *async; + + operation = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)))); + 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 (PlumaFileBrowserWidget *obj, + GtkTreeIter *iter) +{ + GVolume *volume; + + gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->bookmarks_store), iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + &volume, -1); + + /* see if we can mount the volume */ + try_mount_volume (obj, volume); + g_object_unref (volume); +} + +void +pluma_file_browser_widget_refresh (PlumaFileBrowserWidget *obj) +{ + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + pluma_file_browser_store_refresh (PLUMA_FILE_BROWSER_STORE + (model)); + else if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) { + g_hash_table_ref (obj->priv->bookmarks_hash); + g_hash_table_destroy (obj->priv->bookmarks_hash); + + pluma_file_bookmarks_store_refresh + (PLUMA_FILE_BOOKMARKS_STORE (model)); + } +} + +void +pluma_file_browser_widget_history_back (PlumaFileBrowserWidget *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 +pluma_file_browser_widget_history_forward (PlumaFileBrowserWidget *obj) +{ + if (obj->priv->locations) + jump_to_location (obj, obj->priv->current_location->prev, + FALSE); +} + +static void +bookmark_open (PlumaFileBrowserWidget *obj, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gchar *uri; + gint flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + &flags, -1); + + if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_DRIVE) + { + /* handle a drive node */ + pluma_file_browser_store_cancel_mount_operation (obj->priv->file_store); + activate_drive (obj, iter); + return; + } + else if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_VOLUME) + { + /* handle a volume node */ + pluma_file_browser_store_cancel_mount_operation (obj->priv->file_store); + activate_volume (obj, iter); + return; + } + + uri = + pluma_file_bookmarks_store_get_uri + (PLUMA_FILE_BOOKMARKS_STORE (model), iter); + + if (uri) { + /* 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 & PLUMA_FILE_BOOKMARKS_STORE_IS_MOUNT) || + (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK)) { + pluma_file_browser_widget_set_root (obj, + uri, + FALSE); + } else { + pluma_file_browser_widget_set_root (obj, + uri, + TRUE); + } + } else { + g_warning ("No uri!"); + } + + g_free (uri); +} + +static void +file_open (PlumaFileBrowserWidget *obj, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gchar *uri; + gint flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + -1); + + if (!FILE_IS_DIR (flags) && !FILE_IS_DUMMY (flags)) { + g_signal_emit (obj, signals[URI_ACTIVATED], 0, uri); + } + + g_free (uri); +} + +static gboolean +directory_open (PlumaFileBrowserWidget *obj, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gboolean result = FALSE; + GError *error = NULL; + gchar *uri = NULL; + PlumaFileBrowserStoreFlag flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + -1); + + if (FILE_IS_DIR (flags)) { + result = TRUE; + + if (!gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (obj)), uri, GDK_CURRENT_TIME, &error)) { + g_signal_emit (obj, signals[ERROR], 0, + PLUMA_FILE_BROWSER_ERROR_OPEN_DIRECTORY, + error->message); + + g_error_free (error); + error = NULL; + } + } + + g_free (uri); + + return result; +} + +static void +on_bookmark_activated (PlumaFileBrowserView *tree_view, + GtkTreeIter *iter, + PlumaFileBrowserWidget *obj) +{ + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + + bookmark_open (obj, model, iter); +} + +static void +on_file_activated (PlumaFileBrowserView *tree_view, + GtkTreeIter *iter, + PlumaFileBrowserWidget *obj) +{ + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + + file_open (obj, model, iter); +} + +static gboolean +virtual_root_is_root (PlumaFileBrowserWidget * obj, + PlumaFileBrowserStore * model) +{ + GtkTreeIter root; + GtkTreeIter virtual_root; + + if (!pluma_file_browser_store_get_iter_root (model, &root)) + return TRUE; + + if (!pluma_file_browser_store_get_iter_virtual_root (model, &virtual_root)) + return TRUE; + + return pluma_file_browser_store_iter_equal (model, &root, &virtual_root); +} + +static void +on_virtual_root_changed (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + gchar *uri; + gchar *root_uri; + GtkTreeIter root; + GtkAction *action; + Location *loc; + GdkPixbuf *pixbuf; + + 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 (pluma_file_browser_store_get_iter_virtual_root (model, &iter)) { + gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, -1); + + if (pluma_file_browser_store_get_iter_root (model, &root)) { + if (!obj->priv->changing_location) { + /* Remove all items from obj->priv->current_location on */ + if (obj->priv->current_location) + clear_next_locations (obj); + + root_uri = + pluma_file_browser_store_get_root + (model); + + loc = g_new (Location, 1); + loc->root = g_file_new_for_uri (root_uri); + loc->virtual_root = g_file_new_for_uri (uri); + g_free (root_uri); + + 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); + + gtk_tree_model_get (GTK_TREE_MODEL (model), + &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_ICON, + &pixbuf, -1); + + obj->priv->current_location = + obj->priv->locations; + obj->priv->current_location_menu_item = + create_goto_menu_item (obj, + obj->priv-> + current_location, + pixbuf); + + g_object_ref_sink (obj->priv-> + current_location_menu_item); + + if (pixbuf) + g_object_unref (pixbuf); + + } + + action = + gtk_action_group_get_action (obj->priv-> + action_group, + "DirectoryUp"); + gtk_action_set_sensitive (action, + !virtual_root_is_root (obj, model)); + + action = + gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryPrevious"); + gtk_action_set_sensitive (action, + obj->priv-> + current_location != NULL + && obj->priv-> + current_location->next != + NULL); + + action = + gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryNext"); + gtk_action_set_sensitive (action, + obj->priv-> + current_location != NULL + && obj->priv-> + current_location->prev != + NULL); + } + + check_current_item (obj, TRUE); + g_free (uri); + } else { + g_message ("NO!"); + } +} + +static void +on_model_set (GObject * gobject, GParamSpec * arg1, + PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (gobject)); + + clear_signals (obj); + + if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) { + clear_next_locations (obj); + + /* Add the current location to the back menu */ + if (obj->priv->current_location) { + GtkAction *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 = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryPrevious"); + gtk_action_set_sensitive (action, TRUE); + } + + gtk_widget_set_sensitive (obj->priv->filter_expander, FALSE); + + add_signal (obj, gobject, + g_signal_connect (gobject, "bookmark-activated", + G_CALLBACK + (on_bookmark_activated), obj)); + } else if (PLUMA_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_set_sensitive (obj->priv->filter_expander, TRUE); + } + + update_sensitivity (obj); +} + +static void +on_file_store_error (PlumaFileBrowserStore * store, guint code, + gchar * message, PlumaFileBrowserWidget * obj) +{ + g_signal_emit (obj, signals[ERROR], 0, code, message); +} + +static void +on_treeview_error (PlumaFileBrowserView * tree_view, guint code, + gchar * message, PlumaFileBrowserWidget * obj) +{ + g_signal_emit (obj, signals[ERROR], 0, code, message); +} + +static void +on_combo_changed (GtkComboBox * combo, PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + guint id; + gchar * uri; + GFile * file; + + if (!gtk_combo_box_get_active_iter (combo, &iter)) + return; + + gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->combo_model), &iter, + COLUMN_ID, &id, -1); + + switch (id) { + case BOOKMARKS_ID: + pluma_file_browser_widget_show_bookmarks (obj); + break; + + case PATH_ID: + gtk_tree_model_get (GTK_TREE_MODEL + (obj->priv->combo_model), &iter, + COLUMN_FILE, &file, -1); + + uri = g_file_get_uri (file); + pluma_file_browser_store_set_virtual_root_from_string + (obj->priv->file_store, uri); + + g_free (uri); + g_object_unref (file); + break; + } +} + +static gboolean +on_treeview_popup_menu (PlumaFileBrowserView * treeview, + PlumaFileBrowserWidget * obj) +{ + return popup_menu (obj, NULL, gtk_tree_view_get_model (GTK_TREE_VIEW (treeview))); +} + +static gboolean +on_treeview_button_press_event (PlumaFileBrowserView * treeview, + GdkEventButton * event, + PlumaFileBrowserWidget * obj) +{ + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + return popup_menu (obj, event, + gtk_tree_view_get_model (GTK_TREE_VIEW (treeview))); + } + + return FALSE; +} + +static gboolean +do_change_directory (PlumaFileBrowserWidget * obj, + GdkEventKey * event) +{ + GtkAction * action = NULL; + + if ((event->state & + (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK & ~GDK_MOD1_MASK)) == + event->state && event->keyval == GDK_BackSpace) + action = gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryPrevious"); + else if (!((event->state & GDK_MOD1_MASK) && + (event->state & (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK)) == event->state)) + return FALSE; + + switch (event->keyval) { + case GDK_Left: + action = gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryPrevious"); + break; + case GDK_Right: + action = gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryNext"); + break; + case GDK_Up: + action = gtk_action_group_get_action (obj->priv-> + action_group, + "DirectoryUp"); + break; + default: + break; + } + + if (action != NULL) { + gtk_action_activate (action); + return TRUE; + } + + return FALSE; +} + +static gboolean +on_treeview_key_press_event (PlumaFileBrowserView * treeview, + GdkEventKey * event, + PlumaFileBrowserWidget * obj) +{ + guint modifiers; + + if (do_change_directory (obj, event)) + return TRUE; + + if (!PLUMA_IS_FILE_BROWSER_STORE + (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)))) + return FALSE; + + modifiers = gtk_accelerator_get_default_mod_mask (); + + if (event->keyval == GDK_Delete + || event->keyval == GDK_KP_Delete) { + + if ((event->state & modifiers) == GDK_SHIFT_MASK) { + if (obj->priv->enable_delete) { + delete_selected_files (obj, FALSE); + return TRUE; + } + } else if ((event->state & modifiers) == 0) { + delete_selected_files (obj, TRUE); + return TRUE; + } + } + + if ((event->keyval == GDK_F2) + && (event->state & modifiers) == 0) { + rename_selected_file (obj); + + return TRUE; + } + + return FALSE; +} + +static void +on_selection_changed (GtkTreeSelection * selection, + PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + guint selected = 0; + guint files = 0; + guint dirs = 0; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + { + selected = pluma_file_browser_widget_get_num_selected_files_or_directories (obj, + &files, + &dirs); + } + + gtk_action_group_set_sensitive (obj->priv->action_group_selection, + selected > 0); + gtk_action_group_set_sensitive (obj->priv->action_group_file_selection, + (selected > 0) && (selected == files)); + gtk_action_group_set_sensitive (obj->priv->action_group_single_selection, + selected == 1); + gtk_action_group_set_sensitive (obj->priv->action_group_single_most_selection, + selected <= 1); +} + +static gboolean +on_entry_filter_activate (PlumaFileBrowserWidget * obj) +{ + gchar const *text; + + 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, + PlumaFileBrowserWidget * obj) +{ + GList *location; + + 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, + PlumaFileBrowserWidget *obj) +{ + add_bookmark_hash (obj, iter); +} + +static void +on_bookmarks_row_deleted (GtkTreeModel * model, + GtkTreePath * path, + PlumaFileBrowserWidget *obj) +{ + GtkTreeIter iter; + gchar * uri; + GFile * file; + + if (!gtk_tree_model_get_iter (model, &iter, path)) + return; + + uri = pluma_file_bookmarks_store_get_uri (obj->priv->bookmarks_store, &iter); + + if (!uri) + return; + + file = g_file_new_for_uri (uri); + g_hash_table_remove (obj->priv->bookmarks_hash, file); + + g_object_unref (file); + g_free (uri); +} + +static void +on_filter_mode_changed (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaFileBrowserWidget * obj) +{ + gint mode; + GtkToggleAction * action; + gboolean active; + + mode = pluma_file_browser_store_get_filter_mode (model); + + action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (obj->priv->action_group, + "FilterHidden")); + active = !(mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN); + + if (active != gtk_toggle_action_get_active (action)) + gtk_toggle_action_set_active (action, active); + + action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (obj->priv->action_group, + "FilterBinary")); + active = !(mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); + + if (active != gtk_toggle_action_get_active (action)) + gtk_toggle_action_set_active (action, active); +} + +static void +on_action_directory_next (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + pluma_file_browser_widget_history_forward (obj); +} + +static void +on_action_directory_previous (GtkAction * action, + PlumaFileBrowserWidget * obj) +{ + pluma_file_browser_widget_history_back (obj); +} + +static void +on_action_directory_up (GtkAction * action, + PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + pluma_file_browser_store_set_virtual_root_up (PLUMA_FILE_BROWSER_STORE (model)); +} + +static void +on_action_directory_new (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeIter parent; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + if (!pluma_file_browser_widget_get_selected_directory (obj, &parent)) + return; + + if (pluma_file_browser_store_new_directory + (PLUMA_FILE_BROWSER_STORE (model), &parent, &iter)) { + pluma_file_browser_view_start_rename (obj->priv->treeview, + &iter); + } +} + +static void +on_action_file_open (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GList *rows; + GList *row; + GtkTreeIter iter; + GtkTreePath *path; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + rows = gtk_tree_selection_get_selected_rows (selection, &model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + if (gtk_tree_model_get_iter (model, &iter, path)) + file_open (obj, model, &iter); + + gtk_tree_path_free (path); + } + + g_list_free (rows); +} + +static void +on_action_file_new (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeIter parent; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + if (!pluma_file_browser_widget_get_selected_directory (obj, &parent)) + return; + + if (pluma_file_browser_store_new_file + (PLUMA_FILE_BROWSER_STORE (model), &parent, &iter)) { + pluma_file_browser_view_start_rename (obj->priv->treeview, + &iter); + } +} + +static void +on_action_file_rename (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + rename_selected_file (obj); +} + +static void +on_action_file_delete (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + delete_selected_files (obj, FALSE); +} + +static void +on_action_file_move_to_trash (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + delete_selected_files (obj, TRUE); +} + +static void +on_action_directory_refresh (GtkAction * action, + PlumaFileBrowserWidget * obj) +{ + pluma_file_browser_widget_refresh (obj); +} + +static void +on_action_directory_open (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GList *rows; + GList *row; + gboolean directory_opened = FALSE; + GtkTreeIter iter; + GtkTreePath *path; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + rows = gtk_tree_selection_get_selected_rows (selection, &model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + if (gtk_tree_model_get_iter (model, &iter, path)) + directory_opened |= directory_open (obj, model, &iter); + + gtk_tree_path_free (path); + } + + if (!directory_opened) { + if (pluma_file_browser_widget_get_selected_directory (obj, &iter)) + directory_open (obj, model, &iter); + } + + g_list_free (rows); +} + +static void +on_action_filter_hidden (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + update_filter_mode (obj, + action, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN); +} + +static void +on_action_filter_binary (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + update_filter_mode (obj, + action, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); +} + +static void +on_action_bookmark_open (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BOOKMARKS_STORE (model)) + return; + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + bookmark_open (obj, model, &iter); +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-widget.h b/plugins/filebrowser/pluma-file-browser-widget.h new file mode 100755 index 00000000..4d7f43ef --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-widget.h @@ -0,0 +1,121 @@ +/* + * pluma-file-browser-widget.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_WIDGET_H__ +#define __PLUMA_FILE_BROWSER_WIDGET_H__ + +#include +#include "pluma-file-browser-store.h" +#include "pluma-file-bookmarks-store.h" +#include "pluma-file-browser-view.h" + +G_BEGIN_DECLS +#define PLUMA_TYPE_FILE_BROWSER_WIDGET (pluma_file_browser_widget_get_type ()) +#define PLUMA_FILE_BROWSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_WIDGET, PlumaFileBrowserWidget)) +#define PLUMA_FILE_BROWSER_WIDGET_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_WIDGET, PlumaFileBrowserWidget const)) +#define PLUMA_FILE_BROWSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_FILE_BROWSER_WIDGET, PlumaFileBrowserWidgetClass)) +#define PLUMA_IS_FILE_BROWSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_FILE_BROWSER_WIDGET)) +#define PLUMA_IS_FILE_BROWSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_FILE_BROWSER_WIDGET)) +#define PLUMA_FILE_BROWSER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_FILE_BROWSER_WIDGET, PlumaFileBrowserWidgetClass)) + +typedef struct _PlumaFileBrowserWidget PlumaFileBrowserWidget; +typedef struct _PlumaFileBrowserWidgetClass PlumaFileBrowserWidgetClass; +typedef struct _PlumaFileBrowserWidgetPrivate PlumaFileBrowserWidgetPrivate; + +typedef +gboolean (*PlumaFileBrowserWidgetFilterFunc) (PlumaFileBrowserWidget * obj, + PlumaFileBrowserStore * + model, GtkTreeIter * iter, + gpointer user_data); + +struct _PlumaFileBrowserWidget +{ + GtkVBox parent; + + PlumaFileBrowserWidgetPrivate *priv; +}; + +struct _PlumaFileBrowserWidgetClass +{ + GtkVBoxClass parent_class; + + /* Signals */ + void (*uri_activated) (PlumaFileBrowserWidget * widget, + gchar const *uri); + void (*error) (PlumaFileBrowserWidget * widget, + guint code, + gchar const *message); + gboolean (*confirm_delete) (PlumaFileBrowserWidget * widget, + PlumaFileBrowserStore * model, + GList *list); + gboolean (*confirm_no_trash) (PlumaFileBrowserWidget * widget, + GList *list); +}; + +GType pluma_file_browser_widget_get_type (void) G_GNUC_CONST; +GType pluma_file_browser_widget_register_type (GTypeModule * module); + +GtkWidget *pluma_file_browser_widget_new (const gchar *data_dir); + +void pluma_file_browser_widget_show_bookmarks (PlumaFileBrowserWidget * obj); +void pluma_file_browser_widget_show_files (PlumaFileBrowserWidget * obj); + +void pluma_file_browser_widget_set_root (PlumaFileBrowserWidget * obj, + gchar const *root, + gboolean virtual_root); +void +pluma_file_browser_widget_set_root_and_virtual_root (PlumaFileBrowserWidget * obj, + gchar const *root, + gchar const *virtual_root); + +gboolean +pluma_file_browser_widget_get_selected_directory (PlumaFileBrowserWidget * obj, + GtkTreeIter * iter); + +PlumaFileBrowserStore * +pluma_file_browser_widget_get_browser_store (PlumaFileBrowserWidget * obj); +PlumaFileBookmarksStore * +pluma_file_browser_widget_get_bookmarks_store (PlumaFileBrowserWidget * obj); +PlumaFileBrowserView * +pluma_file_browser_widget_get_browser_view (PlumaFileBrowserWidget * obj); +GtkWidget * +pluma_file_browser_widget_get_filter_entry (PlumaFileBrowserWidget * obj); + +GtkUIManager * +pluma_file_browser_widget_get_ui_manager (PlumaFileBrowserWidget * obj); + +gulong pluma_file_browser_widget_add_filter (PlumaFileBrowserWidget * obj, + PlumaFileBrowserWidgetFilterFunc func, + gpointer user_data, + GDestroyNotify notify); +void pluma_file_browser_widget_remove_filter (PlumaFileBrowserWidget * obj, + gulong id); +void pluma_file_browser_widget_set_filter_pattern (PlumaFileBrowserWidget * obj, + gchar const *pattern); + +void pluma_file_browser_widget_refresh (PlumaFileBrowserWidget * obj); +void pluma_file_browser_widget_history_back (PlumaFileBrowserWidget * obj); +void pluma_file_browser_widget_history_forward (PlumaFileBrowserWidget * obj); + +G_END_DECLS +#endif /* __PLUMA_FILE_BROWSER_WIDGET_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser.schemas.in b/plugins/filebrowser/pluma-file-browser.schemas.in new file mode 100755 index 00000000..0ae807d6 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser.schemas.in @@ -0,0 +1,97 @@ + + + + /schemas/apps/pluma-2/plugins/filebrowser/on_load/tree_view + /apps/pluma-2/plugins/filebrowser/on_load/tree_view + pluma + bool + TRUE + + Open With Tree View + Open the tree view when the file browser plugin gets loaded instead of the bookmarks view + + + + + /schemas/apps/pluma-2/plugins/filebrowser/on_load/root + /apps/pluma-2/plugins/filebrowser/on_load/root + pluma + string + + + File Browser Root Directory + The file browser root directory to use when loading the file + browser plugin and onload/tree_view is TRUE. + + + + + /schemas/apps/pluma-2/plugins/filebrowser/on_load/virtual_root + /apps/pluma-2/plugins/filebrowser/on_load/virtual_root + pluma + string + + + File Browser Virtual Root Directory + 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. + + + + + /schemas/apps/pluma-2/plugins/filebrowser/on_load/enable_remote + /apps/pluma-2/plugins/filebrowser/on_load/enable_remote + pluma + bool + FALSE + + Enable Restore of Remote Locations + Sets whether to enable restoring of remote locations. + + + + + /schemas/apps/pluma-2/plugins/filebrowser/open_at_first_doc + /apps/pluma-2/plugins/filebrowser/open_at_first_doc + pluma + bool + TRUE + + Set Location to First Document + 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 Caja, etc.) + + + + + /schemas/apps/pluma-2/plugins/filebrowser/filter_mode + /apps/pluma-2/plugins/filebrowser/filter_mode + pluma + string + hidden_and_binary + + File Browser Filter Mode + This value determines what files get filtered from the file + browser. Valid values are: none (filter nothing), + hidden (filter hidden files), binary (filter binary files) and + hidden_and_binary (filter both hidden and binary files). + + + + + /schemas/apps/pluma-2/plugins/filebrowser/filter_pattern + /apps/pluma-2/plugins/filebrowser/filter_pattern + pluma + string + + + File Browser Filter Pattern + The filter pattern to filter the file browser with. This filter + works on top of the filter_mode. + + + + -- cgit v1.2.1