[PATCH] Another tree view patch (very preliminary)
- From: Robert Atkey <R A Atkey sms ed ac uk>
- To: nautilus-list gnome org
- Subject: [PATCH] Another tree view patch (very preliminary)
- Date: Wed, 15 Jun 2005 10:02:00 +0100
Hi,
I have also been working on a patch for a tree view in nautilus. I took
a different route and based it on the tree sidebar view, and didn't use
FMDirectoryView as a subclass. As a result it is somewhat less
featureful than Juerg Billeter's patch (it really only displays the
files at the moment), but I think it has a cleaner separation of model
and view. It also does not keep non-visible items in memory (after a
timeout), and acts like the tree sidebar with respect to empty/loading
folders.
The attached patch is against CVS HEAD. I couldn't get 'cvs diff' to
include the new files in the patch so I've attached them separately.
They should go in src/file-manager.
Unfortunately, my graphics card has packed up and I am stuck in text
mode so I cannot really do any more development until July. So I am just
sending this code in the hope that someone finds it useful.
Bob
? src/file-manager/fm-directory-tree-model.c
? src/file-manager/fm-directory-tree-model.h
? src/file-manager/fm-directory-tree-view.c
? src/file-manager/fm-directory-tree-view.h
Index: src/nautilus-application.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-application.c,v
retrieving revision 1.234
diff -p -u -r1.234 nautilus-application.c
--- src/nautilus-application.c 2 May 2005 13:44:35 -0000 1.234
+++ src/nautilus-application.c 15 Jun 2005 08:45:05 -0000
@@ -34,6 +34,7 @@
#include "file-manager/fm-icon-view.h"
#include "file-manager/fm-list-view.h"
#include "file-manager/fm-tree-view.h"
+#include "file-manager/fm-directory-tree-view.h"
#include "nautilus-information-panel.h"
#include "nautilus-history-sidebar.h"
#include "nautilus-notes-viewer.h"
@@ -176,6 +177,7 @@ nautilus_application_instance_init (Naut
fm_icon_view_register ();
fm_desktop_icon_view_register ();
fm_list_view_register ();
+ fm_directory_tree_view_register ();
/* register sidebars */
nautilus_information_panel_register ();
Index: src/file-manager/Makefile.am
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/Makefile.am,v
retrieving revision 1.80
diff -p -u -r1.80 Makefile.am
--- src/file-manager/Makefile.am 25 Nov 2004 14:59:54 -0000 1.80
+++ src/file-manager/Makefile.am 15 Jun 2005 08:45:05 -0000
@@ -19,6 +19,10 @@ libnautilus_file_manager_la_SOURCES= \
fm-desktop-icon-view.h \
fm-directory-view.c \
fm-directory-view.h \
+ fm-directory-tree-view.c \
+ fm-directory-tree-view.h \
+ fm-directory-tree-model.c \
+ fm-directory-tree-model.h \
fm-ditem-page.c \
fm-ditem-page.h \
fm-error-reporting.c \
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
#include "fm-directory-tree-model.h"
#include <gtk/gtktreemodel.h>
#include <libnautilus-private/nautilus-file.h>
#include <libnautilus-private/nautilus-directory.h>
#include <gsequence/gsequence.h>
enum {
START_LOADING,
STOP_LOADING,
LAST_SIGNAL
};
static guint directory_tree_model_signals[LAST_SIGNAL] = { 0, 0 };
typedef struct Node Node;
struct Node {
int ref_count;
FMDirectoryTreeModel *model;
NautilusFile *file;
GSequencePtr owner;
Node *parent;
/* Directory stuff */
NautilusDirectory *directory;
int all_children_ref_count;
int dummy_child_ref_count;
GSequence *children;
guint done_loading_id;
guint files_added_id;
guint files_changed_id;
guint done_loading : 1;
};
struct FMDirectoryTreeModelDetails {
int stamp;
Node *root;
guint ensure_monitoring_idle_id;
guint check_for_monitoring_cessation_timeout_id;
GHashTable *file_to_node;
int loading_count;
NautilusFileAttributes attributes;
};
static void tree_model_iface_init (GtkTreeModelIface *iface);
static void destroy_node (FMDirectoryTreeModel *model, Node *node, GtkTreePath *path, gboolean include_dummy);
static void destroy_children (FMDirectoryTreeModel *model, Node *node, GtkTreePath *path, gboolean include_dummy);
static void schedule_check_monitoring_cessation (FMDirectoryTreeModel *model);
G_DEFINE_TYPE_WITH_CODE (FMDirectoryTreeModel, fm_directory_tree_model,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
tree_model_iface_init));
static gboolean
node_has_dummy_child (Node *node)
{
g_assert (node != NULL);
return (node->directory != NULL
&& (!node->done_loading
|| g_sequence_get_length (node->children) == 0));
}
static void
increment_loading_count (FMDirectoryTreeModel *model)
{
model->details->loading_count++;
if (model->details->loading_count == 1) {
g_signal_emit_by_name (G_OBJECT (model), "start_loading");
}
}
static void
decrement_loading_count (FMDirectoryTreeModel *model)
{
model->details->loading_count--;
if (model->details->loading_count == 0) {
g_signal_emit_by_name (G_OBJECT (model), "stop_loading");
}
}
static GtkTreeModelFlags
model_get_flags (GtkTreeModel *model)
{
FMDirectoryTreeModel *tree_model;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
}
static gint
model_get_n_columns (GtkTreeModel *model)
{
FMDirectoryTreeModel *tree_model;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
return FM_DIRECTORY_TREE_MODEL_N_COLUMNS;
}
static GType
model_get_column_type (GtkTreeModel *model, gint index)
{
g_assert (FM_IS_DIRECTORY_TREE_MODEL (model));
switch (index) {
case FM_DIRECTORY_TREE_MODEL_FILE_COLUMN:
return NAUTILUS_TYPE_FILE;
case FM_DIRECTORY_TREE_MODEL_LOADING_COLUMN:
return G_TYPE_BOOLEAN;
default:
g_assert_not_reached ();
}
}
static gboolean
model_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
{
gint *indices;
gint depth, i;
GtkTreeIter parent;
depth = gtk_tree_path_get_depth (path);
indices = gtk_tree_path_get_indices (path);
if (! gtk_tree_model_iter_nth_child (model, iter, NULL, indices[0])) {
return FALSE;
}
for (i = 1; i < depth; i++) {
parent = *iter;
if (! gtk_tree_model_iter_nth_child (model, iter, &parent, indices[i])) {
return FALSE;
}
}
return TRUE;
}
static GtkTreePath *
model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
{
FMDirectoryTreeModel *tree_model;
Node *node, *parent;
GtkTreeIter parent_iter;
GtkTreePath *path;
int index;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_val_if_fail (tree_model->details->stamp == iter->stamp, NULL);
node = iter->user_data;
if (node == NULL) {
parent = iter->user_data2;
g_assert (node_has_dummy_child (parent));
index = 0;
} else if (node == tree_model->details->root) {
/* Internal case: outsiders should never get an iter pointing to the root */
return gtk_tree_path_new ();
} else {
parent = node->parent;
index = g_sequence_ptr_get_position (node->owner) + (node_has_dummy_child (parent) ? 1 : 0);
}
parent_iter.stamp = tree_model->details->stamp;
parent_iter.user_data = parent;
parent_iter.user_data2 = NULL;
parent_iter.user_data3 = NULL;
path = model_get_path (model, &parent_iter);
gtk_tree_path_append_index (path, index);
return path;
}
static void
model_get_value (GtkTreeModel *model, GtkTreeIter *iter, gint column, GValue *value)
{
FMDirectoryTreeModel *tree_model;
Node *node, *parent;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_if_fail (tree_model->details->stamp == iter->stamp);
node = iter->user_data;
switch (column) {
case FM_DIRECTORY_TREE_MODEL_FILE_COLUMN:
g_value_init (value, NAUTILUS_TYPE_FILE);
g_value_set_object (value, node == NULL ? NULL : node->file);
break;
case FM_DIRECTORY_TREE_MODEL_LOADING_COLUMN:
g_value_init (value, G_TYPE_BOOLEAN);
if (node == NULL) {
parent = iter->user_data2;
g_value_set_boolean (value, !parent->done_loading);
} else {
g_value_set_boolean (value, TRUE);
}
break;
default:
g_assert_not_reached ();
}
}
static gboolean
make_iter_invalid (GtkTreeIter *iter)
{
iter->stamp = 0;
iter->user_data = NULL;
iter->user_data2 = NULL;
iter->user_data3 = NULL;
return FALSE;
}
static gboolean
make_iter_for_dummy_child (Node *parent, GtkTreeIter *iter, int stamp)
{
g_assert (parent != NULL);
iter->stamp = stamp;
iter->user_data = NULL;
iter->user_data2 = parent;
iter->user_data3 = NULL;
return TRUE;
}
static gboolean
make_iter_for_node (Node *node, GtkTreeIter *iter, int stamp)
{
if (node == NULL) {
return make_iter_invalid (iter);
}
iter->stamp = stamp;
iter->user_data = node;
iter->user_data2 = NULL;
iter->user_data3 = NULL;
return TRUE;
}
static gboolean
model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
{
FMDirectoryTreeModel *tree_model;
Node *node, *parent;
GSequencePtr ptr;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_val_if_fail (tree_model->details->stamp == iter->stamp, FALSE);
node = iter->user_data;
if (node == NULL) {
parent = iter->user_data2;
g_assert (node_has_dummy_child (parent));
ptr = g_sequence_get_begin_ptr (parent->children);
} else {
ptr = g_sequence_ptr_next (node->owner);
}
if (g_sequence_ptr_is_end (ptr)) {
return make_iter_invalid (iter);
}
return make_iter_for_node (g_sequence_ptr_get_data (ptr),
iter, iter->stamp);
}
static gboolean
model_iter_children (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent_iter)
{
FMDirectoryTreeModel *tree_model;
Node *parent;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_val_if_fail (parent_iter == NULL || tree_model->details->stamp == parent_iter->stamp, FALSE);
if (parent_iter == NULL) {
parent = tree_model->details->root;
} else {
parent = parent_iter->user_data;
}
if (node_has_dummy_child (parent)) {
return make_iter_for_dummy_child (parent, iter, tree_model->details->stamp);
}
if (parent->children != NULL && g_sequence_get_length (parent->children) != 0) {
return make_iter_for_node (g_sequence_ptr_get_data (g_sequence_get_begin_ptr (parent->children)),
iter, tree_model->details->stamp);
}
return make_iter_invalid (iter);
}
static gboolean
model_iter_has_child (GtkTreeModel *model, GtkTreeIter *iter)
{
FMDirectoryTreeModel *tree_model;
Node *node;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_val_if_fail (tree_model->details->stamp == iter->stamp, FALSE);
node = iter->user_data;
return node != NULL && node->directory != NULL;
}
static gint
model_iter_n_children (GtkTreeModel *model, GtkTreeIter *iter)
{
FMDirectoryTreeModel *tree_model;
Node *parent;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_val_if_fail (iter == NULL || iter->stamp == tree_model->details->stamp, 0);
if (iter == NULL) {
parent = tree_model->details->root;
} else {
parent = iter->user_data;
}
if (parent == NULL || parent->directory == NULL) {
return 0;
}
return g_sequence_get_length (parent->children) + (node_has_dummy_child (parent) ? 1 : 0);
}
static gboolean
model_iter_nth_child (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent_iter, gint n)
{
FMDirectoryTreeModel *tree_model;
Node *parent;
GSequencePtr ptr;
int offset;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_val_if_fail (parent_iter == NULL
|| tree_model->details->stamp == parent_iter->stamp, FALSE);
if (parent_iter == NULL) {
parent = tree_model->details->root;
} else {
parent = parent_iter->user_data;
}
if (parent == NULL || parent->directory == NULL) {
return make_iter_invalid (iter);
}
if (node_has_dummy_child (parent)) {
if (n == 0) {
return make_iter_for_dummy_child (parent, iter, tree_model->details->stamp);
} else {
offset = 1;
}
} else {
offset = 0;
}
ptr = g_sequence_get_ptr_at_pos (parent->children, n - offset);
if (ptr == NULL || g_sequence_ptr_is_end (ptr)) {
return make_iter_invalid (iter);
}
return make_iter_for_node (g_sequence_ptr_get_data (ptr), iter, tree_model->details->stamp);
}
static gboolean
model_iter_parent (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *child_iter)
{
FMDirectoryTreeModel *tree_model;
Node *node, *parent;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_val_if_fail (tree_model->details->stamp == child_iter->stamp, FALSE);
node = child_iter->user_data;
if (node == NULL) {
parent = child_iter->user_data2;
} else {
parent = node->parent;
}
if (parent == tree_model->details->root) {
return make_iter_invalid (iter);
}
return make_iter_for_node (parent, iter, tree_model->details->stamp);
}
static void
stop_monitoring_directory (FMDirectoryTreeModel *model, Node *node)
{
g_assert (node->directory != NULL); // we only set callbacks on directories
if (node->done_loading_id == 0) {
g_assert (node->files_added_id == 0);
g_assert (node->files_changed_id == 0);
return;
}
//g_print ("Stopping monitoring : %s\n", nautilus_file_get_uri (node->file));
g_signal_handler_disconnect (node->directory, node->done_loading_id);
g_signal_handler_disconnect (node->directory, node->files_added_id);
g_signal_handler_disconnect (node->directory, node->files_changed_id);
node->done_loading_id = 0;
node->files_added_id = 0;
node->files_changed_id = 0;
nautilus_directory_file_monitor_remove (node->directory, model);
}
static void
report_dummy_row_contents_changed (FMDirectoryTreeModel *model, Node *parent)
{
GtkTreePath *path;
GtkTreeIter iter;
make_iter_for_dummy_child (parent, &iter, model->details->stamp);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
gtk_tree_path_free (path);
}
static void
report_dummy_row_inserted (FMDirectoryTreeModel *model, Node *parent)
{
GtkTreeIter iter;
GtkTreePath *path;
make_iter_for_dummy_child (parent, &iter, model->details->stamp);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
gtk_tree_path_free (path);
}
static void
report_dummy_row_deleted (FMDirectoryTreeModel *model, Node *parent, gboolean inserting_first_child)
{
GtkTreeIter iter;
GtkTreePath *path;
g_assert (!node_has_dummy_child (parent));
make_iter_for_node (parent, &iter, model->details->stamp);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
gtk_tree_path_append_index (path, inserting_first_child ? 1 : 0);
gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
gtk_tree_path_free (path);
parent->all_children_ref_count -= parent->dummy_child_ref_count;
parent->dummy_child_ref_count = 0;
}
static void
set_done_loading (FMDirectoryTreeModel *model, Node *node, gboolean done_loading)
{
gboolean had_dummy;
if (node->done_loading == done_loading) {
return;
}
had_dummy = node_has_dummy_child (node);
node->done_loading = done_loading;
if (done_loading) {
decrement_loading_count (model);
}
if (node_has_dummy_child (node)) {
if (had_dummy) {
report_dummy_row_contents_changed (model, node);
} else {
report_dummy_row_inserted (model, node);
}
} else {
if (had_dummy) {
report_dummy_row_deleted (model, node, FALSE);
} else {
g_assert_not_reached ();
}
}
}
static int
node_cmp_func (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
Node *nodea, *nodeb;
/*FMDirectoryTreeModel *model;
model = (FMDirectoryTreeModel *)model;*/
nodea = (Node *)a;
nodeb = (Node *)b;
return nautilus_file_compare_for_sort (nodea->file, nodeb->file,
NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
TRUE, FALSE);
}
static Node *
partially_create_node (FMDirectoryTreeModel *model, NautilusFile *file)
{
Node *node;
g_assert (g_hash_table_lookup (model->details->file_to_node, file) == NULL);
node = g_new0 (Node, 1);
node->model = model;
node->file = nautilus_file_ref (file);
g_hash_table_insert (model->details->file_to_node, file, node);
return node;
}
static void
update_node (FMDirectoryTreeModel *model, Node *node)
{
GtkTreePath *path;
GtkTreeIter iter;
if (node->directory == NULL && nautilus_file_is_directory (node->file)) {
node->directory = nautilus_directory_get_for_file (node->file);
node->children = g_sequence_new (NULL);
} else if (node->directory != NULL && !nautilus_file_is_directory (node->file)) {
stop_monitoring_directory (model, node);
make_iter_for_node (node, &iter, model->details->stamp);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
destroy_children (model, node, path, TRUE);
gtk_tree_path_free (path);
nautilus_directory_unref (node->directory);
g_sequence_free (node->children);
}
}
static void
report_node_inserted (FMDirectoryTreeModel *model, Node *node, GtkTreePath *path)
{
GtkTreeIter iter;
GSequencePtr ptr;
//g_print ("Inserting : %s at %s\n", nautilus_file_get_uri (node->file), gtk_tree_path_to_string (path));
node->ref_count = 0;
if (node->children) {
node->all_children_ref_count = 0;
node->dummy_child_ref_count = 0;
}
make_iter_for_node (node, &iter, model->details->stamp);
gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
if (node->children) {
gtk_tree_path_down (path);
if (node_has_dummy_child (node)) {
//g_print (" with dummy node at %s\n", gtk_tree_path_to_string (path));
make_iter_for_dummy_child (node, &iter, model->details->stamp);
gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
gtk_tree_path_next (path);
}
for (ptr = g_sequence_get_begin_ptr (node->children); !g_sequence_ptr_is_end (ptr); ptr = g_sequence_ptr_next (ptr)) {
report_node_inserted (model, g_sequence_ptr_get_data (ptr), path);
gtk_tree_path_next (path);
}
gtk_tree_path_up (path);
}
}
static void
insert_node (FMDirectoryTreeModel *model, Node *parent, Node *node)
{
GtkTreePath *path;
GtkTreeIter iter;
gboolean parent_was_empty;
g_assert (parent != NULL);
g_assert (parent->directory != NULL && parent->children != NULL);
parent_was_empty = (g_sequence_get_length (parent->children) == 0);
node->parent = parent;
node->owner = g_sequence_insert_sorted (parent->children, node, node_cmp_func, model);
update_node (model, node);
make_iter_for_node (node, &iter, model->details->stamp);
path = model_get_path (GTK_TREE_MODEL (model), &iter);
report_node_inserted (model, node, path);
gtk_tree_path_free (path);
if (parent_was_empty && !node_has_dummy_child (parent)) {
report_dummy_row_deleted (model, parent, TRUE);
}
}
static void
files_changed_callback (NautilusDirectory *directory,
GList *changed_files,
gpointer callback_data)
{
FMDirectoryTreeModel *model;
NautilusFile *file, *parent_file;
Node *parent, *node, *new_parent;
GtkTreeIter iter;
GtkTreePath *path;
GList *elem;
gboolean parent_had_dummy_child, not_in_this_directory;
gboolean had_dummy_child, had_directory;
gboolean has_dummy_child, has_directory;
parent = (Node *)callback_data;
g_assert (parent != NULL);
model = parent->model;
for (elem = changed_files; elem != NULL; elem = elem->next) {
file = NAUTILUS_FILE (elem->data);
//g_print ("(%p(%p)) : File changed: %s : ", model, parent, nautilus_file_get_uri (file));
node = g_hash_table_lookup (model->details->file_to_node, file);
if (node != NULL) {
make_iter_for_node (node, &iter, model->details->stamp);
path = model_get_path (GTK_TREE_MODEL (model), &iter);
if (nautilus_file_is_gone (file) || !nautilus_file_should_show (file, FALSE, FALSE)) {
new_parent = NULL;
not_in_this_directory = TRUE;
} else if (!nautilus_directory_contains_file (parent->directory, file)) {
parent_file = nautilus_file_get_parent (file);
new_parent = g_hash_table_lookup (model->details->file_to_node, parent_file);
nautilus_file_unref (parent_file);
not_in_this_directory = TRUE;
} else {
not_in_this_directory = FALSE;
}
if (not_in_this_directory) {
/* This node needs reparenting, or removal */
parent_had_dummy_child = node_has_dummy_child (parent);
g_sequence_remove (node->owner);
parent->all_children_ref_count -= node->ref_count;
node->ref_count = 0;
node->parent = NULL;
if (node_has_dummy_child (parent) && !parent_had_dummy_child) {
report_dummy_row_inserted (model, parent);
gtk_tree_path_next (path);
}
gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
if (new_parent != NULL && new_parent->all_children_ref_count != 0) {
insert_node (model, new_parent, node);
} else {
destroy_node (model, node, NULL, FALSE);
}
schedule_check_monitoring_cessation (model);
} else {
had_dummy_child = node_has_dummy_child (node);
had_directory = node->directory != NULL;
update_node (model, node);
has_dummy_child = node_has_dummy_child (node);
has_directory = node->directory != NULL;
if (had_dummy_child != has_dummy_child) {
if (has_dummy_child) {
report_dummy_row_inserted (model, node);
} else {
report_dummy_row_deleted (model, node, FALSE);
}
}
if (had_directory != has_directory) {
gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
}
gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
}
gtk_tree_path_free (path);
} else {
if (nautilus_file_should_show (file, FALSE, FALSE)) {
node = partially_create_node (model, file);
insert_node (model, parent, node);
}
}
}
}
static void
done_loading_callback (NautilusDirectory *directory,
gpointer callback_data)
{
Node *node;
node = (Node *)callback_data;
set_done_loading (node->model, node, TRUE);
}
static void
start_monitoring_directory (FMDirectoryTreeModel *model, Node *node)
{
g_assert (node->directory != NULL); /* we only set callbacks on directories */
if (node->done_loading_id != 0) {
g_assert (node->files_added_id != 0);
g_assert (node->files_changed_id != 0);
return;
}
//g_print ("Start monitoring: %s in %p(%p)\n", nautilus_file_get_uri (node->file), model, node);
g_assert (node->files_added_id == 0);
g_assert (node->files_changed_id == 0);
node->done_loading_id = g_signal_connect
(node->directory, "done_loading",
G_CALLBACK (done_loading_callback), node);
node->files_added_id = g_signal_connect
(node->directory, "files_added",
G_CALLBACK (files_changed_callback), node);
node->files_changed_id = g_signal_connect
(node->directory, "files_changed",
G_CALLBACK (files_changed_callback), node);
nautilus_directory_file_monitor_add (node->directory, model,
FALSE, FALSE,
model->details->attributes,
files_changed_callback, node);
increment_loading_count (model);
set_done_loading (model, node, nautilus_directory_are_all_files_seen (node->directory));
}
static void
check_for_monitoring_cessation_at_node (FMDirectoryTreeModel *model, Node *node, GtkTreePath *path)
{
GSequencePtr ptr;
if (node->directory == NULL) {
return;
}
if (node->all_children_ref_count == 0) {
stop_monitoring_directory (model, node);
destroy_children (model, node, path, FALSE);
set_done_loading (model, node, FALSE);
} else {
gtk_tree_path_down (path);
for (ptr = g_sequence_get_begin_ptr (node->children);
!g_sequence_ptr_is_end (ptr);
ptr = g_sequence_ptr_next (ptr)) {
check_for_monitoring_cessation_at_node (model, g_sequence_ptr_get_data (ptr), path);
gtk_tree_path_next (path);
}
gtk_tree_path_up (path);
}
}
static gboolean
check_for_monitoring_cessation_callback (gpointer callback_data)
{
FMDirectoryTreeModel *model;
GtkTreePath *path;
model = FM_DIRECTORY_TREE_MODEL (callback_data);
model->details->check_for_monitoring_cessation_timeout_id = 0;
path = gtk_tree_path_new ();
check_for_monitoring_cessation_at_node (model, model->details->root, path);
gtk_tree_path_free (path);
return FALSE;
}
static void
schedule_check_monitoring_cessation (FMDirectoryTreeModel *model)
{
if (model->details->check_for_monitoring_cessation_timeout_id != 0) {
g_source_remove (model->details->check_for_monitoring_cessation_timeout_id);
}
model->details->check_for_monitoring_cessation_timeout_id =
g_timeout_add (5000, check_for_monitoring_cessation_callback, model);
}
static void
ensure_monitoring_at_node (FMDirectoryTreeModel *model, Node *node)
{
GSequencePtr ptr;
if (node->directory == NULL || node->all_children_ref_count == 0) {
return;
}
for (ptr = g_sequence_get_begin_ptr (node->children);
!g_sequence_ptr_is_end (ptr);
ptr = g_sequence_ptr_next (ptr)) {
ensure_monitoring_at_node (model, g_sequence_ptr_get_data (ptr));
}
start_monitoring_directory (model, node);
}
static gboolean
ensure_monitoring_callback (gpointer callback_data)
{
FMDirectoryTreeModel *model;
model = FM_DIRECTORY_TREE_MODEL (callback_data);
model->details->ensure_monitoring_idle_id = 0;
ensure_monitoring_at_node (model, model->details->root);
return FALSE;
}
static void
schedule_ensure_monitoring (FMDirectoryTreeModel *model)
{
if (model->details->ensure_monitoring_idle_id == 0) {
model->details->ensure_monitoring_idle_id =
g_idle_add (ensure_monitoring_callback, model);
}
}
static void
model_ref_node (GtkTreeModel *model, GtkTreeIter *iter)
{
FMDirectoryTreeModel *tree_model;
Node *node, *parent;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_if_fail (tree_model->details->stamp == iter->stamp);
node = iter->user_data;
if (node == NULL) {
parent = iter->user_data2;
parent->dummy_child_ref_count++;
//g_print ("Reffing (%d) dummy node under: %s\n", parent->dummy_child_ref_count, nautilus_file_get_uri (parent->file));
} else {
parent = node->parent;
node->ref_count++;
//g_print ("Reffing (%d) node: %s\n", node->ref_count, nautilus_file_get_uri (node->file));
}
g_assert (parent->all_children_ref_count >= 0);
if (++parent->all_children_ref_count == 1) {
schedule_ensure_monitoring (tree_model);
}
//g_print ("All child rc = %d, for: %s\n", parent->all_children_ref_count, nautilus_file_get_uri (parent->file));
}
static void
model_unref_node (GtkTreeModel *model, GtkTreeIter *iter)
{
FMDirectoryTreeModel *tree_model;
Node *node, *parent;
tree_model = FM_DIRECTORY_TREE_MODEL (model);
g_return_if_fail (tree_model->details->stamp == iter->stamp);
node = iter->user_data;
if (node == NULL) {
parent = iter->user_data2;
parent->dummy_child_ref_count--;
//g_print ("UnReffing (%d) dummy node under: %s\n", parent->dummy_child_ref_count, nautilus_file_get_uri (parent->file));
} else {
parent = node->parent;
node->ref_count--;
//g_print ("UnReffing (%d) node: %s\n", node->ref_count, nautilus_file_get_uri (node->file));
}
g_assert (parent->all_children_ref_count > 0);
if (--parent->all_children_ref_count == 0) {
schedule_check_monitoring_cessation (tree_model);
}
//g_print ("All child rc = %d, for: %s\n", parent->all_children_ref_count, nautilus_file_get_uri (parent->file));
}
static Node *
make_new_root_node (FMDirectoryTreeModel *model, const char *uri)
{
Node *node;
node = g_new0 (Node, 1);
node->model = model;
node->owner = NULL;
node->parent = NULL;
node->directory = nautilus_directory_get (uri);
node->file = nautilus_directory_get_corresponding_file (node->directory);
node->all_children_ref_count = 0;
node->children = g_sequence_new (NULL);
node->done_loading = 0;
return node;
}
static void destroy_children (FMDirectoryTreeModel *model, Node *node, GtkTreePath *path, gboolean include_dummy)
{
GSequencePtr ptr, next;
Node *child;
if (path != NULL) {
gtk_tree_path_down (path);
}
if (node_has_dummy_child (node)) {
if (include_dummy) {
node->all_children_ref_count -= node->dummy_child_ref_count;
node->dummy_child_ref_count = 0;
}
if (path != NULL) {
if (include_dummy) {
//g_print ("Removing dummy node under: %s\n", nautilus_file_get_uri (node->file));
gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
} else {
gtk_tree_path_next (path);
}
}
}
for (ptr = g_sequence_get_begin_ptr (node->children); !g_sequence_ptr_is_end (ptr); ) {
child = g_sequence_ptr_get_data (ptr);
destroy_node (model, child, path, include_dummy);
next = g_sequence_ptr_next (ptr);
g_sequence_remove (ptr);
ptr = next;
}
if (path != NULL) {
gtk_tree_path_up (path);
}
}
static void
destroy_node (FMDirectoryTreeModel *model, Node *node, GtkTreePath *path, gboolean include_dummy)
{
if (node->directory != NULL) {
stop_monitoring_directory (model, node);
destroy_children (model, node, path, include_dummy);
nautilus_directory_unref (node->directory);
g_sequence_free (node->children);
}
if (node->parent != NULL) {
node->parent->all_children_ref_count -= node->ref_count;
}
//g_print ("Removing (%d): %s\n", node->ref_count, nautilus_file_get_uri (node->file));
g_hash_table_remove (node->model->details->file_to_node, node->file);
nautilus_file_unref (node->file);
g_free (node);
if (path != NULL && node != model->details->root) {
gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
}
}
void
fm_directory_tree_model_set_directory (FMDirectoryTreeModel *model,
const char *uri)
{
GtkTreePath *path;
g_assert (FM_IS_DIRECTORY_TREE_MODEL (model));
if (model->details->root != NULL) {
path = gtk_tree_path_new ();
destroy_node (model, model->details->root, path, TRUE);
gtk_tree_path_free (path);
}
model->details->root = make_new_root_node (model, uri);
g_hash_table_insert (model->details->file_to_node,
model->details->root->file,
model->details->root);
/* Report insertion of the initial "Loading..." row */
report_dummy_row_inserted (model, model->details->root);
}
void
fm_directory_tree_model_set_attributes (FMDirectoryTreeModel *model, NautilusFileAttributes attributes)
{
model->details->attributes = attributes | NAUTILUS_FILE_ATTRIBUTE_IS_DIRECTORY;
}
static void
tree_model_iface_init (GtkTreeModelIface *iface)
{
iface->get_flags = model_get_flags;
iface->get_n_columns = model_get_n_columns;
iface->get_column_type = model_get_column_type;
iface->get_iter = model_get_iter;
iface->get_path = model_get_path;
iface->get_value = model_get_value;
iface->iter_next = model_iter_next;
iface->iter_children = model_iter_children;
iface->iter_has_child = model_iter_has_child;
iface->iter_n_children = model_iter_n_children;
iface->iter_nth_child = model_iter_nth_child;
iface->iter_parent = model_iter_parent;
iface->ref_node = model_ref_node;
iface->unref_node = model_unref_node;
}
static void
fm_directory_tree_model_finalize (GObject *object)
{
FMDirectoryTreeModel *model;
model = FM_DIRECTORY_TREE_MODEL (object);
if (model->details->check_for_monitoring_cessation_timeout_id != 0) {
g_source_remove (model->details->check_for_monitoring_cessation_timeout_id);
}
if (model->details->ensure_monitoring_idle_id != 0) {
g_source_remove (model->details->ensure_monitoring_idle_id);
}
destroy_node (model, model->details->root, NULL, TRUE);
g_hash_table_destroy (model->details->file_to_node);
g_free (model->details);
G_OBJECT_CLASS (fm_directory_tree_model_parent_class)->finalize (object);
}
static void
fm_directory_tree_model_class_init (FMDirectoryTreeModelClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = fm_directory_tree_model_finalize;
directory_tree_model_signals[START_LOADING] =
g_signal_new ("start_loading",
FM_TYPE_DIRECTORY_TREE_MODEL,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (FMDirectoryTreeModelClass, start_loading),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
directory_tree_model_signals[STOP_LOADING] =
g_signal_new ("stop_loading",
FM_TYPE_DIRECTORY_TREE_MODEL,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (FMDirectoryTreeModelClass, stop_loading),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
fm_directory_tree_model_init (FMDirectoryTreeModel *model)
{
model->details = g_new0 (FMDirectoryTreeModelDetails, 1);
model->details->file_to_node = g_hash_table_new (g_direct_hash, g_direct_equal);
do {
model->details->stamp = g_random_int ();
} while (model->details->stamp == 0);
model->details->attributes = NAUTILUS_FILE_ATTRIBUTE_IS_DIRECTORY;
}
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
#ifndef FM_DIRECTORY_TREE_MODEL_H
#define FM_DIRECTORY_TREE_MODEL_H
#include <glib-object.h>
#include <libnautilus-private/nautilus-file-attributes.h>
#define FM_TYPE_DIRECTORY_TREE_MODEL (fm_directory_tree_model_get_type ())
#define FM_DIRECTORY_TREE_MODEL(obj) (GTK_CHECK_CAST ((obj), FM_TYPE_DIRECTORY_TREE_MODEL, FMDirectoryTreeModel))
#define FM_DIRECTORY_TREE_MODEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), FM_TYPE_DIRECTORY_TREE_MODEL, FMDirectoryTreeModelClass))
#define FM_IS_DIRECTORY_TREE_MODEL(obj) (GTK_CHECK_TYPE ((obj), FM_TYPE_DIRECTORY_TREE_MODEL))
#define FM_IS_DIRECTORY_TREE_MODEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), FM_TYPE_DIRECTORY_TREE_MODEL))
typedef struct FMDirectoryTreeModelDetails FMDirectoryTreeModelDetails;
typedef struct {
GObject parent;
FMDirectoryTreeModelDetails *details;
} FMDirectoryTreeModel;
typedef struct {
GObjectClass parent_class;
/* Signals */
void (*start_loading) (void);
void (*stop_loading) (void);
} FMDirectoryTreeModelClass;
enum {
FM_DIRECTORY_TREE_MODEL_FILE_COLUMN,
FM_DIRECTORY_TREE_MODEL_LOADING_COLUMN,
FM_DIRECTORY_TREE_MODEL_N_COLUMNS
};
GType fm_directory_tree_model_get_type (void);
void fm_directory_tree_model_set_directory (FMDirectoryTreeModel *model,
const char *uri);
void fm_directory_tree_model_set_attributes (FMDirectoryTreeModel *model,
NautilusFileAttributes attributes);
#endif /* FM_DIRECTORY_TREE_MODEL_H */
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
#include "fm-directory-tree-view.h"
#include <gtk/gtk.h>
#include <eel/eel-cell-renderer-pixbuf-list.h>
#include <libnautilus-private/nautilus-view.h>
#include <libnautilus-private/nautilus-view-factory.h>
#include <libnautilus-private/nautilus-window-info.h>
#include <libnautilus-private/nautilus-tree-view-drag-dest.h>
#include <libnautilus-private/nautilus-icon-factory.h>
#include "fm-directory-tree-model.h"
struct FMDirectoryTreeViewDetails {
NautilusWindowInfo *window;
GtkWidget *view;
FMDirectoryTreeModel *model;
char *uri;
NautilusTreeViewDragDest *drag_dest;
guint initial_load : 1;
};
static void fm_directory_tree_view_iface_init (NautilusViewIface *iface);
G_DEFINE_TYPE_WITH_CODE (FMDirectoryTreeView, fm_directory_tree_view, GTK_TYPE_SCROLLED_WINDOW,
G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_VIEW,
fm_directory_tree_view_iface_init));
static const char *
fm_directory_tree_view_get_id (NautilusView *view)
{
return FM_DIRECTORY_TREE_VIEW_ID;
}
static GtkWidget *
fm_directory_tree_view_get_widget (NautilusView *view)
{
return GTK_WIDGET (view);
}
static void
fm_directory_tree_view_load_location (NautilusView *view,
const char *location)
{
FMDirectoryTreeView *directory_tree_view;
directory_tree_view = FM_DIRECTORY_TREE_VIEW (view);
fm_directory_tree_model_set_directory (directory_tree_view->details->model, location);
if (directory_tree_view->details->uri != NULL) {
g_free (directory_tree_view->details->uri);
}
directory_tree_view->details->uri = g_strdup (location);
}
static void
fm_directory_tree_view_model_start_loading (FMDirectoryTreeModel *model, gpointer user_data)
{
FMDirectoryTreeView *directory_tree_view;
directory_tree_view = FM_DIRECTORY_TREE_VIEW (user_data);
nautilus_window_info_report_load_underway (directory_tree_view->details->window, NAUTILUS_VIEW (directory_tree_view));
if (directory_tree_view->details->initial_load) {
nautilus_window_info_show_window (directory_tree_view->details->window);
directory_tree_view->details->initial_load = FALSE;
}
}
static void
fm_directory_tree_view_model_stop_loading (FMDirectoryTreeModel *model, gpointer user_data)
{
FMDirectoryTreeView *directory_tree_view;
directory_tree_view = FM_DIRECTORY_TREE_VIEW (user_data);
nautilus_window_info_report_load_complete (directory_tree_view->details->window, NAUTILUS_VIEW (directory_tree_view));
}
static void
fm_directory_tree_view_stop_loading (NautilusView *view)
{
}
static int
fm_directory_tree_view_get_selection_count (NautilusView *view)
{
return 0;
}
static GList *
fm_directory_tree_view_get_selection (NautilusView *view)
{
return NULL;
}
static void
fm_directory_tree_view_set_selection (NautilusView *view, GList *new_selection)
{
}
static char *
fm_directory_tree_view_get_first_visible_file (NautilusView *view)
{
return g_strdup ("");
}
static void
fm_directory_tree_view_scroll_to_file (NautilusView *view, const char *uri)
{
}
static gboolean
fm_directory_tree_view_supports_zooming (NautilusView *view)
{
return FALSE;
}
static void
fm_directory_tree_view_bump_zoom_level (NautilusView *view, int increment)
{
}
static void
fm_directory_tree_view_zoom_to_level (NautilusView *view, NautilusZoomLevel level)
{
}
static NautilusZoomLevel
fm_directory_tree_view_get_zoom_level (NautilusView *view)
{
return NAUTILUS_ZOOM_LEVEL_STANDARD;
}
static void
fm_directory_tree_view_restore_default_zoom_level (NautilusView *view)
{
}
static gboolean
fm_directory_tree_view_can_zoom_in (NautilusView *view)
{
return FALSE;
}
static gboolean
fm_directory_tree_view_can_zoom_out (NautilusView *view)
{
return FALSE;
}
static void
fm_directory_tree_view_iface_init (NautilusViewIface *iface)
{
iface->get_view_id = fm_directory_tree_view_get_id;
iface->get_widget = fm_directory_tree_view_get_widget;
iface->load_location = fm_directory_tree_view_load_location;
iface->stop_loading = fm_directory_tree_view_stop_loading;
iface->get_selection_count = fm_directory_tree_view_get_selection_count;
iface->get_selection = fm_directory_tree_view_get_selection;
iface->set_selection = fm_directory_tree_view_set_selection;
iface->get_first_visible_file = fm_directory_tree_view_get_first_visible_file;
iface->scroll_to_file = fm_directory_tree_view_scroll_to_file;
iface->supports_zooming = fm_directory_tree_view_supports_zooming;
iface->bump_zoom_level = fm_directory_tree_view_bump_zoom_level;
iface->zoom_to_level = fm_directory_tree_view_zoom_to_level;
iface->get_zoom_level = fm_directory_tree_view_get_zoom_level;
iface->restore_default_zoom_level = fm_directory_tree_view_restore_default_zoom_level;
iface->can_zoom_in = fm_directory_tree_view_can_zoom_in;
iface->can_zoom_out = fm_directory_tree_view_can_zoom_out;
}
static void
fm_directory_tree_view_finalize (GObject *object)
{
FMDirectoryTreeView *view;
view = FM_DIRECTORY_TREE_VIEW (object);
g_object_unref (view->details->model);
g_free (view->details->uri);
g_object_unref (view->details->drag_dest);
g_free (view->details);
G_OBJECT_CLASS (fm_directory_tree_view_parent_class)->finalize (object);
}
static void
fm_directory_tree_view_destroy (GtkObject *object)
{
/* unmerge ui stuff here */
GTK_OBJECT_CLASS (fm_directory_tree_view_parent_class)->destroy (object);
}
static char *
get_root_uri_callback (NautilusTreeViewDragDest *dest,
gpointer user_data)
{
FMDirectoryTreeView *view;
view = FM_DIRECTORY_TREE_VIEW (user_data);
return g_strdup (view->details->uri);
}
static NautilusFile *
get_file_for_path_callback (NautilusTreeViewDragDest *dest,
GtkTreePath *path,
gpointer user_data)
{
FMDirectoryTreeView *view;
GtkTreeIter iter;
NautilusFile *file;
view = FM_DIRECTORY_TREE_VIEW (user_data);
file = NULL;
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model),
&iter, path)) {
gtk_tree_model_get (GTK_TREE_MODEL (view->details->model),
&iter,
FM_DIRECTORY_TREE_MODEL_FILE_COLUMN,
&file,
-1);
}
return file;
}
static void
move_copy_items_callback (NautilusTreeViewDragDest *dest,
const GList *item_uris,
const char *target_uri,
guint action,
int x,
int y,
gpointer user_data)
{
const GList *ptr;
g_print ("Copying/Moving uris to %s:\n", target_uri);
for (ptr = item_uris; ptr != NULL; ptr = ptr->next) {
g_print ("URI: %s\n", (char*)ptr->data);
}
}
static void
row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
gpointer user_data)
{
FMDirectoryTreeView *view;
view = FM_DIRECTORY_TREE_VIEW (user_data);
if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (view->details->view), path)) {
gtk_tree_view_collapse_row (GTK_TREE_VIEW (view->details->view), path);
} else {
gtk_tree_view_expand_row (GTK_TREE_VIEW (view->details->view), path, FALSE);
}
/*if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model), &iter, path)) {
gtk_tree_model_get (GTK_TREE_MODEL (view->details->model), &iter,
FM_DIRECTORY_TREE_MODEL_FILE_COLUMN, &file,
-1);
uri = nautilus_file_get_uri (file);
nautilus_window_info_open_location (view->details->window,
uri,
NAUTILUS_WINDOW_OPEN_ACCORDING_TO_MODE,
0,
NULL);
g_free (uri);
}*/
}
static gboolean
popup_menu_callback (GtkWidget *widget, gpointer callback_data)
{
FMDirectoryTreeView *view;
view = FM_DIRECTORY_TREE_VIEW (callback_data);
g_print ("popup_menu_callback\n");
return TRUE;
}
static gboolean
button_release_callback (GtkWidget *widget,
GdkEventButton *event,
gpointer callback_data)
{
FMDirectoryTreeView *view;
view = FM_DIRECTORY_TREE_VIEW (callback_data);
return FALSE;
}
static gboolean
button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callback_data)
{
FMDirectoryTreeView *view;
view = FM_DIRECTORY_TREE_VIEW (callback_data);
/*if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (view->details->view))) {
return FALSE;
}*/
return FALSE;
}
static gboolean
motion_notify_callback (GtkWidget *widget, GdkEventMotion *event, gpointer callback_data)
{
FMDirectoryTreeView *view;
view = FM_DIRECTORY_TREE_VIEW (callback_data);
return FALSE;
}
/*
static void
drag_data_get_callback (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time)
{
}*/
static void
fm_directory_tree_view_class_init (FMDirectoryTreeViewClass *klass)
{
GtkScrolledWindowClass *scrolled_window_class;
scrolled_window_class = GTK_SCROLLED_WINDOW_CLASS (klass);
scrolled_window_class->scrollbar_spacing = 0;
G_OBJECT_CLASS (klass)->finalize = fm_directory_tree_view_finalize;
GTK_OBJECT_CLASS (klass)->destroy = fm_directory_tree_view_destroy;
}
static void
name_renderer_data_func (GtkCellLayout *column,
GtkCellRenderer *renderer,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
FMDirectoryTreeView *view;
NautilusFile *file;
gboolean loading;
char *name;
view = FM_DIRECTORY_TREE_VIEW (data);
file = NULL;
gtk_tree_model_get (model, iter,
FM_DIRECTORY_TREE_MODEL_FILE_COLUMN, &file,
FM_DIRECTORY_TREE_MODEL_LOADING_COLUMN, &loading,
-1);
if (file != NULL) {
name = nautilus_file_get_display_name (file);
} else {
name = g_strdup (loading ? "Loading ..." : "Empty");
}
g_object_set (G_OBJECT (renderer),
"text", name,
"style", file == NULL ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL,
"underline", file == NULL ? PANGO_UNDERLINE_NONE : PANGO_UNDERLINE_SINGLE,
NULL);
g_free (name);
if (file != NULL) {
nautilus_file_unref (file);
}
}
static void
icon_renderer_data_func (GtkCellLayout *column,
GtkCellRenderer *renderer,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
FMDirectoryTreeView *view;
NautilusFile *file;
GdkPixbuf *opened, *closed;
view = FM_DIRECTORY_TREE_VIEW (data);
file = NULL;
gtk_tree_model_get (model, iter,
FM_DIRECTORY_TREE_MODEL_FILE_COLUMN, &file,
-1);
if (file != NULL) {
closed = nautilus_icon_factory_get_pixbuf_for_file_force_size (file, NULL, NAUTILUS_ICON_SIZE_SMALLEST);
opened = nautilus_icon_factory_get_pixbuf_for_file_force_size (file, "accept", NAUTILUS_ICON_SIZE_SMALLEST);
g_object_set (G_OBJECT (renderer),
"pixbuf", closed, "pixbuf-expander-closed", closed, "pixbuf-expander-open", opened, NULL);
g_object_unref (closed);
g_object_unref (opened);
nautilus_file_unref (file);
} else {
g_object_set (G_OBJECT (renderer),
"pixbuf", NULL, "pixbuf-expander-closed", NULL, "pixbuf-expander-open", NULL, NULL);
}
}
static void
fm_directory_tree_view_init (FMDirectoryTreeView *view)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
view->details = g_new0 (FMDirectoryTreeViewDetails, 1);
view->details->initial_load = TRUE;
/* Model stuff */
view->details->model = g_object_new (FM_TYPE_DIRECTORY_TREE_MODEL, NULL);
g_signal_connect_object (view->details->model,
"start_loading",
G_CALLBACK (fm_directory_tree_view_model_start_loading),
view, 0);
g_signal_connect_object (view->details->model,
"stop_loading",
G_CALLBACK (fm_directory_tree_view_model_stop_loading),
view, 0);
fm_directory_tree_model_set_attributes (view->details->model,
nautilus_icon_factory_get_required_file_attributes ()
| NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME);
/* View stuff */
view->details->view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (view->details->model));
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->view)), GTK_SELECTION_MULTIPLE);
column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_title (column, "Name");
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, FALSE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer, icon_renderer_data_func, view, NULL);
renderer = gtk_cell_renderer_text_new ();
g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, TRUE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer, name_renderer_data_func, view, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (view->details->view), GTK_TREE_VIEW_COLUMN (column));
/*g_signal_connect_object (G_OBJECT (view->details->view), "drag_data_get",
G_CALLBACK (drag_data_get_callback), view, 0);*/
g_signal_connect_object (G_OBJECT (view->details->view), "motion_notify_event",
G_CALLBACK (motion_notify_callback), view, 0);
g_signal_connect_object (G_OBJECT (view->details->view), "button_press_event",
G_CALLBACK (button_press_callback), view, 0);
g_signal_connect_object (G_OBJECT (view->details->view), "button_release_event",
G_CALLBACK (button_release_callback), view, 0);
g_signal_connect_object (G_OBJECT (view->details->view), "popup_menu",
G_CALLBACK (popup_menu_callback), view, 0);
g_signal_connect (G_OBJECT (view->details->view), "row-activated",
G_CALLBACK (row_activated), view);
/* Drag and drop stuff */
view->details->drag_dest =
nautilus_tree_view_drag_dest_new (GTK_TREE_VIEW (view->details->view));
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);
/* g_signal_connect_object (view->details->drag_dest, "handle_url",
G_CALLBACK (list_view_handle_url), view, 0);
g_signal_connect_object (view->details->drag_dest, "handle_uri_list",
G_CALLBACK (list_view_handle_uri_list), view, 0);*/
/* Scrolled Window Stuff */
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_widget_show (view->details->view);
gtk_container_add (GTK_CONTAINER (view), view->details->view);
}
static NautilusView *
fm_directory_tree_view_create (NautilusWindowInfo *window)
{
FMDirectoryTreeView *view;
view = g_object_new (FM_TYPE_DIRECTORY_TREE_VIEW, NULL);
view->details->window = window;
g_object_ref (G_OBJECT (view));
gtk_object_sink (GTK_OBJECT (view));
return NAUTILUS_VIEW (view);
}
static gboolean
fm_directory_tree_view_supports_uri (const char *uri,
GnomeVFSFileType file_type,
const char *mime_type)
{
if (file_type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
return TRUE;
}
if (g_str_has_prefix (uri, "trash:")) {
return TRUE;
}
return FALSE;
}
static NautilusViewInfo fm_directory_tree_view = {
FM_DIRECTORY_TREE_VIEW_ID,
"Tree View",
"View as Tree",
"View as _Tree",
"The tree view has encountered an error.",
"The tree view encountered an error while starting up.",
"Display this location with the tree view.",
fm_directory_tree_view_create,
fm_directory_tree_view_supports_uri
};
void
fm_directory_tree_view_register (void)
{
nautilus_view_factory_register (&fm_directory_tree_view);
}
#ifndef FM_DIRECTORY_TREE_VIEW_H
#define FM_DIRECTORY_TREE_VIEW_H
#include <gtk/gtkscrolledwindow.h>
typedef struct FMDirectoryTreeView FMDirectoryTreeView;
typedef struct FMDirectoryTreeViewClass FMDirectoryTreeViewClass;
#define FM_TYPE_DIRECTORY_TREE_VIEW (fm_directory_tree_view_get_type ())
#define FM_DIRECTORY_TREE_VIEW(obj) (GTK_CHECK_CAST ((obj), FM_TYPE_DIRECTORY_TREE_VIEW, FMDirectoryTreeView))
#define FM_DIRECTORY_TREE_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), FM_TYPE_DIRECTORY_TREE_VIEW, FMDirectoryTreeViewClass))
#define FM_IS_DIRECTORY_TREE_VIEW(obj) (GTK_CHECK_TYPE ((obj), FM_TYPE_DIRECTORY_TREE_VIEW))
#define FM_IS_DIRECTORY_TREE_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), FM_TYPE_DIRECTORY_TREE_VIEW))
#define FM_DIRECTORY_TREE_VIEW_ID "OAFID:Nautilus_File_Manager_Directory_Tree_View"
typedef struct FMDirectoryTreeViewDetails FMDirectoryTreeViewDetails;
struct FMDirectoryTreeView {
GtkScrolledWindow parent;
FMDirectoryTreeViewDetails *details;
};
struct FMDirectoryTreeViewClass {
GtkScrolledWindowClass parent_class;
};
GType fm_directory_tree_view_get_type (void);
void fm_directory_tree_view_register (void);
#endif /* FM_DIRECTORY_TREE_VIEW_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]