b843819894f4b5cb578b514dce1cbe3c2fc2afc0
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()
169 {
170 _message_context->set(Inkscape::NORMAL_MESSAGE,
171 _("<b>Click</b> to select nodes, <b>drag</b> to rearrange."));
172 }
175 /*
176 * \brief Sets the XML status bar, depending on which attr is selected.
177 */
178 void attr_reset_context(gint attr)
179 {
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 }
190 }
193 void sp_xml_tree_dialog()
194 {
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 }
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)
629 {
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;
646 }
649 static void sp_xmltree_desktop_change(Inkscape::Application *inkscape,
650 SPDesktop *desktop,
651 GtkWidget *dialog )
652 {
653 if (!desktop) {
654 return;
655 }
656 set_tree_desktop(desktop);
657 }
660 void set_tree_desktop(SPDesktop *desktop)
661 {
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)
684 {
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 }
702 }
706 void set_tree_repr(Inkscape::XML::Node *repr)
707 {
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);
726 }
730 void set_tree_select(Inkscape::XML::Node *repr)
731 {
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);
760 }
764 void propagate_tree_select(Inkscape::XML::Node *repr)
765 {
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 }
777 }
780 Inkscape::XML::Node *get_dt_select()
781 {
782 if (!current_desktop) {
783 return NULL;
784 }
786 return sp_desktop_selection(current_desktop)->singleRepr();
787 }
791 void set_dt_select(Inkscape::XML::Node *repr)
792 {
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)
830 {
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();
854 }
856 void on_tree_unselect_row(GtkCTree *tree,
857 GtkCTreeNode *node,
858 gint column,
859 gpointer data)
860 {
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 }
874 }
878 void after_tree_move(GtkCTree *tree,
879 GtkCTreeNode *node,
880 GtkCTreeNode *new_parent,
881 GtkCTreeNode *new_sibling,
882 gpointer data)
883 {
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 _("Drag XML subtree"));
889 } else {
890 sp_document_cancel(current_document);
891 }
892 }
895 static void on_destroy(GtkObject *object, gpointer data)
896 {
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;
912 }
916 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data)
917 {
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
930 }
933 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog)
934 {
935 if (status) {
936 gtk_label_set_markup(GTK_LABEL(status), message ? message : "");
937 }
938 }
941 void on_tree_select_row_enable(GtkCTree *tree,
942 GtkCTreeNode *node,
943 gint column,
944 gpointer data)
945 {
946 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
947 }
951 void on_tree_select_row_enable_if_element(GtkCTree *tree,
952 GtkCTreeNode *node,
953 gint column,
954 gpointer data )
955 {
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 }
963 }
967 void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node,
968 gint column, gpointer data)
969 {
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 }
977 }
981 void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node,
982 gint column, gpointer data)
983 {
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 }
991 }
994 gboolean xml_tree_node_mutable(GtkCTreeNode *node)
995 {
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;
1018 }
1021 void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node,
1022 gint column, gpointer data)
1023 {
1024 gtk_widget_set_sensitive(GTK_WIDGET(data), xml_tree_node_mutable(node));
1025 }
1029 void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node,
1030 gint column, gpointer data)
1031 {
1032 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1033 }
1037 void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node,
1038 gint column, gpointer data)
1039 {
1040 gtk_widget_hide(GTK_WIDGET(data));
1041 }
1045 void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node,
1046 gint column, gpointer data)
1047 {
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 }
1055 }
1058 void on_attr_select_row(GtkCList *list, gint row, gint column,
1059 GdkEventButton *event, gpointer data)
1060 {
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);
1065 }
1068 void on_attr_unselect_row(GtkCList *list, gint row, gint column,
1069 GdkEventButton *event, gpointer data)
1070 {
1071 selected_attr = 0;
1072 attr_reset_context(selected_attr);
1073 }
1076 void on_attr_row_changed(GtkCList *list, gint row, gpointer data)
1077 {
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 }
1111 }
1114 void on_attr_select_row_set_name_content(GtkCList *list, gint row,
1115 gint column, GdkEventButton *event,
1116 gpointer data)
1117 {
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);
1123 }
1127 void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column,
1128 GdkEventButton *event,
1129 gpointer data)
1130 {
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));
1138 }
1141 void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node,
1142 gint column, gpointer data)
1143 {
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);
1166 }
1170 void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree,
1171 GtkCTreeNode *node,
1172 gint column,
1173 gpointer data)
1174 {
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 }
1183 }
1187 void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree,
1188 GtkCTreeNode *node,
1189 gint column, gpointer data)
1190 {
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 }
1199 }
1203 void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree,
1204 GtkCTreeNode *node,
1205 gint column, gpointer data)
1206 {
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 }
1219 }
1223 void on_attr_select_row_enable(GtkCList *list, gint row, gint column,
1224 GdkEventButton *event, gpointer data)
1225 {
1226 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1227 }
1231 void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column,
1232 GdkEventButton *event, gpointer data)
1233 {
1234 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1235 }
1239 void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column,
1240 GdkEventButton *event, gpointer data)
1241 {
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 }
1249 }
1253 void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable,
1254 gpointer data)
1255 {
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);
1266 }
1270 void on_desktop_selection_changed(Inkscape::Selection *selection)
1271 {
1272 if (!blocked++) {
1273 set_tree_select(get_dt_select());
1274 }
1275 blocked--;
1276 }
1278 static void on_document_replaced(SPDesktop *dt, SPDocument *doc)
1279 {
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);
1285 }
1287 void on_document_uri_set(gchar const *uri, SPDocument *document)
1288 {
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);
1294 }
1298 void on_clicked_get_editable_text(GtkWidget *widget, gpointer data)
1299 {
1300 EditableDest *dest = (EditableDest *) data;
1301 dest->text = gtk_editable_get_chars(dest->editable, 0, -1);
1302 }
1306 void cmd_new_element_node(GtkObject *object, gpointer data)
1307 {
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);
1375 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1376 _("Create new element node"));
1377 }
1379 } // end of cmd_new_element_node()
1383 void cmd_new_text_node(GtkObject *object, gpointer data)
1384 {
1385 g_assert(selected_repr != NULL);
1387 Inkscape::XML::Node *text = sp_repr_new_text("");
1388 selected_repr->appendChild(text);
1390 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1391 _("Create new text node"));
1393 set_tree_select(text);
1394 set_dt_select(text);
1396 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(content));
1398 }
1400 void cmd_duplicate_node(GtkObject *object, gpointer data)
1401 {
1402 g_assert(selected_repr != NULL);
1404 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1405 Inkscape::XML::Node *dup = selected_repr->duplicate();
1406 parent->addChild(dup, selected_repr);
1408 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1409 _("Duplicate node"));
1411 GtkCTreeNode *node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), dup);
1413 if (node) {
1414 gtk_ctree_select(GTK_CTREE(tree), node);
1415 }
1416 }
1420 void cmd_delete_node(GtkObject *object, gpointer data)
1421 {
1422 g_assert(selected_repr != NULL);
1423 sp_repr_unparent(selected_repr);
1425 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1426 _("Delete node"));
1427 }
1431 void cmd_delete_attr(GtkObject *object, gpointer data)
1432 {
1433 g_assert(selected_repr != NULL);
1434 g_assert(selected_attr != 0);
1435 selected_repr->setAttribute(g_quark_to_string(selected_attr), NULL);
1437 SPObject *updated=current_document->getObjectByRepr(selected_repr);
1438 if (updated) {
1439 // force immediate update of dependant attributes
1440 updated->updateRepr();
1441 }
1443 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1444 _("Delete attribute"));
1445 }
1449 void cmd_set_attr(GtkObject *object, gpointer data)
1450 {
1451 g_assert(selected_repr != NULL);
1453 gchar *name = gtk_editable_get_chars(attr_name, 0, -1);
1454 GtkTextIter start;
1455 GtkTextIter end;
1456 gtk_text_buffer_get_bounds( gtk_text_view_get_buffer(attr_value),
1457 &start, &end );
1458 gchar *value = gtk_text_buffer_get_text( gtk_text_view_get_buffer(attr_value),
1459 &start, &end, TRUE );
1461 if (!sp_repr_set_attr(selected_repr, name, value)) {
1462 gchar *message = g_strdup_printf(_("Cannot set <b>%s</b>: Another element with value <b>%s</b> already exists!"), name, value);
1463 _message_stack->flash(Inkscape::WARNING_MESSAGE, message);
1464 g_free(message);
1465 }
1467 g_free(name);
1468 g_free(value);
1470 SPObject *updated = current_document->getObjectByRepr(selected_repr);
1471 if (updated) {
1472 // force immediate update of dependant attributes
1473 updated->updateRepr();
1474 }
1476 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1477 _("Change attribute"));
1479 /* TODO: actually, the row won't have been created yet. why? */
1480 gint row = sp_xmlview_attr_list_find_row_from_key(GTK_CLIST(attributes),
1481 g_quark_from_string(name));
1482 if (row != -1) {
1483 gtk_clist_select_row(GTK_CLIST(attributes), row, 0);
1484 }
1485 }
1489 void cmd_raise_node(GtkObject *object, gpointer data)
1490 {
1491 g_assert(selected_repr != NULL);
1493 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1494 g_return_if_fail(parent != NULL);
1495 g_return_if_fail(parent->firstChild() != selected_repr);
1497 Inkscape::XML::Node *ref = NULL;
1498 Inkscape::XML::Node *before = parent->firstChild();
1499 while (before && before->next() != selected_repr) {
1500 ref = before;
1501 before = before->next();
1502 }
1504 parent->changeOrder(selected_repr, ref);
1506 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1507 _("Raise node"));
1509 set_tree_select(selected_repr);
1510 set_dt_select(selected_repr);
1511 }
1515 void cmd_lower_node(GtkObject *object, gpointer data)
1516 {
1517 g_assert(selected_repr != NULL);
1518 g_return_if_fail(selected_repr->next() != NULL);
1519 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1521 parent->changeOrder(selected_repr, selected_repr->next());
1523 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1524 _("Lower node"));
1526 set_tree_select(selected_repr);
1527 set_dt_select(selected_repr);
1528 }
1530 void cmd_indent_node(GtkObject *object, gpointer data)
1531 {
1532 Inkscape::XML::Node *repr = selected_repr;
1533 g_assert(repr != NULL);
1534 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1535 g_return_if_fail(parent != NULL);
1536 g_return_if_fail(parent->firstChild() != repr);
1538 Inkscape::XML::Node* prev = parent->firstChild();
1539 while (prev && prev->next() != repr) {
1540 prev = prev->next();
1541 }
1542 g_return_if_fail(prev != NULL);
1543 g_return_if_fail(prev->type() == Inkscape::XML::ELEMENT_NODE);
1545 Inkscape::XML::Node* ref = NULL;
1546 if (prev->firstChild()) {
1547 for( ref = prev->firstChild() ; ref->next() ; ref = ref->next() );
1548 }
1550 parent->removeChild(repr);
1551 prev->addChild(repr, ref);
1553 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1554 _("Indent node"));
1555 set_tree_select(repr);
1556 set_dt_select(repr);
1558 } // end of cmd_indent_node()
1562 void cmd_unindent_node(GtkObject *object, gpointer data)
1563 {
1564 Inkscape::XML::Node *repr = selected_repr;
1565 g_assert(repr != NULL);
1566 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1567 g_return_if_fail(parent);
1568 Inkscape::XML::Node *grandparent = sp_repr_parent(parent);
1569 g_return_if_fail(grandparent);
1571 parent->removeChild(repr);
1572 grandparent->addChild(repr, parent);
1574 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1575 _("Unindent node"));
1576 set_tree_select(repr);
1577 set_dt_select(repr);
1579 } // end of cmd_unindent_node()
1582 /*
1583 Local Variables:
1584 mode:c++
1585 c-file-style:"stroustrup"
1586 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1587 indent-tabs-mode:nil
1588 fill-column:99
1589 End:
1590 */
1591 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :