change things so we focus the cell and select the row, and also dispatch
2000-06-10 Chris Toshok <toshok@helixcode.com> * e-table-item.c (eti_event): change things so we focus the cell and select the row, and also dispatch the event to that row/cell. This fixes the problem with the tree where you had to click twice to activate the tree controls. * Makefile.am (libetable_a_SOURCES): remove e-tree-gnode.* and add e-tree-simple.* (icons): add tree-expanded.xpm and tree-unexpanded.xpm * e-cell-tree.c (ect_enter_edit): defer to subcell's view. (ect_leave_edit): defer to subcell's view. (visible_depth_of_node): visual depth, taking into account that the root node of the model might not be displayed. (offset_of_node): return the offset used to shift the subcell over. (ect_draw): don't draw vertical lines if we're the leftmode node (a visual root node). also, don't shift x2 by the subcell offset, so we get ellipses like we're supposed to. (ect_event): remove GDK_BUTTON_RELEASE from the list of events that we care about. * e-tree-example-1.c: lots of changes, a more dynamic UI so we can test tree model api stuff. * e-tree-gnode.c, e-tree-gnode.c: removed files, since their guts have been rolled into e-tree-model.c * e-tree-model.c, e-tree-model.h: substantially changed. too much to really describe here. this should really be considered the first revision of these files :) * e-tree-simple.c, e-tree-simple.h: analogous to e-table-simple, a subclass that allows the use of function pointers. svn path=/trunk/; revision=3519
This commit is contained in:
parent
835ec00d01
commit
aac3f2c8b6
@ -1,3 +1,39 @@
|
|||||||
|
2000-06-10 Chris Toshok <toshok@helixcode.com>
|
||||||
|
|
||||||
|
* e-table-item.c (eti_event): change things so we focus the cell
|
||||||
|
and select the row, and also dispatch the event to that row/cell.
|
||||||
|
This fixes the problem with the tree where you had to click twice
|
||||||
|
to activate the tree controls.
|
||||||
|
|
||||||
|
* Makefile.am (libetable_a_SOURCES): remove e-tree-gnode.* and add
|
||||||
|
e-tree-simple.*
|
||||||
|
(icons): add tree-expanded.xpm and tree-unexpanded.xpm
|
||||||
|
|
||||||
|
* e-cell-tree.c (ect_enter_edit): defer to subcell's view.
|
||||||
|
(ect_leave_edit): defer to subcell's view.
|
||||||
|
(visible_depth_of_node): visual depth, taking into account that
|
||||||
|
the root node of the model might not be displayed.
|
||||||
|
(offset_of_node): return the offset used to shift the subcell
|
||||||
|
over.
|
||||||
|
(ect_draw): don't draw vertical lines if we're the leftmode node
|
||||||
|
(a visual root node). also, don't shift x2 by the subcell offset,
|
||||||
|
so we get ellipses like we're supposed to.
|
||||||
|
(ect_event): remove GDK_BUTTON_RELEASE from the list of events
|
||||||
|
that we care about.
|
||||||
|
|
||||||
|
* e-tree-example-1.c: lots of changes, a more dynamic UI so we can
|
||||||
|
test tree model api stuff.
|
||||||
|
|
||||||
|
* e-tree-gnode.c, e-tree-gnode.c: removed files, since their guts
|
||||||
|
have been rolled into e-tree-model.c
|
||||||
|
|
||||||
|
* e-tree-model.c, e-tree-model.h: substantially changed. too much
|
||||||
|
to really describe here. this should really be considered the
|
||||||
|
first revision of these files :)
|
||||||
|
|
||||||
|
* e-tree-simple.c, e-tree-simple.h: analogous to e-table-simple, a
|
||||||
|
subclass that allows the use of function pointers.
|
||||||
|
|
||||||
2000-06-11 Christopher James Lahey <clahey@helixcode.com>
|
2000-06-11 Christopher James Lahey <clahey@helixcode.com>
|
||||||
|
|
||||||
* e-table-model.c: Small syntactic changes.
|
* e-table-model.c: Small syntactic changes.
|
||||||
|
@ -76,10 +76,10 @@ libetable_a_SOURCES = \
|
|||||||
e-table-subset-variable.h \
|
e-table-subset-variable.h \
|
||||||
e-table-text-model.c \
|
e-table-text-model.c \
|
||||||
e-table-text-model.h \
|
e-table-text-model.h \
|
||||||
e-tree-gnode.c \
|
|
||||||
e-tree-gnode.h \
|
|
||||||
e-tree-model.c \
|
e-tree-model.c \
|
||||||
e-tree-model.h
|
e-tree-model.h \
|
||||||
|
e-tree-simple.c \
|
||||||
|
e-tree-simple.h
|
||||||
|
|
||||||
noinst_PROGRAMS = \
|
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
|
||||||
@ -159,7 +159,9 @@ icons = \
|
|||||||
add-col.xpm \
|
add-col.xpm \
|
||||||
check-empty.xpm \
|
check-empty.xpm \
|
||||||
check-filled.xpm \
|
check-filled.xpm \
|
||||||
remove-col.xpm
|
remove-col.xpm \
|
||||||
|
tree-expanded.xpm \
|
||||||
|
tree-unexpanded.xpm
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
sample.table \
|
sample.table \
|
||||||
|
@ -49,6 +49,21 @@ static ECellClass *parent_class;
|
|||||||
|
|
||||||
static GdkPixbuf *tree_expanded_pixbuf, *tree_unexpanded_pixbuf;
|
static GdkPixbuf *tree_expanded_pixbuf, *tree_unexpanded_pixbuf;
|
||||||
|
|
||||||
|
#define INDENT_AMOUNT 16
|
||||||
|
|
||||||
|
static int
|
||||||
|
visible_depth_of_node (ETreeModel *tree_model, ETreePath *path)
|
||||||
|
{
|
||||||
|
return (e_tree_model_node_depth (tree_model, path)
|
||||||
|
- (e_tree_model_root_node_is_visible (tree_model) ? 0 : 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
offset_of_node (ETreeModel *tree_model, ETreePath *path)
|
||||||
|
{
|
||||||
|
return (visible_depth_of_node(tree_model, path) + 1) * INDENT_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
static ETreePath*
|
static ETreePath*
|
||||||
e_cell_tree_get_node (ETreeModel *tree_model, int row)
|
e_cell_tree_get_node (ETreeModel *tree_model, int row)
|
||||||
{
|
{
|
||||||
@ -136,7 +151,6 @@ ect_unrealize (ECellView *ecv)
|
|||||||
(* parent_class->unrealize) (ecv);
|
(* parent_class->unrealize) (ecv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define INDENT_AMOUNT 16
|
|
||||||
/*
|
/*
|
||||||
* ECell::draw method
|
* ECell::draw method
|
||||||
*/
|
*/
|
||||||
@ -167,7 +181,7 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
|
|||||||
*/
|
*/
|
||||||
node = e_cell_tree_get_node (tree_model, row);
|
node = e_cell_tree_get_node (tree_model, row);
|
||||||
|
|
||||||
offset = (e_tree_model_node_depth (tree_model, node) + 1) * INDENT_AMOUNT;
|
offset = offset_of_node (tree_model, node);
|
||||||
expandable = e_tree_model_node_is_expandable (tree_model, node);
|
expandable = e_tree_model_node_is_expandable (tree_model, node);
|
||||||
expanded = e_tree_model_node_is_expanded (tree_model, node);
|
expanded = e_tree_model_node_is_expanded (tree_model, node);
|
||||||
subcell_offset = offset;
|
subcell_offset = offset;
|
||||||
@ -196,15 +210,8 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
|
|||||||
rect.x, rect.y, rect.width, rect.height);
|
rect.x, rect.y, rect.width, rect.height);
|
||||||
gdk_gc_set_foreground (tree_view->gc, foreground);
|
gdk_gc_set_foreground (tree_view->gc, foreground);
|
||||||
|
|
||||||
|
/* draw our lines */
|
||||||
if (E_CELL_TREE(tree_view->cell_view.ecell)->draw_lines) {
|
if (E_CELL_TREE(tree_view->cell_view.ecell)->draw_lines) {
|
||||||
/* draw our lines */
|
|
||||||
gdk_draw_line (drawable, tree_view->gc,
|
|
||||||
rect.x + offset - INDENT_AMOUNT / 2,
|
|
||||||
rect.y,
|
|
||||||
rect.x + offset - INDENT_AMOUNT / 2,
|
|
||||||
(e_tree_model_node_get_next (tree_model, node)
|
|
||||||
? rect.y + rect.height
|
|
||||||
: rect.y + rect.height / 2));
|
|
||||||
|
|
||||||
gdk_draw_line (drawable, tree_view->gc,
|
gdk_draw_line (drawable, tree_view->gc,
|
||||||
rect.x + offset - INDENT_AMOUNT / 2 + 1,
|
rect.x + offset - INDENT_AMOUNT / 2 + 1,
|
||||||
@ -212,12 +219,22 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
|
|||||||
rect.x + offset,
|
rect.x + offset,
|
||||||
rect.y + rect.height / 2);
|
rect.y + rect.height / 2);
|
||||||
|
|
||||||
|
if (visible_depth_of_node (tree_model, node) != 0) {
|
||||||
|
gdk_draw_line (drawable, tree_view->gc,
|
||||||
|
rect.x + offset - INDENT_AMOUNT / 2,
|
||||||
|
rect.y,
|
||||||
|
rect.x + offset - INDENT_AMOUNT / 2,
|
||||||
|
(e_tree_model_node_get_next (tree_model, node)
|
||||||
|
? rect.y + rect.height
|
||||||
|
: rect.y + rect.height / 2));
|
||||||
|
}
|
||||||
|
|
||||||
/* now traverse back up to the root of the tree, checking at
|
/* now traverse back up to the root of the tree, checking at
|
||||||
each level if the node has siblings, and drawing the
|
each level if the node has siblings, and drawing the
|
||||||
correct vertical pipe for it's configuration. */
|
correct vertical pipe for it's configuration. */
|
||||||
node = e_tree_model_node_get_parent (tree_model, node);
|
node = e_tree_model_node_get_parent (tree_model, node);
|
||||||
offset -= INDENT_AMOUNT;
|
offset -= INDENT_AMOUNT;
|
||||||
while (node && ! e_tree_model_node_is_root (tree_model, node)) {
|
while (node && visible_depth_of_node (tree_model, node) != 0) {
|
||||||
if (e_tree_model_node_get_next(tree_model, node)) {
|
if (e_tree_model_node_get_next(tree_model, node)) {
|
||||||
gdk_draw_line (drawable, tree_view->gc,
|
gdk_draw_line (drawable, tree_view->gc,
|
||||||
rect.x + offset - INDENT_AMOUNT / 2,
|
rect.x + offset - INDENT_AMOUNT / 2,
|
||||||
@ -255,7 +272,7 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
|
|||||||
subcell_offset pixels */
|
subcell_offset pixels */
|
||||||
e_cell_draw (tree_view->subcell_view, drawable,
|
e_cell_draw (tree_view->subcell_view, drawable,
|
||||||
model_col, view_col, row, selected,
|
model_col, view_col, row, selected,
|
||||||
x1 + subcell_offset, y1, x2 + subcell_offset, y2);
|
x1 + subcell_offset, y1, x2, y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -267,13 +284,12 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col,
|
|||||||
ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
|
ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case GDK_BUTTON_PRESS:
|
case GDK_BUTTON_PRESS: {
|
||||||
case GDK_BUTTON_RELEASE: {
|
|
||||||
/* if the event happened in our area of control (and
|
/* if the event happened in our area of control (and
|
||||||
we care about it), handle it. */
|
we care about it), handle it. */
|
||||||
ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row);
|
ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row);
|
||||||
ETreePath *node = e_cell_tree_get_node (tree_model, row);
|
ETreePath *node = e_cell_tree_get_node (tree_model, row);
|
||||||
int offset = (e_tree_model_node_depth (tree_model, node) + 1) * INDENT_AMOUNT;
|
int offset = offset_of_node (tree_model, node);
|
||||||
|
|
||||||
/* only activate the tree control if the click/release happens in the icon's area. */
|
/* only activate the tree control if the click/release happens in the icon's area. */
|
||||||
if (event->button.x > (offset - INDENT_AMOUNT) && event->button.x < offset) {
|
if (event->button.x > (offset - INDENT_AMOUNT) && event->button.x < offset) {
|
||||||
@ -284,6 +300,8 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col,
|
|||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
else if (event->button.x < (offset - INDENT_AMOUNT))
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
/* otherwise, pass it off to our subcell_view */
|
/* otherwise, pass it off to our subcell_view */
|
||||||
@ -309,7 +327,10 @@ ect_height (ECellView *ecell_view, int model_col, int view_col, int row)
|
|||||||
static void *
|
static void *
|
||||||
ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
|
ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
|
||||||
{
|
{
|
||||||
return NULL;
|
/* just defer to our subcell's view */
|
||||||
|
ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
|
||||||
|
|
||||||
|
return e_cell_enter_edit (tree_view->subcell_view, model_col, view_col, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -318,6 +339,10 @@ ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
|
|||||||
static void
|
static void
|
||||||
ect_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
|
ect_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
|
||||||
{
|
{
|
||||||
|
/* just defer to our subcell's view */
|
||||||
|
ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
|
||||||
|
|
||||||
|
e_cell_leave_edit (tree_view->subcell_view, model_col, view_col, row, edit_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1197,6 +1197,14 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e)
|
|||||||
if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
|
if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
if (eti->cursor_row != row || eti->cursor_col != col){
|
||||||
|
/*
|
||||||
|
* Focus the cell, and select the row
|
||||||
|
*/
|
||||||
|
e_table_item_leave_edit (eti);
|
||||||
|
e_table_item_focus (eti, col, row);
|
||||||
|
}
|
||||||
|
|
||||||
if (eti->cursor_row == row && eti->cursor_col == col){
|
if (eti->cursor_row == row && eti->cursor_col == col){
|
||||||
|
|
||||||
ecol = e_table_header_get_column (eti->header, col);
|
ecol = e_table_header_get_column (eti->header, col);
|
||||||
@ -1209,12 +1217,6 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e)
|
|||||||
e->button.y = y1;
|
e->button.y = y1;
|
||||||
|
|
||||||
e_cell_event (ecell_view, e, ecol->col_idx, col, row);
|
e_cell_event (ecell_view, e, ecol->col_idx, col, row);
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Focus the cell, and select the row
|
|
||||||
*/
|
|
||||||
e_table_item_leave_edit (eti);
|
|
||||||
e_table_item_focus (eti, col, row);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <gnome.h>
|
#include <gnome.h>
|
||||||
#include "e-util/e-cursors.h"
|
#include "e-util/e-cursors.h"
|
||||||
#include "e-tree-gnode.h"
|
|
||||||
#include "e-table-header.h"
|
#include "e-table-header.h"
|
||||||
#include "e-table-header-item.h"
|
#include "e-table-header-item.h"
|
||||||
#include "e-table-item.h"
|
#include "e-table-item.h"
|
||||||
@ -12,6 +11,7 @@
|
|||||||
#include "e-cell-tree.h"
|
#include "e-cell-tree.h"
|
||||||
#include "e-cell-checkbox.h"
|
#include "e-cell-checkbox.h"
|
||||||
#include "e-table.h"
|
#include "e-table.h"
|
||||||
|
#include "e-tree-simple.h"
|
||||||
|
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
|
||||||
@ -56,6 +56,8 @@ char *headers [COLS] = {
|
|||||||
"Date"
|
"Date"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GtkWidget *e_table;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ETableSimple callbacks
|
* ETableSimple callbacks
|
||||||
* These are the callbacks that define the behavior of our custom model.
|
* These are the callbacks that define the behavior of our custom model.
|
||||||
@ -73,12 +75,12 @@ my_col_count (ETableModel *etc, void *data)
|
|||||||
return COLS;
|
return COLS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function returns the value at a particular point in our ETableModel. */
|
/* This function returns the value at a particular point in our ETreeModel. */
|
||||||
static void *
|
static void *
|
||||||
my_value_at (ETreeModel *etc, GNode *node, int col, void *data)
|
my_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data)
|
||||||
{
|
{
|
||||||
switch (col) {
|
switch (col) {
|
||||||
case 0: return "Re: Two things";
|
case 0: return e_tree_model_node_get_data (etm, path);
|
||||||
case 1: return "Chris Toshok";
|
case 1: return "Chris Toshok";
|
||||||
case 2: return "toshok@helixcode.com";
|
case 2: return "toshok@helixcode.com";
|
||||||
case 3: return "Jun 07 2000";
|
case 3: return "Jun 07 2000";
|
||||||
@ -86,67 +88,163 @@ my_value_at (ETreeModel *etc, GNode *node, int col, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function sets the value at a particular point in our ETableModel. */
|
/* This function sets the value at a particular point in our ETreeModel. */
|
||||||
static void
|
static void
|
||||||
my_set_value_at (ETableModel *etc, GNode *node, int col, const void *val, void *data)
|
my_set_value_at (ETreeModel *etm, ETreePath *path, int col, const void *val, void *model_data)
|
||||||
{
|
{
|
||||||
|
if (col == 0) {
|
||||||
|
char *str = e_tree_model_node_get_data (etm, path);
|
||||||
|
g_free (str);
|
||||||
|
e_tree_model_node_set_data (etm, path, g_strdup(val));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function returns whether a particular cell is editable. */
|
/* This function returns whether a particular cell is editable. */
|
||||||
static gboolean
|
static gboolean
|
||||||
my_is_editable (ETableModel *etc, GNode *node, int col, void *data)
|
my_is_editable (ETreeModel *etm, ETreePath *path, int col, void *model_data)
|
||||||
{
|
{
|
||||||
return FALSE;
|
if (col == 0)
|
||||||
|
return TRUE;
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function duplicates the value passed to it. */
|
|
||||||
static void *
|
|
||||||
my_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
|
static void
|
||||||
my_free_value (ETableModel *etc, int col, void *value, void *data)
|
toggle_root (GtkButton *button, gpointer data)
|
||||||
{
|
{
|
||||||
g_free (value);
|
ETreeModel *e_tree_model = (ETreeModel*)data;
|
||||||
|
e_tree_model_root_node_set_visible (e_tree_model, !e_tree_model_root_node_is_visible (e_tree_model));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is for when the model is unfrozen. This can mostly
|
|
||||||
be ignored for simple models. */
|
|
||||||
static void
|
static void
|
||||||
my_thaw (ETableModel *etc, void *data)
|
add_sibling (GtkButton *button, gpointer data)
|
||||||
{
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
ETreePath *parent_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
parent_node = e_tree_model_node_get_parent (e_tree_model, selected_node);
|
||||||
|
|
||||||
|
e_tree_model_node_insert_before (e_tree_model, parent_node,
|
||||||
|
selected_node, "User added sibling");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_child (GtkButton *button, gpointer data)
|
||||||
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
e_tree_model_node_insert (e_tree_model, selected_node,
|
||||||
|
0, "User added child");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_node (GtkButton *button, gpointer data)
|
||||||
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
char *str;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
if (e_tree_model_node_get_children (e_tree_model, selected_node, NULL) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
str = (char*)e_tree_model_node_remove (e_tree_model, selected_node);
|
||||||
|
printf ("removed node %s\n", str);
|
||||||
|
g_free (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
expand_all (GtkButton *button, gpointer data)
|
||||||
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
e_tree_model_node_set_expanded_recurse (e_tree_model, selected_node, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
collapse_all (GtkButton *button, gpointer data)
|
||||||
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
e_tree_model_node_set_expanded_recurse (e_tree_model, selected_node, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We create a window containing our new tree. */
|
/* We create a window containing our new tree. */
|
||||||
static void
|
static void
|
||||||
create_tree (void)
|
create_tree (void)
|
||||||
{
|
{
|
||||||
GtkWidget *e_table, *window, *frame;
|
GtkWidget *window, *frame, *button, *vbox;
|
||||||
ECell *cell_left_just;
|
ECell *cell_left_just;
|
||||||
ECell *cell_tree;
|
ECell *cell_tree;
|
||||||
ETableHeader *e_table_header;
|
ETableHeader *e_table_header;
|
||||||
int i, j;
|
int i, j;
|
||||||
ETreeModel *e_tree_model = NULL;
|
ETreeModel *e_tree_model = NULL;
|
||||||
GNode *root_node;
|
ETreePath *root_node;
|
||||||
|
|
||||||
|
/* here we create our model. This uses the functions we defined
|
||||||
|
earlier. */
|
||||||
|
e_tree_model = e_tree_simple_new (my_value_at,
|
||||||
|
my_set_value_at,
|
||||||
|
my_is_editable,
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* create a root node with 5 children */
|
/* create a root node with 5 children */
|
||||||
root_node = g_node_new (NULL);
|
root_node = e_tree_model_node_insert (e_tree_model, NULL,
|
||||||
|
0, g_strdup("Root Node"));
|
||||||
|
|
||||||
for (i = 0; i < 5; i++){
|
for (i = 0; i < 5; i++){
|
||||||
GNode *n = g_node_insert (root_node, 0, g_node_new(NULL));
|
ETreePath *n = e_tree_model_node_insert (e_tree_model,
|
||||||
|
root_node, 0, g_strdup("First level of children"));
|
||||||
for (j = 0; j < 5; j ++) {
|
for (j = 0; j < 5; j ++) {
|
||||||
g_node_insert (n, 0, g_node_new(NULL));
|
e_tree_model_node_insert (e_tree_model,
|
||||||
|
n, 0, g_strdup("Second level of children"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next we create our model. This uses the functions we defined
|
|
||||||
earlier. */
|
|
||||||
e_tree_model = e_tree_gnode_new (root_node,
|
|
||||||
my_value_at,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next we create a header. The ETableHeader is used in two
|
* Next we create a header. The ETableHeader is used in two
|
||||||
* different way. The first is the full_header. This is the
|
* different way. The first is the full_header. This is the
|
||||||
@ -200,6 +298,7 @@ create_tree (void)
|
|||||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||||
|
|
||||||
/* This frame is simply to get a bevel around our table. */
|
/* This frame is simply to get a bevel around our table. */
|
||||||
|
vbox = gtk_vbox_new (FALSE, 0);
|
||||||
frame = gtk_frame_new (NULL);
|
frame = gtk_frame_new (NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -213,8 +312,34 @@ create_tree (void)
|
|||||||
|
|
||||||
/* Build the gtk widget hierarchy. */
|
/* Build the gtk widget hierarchy. */
|
||||||
gtk_container_add (GTK_CONTAINER (frame), e_table);
|
gtk_container_add (GTK_CONTAINER (frame), e_table);
|
||||||
gtk_container_add (GTK_CONTAINER (window), frame);
|
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Toggle Root Node");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", toggle_root, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Add Sibling");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", add_sibling, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Add Child");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", add_child, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Remove Node");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", remove_node, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Expand All Below");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", expand_all, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Collapse All Below");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", collapse_all, e_tree_model);
|
||||||
|
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||||
|
|
||||||
/* Size the initial window. */
|
/* Size the initial window. */
|
||||||
gtk_widget_set_usize (window, 200, 200);
|
gtk_widget_set_usize (window, 200, 200);
|
||||||
|
|
||||||
|
@ -1,210 +0,0 @@
|
|||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
||||||
/*
|
|
||||||
* e-tree-gnode.c: a Tree Model that reflects a GNode structure visually.
|
|
||||||
*
|
|
||||||
* Author:
|
|
||||||
* Chris Toshok (toshok@helixcode.com)
|
|
||||||
*
|
|
||||||
* (C) 2000 Helix Code, Inc.
|
|
||||||
*/
|
|
||||||
#include <config.h>
|
|
||||||
#include <gtk/gtksignal.h>
|
|
||||||
#include "e-util/e-util.h"
|
|
||||||
#include "e-tree-gnode.h"
|
|
||||||
|
|
||||||
#define PARENT_TYPE E_TREE_MODEL_TYPE
|
|
||||||
|
|
||||||
static ETreePath *
|
|
||||||
gnode_get_root (ETreeModel *etm)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
ETreePath *path = NULL;
|
|
||||||
|
|
||||||
path = g_list_append(path, etg->root);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ETreePath *
|
|
||||||
gnode_get_prev (ETreeModel *etm, ETreePath *node)
|
|
||||||
{
|
|
||||||
ETreePath *prev_path;
|
|
||||||
|
|
||||||
GNode *gnode;
|
|
||||||
GNode *prev_sibling;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, NULL);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
prev_sibling = g_node_prev_sibling(gnode);
|
|
||||||
|
|
||||||
if (!prev_sibling)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
prev_path = g_list_copy (node->next);
|
|
||||||
prev_path = g_list_prepend (prev_path, prev_sibling);
|
|
||||||
return prev_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ETreePath *
|
|
||||||
gnode_get_next (ETreeModel *etm, ETreePath *node)
|
|
||||||
{
|
|
||||||
ETreePath *next_path;
|
|
||||||
GNode *gnode;
|
|
||||||
GNode *next_sibling;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, NULL);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
next_sibling = g_node_next_sibling(gnode);
|
|
||||||
|
|
||||||
if (!next_sibling)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
next_path = g_list_copy (node->next);
|
|
||||||
next_path = g_list_prepend (next_path, next_sibling);
|
|
||||||
return next_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
gnode_value_at (ETreeModel *etm, ETreePath *node, int col)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, NULL);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
return etg->value_at (etm, gnode, col, etg->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gnode_set_value_at (ETreeModel *etm, ETreePath *node, int col, const void *val)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
|
|
||||||
g_return_if_fail (node && node->data);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gnode_is_editable (ETreeModel *etm, ETreePath *node, int col)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, FALSE);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static guint
|
|
||||||
gnode_get_children (ETreeModel *etm, ETreePath *node, ETreePath ***paths)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
guint n_children;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, 0);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
n_children = g_node_n_children (gnode);
|
|
||||||
|
|
||||||
if (paths)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
(*paths) = g_malloc (sizeof (ETreePath*) * n_children);
|
|
||||||
for (i = 0; i < n_children; i ++) {
|
|
||||||
(*paths)[i] = g_list_copy (node);
|
|
||||||
(*paths)[i] = g_list_prepend ((*paths)[i], g_node_nth_child (gnode, i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n_children;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gnode_release_paths (ETreeModel *etm, ETreePath **paths, guint num_paths)
|
|
||||||
{
|
|
||||||
guint i;
|
|
||||||
g_return_if_fail (paths);
|
|
||||||
|
|
||||||
for (i = 0; i < num_paths; i ++)
|
|
||||||
g_list_free (paths[i]);
|
|
||||||
g_free (paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gnode_is_expanded (ETreeModel *etm, ETreePath *node)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, FALSE);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
return (gboolean)gnode->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gnode_set_expanded (ETreeModel *etm, ETreePath *node, gboolean expanded)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
int num_descendents;
|
|
||||||
|
|
||||||
g_return_if_fail (node && node->data);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
gnode->data = (gpointer)expanded;
|
|
||||||
|
|
||||||
e_table_model_changed (E_TABLE_MODEL(etm));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
e_tree_gnode_class_init (GtkObjectClass *object_class)
|
|
||||||
{
|
|
||||||
ETreeModelClass *model_class = (ETreeModelClass *) object_class;
|
|
||||||
|
|
||||||
model_class->get_root = gnode_get_root;
|
|
||||||
model_class->get_next = gnode_get_next;
|
|
||||||
model_class->get_prev = gnode_get_prev;
|
|
||||||
model_class->value_at = gnode_value_at;
|
|
||||||
model_class->set_value_at = gnode_set_value_at;
|
|
||||||
model_class->is_editable = gnode_is_editable;
|
|
||||||
model_class->get_children = gnode_get_children;
|
|
||||||
model_class->release_paths = gnode_release_paths;
|
|
||||||
model_class->is_expanded = gnode_is_expanded;
|
|
||||||
model_class->set_expanded = gnode_set_expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
E_MAKE_TYPE(e_tree_gnode, "ETreeGNode", ETreeGNode, e_tree_gnode_class_init, NULL, PARENT_TYPE)
|
|
||||||
|
|
||||||
ETreeModel *
|
|
||||||
e_tree_gnode_new (GNode *root_node,
|
|
||||||
ETreeGNodeValueAtFn value_at,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg;
|
|
||||||
|
|
||||||
etg = gtk_type_new (e_tree_gnode_get_type ());
|
|
||||||
|
|
||||||
etg->root = root_node;
|
|
||||||
|
|
||||||
etg->value_at = value_at;
|
|
||||||
etg->data = data;
|
|
||||||
|
|
||||||
return (ETreeModel*)etg;
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
||||||
|
|
||||||
#ifndef _E_TREE_GNODE_H_
|
|
||||||
#define _E_TREE_GNODE_H_
|
|
||||||
|
|
||||||
#include "e-tree-model.h"
|
|
||||||
|
|
||||||
#define E_TREE_GNODE_TYPE (e_tree_gnode_get_type ())
|
|
||||||
#define E_TREE_GNODE(o) (GTK_CHECK_CAST ((o), E_TREE_GNODE_TYPE, ETreeGNode))
|
|
||||||
#define E_TREE_GNODE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TREE_GNODE_TYPE, ETreeGNodeClass))
|
|
||||||
#define E_IS_TREE_GNODE(o) (GTK_CHECK_TYPE ((o), E_TREE_GNODE_TYPE))
|
|
||||||
#define E_IS_TREE_GNODE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TREE_GNODE_TYPE))
|
|
||||||
|
|
||||||
typedef void *(*ETreeGNodeValueAtFn)(ETreeModel *model, GNode *node, int col, void *data);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
ETreeModel parent;
|
|
||||||
|
|
||||||
GNode *root;
|
|
||||||
|
|
||||||
ETreeGNodeValueAtFn value_at;
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
} ETreeGNode;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
ETreeModelClass parent_class;
|
|
||||||
} ETreeGNodeClass;
|
|
||||||
|
|
||||||
GtkType e_tree_gnode_get_type (void);
|
|
||||||
|
|
||||||
ETreeModel *e_tree_gnode_new (GNode *tree,
|
|
||||||
ETreeGNodeValueAtFn value_at,
|
|
||||||
void *data);
|
|
||||||
|
|
||||||
#endif /* _E_TREE_GNODE_H_ */
|
|
@ -20,21 +20,197 @@
|
|||||||
|
|
||||||
static ETableModel *e_tree_model_parent_class;
|
static ETableModel *e_tree_model_parent_class;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gboolean expanded;
|
||||||
|
guint visible_descendents;
|
||||||
|
gpointer node_data;
|
||||||
|
} ENode;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NODE_CHANGED,
|
||||||
|
NODE_INSERTED,
|
||||||
|
NODE_REMOVED,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint e_tree_model_signals [LAST_SIGNAL] = {0, };
|
||||||
|
|
||||||
|
static void add_visible_descendents_to_array (ETreeModel *etm, GNode *gnode, int *row, int *count);
|
||||||
|
|
||||||
|
|
||||||
/* virtual methods */
|
/* virtual methods */
|
||||||
|
|
||||||
|
static void
|
||||||
|
etree_destroy (GtkObject *object)
|
||||||
|
{
|
||||||
|
/* XXX lots of stuff to free here */
|
||||||
|
}
|
||||||
|
|
||||||
static ETreePath*
|
static ETreePath*
|
||||||
etree_get_root (ETreeModel *etm)
|
etree_get_root (ETreeModel *etm)
|
||||||
{
|
{
|
||||||
/* shouldn't be called */
|
return etm->root;
|
||||||
g_assert(0);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ETreePath*
|
||||||
|
etree_get_parent (ETreeModel *etm, ETreePath *path)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (path, NULL);
|
||||||
|
|
||||||
|
return path->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ETreePath*
|
||||||
|
etree_get_next (ETreeModel *etm, ETreePath *node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (node, NULL);
|
||||||
|
|
||||||
|
return g_node_next_sibling(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ETreePath*
|
||||||
|
etree_get_prev (ETreeModel *etm, ETreePath *node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (node, NULL);
|
||||||
|
|
||||||
|
return g_node_prev_sibling (node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
etree_get_children (ETreeModel *etm, ETreePath* node, ETreePath ***paths)
|
||||||
|
{
|
||||||
|
guint n_children;
|
||||||
|
|
||||||
|
g_return_val_if_fail (node, 0);
|
||||||
|
|
||||||
|
n_children = g_node_n_children (node);
|
||||||
|
|
||||||
|
if (paths) {
|
||||||
|
int i;
|
||||||
|
(*paths) = g_malloc (sizeof (ETreePath*) * n_children);
|
||||||
|
for (i = 0; i < n_children; i ++) {
|
||||||
|
(*paths)[i] = g_node_nth_child (node, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n_children;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
etree_is_expanded (ETreeModel *etm, ETreePath* node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (node && node->data, FALSE);
|
||||||
|
|
||||||
|
return ((ENode*)node->data)->expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
etree_is_visible (ETreeModel *etm, ETreePath* node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (node, FALSE);
|
||||||
|
|
||||||
|
for (node = node->parent; node; node = node->parent) {
|
||||||
|
if (!((ENode*)node->data)->expanded)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded)
|
||||||
|
{
|
||||||
|
GNode *child;
|
||||||
|
ENode *enode;
|
||||||
|
int row;
|
||||||
|
|
||||||
|
g_return_if_fail (node && node->data);
|
||||||
|
|
||||||
|
enode = ((ENode*)node->data);
|
||||||
|
|
||||||
|
if (enode->expanded == expanded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
enode->expanded = expanded;
|
||||||
|
|
||||||
|
row = e_tree_model_row_of_node (etm, node) + 1;
|
||||||
|
|
||||||
|
if (expanded) {
|
||||||
|
GNode *parent;
|
||||||
|
|
||||||
|
if (e_tree_model_node_is_visible (etm, node)) {
|
||||||
|
enode->visible_descendents = 0;
|
||||||
|
for (child = g_node_first_child (node); child;
|
||||||
|
child = g_node_next_sibling (child)) {
|
||||||
|
add_visible_descendents_to_array (etm, child, &row, &enode->visible_descendents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* now iterate back up the tree, adding to our
|
||||||
|
ancestors' visible descendents */
|
||||||
|
|
||||||
|
for (parent = node->parent; parent; parent = parent->parent) {
|
||||||
|
ENode *parent_enode = (ENode*)parent->data;
|
||||||
|
parent_enode->visible_descendents += enode->visible_descendents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int i;
|
||||||
|
GNode *parent;
|
||||||
|
|
||||||
|
if (e_tree_model_node_is_visible (etm, node)) {
|
||||||
|
for (i = 0; i < enode->visible_descendents; i ++) {
|
||||||
|
etm->row_array = g_array_remove_index (etm->row_array, row);
|
||||||
|
e_table_model_row_deleted (E_TABLE_MODEL (etm), row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* now iterate back up the tree, subtracting from our
|
||||||
|
ancestors' visible descendents */
|
||||||
|
|
||||||
|
for (parent = node->parent; parent; parent = parent->parent) {
|
||||||
|
ENode *parent_enode = (ENode*)parent->data;
|
||||||
|
|
||||||
|
parent_enode->visible_descendents -= enode->visible_descendents;
|
||||||
|
}
|
||||||
|
|
||||||
|
enode->visible_descendents = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fairly naive implementation */
|
||||||
|
static void
|
||||||
|
etree_set_expanded_recurse (ETreeModel *etm, ETreePath* node, gboolean expanded)
|
||||||
|
{
|
||||||
|
ETreePath **paths;
|
||||||
|
guint num_children;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
e_tree_model_node_set_expanded (etm, node, expanded);
|
||||||
|
|
||||||
|
num_children = e_tree_model_node_get_children (etm, node, &paths);
|
||||||
|
if (num_children) {
|
||||||
|
for (i = 0; i < num_children; i ++) {
|
||||||
|
e_tree_model_node_set_expanded_recurse (etm, paths[i], expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (paths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ETreePath *
|
||||||
|
etree_node_at_row (ETreeModel *etree, int row)
|
||||||
|
{
|
||||||
|
GNode *node = g_array_index (etree->row_array, GNode*, row);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ETable analogs */
|
||||||
static void*
|
static void*
|
||||||
etree_value_at (ETreeModel *etm, ETreePath* node, int col)
|
etree_value_at (ETreeModel *etm, ETreePath* node, int col)
|
||||||
{
|
{
|
||||||
/* shouldn't be called */
|
/* shouldn't be called */
|
||||||
g_assert(0);
|
g_assert (0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +218,7 @@ static void
|
|||||||
etree_set_value_at (ETreeModel *etm, ETreePath* node, int col, const void *val)
|
etree_set_value_at (ETreeModel *etm, ETreePath* node, int col, const void *val)
|
||||||
{
|
{
|
||||||
/* shouldn't be called */
|
/* shouldn't be called */
|
||||||
g_assert(0);
|
g_assert (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -53,65 +229,13 @@ etree_is_editable (ETreeModel *etm, ETreePath* node, int col)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
etree_is_expanded (ETreeModel *etm, ETreePath* node)
|
/* ETable virtual functions we map */
|
||||||
{
|
|
||||||
/* shouldn't be called */
|
|
||||||
g_assert(0);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static guint
|
|
||||||
etree_get_children (ETreeModel *etm, ETreePath* node, ETreePath ***paths)
|
|
||||||
{
|
|
||||||
/* shouldn't be called */
|
|
||||||
g_assert(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
etree_release_paths (ETreeModel *etm, ETreePath **paths, guint num_paths)
|
|
||||||
{
|
|
||||||
/* shouldn't be called */
|
|
||||||
g_assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded)
|
|
||||||
{
|
|
||||||
/* shouldn't be called */
|
|
||||||
g_assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
etree_destroy (GtkObject *object)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
guint
|
|
||||||
e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node)
|
|
||||||
{
|
|
||||||
int count = 1;
|
|
||||||
if (e_tree_model_node_is_expanded (etm, node)) {
|
|
||||||
ETreePath **paths;
|
|
||||||
int i;
|
|
||||||
int num_paths;
|
|
||||||
|
|
||||||
num_paths = e_tree_model_node_get_children (etm, node, &paths);
|
|
||||||
|
|
||||||
for (i = 0; i < num_paths; i ++)
|
|
||||||
count += e_tree_model_node_num_visible_descendents(etm, paths[i]);
|
|
||||||
|
|
||||||
e_tree_model_release_paths (etm, paths, num_paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
etable_row_count (ETableModel *etm)
|
etable_row_count (ETableModel *etm)
|
||||||
{
|
{
|
||||||
return e_tree_model_node_num_visible_descendents (E_TREE_MODEL (etm), e_tree_model_get_root (E_TREE_MODEL (etm)));
|
ETreeModel *tree = E_TREE_MODEL (etm);
|
||||||
|
return tree->row_array->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
@ -155,6 +279,7 @@ etable_is_cell_editable (ETableModel *etm, int col, int row)
|
|||||||
return et_class->is_editable (etree, node, col);
|
return et_class->is_editable (etree, node, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
e_tree_model_class_init (GtkObjectClass *klass)
|
e_tree_model_class_init (GtkObjectClass *klass)
|
||||||
{
|
{
|
||||||
@ -165,11 +290,38 @@ e_tree_model_class_init (GtkObjectClass *klass)
|
|||||||
|
|
||||||
klass->destroy = etree_destroy;
|
klass->destroy = etree_destroy;
|
||||||
|
|
||||||
|
e_tree_model_signals [NODE_CHANGED] =
|
||||||
|
gtk_signal_new ("node_changed",
|
||||||
|
GTK_RUN_LAST,
|
||||||
|
klass->type,
|
||||||
|
GTK_SIGNAL_OFFSET (ETreeModelClass, node_changed),
|
||||||
|
gtk_marshal_NONE__POINTER,
|
||||||
|
GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);
|
||||||
|
|
||||||
|
e_tree_model_signals [NODE_INSERTED] =
|
||||||
|
gtk_signal_new ("node_inserted",
|
||||||
|
GTK_RUN_LAST,
|
||||||
|
klass->type,
|
||||||
|
GTK_SIGNAL_OFFSET (ETreeModelClass, node_inserted),
|
||||||
|
gtk_marshal_NONE__POINTER_POINTER,
|
||||||
|
GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
|
||||||
|
|
||||||
|
e_tree_model_signals [NODE_REMOVED] =
|
||||||
|
gtk_signal_new ("node_removed",
|
||||||
|
GTK_RUN_LAST,
|
||||||
|
klass->type,
|
||||||
|
GTK_SIGNAL_OFFSET (ETreeModelClass, node_removed),
|
||||||
|
gtk_marshal_NONE__POINTER_POINTER,
|
||||||
|
GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
|
||||||
|
|
||||||
|
gtk_object_class_add_signals (klass, e_tree_model_signals, LAST_SIGNAL);
|
||||||
|
|
||||||
table_class->row_count = etable_row_count;
|
table_class->row_count = etable_row_count;
|
||||||
table_class->value_at = etable_value_at;
|
table_class->value_at = etable_value_at;
|
||||||
table_class->set_value_at = etable_set_value_at;
|
table_class->set_value_at = etable_set_value_at;
|
||||||
table_class->is_cell_editable = etable_is_cell_editable;
|
table_class->is_cell_editable = etable_is_cell_editable;
|
||||||
#if 0
|
#if 0
|
||||||
|
/* XX need to pass these through */
|
||||||
table_class->duplicate_value = etable_duplicate_value;
|
table_class->duplicate_value = etable_duplicate_value;
|
||||||
table_class->free_value = etable_free_value;
|
table_class->free_value = etable_free_value;
|
||||||
table_class->initialize_value = etable_initialize_value;
|
table_class->initialize_value = etable_initialize_value;
|
||||||
@ -178,19 +330,68 @@ e_tree_model_class_init (GtkObjectClass *klass)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
tree_class->get_root = etree_get_root;
|
tree_class->get_root = etree_get_root;
|
||||||
|
tree_class->get_prev = etree_get_prev;
|
||||||
|
tree_class->get_next = etree_get_next;
|
||||||
|
tree_class->get_parent = etree_get_parent;
|
||||||
|
|
||||||
tree_class->value_at = etree_value_at;
|
tree_class->value_at = etree_value_at;
|
||||||
tree_class->set_value_at = etree_set_value_at;
|
tree_class->set_value_at = etree_set_value_at;
|
||||||
tree_class->is_editable = etree_is_editable;
|
tree_class->is_editable = etree_is_editable;
|
||||||
|
|
||||||
tree_class->get_children = etree_get_children;
|
tree_class->get_children = etree_get_children;
|
||||||
tree_class->release_paths = etree_release_paths;
|
|
||||||
tree_class->is_expanded = etree_is_expanded;
|
tree_class->is_expanded = etree_is_expanded;
|
||||||
|
tree_class->is_visible = etree_is_visible;
|
||||||
tree_class->set_expanded = etree_set_expanded;
|
tree_class->set_expanded = etree_set_expanded;
|
||||||
|
tree_class->set_expanded_recurse = etree_set_expanded_recurse;
|
||||||
|
tree_class->node_at_row = etree_node_at_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
E_MAKE_TYPE(e_tree_model, "ETreeModel", ETreeModel, e_tree_model_class_init, NULL, PARENT_TYPE)
|
E_MAKE_TYPE(e_tree_model, "ETreeModel", ETreeModel, e_tree_model_class_init, NULL, PARENT_TYPE)
|
||||||
|
|
||||||
|
|
||||||
/* signals */
|
/* signals */
|
||||||
|
void
|
||||||
|
e_tree_model_node_changed (ETreeModel *tree_model, ETreePath *node)
|
||||||
|
{
|
||||||
|
g_return_if_fail (tree_model != NULL);
|
||||||
|
g_return_if_fail (E_IS_TREE_MODEL (tree_model));
|
||||||
|
|
||||||
|
gtk_signal_emit (GTK_OBJECT (tree_model),
|
||||||
|
e_tree_model_signals [NODE_CHANGED]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_node_inserted (ETreeModel *tree_model,
|
||||||
|
ETreePath *parent_node,
|
||||||
|
ETreePath *inserted_node)
|
||||||
|
{
|
||||||
|
g_return_if_fail (tree_model != NULL);
|
||||||
|
g_return_if_fail (E_IS_TREE_MODEL (tree_model));
|
||||||
|
|
||||||
|
gtk_signal_emit (GTK_OBJECT (tree_model),
|
||||||
|
e_tree_model_signals [NODE_INSERTED],
|
||||||
|
parent_node, inserted_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_node_removed (ETreeModel *tree_model, ETreePath *parent_node, ETreePath *removed_node)
|
||||||
|
{
|
||||||
|
g_return_if_fail (tree_model != NULL);
|
||||||
|
g_return_if_fail (E_IS_TREE_MODEL (tree_model));
|
||||||
|
|
||||||
|
gtk_signal_emit (GTK_OBJECT (tree_model),
|
||||||
|
e_tree_model_signals [NODE_REMOVED],
|
||||||
|
parent_node, removed_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_construct (ETreeModel *etree)
|
||||||
|
{
|
||||||
|
etree->root = NULL;
|
||||||
|
etree->root_visible = TRUE;
|
||||||
|
etree->row_array = g_array_new (FALSE, FALSE, sizeof(GNode*));
|
||||||
|
}
|
||||||
|
|
||||||
ETreeModel *
|
ETreeModel *
|
||||||
e_tree_model_new ()
|
e_tree_model_new ()
|
||||||
@ -202,40 +403,6 @@ e_tree_model_new ()
|
|||||||
return et;
|
return et;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ETreePath *
|
|
||||||
e_tree_model_node_at_row_1 (ETreeModel *etree, int *row, ETreePath *node)
|
|
||||||
{
|
|
||||||
ETreePath *ret = NULL;
|
|
||||||
|
|
||||||
if (*row == 0)
|
|
||||||
ret = node;
|
|
||||||
else if (e_tree_model_node_is_expanded (etree, node)) {
|
|
||||||
int num_children;
|
|
||||||
int i;
|
|
||||||
ETreePath **paths;
|
|
||||||
|
|
||||||
num_children = e_tree_model_node_get_children (etree, node, &paths);
|
|
||||||
|
|
||||||
for (i = 0; i < num_children; i ++) {
|
|
||||||
ETreePath *p;
|
|
||||||
|
|
||||||
(*row) --;
|
|
||||||
|
|
||||||
p = e_tree_model_node_at_row_1 (etree, row, paths[i]);
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
ret = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX need to find why this release is causing problems */
|
|
||||||
/* e_tree_model_release_paths (etree, paths, num_children); */
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ETreePath *
|
ETreePath *
|
||||||
e_tree_model_get_root (ETreeModel *etree)
|
e_tree_model_get_root (ETreeModel *etree)
|
||||||
{
|
{
|
||||||
@ -245,10 +412,48 @@ e_tree_model_get_root (ETreeModel *etree)
|
|||||||
ETreePath *
|
ETreePath *
|
||||||
e_tree_model_node_at_row (ETreeModel *etree, int row)
|
e_tree_model_node_at_row (ETreeModel *etree, int row)
|
||||||
{
|
{
|
||||||
/* XXX icky, perform a depth first search of the tree. we need this optimized sorely */
|
return ETM_CLASS(etree)->node_at_row (etree, row);
|
||||||
return e_tree_model_node_at_row_1 (etree, &row, ETM_CLASS(etree)->get_root(etree));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
e_tree_model_row_of_node (ETreeModel *etree, ETreePath *node)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < etree->row_array->len; i ++)
|
||||||
|
if (g_array_index (etree->row_array, GNode*, i) == node)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_root_node_set_visible (ETreeModel *etm, gboolean visible)
|
||||||
|
{
|
||||||
|
if (visible != etm->root_visible) {
|
||||||
|
etm->root_visible = visible;
|
||||||
|
if (etm->root) {
|
||||||
|
if (visible) {
|
||||||
|
etm->row_array = g_array_insert_val (etm->row_array, 0, etm->root);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ETreePath *root_path = e_tree_model_get_root (etm);
|
||||||
|
etm->row_array = g_array_remove_index (etm->row_array, 0);
|
||||||
|
e_tree_model_node_set_expanded (etm, root_path, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
e_table_model_changed (E_TABLE_MODEL (etm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
e_tree_model_root_node_is_visible (ETreeModel *etm)
|
||||||
|
{
|
||||||
|
return etm->root_visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ETreePath *
|
ETreePath *
|
||||||
e_tree_model_node_get_next (ETreeModel *etree, ETreePath *node)
|
e_tree_model_node_get_next (ETreeModel *etree, ETreePath *node)
|
||||||
{
|
{
|
||||||
@ -264,18 +469,13 @@ e_tree_model_node_get_prev (ETreeModel *etree, ETreePath *node)
|
|||||||
guint
|
guint
|
||||||
e_tree_model_node_depth (ETreeModel *etree, ETreePath *path)
|
e_tree_model_node_depth (ETreeModel *etree, ETreePath *path)
|
||||||
{
|
{
|
||||||
return g_list_length (path) - 1;
|
return g_node_depth (path) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ETreePath *
|
ETreePath *
|
||||||
e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path)
|
e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (path, NULL);
|
return ETM_CLASS(etree)->get_parent(etree, path);
|
||||||
|
|
||||||
if (path->next == NULL)
|
|
||||||
return NULL;
|
|
||||||
else
|
|
||||||
return g_list_copy (path->next);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@ -296,21 +496,190 @@ e_tree_model_node_is_expanded (ETreeModel *etree, ETreePath *path)
|
|||||||
return ETM_CLASS(etree)->is_expanded (etree, path);
|
return ETM_CLASS(etree)->is_expanded (etree, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
e_tree_model_node_is_visible (ETreeModel *etree, ETreePath *path)
|
||||||
|
{
|
||||||
|
return ETM_CLASS(etree)->is_visible (etree, path);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
e_tree_model_node_set_expanded (ETreeModel *etree, ETreePath *path, gboolean expanded)
|
e_tree_model_node_set_expanded (ETreeModel *etree, ETreePath *path, gboolean expanded)
|
||||||
{
|
{
|
||||||
ETM_CLASS(etree)->set_expanded (etree, path, expanded);
|
ETM_CLASS(etree)->set_expanded (etree, path, expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_node_set_expanded_recurse (ETreeModel *etree, ETreePath *path, gboolean expanded)
|
||||||
|
{
|
||||||
|
ETM_CLASS(etree)->set_expanded_recurse (etree, path, expanded);
|
||||||
|
}
|
||||||
|
|
||||||
guint
|
guint
|
||||||
e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths)
|
e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths)
|
||||||
{
|
{
|
||||||
return ETM_CLASS(etree)->get_children (etree, path, paths);
|
return ETM_CLASS(etree)->get_children (etree, path, paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
guint
|
||||||
e_tree_model_release_paths (ETreeModel *etree, ETreePath **paths, guint num_paths)
|
e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node)
|
||||||
{
|
{
|
||||||
ETM_CLASS(etree)->release_paths (etree, paths, num_paths);
|
ENode *enode = (ENode*)node->data;
|
||||||
|
|
||||||
|
return enode->visible_descendents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpointer
|
||||||
|
e_tree_model_node_get_data (ETreeModel *etm, ETreePath *node)
|
||||||
|
{
|
||||||
|
ENode *enode;
|
||||||
|
|
||||||
|
g_return_val_if_fail (node && node->data, NULL);
|
||||||
|
|
||||||
|
enode = (ENode*)node->data;
|
||||||
|
|
||||||
|
return enode->node_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_node_set_data (ETreeModel *etm, ETreePath *node, gpointer node_data)
|
||||||
|
{
|
||||||
|
ENode *enode;
|
||||||
|
|
||||||
|
g_return_if_fail (node && node->data);
|
||||||
|
|
||||||
|
enode = (ENode*)node->data;
|
||||||
|
|
||||||
|
enode->node_data = node_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ETreePath*
|
||||||
|
e_tree_model_node_insert (ETreeModel *tree_model,
|
||||||
|
ETreePath *parent_path,
|
||||||
|
int position,
|
||||||
|
gpointer node_data)
|
||||||
|
{
|
||||||
|
ENode *node;
|
||||||
|
ETreePath *new_path;
|
||||||
|
|
||||||
|
g_return_val_if_fail (parent_path != NULL || tree_model->root == NULL, NULL);
|
||||||
|
|
||||||
|
node = g_new0 (ENode, 1);
|
||||||
|
|
||||||
|
node->expanded = FALSE;
|
||||||
|
node->node_data = node_data;
|
||||||
|
|
||||||
|
if (parent_path != NULL) {
|
||||||
|
|
||||||
|
new_path = g_node_new (node);
|
||||||
|
|
||||||
|
g_node_insert (parent_path, position, new_path);
|
||||||
|
|
||||||
|
if (e_tree_model_node_is_visible (tree_model, new_path)) {
|
||||||
|
int parent_row;
|
||||||
|
GNode *node;
|
||||||
|
|
||||||
|
/* we need to iterate back up to the root, incrementing the number of visible
|
||||||
|
descendents */
|
||||||
|
for (node = parent_path; node; node = node->parent) {
|
||||||
|
ENode *parent_enode = (ENode*)node->data;
|
||||||
|
|
||||||
|
parent_enode->visible_descendents ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally, insert a row into the table */
|
||||||
|
parent_row = e_tree_model_row_of_node (tree_model, parent_path);
|
||||||
|
|
||||||
|
tree_model->row_array = g_array_insert_val (tree_model->row_array,
|
||||||
|
parent_row + position + 1, new_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tree_model->root = g_node_new (node);
|
||||||
|
if (tree_model->root_visible)
|
||||||
|
tree_model->row_array = g_array_insert_val (tree_model->row_array, 0, tree_model->root);
|
||||||
|
new_path = tree_model->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: find out the number of descendents that will be visible,
|
||||||
|
and call insert_row that many times. */
|
||||||
|
e_table_model_changed (E_TABLE_MODEL(tree_model));
|
||||||
|
|
||||||
|
return new_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
ETreePath *
|
||||||
|
e_tree_model_node_insert_before (ETreeModel *etree, ETreePath *parent,
|
||||||
|
ETreePath *sibling, gpointer node_data)
|
||||||
|
{
|
||||||
|
return e_tree_model_node_insert (etree, parent,
|
||||||
|
g_node_child_position (parent, sibling),
|
||||||
|
node_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpointer
|
||||||
|
e_tree_model_node_remove (ETreeModel *etree, ETreePath *path)
|
||||||
|
{
|
||||||
|
GNode *parent = path->parent;
|
||||||
|
ENode *enode = (ENode*)path->data;
|
||||||
|
gpointer ret = enode->node_data;
|
||||||
|
|
||||||
|
g_return_val_if_fail (!g_node_first_child(path), NULL);
|
||||||
|
|
||||||
|
/* clean up the display */
|
||||||
|
if (parent) {
|
||||||
|
if (e_tree_model_node_is_visible (etree, path)) {
|
||||||
|
int row = e_tree_model_row_of_node (etree, path);
|
||||||
|
etree->row_array = g_array_remove_index (etree->row_array, row);
|
||||||
|
e_table_model_row_deleted (E_TABLE_MODEL (etree), row);
|
||||||
|
|
||||||
|
/* we need to iterate back up to the root, incrementing the number of visible
|
||||||
|
descendents */
|
||||||
|
for (; parent; parent = parent->parent) {
|
||||||
|
ENode *parent_enode = (ENode*)parent->data;
|
||||||
|
|
||||||
|
parent_enode->visible_descendents --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (path == etree->root) {
|
||||||
|
etree->root = NULL;
|
||||||
|
if (etree->root_visible) {
|
||||||
|
etree->row_array = g_array_remove_index (etree->row_array, 0);
|
||||||
|
e_table_model_row_deleted (E_TABLE_MODEL (etree), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* XXX invalid path */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* now free up the storage from that path */
|
||||||
|
g_node_destroy (path);
|
||||||
|
g_free (enode);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_visible_descendents_to_array (ETreeModel *etm, GNode *gnode, int *row, int *count)
|
||||||
|
{
|
||||||
|
GNode *child;
|
||||||
|
ENode *enode;
|
||||||
|
|
||||||
|
/* add a row for this node */
|
||||||
|
etm->row_array = g_array_insert_val (etm->row_array, (*row), gnode);
|
||||||
|
e_table_model_row_inserted (E_TABLE_MODEL (etm), (*row)++);
|
||||||
|
(*count) ++;
|
||||||
|
|
||||||
|
/* then loop over its children, calling this routine for each
|
||||||
|
of them */
|
||||||
|
enode = (ENode*)gnode->data;
|
||||||
|
if (enode->expanded) {
|
||||||
|
for (child = g_node_first_child (gnode); child;
|
||||||
|
child = g_node_next_sibling (child)) {
|
||||||
|
add_visible_descendents_to_array (etm, child, row, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,18 +10,13 @@
|
|||||||
#define E_IS_TREE_MODEL(o) (GTK_CHECK_TYPE ((o), E_TREE_MODEL_TYPE))
|
#define E_IS_TREE_MODEL(o) (GTK_CHECK_TYPE ((o), E_TREE_MODEL_TYPE))
|
||||||
#define E_IS_TREE_MODEL_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TREE_MODEL_TYPE))
|
#define E_IS_TREE_MODEL_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TREE_MODEL_TYPE))
|
||||||
|
|
||||||
typedef gpointer ETreePathItem;
|
typedef GNode ETreePath;
|
||||||
typedef GList ETreePath;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ETableModel base;
|
ETableModel base;
|
||||||
|
GNode *root;
|
||||||
ETableModel *source;
|
gboolean root_visible;
|
||||||
|
GArray *row_array; /* used in the mapping between ETable and our tree */
|
||||||
ETreePath *root_node;
|
|
||||||
|
|
||||||
GArray *array;
|
|
||||||
|
|
||||||
} ETreeModel;
|
} ETreeModel;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -32,41 +27,75 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
ETreePath *(*get_root) (ETreeModel *etm);
|
ETreePath *(*get_root) (ETreeModel *etm);
|
||||||
|
|
||||||
|
ETreePath *(*get_parent) (ETreeModel *etm, ETreePath* node);
|
||||||
ETreePath *(*get_next) (ETreeModel *etm, ETreePath* node);
|
ETreePath *(*get_next) (ETreeModel *etm, ETreePath* node);
|
||||||
ETreePath *(*get_prev) (ETreeModel *etm, ETreePath* node);
|
ETreePath *(*get_prev) (ETreeModel *etm, ETreePath* node);
|
||||||
|
guint (*get_children) (ETreeModel *etm, ETreePath* node, ETreePath ***paths);
|
||||||
|
|
||||||
|
gboolean (*is_expanded) (ETreeModel *etm, ETreePath* node);
|
||||||
|
gboolean (*is_visible) (ETreeModel *etm, ETreePath* node);
|
||||||
|
void (*set_expanded) (ETreeModel *etm, ETreePath* node, gboolean expanded);
|
||||||
|
void (*set_expanded_recurse) (ETreeModel *etm, ETreePath *node, gboolean expanded);
|
||||||
|
void (*set_expanded_level) (ETreeModel *etm, ETreePath *node, gboolean expanded, int level);
|
||||||
|
|
||||||
|
ETreePath* (*node_at_row) (ETreeModel *etm, int row);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ETable analogs
|
||||||
|
*/
|
||||||
void *(*value_at) (ETreeModel *etm, ETreePath* node, int col);
|
void *(*value_at) (ETreeModel *etm, ETreePath* node, int col);
|
||||||
void (*set_value_at) (ETreeModel *etm, ETreePath* node, int col, const void *val);
|
void (*set_value_at) (ETreeModel *etm, ETreePath* node, int col, const void *val);
|
||||||
gboolean (*is_editable) (ETreeModel *etm, ETreePath* node, int col);
|
gboolean (*is_editable) (ETreeModel *etm, ETreePath* node, int col);
|
||||||
|
|
||||||
guint (*get_children) (ETreeModel *etm, ETreePath* node, ETreePath ***paths);
|
|
||||||
void (*release_paths) (ETreeModel *etm, ETreePath **paths, guint num_paths);
|
|
||||||
gboolean (*is_expanded) (ETreeModel *etm, ETreePath* node);
|
|
||||||
void (*set_expanded) (ETreeModel *etm, ETreePath* node, gboolean expanded);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signals
|
* Signals
|
||||||
*/
|
*/
|
||||||
|
void (*node_changed) (ETreeModel *etm, ETreePath *node);
|
||||||
|
void (*node_inserted) (ETreeModel *etm, ETreePath *parent, ETreePath *inserted_node);
|
||||||
|
void (*node_removed) (ETreeModel *etm, ETreePath *parent, ETreePath *removed_node);
|
||||||
|
|
||||||
} ETreeModelClass;
|
} ETreeModelClass;
|
||||||
|
|
||||||
GtkType e_tree_model_get_type (void);
|
GtkType e_tree_model_get_type (void);
|
||||||
|
void e_tree_model_construct (ETreeModel *etree);
|
||||||
ETreeModel *e_tree_model_new (void);
|
ETreeModel *e_tree_model_new (void);
|
||||||
|
|
||||||
/* operations on "nodes" in the tree */
|
/* tree traversal operations */
|
||||||
ETreePath * e_tree_model_get_root (ETreeModel *etree);
|
ETreePath *e_tree_model_get_root (ETreeModel *etree);
|
||||||
ETreePath * e_tree_model_node_at_row (ETreeModel *etree, int row);
|
|
||||||
guint e_tree_model_node_depth (ETreeModel *etree, ETreePath *path);
|
|
||||||
ETreePath *e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path);
|
ETreePath *e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path);
|
||||||
ETreePath *e_tree_model_node_get_next (ETreeModel *etree, ETreePath *path);
|
ETreePath *e_tree_model_node_get_next (ETreeModel *etree, ETreePath *path);
|
||||||
ETreePath *e_tree_model_node_get_prev (ETreeModel *etree, ETreePath *path);
|
ETreePath *e_tree_model_node_get_prev (ETreeModel *etree, ETreePath *path);
|
||||||
gboolean e_tree_model_node_is_root (ETreeModel *etree, ETreePath *path);
|
|
||||||
|
|
||||||
gboolean e_tree_model_node_is_expandable (ETreeModel *etree, ETreePath *path);
|
/* node operations */
|
||||||
gboolean e_tree_model_node_is_expanded (ETreeModel *etree, ETreePath *path);
|
ETreePath *e_tree_model_node_insert (ETreeModel *etree, ETreePath *parent, int position, gpointer node_data);
|
||||||
guint e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths);
|
ETreePath *e_tree_model_node_insert_before (ETreeModel *etree, ETreePath *parent, ETreePath *sibling, gpointer node_data);
|
||||||
void e_tree_model_release_paths (ETreeModel *etree, ETreePath **paths, guint num_paths);
|
gpointer e_tree_model_node_remove (ETreeModel *etree, ETreePath *path);
|
||||||
guint e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node);
|
|
||||||
|
/* node accessors */
|
||||||
|
gboolean e_tree_model_node_is_root (ETreeModel *etree, ETreePath *path);
|
||||||
|
gboolean e_tree_model_node_is_expandable (ETreeModel *etree, ETreePath *path);
|
||||||
|
gboolean e_tree_model_node_is_expanded (ETreeModel *etree, ETreePath *path);
|
||||||
|
gboolean e_tree_model_node_is_visible (ETreeModel *etree, ETreePath *path);
|
||||||
|
void e_tree_model_node_set_expanded (ETreeModel *etree, ETreePath *path, gboolean expanded);
|
||||||
|
void e_tree_model_node_set_expanded_recurse (ETreeModel *etree, ETreePath *path, gboolean expanded);
|
||||||
|
guint e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths);
|
||||||
|
guint e_tree_model_node_depth (ETreeModel *etree, ETreePath *path);
|
||||||
|
guint e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node);
|
||||||
|
gpointer e_tree_model_node_get_data (ETreeModel *etm, ETreePath *node);
|
||||||
|
void e_tree_model_node_set_data (ETreeModel *etm, ETreePath *node, gpointer node_data);
|
||||||
|
|
||||||
|
/* display oriented routines */
|
||||||
|
ETreePath *e_tree_model_node_at_row (ETreeModel *etree, int row);
|
||||||
|
int e_tree_model_row_of_node (ETreeModel *etree, ETreePath *path);
|
||||||
|
void e_tree_model_root_node_set_visible (ETreeModel *etree, gboolean visible);
|
||||||
|
gboolean e_tree_model_root_node_is_visible (ETreeModel *etree);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Routines for emitting signals on the ETreeModel
|
||||||
|
*/
|
||||||
|
void e_tree_model_node_changed (ETreeModel *tree_model, ETreePath *node);
|
||||||
|
void e_tree_model_node_inserted (ETreeModel *tree_model, ETreePath *parent_node, ETreePath *inserted_node);
|
||||||
|
void e_tree_model_node_removed (ETreeModel *tree_model, ETreePath *parent_node, ETreePath *removed_node);
|
||||||
|
|
||||||
#endif /* _E_TREE_MODEL_H */
|
#endif /* _E_TREE_MODEL_H */
|
||||||
|
73
widgets/e-table/e-tree-simple.c
Normal file
73
widgets/e-table/e-tree-simple.c
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||||
|
/*
|
||||||
|
* e-tree-simple.c: a Tree Model that offers a function pointer
|
||||||
|
* interface to using ETreeModel, similar to ETableSimple.
|
||||||
|
*
|
||||||
|
* Author:
|
||||||
|
* Chris Toshok (toshok@helixcode.com)
|
||||||
|
*
|
||||||
|
* (C) 2000 Helix Code, Inc. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <gtk/gtksignal.h>
|
||||||
|
#include "e-util/e-util.h"
|
||||||
|
#include "e-tree-simple.h"
|
||||||
|
|
||||||
|
#define PARENT_TYPE E_TREE_MODEL_TYPE
|
||||||
|
|
||||||
|
static void *
|
||||||
|
simple_value_at (ETreeModel *etm, ETreePath *node, int col)
|
||||||
|
{
|
||||||
|
ETreeSimple *simple = E_TREE_SIMPLE(etm);
|
||||||
|
|
||||||
|
return simple->value_at (etm, node, col, simple->model_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
simple_set_value_at (ETreeModel *etm, ETreePath *node, int col, const void *val)
|
||||||
|
{
|
||||||
|
ETreeSimple *simple = E_TREE_SIMPLE(etm);
|
||||||
|
|
||||||
|
simple->set_value_at (etm, node, col, val, simple->model_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
simple_is_editable (ETreeModel *etm, ETreePath *node, int col)
|
||||||
|
{
|
||||||
|
ETreeSimple *simple = E_TREE_SIMPLE(etm);
|
||||||
|
|
||||||
|
return simple->is_editable (etm, node, col, simple->model_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
e_tree_simple_class_init (GtkObjectClass *object_class)
|
||||||
|
{
|
||||||
|
ETreeModelClass *model_class = (ETreeModelClass *) object_class;
|
||||||
|
|
||||||
|
model_class->value_at = simple_value_at;
|
||||||
|
model_class->set_value_at = simple_set_value_at;
|
||||||
|
model_class->is_editable = simple_is_editable;
|
||||||
|
}
|
||||||
|
|
||||||
|
E_MAKE_TYPE(e_tree_simple, "ETreeSimple", ETreeSimple, e_tree_simple_class_init, NULL, PARENT_TYPE)
|
||||||
|
|
||||||
|
ETreeModel *
|
||||||
|
e_tree_simple_new (ETreeSimpleValueAtFn value_at,
|
||||||
|
ETreeSimpleSetValueAtFn set_value_at,
|
||||||
|
ETreeSimpleIsEditableFn is_editable,
|
||||||
|
gpointer model_data)
|
||||||
|
{
|
||||||
|
ETreeSimple *etg;
|
||||||
|
|
||||||
|
etg = gtk_type_new (e_tree_simple_get_type ());
|
||||||
|
|
||||||
|
e_tree_model_construct (E_TREE_MODEL (etg));
|
||||||
|
|
||||||
|
etg->value_at = value_at;
|
||||||
|
etg->set_value_at = set_value_at;
|
||||||
|
etg->is_editable = is_editable;
|
||||||
|
etg->model_data = model_data;
|
||||||
|
|
||||||
|
return (ETreeModel*)etg;
|
||||||
|
}
|
||||||
|
|
40
widgets/e-table/e-tree-simple.h
Normal file
40
widgets/e-table/e-tree-simple.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||||
|
|
||||||
|
#ifndef _E_TREE_SIMPLE_H_
|
||||||
|
#define _E_TREE_SIMPLE_H_
|
||||||
|
|
||||||
|
#include "e-tree-model.h"
|
||||||
|
|
||||||
|
#define E_TREE_SIMPLE_TYPE (e_tree_simple_get_type ())
|
||||||
|
#define E_TREE_SIMPLE(o) (GTK_CHECK_CAST ((o), E_TREE_SIMPLE_TYPE, ETreeSimple))
|
||||||
|
#define E_TREE_SIMPLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TREE_SIMPLE_TYPE, ETreeSimpleClass))
|
||||||
|
#define E_IS_TREE_SIMPLE(o) (GTK_CHECK_TYPE ((o), E_TREE_SIMPLE_TYPE))
|
||||||
|
#define E_IS_TREE_SIMPLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TREE_SIMPLE_TYPE))
|
||||||
|
|
||||||
|
|
||||||
|
typedef void* (*ETreeSimpleValueAtFn) (ETreeModel *etree, ETreePath *path, int col, void *model_data);
|
||||||
|
typedef void (*ETreeSimpleSetValueAtFn) (ETreeModel *etree, ETreePath *path, int col, const void *val, void *model_data);
|
||||||
|
typedef gboolean (*ETreeSimpleIsEditableFn) (ETreeModel *etree, ETreePath *path, int col, void *model_data);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ETreeModel parent;
|
||||||
|
|
||||||
|
ETreeSimpleValueAtFn value_at;
|
||||||
|
ETreeSimpleSetValueAtFn set_value_at;
|
||||||
|
ETreeSimpleIsEditableFn is_editable;
|
||||||
|
|
||||||
|
gpointer model_data;
|
||||||
|
} ETreeSimple;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ETreeModelClass parent_class;
|
||||||
|
} ETreeSimpleClass;
|
||||||
|
|
||||||
|
GtkType e_tree_simple_get_type (void);
|
||||||
|
|
||||||
|
ETreeModel *e_tree_simple_new (ETreeSimpleValueAtFn value_at,
|
||||||
|
ETreeSimpleSetValueAtFn set_value_at,
|
||||||
|
ETreeSimpleIsEditableFn is_editable,
|
||||||
|
gpointer model_data);
|
||||||
|
|
||||||
|
#endif /* _E_TREE_SIMPLE_H_ */
|
@ -49,6 +49,21 @@ static ECellClass *parent_class;
|
|||||||
|
|
||||||
static GdkPixbuf *tree_expanded_pixbuf, *tree_unexpanded_pixbuf;
|
static GdkPixbuf *tree_expanded_pixbuf, *tree_unexpanded_pixbuf;
|
||||||
|
|
||||||
|
#define INDENT_AMOUNT 16
|
||||||
|
|
||||||
|
static int
|
||||||
|
visible_depth_of_node (ETreeModel *tree_model, ETreePath *path)
|
||||||
|
{
|
||||||
|
return (e_tree_model_node_depth (tree_model, path)
|
||||||
|
- (e_tree_model_root_node_is_visible (tree_model) ? 0 : 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
offset_of_node (ETreeModel *tree_model, ETreePath *path)
|
||||||
|
{
|
||||||
|
return (visible_depth_of_node(tree_model, path) + 1) * INDENT_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
static ETreePath*
|
static ETreePath*
|
||||||
e_cell_tree_get_node (ETreeModel *tree_model, int row)
|
e_cell_tree_get_node (ETreeModel *tree_model, int row)
|
||||||
{
|
{
|
||||||
@ -136,7 +151,6 @@ ect_unrealize (ECellView *ecv)
|
|||||||
(* parent_class->unrealize) (ecv);
|
(* parent_class->unrealize) (ecv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define INDENT_AMOUNT 16
|
|
||||||
/*
|
/*
|
||||||
* ECell::draw method
|
* ECell::draw method
|
||||||
*/
|
*/
|
||||||
@ -167,7 +181,7 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
|
|||||||
*/
|
*/
|
||||||
node = e_cell_tree_get_node (tree_model, row);
|
node = e_cell_tree_get_node (tree_model, row);
|
||||||
|
|
||||||
offset = (e_tree_model_node_depth (tree_model, node) + 1) * INDENT_AMOUNT;
|
offset = offset_of_node (tree_model, node);
|
||||||
expandable = e_tree_model_node_is_expandable (tree_model, node);
|
expandable = e_tree_model_node_is_expandable (tree_model, node);
|
||||||
expanded = e_tree_model_node_is_expanded (tree_model, node);
|
expanded = e_tree_model_node_is_expanded (tree_model, node);
|
||||||
subcell_offset = offset;
|
subcell_offset = offset;
|
||||||
@ -196,15 +210,8 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
|
|||||||
rect.x, rect.y, rect.width, rect.height);
|
rect.x, rect.y, rect.width, rect.height);
|
||||||
gdk_gc_set_foreground (tree_view->gc, foreground);
|
gdk_gc_set_foreground (tree_view->gc, foreground);
|
||||||
|
|
||||||
|
/* draw our lines */
|
||||||
if (E_CELL_TREE(tree_view->cell_view.ecell)->draw_lines) {
|
if (E_CELL_TREE(tree_view->cell_view.ecell)->draw_lines) {
|
||||||
/* draw our lines */
|
|
||||||
gdk_draw_line (drawable, tree_view->gc,
|
|
||||||
rect.x + offset - INDENT_AMOUNT / 2,
|
|
||||||
rect.y,
|
|
||||||
rect.x + offset - INDENT_AMOUNT / 2,
|
|
||||||
(e_tree_model_node_get_next (tree_model, node)
|
|
||||||
? rect.y + rect.height
|
|
||||||
: rect.y + rect.height / 2));
|
|
||||||
|
|
||||||
gdk_draw_line (drawable, tree_view->gc,
|
gdk_draw_line (drawable, tree_view->gc,
|
||||||
rect.x + offset - INDENT_AMOUNT / 2 + 1,
|
rect.x + offset - INDENT_AMOUNT / 2 + 1,
|
||||||
@ -212,12 +219,22 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
|
|||||||
rect.x + offset,
|
rect.x + offset,
|
||||||
rect.y + rect.height / 2);
|
rect.y + rect.height / 2);
|
||||||
|
|
||||||
|
if (visible_depth_of_node (tree_model, node) != 0) {
|
||||||
|
gdk_draw_line (drawable, tree_view->gc,
|
||||||
|
rect.x + offset - INDENT_AMOUNT / 2,
|
||||||
|
rect.y,
|
||||||
|
rect.x + offset - INDENT_AMOUNT / 2,
|
||||||
|
(e_tree_model_node_get_next (tree_model, node)
|
||||||
|
? rect.y + rect.height
|
||||||
|
: rect.y + rect.height / 2));
|
||||||
|
}
|
||||||
|
|
||||||
/* now traverse back up to the root of the tree, checking at
|
/* now traverse back up to the root of the tree, checking at
|
||||||
each level if the node has siblings, and drawing the
|
each level if the node has siblings, and drawing the
|
||||||
correct vertical pipe for it's configuration. */
|
correct vertical pipe for it's configuration. */
|
||||||
node = e_tree_model_node_get_parent (tree_model, node);
|
node = e_tree_model_node_get_parent (tree_model, node);
|
||||||
offset -= INDENT_AMOUNT;
|
offset -= INDENT_AMOUNT;
|
||||||
while (node && ! e_tree_model_node_is_root (tree_model, node)) {
|
while (node && visible_depth_of_node (tree_model, node) != 0) {
|
||||||
if (e_tree_model_node_get_next(tree_model, node)) {
|
if (e_tree_model_node_get_next(tree_model, node)) {
|
||||||
gdk_draw_line (drawable, tree_view->gc,
|
gdk_draw_line (drawable, tree_view->gc,
|
||||||
rect.x + offset - INDENT_AMOUNT / 2,
|
rect.x + offset - INDENT_AMOUNT / 2,
|
||||||
@ -255,7 +272,7 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
|
|||||||
subcell_offset pixels */
|
subcell_offset pixels */
|
||||||
e_cell_draw (tree_view->subcell_view, drawable,
|
e_cell_draw (tree_view->subcell_view, drawable,
|
||||||
model_col, view_col, row, selected,
|
model_col, view_col, row, selected,
|
||||||
x1 + subcell_offset, y1, x2 + subcell_offset, y2);
|
x1 + subcell_offset, y1, x2, y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -267,13 +284,12 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col,
|
|||||||
ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
|
ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case GDK_BUTTON_PRESS:
|
case GDK_BUTTON_PRESS: {
|
||||||
case GDK_BUTTON_RELEASE: {
|
|
||||||
/* if the event happened in our area of control (and
|
/* if the event happened in our area of control (and
|
||||||
we care about it), handle it. */
|
we care about it), handle it. */
|
||||||
ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row);
|
ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row);
|
||||||
ETreePath *node = e_cell_tree_get_node (tree_model, row);
|
ETreePath *node = e_cell_tree_get_node (tree_model, row);
|
||||||
int offset = (e_tree_model_node_depth (tree_model, node) + 1) * INDENT_AMOUNT;
|
int offset = offset_of_node (tree_model, node);
|
||||||
|
|
||||||
/* only activate the tree control if the click/release happens in the icon's area. */
|
/* only activate the tree control if the click/release happens in the icon's area. */
|
||||||
if (event->button.x > (offset - INDENT_AMOUNT) && event->button.x < offset) {
|
if (event->button.x > (offset - INDENT_AMOUNT) && event->button.x < offset) {
|
||||||
@ -284,6 +300,8 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col,
|
|||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
else if (event->button.x < (offset - INDENT_AMOUNT))
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
/* otherwise, pass it off to our subcell_view */
|
/* otherwise, pass it off to our subcell_view */
|
||||||
@ -309,7 +327,10 @@ ect_height (ECellView *ecell_view, int model_col, int view_col, int row)
|
|||||||
static void *
|
static void *
|
||||||
ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
|
ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
|
||||||
{
|
{
|
||||||
return NULL;
|
/* just defer to our subcell's view */
|
||||||
|
ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
|
||||||
|
|
||||||
|
return e_cell_enter_edit (tree_view->subcell_view, model_col, view_col, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -318,6 +339,10 @@ ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
|
|||||||
static void
|
static void
|
||||||
ect_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
|
ect_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
|
||||||
{
|
{
|
||||||
|
/* just defer to our subcell's view */
|
||||||
|
ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
|
||||||
|
|
||||||
|
e_cell_leave_edit (tree_view->subcell_view, model_col, view_col, row, edit_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1197,6 +1197,14 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e)
|
|||||||
if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
|
if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
if (eti->cursor_row != row || eti->cursor_col != col){
|
||||||
|
/*
|
||||||
|
* Focus the cell, and select the row
|
||||||
|
*/
|
||||||
|
e_table_item_leave_edit (eti);
|
||||||
|
e_table_item_focus (eti, col, row);
|
||||||
|
}
|
||||||
|
|
||||||
if (eti->cursor_row == row && eti->cursor_col == col){
|
if (eti->cursor_row == row && eti->cursor_col == col){
|
||||||
|
|
||||||
ecol = e_table_header_get_column (eti->header, col);
|
ecol = e_table_header_get_column (eti->header, col);
|
||||||
@ -1209,12 +1217,6 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e)
|
|||||||
e->button.y = y1;
|
e->button.y = y1;
|
||||||
|
|
||||||
e_cell_event (ecell_view, e, ecol->col_idx, col, row);
|
e_cell_event (ecell_view, e, ecol->col_idx, col, row);
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Focus the cell, and select the row
|
|
||||||
*/
|
|
||||||
e_table_item_leave_edit (eti);
|
|
||||||
e_table_item_focus (eti, col, row);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <gnome.h>
|
#include <gnome.h>
|
||||||
#include "e-util/e-cursors.h"
|
#include "e-util/e-cursors.h"
|
||||||
#include "e-tree-gnode.h"
|
|
||||||
#include "e-table-header.h"
|
#include "e-table-header.h"
|
||||||
#include "e-table-header-item.h"
|
#include "e-table-header-item.h"
|
||||||
#include "e-table-item.h"
|
#include "e-table-item.h"
|
||||||
@ -12,6 +11,7 @@
|
|||||||
#include "e-cell-tree.h"
|
#include "e-cell-tree.h"
|
||||||
#include "e-cell-checkbox.h"
|
#include "e-cell-checkbox.h"
|
||||||
#include "e-table.h"
|
#include "e-table.h"
|
||||||
|
#include "e-tree-simple.h"
|
||||||
|
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
|
||||||
@ -56,6 +56,8 @@ char *headers [COLS] = {
|
|||||||
"Date"
|
"Date"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GtkWidget *e_table;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ETableSimple callbacks
|
* ETableSimple callbacks
|
||||||
* These are the callbacks that define the behavior of our custom model.
|
* These are the callbacks that define the behavior of our custom model.
|
||||||
@ -73,12 +75,12 @@ my_col_count (ETableModel *etc, void *data)
|
|||||||
return COLS;
|
return COLS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function returns the value at a particular point in our ETableModel. */
|
/* This function returns the value at a particular point in our ETreeModel. */
|
||||||
static void *
|
static void *
|
||||||
my_value_at (ETreeModel *etc, GNode *node, int col, void *data)
|
my_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data)
|
||||||
{
|
{
|
||||||
switch (col) {
|
switch (col) {
|
||||||
case 0: return "Re: Two things";
|
case 0: return e_tree_model_node_get_data (etm, path);
|
||||||
case 1: return "Chris Toshok";
|
case 1: return "Chris Toshok";
|
||||||
case 2: return "toshok@helixcode.com";
|
case 2: return "toshok@helixcode.com";
|
||||||
case 3: return "Jun 07 2000";
|
case 3: return "Jun 07 2000";
|
||||||
@ -86,67 +88,163 @@ my_value_at (ETreeModel *etc, GNode *node, int col, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function sets the value at a particular point in our ETableModel. */
|
/* This function sets the value at a particular point in our ETreeModel. */
|
||||||
static void
|
static void
|
||||||
my_set_value_at (ETableModel *etc, GNode *node, int col, const void *val, void *data)
|
my_set_value_at (ETreeModel *etm, ETreePath *path, int col, const void *val, void *model_data)
|
||||||
{
|
{
|
||||||
|
if (col == 0) {
|
||||||
|
char *str = e_tree_model_node_get_data (etm, path);
|
||||||
|
g_free (str);
|
||||||
|
e_tree_model_node_set_data (etm, path, g_strdup(val));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function returns whether a particular cell is editable. */
|
/* This function returns whether a particular cell is editable. */
|
||||||
static gboolean
|
static gboolean
|
||||||
my_is_editable (ETableModel *etc, GNode *node, int col, void *data)
|
my_is_editable (ETreeModel *etm, ETreePath *path, int col, void *model_data)
|
||||||
{
|
{
|
||||||
return FALSE;
|
if (col == 0)
|
||||||
|
return TRUE;
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function duplicates the value passed to it. */
|
|
||||||
static void *
|
|
||||||
my_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
|
static void
|
||||||
my_free_value (ETableModel *etc, int col, void *value, void *data)
|
toggle_root (GtkButton *button, gpointer data)
|
||||||
{
|
{
|
||||||
g_free (value);
|
ETreeModel *e_tree_model = (ETreeModel*)data;
|
||||||
|
e_tree_model_root_node_set_visible (e_tree_model, !e_tree_model_root_node_is_visible (e_tree_model));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is for when the model is unfrozen. This can mostly
|
|
||||||
be ignored for simple models. */
|
|
||||||
static void
|
static void
|
||||||
my_thaw (ETableModel *etc, void *data)
|
add_sibling (GtkButton *button, gpointer data)
|
||||||
{
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
ETreePath *parent_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
parent_node = e_tree_model_node_get_parent (e_tree_model, selected_node);
|
||||||
|
|
||||||
|
e_tree_model_node_insert_before (e_tree_model, parent_node,
|
||||||
|
selected_node, "User added sibling");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_child (GtkButton *button, gpointer data)
|
||||||
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
e_tree_model_node_insert (e_tree_model, selected_node,
|
||||||
|
0, "User added child");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_node (GtkButton *button, gpointer data)
|
||||||
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
char *str;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
if (e_tree_model_node_get_children (e_tree_model, selected_node, NULL) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
str = (char*)e_tree_model_node_remove (e_tree_model, selected_node);
|
||||||
|
printf ("removed node %s\n", str);
|
||||||
|
g_free (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
expand_all (GtkButton *button, gpointer data)
|
||||||
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
e_tree_model_node_set_expanded_recurse (e_tree_model, selected_node, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
collapse_all (GtkButton *button, gpointer data)
|
||||||
|
{
|
||||||
|
ETreeModel *e_tree_model = E_TREE_MODEL (data);
|
||||||
|
int selected_row;
|
||||||
|
ETreePath *selected_node;
|
||||||
|
|
||||||
|
selected_row = e_table_get_selected_view_row (E_TABLE (e_table));
|
||||||
|
if (selected_row == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_node = e_tree_model_node_at_row (e_tree_model, selected_row);
|
||||||
|
g_assert (selected_node);
|
||||||
|
|
||||||
|
e_tree_model_node_set_expanded_recurse (e_tree_model, selected_node, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We create a window containing our new tree. */
|
/* We create a window containing our new tree. */
|
||||||
static void
|
static void
|
||||||
create_tree (void)
|
create_tree (void)
|
||||||
{
|
{
|
||||||
GtkWidget *e_table, *window, *frame;
|
GtkWidget *window, *frame, *button, *vbox;
|
||||||
ECell *cell_left_just;
|
ECell *cell_left_just;
|
||||||
ECell *cell_tree;
|
ECell *cell_tree;
|
||||||
ETableHeader *e_table_header;
|
ETableHeader *e_table_header;
|
||||||
int i, j;
|
int i, j;
|
||||||
ETreeModel *e_tree_model = NULL;
|
ETreeModel *e_tree_model = NULL;
|
||||||
GNode *root_node;
|
ETreePath *root_node;
|
||||||
|
|
||||||
|
/* here we create our model. This uses the functions we defined
|
||||||
|
earlier. */
|
||||||
|
e_tree_model = e_tree_simple_new (my_value_at,
|
||||||
|
my_set_value_at,
|
||||||
|
my_is_editable,
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* create a root node with 5 children */
|
/* create a root node with 5 children */
|
||||||
root_node = g_node_new (NULL);
|
root_node = e_tree_model_node_insert (e_tree_model, NULL,
|
||||||
|
0, g_strdup("Root Node"));
|
||||||
|
|
||||||
for (i = 0; i < 5; i++){
|
for (i = 0; i < 5; i++){
|
||||||
GNode *n = g_node_insert (root_node, 0, g_node_new(NULL));
|
ETreePath *n = e_tree_model_node_insert (e_tree_model,
|
||||||
|
root_node, 0, g_strdup("First level of children"));
|
||||||
for (j = 0; j < 5; j ++) {
|
for (j = 0; j < 5; j ++) {
|
||||||
g_node_insert (n, 0, g_node_new(NULL));
|
e_tree_model_node_insert (e_tree_model,
|
||||||
|
n, 0, g_strdup("Second level of children"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next we create our model. This uses the functions we defined
|
|
||||||
earlier. */
|
|
||||||
e_tree_model = e_tree_gnode_new (root_node,
|
|
||||||
my_value_at,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next we create a header. The ETableHeader is used in two
|
* Next we create a header. The ETableHeader is used in two
|
||||||
* different way. The first is the full_header. This is the
|
* different way. The first is the full_header. This is the
|
||||||
@ -200,6 +298,7 @@ create_tree (void)
|
|||||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||||
|
|
||||||
/* This frame is simply to get a bevel around our table. */
|
/* This frame is simply to get a bevel around our table. */
|
||||||
|
vbox = gtk_vbox_new (FALSE, 0);
|
||||||
frame = gtk_frame_new (NULL);
|
frame = gtk_frame_new (NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -213,8 +312,34 @@ create_tree (void)
|
|||||||
|
|
||||||
/* Build the gtk widget hierarchy. */
|
/* Build the gtk widget hierarchy. */
|
||||||
gtk_container_add (GTK_CONTAINER (frame), e_table);
|
gtk_container_add (GTK_CONTAINER (frame), e_table);
|
||||||
gtk_container_add (GTK_CONTAINER (window), frame);
|
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Toggle Root Node");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", toggle_root, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Add Sibling");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", add_sibling, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Add Child");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", add_child, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Remove Node");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", remove_node, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Expand All Below");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", expand_all, e_tree_model);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label ("Collapse All Below");
|
||||||
|
gtk_signal_connect (GTK_OBJECT (button), "clicked", collapse_all, e_tree_model);
|
||||||
|
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||||
|
|
||||||
/* Size the initial window. */
|
/* Size the initial window. */
|
||||||
gtk_widget_set_usize (window, 200, 200);
|
gtk_widget_set_usize (window, 200, 200);
|
||||||
|
|
||||||
|
@ -1,210 +0,0 @@
|
|||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
||||||
/*
|
|
||||||
* e-tree-gnode.c: a Tree Model that reflects a GNode structure visually.
|
|
||||||
*
|
|
||||||
* Author:
|
|
||||||
* Chris Toshok (toshok@helixcode.com)
|
|
||||||
*
|
|
||||||
* (C) 2000 Helix Code, Inc.
|
|
||||||
*/
|
|
||||||
#include <config.h>
|
|
||||||
#include <gtk/gtksignal.h>
|
|
||||||
#include "e-util/e-util.h"
|
|
||||||
#include "e-tree-gnode.h"
|
|
||||||
|
|
||||||
#define PARENT_TYPE E_TREE_MODEL_TYPE
|
|
||||||
|
|
||||||
static ETreePath *
|
|
||||||
gnode_get_root (ETreeModel *etm)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
ETreePath *path = NULL;
|
|
||||||
|
|
||||||
path = g_list_append(path, etg->root);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ETreePath *
|
|
||||||
gnode_get_prev (ETreeModel *etm, ETreePath *node)
|
|
||||||
{
|
|
||||||
ETreePath *prev_path;
|
|
||||||
|
|
||||||
GNode *gnode;
|
|
||||||
GNode *prev_sibling;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, NULL);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
prev_sibling = g_node_prev_sibling(gnode);
|
|
||||||
|
|
||||||
if (!prev_sibling)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
prev_path = g_list_copy (node->next);
|
|
||||||
prev_path = g_list_prepend (prev_path, prev_sibling);
|
|
||||||
return prev_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ETreePath *
|
|
||||||
gnode_get_next (ETreeModel *etm, ETreePath *node)
|
|
||||||
{
|
|
||||||
ETreePath *next_path;
|
|
||||||
GNode *gnode;
|
|
||||||
GNode *next_sibling;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, NULL);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
next_sibling = g_node_next_sibling(gnode);
|
|
||||||
|
|
||||||
if (!next_sibling)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
next_path = g_list_copy (node->next);
|
|
||||||
next_path = g_list_prepend (next_path, next_sibling);
|
|
||||||
return next_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
gnode_value_at (ETreeModel *etm, ETreePath *node, int col)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, NULL);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
return etg->value_at (etm, gnode, col, etg->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gnode_set_value_at (ETreeModel *etm, ETreePath *node, int col, const void *val)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
|
|
||||||
g_return_if_fail (node && node->data);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gnode_is_editable (ETreeModel *etm, ETreePath *node, int col)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, FALSE);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static guint
|
|
||||||
gnode_get_children (ETreeModel *etm, ETreePath *node, ETreePath ***paths)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
guint n_children;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, 0);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
n_children = g_node_n_children (gnode);
|
|
||||||
|
|
||||||
if (paths)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
(*paths) = g_malloc (sizeof (ETreePath*) * n_children);
|
|
||||||
for (i = 0; i < n_children; i ++) {
|
|
||||||
(*paths)[i] = g_list_copy (node);
|
|
||||||
(*paths)[i] = g_list_prepend ((*paths)[i], g_node_nth_child (gnode, i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n_children;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gnode_release_paths (ETreeModel *etm, ETreePath **paths, guint num_paths)
|
|
||||||
{
|
|
||||||
guint i;
|
|
||||||
g_return_if_fail (paths);
|
|
||||||
|
|
||||||
for (i = 0; i < num_paths; i ++)
|
|
||||||
g_list_free (paths[i]);
|
|
||||||
g_free (paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gnode_is_expanded (ETreeModel *etm, ETreePath *node)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
|
|
||||||
g_return_val_if_fail (node && node->data, FALSE);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
return (gboolean)gnode->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gnode_set_expanded (ETreeModel *etm, ETreePath *node, gboolean expanded)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg = E_TREE_GNODE (etm);
|
|
||||||
GNode *gnode;
|
|
||||||
int num_descendents;
|
|
||||||
|
|
||||||
g_return_if_fail (node && node->data);
|
|
||||||
|
|
||||||
gnode = (GNode*)node->data;
|
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
gnode->data = (gpointer)expanded;
|
|
||||||
|
|
||||||
e_table_model_changed (E_TABLE_MODEL(etm));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
e_tree_gnode_class_init (GtkObjectClass *object_class)
|
|
||||||
{
|
|
||||||
ETreeModelClass *model_class = (ETreeModelClass *) object_class;
|
|
||||||
|
|
||||||
model_class->get_root = gnode_get_root;
|
|
||||||
model_class->get_next = gnode_get_next;
|
|
||||||
model_class->get_prev = gnode_get_prev;
|
|
||||||
model_class->value_at = gnode_value_at;
|
|
||||||
model_class->set_value_at = gnode_set_value_at;
|
|
||||||
model_class->is_editable = gnode_is_editable;
|
|
||||||
model_class->get_children = gnode_get_children;
|
|
||||||
model_class->release_paths = gnode_release_paths;
|
|
||||||
model_class->is_expanded = gnode_is_expanded;
|
|
||||||
model_class->set_expanded = gnode_set_expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
E_MAKE_TYPE(e_tree_gnode, "ETreeGNode", ETreeGNode, e_tree_gnode_class_init, NULL, PARENT_TYPE)
|
|
||||||
|
|
||||||
ETreeModel *
|
|
||||||
e_tree_gnode_new (GNode *root_node,
|
|
||||||
ETreeGNodeValueAtFn value_at,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
ETreeGNode *etg;
|
|
||||||
|
|
||||||
etg = gtk_type_new (e_tree_gnode_get_type ());
|
|
||||||
|
|
||||||
etg->root = root_node;
|
|
||||||
|
|
||||||
etg->value_at = value_at;
|
|
||||||
etg->data = data;
|
|
||||||
|
|
||||||
return (ETreeModel*)etg;
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
||||||
|
|
||||||
#ifndef _E_TREE_GNODE_H_
|
|
||||||
#define _E_TREE_GNODE_H_
|
|
||||||
|
|
||||||
#include "e-tree-model.h"
|
|
||||||
|
|
||||||
#define E_TREE_GNODE_TYPE (e_tree_gnode_get_type ())
|
|
||||||
#define E_TREE_GNODE(o) (GTK_CHECK_CAST ((o), E_TREE_GNODE_TYPE, ETreeGNode))
|
|
||||||
#define E_TREE_GNODE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TREE_GNODE_TYPE, ETreeGNodeClass))
|
|
||||||
#define E_IS_TREE_GNODE(o) (GTK_CHECK_TYPE ((o), E_TREE_GNODE_TYPE))
|
|
||||||
#define E_IS_TREE_GNODE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TREE_GNODE_TYPE))
|
|
||||||
|
|
||||||
typedef void *(*ETreeGNodeValueAtFn)(ETreeModel *model, GNode *node, int col, void *data);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
ETreeModel parent;
|
|
||||||
|
|
||||||
GNode *root;
|
|
||||||
|
|
||||||
ETreeGNodeValueAtFn value_at;
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
} ETreeGNode;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
ETreeModelClass parent_class;
|
|
||||||
} ETreeGNodeClass;
|
|
||||||
|
|
||||||
GtkType e_tree_gnode_get_type (void);
|
|
||||||
|
|
||||||
ETreeModel *e_tree_gnode_new (GNode *tree,
|
|
||||||
ETreeGNodeValueAtFn value_at,
|
|
||||||
void *data);
|
|
||||||
|
|
||||||
#endif /* _E_TREE_GNODE_H_ */
|
|
@ -20,21 +20,197 @@
|
|||||||
|
|
||||||
static ETableModel *e_tree_model_parent_class;
|
static ETableModel *e_tree_model_parent_class;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gboolean expanded;
|
||||||
|
guint visible_descendents;
|
||||||
|
gpointer node_data;
|
||||||
|
} ENode;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NODE_CHANGED,
|
||||||
|
NODE_INSERTED,
|
||||||
|
NODE_REMOVED,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint e_tree_model_signals [LAST_SIGNAL] = {0, };
|
||||||
|
|
||||||
|
static void add_visible_descendents_to_array (ETreeModel *etm, GNode *gnode, int *row, int *count);
|
||||||
|
|
||||||
|
|
||||||
/* virtual methods */
|
/* virtual methods */
|
||||||
|
|
||||||
|
static void
|
||||||
|
etree_destroy (GtkObject *object)
|
||||||
|
{
|
||||||
|
/* XXX lots of stuff to free here */
|
||||||
|
}
|
||||||
|
|
||||||
static ETreePath*
|
static ETreePath*
|
||||||
etree_get_root (ETreeModel *etm)
|
etree_get_root (ETreeModel *etm)
|
||||||
{
|
{
|
||||||
/* shouldn't be called */
|
return etm->root;
|
||||||
g_assert(0);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ETreePath*
|
||||||
|
etree_get_parent (ETreeModel *etm, ETreePath *path)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (path, NULL);
|
||||||
|
|
||||||
|
return path->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ETreePath*
|
||||||
|
etree_get_next (ETreeModel *etm, ETreePath *node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (node, NULL);
|
||||||
|
|
||||||
|
return g_node_next_sibling(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ETreePath*
|
||||||
|
etree_get_prev (ETreeModel *etm, ETreePath *node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (node, NULL);
|
||||||
|
|
||||||
|
return g_node_prev_sibling (node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
etree_get_children (ETreeModel *etm, ETreePath* node, ETreePath ***paths)
|
||||||
|
{
|
||||||
|
guint n_children;
|
||||||
|
|
||||||
|
g_return_val_if_fail (node, 0);
|
||||||
|
|
||||||
|
n_children = g_node_n_children (node);
|
||||||
|
|
||||||
|
if (paths) {
|
||||||
|
int i;
|
||||||
|
(*paths) = g_malloc (sizeof (ETreePath*) * n_children);
|
||||||
|
for (i = 0; i < n_children; i ++) {
|
||||||
|
(*paths)[i] = g_node_nth_child (node, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n_children;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
etree_is_expanded (ETreeModel *etm, ETreePath* node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (node && node->data, FALSE);
|
||||||
|
|
||||||
|
return ((ENode*)node->data)->expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
etree_is_visible (ETreeModel *etm, ETreePath* node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (node, FALSE);
|
||||||
|
|
||||||
|
for (node = node->parent; node; node = node->parent) {
|
||||||
|
if (!((ENode*)node->data)->expanded)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded)
|
||||||
|
{
|
||||||
|
GNode *child;
|
||||||
|
ENode *enode;
|
||||||
|
int row;
|
||||||
|
|
||||||
|
g_return_if_fail (node && node->data);
|
||||||
|
|
||||||
|
enode = ((ENode*)node->data);
|
||||||
|
|
||||||
|
if (enode->expanded == expanded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
enode->expanded = expanded;
|
||||||
|
|
||||||
|
row = e_tree_model_row_of_node (etm, node) + 1;
|
||||||
|
|
||||||
|
if (expanded) {
|
||||||
|
GNode *parent;
|
||||||
|
|
||||||
|
if (e_tree_model_node_is_visible (etm, node)) {
|
||||||
|
enode->visible_descendents = 0;
|
||||||
|
for (child = g_node_first_child (node); child;
|
||||||
|
child = g_node_next_sibling (child)) {
|
||||||
|
add_visible_descendents_to_array (etm, child, &row, &enode->visible_descendents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* now iterate back up the tree, adding to our
|
||||||
|
ancestors' visible descendents */
|
||||||
|
|
||||||
|
for (parent = node->parent; parent; parent = parent->parent) {
|
||||||
|
ENode *parent_enode = (ENode*)parent->data;
|
||||||
|
parent_enode->visible_descendents += enode->visible_descendents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int i;
|
||||||
|
GNode *parent;
|
||||||
|
|
||||||
|
if (e_tree_model_node_is_visible (etm, node)) {
|
||||||
|
for (i = 0; i < enode->visible_descendents; i ++) {
|
||||||
|
etm->row_array = g_array_remove_index (etm->row_array, row);
|
||||||
|
e_table_model_row_deleted (E_TABLE_MODEL (etm), row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* now iterate back up the tree, subtracting from our
|
||||||
|
ancestors' visible descendents */
|
||||||
|
|
||||||
|
for (parent = node->parent; parent; parent = parent->parent) {
|
||||||
|
ENode *parent_enode = (ENode*)parent->data;
|
||||||
|
|
||||||
|
parent_enode->visible_descendents -= enode->visible_descendents;
|
||||||
|
}
|
||||||
|
|
||||||
|
enode->visible_descendents = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fairly naive implementation */
|
||||||
|
static void
|
||||||
|
etree_set_expanded_recurse (ETreeModel *etm, ETreePath* node, gboolean expanded)
|
||||||
|
{
|
||||||
|
ETreePath **paths;
|
||||||
|
guint num_children;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
e_tree_model_node_set_expanded (etm, node, expanded);
|
||||||
|
|
||||||
|
num_children = e_tree_model_node_get_children (etm, node, &paths);
|
||||||
|
if (num_children) {
|
||||||
|
for (i = 0; i < num_children; i ++) {
|
||||||
|
e_tree_model_node_set_expanded_recurse (etm, paths[i], expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (paths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ETreePath *
|
||||||
|
etree_node_at_row (ETreeModel *etree, int row)
|
||||||
|
{
|
||||||
|
GNode *node = g_array_index (etree->row_array, GNode*, row);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ETable analogs */
|
||||||
static void*
|
static void*
|
||||||
etree_value_at (ETreeModel *etm, ETreePath* node, int col)
|
etree_value_at (ETreeModel *etm, ETreePath* node, int col)
|
||||||
{
|
{
|
||||||
/* shouldn't be called */
|
/* shouldn't be called */
|
||||||
g_assert(0);
|
g_assert (0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +218,7 @@ static void
|
|||||||
etree_set_value_at (ETreeModel *etm, ETreePath* node, int col, const void *val)
|
etree_set_value_at (ETreeModel *etm, ETreePath* node, int col, const void *val)
|
||||||
{
|
{
|
||||||
/* shouldn't be called */
|
/* shouldn't be called */
|
||||||
g_assert(0);
|
g_assert (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -53,65 +229,13 @@ etree_is_editable (ETreeModel *etm, ETreePath* node, int col)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
etree_is_expanded (ETreeModel *etm, ETreePath* node)
|
/* ETable virtual functions we map */
|
||||||
{
|
|
||||||
/* shouldn't be called */
|
|
||||||
g_assert(0);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static guint
|
|
||||||
etree_get_children (ETreeModel *etm, ETreePath* node, ETreePath ***paths)
|
|
||||||
{
|
|
||||||
/* shouldn't be called */
|
|
||||||
g_assert(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
etree_release_paths (ETreeModel *etm, ETreePath **paths, guint num_paths)
|
|
||||||
{
|
|
||||||
/* shouldn't be called */
|
|
||||||
g_assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded)
|
|
||||||
{
|
|
||||||
/* shouldn't be called */
|
|
||||||
g_assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
etree_destroy (GtkObject *object)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
guint
|
|
||||||
e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node)
|
|
||||||
{
|
|
||||||
int count = 1;
|
|
||||||
if (e_tree_model_node_is_expanded (etm, node)) {
|
|
||||||
ETreePath **paths;
|
|
||||||
int i;
|
|
||||||
int num_paths;
|
|
||||||
|
|
||||||
num_paths = e_tree_model_node_get_children (etm, node, &paths);
|
|
||||||
|
|
||||||
for (i = 0; i < num_paths; i ++)
|
|
||||||
count += e_tree_model_node_num_visible_descendents(etm, paths[i]);
|
|
||||||
|
|
||||||
e_tree_model_release_paths (etm, paths, num_paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
etable_row_count (ETableModel *etm)
|
etable_row_count (ETableModel *etm)
|
||||||
{
|
{
|
||||||
return e_tree_model_node_num_visible_descendents (E_TREE_MODEL (etm), e_tree_model_get_root (E_TREE_MODEL (etm)));
|
ETreeModel *tree = E_TREE_MODEL (etm);
|
||||||
|
return tree->row_array->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
@ -155,6 +279,7 @@ etable_is_cell_editable (ETableModel *etm, int col, int row)
|
|||||||
return et_class->is_editable (etree, node, col);
|
return et_class->is_editable (etree, node, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
e_tree_model_class_init (GtkObjectClass *klass)
|
e_tree_model_class_init (GtkObjectClass *klass)
|
||||||
{
|
{
|
||||||
@ -165,11 +290,38 @@ e_tree_model_class_init (GtkObjectClass *klass)
|
|||||||
|
|
||||||
klass->destroy = etree_destroy;
|
klass->destroy = etree_destroy;
|
||||||
|
|
||||||
|
e_tree_model_signals [NODE_CHANGED] =
|
||||||
|
gtk_signal_new ("node_changed",
|
||||||
|
GTK_RUN_LAST,
|
||||||
|
klass->type,
|
||||||
|
GTK_SIGNAL_OFFSET (ETreeModelClass, node_changed),
|
||||||
|
gtk_marshal_NONE__POINTER,
|
||||||
|
GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);
|
||||||
|
|
||||||
|
e_tree_model_signals [NODE_INSERTED] =
|
||||||
|
gtk_signal_new ("node_inserted",
|
||||||
|
GTK_RUN_LAST,
|
||||||
|
klass->type,
|
||||||
|
GTK_SIGNAL_OFFSET (ETreeModelClass, node_inserted),
|
||||||
|
gtk_marshal_NONE__POINTER_POINTER,
|
||||||
|
GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
|
||||||
|
|
||||||
|
e_tree_model_signals [NODE_REMOVED] =
|
||||||
|
gtk_signal_new ("node_removed",
|
||||||
|
GTK_RUN_LAST,
|
||||||
|
klass->type,
|
||||||
|
GTK_SIGNAL_OFFSET (ETreeModelClass, node_removed),
|
||||||
|
gtk_marshal_NONE__POINTER_POINTER,
|
||||||
|
GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
|
||||||
|
|
||||||
|
gtk_object_class_add_signals (klass, e_tree_model_signals, LAST_SIGNAL);
|
||||||
|
|
||||||
table_class->row_count = etable_row_count;
|
table_class->row_count = etable_row_count;
|
||||||
table_class->value_at = etable_value_at;
|
table_class->value_at = etable_value_at;
|
||||||
table_class->set_value_at = etable_set_value_at;
|
table_class->set_value_at = etable_set_value_at;
|
||||||
table_class->is_cell_editable = etable_is_cell_editable;
|
table_class->is_cell_editable = etable_is_cell_editable;
|
||||||
#if 0
|
#if 0
|
||||||
|
/* XX need to pass these through */
|
||||||
table_class->duplicate_value = etable_duplicate_value;
|
table_class->duplicate_value = etable_duplicate_value;
|
||||||
table_class->free_value = etable_free_value;
|
table_class->free_value = etable_free_value;
|
||||||
table_class->initialize_value = etable_initialize_value;
|
table_class->initialize_value = etable_initialize_value;
|
||||||
@ -178,19 +330,68 @@ e_tree_model_class_init (GtkObjectClass *klass)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
tree_class->get_root = etree_get_root;
|
tree_class->get_root = etree_get_root;
|
||||||
|
tree_class->get_prev = etree_get_prev;
|
||||||
|
tree_class->get_next = etree_get_next;
|
||||||
|
tree_class->get_parent = etree_get_parent;
|
||||||
|
|
||||||
tree_class->value_at = etree_value_at;
|
tree_class->value_at = etree_value_at;
|
||||||
tree_class->set_value_at = etree_set_value_at;
|
tree_class->set_value_at = etree_set_value_at;
|
||||||
tree_class->is_editable = etree_is_editable;
|
tree_class->is_editable = etree_is_editable;
|
||||||
|
|
||||||
tree_class->get_children = etree_get_children;
|
tree_class->get_children = etree_get_children;
|
||||||
tree_class->release_paths = etree_release_paths;
|
|
||||||
tree_class->is_expanded = etree_is_expanded;
|
tree_class->is_expanded = etree_is_expanded;
|
||||||
|
tree_class->is_visible = etree_is_visible;
|
||||||
tree_class->set_expanded = etree_set_expanded;
|
tree_class->set_expanded = etree_set_expanded;
|
||||||
|
tree_class->set_expanded_recurse = etree_set_expanded_recurse;
|
||||||
|
tree_class->node_at_row = etree_node_at_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
E_MAKE_TYPE(e_tree_model, "ETreeModel", ETreeModel, e_tree_model_class_init, NULL, PARENT_TYPE)
|
E_MAKE_TYPE(e_tree_model, "ETreeModel", ETreeModel, e_tree_model_class_init, NULL, PARENT_TYPE)
|
||||||
|
|
||||||
|
|
||||||
/* signals */
|
/* signals */
|
||||||
|
void
|
||||||
|
e_tree_model_node_changed (ETreeModel *tree_model, ETreePath *node)
|
||||||
|
{
|
||||||
|
g_return_if_fail (tree_model != NULL);
|
||||||
|
g_return_if_fail (E_IS_TREE_MODEL (tree_model));
|
||||||
|
|
||||||
|
gtk_signal_emit (GTK_OBJECT (tree_model),
|
||||||
|
e_tree_model_signals [NODE_CHANGED]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_node_inserted (ETreeModel *tree_model,
|
||||||
|
ETreePath *parent_node,
|
||||||
|
ETreePath *inserted_node)
|
||||||
|
{
|
||||||
|
g_return_if_fail (tree_model != NULL);
|
||||||
|
g_return_if_fail (E_IS_TREE_MODEL (tree_model));
|
||||||
|
|
||||||
|
gtk_signal_emit (GTK_OBJECT (tree_model),
|
||||||
|
e_tree_model_signals [NODE_INSERTED],
|
||||||
|
parent_node, inserted_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_node_removed (ETreeModel *tree_model, ETreePath *parent_node, ETreePath *removed_node)
|
||||||
|
{
|
||||||
|
g_return_if_fail (tree_model != NULL);
|
||||||
|
g_return_if_fail (E_IS_TREE_MODEL (tree_model));
|
||||||
|
|
||||||
|
gtk_signal_emit (GTK_OBJECT (tree_model),
|
||||||
|
e_tree_model_signals [NODE_REMOVED],
|
||||||
|
parent_node, removed_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_construct (ETreeModel *etree)
|
||||||
|
{
|
||||||
|
etree->root = NULL;
|
||||||
|
etree->root_visible = TRUE;
|
||||||
|
etree->row_array = g_array_new (FALSE, FALSE, sizeof(GNode*));
|
||||||
|
}
|
||||||
|
|
||||||
ETreeModel *
|
ETreeModel *
|
||||||
e_tree_model_new ()
|
e_tree_model_new ()
|
||||||
@ -202,40 +403,6 @@ e_tree_model_new ()
|
|||||||
return et;
|
return et;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ETreePath *
|
|
||||||
e_tree_model_node_at_row_1 (ETreeModel *etree, int *row, ETreePath *node)
|
|
||||||
{
|
|
||||||
ETreePath *ret = NULL;
|
|
||||||
|
|
||||||
if (*row == 0)
|
|
||||||
ret = node;
|
|
||||||
else if (e_tree_model_node_is_expanded (etree, node)) {
|
|
||||||
int num_children;
|
|
||||||
int i;
|
|
||||||
ETreePath **paths;
|
|
||||||
|
|
||||||
num_children = e_tree_model_node_get_children (etree, node, &paths);
|
|
||||||
|
|
||||||
for (i = 0; i < num_children; i ++) {
|
|
||||||
ETreePath *p;
|
|
||||||
|
|
||||||
(*row) --;
|
|
||||||
|
|
||||||
p = e_tree_model_node_at_row_1 (etree, row, paths[i]);
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
ret = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX need to find why this release is causing problems */
|
|
||||||
/* e_tree_model_release_paths (etree, paths, num_children); */
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ETreePath *
|
ETreePath *
|
||||||
e_tree_model_get_root (ETreeModel *etree)
|
e_tree_model_get_root (ETreeModel *etree)
|
||||||
{
|
{
|
||||||
@ -245,10 +412,48 @@ e_tree_model_get_root (ETreeModel *etree)
|
|||||||
ETreePath *
|
ETreePath *
|
||||||
e_tree_model_node_at_row (ETreeModel *etree, int row)
|
e_tree_model_node_at_row (ETreeModel *etree, int row)
|
||||||
{
|
{
|
||||||
/* XXX icky, perform a depth first search of the tree. we need this optimized sorely */
|
return ETM_CLASS(etree)->node_at_row (etree, row);
|
||||||
return e_tree_model_node_at_row_1 (etree, &row, ETM_CLASS(etree)->get_root(etree));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
e_tree_model_row_of_node (ETreeModel *etree, ETreePath *node)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < etree->row_array->len; i ++)
|
||||||
|
if (g_array_index (etree->row_array, GNode*, i) == node)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_root_node_set_visible (ETreeModel *etm, gboolean visible)
|
||||||
|
{
|
||||||
|
if (visible != etm->root_visible) {
|
||||||
|
etm->root_visible = visible;
|
||||||
|
if (etm->root) {
|
||||||
|
if (visible) {
|
||||||
|
etm->row_array = g_array_insert_val (etm->row_array, 0, etm->root);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ETreePath *root_path = e_tree_model_get_root (etm);
|
||||||
|
etm->row_array = g_array_remove_index (etm->row_array, 0);
|
||||||
|
e_tree_model_node_set_expanded (etm, root_path, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
e_table_model_changed (E_TABLE_MODEL (etm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
e_tree_model_root_node_is_visible (ETreeModel *etm)
|
||||||
|
{
|
||||||
|
return etm->root_visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ETreePath *
|
ETreePath *
|
||||||
e_tree_model_node_get_next (ETreeModel *etree, ETreePath *node)
|
e_tree_model_node_get_next (ETreeModel *etree, ETreePath *node)
|
||||||
{
|
{
|
||||||
@ -264,18 +469,13 @@ e_tree_model_node_get_prev (ETreeModel *etree, ETreePath *node)
|
|||||||
guint
|
guint
|
||||||
e_tree_model_node_depth (ETreeModel *etree, ETreePath *path)
|
e_tree_model_node_depth (ETreeModel *etree, ETreePath *path)
|
||||||
{
|
{
|
||||||
return g_list_length (path) - 1;
|
return g_node_depth (path) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ETreePath *
|
ETreePath *
|
||||||
e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path)
|
e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (path, NULL);
|
return ETM_CLASS(etree)->get_parent(etree, path);
|
||||||
|
|
||||||
if (path->next == NULL)
|
|
||||||
return NULL;
|
|
||||||
else
|
|
||||||
return g_list_copy (path->next);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@ -296,21 +496,190 @@ e_tree_model_node_is_expanded (ETreeModel *etree, ETreePath *path)
|
|||||||
return ETM_CLASS(etree)->is_expanded (etree, path);
|
return ETM_CLASS(etree)->is_expanded (etree, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
e_tree_model_node_is_visible (ETreeModel *etree, ETreePath *path)
|
||||||
|
{
|
||||||
|
return ETM_CLASS(etree)->is_visible (etree, path);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
e_tree_model_node_set_expanded (ETreeModel *etree, ETreePath *path, gboolean expanded)
|
e_tree_model_node_set_expanded (ETreeModel *etree, ETreePath *path, gboolean expanded)
|
||||||
{
|
{
|
||||||
ETM_CLASS(etree)->set_expanded (etree, path, expanded);
|
ETM_CLASS(etree)->set_expanded (etree, path, expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_node_set_expanded_recurse (ETreeModel *etree, ETreePath *path, gboolean expanded)
|
||||||
|
{
|
||||||
|
ETM_CLASS(etree)->set_expanded_recurse (etree, path, expanded);
|
||||||
|
}
|
||||||
|
|
||||||
guint
|
guint
|
||||||
e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths)
|
e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths)
|
||||||
{
|
{
|
||||||
return ETM_CLASS(etree)->get_children (etree, path, paths);
|
return ETM_CLASS(etree)->get_children (etree, path, paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
guint
|
||||||
e_tree_model_release_paths (ETreeModel *etree, ETreePath **paths, guint num_paths)
|
e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node)
|
||||||
{
|
{
|
||||||
ETM_CLASS(etree)->release_paths (etree, paths, num_paths);
|
ENode *enode = (ENode*)node->data;
|
||||||
|
|
||||||
|
return enode->visible_descendents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpointer
|
||||||
|
e_tree_model_node_get_data (ETreeModel *etm, ETreePath *node)
|
||||||
|
{
|
||||||
|
ENode *enode;
|
||||||
|
|
||||||
|
g_return_val_if_fail (node && node->data, NULL);
|
||||||
|
|
||||||
|
enode = (ENode*)node->data;
|
||||||
|
|
||||||
|
return enode->node_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
e_tree_model_node_set_data (ETreeModel *etm, ETreePath *node, gpointer node_data)
|
||||||
|
{
|
||||||
|
ENode *enode;
|
||||||
|
|
||||||
|
g_return_if_fail (node && node->data);
|
||||||
|
|
||||||
|
enode = (ENode*)node->data;
|
||||||
|
|
||||||
|
enode->node_data = node_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ETreePath*
|
||||||
|
e_tree_model_node_insert (ETreeModel *tree_model,
|
||||||
|
ETreePath *parent_path,
|
||||||
|
int position,
|
||||||
|
gpointer node_data)
|
||||||
|
{
|
||||||
|
ENode *node;
|
||||||
|
ETreePath *new_path;
|
||||||
|
|
||||||
|
g_return_val_if_fail (parent_path != NULL || tree_model->root == NULL, NULL);
|
||||||
|
|
||||||
|
node = g_new0 (ENode, 1);
|
||||||
|
|
||||||
|
node->expanded = FALSE;
|
||||||
|
node->node_data = node_data;
|
||||||
|
|
||||||
|
if (parent_path != NULL) {
|
||||||
|
|
||||||
|
new_path = g_node_new (node);
|
||||||
|
|
||||||
|
g_node_insert (parent_path, position, new_path);
|
||||||
|
|
||||||
|
if (e_tree_model_node_is_visible (tree_model, new_path)) {
|
||||||
|
int parent_row;
|
||||||
|
GNode *node;
|
||||||
|
|
||||||
|
/* we need to iterate back up to the root, incrementing the number of visible
|
||||||
|
descendents */
|
||||||
|
for (node = parent_path; node; node = node->parent) {
|
||||||
|
ENode *parent_enode = (ENode*)node->data;
|
||||||
|
|
||||||
|
parent_enode->visible_descendents ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally, insert a row into the table */
|
||||||
|
parent_row = e_tree_model_row_of_node (tree_model, parent_path);
|
||||||
|
|
||||||
|
tree_model->row_array = g_array_insert_val (tree_model->row_array,
|
||||||
|
parent_row + position + 1, new_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tree_model->root = g_node_new (node);
|
||||||
|
if (tree_model->root_visible)
|
||||||
|
tree_model->row_array = g_array_insert_val (tree_model->row_array, 0, tree_model->root);
|
||||||
|
new_path = tree_model->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: find out the number of descendents that will be visible,
|
||||||
|
and call insert_row that many times. */
|
||||||
|
e_table_model_changed (E_TABLE_MODEL(tree_model));
|
||||||
|
|
||||||
|
return new_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
ETreePath *
|
||||||
|
e_tree_model_node_insert_before (ETreeModel *etree, ETreePath *parent,
|
||||||
|
ETreePath *sibling, gpointer node_data)
|
||||||
|
{
|
||||||
|
return e_tree_model_node_insert (etree, parent,
|
||||||
|
g_node_child_position (parent, sibling),
|
||||||
|
node_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpointer
|
||||||
|
e_tree_model_node_remove (ETreeModel *etree, ETreePath *path)
|
||||||
|
{
|
||||||
|
GNode *parent = path->parent;
|
||||||
|
ENode *enode = (ENode*)path->data;
|
||||||
|
gpointer ret = enode->node_data;
|
||||||
|
|
||||||
|
g_return_val_if_fail (!g_node_first_child(path), NULL);
|
||||||
|
|
||||||
|
/* clean up the display */
|
||||||
|
if (parent) {
|
||||||
|
if (e_tree_model_node_is_visible (etree, path)) {
|
||||||
|
int row = e_tree_model_row_of_node (etree, path);
|
||||||
|
etree->row_array = g_array_remove_index (etree->row_array, row);
|
||||||
|
e_table_model_row_deleted (E_TABLE_MODEL (etree), row);
|
||||||
|
|
||||||
|
/* we need to iterate back up to the root, incrementing the number of visible
|
||||||
|
descendents */
|
||||||
|
for (; parent; parent = parent->parent) {
|
||||||
|
ENode *parent_enode = (ENode*)parent->data;
|
||||||
|
|
||||||
|
parent_enode->visible_descendents --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (path == etree->root) {
|
||||||
|
etree->root = NULL;
|
||||||
|
if (etree->root_visible) {
|
||||||
|
etree->row_array = g_array_remove_index (etree->row_array, 0);
|
||||||
|
e_table_model_row_deleted (E_TABLE_MODEL (etree), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* XXX invalid path */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* now free up the storage from that path */
|
||||||
|
g_node_destroy (path);
|
||||||
|
g_free (enode);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_visible_descendents_to_array (ETreeModel *etm, GNode *gnode, int *row, int *count)
|
||||||
|
{
|
||||||
|
GNode *child;
|
||||||
|
ENode *enode;
|
||||||
|
|
||||||
|
/* add a row for this node */
|
||||||
|
etm->row_array = g_array_insert_val (etm->row_array, (*row), gnode);
|
||||||
|
e_table_model_row_inserted (E_TABLE_MODEL (etm), (*row)++);
|
||||||
|
(*count) ++;
|
||||||
|
|
||||||
|
/* then loop over its children, calling this routine for each
|
||||||
|
of them */
|
||||||
|
enode = (ENode*)gnode->data;
|
||||||
|
if (enode->expanded) {
|
||||||
|
for (child = g_node_first_child (gnode); child;
|
||||||
|
child = g_node_next_sibling (child)) {
|
||||||
|
add_visible_descendents_to_array (etm, child, row, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,18 +10,13 @@
|
|||||||
#define E_IS_TREE_MODEL(o) (GTK_CHECK_TYPE ((o), E_TREE_MODEL_TYPE))
|
#define E_IS_TREE_MODEL(o) (GTK_CHECK_TYPE ((o), E_TREE_MODEL_TYPE))
|
||||||
#define E_IS_TREE_MODEL_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TREE_MODEL_TYPE))
|
#define E_IS_TREE_MODEL_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TREE_MODEL_TYPE))
|
||||||
|
|
||||||
typedef gpointer ETreePathItem;
|
typedef GNode ETreePath;
|
||||||
typedef GList ETreePath;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ETableModel base;
|
ETableModel base;
|
||||||
|
GNode *root;
|
||||||
ETableModel *source;
|
gboolean root_visible;
|
||||||
|
GArray *row_array; /* used in the mapping between ETable and our tree */
|
||||||
ETreePath *root_node;
|
|
||||||
|
|
||||||
GArray *array;
|
|
||||||
|
|
||||||
} ETreeModel;
|
} ETreeModel;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -32,41 +27,75 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
ETreePath *(*get_root) (ETreeModel *etm);
|
ETreePath *(*get_root) (ETreeModel *etm);
|
||||||
|
|
||||||
|
ETreePath *(*get_parent) (ETreeModel *etm, ETreePath* node);
|
||||||
ETreePath *(*get_next) (ETreeModel *etm, ETreePath* node);
|
ETreePath *(*get_next) (ETreeModel *etm, ETreePath* node);
|
||||||
ETreePath *(*get_prev) (ETreeModel *etm, ETreePath* node);
|
ETreePath *(*get_prev) (ETreeModel *etm, ETreePath* node);
|
||||||
|
guint (*get_children) (ETreeModel *etm, ETreePath* node, ETreePath ***paths);
|
||||||
|
|
||||||
|
gboolean (*is_expanded) (ETreeModel *etm, ETreePath* node);
|
||||||
|
gboolean (*is_visible) (ETreeModel *etm, ETreePath* node);
|
||||||
|
void (*set_expanded) (ETreeModel *etm, ETreePath* node, gboolean expanded);
|
||||||
|
void (*set_expanded_recurse) (ETreeModel *etm, ETreePath *node, gboolean expanded);
|
||||||
|
void (*set_expanded_level) (ETreeModel *etm, ETreePath *node, gboolean expanded, int level);
|
||||||
|
|
||||||
|
ETreePath* (*node_at_row) (ETreeModel *etm, int row);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ETable analogs
|
||||||
|
*/
|
||||||
void *(*value_at) (ETreeModel *etm, ETreePath* node, int col);
|
void *(*value_at) (ETreeModel *etm, ETreePath* node, int col);
|
||||||
void (*set_value_at) (ETreeModel *etm, ETreePath* node, int col, const void *val);
|
void (*set_value_at) (ETreeModel *etm, ETreePath* node, int col, const void *val);
|
||||||
gboolean (*is_editable) (ETreeModel *etm, ETreePath* node, int col);
|
gboolean (*is_editable) (ETreeModel *etm, ETreePath* node, int col);
|
||||||
|
|
||||||
guint (*get_children) (ETreeModel *etm, ETreePath* node, ETreePath ***paths);
|
|
||||||
void (*release_paths) (ETreeModel *etm, ETreePath **paths, guint num_paths);
|
|
||||||
gboolean (*is_expanded) (ETreeModel *etm, ETreePath* node);
|
|
||||||
void (*set_expanded) (ETreeModel *etm, ETreePath* node, gboolean expanded);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signals
|
* Signals
|
||||||
*/
|
*/
|
||||||
|
void (*node_changed) (ETreeModel *etm, ETreePath *node);
|
||||||
|
void (*node_inserted) (ETreeModel *etm, ETreePath *parent, ETreePath *inserted_node);
|
||||||
|
void (*node_removed) (ETreeModel *etm, ETreePath *parent, ETreePath *removed_node);
|
||||||
|
|
||||||
} ETreeModelClass;
|
} ETreeModelClass;
|
||||||
|
|
||||||
GtkType e_tree_model_get_type (void);
|
GtkType e_tree_model_get_type (void);
|
||||||
|
void e_tree_model_construct (ETreeModel *etree);
|
||||||
ETreeModel *e_tree_model_new (void);
|
ETreeModel *e_tree_model_new (void);
|
||||||
|
|
||||||
/* operations on "nodes" in the tree */
|
/* tree traversal operations */
|
||||||
ETreePath * e_tree_model_get_root (ETreeModel *etree);
|
ETreePath *e_tree_model_get_root (ETreeModel *etree);
|
||||||
ETreePath * e_tree_model_node_at_row (ETreeModel *etree, int row);
|
|
||||||
guint e_tree_model_node_depth (ETreeModel *etree, ETreePath *path);
|
|
||||||
ETreePath *e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path);
|
ETreePath *e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path);
|
||||||
ETreePath *e_tree_model_node_get_next (ETreeModel *etree, ETreePath *path);
|
ETreePath *e_tree_model_node_get_next (ETreeModel *etree, ETreePath *path);
|
||||||
ETreePath *e_tree_model_node_get_prev (ETreeModel *etree, ETreePath *path);
|
ETreePath *e_tree_model_node_get_prev (ETreeModel *etree, ETreePath *path);
|
||||||
gboolean e_tree_model_node_is_root (ETreeModel *etree, ETreePath *path);
|
|
||||||
|
|
||||||
gboolean e_tree_model_node_is_expandable (ETreeModel *etree, ETreePath *path);
|
/* node operations */
|
||||||
gboolean e_tree_model_node_is_expanded (ETreeModel *etree, ETreePath *path);
|
ETreePath *e_tree_model_node_insert (ETreeModel *etree, ETreePath *parent, int position, gpointer node_data);
|
||||||
guint e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths);
|
ETreePath *e_tree_model_node_insert_before (ETreeModel *etree, ETreePath *parent, ETreePath *sibling, gpointer node_data);
|
||||||
void e_tree_model_release_paths (ETreeModel *etree, ETreePath **paths, guint num_paths);
|
gpointer e_tree_model_node_remove (ETreeModel *etree, ETreePath *path);
|
||||||
guint e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node);
|
|
||||||
|
/* node accessors */
|
||||||
|
gboolean e_tree_model_node_is_root (ETreeModel *etree, ETreePath *path);
|
||||||
|
gboolean e_tree_model_node_is_expandable (ETreeModel *etree, ETreePath *path);
|
||||||
|
gboolean e_tree_model_node_is_expanded (ETreeModel *etree, ETreePath *path);
|
||||||
|
gboolean e_tree_model_node_is_visible (ETreeModel *etree, ETreePath *path);
|
||||||
|
void e_tree_model_node_set_expanded (ETreeModel *etree, ETreePath *path, gboolean expanded);
|
||||||
|
void e_tree_model_node_set_expanded_recurse (ETreeModel *etree, ETreePath *path, gboolean expanded);
|
||||||
|
guint e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths);
|
||||||
|
guint e_tree_model_node_depth (ETreeModel *etree, ETreePath *path);
|
||||||
|
guint e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node);
|
||||||
|
gpointer e_tree_model_node_get_data (ETreeModel *etm, ETreePath *node);
|
||||||
|
void e_tree_model_node_set_data (ETreeModel *etm, ETreePath *node, gpointer node_data);
|
||||||
|
|
||||||
|
/* display oriented routines */
|
||||||
|
ETreePath *e_tree_model_node_at_row (ETreeModel *etree, int row);
|
||||||
|
int e_tree_model_row_of_node (ETreeModel *etree, ETreePath *path);
|
||||||
|
void e_tree_model_root_node_set_visible (ETreeModel *etree, gboolean visible);
|
||||||
|
gboolean e_tree_model_root_node_is_visible (ETreeModel *etree);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Routines for emitting signals on the ETreeModel
|
||||||
|
*/
|
||||||
|
void e_tree_model_node_changed (ETreeModel *tree_model, ETreePath *node);
|
||||||
|
void e_tree_model_node_inserted (ETreeModel *tree_model, ETreePath *parent_node, ETreePath *inserted_node);
|
||||||
|
void e_tree_model_node_removed (ETreeModel *tree_model, ETreePath *parent_node, ETreePath *removed_node);
|
||||||
|
|
||||||
#endif /* _E_TREE_MODEL_H */
|
#endif /* _E_TREE_MODEL_H */
|
||||||
|
73
widgets/table/e-tree-simple.c
Normal file
73
widgets/table/e-tree-simple.c
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||||
|
/*
|
||||||
|
* e-tree-simple.c: a Tree Model that offers a function pointer
|
||||||
|
* interface to using ETreeModel, similar to ETableSimple.
|
||||||
|
*
|
||||||
|
* Author:
|
||||||
|
* Chris Toshok (toshok@helixcode.com)
|
||||||
|
*
|
||||||
|
* (C) 2000 Helix Code, Inc. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <gtk/gtksignal.h>
|
||||||
|
#include "e-util/e-util.h"
|
||||||
|
#include "e-tree-simple.h"
|
||||||
|
|
||||||
|
#define PARENT_TYPE E_TREE_MODEL_TYPE
|
||||||
|
|
||||||
|
static void *
|
||||||
|
simple_value_at (ETreeModel *etm, ETreePath *node, int col)
|
||||||
|
{
|
||||||
|
ETreeSimple *simple = E_TREE_SIMPLE(etm);
|
||||||
|
|
||||||
|
return simple->value_at (etm, node, col, simple->model_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
simple_set_value_at (ETreeModel *etm, ETreePath *node, int col, const void *val)
|
||||||
|
{
|
||||||
|
ETreeSimple *simple = E_TREE_SIMPLE(etm);
|
||||||
|
|
||||||
|
simple->set_value_at (etm, node, col, val, simple->model_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
simple_is_editable (ETreeModel *etm, ETreePath *node, int col)
|
||||||
|
{
|
||||||
|
ETreeSimple *simple = E_TREE_SIMPLE(etm);
|
||||||
|
|
||||||
|
return simple->is_editable (etm, node, col, simple->model_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
e_tree_simple_class_init (GtkObjectClass *object_class)
|
||||||
|
{
|
||||||
|
ETreeModelClass *model_class = (ETreeModelClass *) object_class;
|
||||||
|
|
||||||
|
model_class->value_at = simple_value_at;
|
||||||
|
model_class->set_value_at = simple_set_value_at;
|
||||||
|
model_class->is_editable = simple_is_editable;
|
||||||
|
}
|
||||||
|
|
||||||
|
E_MAKE_TYPE(e_tree_simple, "ETreeSimple", ETreeSimple, e_tree_simple_class_init, NULL, PARENT_TYPE)
|
||||||
|
|
||||||
|
ETreeModel *
|
||||||
|
e_tree_simple_new (ETreeSimpleValueAtFn value_at,
|
||||||
|
ETreeSimpleSetValueAtFn set_value_at,
|
||||||
|
ETreeSimpleIsEditableFn is_editable,
|
||||||
|
gpointer model_data)
|
||||||
|
{
|
||||||
|
ETreeSimple *etg;
|
||||||
|
|
||||||
|
etg = gtk_type_new (e_tree_simple_get_type ());
|
||||||
|
|
||||||
|
e_tree_model_construct (E_TREE_MODEL (etg));
|
||||||
|
|
||||||
|
etg->value_at = value_at;
|
||||||
|
etg->set_value_at = set_value_at;
|
||||||
|
etg->is_editable = is_editable;
|
||||||
|
etg->model_data = model_data;
|
||||||
|
|
||||||
|
return (ETreeModel*)etg;
|
||||||
|
}
|
||||||
|
|
40
widgets/table/e-tree-simple.h
Normal file
40
widgets/table/e-tree-simple.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||||
|
|
||||||
|
#ifndef _E_TREE_SIMPLE_H_
|
||||||
|
#define _E_TREE_SIMPLE_H_
|
||||||
|
|
||||||
|
#include "e-tree-model.h"
|
||||||
|
|
||||||
|
#define E_TREE_SIMPLE_TYPE (e_tree_simple_get_type ())
|
||||||
|
#define E_TREE_SIMPLE(o) (GTK_CHECK_CAST ((o), E_TREE_SIMPLE_TYPE, ETreeSimple))
|
||||||
|
#define E_TREE_SIMPLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TREE_SIMPLE_TYPE, ETreeSimpleClass))
|
||||||
|
#define E_IS_TREE_SIMPLE(o) (GTK_CHECK_TYPE ((o), E_TREE_SIMPLE_TYPE))
|
||||||
|
#define E_IS_TREE_SIMPLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TREE_SIMPLE_TYPE))
|
||||||
|
|
||||||
|
|
||||||
|
typedef void* (*ETreeSimpleValueAtFn) (ETreeModel *etree, ETreePath *path, int col, void *model_data);
|
||||||
|
typedef void (*ETreeSimpleSetValueAtFn) (ETreeModel *etree, ETreePath *path, int col, const void *val, void *model_data);
|
||||||
|
typedef gboolean (*ETreeSimpleIsEditableFn) (ETreeModel *etree, ETreePath *path, int col, void *model_data);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ETreeModel parent;
|
||||||
|
|
||||||
|
ETreeSimpleValueAtFn value_at;
|
||||||
|
ETreeSimpleSetValueAtFn set_value_at;
|
||||||
|
ETreeSimpleIsEditableFn is_editable;
|
||||||
|
|
||||||
|
gpointer model_data;
|
||||||
|
} ETreeSimple;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ETreeModelClass parent_class;
|
||||||
|
} ETreeSimpleClass;
|
||||||
|
|
||||||
|
GtkType e_tree_simple_get_type (void);
|
||||||
|
|
||||||
|
ETreeModel *e_tree_simple_new (ETreeSimpleValueAtFn value_at,
|
||||||
|
ETreeSimpleSetValueAtFn set_value_at,
|
||||||
|
ETreeSimpleIsEditableFn is_editable,
|
||||||
|
gpointer model_data);
|
||||||
|
|
||||||
|
#endif /* _E_TREE_SIMPLE_H_ */
|
Loading…
Reference in New Issue
Block a user