~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

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 <cstring>
 
15
#include <string>
 
16
 
 
17
#include "../xml/node-event-vector.h"
 
18
#include "sp-xmlview-tree.h"
 
19
 
 
20
struct NodeData {
 
21
        SPXMLViewTree * tree;
 
22
        GtkCTreeNode * node;
 
23
        Inkscape::XML::Node * repr;
 
24
};
 
25
 
 
26
#define NODE_DATA(node) ((NodeData *)(GTK_CTREE_ROW ((node))->row.data))
 
27
 
 
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);
 
31
 
 
32
static NodeData * node_data_new (SPXMLViewTree * tree, GtkCTreeNode * node, Inkscape::XML::Node * repr);
 
33
static void node_data_free (gpointer data);
 
34
 
 
35
static GtkCTreeNode * add_node (SPXMLViewTree * tree, GtkCTreeNode * parent, GtkCTreeNode * before, Inkscape::XML::Node * repr);
 
36
 
 
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);
 
41
 
 
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);
 
45
 
 
46
static void tree_move (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling);
 
47
 
 
48
static gboolean check_drag (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling);
 
49
 
 
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);
 
53
 
 
54
static gint match_node_data_by_repr(gconstpointer data_p, gconstpointer repr);
 
55
 
 
56
static const Inkscape::XML::NodeEventVector element_repr_events = {
 
57
        element_child_added,
 
58
        element_child_removed,
 
59
        element_attr_changed,
 
60
        NULL, /* content_changed */
 
61
        element_order_changed
 
62
};
 
63
 
 
64
static const Inkscape::XML::NodeEventVector text_repr_events = {
 
65
        NULL, /* child_added */
 
66
        NULL, /* child_removed */
 
67
        NULL, /* attr_changed */
 
68
        text_content_changed,
 
69
        NULL  /* order_changed */
 
70
};
 
71
 
 
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 */
 
78
};
 
79
 
 
80
static const Inkscape::XML::NodeEventVector pi_repr_events = {
 
81
        NULL, /* child_added */
 
82
        NULL, /* child_removed */
 
83
        NULL, /* attr_changed */
 
84
        pi_content_changed,
 
85
        NULL  /* order_changed */
 
86
};
 
87
 
 
88
static GtkCTreeClass * parent_class = NULL;
 
89
 
 
90
GtkWidget *
 
91
sp_xmlview_tree_new (Inkscape::XML::Node * repr, void * /*factory*/, void * /*data*/)
 
92
{
 
93
        SPXMLViewTree * tree;
 
94
 
 
95
        tree = (SPXMLViewTree*)g_object_new (SP_TYPE_XMLVIEW_TREE, "n_columns", 1, "tree_column", 0, NULL);
 
96
 
 
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);
 
103
 
 
104
        sp_xmlview_tree_set_repr (tree, repr);
 
105
 
 
106
        return (GtkWidget *) tree;
 
107
}
 
108
 
 
109
void
 
110
sp_xmlview_tree_set_repr (SPXMLViewTree * tree, Inkscape::XML::Node * repr)
 
111
{
 
112
        if ( tree->repr == repr ) return;
 
113
        gtk_clist_freeze (GTK_CLIST (tree));
 
114
        if (tree->repr) {
 
115
                gtk_clist_clear (GTK_CLIST (tree));
 
116
                Inkscape::GC::release(tree->repr);
 
117
        }
 
118
        tree->repr = repr;
 
119
        if (repr) {
 
120
                GtkCTreeNode * node;
 
121
                Inkscape::GC::anchor(repr);
 
122
                node = add_node (tree, NULL, NULL, repr);
 
123
                gtk_ctree_expand (GTK_CTREE (tree), node);
 
124
        }
 
125
        gtk_clist_thaw (GTK_CLIST (tree));
 
126
}
 
127
 
 
128
GtkType
 
129
sp_xmlview_tree_get_type (void)
 
130
{
 
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
 
134
 
 
135
        static GtkType type = 0;
 
136
 
 
137
        if (!type) {
 
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,
 
144
                        NULL, NULL, NULL
 
145
                };
 
146
                type = gtk_type_unique (GTK_TYPE_CTREE, &info);
 
147
        }
 
148
 
 
149
        return type;
 
150
}
 
151
 
 
152
void
 
153
sp_xmlview_tree_class_init (SPXMLViewTreeClass * klass)
 
154
{
 
155
        GtkObjectClass * object_class;
 
156
 
 
157
        object_class = (GtkObjectClass *) klass;
 
158
        parent_class = (GtkCTreeClass *) gtk_type_class (GTK_TYPE_CTREE);
 
159
 
 
160
        GTK_CTREE_CLASS (object_class)->tree_move = tree_move;
 
161
 
 
162
        object_class->destroy = sp_xmlview_tree_destroy;
 
163
}
 
164
 
 
165
void
 
166
sp_xmlview_tree_init (SPXMLViewTree * tree)
 
167
{
 
168
        tree->repr = NULL;
 
169
        tree->blocked = 0;
 
170
}
 
171
 
 
172
void
 
173
sp_xmlview_tree_destroy (GtkObject * object)
 
174
{
 
175
        SPXMLViewTree * tree;
 
176
 
 
177
        tree = SP_XMLVIEW_TREE (object);
 
178
 
 
179
        sp_xmlview_tree_set_repr (tree, NULL);
 
180
 
 
181
        GTK_OBJECT_CLASS (parent_class)->destroy (object);
 
182
}
 
183
 
 
184
GtkCTreeNode *
 
185
add_node (SPXMLViewTree * tree, GtkCTreeNode * parent, GtkCTreeNode * before, Inkscape::XML::Node * repr)
 
186
{
 
187
        NodeData * data;
 
188
        GtkCTreeNode * node;
 
189
        const Inkscape::XML::NodeEventVector * vec;
 
190
        static const gchar *default_text[] = { "???" };
 
191
 
 
192
        g_assert (tree != NULL);
 
193
        g_assert (repr != NULL);
 
194
 
 
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);
 
197
 
 
198
        data = node_data_new (tree, node, repr);
 
199
        g_assert (data != NULL);
 
200
 
 
201
        gtk_ctree_node_set_row_data_full (GTK_CTREE (tree), data->node, data, node_data_free);
 
202
 
 
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;
 
211
        } else {
 
212
                vec = NULL;
 
213
        }
 
214
 
 
215
        if (vec) {
 
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);
 
220
                }
 
221
                sp_repr_add_listener (repr, vec, data);
 
222
                sp_repr_synthesize_events (repr, vec, data);
 
223
                gtk_clist_thaw (GTK_CLIST (tree));
 
224
        }
 
225
 
 
226
        return node;
 
227
}
 
228
 
 
229
NodeData *
 
230
node_data_new (SPXMLViewTree * tree, GtkCTreeNode * node, Inkscape::XML::Node * repr)
 
231
{
 
232
        NodeData * data;
 
233
        data = g_new (NodeData, 1);
 
234
        data->tree = tree;
 
235
        data->node = node;
 
236
        data->repr = repr;
 
237
        Inkscape::GC::anchor(repr);
 
238
        return data;
 
239
}
 
240
 
 
241
void
 
242
node_data_free (gpointer ptr) {
 
243
        NodeData * data;
 
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);
 
248
        g_free (data);
 
249
}
 
250
 
 
251
void
 
252
element_child_added (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer ptr)
 
253
{
 
254
        NodeData * data;
 
255
        GtkCTreeNode * before;
 
256
 
 
257
        data = (NodeData *) ptr;
 
258
 
 
259
        if (data->tree->blocked) return;
 
260
 
 
261
        before = ref_to_sibling (data->node, ref);
 
262
 
 
263
        add_node (data->tree, data->node, before, child);
 
264
}
 
265
 
 
266
void
 
267
element_attr_changed (Inkscape::XML::Node * repr, const gchar * key, const gchar * /*old_value*/, const gchar * new_value, bool /*is_interactive*/, gpointer ptr)
 
268
{
 
269
        NodeData * data;
 
270
        gchar *label;
 
271
        const gchar *layer;
 
272
 
 
273
        data = (NodeData *) ptr;
 
274
 
 
275
        if (data->tree->blocked) return;
 
276
 
 
277
        if (0 != strcmp (key, "id") && 0 != strcmp (key, "inkscape:label"))
 
278
                return;
 
279
 
 
280
        new_value = repr->attribute("id");
 
281
        layer = repr->attribute("inkscape:label");
 
282
 
 
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);
 
287
        } else {
 
288
                label = g_strdup_printf ("<%s>", repr->name());
 
289
        }
 
290
        gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
 
291
        g_free (label);
 
292
}
 
293
 
 
294
void
 
295
element_child_removed (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * /*ref*/, gpointer ptr)
 
296
{
 
297
        NodeData * data;
 
298
 
 
299
        data = (NodeData *) ptr;
 
300
 
 
301
        if (data->tree->blocked) return;
 
302
 
 
303
        gtk_ctree_remove_node (GTK_CTREE (data->tree), repr_to_child (data->node, child));
 
304
}
 
305
 
 
306
void
 
307
element_order_changed (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * /*oldref*/, Inkscape::XML::Node * newref, gpointer ptr)
 
308
{
 
309
        NodeData * data;
 
310
        GtkCTreeNode * before, * node;
 
311
 
 
312
        data = (NodeData *) ptr;
 
313
 
 
314
        if (data->tree->blocked) return;
 
315
 
 
316
        before = ref_to_sibling (data->node, newref);
 
317
        node = repr_to_child (data->node, child);
 
318
 
 
319
        if ( before == node ) before = GTK_CTREE_ROW (before)->sibling;
 
320
 
 
321
        parent_class->tree_move (GTK_CTREE (data->tree), node, data->node, before);
 
322
}
 
323
 
 
324
void
 
325
text_content_changed (Inkscape::XML::Node * /*repr*/, const gchar * /*old_content*/, const gchar * new_content, gpointer ptr)
 
326
{
 
327
        NodeData *data;
 
328
        gchar *label;
 
329
 
 
330
        data = (NodeData *) ptr;
 
331
 
 
332
        if (data->tree->blocked) return;
 
333
 
 
334
        label = g_strdup_printf ("\"%s\"", new_content);
 
335
        gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
 
336
        g_free (label);
 
337
}
 
338
 
 
339
void
 
340
comment_content_changed (Inkscape::XML::Node */*repr*/, const gchar * /*old_content*/, const gchar *new_content, gpointer ptr)
 
341
{
 
342
        NodeData *data;
 
343
        gchar *label;
 
344
 
 
345
        data = (NodeData *) ptr;
 
346
 
 
347
        if (data->tree->blocked) return;
 
348
 
 
349
        label = g_strdup_printf ("<!--%s-->", new_content);
 
350
        gtk_ctree_node_set_text (GTK_CTREE (data->tree), data->node, 0, label);
 
351
        g_free (label);
 
352
}
 
353
 
 
354
void
 
355
pi_content_changed(Inkscape::XML::Node *repr, const gchar * /*old_content*/, const gchar *new_content, gpointer ptr)
 
356
{
 
357
        NodeData *data;
 
358
        gchar *label;
 
359
 
 
360
        data = (NodeData *) ptr;
 
361
 
 
362
        if (data->tree->blocked) return;
 
363
 
 
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);
 
366
        g_free (label);
 
367
}
 
368
void
 
369
tree_move (GtkCTree * tree, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * new_sibling)
 
370
{
 
371
        GtkCTreeNode * old_parent;
 
372
        Inkscape::XML::Node * ref;
 
373
 
 
374
        old_parent = GTK_CTREE_ROW (node)->parent;
 
375
        if ( !old_parent || !new_parent ) return;
 
376
 
 
377
        ref = sibling_to_ref (new_parent, new_sibling);
 
378
 
 
379
        gtk_clist_freeze (GTK_CLIST (tree));
 
380
 
 
381
        SP_XMLVIEW_TREE (tree)->blocked++;
 
382
        if (new_parent == old_parent) {
 
383
                NODE_DATA (old_parent)->repr->changeOrder(NODE_DATA (node)->repr, ref);
 
384
        } else {
 
385
                NODE_DATA (old_parent)->repr->removeChild(NODE_DATA (node)->repr);
 
386
                NODE_DATA (new_parent)->repr->addChild(NODE_DATA (node)->repr, ref);
 
387
        }
 
388
        SP_XMLVIEW_TREE (tree)->blocked--;
 
389
 
 
390
        parent_class->tree_move (tree, node, new_parent, new_sibling);
 
391
 
 
392
        gtk_clist_thaw (GTK_CLIST (tree));
 
393
}
 
394
 
 
395
GtkCTreeNode *
 
396
ref_to_sibling (GtkCTreeNode * parent, Inkscape::XML::Node * ref)
 
397
{
 
398
        if (ref) {
 
399
                GtkCTreeNode * before;
 
400
                before = repr_to_child (parent, ref);
 
401
                g_assert (before != NULL);
 
402
                before = GTK_CTREE_ROW (before)->sibling;
 
403
                return before;
 
404
        } else {
 
405
                return GTK_CTREE_ROW (parent)->children;
 
406
        }
 
407
}
 
408
 
 
409
GtkCTreeNode *
 
410
repr_to_child (GtkCTreeNode * parent, Inkscape::XML::Node * repr)
 
411
{
 
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;
 
416
        }
 
417
        return child;
 
418
}
 
419
 
 
420
Inkscape::XML::Node *
 
421
sibling_to_ref (GtkCTreeNode * parent, GtkCTreeNode * sibling)
 
422
{
 
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;
 
428
        }
 
429
        return NODE_DATA (child)->repr;
 
430
}
 
431
 
 
432
gboolean
 
433
check_drag (GtkCTree * /*tree*/, GtkCTreeNode * node, GtkCTreeNode * new_parent, GtkCTreeNode * /*new_sibling*/)
 
434
{
 
435
        GtkCTreeNode * old_parent;
 
436
 
 
437
        old_parent = GTK_CTREE_ROW (node)->parent;
 
438
 
 
439
        if (!old_parent || !new_parent) return FALSE;
 
440
        if (NODE_DATA (new_parent)->repr->type() != Inkscape::XML::ELEMENT_NODE) return FALSE;
 
441
 
 
442
        /* fixme: we need add_child/remove_child/etc repr events without side-effects, so we can check here and give better visual feedback */
 
443
 
 
444
        return TRUE;
 
445
}
 
446
 
 
447
Inkscape::XML::Node *
 
448
sp_xmlview_tree_node_get_repr (SPXMLViewTree * /*tree*/, GtkCTreeNode * node)
 
449
{
 
450
        return NODE_DATA (node)->repr;
 
451
}
 
452
 
 
453
GtkCTreeNode *
 
454
sp_xmlview_tree_get_repr_node (SPXMLViewTree * tree, Inkscape::XML::Node * repr)
 
455
{
 
456
        return gtk_ctree_find_by_row_data_custom (GTK_CTREE (tree), NULL, repr, match_node_data_by_repr);
 
457
}
 
458
 
 
459
gint
 
460
match_node_data_by_repr(gconstpointer data_p, gconstpointer repr)
 
461
{
 
462
        return ((const NodeData *)data_p)->repr != (const Inkscape::XML::Node *)repr;
 
463
}