1
#define __SP_XMLVIEW_TREE_C__
4
* Specialization of GtkCTree for the XML tree view
7
* MenTaLguY <mental@rydia.net>
9
* Copyright (C) 2002 MenTaLguY
11
* Released under the GNU GPL; see COPYING for details
17
#include "../xml/node-event-vector.h"
18
#include "sp-xmlview-tree.h"
23
Inkscape::XML::Node * repr;
26
#define NODE_DATA(node) ((NodeData *)(GTK_CTREE_ROW ((node))->row.data))
28
static void sp_xmlview_tree_class_init (SPXMLViewTreeClass * klass);
29
static void sp_xmlview_tree_init (SPXMLViewTree * tree);
30
static void sp_xmlview_tree_destroy (GtkObject * object);
32
static NodeData * node_data_new (SPXMLViewTree * tree, GtkCTreeNode * node, Inkscape::XML::Node * repr);
33
static void node_data_free (gpointer data);
35
static GtkCTreeNode * add_node (SPXMLViewTree * tree, GtkCTreeNode * parent, GtkCTreeNode * before, Inkscape::XML::Node * repr);
37
static void element_child_added (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer data);
38
static void element_attr_changed (Inkscape::XML::Node * repr, const gchar * key, const gchar * old_value, const gchar * new_value, bool is_interactive, gpointer data);
39
static void element_child_removed (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer data);
40
static void element_order_changed (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * oldref, Inkscape::XML::Node * newref, gpointer data);
42
static void text_content_changed (Inkscape::XML::Node * repr, const gchar * old_content, const gchar * new_content, gpointer data);
43
static void comment_content_changed (Inkscape::XML::Node * repr, const gchar * old_content, const gchar * new_content, gpointer data);
44
static void pi_content_changed (Inkscape::XML::Node * repr, const gchar * old_content, const gchar * new_content, gpointer data);
46
static void tree_move (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling);
48
static gboolean check_drag (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling);
50
static GtkCTreeNode * ref_to_sibling (GtkCTreeNode * parent, Inkscape::XML::Node * ref);
51
static GtkCTreeNode * repr_to_child (GtkCTreeNode * parent, Inkscape::XML::Node * repr);
52
static Inkscape::XML::Node * sibling_to_ref (GtkCTreeNode * parent, GtkCTreeNode * sibling);
54
static gint match_node_data_by_repr(gconstpointer data_p, gconstpointer repr);
56
static const Inkscape::XML::NodeEventVector element_repr_events = {
58
element_child_removed,
60
NULL, /* content_changed */
64
static const Inkscape::XML::NodeEventVector text_repr_events = {
65
NULL, /* child_added */
66
NULL, /* child_removed */
67
NULL, /* attr_changed */
69
NULL /* order_changed */
72
static const Inkscape::XML::NodeEventVector comment_repr_events = {
73
NULL, /* child_added */
74
NULL, /* child_removed */
75
NULL, /* attr_changed */
76
comment_content_changed,
77
NULL /* order_changed */
80
static const Inkscape::XML::NodeEventVector pi_repr_events = {
81
NULL, /* child_added */
82
NULL, /* child_removed */
83
NULL, /* attr_changed */
85
NULL /* order_changed */
88
static GtkCTreeClass * parent_class = NULL;
91
sp_xmlview_tree_new (Inkscape::XML::Node * repr, void * /*factory*/, void * /*data*/)
95
tree = (SPXMLViewTree*)g_object_new (SP_TYPE_XMLVIEW_TREE, "n_columns", 1, "tree_column", 0, NULL);
97
gtk_clist_column_titles_hide (GTK_CLIST (tree));
98
gtk_ctree_set_line_style (GTK_CTREE (tree), GTK_CTREE_LINES_NONE);
99
gtk_ctree_set_expander_style (GTK_CTREE (tree), GTK_CTREE_EXPANDER_TRIANGLE);
100
gtk_clist_set_column_auto_resize (GTK_CLIST (tree), 0, TRUE);
101
gtk_clist_set_reorderable (GTK_CLIST (tree), TRUE);
102
gtk_ctree_set_drag_compare_func (GTK_CTREE (tree), check_drag);
104
sp_xmlview_tree_set_repr (tree, repr);
106
return (GtkWidget *) tree;
110
sp_xmlview_tree_set_repr (SPXMLViewTree * tree, Inkscape::XML::Node * repr)
112
if ( tree->repr == repr ) return;
113
gtk_clist_freeze (GTK_CLIST (tree));
115
gtk_clist_clear (GTK_CLIST (tree));
116
Inkscape::GC::release(tree->repr);
121
Inkscape::GC::anchor(repr);
122
node = add_node (tree, NULL, NULL, repr);
123
gtk_ctree_expand (GTK_CTREE (tree), node);
125
gtk_clist_thaw (GTK_CLIST (tree));
129
sp_xmlview_tree_get_type (void)
131
//TODO: switch to GObject
132
// GtkType and such calls were deprecated a while back with the
133
// introduction of GObject as a separate layer, with GType instead. --JonCruz
135
static GtkType type = 0;
138
static const GtkTypeInfo info = {
139
(gchar*) "SPXMLViewTree",
140
sizeof (SPXMLViewTree),
141
sizeof (SPXMLViewTreeClass),
142
(GtkClassInitFunc) sp_xmlview_tree_class_init,
143
(GtkObjectInitFunc) sp_xmlview_tree_init,
146
type = gtk_type_unique (GTK_TYPE_CTREE, &info);
153
sp_xmlview_tree_class_init (SPXMLViewTreeClass * klass)
155
GtkObjectClass * object_class;
157
object_class = (GtkObjectClass *) klass;
158
parent_class = (GtkCTreeClass *) gtk_type_class (GTK_TYPE_CTREE);
160
GTK_CTREE_CLASS (object_class)->tree_move = tree_move;
162
object_class->destroy = sp_xmlview_tree_destroy;
166
sp_xmlview_tree_init (SPXMLViewTree * tree)
173
sp_xmlview_tree_destroy (GtkObject * object)
175
SPXMLViewTree * tree;
177
tree = SP_XMLVIEW_TREE (object);
179
sp_xmlview_tree_set_repr (tree, NULL);
181
GTK_OBJECT_CLASS (parent_class)->destroy (object);
185
add_node (SPXMLViewTree * tree, GtkCTreeNode * parent, GtkCTreeNode * before, Inkscape::XML::Node * repr)
189
const Inkscape::XML::NodeEventVector * vec;
190
static const gchar *default_text[] = { "???" };
192
g_assert (tree != NULL);
193
g_assert (repr != NULL);
195
node = gtk_ctree_insert_node (GTK_CTREE (tree), parent, before, (gchar **)default_text, 2, NULL, NULL, NULL, NULL, ( repr->type() != Inkscape::XML::ELEMENT_NODE ), FALSE);
196
g_assert (node != NULL);
198
data = node_data_new (tree, node, repr);
199
g_assert (data != NULL);
201
gtk_ctree_node_set_row_data_full (GTK_CTREE (tree), data->node, data, node_data_free);
203
if ( repr->type() == Inkscape::XML::TEXT_NODE ) {
204
vec = &text_repr_events;
205
} else if ( repr->type() == Inkscape::XML::COMMENT_NODE ) {
206
vec = &comment_repr_events;
207
} else if ( repr->type() == Inkscape::XML::PI_NODE ) {
208
vec = &pi_repr_events;
209
} else if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) {
210
vec = &element_repr_events;
216
gtk_clist_freeze (GTK_CLIST (tree));
217
/* cheat a little to get the id upated properly */
218
if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
219
element_attr_changed (repr, "id", NULL, NULL, false, data);
221
sp_repr_add_listener (repr, vec, data);
222
sp_repr_synthesize_events (repr, vec, data);
223
gtk_clist_thaw (GTK_CLIST (tree));
230
node_data_new (SPXMLViewTree * tree, GtkCTreeNode * node, Inkscape::XML::Node * repr)
233
data = g_new (NodeData, 1);
237
Inkscape::GC::anchor(repr);
242
node_data_free (gpointer ptr) {
244
data = (NodeData *) ptr;
245
sp_repr_remove_listener_by_data (data->repr, data);
246
g_assert (data->repr != NULL);
247
Inkscape::GC::release(data->repr);
252
element_child_added (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer ptr)
255
GtkCTreeNode * before;
257
data = (NodeData *) ptr;
259
if (data->tree->blocked) return;
261
before = ref_to_sibling (data->node, ref);
263
add_node (data->tree, data->node, before, child);
267
element_attr_changed (Inkscape::XML::Node * repr, const gchar * key, const gchar * /*old_value*/, const gchar * new_value, bool /*is_interactive*/, gpointer ptr)
273
data = (NodeData *) ptr;
275
if (data->tree->blocked) return;
277
if (0 != strcmp (key, "id") && 0 != strcmp (key, "inkscape:label"))
280
new_value = repr->attribute("id");
281
layer = repr->attribute("inkscape:label");
283
if (new_value && layer) {
284
label = g_strdup_printf ("<%s id=\"%s\" inkscape:label=\"%s\">", repr->name(), new_value, layer);
285
} else if (new_value) {
286
label = g_strdup_printf ("<%s id=\"%s\">", repr->name(), new_value);
288
label = g_strdup_printf ("<%s>", repr->name());
290
gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
295
element_child_removed (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * /*ref*/, gpointer ptr)
299
data = (NodeData *) ptr;
301
if (data->tree->blocked) return;
303
gtk_ctree_remove_node (GTK_CTREE (data->tree), repr_to_child (data->node, child));
307
element_order_changed (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * /*oldref*/, Inkscape::XML::Node * newref, gpointer ptr)
310
GtkCTreeNode * before, * node;
312
data = (NodeData *) ptr;
314
if (data->tree->blocked) return;
316
before = ref_to_sibling (data->node, newref);
317
node = repr_to_child (data->node, child);
319
if ( before == node ) before = GTK_CTREE_ROW (before)->sibling;
321
parent_class->tree_move (GTK_CTREE (data->tree), node, data->node, before);
325
text_content_changed (Inkscape::XML::Node * /*repr*/, const gchar * /*old_content*/, const gchar * new_content, gpointer ptr)
330
data = (NodeData *) ptr;
332
if (data->tree->blocked) return;
334
label = g_strdup_printf ("\"%s\"", new_content);
335
gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
340
comment_content_changed (Inkscape::XML::Node */*repr*/, const gchar * /*old_content*/, const gchar *new_content, gpointer ptr)
345
data = (NodeData *) ptr;
347
if (data->tree->blocked) return;
349
label = g_strdup_printf ("<!--%s-->", new_content);
350
gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
355
pi_content_changed(Inkscape::XML::Node *repr, const gchar * /*old_content*/, const gchar *new_content, gpointer ptr)
360
data = (NodeData *) ptr;
362
if (data->tree->blocked) return;
364
label = g_strdup_printf ("<?%s %s?>", repr->name(), new_content);
365
gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
369
tree_move (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling)
371
GtkCTreeNode * old_parent;
372
Inkscape::XML::Node * ref;
374
old_parent = GTK_CTREE_ROW (node)->parent;
375
if ( !old_parent || !new_parent ) return;
377
ref = sibling_to_ref (new_parent, new_sibling);
379
gtk_clist_freeze (GTK_CLIST (tree));
381
SP_XMLVIEW_TREE (tree)->blocked++;
382
if (new_parent == old_parent) {
383
NODE_DATA (old_parent)->repr->changeOrder(NODE_DATA (node)->repr, ref);
385
NODE_DATA (old_parent)->repr->removeChild(NODE_DATA (node)->repr);
386
NODE_DATA (new_parent)->repr->addChild(NODE_DATA (node)->repr, ref);
388
SP_XMLVIEW_TREE (tree)->blocked--;
390
parent_class->tree_move (tree, node, new_parent, new_sibling);
392
gtk_clist_thaw (GTK_CLIST (tree));
396
ref_to_sibling (GtkCTreeNode * parent, Inkscape::XML::Node * ref)
399
GtkCTreeNode * before;
400
before = repr_to_child (parent, ref);
401
g_assert (before != NULL);
402
before = GTK_CTREE_ROW (before)->sibling;
405
return GTK_CTREE_ROW (parent)->children;
410
repr_to_child (GtkCTreeNode * parent, Inkscape::XML::Node * repr)
412
GtkCTreeNode * child;
413
child = GTK_CTREE_ROW (parent)->children;
414
while ( child && NODE_DATA (child)->repr != repr ) {
415
child = GTK_CTREE_ROW (child)->sibling;
420
Inkscape::XML::Node *
421
sibling_to_ref (GtkCTreeNode * parent, GtkCTreeNode * sibling)
423
GtkCTreeNode * child;
424
child = GTK_CTREE_ROW (parent)->children;
425
if ( child == sibling ) return NULL;
426
while ( child && GTK_CTREE_ROW (child)->sibling != sibling ) {
427
child = GTK_CTREE_ROW (child)->sibling;
429
return NODE_DATA (child)->repr;
433
check_drag (GtkCTree * /*tree*/, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * /*new_sibling*/)
435
GtkCTreeNode * old_parent;
437
old_parent = GTK_CTREE_ROW (node)->parent;
439
if (!old_parent || !new_parent) return FALSE;
440
if (NODE_DATA (new_parent)->repr->type() != Inkscape::XML::ELEMENT_NODE) return FALSE;
442
/* fixme: we need add_child/remove_child/etc repr events without side-effects, so we can check here and give better visual feedback */
447
Inkscape::XML::Node *
448
sp_xmlview_tree_node_get_repr (SPXMLViewTree * /*tree*/, GtkCTreeNode * node)
450
return NODE_DATA (node)->repr;
454
sp_xmlview_tree_get_repr_node (SPXMLViewTree * tree, Inkscape::XML::Node * repr)
456
return gtk_ctree_find_by_row_data_custom (GTK_CTREE (tree), NULL, repr, match_node_data_by_repr);
460
match_node_data_by_repr(gconstpointer data_p, gconstpointer repr)
462
return ((const NodeData *)data_p)->repr != (const Inkscape::XML::Node *)repr;