9ad3c0586b4ed1ceb708646ac83f344635b89d0c
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 * Johan Engelen <goejendaagh@zonnet.nl>
11 *
12 * Copyright (C) 1999-2006 Authors
13 * Copyright (C) 2004 David Turner
14 *
15 * Released under GNU GPL, read the file 'COPYING' for more information
16 */
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
22 #include <gtk/gtkmain.h>
23 #include <gtk/gtkhbox.h>
24 #include <gtk/gtkvbox.h>
25 #include <gtk/gtkhpaned.h>
26 #include <gtk/gtkvpaned.h>
27 #include <gtk/gtkhseparator.h>
28 #include <gtk/gtkhbbox.h>
29 #include <gtk/gtktoolbar.h>
30 #include <gtk/gtkscrolledwindow.h>
31 #include <gtk/gtkentry.h>
32 #include <gtk/gtkarrow.h>
34 #include <glibmm/i18n.h>
35 #include "helper/window.h"
36 #include "macros.h"
37 #include "../inkscape.h"
38 #include "../document.h"
39 #include "../desktop-handles.h"
40 #include "desktop.h"
41 #include "../selection.h"
42 #include "../sp-string.h"
43 #include "../sp-tspan.h"
44 #include "../sp-root.h"
45 #include "../event-context.h"
46 #include "in-dt-coordsys.h"
49 #include "../widgets/sp-xmlview-tree.h"
50 #include "../widgets/sp-xmlview-content.h"
51 #include "../widgets/sp-xmlview-attr-list.h"
53 #include "../inkscape-stock.h"
54 #include "widgets/icon.h"
56 #include "dialog-events.h"
57 #include "../prefs-utils.h"
58 #include "../verbs.h"
59 #include "../interface.h"
61 #include "shortcuts.h"
62 #include <gdk/gdkkeysyms.h>
64 #include "message-stack.h"
65 #include "message-context.h"
67 #define MIN_ONSCREEN_DISTANCE 50
69 struct EditableDest {
70 GtkEditable *editable;
71 gchar *text;
72 };
74 static GtkWidget *dlg = NULL;
75 static sigc::connection sel_changed_connection;
76 static sigc::connection document_uri_set_connection;
77 static sigc::connection document_replaced_connection;
78 static win_data wd;
79 // impossible original values to make sure they are read from prefs
80 static gint x = -1000, y = -1000, w = 0, h = 0;
81 static gchar *prefs_path = "dialogs.xml";
82 static GtkWidget *status = NULL;
83 static Inkscape::MessageStack *_message_stack = NULL;
84 static Inkscape::MessageContext *_message_context = NULL;
85 static sigc::connection _message_changed_connection;
87 static GtkTooltips *tooltips = NULL;
88 static GtkEditable *attr_name = NULL;
89 static GtkTextView *attr_value = NULL;
90 static SPXMLViewTree *tree = NULL;
91 static SPXMLViewAttrList *attributes = NULL;
92 static SPXMLViewContent *content = NULL;
94 static gint blocked = 0;
95 static SPDesktop *current_desktop = NULL;
96 static SPDocument *current_document = NULL;
97 static gint selected_attr = 0;
98 static Inkscape::XML::Node *selected_repr = NULL;
100 static void sp_xmltree_desktop_change( Inkscape::Application *inkscape, SPDesktop *desktop, GtkWidget *dialog );
102 static void set_tree_desktop(SPDesktop *desktop);
103 static void set_tree_document(SPDocument *document);
104 static void set_tree_repr(Inkscape::XML::Node *repr);
106 static void set_tree_select(Inkscape::XML::Node *repr);
107 static void propagate_tree_select(Inkscape::XML::Node *repr);
109 static Inkscape::XML::Node *get_dt_select();
110 static void set_dt_select(Inkscape::XML::Node *repr);
112 static void on_tree_select_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
113 static void on_tree_unselect_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
114 static void after_tree_move(GtkCTree *tree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling, gpointer data);
115 static void on_destroy(GtkObject *object, gpointer data);
116 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data);
118 static void on_tree_select_row_enable_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
119 static void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
120 static void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
121 static void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
122 static void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
123 static void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
124 static void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
125 static void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
127 static void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
128 static void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
129 static void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
131 static void on_attr_select_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
132 static void on_attr_unselect_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
133 static void on_attr_row_changed( GtkCList *list, gint row, gpointer data );
135 static void on_attr_select_row_enable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
136 static void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
138 static void on_attr_select_row_set_name_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
139 static void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
140 static void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
142 static void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable, gpointer data);
144 static void on_desktop_selection_changed(Inkscape::Selection *selection);
145 static void on_document_replaced(SPDesktop *dt, SPDocument *document);
146 static void on_document_uri_set(gchar const *uri, SPDocument *document);
148 static void on_clicked_get_editable_text(GtkWidget *widget, gpointer data);
150 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog);
152 static void cmd_new_element_node(GtkObject *object, gpointer data);
153 static void cmd_new_text_node(GtkObject *object, gpointer data);
154 static void cmd_duplicate_node(GtkObject *object, gpointer data);
155 static void cmd_delete_node(GtkObject *object, gpointer data);
157 static void cmd_raise_node(GtkObject *object, gpointer data);
158 static void cmd_lower_node(GtkObject *object, gpointer data);
159 static void cmd_indent_node(GtkObject *object, gpointer data);
160 static void cmd_unindent_node(GtkObject *object, gpointer data);
162 static void cmd_delete_attr(GtkObject *object, gpointer data);
163 static void cmd_set_attr(GtkObject *object, gpointer data);
165 static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event);
168 /*
169 * \brief Sets the XML status bar when the tree is selected.
170 */
171 void tree_reset_context()
172 {
173 _message_context->set(Inkscape::NORMAL_MESSAGE,
174 _("<b>Click</b> to select nodes, <b>drag</b> to rearrange."));
175 }
178 /*
179 * \brief Sets the XML status bar, depending on which attr is selected.
180 */
181 void attr_reset_context(gint attr)
182 {
183 if (attr == 0) {
184 _message_context->set(Inkscape::NORMAL_MESSAGE,
185 _("<b>Click</b> attribute to edit."));
186 }
187 else {
188 const gchar *name = g_quark_to_string(attr);
189 gchar *message = g_strdup_printf(_("Attribute <b>%s</b> selected. Press <b>Ctrl+Enter</b> when done editing to commit changes."), name);
190 _message_context->set(Inkscape::NORMAL_MESSAGE, message);
191 g_free(message);
192 }
193 }
196 void sp_xml_tree_dialog()
197 {
198 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
200 if (!desktop) {
201 return;
202 }
204 if (dlg == NULL)
205 { // very long block
207 GtkWidget *box, *sw, *paned, *toolbar, *button;
208 GtkWidget *text_container, *attr_container, *attr_subpaned_container, *box2;
209 GtkWidget *set_attr;
211 tooltips = gtk_tooltips_new();
212 gtk_tooltips_enable(tooltips);
214 dlg = sp_window_new("", TRUE);
215 if (x == -1000 || y == -1000) {
216 x = prefs_get_int_attribute(prefs_path, "x", -1000);
217 y = prefs_get_int_attribute(prefs_path, "y", -1000);
218 }
219 if (w ==0 || h == 0) {
220 w = prefs_get_int_attribute(prefs_path, "w", 0);
221 h = prefs_get_int_attribute(prefs_path, "h", 0);
222 }
224 // if (x<0) x=0;
225 // if (y<0) y=0;
227 if (w && h) {
228 gtk_window_resize((GtkWindow *) dlg, w, h);
229 }
230 if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE))) {
231 gtk_window_move((GtkWindow *) dlg, x, y);
232 } else {
233 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
234 }
236 sp_transientize(dlg);
237 wd.win = dlg;
238 wd.stop = 0;
239 g_signal_connect ( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd );
241 gtk_signal_connect( GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg );
243 gtk_signal_connect( GTK_OBJECT(dlg), "destroy", G_CALLBACK(on_destroy), dlg);
244 gtk_signal_connect( GTK_OBJECT(dlg), "delete_event", G_CALLBACK(on_delete), dlg);
245 g_signal_connect ( G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(on_delete), dlg);
247 g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg);
248 g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg);
251 gtk_container_set_border_width(GTK_CONTAINER(dlg), 0);
252 gtk_window_set_default_size(GTK_WINDOW(dlg), 640, 384);
254 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
255 gtk_container_add(GTK_CONTAINER(dlg), vbox);
257 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
258 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
260 status = gtk_label_new(NULL);
261 gtk_misc_set_alignment(GTK_MISC(status), 0.0, 0.5);
262 gtk_widget_set_size_request(status, 1, -1);
263 gtk_label_set_markup(GTK_LABEL(status), "");
264 gtk_box_pack_start(GTK_BOX(hbox), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 4);
265 gtk_box_pack_start(GTK_BOX(hbox), status, TRUE, TRUE, 0);
267 paned = gtk_hpaned_new();
268 gtk_paned_set_position(GTK_PANED(paned), 256);
269 gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 0);
271 _message_stack = new Inkscape::MessageStack();
272 _message_context = new Inkscape::MessageContext(_message_stack);
273 _message_changed_connection = _message_stack->connectChanged(
274 sigc::bind(sigc::ptr_fun(_set_status_message), dlg)
275 );
277 /* tree view */
279 box = gtk_vbox_new(FALSE, 0);
280 gtk_paned_pack1(GTK_PANED(paned), box, FALSE, FALSE);
282 tree = SP_XMLVIEW_TREE(sp_xmlview_tree_new(NULL, NULL, NULL));
283 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(tree),
284 _("Drag to reorder nodes"), NULL );
286 g_signal_connect( G_OBJECT(tree), "tree_select_row",
287 G_CALLBACK(on_tree_select_row), NULL );
289 g_signal_connect( G_OBJECT(tree), "tree_unselect_row",
290 G_CALLBACK(on_tree_unselect_row), NULL );
292 g_signal_connect_after( G_OBJECT(tree), "tree_move",
293 G_CALLBACK(after_tree_move), NULL);
295 /* TODO: replace gtk_signal_connect_while_alive() with something
296 * else...
297 */
298 toolbar = gtk_toolbar_new();
299 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
300 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
302 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
303 NULL,
304 _("New element node"),
305 NULL,
306 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
307 INKSCAPE_STOCK_ADD_XML_ELEMENT_NODE ),
308 G_CALLBACK(cmd_new_element_node),
309 NULL);
311 gtk_signal_connect_while_alive( GTK_OBJECT(tree),
312 "tree_select_row",
313 G_CALLBACK(on_tree_select_row_enable_if_element),
314 button,
315 GTK_OBJECT(button));
317 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
318 "tree_unselect_row",
319 G_CALLBACK(on_tree_unselect_row_disable),
320 button,
321 GTK_OBJECT(button));
323 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
325 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
326 NULL, _("New text node"), NULL,
327 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
328 INKSCAPE_STOCK_ADD_XML_TEXT_NODE ),
329 G_CALLBACK(cmd_new_text_node),
330 NULL);
332 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
333 "tree_select_row",
334 G_CALLBACK(on_tree_select_row_enable_if_element),
335 button,
336 GTK_OBJECT(button));
338 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
339 "tree_unselect_row",
340 G_CALLBACK(on_tree_unselect_row_disable),
341 button,
342 GTK_OBJECT(button));
344 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
346 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
347 NULL, _("Duplicate node"), NULL,
348 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
349 INKSCAPE_STOCK_DUPLICATE_XML_NODE ),
350 G_CALLBACK(cmd_duplicate_node),
351 NULL);
353 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
354 "tree_select_row",
355 G_CALLBACK(on_tree_select_row_enable_if_mutable),
356 button,
357 GTK_OBJECT(button));
359 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
360 G_CALLBACK(on_tree_unselect_row_disable),
361 button, GTK_OBJECT(button));
363 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
365 gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
367 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
368 NULL, _("Delete node"), NULL,
369 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
370 INKSCAPE_STOCK_DELETE_XML_NODE ),
371 G_CALLBACK(cmd_delete_node), NULL );
373 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
374 G_CALLBACK(on_tree_select_row_enable_if_mutable),
375 button, GTK_OBJECT(button));
376 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
377 G_CALLBACK(on_tree_unselect_row_disable),
378 button, GTK_OBJECT(button));
379 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
381 gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
383 button = gtk_toolbar_append_item( GTK_TOOLBAR(toolbar), "<",
384 _("Unindent node"), NULL,
385 gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_IN),
386 G_CALLBACK(cmd_unindent_node), NULL);
388 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
389 G_CALLBACK(on_tree_select_row_enable_if_has_grandparent),
390 button, GTK_OBJECT(button));
392 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
393 G_CALLBACK(on_tree_unselect_row_disable),
394 button, GTK_OBJECT(button));
396 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
398 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), ">",
399 _("Indent node"), NULL,
400 gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_IN),
401 G_CALLBACK(cmd_indent_node), NULL);
402 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
403 G_CALLBACK(on_tree_select_row_enable_if_indentable),
404 button, GTK_OBJECT(button));
405 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
406 (GCallback) on_tree_unselect_row_disable,
407 button, GTK_OBJECT(button));
408 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
410 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "^",
411 _("Raise node"), NULL,
412 gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_IN),
413 G_CALLBACK(cmd_raise_node), NULL);
414 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
415 G_CALLBACK(on_tree_select_row_enable_if_not_first_child),
416 button, GTK_OBJECT(button));
417 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
418 G_CALLBACK(on_tree_unselect_row_disable),
419 button, GTK_OBJECT(button));
420 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
422 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "v",
423 _("Lower node"), NULL,
424 gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_IN),
425 G_CALLBACK(cmd_lower_node), NULL);
426 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
427 G_CALLBACK(on_tree_select_row_enable_if_not_last_child),
428 button, GTK_OBJECT(button));
429 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
430 G_CALLBACK(on_tree_unselect_row_disable),
431 button, GTK_OBJECT(button));
432 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
434 gtk_box_pack_start(GTK_BOX(box), toolbar, FALSE, TRUE, 0);
436 sw = gtk_scrolled_window_new(NULL, NULL);
437 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
438 GTK_POLICY_AUTOMATIC,
439 GTK_POLICY_AUTOMATIC );
440 gtk_box_pack_start(GTK_BOX(box), sw, TRUE, TRUE, 0);
442 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(tree));
444 /* node view */
446 box = gtk_vbox_new(FALSE, 0);
447 gtk_paned_pack2(GTK_PANED(paned), box, TRUE, TRUE);
449 /* attributes */
451 attr_container = gtk_vbox_new(FALSE, 0);
452 gtk_box_pack_start( GTK_BOX(box), GTK_WIDGET(attr_container),
453 TRUE, TRUE, 0 );
455 attributes = SP_XMLVIEW_ATTR_LIST(sp_xmlview_attr_list_new(NULL));
456 g_signal_connect( G_OBJECT(attributes), "select_row",
457 G_CALLBACK(on_attr_select_row), NULL);
458 g_signal_connect( G_OBJECT(attributes), "unselect_row",
459 G_CALLBACK(on_attr_unselect_row), NULL);
460 g_signal_connect( G_OBJECT(attributes), "row-value-changed",
461 G_CALLBACK(on_attr_row_changed), NULL);
463 toolbar = gtk_toolbar_new();
464 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
465 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
467 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
468 NULL, _("Delete attribute"), NULL,
469 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
470 INKSCAPE_STOCK_DELETE_XML_ATTRIBUTE ),
471 (GCallback) cmd_delete_attr, NULL);
473 gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "select_row",
474 (GCallback) on_attr_select_row_enable, button,
475 GTK_OBJECT(button));
477 gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "unselect_row",
478 (GCallback) on_attr_unselect_row_disable, button,
479 GTK_OBJECT(button));
481 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
482 (GCallback) on_tree_unselect_row_disable, button,
483 GTK_OBJECT(button));
485 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
487 gtk_box_pack_start( GTK_BOX(attr_container),
488 GTK_WIDGET(toolbar), FALSE, TRUE, 0 );
490 attr_subpaned_container = gtk_vpaned_new();
491 gtk_box_pack_start( GTK_BOX(attr_container),
492 GTK_WIDGET(attr_subpaned_container),
493 TRUE, TRUE, 0 );
494 gtk_widget_show(attr_subpaned_container);
496 sw = gtk_scrolled_window_new(NULL, NULL);
497 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
498 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
499 gtk_paned_pack1( GTK_PANED(attr_subpaned_container),
500 GTK_WIDGET(sw), TRUE, TRUE );
501 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(attributes));
503 toolbar = gtk_vbox_new(FALSE, 4);
504 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 4);
506 box2 = gtk_hbox_new(FALSE, 4);
507 gtk_box_pack_start( GTK_BOX(toolbar), GTK_WIDGET(box2),
508 FALSE, TRUE, 0);
510 attr_name = GTK_EDITABLE(gtk_entry_new());
511 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_name),
512 // TRANSLATORS: "Attribute" is a noun here
513 _("Attribute name"), NULL );
515 gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
516 (GCallback) on_attr_select_row_set_name_content,
517 attr_name);
519 gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
520 (GCallback) on_attr_unselect_row_clear_text,
521 attr_name);
523 gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
524 (GCallback) on_tree_unselect_row_clear_text,
525 attr_name);
527 gtk_box_pack_start( GTK_BOX(box2), GTK_WIDGET(attr_name),
528 TRUE, TRUE, 0);
530 set_attr = gtk_button_new();
531 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(set_attr),
532 // TRANSLATORS: "Set" is a verb here
533 _("Set attribute"), NULL );
534 // TRANSLATORS: "Set" is a verb here
535 GtkWidget *set_label = gtk_label_new(_("Set"));
536 gtk_container_add(GTK_CONTAINER(set_attr), set_label);
538 gtk_signal_connect( GTK_OBJECT(set_attr), "clicked",
539 (GCallback) cmd_set_attr, NULL);
540 gtk_signal_connect( GTK_OBJECT(attr_name), "changed",
541 (GCallback) on_editable_changed_enable_if_valid_xml_name,
542 set_attr );
543 gtk_widget_set_sensitive(GTK_WIDGET(set_attr), FALSE);
545 gtk_box_pack_start(GTK_BOX(box2), set_attr, FALSE, FALSE, 0);
547 sw = gtk_scrolled_window_new(NULL, NULL);
548 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
549 GTK_POLICY_AUTOMATIC,
550 GTK_POLICY_AUTOMATIC );
551 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
552 gtk_box_pack_start(GTK_BOX(toolbar), sw, TRUE, TRUE, 0);
554 attr_value =(GtkTextView *) gtk_text_view_new();
555 gtk_text_view_set_wrap_mode((GtkTextView *) attr_value, GTK_WRAP_CHAR);
556 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_value),
557 // TRANSLATORS: "Attribute" is a noun here
558 _("Attribute value"), NULL );
559 gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
560 (GCallback) on_attr_select_row_set_value_content,
561 attr_value );
562 gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
563 (GCallback) on_attr_unselect_row_clear_text,
564 attr_value );
565 gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
566 (GCallback) on_tree_unselect_row_clear_text,
567 attr_value );
568 gtk_text_view_set_editable(attr_value, TRUE);
569 gtk_container_add( GTK_CONTAINER(sw),
570 GTK_WIDGET(attr_value) );
572 gtk_paned_pack2( GTK_PANED(attr_subpaned_container),
573 GTK_WIDGET(toolbar), FALSE, TRUE );
575 /* text */
577 sw = gtk_scrolled_window_new(NULL, NULL);
578 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
579 GTK_POLICY_AUTOMATIC,
580 GTK_POLICY_AUTOMATIC );
581 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
582 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(sw), TRUE, TRUE, 0);
584 content = SP_XMLVIEW_CONTENT(sp_xmlview_content_new(NULL));
585 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(content));
587 text_container = sw;
589 /* initial show/hide */
591 gtk_widget_show_all(GTK_WIDGET(dlg));
593 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
594 (GCallback) on_tree_select_row_show_if_element,
595 attr_container, GTK_OBJECT(attr_container));
597 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
598 (GCallback) on_tree_unselect_row_hide,
599 attr_container, GTK_OBJECT(attr_container));
601 gtk_widget_hide(attr_container);
603 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
604 (GCallback) on_tree_select_row_show_if_text,
605 text_container, GTK_OBJECT(text_container));
607 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
608 (GCallback) on_tree_unselect_row_hide,
609 text_container, GTK_OBJECT(text_container));
611 gtk_widget_hide(text_container);
613 g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop",
614 G_CALLBACK(sp_xmltree_desktop_change), dlg);
616 g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop",
617 G_CALLBACK(sp_xmltree_desktop_change), dlg);
619 g_signal_connect((GObject *) dlg, "key_press_event", (GCallback) sp_xml_tree_key_press, NULL);
621 tree_reset_context();
622 } // end of if (dlg == NULL)
624 gtk_window_present((GtkWindow *) dlg);
626 g_assert(desktop != NULL);
627 set_tree_desktop(desktop);
629 } // end of sp_xml_tree_dialog()
631 static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event)
632 {
634 unsigned int shortcut = get_group0_keyval(event) |
635 ( event->state & GDK_SHIFT_MASK ?
636 SP_SHORTCUT_SHIFT_MASK : 0 ) |
637 ( event->state & GDK_CONTROL_MASK ?
638 SP_SHORTCUT_CONTROL_MASK : 0 ) |
639 ( event->state & GDK_MOD1_MASK ?
640 SP_SHORTCUT_ALT_MASK : 0 );
642 /* fixme: if you need to add more xml-tree-specific callbacks, you should probably upgrade
643 * the sp_shortcut mechanism to take into account windows. */
644 if (shortcut == (SP_SHORTCUT_CONTROL_MASK | GDK_Return)) {
645 cmd_set_attr(NULL, NULL);
646 return true;
647 }
648 return false;
649 }
652 static void sp_xmltree_desktop_change(Inkscape::Application *inkscape,
653 SPDesktop *desktop,
654 GtkWidget *dialog )
655 {
656 if (!desktop) {
657 return;
658 }
659 set_tree_desktop(desktop);
660 }
663 void set_tree_desktop(SPDesktop *desktop)
664 {
665 if ( desktop == current_desktop ) {
666 return;
667 }
669 if (current_desktop) {
670 sel_changed_connection.disconnect();
671 document_replaced_connection.disconnect();
672 }
673 current_desktop = desktop;
674 if (desktop) {
675 sel_changed_connection = sp_desktop_selection(desktop)->connectChanged(&on_desktop_selection_changed);
676 document_replaced_connection = desktop->connectDocumentReplaced(&on_document_replaced);
677 set_tree_document(sp_desktop_document(desktop));
678 } else {
679 set_tree_document(NULL);
680 }
682 } // end of set_tree_desktop()
686 void set_tree_document(SPDocument *document)
687 {
688 if (document == current_document) {
689 return;
690 }
692 if (current_document) {
693 document_uri_set_connection.disconnect();
694 }
695 current_document = document;
696 if (current_document) {
698 document_uri_set_connection = current_document->connectURISet(sigc::bind(sigc::ptr_fun(&on_document_uri_set), current_document));
699 on_document_uri_set(SP_DOCUMENT_URI(current_document), current_document);
700 set_tree_repr(sp_document_repr_root(current_document));
702 } else {
703 set_tree_repr(NULL);
704 }
705 }
709 void set_tree_repr(Inkscape::XML::Node *repr)
710 {
711 if (repr == selected_repr) {
712 return;
713 }
715 gtk_clist_freeze(GTK_CLIST(tree));
717 sp_xmlview_tree_set_repr(tree, repr);
719 if (repr) {
720 set_tree_select(get_dt_select());
721 } else {
722 set_tree_select(NULL);
723 }
725 gtk_clist_thaw(GTK_CLIST(tree));
727 propagate_tree_select(selected_repr);
729 }
733 void set_tree_select(Inkscape::XML::Node *repr)
734 {
735 if (selected_repr) {
736 Inkscape::GC::release(selected_repr);
737 }
739 selected_repr = repr;
740 if (repr) {
741 GtkCTreeNode *node;
743 Inkscape::GC::anchor(selected_repr);
745 node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), repr);
746 if (node) {
747 GtkCTreeNode *parent;
749 gtk_ctree_select(GTK_CTREE(tree), node);
751 parent = GTK_CTREE_ROW(node)->parent;
752 while (parent) {
753 gtk_ctree_expand(GTK_CTREE(tree), parent);
754 parent = GTK_CTREE_ROW(parent)->parent;
755 }
757 gtk_ctree_node_moveto(GTK_CTREE(tree), node, 0, 0.66, 0.0);
758 }
759 } else {
760 gtk_clist_unselect_all(GTK_CLIST(tree));
761 }
762 propagate_tree_select(repr);
763 }
767 void propagate_tree_select(Inkscape::XML::Node *repr)
768 {
769 if (repr && repr->type() == Inkscape::XML::ELEMENT_NODE) {
770 sp_xmlview_attr_list_set_repr(attributes, repr);
771 } else {
772 sp_xmlview_attr_list_set_repr(attributes, NULL);
773 }
775 if (repr && ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE ) ) {
776 sp_xmlview_content_set_repr(content, repr);
777 } else {
778 sp_xmlview_content_set_repr(content, NULL);
779 }
780 }
783 Inkscape::XML::Node *get_dt_select()
784 {
785 if (!current_desktop) {
786 return NULL;
787 }
789 return sp_desktop_selection(current_desktop)->singleRepr();
790 }
794 void set_dt_select(Inkscape::XML::Node *repr)
795 {
796 if (!current_desktop) {
797 return;
798 }
800 Inkscape::Selection *selection = sp_desktop_selection(current_desktop);
802 SPObject *object;
803 if (repr) {
804 while ( ( repr->type() != Inkscape::XML::ELEMENT_NODE )
805 && sp_repr_parent(repr) )
806 {
807 repr = sp_repr_parent(repr);
808 } // end of while loop
810 object = sp_desktop_document(current_desktop)->getObjectByRepr(repr);
811 } else {
812 object = NULL;
813 }
815 blocked++;
816 if ( object && in_dt_coordsys(*object)
817 && !(SP_IS_STRING(object) ||
818 SP_IS_ROOT(object) ) )
819 {
820 /* We cannot set selection to root or string - they are not items and selection is not
821 * equipped to deal with them */
822 selection->set(SP_ITEM(object));
823 }
824 blocked--;
826 } // end of set_dt_select()
829 void on_tree_select_row(GtkCTree *tree,
830 GtkCTreeNode *node,
831 gint column,
832 gpointer data)
833 {
834 if (blocked) {
835 return;
836 }
838 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
839 g_assert(repr != NULL);
841 if (selected_repr == repr) {
842 return;
843 }
845 if (selected_repr) {
846 Inkscape::GC::release(selected_repr);
847 selected_repr = NULL;
848 }
849 selected_repr = repr;
850 Inkscape::GC::anchor(selected_repr);
852 propagate_tree_select(selected_repr);
854 set_dt_select(selected_repr);
856 tree_reset_context();
857 }
859 void on_tree_unselect_row(GtkCTree *tree,
860 GtkCTreeNode *node,
861 gint column,
862 gpointer data)
863 {
864 if (blocked) {
865 return;
866 }
868 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
869 propagate_tree_select(NULL);
870 set_dt_select(NULL);
872 if (selected_repr && (selected_repr == repr)) {
873 Inkscape::GC::release(selected_repr);
874 selected_repr = NULL;
875 selected_attr = 0;
876 }
877 }
881 void after_tree_move(GtkCTree *tree,
882 GtkCTreeNode *node,
883 GtkCTreeNode *new_parent,
884 GtkCTreeNode *new_sibling,
885 gpointer data)
886 {
887 if (GTK_CTREE_ROW(node)->parent == new_parent &&
888 GTK_CTREE_ROW(node)->sibling == new_sibling)
889 {
890 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
891 _("Drag XML subtree"));
892 } else {
893 sp_document_cancel(current_document);
894 }
895 }
898 static void on_destroy(GtkObject *object, gpointer data)
899 {
900 set_tree_desktop(NULL);
901 gtk_object_destroy(GTK_OBJECT(tooltips));
902 tooltips = NULL;
903 sp_signal_disconnect_by_data(INKSCAPE, dlg);
904 wd.win = dlg = NULL;
905 wd.stop = 0;
907 _message_changed_connection.disconnect();
908 delete _message_context;
909 _message_context = NULL;
910 Inkscape::GC::release(_message_stack);
911 _message_stack = NULL;
912 _message_changed_connection.~connection();
914 status = NULL;
915 }
919 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data)
920 {
921 gtk_window_get_position((GtkWindow *) dlg, &x, &y);
922 gtk_window_get_size((GtkWindow *) dlg, &w, &h);
924 if (x<0) x=0;
925 if (y<0) y=0;
927 prefs_set_int_attribute(prefs_path, "x", x);
928 prefs_set_int_attribute(prefs_path, "y", y);
929 prefs_set_int_attribute(prefs_path, "w", w);
930 prefs_set_int_attribute(prefs_path, "h", h);
932 return FALSE; // which means, go ahead and destroy it
933 }
936 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog)
937 {
938 if (status) {
939 gtk_label_set_markup(GTK_LABEL(status), message ? message : "");
940 }
941 }
944 void on_tree_select_row_enable(GtkCTree *tree,
945 GtkCTreeNode *node,
946 gint column,
947 gpointer data)
948 {
949 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
950 }
954 void on_tree_select_row_enable_if_element(GtkCTree *tree,
955 GtkCTreeNode *node,
956 gint column,
957 gpointer data )
958 {
959 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
961 if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
962 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
963 } else {
964 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
965 }
966 }
970 void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node,
971 gint column, gpointer data)
972 {
973 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
975 if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
976 gtk_widget_show(GTK_WIDGET(data));
977 } else {
978 gtk_widget_hide(GTK_WIDGET(data));
979 }
980 }
984 void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node,
985 gint column, gpointer data)
986 {
987 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
989 if ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE ) {
990 gtk_widget_show(GTK_WIDGET(data));
991 } else {
992 gtk_widget_hide(GTK_WIDGET(data));
993 }
994 }
997 gboolean xml_tree_node_mutable(GtkCTreeNode *node)
998 {
999 // top-level is immutable, obviously
1000 if (!GTK_CTREE_ROW(node)->parent) {
1001 return false;
1002 }
1004 // if not in base level (where namedview, defs, etc go), we're mutable
1005 if (GTK_CTREE_ROW(GTK_CTREE_ROW(node)->parent)->parent) {
1006 return true;
1007 }
1009 Inkscape::XML::Node *repr;
1010 repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1011 g_assert(repr);
1013 // don't let "defs" or "namedview" disappear
1014 if ( !strcmp(repr->name(),"svg:defs") ||
1015 !strcmp(repr->name(),"sodipodi:namedview") ) {
1016 return false;
1017 }
1019 // everyone else is okay, I guess. :)
1020 return true;
1021 }
1024 void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node,
1025 gint column, gpointer data)
1026 {
1027 gtk_widget_set_sensitive(GTK_WIDGET(data), xml_tree_node_mutable(node));
1028 }
1032 void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node,
1033 gint column, gpointer data)
1034 {
1035 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1036 }
1040 void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node,
1041 gint column, gpointer data)
1042 {
1043 gtk_widget_hide(GTK_WIDGET(data));
1044 }
1048 void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node,
1049 gint column, gpointer data)
1050 {
1051 if (GTK_IS_EDITABLE(data)) {
1052 gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1053 } else if (GTK_IS_TEXT_VIEW(data)) {
1054 GtkTextBuffer *tb;
1055 tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1056 gtk_text_buffer_set_text(tb, "", 0);
1057 }
1058 }
1061 void on_attr_select_row(GtkCList *list, gint row, gint column,
1062 GdkEventButton *event, gpointer data)
1063 {
1064 selected_attr = sp_xmlview_attr_list_get_row_key(list, row);
1065 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(attr_value));
1067 attr_reset_context(selected_attr);
1068 }
1071 void on_attr_unselect_row(GtkCList *list, gint row, gint column,
1072 GdkEventButton *event, gpointer data)
1073 {
1074 selected_attr = 0;
1075 attr_reset_context(selected_attr);
1076 }
1079 void on_attr_row_changed(GtkCList *list, gint row, gpointer data)
1080 {
1081 gint attr = sp_xmlview_attr_list_get_row_key(list, row);
1083 if (attr == selected_attr) {
1084 /* if the attr changed, reselect the row in the list to sync
1085 the edit box */
1087 /*
1088 // get current attr values
1089 const gchar * name = g_quark_to_string (sp_xmlview_attr_list_get_row_key (list, row));
1090 const gchar * value = selected_repr->attribute(name);
1092 g_warning("value: '%s'",value);
1094 // get the edit box value
1095 GtkTextIter start, end;
1096 gtk_text_buffer_get_bounds ( gtk_text_view_get_buffer (attr_value),
1097 &start, &end );
1098 gchar * text = gtk_text_buffer_get_text ( gtk_text_view_get_buffer (attr_value),
1099 &start, &end, TRUE );
1100 g_warning("text: '%s'",text);
1102 // compare to edit box
1103 if (strcmp(text,value)) {
1104 // issue warning if they're different
1105 _message_stack->flash(Inkscape::WARNING_MESSAGE,
1106 _("Attribute changed in GUI while editing values!"));
1107 }
1108 g_free (text);
1110 */
1111 gtk_clist_unselect_row( GTK_CLIST(list), row, 0 );
1112 gtk_clist_select_row( GTK_CLIST(list), row, 0 );
1113 }
1114 }
1117 void on_attr_select_row_set_name_content(GtkCList *list, gint row,
1118 gint column, GdkEventButton *event,
1119 gpointer data)
1120 {
1121 GtkEditable *editable = GTK_EDITABLE(data);
1122 const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1123 gtk_editable_delete_text(editable, 0, -1);
1124 gint pos = 0;
1125 gtk_editable_insert_text(editable, name, strlen(name), &pos);
1126 }
1130 void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column,
1131 GdkEventButton *event,
1132 gpointer data)
1133 {
1134 GtkTextBuffer *tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1135 const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1136 const gchar *value = selected_repr->attribute(name);
1137 if (!value) {
1138 value = "";
1139 }
1140 gtk_text_buffer_set_text(tb, value, strlen(value));
1141 }
1144 void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node,
1145 gint column, gpointer data)
1146 {
1147 gboolean indentable = FALSE;
1149 if (xml_tree_node_mutable(node)) {
1150 Inkscape::XML::Node *repr, *prev;
1151 repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1153 Inkscape::XML::Node *parent=repr->parent();
1154 if ( parent && repr != parent->firstChild() ) {
1155 g_assert(parent->firstChild());
1157 // skip to the child just before the current repr
1158 for ( prev = parent->firstChild() ;
1159 prev && prev->next() != repr ;
1160 prev = prev->next() );
1162 if (prev && prev->type() == Inkscape::XML::ELEMENT_NODE) {
1163 indentable = TRUE;
1164 }
1165 }
1166 }
1168 gtk_widget_set_sensitive(GTK_WIDGET(data), indentable);
1169 }
1173 void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree,
1174 GtkCTreeNode *node,
1175 gint column,
1176 gpointer data)
1177 {
1178 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1180 Inkscape::XML::Node *parent=repr->parent();
1181 if ( parent && repr != parent->firstChild() ) {
1182 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1183 } else {
1184 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1185 }
1186 }
1190 void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree,
1191 GtkCTreeNode *node,
1192 gint column, gpointer data)
1193 {
1194 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1196 Inkscape::XML::Node *parent=repr->parent();
1197 if ( parent && parent->parent() && repr->next() ) {
1198 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1199 } else {
1200 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1201 }
1202 }
1206 void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree,
1207 GtkCTreeNode *node,
1208 gint column, gpointer data)
1209 {
1210 GtkCTreeNode *parent = GTK_CTREE_ROW(node)->parent;
1212 if (parent) {
1213 GtkCTreeNode *grandparent = GTK_CTREE_ROW(parent)->parent;
1214 if (grandparent) {
1215 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1216 } else {
1217 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1218 }
1219 } else {
1220 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1221 }
1222 }
1226 void on_attr_select_row_enable(GtkCList *list, gint row, gint column,
1227 GdkEventButton *event, gpointer data)
1228 {
1229 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1230 }
1234 void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column,
1235 GdkEventButton *event, gpointer data)
1236 {
1237 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1238 }
1242 void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column,
1243 GdkEventButton *event, gpointer data)
1244 {
1245 if (GTK_IS_EDITABLE(data)) {
1246 gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1247 } else if (GTK_IS_TEXT_VIEW(data)) {
1248 GtkTextBuffer *tb;
1249 tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1250 gtk_text_buffer_set_text(tb, "", 0);
1251 }
1252 }
1256 void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable,
1257 gpointer data)
1258 {
1259 gchar *text = gtk_editable_get_chars(editable, 0, -1);
1261 /* TODO: need to do checking a little more rigorous than this */
1263 if (strlen(text)) {
1264 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1265 } else {
1266 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1267 }
1268 g_free(text);
1269 }
1273 void on_desktop_selection_changed(Inkscape::Selection *selection)
1274 {
1275 if (!blocked++) {
1276 set_tree_select(get_dt_select());
1277 }
1278 blocked--;
1279 }
1281 static void on_document_replaced(SPDesktop *dt, SPDocument *doc)
1282 {
1283 if (current_desktop)
1284 sel_changed_connection.disconnect();
1286 sel_changed_connection = sp_desktop_selection(dt)->connectChanged(&on_desktop_selection_changed);
1287 set_tree_document(doc);
1288 }
1290 void on_document_uri_set(gchar const *uri, SPDocument *document)
1291 {
1292 gchar title[500];
1293 sp_ui_dialog_title_string(Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), title);
1294 gchar *t = g_strdup_printf("%s: %s", SP_DOCUMENT_NAME(document), title);
1295 gtk_window_set_title(GTK_WINDOW(dlg), t);
1296 g_free(t);
1297 }
1301 void on_clicked_get_editable_text(GtkWidget *widget, gpointer data)
1302 {
1303 EditableDest *dest = (EditableDest *) data;
1304 dest->text = gtk_editable_get_chars(dest->editable, 0, -1);
1305 }
1309 void cmd_new_element_node(GtkObject *object, gpointer data)
1310 {
1311 EditableDest name;
1312 GtkWidget *window, *create, *cancel, *vbox, *entry, *bbox, *sep;
1314 g_assert(selected_repr != NULL);
1316 window = sp_window_new(NULL, TRUE);
1317 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
1318 gtk_window_set_title(GTK_WINDOW(window), _("New element node..."));
1319 gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE);
1320 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1321 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(dlg));
1322 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1323 gtk_signal_connect(GTK_OBJECT(window), "destroy", gtk_main_quit, NULL);
1325 vbox = gtk_vbox_new(FALSE, 4);
1326 gtk_container_add(GTK_CONTAINER(window), vbox);
1328 entry = gtk_entry_new();
1329 gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 0);
1331 sep = gtk_hseparator_new();
1332 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, TRUE, 0);
1334 bbox = gtk_hbutton_box_new();
1335 gtk_container_set_border_width(GTK_CONTAINER(bbox), 4);
1336 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1337 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
1339 cancel = gtk_button_new_with_label(_("Cancel"));
1340 gtk_signal_connect_object( GTK_OBJECT(cancel), "clicked",
1341 G_CALLBACK(gtk_widget_destroy),
1342 GTK_OBJECT(window) );
1343 gtk_container_add(GTK_CONTAINER(bbox), cancel);
1345 create = gtk_button_new_with_label(_("Create"));
1346 gtk_widget_set_sensitive(GTK_WIDGET(create), FALSE);
1347 gtk_signal_connect( GTK_OBJECT(entry), "changed",
1348 G_CALLBACK(on_editable_changed_enable_if_valid_xml_name),
1349 create );
1350 gtk_signal_connect( GTK_OBJECT(create), "clicked",
1351 G_CALLBACK(on_clicked_get_editable_text), &name );
1352 gtk_signal_connect_object( GTK_OBJECT(create), "clicked",
1353 G_CALLBACK(gtk_widget_destroy),
1354 GTK_OBJECT(window) );
1355 GTK_WIDGET_SET_FLAGS( GTK_WIDGET(create),
1356 GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT );
1357 gtk_container_add(GTK_CONTAINER(bbox), create);
1359 gtk_widget_show_all(GTK_WIDGET(window));
1360 gtk_window_set_default(GTK_WINDOW(window), GTK_WIDGET(create));
1361 gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(entry));
1363 name.editable = GTK_EDITABLE(entry);
1364 name.text = NULL;
1366 gtk_main();
1368 g_assert(selected_repr != NULL);
1370 if (name.text) {
1371 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(current_document);
1372 Inkscape::XML::Node *new_repr;
1373 new_repr = xml_doc->createElement(name.text);
1374 g_free(name.text);
1375 selected_repr->appendChild(new_repr);
1376 set_tree_select(new_repr);
1377 set_dt_select(new_repr);
1379 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1380 _("Create new element node"));
1381 }
1383 } // end of cmd_new_element_node()
1387 void cmd_new_text_node(GtkObject *object, gpointer data)
1388 {
1389 g_assert(selected_repr != NULL);
1391 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(current_document);
1392 Inkscape::XML::Node *text = xml_doc->createTextNode("");
1393 selected_repr->appendChild(text);
1395 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1396 _("Create new text node"));
1398 set_tree_select(text);
1399 set_dt_select(text);
1401 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(content));
1403 }
1405 void cmd_duplicate_node(GtkObject *object, gpointer data)
1406 {
1407 g_assert(selected_repr != NULL);
1409 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1410 Inkscape::XML::Node *dup = selected_repr->duplicate();
1411 parent->addChild(dup, selected_repr);
1413 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1414 _("Duplicate node"));
1416 GtkCTreeNode *node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), dup);
1418 if (node) {
1419 gtk_ctree_select(GTK_CTREE(tree), node);
1420 }
1421 }
1425 void cmd_delete_node(GtkObject *object, gpointer data)
1426 {
1427 g_assert(selected_repr != NULL);
1428 sp_repr_unparent(selected_repr);
1430 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1431 _("Delete node"));
1432 }
1436 void cmd_delete_attr(GtkObject *object, gpointer data)
1437 {
1438 g_assert(selected_repr != NULL);
1439 g_assert(selected_attr != 0);
1440 selected_repr->setAttribute(g_quark_to_string(selected_attr), NULL);
1442 SPObject *updated=current_document->getObjectByRepr(selected_repr);
1443 if (updated) {
1444 // force immediate update of dependant attributes
1445 updated->updateRepr();
1446 }
1448 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1449 _("Delete attribute"));
1450 }
1454 void cmd_set_attr(GtkObject *object, gpointer data)
1455 {
1456 g_assert(selected_repr != NULL);
1458 gchar *name = gtk_editable_get_chars(attr_name, 0, -1);
1459 GtkTextIter start;
1460 GtkTextIter end;
1461 gtk_text_buffer_get_bounds( gtk_text_view_get_buffer(attr_value),
1462 &start, &end );
1463 gchar *value = gtk_text_buffer_get_text( gtk_text_view_get_buffer(attr_value),
1464 &start, &end, TRUE );
1466 if (!sp_repr_set_attr(selected_repr, name, value)) {
1467 gchar *message = g_strdup_printf(_("Cannot set <b>%s</b>: Another element with value <b>%s</b> already exists!"), name, value);
1468 _message_stack->flash(Inkscape::WARNING_MESSAGE, message);
1469 g_free(message);
1470 }
1472 g_free(name);
1473 g_free(value);
1475 SPObject *updated = current_document->getObjectByRepr(selected_repr);
1476 if (updated) {
1477 // force immediate update of dependant attributes
1478 updated->updateRepr();
1479 }
1481 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1482 _("Change attribute"));
1484 /* TODO: actually, the row won't have been created yet. why? */
1485 gint row = sp_xmlview_attr_list_find_row_from_key(GTK_CLIST(attributes),
1486 g_quark_from_string(name));
1487 if (row != -1) {
1488 gtk_clist_select_row(GTK_CLIST(attributes), row, 0);
1489 }
1490 }
1494 void cmd_raise_node(GtkObject *object, gpointer data)
1495 {
1496 g_assert(selected_repr != NULL);
1498 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1499 g_return_if_fail(parent != NULL);
1500 g_return_if_fail(parent->firstChild() != selected_repr);
1502 Inkscape::XML::Node *ref = NULL;
1503 Inkscape::XML::Node *before = parent->firstChild();
1504 while (before && before->next() != selected_repr) {
1505 ref = before;
1506 before = before->next();
1507 }
1509 parent->changeOrder(selected_repr, ref);
1511 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1512 _("Raise node"));
1514 set_tree_select(selected_repr);
1515 set_dt_select(selected_repr);
1516 }
1520 void cmd_lower_node(GtkObject *object, gpointer data)
1521 {
1522 g_assert(selected_repr != NULL);
1523 g_return_if_fail(selected_repr->next() != NULL);
1524 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1526 parent->changeOrder(selected_repr, selected_repr->next());
1528 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1529 _("Lower node"));
1531 set_tree_select(selected_repr);
1532 set_dt_select(selected_repr);
1533 }
1535 void cmd_indent_node(GtkObject *object, gpointer data)
1536 {
1537 Inkscape::XML::Node *repr = selected_repr;
1538 g_assert(repr != NULL);
1539 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1540 g_return_if_fail(parent != NULL);
1541 g_return_if_fail(parent->firstChild() != repr);
1543 Inkscape::XML::Node* prev = parent->firstChild();
1544 while (prev && prev->next() != repr) {
1545 prev = prev->next();
1546 }
1547 g_return_if_fail(prev != NULL);
1548 g_return_if_fail(prev->type() == Inkscape::XML::ELEMENT_NODE);
1550 Inkscape::XML::Node* ref = NULL;
1551 if (prev->firstChild()) {
1552 for( ref = prev->firstChild() ; ref->next() ; ref = ref->next() );
1553 }
1555 parent->removeChild(repr);
1556 prev->addChild(repr, ref);
1558 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1559 _("Indent node"));
1560 set_tree_select(repr);
1561 set_dt_select(repr);
1563 } // end of cmd_indent_node()
1567 void cmd_unindent_node(GtkObject *object, gpointer data)
1568 {
1569 Inkscape::XML::Node *repr = selected_repr;
1570 g_assert(repr != NULL);
1571 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1572 g_return_if_fail(parent);
1573 Inkscape::XML::Node *grandparent = sp_repr_parent(parent);
1574 g_return_if_fail(grandparent);
1576 parent->removeChild(repr);
1577 grandparent->addChild(repr, parent);
1579 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1580 _("Unindent node"));
1581 set_tree_select(repr);
1582 set_dt_select(repr);
1584 } // end of cmd_unindent_node()
1587 /*
1588 Local Variables:
1589 mode:c++
1590 c-file-style:"stroustrup"
1591 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1592 indent-tabs-mode:nil
1593 fill-column:99
1594 End:
1595 */
1596 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :