729 lines
20 KiB
C
729 lines
20 KiB
C
/* -*- 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 <gdk-pixbuf/gdk-pixbuf.h>
|
||
#include <libgnomevfs/gnome-vfs.h>
|
||
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
|
||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||
#include "e-hpaned.h"
|
||
#include "gal/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 "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 "";
|
||
else {
|
||
g_snprintf (buf, sizeof(buf), "%ld", (glong) vfs_info->info->size);
|
||
return buf;
|
||
}
|
||
}
|
||
else
|
||
return "";
|
||
}
|
||
case 2: /* file type */
|
||
if (vfs_info->info)
|
||
return type_to_string (vfs_info->info->type);
|
||
else
|
||
return "";
|
||
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 "";
|
||
}
|
||
default: return "";
|
||
}
|
||
}
|
||
|
||
/* This function returns the number of columns in our ETableModel. */
|
||
static int
|
||
tree_col_count (ETableModel *etc, void *data)
|
||
{
|
||
return RIGHT_COLS;
|
||
}
|
||
|
||
/* This function duplicates the value passed to it. */
|
||
static void *
|
||
tree_duplicate_value (ETableModel *etc, int col, const void *value, void *data)
|
||
{
|
||
return g_strdup (value);
|
||
}
|
||
|
||
/* This function frees the value passed to it. */
|
||
static void
|
||
tree_free_value (ETableModel *etc, int col, void *value, void *data)
|
||
{
|
||
g_free (value);
|
||
}
|
||
|
||
/* This function creates an empty value. */
|
||
static void *
|
||
tree_initialize_value (ETableModel *etc, int col, void *data)
|
||
{
|
||
return g_strdup ("");
|
||
}
|
||
|
||
/* This function reports if a value is empty. */
|
||
static gboolean
|
||
tree_value_is_empty (ETableModel *etc, int col, const void *value, void *data)
|
||
{
|
||
return !(value && *(char *)value);
|
||
}
|
||
|
||
/* This function reports if a value is empty. */
|
||
static char *
|
||
tree_value_to_string (ETableModel *etc, int col, const void *value, void *data)
|
||
{
|
||
return g_strdup(value);
|
||
}
|
||
|
||
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_col_count,
|
||
tree_duplicate_value,
|
||
tree_free_value,
|
||
tree_initialize_value,
|
||
tree_value_is_empty,
|
||
tree_value_to_string,
|
||
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_col_count,
|
||
tree_duplicate_value,
|
||
tree_free_value,
|
||
tree_initialize_value,
|
||
tree_value_is_empty,
|
||
tree_value_to_string,
|
||
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;
|
||
}
|