~mc.../inkscape/inkscape

« back to all changes in this revision

Viewing changes to src/widgets/sp-xmlview-tree.cpp

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define __SP_XMLVIEW_TREE_C__
 
2
 
 
3
/*
 
4
 * Specialization of GtkCTree for the XML tree view
 
5
 *
 
6
 * Authors:
 
7
 *   MenTaLguY <mental@rydia.net>
 
8
 *
 
9
 * Copyright (C) 2002 MenTaLguY
 
10
 *
 
11
 * Released under the GNU GPL; see COPYING for details
 
12
 */
 
13
 
 
14
#include "../xml/node-event-vector.h"
 
15
#include "sp-xmlview-tree.h"
 
16
 
 
17
struct NodeData {
 
18
        SPXMLViewTree * tree;
 
19
        GtkCTreeNode * node;
 
20
        Inkscape::XML::Node * repr;
 
21
};
 
22
 
 
23
#define NODE_DATA(node) ((NodeData *)(GTK_CTREE_ROW ((node))->row.data))
 
24
 
 
25
static void sp_xmlview_tree_class_init (SPXMLViewTreeClass * klass);
 
26
static void sp_xmlview_tree_init (SPXMLViewTree * tree);
 
27
static void sp_xmlview_tree_destroy (GtkObject * object);
 
28
 
 
29
static NodeData * node_data_new (SPXMLViewTree * tree, GtkCTreeNode * node, Inkscape::XML::Node * repr);
 
30
static void node_data_free (gpointer data);
 
31
 
 
32
static GtkCTreeNode * add_node (SPXMLViewTree * tree, GtkCTreeNode * parent, GtkCTreeNode * before, Inkscape::XML::Node * repr);
 
33
 
 
34
static void element_child_added (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer data);
 
35
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);
 
36
static void element_child_removed (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer data);
 
37
static void element_order_changed (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * oldref, Inkscape::XML::Node * newref, gpointer data);
 
38
 
 
39
static void text_content_changed (Inkscape::XML::Node * repr, const gchar * old_content, const gchar * new_content, gpointer data);
 
40
static void comment_content_changed (Inkscape::XML::Node * repr, const gchar * old_content, const gchar * new_content, gpointer data);
 
41
 
 
42
static void tree_move (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling);
 
43
 
 
44
static gboolean check_drag (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling);
 
45
 
 
46
static GtkCTreeNode * ref_to_sibling (GtkCTreeNode * parent, Inkscape::XML::Node * ref);
 
47
static GtkCTreeNode * repr_to_child (GtkCTreeNode * parent, Inkscape::XML::Node * repr);
 
48
static Inkscape::XML::Node * sibling_to_ref (GtkCTreeNode * parent, GtkCTreeNode * sibling);
 
49
 
 
50
static gint match_node_data_by_repr(gconstpointer data_p, gconstpointer repr);
 
51
 
 
52
static const Inkscape::XML::NodeEventVector element_repr_events = {
 
53
        element_child_added,
 
54
        element_child_removed,
 
55
        element_attr_changed,
 
56
        NULL, /* content_changed */
 
57
        element_order_changed
 
58
};
 
59
 
 
60
static const Inkscape::XML::NodeEventVector text_repr_events = {
 
61
        NULL, /* child_added */
 
62
        NULL, /* child_removed */
 
63
        NULL, /* attr_changed */
 
64
        text_content_changed,
 
65
        NULL  /* order_changed */
 
66
};
 
67
 
 
68
static const Inkscape::XML::NodeEventVector comment_repr_events = {
 
69
        NULL, /* child_added */
 
70
        NULL, /* child_removed */
 
71
        NULL, /* attr_changed */
 
72
        comment_content_changed,
 
73
        NULL  /* order_changed */
 
74
};
 
75
 
 
76
static GtkCTreeClass * parent_class = NULL;
 
77
 
 
78
GtkWidget *
 
79
sp_xmlview_tree_new (Inkscape::XML::Node * repr, void * factory, void * data)
 
80
{
 
81
        SPXMLViewTree * tree;
 
82
 
 
83
        tree = (SPXMLViewTree*)g_object_new (SP_TYPE_XMLVIEW_TREE, "n_columns", 1, "tree_column", 0, NULL);
 
84
 
 
85
        gtk_clist_column_titles_hide (GTK_CLIST (tree));
 
86
        gtk_ctree_set_line_style (GTK_CTREE (tree), GTK_CTREE_LINES_NONE);
 
87
        gtk_ctree_set_expander_style (GTK_CTREE (tree), GTK_CTREE_EXPANDER_TRIANGLE);
 
88
        gtk_clist_set_column_auto_resize (GTK_CLIST (tree), 0, TRUE);
 
89
        gtk_clist_set_reorderable (GTK_CLIST (tree), TRUE);
 
90
        gtk_ctree_set_drag_compare_func (GTK_CTREE (tree), check_drag);
 
91
 
 
92
        sp_xmlview_tree_set_repr (tree, repr);
 
93
 
 
94
        return (GtkWidget *) tree;
 
95
}
 
96
 
 
97
void
 
98
sp_xmlview_tree_set_repr (SPXMLViewTree * tree, Inkscape::XML::Node * repr)
 
99
{
 
100
        if ( tree->repr == repr ) return;
 
101
        gtk_clist_freeze (GTK_CLIST (tree));
 
102
        if (tree->repr) {
 
103
                gtk_clist_clear (GTK_CLIST (tree));
 
104
                Inkscape::GC::release(tree->repr);
 
105
        }
 
106
        tree->repr = repr;
 
107
        if (repr) {
 
108
                GtkCTreeNode * node;
 
109
                Inkscape::GC::anchor(repr);
 
110
                node = add_node (tree, NULL, NULL, repr);
 
111
                gtk_ctree_expand (GTK_CTREE (tree), node);
 
112
        }
 
113
        gtk_clist_thaw (GTK_CLIST (tree));
 
114
}
 
115
 
 
116
GtkType
 
117
sp_xmlview_tree_get_type (void)
 
118
{
 
119
        static GtkType type = 0;
 
120
 
 
121
        if (!type) {
 
122
                static const GtkTypeInfo info = {
 
123
                        "SPXMLViewTree",
 
124
                        sizeof (SPXMLViewTree),
 
125
                        sizeof (SPXMLViewTreeClass),
 
126
                        (GtkClassInitFunc) sp_xmlview_tree_class_init,
 
127
                        (GtkObjectInitFunc) sp_xmlview_tree_init,
 
128
                        NULL, NULL, NULL
 
129
                };
 
130
                type = gtk_type_unique (GTK_TYPE_CTREE, &info);
 
131
        }
 
132
 
 
133
        return type;
 
134
}
 
135
 
 
136
void
 
137
sp_xmlview_tree_class_init (SPXMLViewTreeClass * klass)
 
138
{
 
139
        GtkObjectClass * object_class;
 
140
 
 
141
        object_class = (GtkObjectClass *) klass;
 
142
        parent_class = (GtkCTreeClass *) gtk_type_class (GTK_TYPE_CTREE);
 
143
 
 
144
        GTK_CTREE_CLASS (object_class)->tree_move = tree_move;
 
145
 
 
146
        object_class->destroy = sp_xmlview_tree_destroy;
 
147
}
 
148
 
 
149
void
 
150
sp_xmlview_tree_init (SPXMLViewTree * tree)
 
151
{
 
152
        tree->repr = NULL;
 
153
        tree->blocked = 0;
 
154
}
 
155
 
 
156
void
 
157
sp_xmlview_tree_destroy (GtkObject * object)
 
158
{
 
159
        SPXMLViewTree * tree;
 
160
 
 
161
        tree = SP_XMLVIEW_TREE (object);
 
162
 
 
163
        sp_xmlview_tree_set_repr (tree, NULL);
 
164
 
 
165
        GTK_OBJECT_CLASS (parent_class)->destroy (object);
 
166
}
 
167
 
 
168
GtkCTreeNode *
 
169
add_node (SPXMLViewTree * tree, GtkCTreeNode * parent, GtkCTreeNode * before, Inkscape::XML::Node * repr)
 
170
{
 
171
        NodeData * data;
 
172
        GtkCTreeNode * node;
 
173
        const Inkscape::XML::NodeEventVector * vec;
 
174
        static const gchar *default_text[] = { "???" };
 
175
 
 
176
        g_assert (tree != NULL);
 
177
        g_assert (repr != NULL);
 
178
 
 
179
        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);
 
180
        g_assert (node != NULL);
 
181
 
 
182
        data = node_data_new (tree, node, repr);
 
183
        g_assert (data != NULL);
 
184
 
 
185
        gtk_ctree_node_set_row_data_full (GTK_CTREE (tree), data->node, data, node_data_free);
 
186
 
 
187
        if ( repr->type() == Inkscape::XML::TEXT_NODE ) {
 
188
                vec = &text_repr_events;
 
189
        } else if ( repr->type() == Inkscape::XML::COMMENT_NODE ) {
 
190
                vec = &comment_repr_events;
 
191
        } else if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) {
 
192
                vec = &element_repr_events;
 
193
        } else {
 
194
                vec = NULL;
 
195
        }
 
196
 
 
197
        if (vec) {
 
198
                gtk_clist_freeze (GTK_CLIST (tree));
 
199
                /* cheat a little to get the id upated properly */
 
200
                if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
 
201
                        element_attr_changed (repr, "id", NULL, NULL, false, data);
 
202
                }
 
203
                sp_repr_add_listener (repr, vec, data);
 
204
                sp_repr_synthesize_events (repr, vec, data);
 
205
                gtk_clist_thaw (GTK_CLIST (tree));
 
206
        }
 
207
 
 
208
        return node;
 
209
}
 
210
 
 
211
NodeData *
 
212
node_data_new (SPXMLViewTree * tree, GtkCTreeNode * node, Inkscape::XML::Node * repr)
 
213
{
 
214
        NodeData * data;
 
215
        data = g_new (NodeData, 1);
 
216
        data->tree = tree;
 
217
        data->node = node;
 
218
        data->repr = repr;
 
219
        Inkscape::GC::anchor(repr);
 
220
        return data;
 
221
}
 
222
 
 
223
void
 
224
node_data_free (gpointer ptr) {
 
225
        NodeData * data;
 
226
        data = (NodeData *) ptr;
 
227
        sp_repr_remove_listener_by_data (data->repr, data);
 
228
        g_assert (data->repr != NULL);
 
229
        Inkscape::GC::release(data->repr);
 
230
        g_free (data);
 
231
}
 
232
 
 
233
void
 
234
element_child_added (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer ptr)
 
235
{
 
236
        NodeData * data;
 
237
        GtkCTreeNode * before;
 
238
 
 
239
        data = (NodeData *) ptr;
 
240
 
 
241
        if (data->tree->blocked) return;
 
242
 
 
243
        before = ref_to_sibling (data->node, ref);
 
244
 
 
245
        add_node (data->tree, data->node, before, child);
 
246
}
 
247
 
 
248
void
 
249
element_attr_changed (Inkscape::XML::Node * repr, const gchar * key, const gchar * old_value, const gchar * new_value, bool is_interactive, gpointer ptr)
 
250
{
 
251
        NodeData * data;
 
252
        gchar *label;
 
253
 
 
254
        data = (NodeData *) ptr;
 
255
 
 
256
        if (data->tree->blocked) return;
 
257
 
 
258
        if (strcmp (key, "id")) return;
 
259
        
 
260
        if (new_value) {
 
261
                label = g_strdup_printf ("<%s id=\"%s\">", repr->name(), new_value);
 
262
        } else {
 
263
                label = g_strdup_printf ("<%s>", repr->name());
 
264
        }
 
265
        gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
 
266
        g_free (label);
 
267
}
 
268
 
 
269
void
 
270
element_child_removed (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer ptr)
 
271
{
 
272
        NodeData * data;
 
273
 
 
274
        data = (NodeData *) ptr;
 
275
 
 
276
        if (data->tree->blocked) return;
 
277
 
 
278
        gtk_ctree_remove_node (GTK_CTREE (data->tree), repr_to_child (data->node, child));
 
279
}
 
280
 
 
281
void
 
282
element_order_changed (Inkscape::XML::Node * repr, Inkscape::XML::Node * child, Inkscape::XML::Node * oldref, Inkscape::XML::Node * newref, gpointer ptr)
 
283
{
 
284
        NodeData * data;
 
285
        GtkCTreeNode * before, * node;
 
286
 
 
287
        data = (NodeData *) ptr;
 
288
 
 
289
        if (data->tree->blocked) return;
 
290
 
 
291
        before = ref_to_sibling (data->node, newref);
 
292
        node = repr_to_child (data->node, child);
 
293
 
 
294
        if ( before == node ) before = GTK_CTREE_ROW (before)->sibling;
 
295
 
 
296
        parent_class->tree_move (GTK_CTREE (data->tree), node, data->node, before);
 
297
}
 
298
 
 
299
void
 
300
text_content_changed (Inkscape::XML::Node * repr, const gchar * old_content, const gchar * new_content, gpointer ptr)
 
301
{
 
302
        NodeData *data;
 
303
        gchar *label;
 
304
 
 
305
        data = (NodeData *) ptr;
 
306
 
 
307
        if (data->tree->blocked) return;
 
308
 
 
309
        label = g_strdup_printf ("\"%s\"", new_content);
 
310
        gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
 
311
        g_free (label);
 
312
}
 
313
 
 
314
void
 
315
comment_content_changed (Inkscape::XML::Node *repr, const gchar * old_content, const gchar *new_content, gpointer ptr)
 
316
{
 
317
        NodeData *data;
 
318
        gchar *label;
 
319
 
 
320
        data = (NodeData *) ptr;
 
321
 
 
322
        if (data->tree->blocked) return;
 
323
 
 
324
        label = g_strdup_printf ("<!--%s-->", new_content);
 
325
        gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
 
326
        g_free (label);
 
327
}
 
328
 
 
329
void
 
330
tree_move (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling)
 
331
{
 
332
        GtkCTreeNode * old_parent;
 
333
        Inkscape::XML::Node * ref;
 
334
 
 
335
        old_parent = GTK_CTREE_ROW (node)->parent;
 
336
        if ( !old_parent || !new_parent ) return;
 
337
 
 
338
        ref = sibling_to_ref (new_parent, new_sibling);
 
339
 
 
340
        gtk_clist_freeze (GTK_CLIST (tree));
 
341
 
 
342
        SP_XMLVIEW_TREE (tree)->blocked++;
 
343
        if (new_parent == old_parent) {
 
344
                NODE_DATA (old_parent)->repr->changeOrder(NODE_DATA (node)->repr, ref);
 
345
        } else {
 
346
                NODE_DATA (old_parent)->repr->removeChild(NODE_DATA (node)->repr);
 
347
                NODE_DATA (new_parent)->repr->addChild(NODE_DATA (node)->repr, ref);
 
348
        }
 
349
        SP_XMLVIEW_TREE (tree)->blocked--;
 
350
 
 
351
        parent_class->tree_move (tree, node, new_parent, new_sibling);
 
352
 
 
353
        gtk_clist_thaw (GTK_CLIST (tree));
 
354
}
 
355
 
 
356
GtkCTreeNode *
 
357
ref_to_sibling (GtkCTreeNode * parent, Inkscape::XML::Node * ref)
 
358
{
 
359
        if (ref) {
 
360
                GtkCTreeNode * before;
 
361
                before = repr_to_child (parent, ref); 
 
362
                g_assert (before != NULL);
 
363
                before = GTK_CTREE_ROW (before)->sibling;
 
364
                return before;
 
365
        } else {
 
366
                return GTK_CTREE_ROW (parent)->children;
 
367
        }
 
368
}
 
369
 
 
370
GtkCTreeNode *
 
371
repr_to_child (GtkCTreeNode * parent, Inkscape::XML::Node * repr)
 
372
{
 
373
        GtkCTreeNode * child;
 
374
        child = GTK_CTREE_ROW (parent)->children;
 
375
        while ( child && NODE_DATA (child)->repr != repr ) {
 
376
                child = GTK_CTREE_ROW (child)->sibling;
 
377
        }
 
378
        return child;
 
379
}
 
380
 
 
381
Inkscape::XML::Node *
 
382
sibling_to_ref (GtkCTreeNode * parent, GtkCTreeNode * sibling)
 
383
{
 
384
        GtkCTreeNode * child;
 
385
        child = GTK_CTREE_ROW (parent)->children;
 
386
        if ( child == sibling ) return NULL;
 
387
        while ( child && GTK_CTREE_ROW (child)->sibling != sibling ) {
 
388
                child = GTK_CTREE_ROW (child)->sibling;
 
389
        }
 
390
        return NODE_DATA (child)->repr;
 
391
}
 
392
 
 
393
gboolean
 
394
check_drag (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling)
 
395
{
 
396
        GtkCTreeNode * old_parent;
 
397
 
 
398
        old_parent = GTK_CTREE_ROW (node)->parent;
 
399
 
 
400
        if (!old_parent || !new_parent) return FALSE;
 
401
        if (NODE_DATA (new_parent)->repr->type() != Inkscape::XML::ELEMENT_NODE) return FALSE;
 
402
 
 
403
        /* fixme: we need add_child/remove_child/etc repr events without side-effects, so we can check here and give better visual feedback */
 
404
 
 
405
        return TRUE;
 
406
}
 
407
 
 
408
Inkscape::XML::Node *
 
409
sp_xmlview_tree_node_get_repr (SPXMLViewTree * tree, GtkCTreeNode * node)
 
410
{
 
411
        return NODE_DATA (node)->repr;
 
412
}
 
413
 
 
414
GtkCTreeNode *
 
415
sp_xmlview_tree_get_repr_node (SPXMLViewTree * tree, Inkscape::XML::Node * repr)
 
416
{
 
417
        return gtk_ctree_find_by_row_data_custom (GTK_CTREE (tree), NULL, repr, match_node_data_by_repr);
 
418
}
 
419
 
 
420
gint
 
421
match_node_data_by_repr(gconstpointer data_p, gconstpointer repr)
 
422
{
 
423
        return ((const NodeData *)data_p)->repr != (const Inkscape::XML::Node *)repr;
 
424
}