Code

patch from Gustav Broberg: undo annotations and history dialog
[inkscape.git] / src / dialogs / xml-tree.cpp
1 #define __SP_XMLVIEW_TREE_C__
3 /**
4  * \brief  XML View
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   MenTaLguY <mental@rydia.net>
9  *   bulia byak <buliabyak@users.sf.net>
10  *
11  * Copyright (C) 1999-2005 Authors
12  * Copyright (C) 2004 David Turner
13  *
14  * Released under GNU GPL, read the file 'COPYING' for more information
15  */
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
21 #include <gtk/gtkmain.h>
22 #include <gtk/gtkhbox.h>
23 #include <gtk/gtkvbox.h>
24 #include <gtk/gtkhpaned.h>
25 #include <gtk/gtkvpaned.h>
26 #include <gtk/gtkhseparator.h>
27 #include <gtk/gtkhbbox.h>
28 #include <gtk/gtktoolbar.h>
29 #include <gtk/gtkscrolledwindow.h>
30 #include <gtk/gtkentry.h>
31 #include <gtk/gtkarrow.h>
33 #include <glibmm/i18n.h>
34 #include "helper/window.h"
35 #include "macros.h"
36 #include "../inkscape.h"
37 #include "../document.h"
38 #include "../desktop-handles.h"
39 #include "desktop.h"
40 #include "../selection.h"
41 #include "../sp-string.h"
42 #include "../sp-tspan.h"
43 #include "../sp-root.h"
44 #include "../event-context.h"
45 #include "in-dt-coordsys.h"
48 #include "../widgets/sp-xmlview-tree.h"
49 #include "../widgets/sp-xmlview-content.h"
50 #include "../widgets/sp-xmlview-attr-list.h"
52 #include "../inkscape-stock.h"
53 #include "widgets/icon.h"
55 #include "dialog-events.h"
56 #include "../prefs-utils.h"
57 #include "../verbs.h"
58 #include "../interface.h"
60 #include "shortcuts.h"
61 #include <gdk/gdkkeysyms.h>
63 #include "message-stack.h"
64 #include "message-context.h"
66 struct EditableDest {
67     GtkEditable *editable;
68     gchar *text;
69 };
71 static GtkWidget *dlg = NULL;
72 static sigc::connection sel_changed_connection;
73 static sigc::connection document_uri_set_connection;
74 static sigc::connection document_replaced_connection;
75 static win_data wd;
76 // impossible original values to make sure they are read from prefs
77 static gint x = -1000, y = -1000, w = 0, h = 0;
78 static gchar *prefs_path = "dialogs.xml";
79 static GtkWidget *status = NULL;
80 static Inkscape::MessageStack *_message_stack = NULL;
81 static Inkscape::MessageContext *_message_context = NULL;
82 static sigc::connection _message_changed_connection;
84 static GtkTooltips *tooltips = NULL;
85 static GtkEditable *attr_name = NULL;
86 static GtkTextView *attr_value = NULL;
87 static SPXMLViewTree *tree = NULL;
88 static SPXMLViewAttrList *attributes = NULL;
89 static SPXMLViewContent *content = NULL;
91 static gint blocked = 0;
92 static SPDesktop *current_desktop = NULL;
93 static SPDocument *current_document = NULL;
94 static gint selected_attr = 0;
95 static Inkscape::XML::Node *selected_repr = NULL;
97 static void sp_xmltree_desktop_change( Inkscape::Application *inkscape,  SPDesktop *desktop, GtkWidget *dialog );
99 static void set_tree_desktop(SPDesktop *desktop);
100 static void set_tree_document(SPDocument *document);
101 static void set_tree_repr(Inkscape::XML::Node *repr);
103 static void set_tree_select(Inkscape::XML::Node *repr);
104 static void propagate_tree_select(Inkscape::XML::Node *repr);
106 static Inkscape::XML::Node *get_dt_select();
107 static void set_dt_select(Inkscape::XML::Node *repr);
109 static void on_tree_select_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
110 static void on_tree_unselect_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
111 static void after_tree_move(GtkCTree *tree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling, gpointer data);
112 static void on_destroy(GtkObject *object, gpointer data);
113 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data);
115 static void on_tree_select_row_enable_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
116 static void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
117 static void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
118 static void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
119 static void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
120 static void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
121 static void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
122 static void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
124 static void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
125 static void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
126 static void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
128 static void on_attr_select_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
129 static void on_attr_unselect_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
130 static void on_attr_row_changed( GtkCList *list, gint row, gpointer data );
132 static void on_attr_select_row_enable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
133 static void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
135 static void on_attr_select_row_set_name_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
136 static void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
137 static void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
139 static void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable, gpointer data);
141 static void on_desktop_selection_changed(Inkscape::Selection *selection);
142 static void on_document_replaced(SPDesktop *dt, SPDocument *document);
143 static void on_document_uri_set(gchar const *uri, SPDocument *document);
145 static void on_clicked_get_editable_text(GtkWidget *widget, gpointer data);
147 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog);
149 static void cmd_new_element_node(GtkObject *object, gpointer data);
150 static void cmd_new_text_node(GtkObject *object, gpointer data);
151 static void cmd_duplicate_node(GtkObject *object, gpointer data);
152 static void cmd_delete_node(GtkObject *object, gpointer data);
154 static void cmd_raise_node(GtkObject *object, gpointer data);
155 static void cmd_lower_node(GtkObject *object, gpointer data);
156 static void cmd_indent_node(GtkObject *object, gpointer data);
157 static void cmd_unindent_node(GtkObject *object, gpointer data);
159 static void cmd_delete_attr(GtkObject *object, gpointer data);
160 static void cmd_set_attr(GtkObject *object, gpointer data);
162 static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event);
165 /*
166  * \brief Sets the XML status bar when the tree is selected.
167  */
168 void tree_reset_context()
170     _message_context->set(Inkscape::NORMAL_MESSAGE,
171                           _("<b>Click</b> to select nodes, <b>drag</b> to rearrange."));
175 /*
176  * \brief Sets the XML status bar, depending on which attr is selected.
177  */
178 void attr_reset_context(gint attr)
180     if (attr == 0) {
181         _message_context->set(Inkscape::NORMAL_MESSAGE,
182                               _("<b>Click</b> attribute to edit."));
183     }
184     else {
185         const gchar *name = g_quark_to_string(attr);
186         gchar *message = g_strdup_printf(_("Attribute <b>%s</b> selected. Press <b>Ctrl+Enter</b> when done editing to commit changes."), name);
187         _message_context->set(Inkscape::NORMAL_MESSAGE, message);
188         g_free(message);
189     }
193 void sp_xml_tree_dialog()
195     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
197     if (!desktop) {
198         return;
199     }
201     if (dlg == NULL)
202     { // very long block
204         GtkWidget *box, *sw, *paned, *toolbar, *button;
205         GtkWidget *text_container, *attr_container, *attr_subpaned_container, *box2;
206         GtkWidget *set_attr;
208         tooltips = gtk_tooltips_new();
209         gtk_tooltips_enable(tooltips);
211         dlg = sp_window_new("", TRUE);
212         if (x == -1000 || y == -1000) {
213             x = prefs_get_int_attribute(prefs_path, "x", 0);
214             y = prefs_get_int_attribute(prefs_path, "y", 0);
215         }
216         if (w ==0 || h == 0) {
217             w = prefs_get_int_attribute(prefs_path, "w", 0);
218             h = prefs_get_int_attribute(prefs_path, "h", 0);
219         }
220         
221         if (x<0) x=0;
222         if (y<0) y=0;
224         if (x != 0 || y != 0) {
225             gtk_window_move((GtkWindow *) dlg, x, y);
226         } else {
227             gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
228         }
230         if (w && h) {
231             gtk_window_resize((GtkWindow *) dlg, w, h);
232         }
233         sp_transientize(dlg);
234         wd.win = dlg;
235         wd.stop = 0;
236         g_signal_connect  ( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd );
238         gtk_signal_connect( GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg );
240         gtk_signal_connect( GTK_OBJECT(dlg), "destroy", G_CALLBACK(on_destroy), dlg);
241         gtk_signal_connect( GTK_OBJECT(dlg), "delete_event", G_CALLBACK(on_delete), dlg);
242         g_signal_connect  ( G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(on_delete), dlg);
244         g_signal_connect  ( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg);
245         g_signal_connect  ( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg);
248         gtk_container_set_border_width(GTK_CONTAINER(dlg), 0);
249         gtk_window_set_default_size(GTK_WINDOW(dlg), 640, 384);
251         GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
252         gtk_container_add(GTK_CONTAINER(dlg), vbox);
254         GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
255         gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
257         status = gtk_label_new(NULL);
258         gtk_misc_set_alignment(GTK_MISC(status), 0.0, 0.5);
259         gtk_widget_set_size_request(status, 1, -1);
260         gtk_label_set_markup(GTK_LABEL(status), "");
261         gtk_box_pack_start(GTK_BOX(hbox), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 4);
262         gtk_box_pack_start(GTK_BOX(hbox), status, TRUE, TRUE, 0);
264         paned = gtk_hpaned_new();
265         gtk_paned_set_position(GTK_PANED(paned), 256);
266         gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 0);
268         _message_stack = new Inkscape::MessageStack();
269         _message_context = new Inkscape::MessageContext(_message_stack);
270         _message_changed_connection = _message_stack->connectChanged(
271             sigc::bind(sigc::ptr_fun(_set_status_message), dlg)
272         );
274         /* tree view */
276         box = gtk_vbox_new(FALSE, 0);
277         gtk_paned_pack1(GTK_PANED(paned), box, FALSE, FALSE);
279         tree = SP_XMLVIEW_TREE(sp_xmlview_tree_new(NULL, NULL, NULL));
280         gtk_tooltips_set_tip( tooltips, GTK_WIDGET(tree),
281                                _("Drag to reorder nodes"), NULL );
283         g_signal_connect( G_OBJECT(tree), "tree_select_row",
284                            G_CALLBACK(on_tree_select_row), NULL );
286         g_signal_connect( G_OBJECT(tree), "tree_unselect_row",
287                            G_CALLBACK(on_tree_unselect_row), NULL );
289         g_signal_connect_after( G_OBJECT(tree), "tree_move",
290                                  G_CALLBACK(after_tree_move), NULL);
292         /* TODO: replace gtk_signal_connect_while_alive() with something
293          * else...
294          */
295         toolbar = gtk_toolbar_new();
296         gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
297         gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
299         button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
300                 NULL,
301                 _("New element node"),
302                 NULL,
303                 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
304                                     INKSCAPE_STOCK_ADD_XML_ELEMENT_NODE ),
305                 G_CALLBACK(cmd_new_element_node),
306                 NULL);
308         gtk_signal_connect_while_alive( GTK_OBJECT(tree),
309                         "tree_select_row",
310                         G_CALLBACK(on_tree_select_row_enable_if_element),
311                         button,
312                         GTK_OBJECT(button));
314         gtk_signal_connect_while_alive(GTK_OBJECT(tree),
315                         "tree_unselect_row",
316                         G_CALLBACK(on_tree_unselect_row_disable),
317                         button,
318                         GTK_OBJECT(button));
320         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
322         button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
323                 NULL, _("New text node"), NULL,
324                 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
325                              INKSCAPE_STOCK_ADD_XML_TEXT_NODE ),
326                 G_CALLBACK(cmd_new_text_node),
327                 NULL);
329         gtk_signal_connect_while_alive(GTK_OBJECT(tree),
330                         "tree_select_row",
331                         G_CALLBACK(on_tree_select_row_enable_if_element),
332                         button,
333                         GTK_OBJECT(button));
335         gtk_signal_connect_while_alive(GTK_OBJECT(tree),
336                         "tree_unselect_row",
337                         G_CALLBACK(on_tree_unselect_row_disable),
338                         button,
339                         GTK_OBJECT(button));
341         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
343         button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
344                 NULL, _("Duplicate node"), NULL,
345                 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
346                              INKSCAPE_STOCK_DUPLICATE_XML_NODE ),
347                 G_CALLBACK(cmd_duplicate_node),
348                 NULL);
350         gtk_signal_connect_while_alive(GTK_OBJECT(tree),
351                         "tree_select_row",
352                         G_CALLBACK(on_tree_select_row_enable_if_mutable),
353                         button,
354                         GTK_OBJECT(button));
356         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
357                         G_CALLBACK(on_tree_unselect_row_disable),
358                         button, GTK_OBJECT(button));
360         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
362         gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
364         button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
365                 NULL, _("Delete node"), NULL,
366                 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
367                              INKSCAPE_STOCK_DELETE_XML_NODE ),
368                                            G_CALLBACK(cmd_delete_node), NULL );
370         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
371                         G_CALLBACK(on_tree_select_row_enable_if_mutable),
372                         button, GTK_OBJECT(button));
373         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
374                         G_CALLBACK(on_tree_unselect_row_disable),
375                         button, GTK_OBJECT(button));
376         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
378         gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
380         button = gtk_toolbar_append_item( GTK_TOOLBAR(toolbar), "<",
381                         _("Unindent node"), NULL,
382                         gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_IN),
383                         G_CALLBACK(cmd_unindent_node), NULL);
385         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
386                     G_CALLBACK(on_tree_select_row_enable_if_has_grandparent),
387                     button, GTK_OBJECT(button));
389         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
390                         G_CALLBACK(on_tree_unselect_row_disable),
391                         button, GTK_OBJECT(button));
393         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
395         button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), ">",
396                         _("Indent node"), NULL,
397                         gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_IN),
398                         G_CALLBACK(cmd_indent_node), NULL);
399         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
400                         G_CALLBACK(on_tree_select_row_enable_if_indentable),
401                         button, GTK_OBJECT(button));
402         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
403                        (GCallback) on_tree_unselect_row_disable,
404                         button, GTK_OBJECT(button));
405         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
407         button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "^",
408                         _("Raise node"), NULL,
409                         gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_IN),
410                         G_CALLBACK(cmd_raise_node), NULL);
411         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
412                     G_CALLBACK(on_tree_select_row_enable_if_not_first_child),
413                     button, GTK_OBJECT(button));
414         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
415                         G_CALLBACK(on_tree_unselect_row_disable),
416                         button, GTK_OBJECT(button));
417         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
419         button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "v",
420                         _("Lower node"), NULL,
421                         gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_IN),
422                         G_CALLBACK(cmd_lower_node), NULL);
423         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
424                         G_CALLBACK(on_tree_select_row_enable_if_not_last_child),
425                         button, GTK_OBJECT(button));
426         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
427                         G_CALLBACK(on_tree_unselect_row_disable),
428                         button, GTK_OBJECT(button));
429         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
431         gtk_box_pack_start(GTK_BOX(box), toolbar, FALSE, TRUE, 0);
433         sw = gtk_scrolled_window_new(NULL, NULL);
434         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
435                                          GTK_POLICY_AUTOMATIC,
436                                          GTK_POLICY_AUTOMATIC );
437         gtk_box_pack_start(GTK_BOX(box), sw, TRUE, TRUE, 0);
439         gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(tree));
441         /* node view */
443         box = gtk_vbox_new(FALSE, 0);
444         gtk_paned_pack2(GTK_PANED(paned), box, TRUE, TRUE);
446         /* attributes */
448         attr_container = gtk_vbox_new(FALSE, 0);
449         gtk_box_pack_start( GTK_BOX(box), GTK_WIDGET(attr_container),
450                              TRUE, TRUE, 0 );
452         attributes = SP_XMLVIEW_ATTR_LIST(sp_xmlview_attr_list_new(NULL));
453         g_signal_connect( G_OBJECT(attributes), "select_row",
454                            G_CALLBACK(on_attr_select_row), NULL);
455         g_signal_connect( G_OBJECT(attributes), "unselect_row",
456                            G_CALLBACK(on_attr_unselect_row), NULL);
457         g_signal_connect( G_OBJECT(attributes), "row-value-changed",
458                            G_CALLBACK(on_attr_row_changed), NULL);
460         toolbar = gtk_toolbar_new();
461         gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
462         gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
464         button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
465                 NULL, _("Delete attribute"), NULL,
466                 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
467                              INKSCAPE_STOCK_DELETE_XML_ATTRIBUTE ),
468                (GCallback) cmd_delete_attr, NULL);
470         gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "select_row",
471                        (GCallback) on_attr_select_row_enable, button,
472                         GTK_OBJECT(button));
474         gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "unselect_row",
475                        (GCallback) on_attr_unselect_row_disable, button,
476                         GTK_OBJECT(button));
478         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
479                        (GCallback) on_tree_unselect_row_disable, button,
480                         GTK_OBJECT(button));
482         gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
484         gtk_box_pack_start( GTK_BOX(attr_container),
485                              GTK_WIDGET(toolbar), FALSE, TRUE, 0 );
487         attr_subpaned_container = gtk_vpaned_new();
488         gtk_box_pack_start( GTK_BOX(attr_container),
489                              GTK_WIDGET(attr_subpaned_container),
490                              TRUE, TRUE, 0 );
491         gtk_widget_show(attr_subpaned_container);
493         sw = gtk_scrolled_window_new(NULL, NULL);
494         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
495                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
496         gtk_paned_pack1( GTK_PANED(attr_subpaned_container),
497                           GTK_WIDGET(sw), TRUE, TRUE );
498         gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(attributes));
500         toolbar = gtk_vbox_new(FALSE, 4);
501         gtk_container_set_border_width(GTK_CONTAINER(toolbar), 4);
503         box2 = gtk_hbox_new(FALSE, 4);
504         gtk_box_pack_start( GTK_BOX(toolbar), GTK_WIDGET(box2),
505                              FALSE, TRUE, 0);
507         attr_name = GTK_EDITABLE(gtk_entry_new());
508         gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_name),
509                                // TRANSLATORS: "Attribute" is a noun here
510                                _("Attribute name"), NULL );
512         gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
513                             (GCallback) on_attr_select_row_set_name_content,
514                              attr_name);
516         gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
517                             (GCallback) on_attr_unselect_row_clear_text,
518                              attr_name);
520         gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
521                             (GCallback) on_tree_unselect_row_clear_text,
522                              attr_name);
524         gtk_box_pack_start( GTK_BOX(box2), GTK_WIDGET(attr_name),
525                              TRUE, TRUE, 0);
527         set_attr = gtk_button_new();
528         gtk_tooltips_set_tip( tooltips, GTK_WIDGET(set_attr),
529                                // TRANSLATORS: "Set" is a verb here
530                                _("Set attribute"), NULL );
531         // TRANSLATORS: "Set" is a verb here
532         GtkWidget *set_label = gtk_label_new(_("Set"));
533         gtk_container_add(GTK_CONTAINER(set_attr), set_label);
535         gtk_signal_connect( GTK_OBJECT(set_attr), "clicked",
536                             (GCallback) cmd_set_attr, NULL);
537         gtk_signal_connect( GTK_OBJECT(attr_name), "changed",
538                    (GCallback) on_editable_changed_enable_if_valid_xml_name,
539                     set_attr );
540         gtk_widget_set_sensitive(GTK_WIDGET(set_attr), FALSE);
542         gtk_box_pack_start(GTK_BOX(box2), set_attr, FALSE, FALSE, 0);
544         sw = gtk_scrolled_window_new(NULL, NULL);
545         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
546                                          GTK_POLICY_AUTOMATIC,
547                                          GTK_POLICY_AUTOMATIC );
548         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
549         gtk_box_pack_start(GTK_BOX(toolbar), sw, TRUE, TRUE, 0);
551         attr_value =(GtkTextView *) gtk_text_view_new();
552         gtk_text_view_set_wrap_mode((GtkTextView *) attr_value, GTK_WRAP_CHAR);
553         gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_value),
554                                // TRANSLATORS: "Attribute" is a noun here
555                                _("Attribute value"), NULL );
556         gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
557                             (GCallback) on_attr_select_row_set_value_content,
558                              attr_value );
559         gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
560                             (GCallback) on_attr_unselect_row_clear_text,
561                              attr_value );
562         gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
563                             (GCallback) on_tree_unselect_row_clear_text,
564                              attr_value );
565         gtk_text_view_set_editable(attr_value, TRUE);
566         gtk_container_add( GTK_CONTAINER(sw),
567                             GTK_WIDGET(attr_value) );
569         gtk_paned_pack2( GTK_PANED(attr_subpaned_container),
570                           GTK_WIDGET(toolbar), FALSE, TRUE );
572         /* text */
574         sw = gtk_scrolled_window_new(NULL, NULL);
575         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
576                                          GTK_POLICY_AUTOMATIC,
577                                          GTK_POLICY_AUTOMATIC );
578         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
579         gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(sw), TRUE, TRUE, 0);
581         content = SP_XMLVIEW_CONTENT(sp_xmlview_content_new(NULL));
582         gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(content));
584         text_container = sw;
586         /* initial show/hide */
588         gtk_widget_show_all(GTK_WIDGET(dlg));
590         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
591                        (GCallback) on_tree_select_row_show_if_element,
592                         attr_container, GTK_OBJECT(attr_container));
594         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
595                        (GCallback) on_tree_unselect_row_hide,
596                         attr_container, GTK_OBJECT(attr_container));
598         gtk_widget_hide(attr_container);
600         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
601                        (GCallback) on_tree_select_row_show_if_text,
602                         text_container, GTK_OBJECT(text_container));
604         gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
605                        (GCallback) on_tree_unselect_row_hide,
606                         text_container, GTK_OBJECT(text_container));
608         gtk_widget_hide(text_container);
610         g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop",
611                            G_CALLBACK(sp_xmltree_desktop_change), dlg);
613         g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop",
614                            G_CALLBACK(sp_xmltree_desktop_change), dlg);
616         g_signal_connect((GObject *) dlg, "key_press_event", (GCallback) sp_xml_tree_key_press, NULL);
618         tree_reset_context();
619     } // end of if (dlg == NULL)
621     gtk_window_present((GtkWindow *) dlg);
623     g_assert(desktop != NULL);
624     set_tree_desktop(desktop);
626 } // end of sp_xml_tree_dialog()
628 static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event)
631     unsigned int shortcut = get_group0_keyval(event) |
632         ( event->state & GDK_SHIFT_MASK ?
633           SP_SHORTCUT_SHIFT_MASK : 0 ) |
634         ( event->state & GDK_CONTROL_MASK ?
635           SP_SHORTCUT_CONTROL_MASK : 0 ) |
636         ( event->state & GDK_MOD1_MASK ?
637           SP_SHORTCUT_ALT_MASK : 0 );
639     /* fixme: if you need to add more xml-tree-specific callbacks, you should probably upgrade
640      * the sp_shortcut mechanism to take into account windows. */
641     if (shortcut == (SP_SHORTCUT_CONTROL_MASK | GDK_Return)) {
642         cmd_set_attr(NULL, NULL);
643         return true;
644     }
645     return false;
649 static void sp_xmltree_desktop_change(Inkscape::Application *inkscape,
650                                       SPDesktop *desktop,
651                                       GtkWidget *dialog )
653     if (!desktop) {
654         return;
655     }
656     set_tree_desktop(desktop);
660 void set_tree_desktop(SPDesktop *desktop)
662     if ( desktop == current_desktop ) {
663         return;
664     }
666     if (current_desktop) {
667         sel_changed_connection.disconnect();
668         document_replaced_connection.disconnect();
669     }
670     current_desktop = desktop;
671     if (desktop) {
672         sel_changed_connection = sp_desktop_selection(desktop)->connectChanged(&on_desktop_selection_changed);
673         document_replaced_connection = desktop->connectDocumentReplaced(&on_document_replaced);
674         set_tree_document(sp_desktop_document(desktop));
675     } else {
676         set_tree_document(NULL);
677     }
679 } // end of set_tree_desktop()
683 void set_tree_document(SPDocument *document)
685     if (document == current_document) {
686         return;
687     }
689     if (current_document) {
690         document_uri_set_connection.disconnect();
691     }
692     current_document = document;
693     if (current_document) {
695         document_uri_set_connection = current_document->connectURISet(sigc::bind(sigc::ptr_fun(&on_document_uri_set), current_document));
696         on_document_uri_set(SP_DOCUMENT_URI(current_document), current_document);
697         set_tree_repr(sp_document_repr_root(current_document));
699     } else {
700         set_tree_repr(NULL);
701     }
706 void set_tree_repr(Inkscape::XML::Node *repr)
708     if (repr == selected_repr) {
709         return;
710     }
712     gtk_clist_freeze(GTK_CLIST(tree));
714     sp_xmlview_tree_set_repr(tree, repr);
716     if (repr) {
717         set_tree_select(get_dt_select());
718     } else {
719         set_tree_select(NULL);
720     }
722     gtk_clist_thaw(GTK_CLIST(tree));
724     propagate_tree_select(selected_repr);
730 void set_tree_select(Inkscape::XML::Node *repr)
732     if (selected_repr) {
733         Inkscape::GC::release(selected_repr);
734     }
736     selected_repr = repr;
737     if (repr) {
738         GtkCTreeNode *node;
740         Inkscape::GC::anchor(selected_repr);
742         node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), repr);
743         if (node) {
744             GtkCTreeNode *parent;
746             gtk_ctree_select(GTK_CTREE(tree), node);
748             parent = GTK_CTREE_ROW(node)->parent;
749             while (parent) {
750                 gtk_ctree_expand(GTK_CTREE(tree), parent);
751                 parent = GTK_CTREE_ROW(parent)->parent;
752             }
754             gtk_ctree_node_moveto(GTK_CTREE(tree), node, 0, 0.66, 0.0);
755         }
756     } else {
757         gtk_clist_unselect_all(GTK_CLIST(tree));
758     }
759     propagate_tree_select(repr);
764 void propagate_tree_select(Inkscape::XML::Node *repr)
766     if (repr && repr->type() == Inkscape::XML::ELEMENT_NODE) {
767         sp_xmlview_attr_list_set_repr(attributes, repr);
768     } else {
769         sp_xmlview_attr_list_set_repr(attributes, NULL);
770     }
772     if (repr && ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE ) ) {
773         sp_xmlview_content_set_repr(content, repr);
774     } else {
775         sp_xmlview_content_set_repr(content, NULL);
776     }
780 Inkscape::XML::Node *get_dt_select()
782     if (!current_desktop) {
783         return NULL;
784     }
786     return sp_desktop_selection(current_desktop)->singleRepr();
791 void set_dt_select(Inkscape::XML::Node *repr)
793     if (!current_desktop) {
794         return;
795     }
797     Inkscape::Selection *selection = sp_desktop_selection(current_desktop);
799     SPObject *object;
800     if (repr) {
801         while ( ( repr->type() != Inkscape::XML::ELEMENT_NODE )
802                 && sp_repr_parent(repr) )
803         {
804             repr = sp_repr_parent(repr);
805         } // end of while loop
807         object = sp_desktop_document(current_desktop)->getObjectByRepr(repr);
808     } else {
809         object = NULL;
810     }
812     blocked++;
813     if ( object && in_dt_coordsys(*object)
814          && !(SP_IS_STRING(object) ||
815                 SP_IS_ROOT(object)     ) )
816     {
817             /* We cannot set selection to root or string - they are not items and selection is not
818              * equipped to deal with them */
819             selection->set(SP_ITEM(object));
820     }
821     blocked--;
823 } // end of set_dt_select()
826 void on_tree_select_row(GtkCTree *tree,
827                         GtkCTreeNode *node,
828                         gint column,
829                         gpointer data)
831     if (blocked) {
832         return;
833     }
835     Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
836     g_assert(repr != NULL);
838     if (selected_repr == repr) {
839         return;
840     }
842     if (selected_repr) {
843         Inkscape::GC::release(selected_repr);
844         selected_repr = NULL;
845     }
846     selected_repr = repr;
847     Inkscape::GC::anchor(selected_repr);
849     propagate_tree_select(selected_repr);
851     set_dt_select(selected_repr);
853     tree_reset_context();
856 void on_tree_unselect_row(GtkCTree *tree,
857                           GtkCTreeNode *node,
858                           gint column,
859                           gpointer data)
861     if (blocked) {
862         return;
863     }
865     Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
866     propagate_tree_select(NULL);
867     set_dt_select(NULL);
869     if (selected_repr && (selected_repr == repr)) {
870         Inkscape::GC::release(selected_repr);
871         selected_repr = NULL;
872         selected_attr = 0;
873     }
878 void after_tree_move(GtkCTree *tree,
879                      GtkCTreeNode *node,
880                      GtkCTreeNode *new_parent,
881                      GtkCTreeNode *new_sibling,
882                      gpointer data)
884     if (GTK_CTREE_ROW(node)->parent  == new_parent &&
885         GTK_CTREE_ROW(node)->sibling == new_sibling)
886     {
887         sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
888                          /* TODO: annotate */ "xml-tree.cpp:888");
889     } else {
890         sp_document_cancel(current_document);
891     }
895 static void on_destroy(GtkObject *object, gpointer data)
897     set_tree_desktop(NULL);
898     gtk_object_destroy(GTK_OBJECT(tooltips));
899     tooltips = NULL;
900     sp_signal_disconnect_by_data(INKSCAPE, dlg);
901     wd.win = dlg = NULL;
902     wd.stop = 0;
904     _message_changed_connection.disconnect();
905     delete _message_context;
906     _message_context = NULL;
907     Inkscape::GC::release(_message_stack);
908     _message_stack = NULL;
909     _message_changed_connection.~connection();
911     status = NULL;
916 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data)
918     gtk_window_get_position((GtkWindow *) dlg, &x, &y);
919     gtk_window_get_size((GtkWindow *) dlg, &w, &h);
921     if (x<0) x=0;
922     if (y<0) y=0;
924     prefs_set_int_attribute(prefs_path, "x", x);
925     prefs_set_int_attribute(prefs_path, "y", y);
926     prefs_set_int_attribute(prefs_path, "w", w);
927     prefs_set_int_attribute(prefs_path, "h", h);
929     return FALSE; // which means, go ahead and destroy it
933 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog)
935     if (status) {
936         gtk_label_set_markup(GTK_LABEL(status), message ? message : "");
937     }
941 void on_tree_select_row_enable(GtkCTree *tree,
942                                GtkCTreeNode *node,
943                                gint column,
944                                gpointer data)
946     gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
951 void on_tree_select_row_enable_if_element(GtkCTree *tree,
952                                           GtkCTreeNode *node,
953                                           gint column,
954                                           gpointer data )
956     Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
958     if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
959         gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
960     } else {
961         gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
962     }
967 void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node,
968                                         gint column, gpointer data)
970     Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
972     if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
973         gtk_widget_show(GTK_WIDGET(data));
974     } else {
975         gtk_widget_hide(GTK_WIDGET(data));
976     }
981 void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node,
982                                      gint column, gpointer data)
984     Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
986     if ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE ) {
987         gtk_widget_show(GTK_WIDGET(data));
988     } else {
989         gtk_widget_hide(GTK_WIDGET(data));
990     }
994 gboolean xml_tree_node_mutable(GtkCTreeNode *node)
996     // top-level is immutable, obviously
997     if (!GTK_CTREE_ROW(node)->parent) {
998         return false;
999     }
1001     // if not in base level (where namedview, defs, etc go), we're mutable
1002     if (GTK_CTREE_ROW(GTK_CTREE_ROW(node)->parent)->parent) {
1003         return true;
1004     }
1006     Inkscape::XML::Node *repr;
1007     repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1008     g_assert(repr);
1010     // don't let "defs" or "namedview" disappear
1011     if ( !strcmp(repr->name(),"svg:defs") ||
1012          !strcmp(repr->name(),"sodipodi:namedview") ) {
1013         return false;
1014     }
1016     // everyone else is okay, I guess.  :)
1017     return true;
1021 void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node,
1022                                           gint column, gpointer data)
1024     gtk_widget_set_sensitive(GTK_WIDGET(data), xml_tree_node_mutable(node));
1029 void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node,
1030                                   gint column, gpointer data)
1032     gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1037 void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node,
1038                                gint column, gpointer data)
1040     gtk_widget_hide(GTK_WIDGET(data));
1045 void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node,
1046                                      gint column, gpointer data)
1048     if (GTK_IS_EDITABLE(data)) {
1049         gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1050     } else if (GTK_IS_TEXT_VIEW(data)) {
1051         GtkTextBuffer *tb;
1052         tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1053         gtk_text_buffer_set_text(tb, "", 0);
1054     }
1058 void on_attr_select_row(GtkCList *list, gint row, gint column,
1059                         GdkEventButton *event, gpointer data)
1061     selected_attr = sp_xmlview_attr_list_get_row_key(list, row);
1062     gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(attr_value));
1064     attr_reset_context(selected_attr);
1068 void on_attr_unselect_row(GtkCList *list, gint row, gint column,
1069                           GdkEventButton *event, gpointer data)
1071     selected_attr = 0;
1072     attr_reset_context(selected_attr);
1076 void on_attr_row_changed(GtkCList *list, gint row, gpointer data)
1078     gint attr = sp_xmlview_attr_list_get_row_key(list, row);
1080     if (attr == selected_attr) {
1081         /* if the attr changed, reselect the row in the list to sync
1082            the edit box */
1084         /*
1085         // get current attr values
1086         const gchar * name = g_quark_to_string (sp_xmlview_attr_list_get_row_key (list, row));
1087         const gchar * value = selected_repr->attribute(name);
1089         g_warning("value: '%s'",value);
1091         // get the edit box value
1092         GtkTextIter start, end;
1093         gtk_text_buffer_get_bounds ( gtk_text_view_get_buffer (attr_value),
1094                                      &start, &end );
1095         gchar * text = gtk_text_buffer_get_text ( gtk_text_view_get_buffer (attr_value),
1096                                        &start, &end, TRUE );
1097         g_warning("text: '%s'",text);
1099         // compare to edit box
1100         if (strcmp(text,value)) {
1101             // issue warning if they're different
1102             _message_stack->flash(Inkscape::WARNING_MESSAGE,
1103                                   _("Attribute changed in GUI while editing values!"));
1104         }
1105         g_free (text);
1107         */
1108         gtk_clist_unselect_row( GTK_CLIST(list), row, 0 );
1109         gtk_clist_select_row( GTK_CLIST(list), row, 0 );
1110     }
1114 void on_attr_select_row_set_name_content(GtkCList *list, gint row,
1115                                          gint column, GdkEventButton *event,
1116                                          gpointer data)
1118     GtkEditable *editable = GTK_EDITABLE(data);
1119     const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1120     gtk_editable_delete_text(editable, 0, -1);
1121     gint pos = 0;
1122     gtk_editable_insert_text(editable, name, strlen(name), &pos);
1127 void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column,
1128                                           GdkEventButton *event,
1129                                           gpointer data)
1131     GtkTextBuffer *tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1132     const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1133     const gchar *value = selected_repr->attribute(name);
1134     if (!value) {
1135         value = "";
1136     }
1137     gtk_text_buffer_set_text(tb, value, strlen(value));
1141 void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node,
1142                                              gint column, gpointer data)
1144     gboolean indentable = FALSE;
1146     if (xml_tree_node_mutable(node)) {
1147         Inkscape::XML::Node *repr, *prev;
1148         repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1150         Inkscape::XML::Node *parent=repr->parent();
1151         if ( parent && repr != parent->firstChild() ) {
1152             g_assert(parent->firstChild());
1154             // skip to the child just before the current repr
1155             for ( prev = parent->firstChild() ;
1156                   prev && prev->next() != repr ;
1157                   prev = prev->next() );
1159             if (prev && prev->type() == Inkscape::XML::ELEMENT_NODE) {
1160                 indentable = TRUE;
1161             }
1162         }
1163     }
1165     gtk_widget_set_sensitive(GTK_WIDGET(data), indentable);
1170 void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree,
1171                                                   GtkCTreeNode *node,
1172                                                   gint column,
1173                                                   gpointer data)
1175     Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1177     Inkscape::XML::Node *parent=repr->parent();
1178     if ( parent && repr != parent->firstChild() ) {
1179         gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1180     } else {
1181         gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1182     }
1187 void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree,
1188                                                  GtkCTreeNode *node,
1189                                                  gint column, gpointer data)
1191     Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1193     Inkscape::XML::Node *parent=repr->parent();
1194     if ( parent && parent->parent() && repr->next() ) {
1195         gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1196     } else {
1197         gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1198     }
1203 void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree,
1204                                                   GtkCTreeNode *node,
1205                                                   gint column, gpointer data)
1207     GtkCTreeNode *parent = GTK_CTREE_ROW(node)->parent;
1209     if (parent) {
1210         GtkCTreeNode *grandparent = GTK_CTREE_ROW(parent)->parent;
1211         if (grandparent) {
1212             gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1213         } else {
1214             gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1215         }
1216     } else {
1217         gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1218     }
1223 void on_attr_select_row_enable(GtkCList *list, gint row, gint column,
1224                                GdkEventButton *event, gpointer data)
1226     gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1231 void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column,
1232                                   GdkEventButton *event, gpointer data)
1234     gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1239 void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column,
1240                                      GdkEventButton *event, gpointer data)
1242     if (GTK_IS_EDITABLE(data)) {
1243         gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1244     } else if (GTK_IS_TEXT_VIEW(data)) {
1245         GtkTextBuffer *tb;
1246         tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1247         gtk_text_buffer_set_text(tb, "", 0);
1248     }
1253 void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable,
1254                                                   gpointer data)
1256     gchar *text = gtk_editable_get_chars(editable, 0, -1);
1258     /* TODO: need to do checking a little more rigorous than this */
1260     if (strlen(text)) {
1261         gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1262     } else {
1263         gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1264     }
1265     g_free(text);
1270 void on_desktop_selection_changed(Inkscape::Selection *selection)
1272     if (!blocked++) {
1273         set_tree_select(get_dt_select());
1274     }
1275     blocked--;
1278 static void on_document_replaced(SPDesktop *dt, SPDocument *doc)
1280     if (current_desktop)
1281         sel_changed_connection.disconnect();
1283     sel_changed_connection = sp_desktop_selection(dt)->connectChanged(&on_desktop_selection_changed);
1284     set_tree_document(doc);
1287 void on_document_uri_set(gchar const *uri, SPDocument *document)
1289     gchar title[500];
1290     sp_ui_dialog_title_string(Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), title);
1291     gchar *t = g_strdup_printf("%s: %s", SP_DOCUMENT_NAME(document), title);
1292     gtk_window_set_title(GTK_WINDOW(dlg), t);
1293     g_free(t);
1298 void on_clicked_get_editable_text(GtkWidget *widget, gpointer data)
1300     EditableDest *dest = (EditableDest *) data;
1301     dest->text = gtk_editable_get_chars(dest->editable, 0, -1);
1306 void cmd_new_element_node(GtkObject *object, gpointer data)
1308     EditableDest name;
1309     GtkWidget *window, *create, *cancel, *vbox, *entry, *bbox, *sep;
1311     g_assert(selected_repr != NULL);
1313     window = sp_window_new(NULL, TRUE);
1314     gtk_container_set_border_width(GTK_CONTAINER(window), 4);
1315     gtk_window_set_title(GTK_WINDOW(window), _("New element node..."));
1316     gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE);
1317     gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1318     gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(dlg));
1319     gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1320     gtk_signal_connect(GTK_OBJECT(window), "destroy", gtk_main_quit, NULL);
1322     vbox = gtk_vbox_new(FALSE, 4);
1323     gtk_container_add(GTK_CONTAINER(window), vbox);
1325     entry = gtk_entry_new();
1326     gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 0);
1328     sep = gtk_hseparator_new();
1329     gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, TRUE, 0);
1331     bbox = gtk_hbutton_box_new();
1332     gtk_container_set_border_width(GTK_CONTAINER(bbox), 4);
1333     gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1334     gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
1336     cancel = gtk_button_new_with_label(_("Cancel"));
1337     gtk_signal_connect_object( GTK_OBJECT(cancel), "clicked",
1338                                 G_CALLBACK(gtk_widget_destroy),
1339                                 GTK_OBJECT(window) );
1340     gtk_container_add(GTK_CONTAINER(bbox), cancel);
1342     create = gtk_button_new_with_label(_("Create"));
1343     gtk_widget_set_sensitive(GTK_WIDGET(create), FALSE);
1344     gtk_signal_connect( GTK_OBJECT(entry), "changed",
1345                     G_CALLBACK(on_editable_changed_enable_if_valid_xml_name),
1346                     create );
1347     gtk_signal_connect( GTK_OBJECT(create), "clicked",
1348                          G_CALLBACK(on_clicked_get_editable_text), &name );
1349     gtk_signal_connect_object( GTK_OBJECT(create), "clicked",
1350                                 G_CALLBACK(gtk_widget_destroy),
1351                                 GTK_OBJECT(window) );
1352     GTK_WIDGET_SET_FLAGS( GTK_WIDGET(create),
1353                            GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT );
1354     gtk_container_add(GTK_CONTAINER(bbox), create);
1356     gtk_widget_show_all(GTK_WIDGET(window));
1357     gtk_window_set_default(GTK_WINDOW(window), GTK_WIDGET(create));
1358     gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(entry));
1360     name.editable = GTK_EDITABLE(entry);
1361     name.text = NULL;
1363     gtk_main();
1365     g_assert(selected_repr != NULL);
1367     if (name.text) {
1368         Inkscape::XML::Node *new_repr;
1369         new_repr = sp_repr_new(name.text);
1370         g_free(name.text);
1371         selected_repr->appendChild(new_repr);
1372         set_tree_select(new_repr);
1373         set_dt_select(new_repr);
1374     }
1376 } // end of cmd_new_element_node()
1380 void cmd_new_text_node(GtkObject *object, gpointer data)
1382     g_assert(selected_repr != NULL);
1384     Inkscape::XML::Node *text = sp_repr_new_text("");
1385     selected_repr->appendChild(text);
1387     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1388                      /* TODO: annotate */ "xml-tree.cpp:1388");
1390     set_tree_select(text);
1391     set_dt_select(text);
1393     gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(content));
1397 void cmd_duplicate_node(GtkObject *object, gpointer data)
1399     g_assert(selected_repr != NULL);
1401     Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1402     Inkscape::XML::Node *dup = selected_repr->duplicate();
1403     parent->addChild(dup, selected_repr);
1405     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1406                      /* TODO: annotate */ "xml-tree.cpp:1406");
1408     GtkCTreeNode *node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), dup);
1410     if (node) {
1411         gtk_ctree_select(GTK_CTREE(tree), node);
1412     }
1417 void cmd_delete_node(GtkObject *object, gpointer data)
1419     g_assert(selected_repr != NULL);
1420     sp_repr_unparent(selected_repr);
1422     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1423                      /* TODO: annotate */ "xml-tree.cpp:1423");
1428 void cmd_delete_attr(GtkObject *object, gpointer data)
1430     g_assert(selected_repr != NULL);
1431     g_assert(selected_attr != 0);
1432     selected_repr->setAttribute(g_quark_to_string(selected_attr), NULL);
1434     SPObject *updated=current_document->getObjectByRepr(selected_repr);
1435     if (updated) {
1436         // force immediate update of dependant attributes
1437         updated->updateRepr();
1438     }
1440     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR, 
1441                      /* TODO: annotate */ "xml-tree.cpp:1441");
1446 void cmd_set_attr(GtkObject *object, gpointer data)
1448     g_assert(selected_repr != NULL);
1450     gchar *name = gtk_editable_get_chars(attr_name, 0, -1);
1451     GtkTextIter start;
1452     GtkTextIter end;
1453     gtk_text_buffer_get_bounds( gtk_text_view_get_buffer(attr_value),
1454                                  &start, &end );
1455     gchar *value = gtk_text_buffer_get_text( gtk_text_view_get_buffer(attr_value),
1456                                        &start, &end, TRUE );
1458     if (!sp_repr_set_attr(selected_repr, name, value)) {
1459         gchar *message = g_strdup_printf(_("Cannot set <b>%s</b>: Another element with value <b>%s</b> already exists!"), name, value);
1460         _message_stack->flash(Inkscape::WARNING_MESSAGE, message);
1461         g_free(message);
1462     }
1464     g_free(name);
1465     g_free(value);
1467     SPObject *updated = current_document->getObjectByRepr(selected_repr);
1468     if (updated) {
1469         // force immediate update of dependant attributes
1470         updated->updateRepr();
1471     }
1473     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1474                      /* TODO: annotate */ "xml-tree.cpp:1474");
1476     /* TODO: actually, the row won't have been created yet.  why? */
1477     gint row = sp_xmlview_attr_list_find_row_from_key(GTK_CLIST(attributes),
1478                                                       g_quark_from_string(name));
1479     if (row != -1) {
1480         gtk_clist_select_row(GTK_CLIST(attributes), row, 0);
1481     }
1486 void cmd_raise_node(GtkObject *object, gpointer data)
1488     g_assert(selected_repr != NULL);
1490     Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1491     g_return_if_fail(parent != NULL);
1492     g_return_if_fail(parent->firstChild() != selected_repr);
1494     Inkscape::XML::Node *ref = NULL;
1495     Inkscape::XML::Node *before = parent->firstChild();
1496     while (before && before->next() != selected_repr) {
1497         ref = before;
1498         before = before->next();
1499     }
1501     parent->changeOrder(selected_repr, ref);
1503     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR, 
1504                      /* TODO: annotate */ "xml-tree.cpp:1504");
1506     set_tree_select(selected_repr);
1507     set_dt_select(selected_repr);
1512 void cmd_lower_node(GtkObject *object, gpointer data)
1514     g_assert(selected_repr != NULL);
1515     g_return_if_fail(selected_repr->next() != NULL);
1516     Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1518     parent->changeOrder(selected_repr, selected_repr->next());
1520     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1521                      /* TODO: annotate */ "xml-tree.cpp:1521");
1523     set_tree_select(selected_repr);
1524     set_dt_select(selected_repr);
1527 void cmd_indent_node(GtkObject *object, gpointer data)
1529     Inkscape::XML::Node *repr = selected_repr;
1530     g_assert(repr != NULL);
1531     Inkscape::XML::Node *parent = sp_repr_parent(repr);
1532     g_return_if_fail(parent != NULL);
1533     g_return_if_fail(parent->firstChild() != repr);
1535     Inkscape::XML::Node* prev = parent->firstChild();
1536     while (prev && prev->next() != repr) {
1537         prev = prev->next();
1538     }
1539     g_return_if_fail(prev != NULL);
1540     g_return_if_fail(prev->type() == Inkscape::XML::ELEMENT_NODE);
1542     Inkscape::XML::Node* ref = NULL;
1543     if (prev->firstChild()) {
1544         for( ref = prev->firstChild() ; ref->next() ; ref = ref->next() );
1545     }
1547     parent->removeChild(repr);
1548     prev->addChild(repr, ref);
1550     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR, 
1551                      /* TODO: annotate */ "xml-tree.cpp:1551");
1552     set_tree_select(repr);
1553     set_dt_select(repr);
1555 } // end of cmd_indent_node()
1559 void cmd_unindent_node(GtkObject *object, gpointer data)
1561     Inkscape::XML::Node *repr = selected_repr;
1562     g_assert(repr != NULL);
1563     Inkscape::XML::Node *parent = sp_repr_parent(repr);
1564     g_return_if_fail(parent);
1565     Inkscape::XML::Node *grandparent = sp_repr_parent(parent);
1566     g_return_if_fail(grandparent);
1568     parent->removeChild(repr);
1569     grandparent->addChild(repr, parent);
1571     sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR, 
1572                      /* TODO: annotate */ "xml-tree.cpp:1572");
1573     set_tree_select(repr);
1574     set_dt_select(repr);
1576 } // end of cmd_unindent_node()
1579 /*
1580   Local Variables:
1581   mode:c++
1582   c-file-style:"stroustrup"
1583   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1584   indent-tabs-mode:nil
1585   fill-column:99
1586   End:
1587 */
1588 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :