summaryrefslogtreecommitdiff
path: root/src/file-manager/fm-tree-view.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/file-manager/fm-tree-view.c')
-rw-r--r--src/file-manager/fm-tree-view.c1814
1 files changed, 1814 insertions, 0 deletions
diff --git a/src/file-manager/fm-tree-view.c b/src/file-manager/fm-tree-view.c
new file mode 100644
index 00000000..2a6cbd60
--- /dev/null
+++ b/src/file-manager/fm-tree-view.c
@@ -0,0 +1,1814 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/*
+ * Copyright (C) 2000, 2001 Eazel, Inc
+ * Copyright (C) 2002 Anders Carlsson
+ * Copyright (C) 2002 Darin Adler
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Maciej Stachowiak <[email protected]>
+ * Anders Carlsson <[email protected]>
+ * Darin Adler <[email protected]>
+ */
+
+/* fm-tree-view.c - tree sidebar panel
+ */
+
+#include <config.h>
+#include "fm-tree-view.h"
+
+#include "fm-tree-model.h"
+#include "fm-properties-window.h"
+#include <string.h>
+#include <eel/eel-alert-dialog.h>
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gtk-extensions.h>
+#include <eel/eel-preferences.h>
+#include <eel/eel-stock-dialogs.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <libcaja-private/caja-clipboard.h>
+#include <libcaja-private/caja-clipboard-monitor.h>
+#include <libcaja-private/caja-desktop-icon-file.h>
+#include <libcaja-private/caja-debug-log.h>
+#include <libcaja-private/caja-file-attributes.h>
+#include <libcaja-private/caja-file-operations.h>
+#include <libcaja-private/caja-file-utilities.h>
+#include <libcaja-private/caja-global-preferences.h>
+#include <libcaja-private/caja-icon-names.h>
+#include <libcaja-private/caja-program-choosing.h>
+#include <libcaja-private/caja-tree-view-drag-dest.h>
+#include <libcaja-private/caja-cell-renderer-pixbuf-emblem.h>
+#include <libcaja-private/caja-sidebar-provider.h>
+#include <libcaja-private/caja-module.h>
+#include <libcaja-private/caja-window-info.h>
+#include <libcaja-private/caja-window-slot-info.h>
+
+typedef struct
+{
+ GObject parent;
+} FMTreeViewProvider;
+
+typedef struct
+{
+ GObjectClass parent;
+} FMTreeViewProviderClass;
+
+
+struct FMTreeViewDetails
+{
+ CajaWindowInfo *window;
+ GtkTreeView *tree_widget;
+ GtkTreeModelSort *sort_model;
+ FMTreeModel *child_model;
+
+ GVolumeMonitor *volume_monitor;
+
+ CajaFile *activation_file;
+ CajaWindowOpenFlags activation_flags;
+
+ CajaTreeViewDragDest *drag_dest;
+
+ char *selection_location;
+ gboolean selecting;
+
+ guint show_selection_idle_id;
+ gulong clipboard_handler_id;
+
+ GtkWidget *popup;
+ GtkWidget *popup_open;
+ GtkWidget *popup_open_in_new_window;
+ GtkWidget *popup_create_folder;
+ GtkWidget *popup_cut;
+ GtkWidget *popup_copy;
+ GtkWidget *popup_paste;
+ GtkWidget *popup_rename;
+ GtkWidget *popup_trash;
+ GtkWidget *popup_delete;
+ GtkWidget *popup_properties;
+ GtkWidget *popup_unmount_separator;
+ GtkWidget *popup_unmount;
+ GtkWidget *popup_eject;
+ CajaFile *popup_file;
+ guint popup_file_idle_handler;
+
+ guint selection_changed_timer;
+};
+
+typedef struct
+{
+ GList *uris;
+ FMTreeView *view;
+} PrependURIParameters;
+
+static GdkAtom copied_files_atom;
+static gboolean show_delete_command_auto_value;
+
+static void fm_tree_view_iface_init (CajaSidebarIface *iface);
+static void sidebar_provider_iface_init (CajaSidebarProviderIface *iface);
+static void fm_tree_view_activate_file (FMTreeView *view,
+ CajaFile *file,
+ CajaWindowOpenFlags flags);
+static GType fm_tree_view_provider_get_type (void);
+
+static void create_popup_menu (FMTreeView *view);
+
+G_DEFINE_TYPE_WITH_CODE (FMTreeView, fm_tree_view, GTK_TYPE_SCROLLED_WINDOW,
+ G_IMPLEMENT_INTERFACE (CAJA_TYPE_SIDEBAR,
+ fm_tree_view_iface_init));
+#define parent_class fm_tree_view_parent_class
+
+G_DEFINE_TYPE_WITH_CODE (FMTreeViewProvider, fm_tree_view_provider, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (CAJA_TYPE_SIDEBAR_PROVIDER,
+ sidebar_provider_iface_init));
+
+static void
+notify_clipboard_info (CajaClipboardMonitor *monitor,
+ CajaClipboardInfo *info,
+ FMTreeView *view)
+{
+ if (info != NULL && info->cut)
+ {
+ fm_tree_model_set_highlight_for_files (view->details->child_model, info->files);
+ }
+ else
+ {
+ fm_tree_model_set_highlight_for_files (view->details->child_model, NULL);
+ }
+}
+
+
+static gboolean
+show_iter_for_file (FMTreeView *view, CajaFile *file, GtkTreeIter *iter)
+{
+ GtkTreeModel *model;
+ CajaFile *parent_file;
+ GtkTreeIter parent_iter;
+ GtkTreePath *path, *sort_path;
+ GtkTreeIter cur_iter;
+
+ if (view->details->child_model == NULL)
+ {
+ return FALSE;
+ }
+ model = GTK_TREE_MODEL (view->details->child_model);
+
+ /* check if file is visible in the same root as the currently selected folder is */
+ gtk_tree_view_get_cursor (view->details->tree_widget, &path, NULL);
+ if (path != NULL)
+ {
+ if (gtk_tree_model_get_iter (model, &cur_iter, path) &&
+ fm_tree_model_file_get_iter (view->details->child_model, iter,
+ file, &cur_iter))
+ {
+ gtk_tree_path_free (path);
+ return TRUE;
+ }
+ gtk_tree_path_free (path);
+ }
+ /* check if file is visible at all */
+ if (fm_tree_model_file_get_iter (view->details->child_model,
+ iter, file, NULL))
+ {
+ return TRUE;
+ }
+
+ parent_file = caja_file_get_parent (file);
+
+ if (parent_file == NULL)
+ {
+ return FALSE;
+ }
+ if (!show_iter_for_file (view, parent_file, &parent_iter))
+ {
+ caja_file_unref (parent_file);
+ return FALSE;
+ }
+ caja_file_unref (parent_file);
+
+ if (parent_iter.user_data == NULL || parent_iter.stamp == 0)
+ {
+ return FALSE;
+ }
+ path = gtk_tree_model_get_path (model, &parent_iter);
+ sort_path = gtk_tree_model_sort_convert_child_path_to_path
+ (view->details->sort_model, path);
+ gtk_tree_path_free (path);
+ gtk_tree_view_expand_row (view->details->tree_widget, sort_path, FALSE);
+ gtk_tree_path_free (sort_path);
+
+ return FALSE;
+}
+
+static void
+refresh_highlight (FMTreeView *view)
+{
+ CajaClipboardMonitor *monitor;
+ CajaClipboardInfo *info;
+
+ monitor = caja_clipboard_monitor_get ();
+ info = caja_clipboard_monitor_get_clipboard_info (monitor);
+
+ notify_clipboard_info (monitor, info, view);
+}
+
+static gboolean
+show_selection_idle_callback (gpointer callback_data)
+{
+ FMTreeView *view;
+ CajaFile *file, *old_file;
+ GtkTreeIter iter;
+ GtkTreePath *path, *sort_path;
+
+ view = FM_TREE_VIEW (callback_data);
+
+ view->details->show_selection_idle_id = 0;
+
+ file = caja_file_get_by_uri (view->details->selection_location);
+ if (file == NULL)
+ {
+ return FALSE;
+ }
+
+ if (!caja_file_is_directory (file))
+ {
+ old_file = file;
+ file = caja_file_get_parent (file);
+ caja_file_unref (old_file);
+ if (file == NULL)
+ {
+ return FALSE;
+ }
+ }
+
+ view->details->selecting = TRUE;
+ if (!show_iter_for_file (view, file, &iter))
+ {
+ caja_file_unref (file);
+ return FALSE;
+ }
+ view->details->selecting = FALSE;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->child_model), &iter);
+ sort_path = gtk_tree_model_sort_convert_child_path_to_path
+ (view->details->sort_model, path);
+ gtk_tree_path_free (path);
+ gtk_tree_view_set_cursor (view->details->tree_widget, sort_path, NULL, FALSE);
+ if (gtk_widget_get_realized (GTK_WIDGET (view->details->tree_widget)))
+ {
+ gtk_tree_view_scroll_to_cell (view->details->tree_widget, sort_path, NULL, FALSE, 0, 0);
+ }
+ gtk_tree_path_free (sort_path);
+
+ caja_file_unref (file);
+ refresh_highlight (view);
+
+ return FALSE;
+}
+
+static void
+schedule_show_selection (FMTreeView *view)
+{
+ if (view->details->show_selection_idle_id == 0)
+ {
+ view->details->show_selection_idle_id = g_idle_add (show_selection_idle_callback, view);
+ }
+}
+
+static void
+schedule_select_and_show_location (FMTreeView *view, char *location)
+{
+ if (view->details->selection_location != NULL)
+ {
+ g_free (view->details->selection_location);
+ }
+ view->details->selection_location = g_strdup (location);
+ schedule_show_selection (view);
+}
+
+static void
+row_loaded_callback (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ FMTreeView *view)
+{
+ CajaFile *file, *tmp_file, *selection_file;
+
+ if (view->details->selection_location == NULL
+ || !view->details->selecting
+ || iter->user_data == NULL || iter->stamp == 0)
+ {
+ return;
+ }
+
+ file = fm_tree_model_iter_get_file (view->details->child_model, iter);
+ if (file == NULL)
+ {
+ return;
+ }
+ if (!caja_file_is_directory (file))
+ {
+ caja_file_unref(file);
+ return;
+ }
+
+ /* if iter is ancestor of wanted selection_location then update selection */
+ selection_file = caja_file_get_by_uri (view->details->selection_location);
+ while (selection_file != NULL)
+ {
+ if (file == selection_file)
+ {
+ caja_file_unref (file);
+ caja_file_unref (selection_file);
+
+ schedule_show_selection (view);
+ return;
+ }
+ tmp_file = caja_file_get_parent (selection_file);
+ caja_file_unref (selection_file);
+ selection_file = tmp_file;
+ }
+ caja_file_unref (file);
+}
+
+static CajaFile *
+sort_model_iter_to_file (FMTreeView *view, GtkTreeIter *iter)
+{
+ GtkTreeIter child_iter;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (view->details->sort_model, &child_iter, iter);
+ return fm_tree_model_iter_get_file (view->details->child_model, &child_iter);
+}
+
+static CajaFile *
+sort_model_path_to_file (FMTreeView *view, GtkTreePath *path)
+{
+ GtkTreeIter iter;
+
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->sort_model), &iter, path))
+ {
+ return NULL;
+ }
+ return sort_model_iter_to_file (view, &iter);
+}
+
+static void
+got_activation_uri_callback (CajaFile *file, gpointer callback_data)
+{
+ char *uri, *file_uri;
+ FMTreeView *view;
+ GdkScreen *screen;
+ GFile *location;
+ CajaWindowSlotInfo *slot;
+ gboolean open_in_same_slot;
+
+ view = FM_TREE_VIEW (callback_data);
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (view->details->tree_widget));
+
+ g_assert (file == view->details->activation_file);
+
+ open_in_same_slot =
+ (view->details->activation_flags &
+ (CAJA_WINDOW_OPEN_FLAG_NEW_WINDOW |
+ CAJA_WINDOW_OPEN_FLAG_NEW_TAB)) == 0;
+
+ slot = caja_window_info_get_active_slot (view->details->window);
+
+ uri = caja_file_get_activation_uri (file);
+ if (caja_file_is_launcher (file))
+ {
+ file_uri = caja_file_get_uri (file);
+ caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
+ "tree view launch_desktop_file window=%p: %s",
+ view->details->window, file_uri);
+ caja_launch_desktop_file (screen, file_uri, NULL, NULL);
+ g_free (file_uri);
+ }
+ else if (uri != NULL
+ && caja_file_is_executable (file)
+ && caja_file_can_execute (file)
+ && !caja_file_is_directory (file))
+ {
+
+ file_uri = g_filename_from_uri (uri, NULL, NULL);
+
+ /* Non-local executables don't get launched. They act like non-executables. */
+ if (file_uri == NULL)
+ {
+ caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
+ "tree view window_info_open_location window=%p: %s",
+ view->details->window, uri);
+ location = g_file_new_for_uri (uri);
+ caja_window_slot_info_open_location
+ (slot,
+ location,
+ CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
+ view->details->activation_flags,
+ NULL);
+ g_object_unref (location);
+ }
+ else
+ {
+ caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
+ "tree view launch_application_from_command window=%p: %s",
+ view->details->window, file_uri);
+ caja_launch_application_from_command (screen, NULL, file_uri, FALSE, NULL);
+ g_free (file_uri);
+ }
+
+ }
+ else if (uri != NULL)
+ {
+ if (!open_in_same_slot ||
+ view->details->selection_location == NULL ||
+ strcmp (uri, view->details->selection_location) != 0)
+ {
+ if (open_in_same_slot)
+ {
+ if (view->details->selection_location != NULL)
+ {
+ g_free (view->details->selection_location);
+ }
+ view->details->selection_location = g_strdup (uri);
+ }
+
+ caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
+ "tree view window_info_open_location window=%p: %s",
+ view->details->window, uri);
+ location = g_file_new_for_uri (uri);
+ caja_window_slot_info_open_location
+ (slot,
+ location,
+ CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
+ view->details->activation_flags,
+ NULL);
+ g_object_unref (location);
+ }
+ }
+
+ g_free (uri);
+ caja_file_unref (view->details->activation_file);
+ view->details->activation_file = NULL;
+}
+
+static void
+cancel_activation (FMTreeView *view)
+{
+ if (view->details->activation_file == NULL)
+ {
+ return;
+ }
+
+ caja_file_cancel_call_when_ready
+ (view->details->activation_file,
+ got_activation_uri_callback, view);
+ caja_file_unref (view->details->activation_file);
+ view->details->activation_file = NULL;
+}
+
+static void
+row_activated_callback (GtkTreeView *treeview, GtkTreePath *path,
+ GtkTreeViewColumn *column, FMTreeView *view)
+{
+ if (gtk_tree_view_row_expanded (view->details->tree_widget, path))
+ {
+ gtk_tree_view_collapse_row (view->details->tree_widget, path);
+ }
+ else
+ {
+ gtk_tree_view_expand_row (view->details->tree_widget,
+ path, FALSE);
+ }
+}
+
+static gboolean
+selection_changed_timer_callback(FMTreeView *view)
+{
+ CajaFileAttributes attributes;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_widget));
+
+ /* no activation if popup menu is open */
+ if (view->details->popup_file != NULL)
+ {
+ return FALSE;
+ }
+
+ cancel_activation (view);
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ return FALSE;
+ }
+
+ view->details->activation_file = sort_model_iter_to_file (view, &iter);
+ if (view->details->activation_file == NULL)
+ {
+ return FALSE;
+ }
+ view->details->activation_flags = 0;
+
+ attributes = CAJA_FILE_ATTRIBUTE_INFO | CAJA_FILE_ATTRIBUTE_LINK_INFO;
+ caja_file_call_when_ready (view->details->activation_file, attributes,
+ got_activation_uri_callback, view);
+ return FALSE; /* remove timeout */
+}
+
+static void
+selection_changed_callback (GtkTreeSelection *selection,
+ FMTreeView *view)
+{
+ GdkEvent *event;
+ gboolean is_keyboard;
+
+ if (view->details->selection_changed_timer)
+ {
+ g_source_remove (view->details->selection_changed_timer);
+ view->details->selection_changed_timer = 0;
+ }
+
+ event = gtk_get_current_event ();
+ if (event)
+ {
+ is_keyboard = (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE);
+ gdk_event_free (event);
+
+ if (is_keyboard)
+ {
+ /* on keyboard event: delay the change */
+ /* TODO: make dependent on keyboard repeat rate as per Markus Bertheau ? */
+ view->details->selection_changed_timer = g_timeout_add (300, (GSourceFunc) selection_changed_timer_callback, view);
+ }
+ else
+ {
+ /* on mouse event: show the change immediately */
+ selection_changed_timer_callback (view);
+ }
+ }
+}
+
+static int
+compare_rows (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer callback_data)
+{
+ CajaFile *file_a, *file_b;
+ int result;
+
+ /* Dummy rows are always first */
+ if (a->user_data == NULL)
+ {
+ return -1;
+ }
+ else if (b->user_data == NULL)
+ {
+ return 1;
+ }
+
+ /* don't sort root nodes */
+ if (fm_tree_model_iter_is_root (FM_TREE_MODEL (model), a) &&
+ fm_tree_model_iter_is_root (FM_TREE_MODEL (model), b))
+ {
+ return fm_tree_model_iter_compare_roots (FM_TREE_MODEL (model), a, b);
+ }
+
+ file_a = fm_tree_model_iter_get_file (FM_TREE_MODEL (model), a);
+ file_b = fm_tree_model_iter_get_file (FM_TREE_MODEL (model), b);
+
+ if (file_a == file_b)
+ {
+ result = 0;
+ }
+ else if (file_a == NULL)
+ {
+ result = -1;
+ }
+ else if (file_b == NULL)
+ {
+ result = +1;
+ }
+ else
+ {
+ result = caja_file_compare_for_sort (file_a, file_b,
+ CAJA_FILE_SORT_BY_DISPLAY_NAME,
+ FALSE, FALSE);
+ }
+
+ caja_file_unref (file_a);
+ caja_file_unref (file_b);
+
+ return result;
+}
+
+
+static char *
+get_root_uri_callback (CajaTreeViewDragDest *dest,
+ gpointer user_data)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (user_data);
+
+ /* Don't allow drops on background */
+ return NULL;
+}
+
+static CajaFile *
+get_file_for_path_callback (CajaTreeViewDragDest *dest,
+ GtkTreePath *path,
+ gpointer user_data)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (user_data);
+
+ return sort_model_path_to_file (view, path);
+}
+
+static void
+move_copy_items_callback (CajaTreeViewDragDest *dest,
+ const GList *item_uris,
+ const char *target_uri,
+ GdkDragAction action,
+ int x,
+ int y,
+ gpointer user_data)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (user_data);
+
+ caja_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
+ item_uris,
+ copied_files_atom);
+ caja_file_operations_copy_move
+ (item_uris,
+ NULL,
+ target_uri,
+ action,
+ GTK_WIDGET (view->details->tree_widget),
+ NULL, NULL);
+}
+
+static void
+add_root_for_mount (FMTreeView *view,
+ GMount *mount)
+{
+ char *mount_uri, *name;
+ GFile *root;
+ GIcon *icon;
+
+ if (g_mount_is_shadowed (mount))
+ return;
+
+ icon = g_mount_get_icon (mount);
+ root = g_mount_get_root (mount);
+ mount_uri = g_file_get_uri (root);
+ g_object_unref (root);
+ name = g_mount_get_name (mount);
+
+ fm_tree_model_add_root_uri(view->details->child_model,
+ mount_uri, name, icon, mount);
+
+ g_object_unref (icon);
+ g_free (name);
+ g_free (mount_uri);
+
+}
+
+static void
+mount_added_callback (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ FMTreeView *view)
+{
+ add_root_for_mount (view, mount);
+}
+
+static void
+mount_removed_callback (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ FMTreeView *view)
+{
+ GFile *root;
+ char *mount_uri;
+
+ root = g_mount_get_root (mount);
+ mount_uri = g_file_get_uri (root);
+ g_object_unref (root);
+ fm_tree_model_remove_root_uri (view->details->child_model,
+ mount_uri);
+ g_free (mount_uri);
+}
+
+static void
+clipboard_contents_received_callback (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ gpointer data)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (data);
+
+ if (gtk_selection_data_get_data_type (selection_data) == copied_files_atom
+ && gtk_selection_data_get_length (selection_data) > 0 &&
+ view->details->popup != NULL)
+ {
+ gtk_widget_set_sensitive (view->details->popup_paste, TRUE);
+ }
+
+ g_object_unref (view);
+}
+
+static gboolean
+is_parent_writable (CajaFile *file)
+{
+ CajaFile *parent;
+ gboolean result;
+
+ parent = caja_file_get_parent (file);
+
+ /* No parent directory, return FALSE */
+ if (parent == NULL)
+ {
+ return FALSE;
+ }
+
+ result = caja_file_can_write (parent);
+ caja_file_unref (parent);
+
+ return result;
+}
+
+static gboolean
+button_pressed_callback (GtkTreeView *treeview, GdkEventButton *event,
+ FMTreeView *view)
+{
+ GtkTreePath *path, *cursor_path;
+ gboolean parent_file_is_writable;
+ gboolean file_is_home_or_desktop;
+ gboolean file_is_special_link;
+ gboolean can_move_file_to_trash;
+ gboolean can_delete_file;
+
+ if (event->button == 3)
+ {
+ gboolean show_unmount = FALSE;
+ gboolean show_eject = FALSE;
+ GMount *mount = NULL;
+
+ if (view->details->popup_file != NULL)
+ {
+ return FALSE; /* Already up, ignore */
+ }
+
+ if (!gtk_tree_view_get_path_at_pos (treeview, event->x, event->y,
+ &path, NULL, NULL, NULL))
+ {
+ return FALSE;
+ }
+
+ view->details->popup_file = sort_model_path_to_file (view, path);
+ if (view->details->popup_file == NULL)
+ {
+ gtk_tree_path_free (path);
+ return FALSE;
+ }
+ gtk_tree_view_get_cursor (view->details->tree_widget, &cursor_path, NULL);
+ gtk_tree_view_set_cursor (view->details->tree_widget, path, NULL, FALSE);
+ gtk_tree_path_free (path);
+
+ create_popup_menu (view);
+
+ gtk_widget_set_sensitive (view->details->popup_open_in_new_window,
+ caja_file_is_directory (view->details->popup_file));
+ gtk_widget_set_sensitive (view->details->popup_create_folder,
+ caja_file_is_directory (view->details->popup_file) &&
+ caja_file_can_write (view->details->popup_file));
+ gtk_widget_set_sensitive (view->details->popup_paste, FALSE);
+ if (caja_file_is_directory (view->details->popup_file) &&
+ caja_file_can_write (view->details->popup_file))
+ {
+ gtk_clipboard_request_contents (caja_clipboard_get (GTK_WIDGET (view->details->tree_widget)),
+ copied_files_atom,
+ clipboard_contents_received_callback, g_object_ref (view));
+ }
+ can_move_file_to_trash = caja_file_can_trash (view->details->popup_file);
+ gtk_widget_set_sensitive (view->details->popup_trash, can_move_file_to_trash);
+
+ if (show_delete_command_auto_value)
+ {
+ parent_file_is_writable = is_parent_writable (view->details->popup_file);
+ file_is_home_or_desktop = caja_file_is_home (view->details->popup_file)
+ || caja_file_is_desktop_directory (view->details->popup_file);
+ file_is_special_link = CAJA_IS_DESKTOP_ICON_FILE (view->details->popup_file);
+
+ can_delete_file = parent_file_is_writable
+ && !file_is_home_or_desktop
+ && !file_is_special_link;
+
+ gtk_widget_show (view->details->popup_delete);
+ gtk_widget_set_sensitive (view->details->popup_delete, can_delete_file);
+ }
+ else
+ {
+ gtk_widget_hide (view->details->popup_delete);
+ }
+
+ mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, view->details->popup_file);
+ if (mount)
+ {
+ show_unmount = g_mount_can_unmount (mount);
+ show_eject = g_mount_can_eject (mount);
+ }
+
+ if (show_unmount)
+ {
+ gtk_widget_show (view->details->popup_unmount);
+ }
+ else
+ {
+ gtk_widget_hide (view->details->popup_unmount);
+ }
+
+ if (show_eject)
+ {
+ gtk_widget_show (view->details->popup_eject);
+ }
+ else
+ {
+ gtk_widget_hide (view->details->popup_eject);
+ }
+
+ if (show_unmount || show_eject)
+ {
+ gtk_widget_show (view->details->popup_unmount_separator);
+ }
+ else
+ {
+ gtk_widget_hide (view->details->popup_unmount_separator);
+ }
+
+ gtk_menu_popup (GTK_MENU (view->details->popup),
+ NULL, NULL, NULL, NULL,
+ event->button, event->time);
+
+ gtk_tree_view_set_cursor (view->details->tree_widget, cursor_path, NULL, FALSE);
+ gtk_tree_path_free (cursor_path);
+
+ return TRUE;
+ }
+ else if (event->button == 2 && event->type == GDK_BUTTON_PRESS)
+ {
+ CajaFile *file;
+
+ if (!gtk_tree_view_get_path_at_pos (treeview, event->x, event->y,
+ &path, NULL, NULL, NULL))
+ {
+ return FALSE;
+ }
+
+ file = sort_model_path_to_file (view, path);
+ if (file)
+ {
+ fm_tree_view_activate_file (view, file,
+ (event->state & GDK_CONTROL_MASK) != 0 ?
+ CAJA_WINDOW_OPEN_FLAG_NEW_WINDOW :
+ CAJA_WINDOW_OPEN_FLAG_NEW_TAB);
+ caja_file_unref (file);
+ }
+
+ gtk_tree_path_free (path);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+fm_tree_view_activate_file (FMTreeView *view,
+ CajaFile *file,
+ CajaWindowOpenFlags flags)
+{
+ CajaFileAttributes attributes;
+
+ cancel_activation (view);
+
+ view->details->activation_file = caja_file_ref (file);
+ view->details->activation_flags = flags;
+
+ attributes = CAJA_FILE_ATTRIBUTE_INFO | CAJA_FILE_ATTRIBUTE_LINK_INFO;
+ caja_file_call_when_ready (view->details->activation_file, attributes,
+ got_activation_uri_callback, view);
+}
+
+static void
+fm_tree_view_open_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ fm_tree_view_activate_file (view, view->details->popup_file, 0);
+}
+
+static void
+fm_tree_view_open_in_new_tab_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ fm_tree_view_activate_file (view, view->details->popup_file, CAJA_WINDOW_OPEN_FLAG_NEW_TAB);
+}
+
+static void
+fm_tree_view_open_in_new_window_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ fm_tree_view_activate_file (view, view->details->popup_file, CAJA_WINDOW_OPEN_FLAG_NEW_WINDOW);
+}
+
+static void
+new_folder_done (GFile *new_folder, gpointer data)
+{
+ GList *list;
+
+ /* show the properties window for the newly created
+ * folder so the user can change its name
+ */
+ list = g_list_prepend (NULL, caja_file_get (new_folder));
+
+ fm_properties_window_present (list, GTK_WIDGET (data));
+
+ caja_file_list_free (list);
+}
+
+static void
+fm_tree_view_create_folder_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ char *parent_uri;
+
+ parent_uri = caja_file_get_uri (view->details->popup_file);
+ caja_file_operations_new_folder (GTK_WIDGET (view->details->tree_widget),
+ NULL,
+ parent_uri,
+ new_folder_done, view->details->tree_widget);
+
+ g_free (parent_uri);
+}
+
+static void
+copy_or_cut_files (FMTreeView *view,
+ gboolean cut)
+{
+ char *status_string, *name;
+ CajaClipboardInfo info;
+ GtkTargetList *target_list;
+ GtkTargetEntry *targets;
+ int n_targets;
+
+ info.cut = cut;
+ info.files = g_list_prepend (NULL, view->details->popup_file);
+
+ target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add (target_list, copied_files_atom, 0, 0);
+ gtk_target_list_add_uri_targets (target_list, 0);
+ gtk_target_list_add_text_targets (target_list, 0);
+
+ targets = gtk_target_table_new_from_list (target_list, &n_targets);
+ gtk_target_list_unref (target_list);
+
+ gtk_clipboard_set_with_data (caja_clipboard_get (GTK_WIDGET (view->details->tree_widget)),
+ targets, n_targets,
+ caja_get_clipboard_callback, caja_clear_clipboard_callback,
+ NULL);
+ gtk_target_table_free (targets, n_targets);
+
+ caja_clipboard_monitor_set_clipboard_info (caja_clipboard_monitor_get (),
+ &info);
+ g_list_free (info.files);
+
+ name = caja_file_get_display_name (view->details->popup_file);
+ if (cut)
+ {
+ status_string = g_strdup_printf (_("\"%s\" will be moved "
+ "if you select the Paste command"),
+ name);
+ }
+ else
+ {
+ status_string = g_strdup_printf (_("\"%s\" will be copied "
+ "if you select the Paste command"),
+ name);
+ }
+ g_free (name);
+
+ caja_window_info_push_status (view->details->window,
+ status_string);
+ g_free (status_string);
+}
+
+static void
+fm_tree_view_cut_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ copy_or_cut_files (view, TRUE);
+}
+
+static void
+fm_tree_view_copy_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ copy_or_cut_files (view, FALSE);
+}
+
+static void
+paste_clipboard_data (FMTreeView *view,
+ GtkSelectionData *selection_data,
+ char *destination_uri)
+{
+ gboolean cut;
+ GList *item_uris;
+
+ cut = FALSE;
+ item_uris = caja_clipboard_get_uri_list_from_selection_data (selection_data, &cut,
+ copied_files_atom);
+
+ if (item_uris == NULL|| destination_uri == NULL)
+ {
+ caja_window_info_push_status (view->details->window,
+ _("There is nothing on the clipboard to paste."));
+ }
+ else
+ {
+ caja_file_operations_copy_move
+ (item_uris, NULL, destination_uri,
+ cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY,
+ GTK_WIDGET (view->details->tree_widget),
+ NULL, NULL);
+
+ /* If items are cut then remove from clipboard */
+ if (cut)
+ {
+ gtk_clipboard_clear (caja_clipboard_get (GTK_WIDGET (view)));
+ }
+
+ eel_g_list_free_deep (item_uris);
+ }
+}
+
+static void
+paste_into_clipboard_received_callback (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ gpointer data)
+{
+ FMTreeView *view;
+ char *directory_uri;
+
+ view = FM_TREE_VIEW (data);
+
+ directory_uri = caja_file_get_uri (view->details->popup_file);
+
+ paste_clipboard_data (view, selection_data, directory_uri);
+
+ g_free (directory_uri);
+}
+
+static void
+fm_tree_view_paste_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ gtk_clipboard_request_contents (caja_clipboard_get (GTK_WIDGET (view->details->tree_widget)),
+ copied_files_atom,
+ paste_into_clipboard_received_callback, view);
+}
+
+static GtkWindow *
+fm_tree_view_get_containing_window (FMTreeView *view)
+{
+ GtkWidget *window;
+
+ g_assert (FM_IS_TREE_VIEW (view));
+
+ window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW);
+ if (window == NULL)
+ {
+ return NULL;
+ }
+
+ return GTK_WINDOW (window);
+}
+
+static void
+fm_tree_view_trash_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ GList *list;
+
+ if (!caja_file_can_trash (view->details->popup_file))
+ {
+ return;
+ }
+
+ list = g_list_prepend (NULL,
+ caja_file_get_location (view->details->popup_file));
+
+ caja_file_operations_trash_or_delete (list,
+ fm_tree_view_get_containing_window (view),
+ NULL, NULL);
+ eel_g_object_list_free (list);
+}
+
+static void
+fm_tree_view_delete_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ GList *location_list;
+
+ if (!show_delete_command_auto_value)
+ {
+ return;
+ }
+
+ location_list = g_list_prepend (NULL,
+ caja_file_get_location (view->details->popup_file));
+
+ caja_file_operations_delete (location_list, fm_tree_view_get_containing_window (view), NULL, NULL);
+ eel_g_object_list_free (location_list);
+}
+
+static void
+fm_tree_view_properties_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ GList *list;
+
+ list = g_list_prepend (NULL, caja_file_ref (view->details->popup_file));
+
+ fm_properties_window_present (list, GTK_WIDGET (view->details->tree_widget));
+
+ caja_file_list_free (list);
+}
+
+static void
+fm_tree_view_unmount_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ CajaFile *file = view->details->popup_file;
+ GMount *mount;
+
+ if (file == NULL)
+ {
+ return;
+ }
+
+ mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, file);
+
+ if (mount != NULL)
+ {
+ caja_file_operations_unmount_mount (fm_tree_view_get_containing_window (view),
+ mount, FALSE, TRUE);
+ }
+}
+
+static void
+fm_tree_view_eject_cb (GtkWidget *menu_item,
+ FMTreeView *view)
+{
+ CajaFile *file = view->details->popup_file;
+ GMount *mount;
+
+ if (file == NULL)
+ {
+ return;
+ }
+
+ mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, file);
+
+ if (mount != NULL)
+ {
+ caja_file_operations_unmount_mount (fm_tree_view_get_containing_window (view),
+ mount, TRUE, TRUE);
+ }
+}
+
+static gboolean
+free_popup_file_in_idle_cb (gpointer data)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (data);
+
+ if (view->details->popup_file != NULL)
+ {
+ caja_file_unref (view->details->popup_file);
+ view->details->popup_file = NULL;
+ }
+ view->details->popup_file_idle_handler = 0;
+ return FALSE;
+}
+
+static void
+popup_menu_deactivated (GtkMenuShell *menu_shell, gpointer data)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (data);
+
+ /* The popup menu is deactivated. (I.E. hidden)
+ We want to free popup_file, but can't right away as it might immediately get
+ used if we're deactivation due to activating a menu item. So, we free it in
+ idle */
+
+ if (view->details->popup_file != NULL &&
+ view->details->popup_file_idle_handler == 0)
+ {
+ view->details->popup_file_idle_handler = g_idle_add (free_popup_file_in_idle_cb, view);
+ }
+}
+
+static void
+create_popup_menu (FMTreeView *view)
+{
+ GtkWidget *popup, *menu_item, *menu_image;
+
+ if (view->details->popup != NULL)
+ {
+ /* already created */
+ return;
+ }
+
+ popup = gtk_menu_new ();
+
+ g_signal_connect (popup, "deactivate",
+ G_CALLBACK (popup_menu_deactivated),
+ view);
+
+
+ /* add the "open" menu item */
+ menu_image = gtk_image_new_from_stock (GTK_STOCK_OPEN,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_show (menu_image);
+ menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Open"));
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
+ menu_image);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_open_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_open = menu_item;
+
+ /* add the "open in new tab" menu item */
+ menu_item = gtk_menu_item_new_with_mnemonic (_("Open in New _Tab"));
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_open_in_new_tab_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_open_in_new_window = menu_item;
+
+ /* add the "open in new window" menu item */
+ menu_item = gtk_menu_item_new_with_mnemonic (_("Open in New _Window"));
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_open_in_new_window_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_open_in_new_window = menu_item;
+
+ eel_gtk_menu_append_separator (GTK_MENU (popup));
+
+ /* add the "create folder" menu item */
+ menu_item = gtk_image_menu_item_new_with_mnemonic (_("Create _Folder"));
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_create_folder_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_create_folder = menu_item;
+
+ eel_gtk_menu_append_separator (GTK_MENU (popup));
+
+ /* add the "cut folder" menu item */
+ menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CUT, NULL);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_cut_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_cut = menu_item;
+
+ /* add the "copy folder" menu item */
+ menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_COPY, NULL);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_copy_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_copy = menu_item;
+
+ /* add the "paste files into folder" menu item */
+ menu_image = gtk_image_new_from_stock (GTK_STOCK_PASTE,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_show (menu_image);
+ menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Paste Into Folder"));
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
+ menu_image);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_paste_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_paste = menu_item;
+
+ eel_gtk_menu_append_separator (GTK_MENU (popup));
+
+ /* add the "move to trash" menu item */
+ menu_image = gtk_image_new_from_icon_name (CAJA_ICON_TRASH_FULL,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_show (menu_image);
+ menu_item = gtk_image_menu_item_new_with_mnemonic (_("Mo_ve to Trash"));
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
+ menu_image);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_trash_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_trash = menu_item;
+
+ /* add the "delete" menu item */
+ menu_image = gtk_image_new_from_icon_name (CAJA_ICON_DELETE,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_show (menu_image);
+ menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Delete"));
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
+ menu_image);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_delete_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_delete = menu_item;
+
+ eel_gtk_menu_append_separator (GTK_MENU (popup));
+
+ /* add the "Unmount" menu item */
+ menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Unmount"));
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_unmount_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_unmount = menu_item;
+
+ /* add the "Eject" menu item */
+ menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Eject"));
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_eject_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_eject = menu_item;
+
+ /* add the unmount separator menu item */
+ view->details->popup_unmount_separator =
+ GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (popup)));
+
+ /* add the "properties" menu item */
+ menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_PROPERTIES, NULL);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (fm_tree_view_properties_cb),
+ view);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
+ view->details->popup_properties = menu_item;
+
+ view->details->popup = popup;
+}
+
+static void
+create_tree (FMTreeView *view)
+{
+ GtkCellRenderer *cell;
+ GtkTreeViewColumn *column;
+ GVolumeMonitor *volume_monitor;
+ char *home_uri;
+ GList *mounts, *l;
+ char *location;
+ GIcon *icon;
+ CajaWindowSlotInfo *slot;
+
+ view->details->child_model = fm_tree_model_new ();
+ view->details->sort_model = GTK_TREE_MODEL_SORT
+ (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (view->details->child_model)));
+ view->details->tree_widget = GTK_TREE_VIEW
+ (gtk_tree_view_new_with_model (GTK_TREE_MODEL (view->details->sort_model)));
+ g_object_unref (view->details->sort_model);
+
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (view->details->sort_model),
+ compare_rows, view, NULL);
+
+ g_signal_connect_object
+ (view->details->child_model, "row_loaded",
+ G_CALLBACK (row_loaded_callback),
+ view, G_CONNECT_AFTER);
+ home_uri = caja_get_home_directory_uri ();
+ icon = g_themed_icon_new (CAJA_ICON_HOME);
+ fm_tree_model_add_root_uri (view->details->child_model, home_uri, _("Home Folder"), icon, NULL);
+ g_object_unref (icon);
+ g_free (home_uri);
+ icon = g_themed_icon_new (CAJA_ICON_FILESYSTEM);
+ fm_tree_model_add_root_uri (view->details->child_model, "file:///", _("File System"), icon, NULL);
+ g_object_unref (icon);
+#ifdef NOT_YET_USABLE /* Do we really want this? */
+ icon = g_themed_icon_new (CAJA_ICON_NETWORK);
+ fm_tree_model_add_root_uri (view->details->child_model, "network:///", _("Network Neighbourhood"), icon, NULL);
+ g_object_unref (icon);
+#endif
+
+ volume_monitor = g_volume_monitor_get ();
+ view->details->volume_monitor = volume_monitor;
+ mounts = g_volume_monitor_get_mounts (volume_monitor);
+ for (l = mounts; l != NULL; l = l->next)
+ {
+ add_root_for_mount (view, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free (mounts);
+
+ g_signal_connect_object (volume_monitor, "mount_added",
+ G_CALLBACK (mount_added_callback), view, 0);
+ g_signal_connect_object (volume_monitor, "mount_removed",
+ G_CALLBACK (mount_removed_callback), view, 0);
+
+ g_object_unref (view->details->child_model);
+
+ gtk_tree_view_set_headers_visible (view->details->tree_widget, FALSE);
+
+ view->details->drag_dest =
+ caja_tree_view_drag_dest_new (view->details->tree_widget);
+ g_signal_connect_object (view->details->drag_dest,
+ "get_root_uri",
+ G_CALLBACK (get_root_uri_callback),
+ view, 0);
+ g_signal_connect_object (view->details->drag_dest,
+ "get_file_for_path",
+ G_CALLBACK (get_file_for_path_callback),
+ view, 0);
+ g_signal_connect_object (view->details->drag_dest,
+ "move_copy_items",
+ G_CALLBACK (move_copy_items_callback),
+ view, 0);
+
+ /* Create column */
+ column = gtk_tree_view_column_new ();
+
+ cell = caja_cell_renderer_pixbuf_emblem_new ();
+ gtk_tree_view_column_pack_start (column, cell, FALSE);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "pixbuf", FM_TREE_MODEL_CLOSED_PIXBUF_COLUMN,
+ "pixbuf_expander_closed", FM_TREE_MODEL_CLOSED_PIXBUF_COLUMN,
+ "pixbuf_expander_open", FM_TREE_MODEL_OPEN_PIXBUF_COLUMN,
+ "pixbuf_emblem", FM_TREE_MODEL_EMBLEM_PIXBUF_COLUMN,
+ NULL);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "text", FM_TREE_MODEL_DISPLAY_NAME_COLUMN,
+ "style", FM_TREE_MODEL_FONT_STYLE_COLUMN,
+ NULL);
+
+ gtk_tree_view_append_column (view->details->tree_widget, column);
+
+ gtk_widget_show (GTK_WIDGET (view->details->tree_widget));
+
+ gtk_container_add (GTK_CONTAINER (view),
+ GTK_WIDGET (view->details->tree_widget));
+
+ g_signal_connect_object (gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_widget)), "changed",
+ G_CALLBACK (selection_changed_callback), view, 0);
+
+ g_signal_connect (G_OBJECT (view->details->tree_widget),
+ "row-activated", G_CALLBACK (row_activated_callback),
+ view);
+
+ g_signal_connect (G_OBJECT (view->details->tree_widget),
+ "button_press_event", G_CALLBACK (button_pressed_callback),
+ view);
+
+ slot = caja_window_info_get_active_slot (view->details->window);
+ location = caja_window_slot_info_get_current_location (slot);
+ schedule_select_and_show_location (view, location);
+ g_free (location);
+}
+
+static void
+update_filtering_from_preferences (FMTreeView *view)
+{
+ CajaWindowShowHiddenFilesMode mode;
+
+ if (view->details->child_model == NULL)
+ {
+ return;
+ }
+
+ mode = caja_window_info_get_hidden_files_mode (view->details->window);
+
+ if (mode == CAJA_WINDOW_SHOW_HIDDEN_FILES_DEFAULT)
+ {
+ fm_tree_model_set_show_hidden_files
+ (view->details->child_model,
+ eel_preferences_get_boolean (CAJA_PREFERENCES_SHOW_HIDDEN_FILES));
+ }
+ else
+ {
+ fm_tree_model_set_show_hidden_files
+ (view->details->child_model,
+ mode == CAJA_WINDOW_SHOW_HIDDEN_FILES_ENABLE);
+ }
+ fm_tree_model_set_show_only_directories
+ (view->details->child_model,
+ eel_preferences_get_boolean (CAJA_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES));
+}
+
+static void
+parent_set_callback (GtkWidget *widget,
+ GtkWidget *previous_parent,
+ gpointer callback_data)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (callback_data);
+
+ if (gtk_widget_get_parent (widget) != NULL && view->details->tree_widget == NULL)
+ {
+ create_tree (view);
+ update_filtering_from_preferences (view);
+ }
+}
+
+static void
+filtering_changed_callback (gpointer callback_data)
+{
+ update_filtering_from_preferences (FM_TREE_VIEW (callback_data));
+}
+
+static void
+loading_uri_callback (CajaWindowInfo *window,
+ char *location,
+ gpointer callback_data)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (callback_data);
+ schedule_select_and_show_location (view, location);
+}
+
+static void
+fm_tree_view_init (FMTreeView *view)
+{
+ view->details = g_new0 (FMTreeViewDetails, 1);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (view), NULL);
+ gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (view), NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view), GTK_SHADOW_IN);
+
+ gtk_widget_show (GTK_WIDGET (view));
+
+ g_signal_connect_object (view, "parent_set",
+ G_CALLBACK (parent_set_callback), view, 0);
+
+ view->details->selection_location = NULL;
+
+ view->details->selecting = FALSE;
+
+ eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_SHOW_HIDDEN_FILES,
+ filtering_changed_callback, view, G_OBJECT (view));
+ eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_SHOW_BACKUP_FILES,
+ filtering_changed_callback, view, G_OBJECT (view));
+ eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES,
+ filtering_changed_callback, view, G_OBJECT (view));
+
+ view->details->popup_file = NULL;
+
+ view->details->clipboard_handler_id =
+ g_signal_connect (caja_clipboard_monitor_get (),
+ "clipboard_info",
+ G_CALLBACK (notify_clipboard_info), view);
+}
+
+static void
+fm_tree_view_dispose (GObject *object)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (object);
+
+ if (view->details->selection_changed_timer)
+ {
+ g_source_remove (view->details->selection_changed_timer);
+ view->details->selection_changed_timer = 0;
+ }
+
+ if (view->details->drag_dest)
+ {
+ g_object_unref (view->details->drag_dest);
+ view->details->drag_dest = NULL;
+ }
+
+ if (view->details->show_selection_idle_id)
+ {
+ g_source_remove (view->details->show_selection_idle_id);
+ view->details->show_selection_idle_id = 0;
+ }
+
+ if (view->details->clipboard_handler_id != 0)
+ {
+ g_signal_handler_disconnect (caja_clipboard_monitor_get (),
+ view->details->clipboard_handler_id);
+ view->details->clipboard_handler_id = 0;
+ }
+
+ cancel_activation (view);
+
+ if (view->details->popup != NULL)
+ {
+ gtk_widget_destroy (view->details->popup);
+ view->details->popup = NULL;
+ }
+
+ if (view->details->popup_file_idle_handler != 0)
+ {
+ g_source_remove (view->details->popup_file_idle_handler);
+ view->details->popup_file_idle_handler = 0;
+ }
+
+ if (view->details->popup_file != NULL)
+ {
+ caja_file_unref (view->details->popup_file);
+ view->details->popup_file = NULL;
+ }
+
+ if (view->details->selection_location != NULL)
+ {
+ g_free (view->details->selection_location);
+ view->details->selection_location = NULL;
+ }
+
+ if (view->details->volume_monitor != NULL)
+ {
+ g_object_unref (view->details->volume_monitor);
+ view->details->volume_monitor = NULL;
+ }
+
+ view->details->window = NULL;
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+fm_tree_view_finalize (GObject *object)
+{
+ FMTreeView *view;
+
+ view = FM_TREE_VIEW (object);
+
+ g_free (view->details);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+fm_tree_view_class_init (FMTreeViewClass *class)
+{
+ G_OBJECT_CLASS (class)->dispose = fm_tree_view_dispose;
+ G_OBJECT_CLASS (class)->finalize = fm_tree_view_finalize;
+
+ copied_files_atom = gdk_atom_intern ("x-special/mate-copied-files", FALSE);
+
+ eel_preferences_add_auto_boolean (CAJA_PREFERENCES_ENABLE_DELETE,
+ &show_delete_command_auto_value);
+}
+
+static const char *
+fm_tree_view_get_sidebar_id (CajaSidebar *sidebar)
+{
+ return TREE_SIDEBAR_ID;
+}
+
+static char *
+fm_tree_view_get_tab_label (CajaSidebar *sidebar)
+{
+ return g_strdup (_("Tree"));
+}
+
+static char *
+fm_tree_view_get_tab_tooltip (CajaSidebar *sidebar)
+{
+ return g_strdup (_("Show Tree"));
+}
+
+static GdkPixbuf *
+fm_tree_view_get_tab_icon (CajaSidebar *sidebar)
+{
+ return NULL;
+}
+
+static void
+fm_tree_view_is_visible_changed (CajaSidebar *sidebar,
+ gboolean is_visible)
+{
+ /* Do nothing */
+}
+
+static void
+hidden_files_mode_changed_callback (CajaWindowInfo *window,
+ FMTreeView *view)
+{
+ update_filtering_from_preferences (view);
+}
+
+static void
+fm_tree_view_iface_init (CajaSidebarIface *iface)
+{
+ iface->get_sidebar_id = fm_tree_view_get_sidebar_id;
+ iface->get_tab_label = fm_tree_view_get_tab_label;
+ iface->get_tab_tooltip = fm_tree_view_get_tab_tooltip;
+ iface->get_tab_icon = fm_tree_view_get_tab_icon;
+ iface->is_visible_changed = fm_tree_view_is_visible_changed;
+}
+
+static void
+fm_tree_view_set_parent_window (FMTreeView *sidebar,
+ CajaWindowInfo *window)
+{
+ char *location;
+ CajaWindowSlotInfo *slot;
+
+ sidebar->details->window = window;
+
+ slot = caja_window_info_get_active_slot (window);
+
+ g_signal_connect_object (window, "loading_uri",
+ G_CALLBACK (loading_uri_callback), sidebar, 0);
+ location = caja_window_slot_info_get_current_location (slot);
+ loading_uri_callback (window, location, sidebar);
+ g_free (location);
+
+ g_signal_connect_object (window, "hidden_files_mode_changed",
+ G_CALLBACK (hidden_files_mode_changed_callback), sidebar, 0);
+
+}
+
+static CajaSidebar *
+fm_tree_view_create (CajaSidebarProvider *provider,
+ CajaWindowInfo *window)
+{
+ FMTreeView *sidebar;
+
+ sidebar = g_object_new (fm_tree_view_get_type (), NULL);
+ fm_tree_view_set_parent_window (sidebar, window);
+ g_object_ref_sink (sidebar);
+
+ return CAJA_SIDEBAR (sidebar);
+}
+
+static void
+sidebar_provider_iface_init (CajaSidebarProviderIface *iface)
+{
+ iface->create = fm_tree_view_create;
+}
+
+static void
+fm_tree_view_provider_init (FMTreeViewProvider *sidebar)
+{
+}
+
+static void
+fm_tree_view_provider_class_init (FMTreeViewProviderClass *class)
+{
+}
+
+void
+fm_tree_view_register (void)
+{
+ caja_module_add_type (fm_tree_view_provider_get_type ());
+}