aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Toshok <toshok@helixcode.com>2000-09-01 17:05:56 +0800
committerChris Toshok <toshok@src.gnome.org>2000-09-01 17:05:56 +0800
commit943c181c658d64e2e89026db65613c905ffe9f25 (patch)
treee1acb10a097618e739915936e1315b9966d8ac38
parent0a380243b1363ab2477a8fd846d4fae92bb24912 (diff)
downloadgsoc2013-evolution-943c181c658d64e2e89026db65613c905ffe9f25.tar
gsoc2013-evolution-943c181c658d64e2e89026db65613c905ffe9f25.tar.gz
gsoc2013-evolution-943c181c658d64e2e89026db65613c905ffe9f25.tar.bz2
gsoc2013-evolution-943c181c658d64e2e89026db65613c905ffe9f25.tar.lz
gsoc2013-evolution-943c181c658d64e2e89026db65613c905ffe9f25.tar.xz
gsoc2013-evolution-943c181c658d64e2e89026db65613c905ffe9f25.tar.zst
gsoc2013-evolution-943c181c658d64e2e89026db65613c905ffe9f25.zip
new test, a home grown 2 hour hack of a file browser. uses
2000-09-01 Chris Toshok <toshok@helixcode.com> * e-tree-example-2.c: new test, a home grown 2 hour hack of a file browser. uses node_collapsed/emitted signals to populate the left tree. * Makefile.am: add tree-example-2.c stuff. * .cvsignore: add tree-example-2 svn path=/trunk/; revision=5163
-rw-r--r--widgets/e-table/.cvsignore1
-rw-r--r--widgets/e-table/ChangeLog10
-rw-r--r--widgets/e-table/Makefile.am17
-rw-r--r--widgets/e-table/e-tree-example-2.c673
-rw-r--r--widgets/table/.cvsignore1
-rw-r--r--widgets/table/e-tree-example-2.c673
6 files changed, 1374 insertions, 1 deletions
diff --git a/widgets/e-table/.cvsignore b/widgets/e-table/.cvsignore
index ecfa617948..b1004fee2c 100644
--- a/widgets/e-table/.cvsignore
+++ b/widgets/e-table/.cvsignore
@@ -10,3 +10,4 @@ table-example-1
table-example-2
table-size-test
tree-example-1
+tree-example-2
diff --git a/widgets/e-table/ChangeLog b/widgets/e-table/ChangeLog
index 7de92bf0b2..a701b726ef 100644
--- a/widgets/e-table/ChangeLog
+++ b/widgets/e-table/ChangeLog
@@ -1,5 +1,15 @@
2000-09-01 Chris Toshok <toshok@helixcode.com>
+ * e-tree-example-2.c: new test, a home grown 2 hour hack of a file
+ browser. uses node_collapsed/emitted signals to populate the left
+ tree.
+
+ * Makefile.am: add tree-example-2.c stuff.
+
+ * .cvsignore: add tree-example-2
+
+2000-09-01 Chris Toshok <toshok@helixcode.com>
+
* e-tree-model.h: add signals/prototypes for
e_tree_model_node_collapsed and e_tree_model_node_expanded.
diff --git a/widgets/e-table/Makefile.am b/widgets/e-table/Makefile.am
index 14bab7e2f4..1afe8d9f20 100644
--- a/widgets/e-table/Makefile.am
+++ b/widgets/e-table/Makefile.am
@@ -16,6 +16,7 @@ INCLUDES = \
$(GNOME_INCLUDEDIR) \
-DETABLE_GLADEDIR=\"$(gladedir)\" \
-I$(top_srcdir)/widgets/e-text \
+ -I$(top_srcdir)/widgets/e-paned \
-I$(top_srcdir)/e-util \
-I$(top_srcdir) \
-DG_LOG_DOMAIN=\"e-table\"
@@ -92,7 +93,7 @@ libetable_a_SOURCES = \
e-tree-simple.h
noinst_PROGRAMS = \
- table-test table-example-1 table-example-2 table-size-test tree-example-1
+ table-test table-example-1 table-example-2 table-size-test tree-example-1 tree-example-2
table_test_SOURCES = \
test-table.c \
@@ -163,6 +164,20 @@ tree_example_1_LDADD = \
$(top_builddir)/e-util/libeutil.la \
$(GNOME_PRINT_LIBS)
+tree_example_2_SOURCES = \
+ e-tree-example-2.c
+
+tree_example_2_LDFLAGS = `gnome-config --libs gdk_pixbuf` `gnome-config --libs vfs`
+
+tree_example_2_LDADD = \
+ libetable.a \
+ $(EXTRA_GNOME_LIBS) \
+ $(top_builddir)/widgets/e-text/libetext.a \
+ $(top_builddir)/widgets/e-paned/libepaned.a \
+ $(top_builddir)/widgets/misc/libemiscwidgets.a \
+ $(top_builddir)/e-util/libeutil.la \
+ $(GNOME_PRINT_LIBS)
+
icons = \
arrow-down.xpm \
arrow-up.xpm \
diff --git a/widgets/e-table/e-tree-example-2.c b/widgets/e-table/e-tree-example-2.c
new file mode 100644
index 0000000000..d7db861953
--- /dev/null
+++ b/widgets/e-table/e-tree-example-2.c
@@ -0,0 +1,673 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-tree-example-2.c - Test program for directory reading in the GNOME
+ Virtual File System.
+
+ Copyright (C) 1999 Free Software Foundation
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Ettore Perazzoli <ettore@comm2000.it> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <gnome.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+#include "e-hpaned.h"
+#include "e-util/e-cursors.h"
+#include "e-table-header.h"
+#include "e-table-header-item.h"
+#include "e-table-item.h"
+#include "e-cell-text.h"
+#include "e-cell-tree.h"
+#include "e-cell-checkbox.h"
+#include "e-table-scrolled.h"
+#include "e-tree-simple.h"
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "art/tree-expanded.xpm"
+#include "art/tree-unexpanded.xpm"
+
+GdkPixbuf *tree_expanded_pixbuf;
+GdkPixbuf *tree_unexpanded_pixbuf;
+
+#define MINI_ICON_SIZE 16
+
+#define RIGHT_COLS 4
+#define LEFT_COLS 4
+
+#define RIGHT_E_TABLE_SPEC \
+"<ETableSpecification> \
+ <columns-shown> \
+ <column> 0 </column> \
+ <column> 1 </column> \
+ <column> 2 </column> \
+ <column> 3 </column> \
+ </columns-shown> \
+ <grouping></grouping> \
+</ETableSpecification>"
+
+#define LEFT_E_TABLE_SPEC \
+"<ETableSpecification no-header=\"1\"> \
+ <columns-shown> \
+ <column> 0 </column> \
+ </columns-shown> \
+ <grouping></grouping> \
+</ETableSpecification>"
+
+char *left_headers [LEFT_COLS] = {
+ "Folder"
+};
+
+char *right_headers [RIGHT_COLS] = {
+ "Name",
+ "Size",
+ "Type",
+ "Mime Type"
+};
+
+
+
+GnomeVFSDirectoryFilter *left_filter;
+GnomeVFSDirectoryFilter *right_filter;
+GHashTable *mime_type_to_pixbuf;
+GnomeVFSDirectoryList *right_list = NULL;
+ETreePath *right_root;
+ETreeModel *right_model = NULL;
+ETreeModel *left_model = NULL;
+
+typedef struct {
+ char *node_uri;
+ GnomeVFSFileInfo *info;
+
+ /* next two used only if the node is a directory */
+ /* used if the node is expanded */
+ GnomeVFSDirectoryList *list;
+ /* used if the node is collapsed */
+ ETreePath *placeholder;
+} VFSInfo;
+
+/*
+ * ETreeSimple callbacks
+ * These are the callbacks that define the behavior of our custom model.
+ */
+
+static gchar *
+type_to_string (GnomeVFSFileType type)
+{
+ switch (type) {
+ case GNOME_VFS_FILE_TYPE_UNKNOWN:
+ return "Unknown";
+ case GNOME_VFS_FILE_TYPE_REGULAR:
+ return "Regular";
+ case GNOME_VFS_FILE_TYPE_DIRECTORY:
+ return "Directory";
+ case GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK:
+ return "Symbolic Link";
+ case GNOME_VFS_FILE_TYPE_FIFO:
+ return "FIFO";
+ case GNOME_VFS_FILE_TYPE_SOCKET:
+ return "Socket";
+ case GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE:
+ return "Character device";
+ case GNOME_VFS_FILE_TYPE_BLOCK_DEVICE:
+ return "Block device";
+ default:
+ return "???";
+ }
+}
+
+/* This function returns the value at a particular point in our ETreeModel. */
+static void *
+tree_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data)
+{
+ VFSInfo *vfs_info = e_tree_model_node_get_data (etm, path);
+
+ switch (col) {
+ case 0: /* filename */
+ if (vfs_info->info)
+ return vfs_info->info->name;
+ else
+ return vfs_info->node_uri;
+ case 1: /* size */ {
+ static char buf[15];
+ if (vfs_info->info) {
+ if (vfs_info->info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
+ return NULL;
+ else {
+ g_snprintf (buf, sizeof(buf), "%ld", (glong) vfs_info->info->size);
+ return buf;
+ }
+ }
+ else
+ return NULL;
+ }
+ case 2: /* file type */
+ if (vfs_info->info)
+ return type_to_string (vfs_info->info->type);
+ else
+ return NULL;
+ case 3: /* mime type */
+ if (vfs_info->info) {
+ const char *mime_type = gnome_vfs_file_info_get_mime_type (vfs_info->info);
+ if (mime_type == NULL)
+ mime_type = "(Unknown)";
+ return (void*)mime_type;
+ }
+ else {
+ return NULL;
+ }
+ default: return NULL;
+ }
+}
+
+static GdkPixbuf *
+tree_icon_at (ETreeModel *etm, ETreePath *path, void *model_data)
+{
+ VFSInfo *vfs_info = e_tree_model_node_get_data (etm, path);
+ const char *mime_type;
+ GdkPixbuf *scaled_pixbuf = NULL;
+
+ if (vfs_info->info == NULL)
+ return NULL;
+
+ mime_type = gnome_vfs_file_info_get_mime_type (vfs_info->info);
+ if (mime_type == NULL)
+ mime_type = "(Unknown)";
+
+ scaled_pixbuf = g_hash_table_lookup (mime_type_to_pixbuf, mime_type);
+ if (!scaled_pixbuf) {
+ const char *icon_filename = gnome_vfs_mime_get_icon (mime_type);
+ if (icon_filename) {
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (icon_filename);
+
+ if (pixbuf) {
+ scaled_pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf),
+ gdk_pixbuf_get_has_alpha (pixbuf),
+ gdk_pixbuf_get_bits_per_sample (pixbuf),
+ MINI_ICON_SIZE, MINI_ICON_SIZE);
+
+ gdk_pixbuf_scale (pixbuf, scaled_pixbuf,
+ 0, 0, MINI_ICON_SIZE, MINI_ICON_SIZE,
+ 0.0, 0.0,
+ (double) MINI_ICON_SIZE / gdk_pixbuf_get_width (pixbuf),
+ (double) MINI_ICON_SIZE / gdk_pixbuf_get_height (pixbuf),
+ GDK_INTERP_HYPER);
+
+ g_hash_table_insert (mime_type_to_pixbuf, (char*)mime_type, scaled_pixbuf);
+
+ gdk_pixbuf_unref (pixbuf);
+ }
+ }
+ }
+
+ return scaled_pixbuf;
+}
+
+/* This function sets the value at a particular point in our ETreeModel. */
+static void
+tree_set_value_at (ETreeModel *etm, ETreePath *path, int col, const void *val, void *model_data)
+{
+}
+
+/* This function returns whether a particular cell is editable. */
+static gboolean
+tree_is_editable (ETreeModel *etm, ETreePath *path, int col, void *model_data)
+{
+ return FALSE;
+}
+
+static void
+sort_list (GnomeVFSDirectoryList *list)
+{
+ GnomeVFSDirectorySortRule rules[] = {
+ GNOME_VFS_DIRECTORY_SORT_DIRECTORYFIRST,
+ GNOME_VFS_DIRECTORY_SORT_BYNAME,
+ GNOME_VFS_DIRECTORY_SORT_NONE
+ };
+
+
+ gnome_vfs_directory_list_sort (list, FALSE, rules);
+}
+
+
+
+static void
+node_collapsed (ETreeModel *etm, ETreePath *path, void *data)
+{
+ VFSInfo *vfs_info = e_tree_model_node_get_data (etm, path);
+ char *name;
+ ETreePath **paths;
+ int num_children, i;
+
+ if (vfs_info->info)
+ name = vfs_info->info->name;
+ else
+ name = vfs_info->node_uri;
+
+ gnome_vfs_directory_list_destroy (vfs_info->list);
+
+ /* remove the children of this node, and replace the placeholder */
+ num_children = e_tree_model_node_get_children (etm, path, &paths);
+ for (i = 0; i < num_children; i ++)
+ e_tree_model_node_remove (etm, paths[i]);
+ vfs_info->placeholder = e_tree_model_node_insert (etm, path, 0, NULL);
+}
+
+static void
+node_expanded (ETreeModel *etm, ETreePath *path, gboolean *allow_expand, void *data)
+{
+ VFSInfo *vfs_info = e_tree_model_node_get_data (etm, path);
+ GnomeVFSFileInfo *info;
+ GnomeVFSResult result;
+ char *name;
+
+ if (vfs_info->info)
+ name = vfs_info->info->name;
+ else
+ name = vfs_info->node_uri;
+
+ /* Load with no filters and without requesting any metadata. */
+ result = gnome_vfs_directory_list_load
+ (&vfs_info->list, vfs_info->node_uri,
+ (GNOME_VFS_FILE_INFO_GET_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FOLLOW_LINKS),
+ left_filter);
+
+ *allow_expand = (result == GNOME_VFS_OK);
+
+ if (!*allow_expand) {
+ char *buf = g_strdup_printf ("Cannot open directory %s : %s\n",
+ vfs_info->info->name, gnome_vfs_result_to_string (result));
+ gnome_error_dialog (buf);
+ g_free (buf);
+ return;
+ }
+
+ sort_list (vfs_info->list);
+
+ /* remove the placeholder and insert all the children of this node */
+ e_tree_model_node_remove (etm, vfs_info->placeholder);
+
+ info = gnome_vfs_directory_list_first (vfs_info->list);
+
+ if (info == NULL) {
+ /* no files */
+ return;
+ }
+
+ while (info != NULL) {
+ if (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
+ ETreePath *new_node;
+ VFSInfo *new_vfs_info = g_new0(VFSInfo, 1);
+ new_vfs_info->info = info;
+
+ new_node = e_tree_model_node_insert (etm, path, -1, new_vfs_info);
+ new_vfs_info->placeholder = e_tree_model_node_insert (etm, new_node, -1, NULL);
+ new_vfs_info->node_uri = g_strdup_printf("%s%s/", vfs_info->node_uri, info->name);
+ }
+
+ info = gnome_vfs_directory_list_next (vfs_info->list);
+ }
+}
+
+static void
+on_cursor_change (ETable *table,
+ int row,
+ gpointer user_data)
+{
+ int num_children, i;
+ GnomeVFSFileInfo *info;
+ GnomeVFSResult result;
+ ETreePath **paths;
+ ETreePath *left_path = e_tree_model_node_at_row (left_model, row);
+ VFSInfo *vfs_info = e_tree_model_node_get_data (left_model, left_path);
+
+ if (right_list) {
+ gnome_vfs_directory_list_destroy (right_list);
+ right_list = NULL;
+ }
+
+ /* remove the children of this node, and replace the placeholder */
+ num_children = e_tree_model_node_get_children (right_model, right_root, &paths);
+ for (i = 0; i < num_children; i ++)
+ e_tree_model_node_remove (right_model, paths[i]);
+
+ /* Load with no filters and without requesting any metadata. */
+ result = gnome_vfs_directory_list_load
+ (&right_list, vfs_info->node_uri,
+ (GNOME_VFS_FILE_INFO_GET_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FOLLOW_LINKS),
+ right_filter);
+
+ if (result != GNOME_VFS_OK)
+ return;
+
+ info = gnome_vfs_directory_list_first (right_list);
+ if (!info)
+ return;
+
+ while (info != NULL) {
+ ETreePath *new_node;
+ VFSInfo *new_vfs_info = g_new0(VFSInfo, 1);
+ new_vfs_info->info = info;
+
+ new_node = e_tree_model_node_insert (right_model, right_root, -1, new_vfs_info);
+
+ new_vfs_info->node_uri = g_strdup_printf("%s%s", vfs_info->node_uri, info->name);
+
+ info = gnome_vfs_directory_list_next (right_list);
+ }
+
+}
+
+static void
+on_double_click (ETable *etable,
+ int row,
+ void *data)
+{
+ GnomeVFSMimeApplication *app;
+ ETreePath *path = e_tree_model_node_at_row (right_model, row);
+ VFSInfo *vfs_info = e_tree_model_node_get_data (right_model, path);
+ const char *mime_type = gnome_vfs_file_info_get_mime_type (vfs_info->info);
+ if (mime_type == NULL)
+ mime_type = "(Unknown)";
+
+ app = gnome_vfs_mime_get_default_application (mime_type);
+
+ if (app)
+ printf ("exec %s\n", app->command);
+ else
+ printf ("no command for mime type %s\n", mime_type);
+}
+
+/* create the table on the right */
+static GtkWidget*
+create_right_tree(GtkWidget *paned)
+{
+ GtkWidget *e_table;
+ GtkWidget *frame;
+ ECell *cell_left_just;
+ ECell *cell_tree;
+ ETableHeader *e_table_header;
+ int i;
+
+ right_filter = gnome_vfs_directory_filter_new (GNOME_VFS_DIRECTORY_FILTER_NONE,
+ GNOME_VFS_DIRECTORY_FILTER_NODIRS,
+ NULL);
+
+ /* here we create our model. This uses the functions we defined
+ earlier. */
+ right_model = e_tree_simple_new (tree_icon_at,
+ tree_value_at,
+ tree_set_value_at,
+ tree_is_editable,
+ NULL);
+
+ /* create the unexpanded root node and it's placeholder child. */
+ right_root = e_tree_model_node_insert (right_model, NULL,
+ 0, NULL);
+ e_tree_model_root_node_set_visible (right_model, FALSE);
+
+ /*
+ * Next we create a header. The ETableHeader is used in two
+ * different way. The first is the full_header. This is the
+ * list of possible columns in the view. The second use is
+ * completely internal. Many of the ETableHeader functions are
+ * for that purpose. The only functions we really need are
+ * e_table_header_new and e_table_header_add_col.
+ *
+ * First we create the header.
+ */
+ e_table_header = e_table_header_new ();
+
+ /*
+ * Next we have to build renderers for all of the columns.
+ * Since all our columns are text columns, we can simply use
+ * the same renderer over and over again. If we had different
+ * types of columns, we could use a different renderer for
+ * each column.
+ */
+ cell_left_just = e_cell_text_new (E_TABLE_MODEL(right_model), NULL, GTK_JUSTIFY_LEFT);
+
+ /*
+ * This renderer is used for the tree column (the leftmost one), and
+ * has as its subcell renderer the text renderer. this means that
+ * text is displayed to the right of the tree pipes.
+ */
+ cell_tree = e_cell_tree_new (E_TABLE_MODEL(right_model),
+ tree_expanded_pixbuf, tree_unexpanded_pixbuf,
+ TRUE, cell_left_just);
+
+ /*
+ * Next we create a column object for each view column and add
+ * them to the header. We don't create a column object for
+ * the importance column since it will not be shown.
+ */
+ for (i = 0; i < RIGHT_COLS; i++) {
+ /* Create the column. */
+ ETableCol *ecol = e_table_col_new (
+ i, right_headers [i],
+ 80, 20,
+ i == 0 ? cell_tree
+ : cell_left_just,
+ g_str_compare, TRUE);
+ /* Add it to the header. */
+ e_table_header_add_column (e_table_header, ecol, i);
+ }
+
+ /* This frame is simply to get a bevel around our table. */
+ frame = gtk_frame_new (NULL);
+
+ /*
+ * Here we create the table. We give it the three pieces of
+ * the table we've created, the header, the model, and the
+ * initial layout. It does the rest.
+ */
+ e_table = e_table_scrolled_new (e_table_header, E_TABLE_MODEL(right_model), RIGHT_E_TABLE_SPEC);
+
+ gtk_signal_connect (GTK_OBJECT (e_table), "double_click", GTK_SIGNAL_FUNC (on_double_click), NULL);
+
+ /* Build the gtk widget hierarchy. */
+ gtk_container_add (GTK_CONTAINER (frame), e_table);
+ gtk_container_add (GTK_CONTAINER (paned), frame);
+
+ return e_table;
+}
+
+/* We create a window containing our new tree. */
+static GtkWidget *
+create_left_tree (GtkWidget *paned, char *root_uri)
+{
+ GtkWidget *scrolled;
+ GtkWidget *e_table;
+ GtkWidget *frame;
+ ECell *cell_left_just;
+ ECell *cell_tree;
+ ETableHeader *e_table_header;
+ ETreePath *root_node;
+ VFSInfo *root_vfs_info;
+ ETableCol *ecol;
+
+ left_filter = gnome_vfs_directory_filter_new (GNOME_VFS_DIRECTORY_FILTER_NONE,
+ /* putting DIRSONLY doesn't work here, so we filter
+ files out in node_expanded. */
+ (GNOME_VFS_DIRECTORY_FILTER_NOSELFDIR
+ | GNOME_VFS_DIRECTORY_FILTER_NOPARENTDIR),
+ NULL);
+
+
+ /* here we create our model. This uses the functions we defined
+ earlier. */
+ left_model = e_tree_simple_new (tree_icon_at,
+ tree_value_at,
+ tree_set_value_at,
+ tree_is_editable,
+ NULL);
+
+ /* catch collapsed/expanded signals */
+ gtk_signal_connect (GTK_OBJECT (left_model), "node_expanded",
+ GTK_SIGNAL_FUNC (node_expanded), NULL);
+
+ gtk_signal_connect (GTK_OBJECT (left_model), "node_collapsed",
+ GTK_SIGNAL_FUNC (node_collapsed), NULL);
+
+ /* create the unexpanded root node and it's placeholder child. */
+ root_vfs_info = g_new0 (VFSInfo, 1);
+ root_vfs_info->node_uri = g_strdup (root_uri);
+ root_vfs_info->info = gnome_vfs_file_info_new();
+
+ gnome_vfs_get_file_info (root_uri, root_vfs_info->info,
+ GNOME_VFS_FILE_INFO_GET_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
+
+ root_node = e_tree_model_node_insert (left_model, NULL,
+ 0,
+ root_vfs_info);
+ e_tree_model_node_set_expanded (left_model, root_node, FALSE);
+
+ root_vfs_info->placeholder = e_tree_model_node_insert (left_model, root_node, 0, NULL);
+
+ e_tree_model_root_node_set_visible (left_model, TRUE);
+
+ /*
+ * Next we create a header. The ETableHeader is used in two
+ * different way. The first is the full_header. This is the
+ * list of possible columns in the view. The second use is
+ * completely internal. Many of the ETableHeader functions are
+ * for that purpose. The only functions we really need are
+ * e_table_header_new and e_table_header_add_col.
+ *
+ * First we create the header.
+ */
+ e_table_header = e_table_header_new ();
+
+ /*
+ * Next we have to build renderers for all of the columns.
+ * Since all our columns are text columns, we can simply use
+ * the same renderer over and over again. If we had different
+ * types of columns, we could use a different renderer for
+ * each column.
+ */
+ cell_left_just = e_cell_text_new (E_TABLE_MODEL(left_model), NULL, GTK_JUSTIFY_LEFT);
+
+ /*
+ * This renderer is used for the tree column (the leftmost one), and
+ * has as its subcell renderer the text renderer. this means that
+ * text is displayed to the right of the tree pipes.
+ */
+ cell_tree = e_cell_tree_new (E_TABLE_MODEL(left_model),
+ tree_expanded_pixbuf, tree_unexpanded_pixbuf,
+ TRUE, cell_left_just);
+
+ /* Create the column. */
+ ecol = e_table_col_new (0, left_headers [0],
+ 80, 20,
+ cell_tree,
+ g_str_compare, TRUE);
+
+ e_table_header_add_column (e_table_header, ecol, 0);
+
+ /* This frame is simply to get a bevel around our table. */
+ frame = gtk_frame_new (NULL);
+
+ /*
+ * Here we create the table. We give it the three pieces of
+ * the table we've created, the header, the model, and the
+ * initial layout. It does the rest.
+ */
+ e_table = e_table_new (e_table_header, E_TABLE_MODEL(left_model), LEFT_E_TABLE_SPEC);
+
+ gtk_object_set (GTK_OBJECT (e_table),
+ "cursor_mode", E_TABLE_CURSOR_LINE,
+ NULL);
+
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ /* Build the gtk widget hierarchy. */
+ gtk_container_add (GTK_CONTAINER (scrolled), e_table);
+ gtk_container_add (GTK_CONTAINER (frame), scrolled);
+ gtk_container_add (GTK_CONTAINER (paned), frame);
+
+ return e_table;
+}
+
+static void
+create_window(char *root_uri)
+{
+ GtkWidget *paned;
+ GtkWidget *window, *left_tree, *right_tree;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ paned = e_hpaned_new ();
+
+ gtk_container_add (GTK_CONTAINER (window), paned);
+
+ left_tree = create_left_tree (paned, root_uri);
+ right_tree = create_right_tree (paned);
+
+ /* Show it all. */
+ gtk_widget_show_all (window);
+
+ gtk_signal_connect (GTK_OBJECT (left_tree), "cursor_change", GTK_SIGNAL_FUNC (on_cursor_change), NULL);
+ gtk_signal_connect (GTK_OBJECT (window), "delete-event", gtk_main_quit, NULL);
+
+ /* kick things off by selecting the root node */
+ e_table_set_cursor_row (E_TABLE (left_tree), 0);
+ on_cursor_change (E_TABLE(left_tree), 0, NULL);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ gchar *root_uri;
+
+ if (argv[1] == NULL)
+ root_uri = "file:///";
+ else
+ root_uri = argv[1];
+
+ gnome_init ("TableExample", "TableExample", argc, argv);
+ e_cursors_init ();
+ gnome_vfs_init ();
+
+ mime_type_to_pixbuf = g_hash_table_new (g_str_hash, g_str_equal);
+
+ gtk_widget_push_visual (gdk_rgb_get_visual ());
+ gtk_widget_push_colormap (gdk_rgb_get_cmap ());
+
+ /*
+ * Create our pixbuf for expanding/unexpanding
+ */
+ tree_expanded_pixbuf = gdk_pixbuf_new_from_xpm_data((const char**)tree_expanded_xpm);
+ tree_unexpanded_pixbuf = gdk_pixbuf_new_from_xpm_data((const char**)tree_unexpanded_xpm);
+
+ create_window (root_uri);
+
+ gtk_main ();
+
+ e_cursors_shutdown ();
+ return 0;
+}
diff --git a/widgets/table/.cvsignore b/widgets/table/.cvsignore
index ecfa617948..b1004fee2c 100644
--- a/widgets/table/.cvsignore
+++ b/widgets/table/.cvsignore
@@ -10,3 +10,4 @@ table-example-1
table-example-2
table-size-test
tree-example-1
+tree-example-2
diff --git a/widgets/table/e-tree-example-2.c b/widgets/table/e-tree-example-2.c
new file mode 100644
index 0000000000..d7db861953
--- /dev/null
+++ b/widgets/table/e-tree-example-2.c
@@ -0,0 +1,673 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-tree-example-2.c - Test program for directory reading in the GNOME
+ Virtual File System.
+
+ Copyright (C) 1999 Free Software Foundation
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Ettore Perazzoli <ettore@comm2000.it> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <gnome.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+#include "e-hpaned.h"
+#include "e-util/e-cursors.h"
+#include "e-table-header.h"
+#include "e-table-header-item.h"
+#include "e-table-item.h"
+#include "e-cell-text.h"
+#include "e-cell-tree.h"
+#include "e-cell-checkbox.h"
+#include "e-table-scrolled.h"
+#include "e-tree-simple.h"
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "art/tree-expanded.xpm"
+#include "art/tree-unexpanded.xpm"
+
+GdkPixbuf *tree_expanded_pixbuf;
+GdkPixbuf *tree_unexpanded_pixbuf;
+
+#define MINI_ICON_SIZE 16
+
+#define RIGHT_COLS 4
+#define LEFT_COLS 4
+
+#define RIGHT_E_TABLE_SPEC \
+"<ETableSpecification> \
+ <columns-shown> \
+ <column> 0 </column> \
+ <column> 1 </column> \
+ <column> 2 </column> \
+ <column> 3 </column> \
+ </columns-shown> \
+ <grouping></grouping> \
+</ETableSpecification>"
+
+#define LEFT_E_TABLE_SPEC \
+"<ETableSpecification no-header=\"1\"> \
+ <columns-shown> \
+ <column> 0 </column> \
+ </columns-shown> \
+ <grouping></grouping> \
+</ETableSpecification>"
+
+char *left_headers [LEFT_COLS] = {
+ "Folder"
+};
+
+char *right_headers [RIGHT_COLS] = {
+ "Name",
+ "Size",
+ "Type",
+ "Mime Type"
+};
+
+
+
+GnomeVFSDirectoryFilter *left_filter;
+GnomeVFSDirectoryFilter *right_filter;
+GHashTable *mime_type_to_pixbuf;
+GnomeVFSDirectoryList *right_list = NULL;
+ETreePath *right_root;
+ETreeModel *right_model = NULL;
+ETreeModel *left_model = NULL;
+
+typedef struct {
+ char *node_uri;
+ GnomeVFSFileInfo *info;
+
+ /* next two used only if the node is a directory */
+ /* used if the node is expanded */
+ GnomeVFSDirectoryList *list;
+ /* used if the node is collapsed */
+ ETreePath *placeholder;
+} VFSInfo;
+
+/*
+ * ETreeSimple callbacks
+ * These are the callbacks that define the behavior of our custom model.
+ */
+
+static gchar *
+type_to_string (GnomeVFSFileType type)
+{
+ switch (type) {
+ case GNOME_VFS_FILE_TYPE_UNKNOWN:
+ return "Unknown";
+ case GNOME_VFS_FILE_TYPE_REGULAR:
+ return "Regular";
+ case GNOME_VFS_FILE_TYPE_DIRECTORY:
+ return "Directory";
+ case GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK:
+ return "Symbolic Link";
+ case GNOME_VFS_FILE_TYPE_FIFO:
+ return "FIFO";
+ case GNOME_VFS_FILE_TYPE_SOCKET:
+ return "Socket";
+ case GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE:
+ return "Character device";
+ case GNOME_VFS_FILE_TYPE_BLOCK_DEVICE:
+ return "Block device";
+ default:
+ return "???";
+ }
+}
+
+/* This function returns the value at a particular point in our ETreeModel. */
+static void *
+tree_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data)
+{
+ VFSInfo *vfs_info = e_tree_model_node_get_data (etm, path);
+
+ switch (col) {
+ case 0: /* filename */
+ if (vfs_info->info)
+ return vfs_info->info->name;
+ else
+ return vfs_info->node_uri;
+ case 1: /* size */ {
+ static char buf[15];
+ if (vfs_info->info) {
+ if (vfs_info->info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
+ return NULL;
+ else {
+ g_snprintf (buf, sizeof(buf), "%ld", (glong) vfs_info->info->size);
+ return buf;
+ }
+ }
+ else
+ return NULL;
+ }
+ case 2: /* file type */
+ if (vfs_info->info)
+ return type_to_string (vfs_info->info->type);
+ else
+ return NULL;
+ case 3: /* mime type */
+ if (vfs_info->info) {
+ const char *mime_type = gnome_vfs_file_info_get_mime_type (vfs_info->info);
+ if (mime_type == NULL)
+ mime_type = "(Unknown)";
+ return (void*)mime_type;
+ }
+ else {
+ return NULL;
+ }
+ default: return NULL;
+ }
+}
+
+static GdkPixbuf *
+tree_icon_at (ETreeModel *etm, ETreePath *path, void *model_data)
+{
+ VFSInfo *vfs_info = e_tree_model_node_get_data (etm, path);
+ const char *mime_type;
+ GdkPixbuf *scaled_pixbuf = NULL;
+
+ if (vfs_info->info == NULL)
+ return NULL;
+
+ mime_type = gnome_vfs_file_info_get_mime_type (vfs_info->info);
+ if (mime_type == NULL)
+ mime_type = "(Unknown)";
+
+ scaled_pixbuf = g_hash_table_lookup (mime_type_to_pixbuf, mime_type);
+ if (!scaled_pixbuf) {
+ const char *icon_filename = gnome_vfs_mime_get_icon (mime_type);
+ if (icon_filename) {
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (icon_filename);
+
+ if (pixbuf) {
+ scaled_pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf),
+ gdk_pixbuf_get_has_alpha (pixbuf),
+ gdk_pixbuf_get_bits_per_sample (pixbuf),
+ MINI_ICON_SIZE, MINI_ICON_SIZE);
+
+ gdk_pixbuf_scale (pixbuf, scaled_pixbuf,
+ 0, 0, MINI_ICON_SIZE, MINI_ICON_SIZE,
+ 0.0, 0.0,
+ (double) MINI_ICON_SIZE / gdk_pixbuf_get_width (pixbuf),
+ (double) MINI_ICON_SIZE / gdk_pixbuf_get_height (pixbuf),
+ GDK_INTERP_HYPER);
+
+ g_hash_table_insert (mime_type_to_pixbuf, (char*)mime_type, scaled_pixbuf);
+
+ gdk_pixbuf_unref (pixbuf);
+ }
+ }
+ }
+
+ return scaled_pixbuf;
+}
+
+/* This function sets the value at a particular point in our ETreeModel. */
+static void
+tree_set_value_at (ETreeModel *etm, ETreePath *path, int col, const void *val, void *model_data)
+{
+}
+
+/* This function returns whether a particular cell is editable. */
+static gboolean
+tree_is_editable (ETreeModel *etm, ETreePath *path, int col, void *model_data)
+{
+ return FALSE;
+}
+
+static void
+sort_list (GnomeVFSDirectoryList *list)
+{
+ GnomeVFSDirectorySortRule rules[] = {
+ GNOME_VFS_DIRECTORY_SORT_DIRECTORYFIRST,
+ GNOME_VFS_DIRECTORY_SORT_BYNAME,
+ GNOME_VFS_DIRECTORY_SORT_NONE
+ };
+
+
+ gnome_vfs_directory_list_sort (list, FALSE, rules);
+}
+
+
+
+static void
+node_collapsed (ETreeModel *etm, ETreePath *path, void *data)
+{
+ VFSInfo *vfs_info = e_tree_model_node_get_data (etm, path);
+ char *name;
+ ETreePath **paths;
+ int num_children, i;
+
+ if (vfs_info->info)
+ name = vfs_info->info->name;
+ else
+ name = vfs_info->node_uri;
+
+ gnome_vfs_directory_list_destroy (vfs_info->list);
+
+ /* remove the children of this node, and replace the placeholder */
+ num_children = e_tree_model_node_get_children (etm, path, &paths);
+ for (i = 0; i < num_children; i ++)
+ e_tree_model_node_remove (etm, paths[i]);
+ vfs_info->placeholder = e_tree_model_node_insert (etm, path, 0, NULL);
+}
+
+static void
+node_expanded (ETreeModel *etm, ETreePath *path, gboolean *allow_expand, void *data)
+{
+ VFSInfo *vfs_info = e_tree_model_node_get_data (etm, path);
+ GnomeVFSFileInfo *info;
+ GnomeVFSResult result;
+ char *name;
+
+ if (vfs_info->info)
+ name = vfs_info->info->name;
+ else
+ name = vfs_info->node_uri;
+
+ /* Load with no filters and without requesting any metadata. */
+ result = gnome_vfs_directory_list_load
+ (&vfs_info->list, vfs_info->node_uri,
+ (GNOME_VFS_FILE_INFO_GET_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FOLLOW_LINKS),
+ left_filter);
+
+ *allow_expand = (result == GNOME_VFS_OK);
+
+ if (!*allow_expand) {
+ char *buf = g_strdup_printf ("Cannot open directory %s : %s\n",
+ vfs_info->info->name, gnome_vfs_result_to_string (result));
+ gnome_error_dialog (buf);
+ g_free (buf);
+ return;
+ }
+
+ sort_list (vfs_info->list);
+
+ /* remove the placeholder and insert all the children of this node */
+ e_tree_model_node_remove (etm, vfs_info->placeholder);
+
+ info = gnome_vfs_directory_list_first (vfs_info->list);
+
+ if (info == NULL) {
+ /* no files */
+ return;
+ }
+
+ while (info != NULL) {
+ if (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
+ ETreePath *new_node;
+ VFSInfo *new_vfs_info = g_new0(VFSInfo, 1);
+ new_vfs_info->info = info;
+
+ new_node = e_tree_model_node_insert (etm, path, -1, new_vfs_info);
+ new_vfs_info->placeholder = e_tree_model_node_insert (etm, new_node, -1, NULL);
+ new_vfs_info->node_uri = g_strdup_printf("%s%s/", vfs_info->node_uri, info->name);
+ }
+
+ info = gnome_vfs_directory_list_next (vfs_info->list);
+ }
+}
+
+static void
+on_cursor_change (ETable *table,
+ int row,
+ gpointer user_data)
+{
+ int num_children, i;
+ GnomeVFSFileInfo *info;
+ GnomeVFSResult result;
+ ETreePath **paths;
+ ETreePath *left_path = e_tree_model_node_at_row (left_model, row);
+ VFSInfo *vfs_info = e_tree_model_node_get_data (left_model, left_path);
+
+ if (right_list) {
+ gnome_vfs_directory_list_destroy (right_list);
+ right_list = NULL;
+ }
+
+ /* remove the children of this node, and replace the placeholder */
+ num_children = e_tree_model_node_get_children (right_model, right_root, &paths);
+ for (i = 0; i < num_children; i ++)
+ e_tree_model_node_remove (right_model, paths[i]);
+
+ /* Load with no filters and without requesting any metadata. */
+ result = gnome_vfs_directory_list_load
+ (&right_list, vfs_info->node_uri,
+ (GNOME_VFS_FILE_INFO_GET_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FOLLOW_LINKS),
+ right_filter);
+
+ if (result != GNOME_VFS_OK)
+ return;
+
+ info = gnome_vfs_directory_list_first (right_list);
+ if (!info)
+ return;
+
+ while (info != NULL) {
+ ETreePath *new_node;
+ VFSInfo *new_vfs_info = g_new0(VFSInfo, 1);
+ new_vfs_info->info = info;
+
+ new_node = e_tree_model_node_insert (right_model, right_root, -1, new_vfs_info);
+
+ new_vfs_info->node_uri = g_strdup_printf("%s%s", vfs_info->node_uri, info->name);
+
+ info = gnome_vfs_directory_list_next (right_list);
+ }
+
+}
+
+static void
+on_double_click (ETable *etable,
+ int row,
+ void *data)
+{
+ GnomeVFSMimeApplication *app;
+ ETreePath *path = e_tree_model_node_at_row (right_model, row);
+ VFSInfo *vfs_info = e_tree_model_node_get_data (right_model, path);
+ const char *mime_type = gnome_vfs_file_info_get_mime_type (vfs_info->info);
+ if (mime_type == NULL)
+ mime_type = "(Unknown)";
+
+ app = gnome_vfs_mime_get_default_application (mime_type);
+
+ if (app)
+ printf ("exec %s\n", app->command);
+ else
+ printf ("no command for mime type %s\n", mime_type);
+}
+
+/* create the table on the right */
+static GtkWidget*
+create_right_tree(GtkWidget *paned)
+{
+ GtkWidget *e_table;
+ GtkWidget *frame;
+ ECell *cell_left_just;
+ ECell *cell_tree;
+ ETableHeader *e_table_header;
+ int i;
+
+ right_filter = gnome_vfs_directory_filter_new (GNOME_VFS_DIRECTORY_FILTER_NONE,
+ GNOME_VFS_DIRECTORY_FILTER_NODIRS,
+ NULL);
+
+ /* here we create our model. This uses the functions we defined
+ earlier. */
+ right_model = e_tree_simple_new (tree_icon_at,
+ tree_value_at,
+ tree_set_value_at,
+ tree_is_editable,
+ NULL);
+
+ /* create the unexpanded root node and it's placeholder child. */
+ right_root = e_tree_model_node_insert (right_model, NULL,
+ 0, NULL);
+ e_tree_model_root_node_set_visible (right_model, FALSE);
+
+ /*
+ * Next we create a header. The ETableHeader is used in two
+ * different way. The first is the full_header. This is the
+ * list of possible columns in the view. The second use is
+ * completely internal. Many of the ETableHeader functions are
+ * for that purpose. The only functions we really need are
+ * e_table_header_new and e_table_header_add_col.
+ *
+ * First we create the header.
+ */
+ e_table_header = e_table_header_new ();
+
+ /*
+ * Next we have to build renderers for all of the columns.
+ * Since all our columns are text columns, we can simply use
+ * the same renderer over and over again. If we had different
+ * types of columns, we could use a different renderer for
+ * each column.
+ */
+ cell_left_just = e_cell_text_new (E_TABLE_MODEL(right_model), NULL, GTK_JUSTIFY_LEFT);
+
+ /*
+ * This renderer is used for the tree column (the leftmost one), and
+ * has as its subcell renderer the text renderer. this means that
+ * text is displayed to the right of the tree pipes.
+ */
+ cell_tree = e_cell_tree_new (E_TABLE_MODEL(right_model),
+ tree_expanded_pixbuf, tree_unexpanded_pixbuf,
+ TRUE, cell_left_just);
+
+ /*
+ * Next we create a column object for each view column and add
+ * them to the header. We don't create a column object for
+ * the importance column since it will not be shown.
+ */
+ for (i = 0; i < RIGHT_COLS; i++) {
+ /* Create the column. */
+ ETableCol *ecol = e_table_col_new (
+ i, right_headers [i],
+ 80, 20,
+ i == 0 ? cell_tree
+ : cell_left_just,
+ g_str_compare, TRUE);
+ /* Add it to the header. */
+ e_table_header_add_column (e_table_header, ecol, i);
+ }
+
+ /* This frame is simply to get a bevel around our table. */
+ frame = gtk_frame_new (NULL);
+
+ /*
+ * Here we create the table. We give it the three pieces of
+ * the table we've created, the header, the model, and the
+ * initial layout. It does the rest.
+ */
+ e_table = e_table_scrolled_new (e_table_header, E_TABLE_MODEL(right_model), RIGHT_E_TABLE_SPEC);
+
+ gtk_signal_connect (GTK_OBJECT (e_table), "double_click", GTK_SIGNAL_FUNC (on_double_click), NULL);
+
+ /* Build the gtk widget hierarchy. */
+ gtk_container_add (GTK_CONTAINER (frame), e_table);
+ gtk_container_add (GTK_CONTAINER (paned), frame);
+
+ return e_table;
+}
+
+/* We create a window containing our new tree. */
+static GtkWidget *
+create_left_tree (GtkWidget *paned, char *root_uri)
+{
+ GtkWidget *scrolled;
+ GtkWidget *e_table;
+ GtkWidget *frame;
+ ECell *cell_left_just;
+ ECell *cell_tree;
+ ETableHeader *e_table_header;
+ ETreePath *root_node;
+ VFSInfo *root_vfs_info;
+ ETableCol *ecol;
+
+ left_filter = gnome_vfs_directory_filter_new (GNOME_VFS_DIRECTORY_FILTER_NONE,
+ /* putting DIRSONLY doesn't work here, so we filter
+ files out in node_expanded. */
+ (GNOME_VFS_DIRECTORY_FILTER_NOSELFDIR
+ | GNOME_VFS_DIRECTORY_FILTER_NOPARENTDIR),
+ NULL);
+
+
+ /* here we create our model. This uses the functions we defined
+ earlier. */
+ left_model = e_tree_simple_new (tree_icon_at,
+ tree_value_at,
+ tree_set_value_at,
+ tree_is_editable,
+ NULL);
+
+ /* catch collapsed/expanded signals */
+ gtk_signal_connect (GTK_OBJECT (left_model), "node_expanded",
+ GTK_SIGNAL_FUNC (node_expanded), NULL);
+
+ gtk_signal_connect (GTK_OBJECT (left_model), "node_collapsed",
+ GTK_SIGNAL_FUNC (node_collapsed), NULL);
+
+ /* create the unexpanded root node and it's placeholder child. */
+ root_vfs_info = g_new0 (VFSInfo, 1);
+ root_vfs_info->node_uri = g_strdup (root_uri);
+ root_vfs_info->info = gnome_vfs_file_info_new();
+
+ gnome_vfs_get_file_info (root_uri, root_vfs_info->info,
+ GNOME_VFS_FILE_INFO_GET_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
+
+ root_node = e_tree_model_node_insert (left_model, NULL,
+ 0,
+ root_vfs_info);
+ e_tree_model_node_set_expanded (left_model, root_node, FALSE);
+
+ root_vfs_info->placeholder = e_tree_model_node_insert (left_model, root_node, 0, NULL);
+
+ e_tree_model_root_node_set_visible (left_model, TRUE);
+
+ /*
+ * Next we create a header. The ETableHeader is used in two
+ * different way. The first is the full_header. This is the
+ * list of possible columns in the view. The second use is
+ * completely internal. Many of the ETableHeader functions are
+ * for that purpose. The only functions we really need are
+ * e_table_header_new and e_table_header_add_col.
+ *
+ * First we create the header.
+ */
+ e_table_header = e_table_header_new ();
+
+ /*
+ * Next we have to build renderers for all of the columns.
+ * Since all our columns are text columns, we can simply use
+ * the same renderer over and over again. If we had different
+ * types of columns, we could use a different renderer for
+ * each column.
+ */
+ cell_left_just = e_cell_text_new (E_TABLE_MODEL(left_model), NULL, GTK_JUSTIFY_LEFT);
+
+ /*
+ * This renderer is used for the tree column (the leftmost one), and
+ * has as its subcell renderer the text renderer. this means that
+ * text is displayed to the right of the tree pipes.
+ */
+ cell_tree = e_cell_tree_new (E_TABLE_MODEL(left_model),
+ tree_expanded_pixbuf, tree_unexpanded_pixbuf,
+ TRUE, cell_left_just);
+
+ /* Create the column. */
+ ecol = e_table_col_new (0, left_headers [0],
+ 80, 20,
+ cell_tree,
+ g_str_compare, TRUE);
+
+ e_table_header_add_column (e_table_header, ecol, 0);
+
+ /* This frame is simply to get a bevel around our table. */
+ frame = gtk_frame_new (NULL);
+
+ /*
+ * Here we create the table. We give it the three pieces of
+ * the table we've created, the header, the model, and the
+ * initial layout. It does the rest.
+ */
+ e_table = e_table_new (e_table_header, E_TABLE_MODEL(left_model), LEFT_E_TABLE_SPEC);
+
+ gtk_object_set (GTK_OBJECT (e_table),
+ "cursor_mode", E_TABLE_CURSOR_LINE,
+ NULL);
+
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ /* Build the gtk widget hierarchy. */
+ gtk_container_add (GTK_CONTAINER (scrolled), e_table);
+ gtk_container_add (GTK_CONTAINER (frame), scrolled);
+ gtk_container_add (GTK_CONTAINER (paned), frame);
+
+ return e_table;
+}
+
+static void
+create_window(char *root_uri)
+{
+ GtkWidget *paned;
+ GtkWidget *window, *left_tree, *right_tree;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ paned = e_hpaned_new ();
+
+ gtk_container_add (GTK_CONTAINER (window), paned);
+
+ left_tree = create_left_tree (paned, root_uri);
+ right_tree = create_right_tree (paned);
+
+ /* Show it all. */
+ gtk_widget_show_all (window);
+
+ gtk_signal_connect (GTK_OBJECT (left_tree), "cursor_change", GTK_SIGNAL_FUNC (on_cursor_change), NULL);
+ gtk_signal_connect (GTK_OBJECT (window), "delete-event", gtk_main_quit, NULL);
+
+ /* kick things off by selecting the root node */
+ e_table_set_cursor_row (E_TABLE (left_tree), 0);
+ on_cursor_change (E_TABLE(left_tree), 0, NULL);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ gchar *root_uri;
+
+ if (argv[1] == NULL)
+ root_uri = "file:///";
+ else
+ root_uri = argv[1];
+
+ gnome_init ("TableExample", "TableExample", argc, argv);
+ e_cursors_init ();
+ gnome_vfs_init ();
+
+ mime_type_to_pixbuf = g_hash_table_new (g_str_hash, g_str_equal);
+
+ gtk_widget_push_visual (gdk_rgb_get_visual ());
+ gtk_widget_push_colormap (gdk_rgb_get_cmap ());
+
+ /*
+ * Create our pixbuf for expanding/unexpanding
+ */
+ tree_expanded_pixbuf = gdk_pixbuf_new_from_xpm_data((const char**)tree_expanded_xpm);
+ tree_unexpanded_pixbuf = gdk_pixbuf_new_from_xpm_data((const char**)tree_unexpanded_xpm);
+
+ create_window (root_uri);
+
+ gtk_main ();
+
+ e_cursors_shutdown ();
+ return 0;
+}