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 "../preferences.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 Glib::ustring const 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_activate( Inkscape::Application *inkscape, SPDesktop *desktop, GtkWidget *dialog );
101 static void sp_xmltree_desktop_deactivate( Inkscape::Application *inkscape, SPDesktop *desktop, GtkWidget *dialog );
103 static void set_tree_desktop(SPDesktop *desktop);
104 static void set_tree_document(SPDocument *document);
105 static void set_tree_repr(Inkscape::XML::Node *repr);
107 static void set_tree_select(Inkscape::XML::Node *repr);
108 static void propagate_tree_select(Inkscape::XML::Node *repr);
110 static Inkscape::XML::Node *get_dt_select();
111 static void set_dt_select(Inkscape::XML::Node *repr);
113 static void on_tree_select_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
114 static void on_tree_unselect_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
115 static void after_tree_move(GtkCTree *tree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling, gpointer data);
116 static void on_destroy(GtkObject *object, gpointer data);
117 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data);
119 static void on_tree_select_row_enable_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
120 static void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
121 static void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
122 static void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
123 static void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
124 static void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
125 static void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
126 static void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
128 static void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
129 static void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
130 static void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
132 static void on_attr_select_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
133 static void on_attr_unselect_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
134 static void on_attr_row_changed( GtkCList *list, gint row, gpointer data );
136 static void on_attr_select_row_enable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
137 static void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
139 static void on_attr_select_row_set_name_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
140 static void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
141 static void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
143 static void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable, gpointer data);
145 static void on_desktop_selection_changed(Inkscape::Selection *selection);
146 static void on_document_replaced(SPDesktop *dt, SPDocument *document);
147 static void on_document_uri_set(gchar const *uri, SPDocument *document);
149 static void on_clicked_get_editable_text(GtkWidget *widget, gpointer data);
151 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog);
153 static void cmd_new_element_node(GtkObject *object, gpointer data);
154 static void cmd_new_text_node(GtkObject *object, gpointer data);
155 static void cmd_duplicate_node(GtkObject *object, gpointer data);
156 static void cmd_delete_node(GtkObject *object, gpointer data);
158 static void cmd_raise_node(GtkObject *object, gpointer data);
159 static void cmd_lower_node(GtkObject *object, gpointer data);
160 static void cmd_indent_node(GtkObject *object, gpointer data);
161 static void cmd_unindent_node(GtkObject *object, gpointer data);
163 static void cmd_delete_attr(GtkObject *object, gpointer data);
164 static void cmd_set_attr(GtkObject *object, gpointer data);
166 static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event);
169 /*
170 * \brief Sets the XML status bar when the tree is selected.
171 */
172 void tree_reset_context()
173 {
174 _message_context->set(Inkscape::NORMAL_MESSAGE,
175 _("<b>Click</b> to select nodes, <b>drag</b> to rearrange."));
176 }
179 /*
180 * \brief Sets the XML status bar, depending on which attr is selected.
181 */
182 void attr_reset_context(gint attr)
183 {
184 if (attr == 0) {
185 _message_context->set(Inkscape::NORMAL_MESSAGE,
186 _("<b>Click</b> attribute to edit."));
187 }
188 else {
189 const gchar *name = g_quark_to_string(attr);
190 gchar *message = g_strdup_printf(_("Attribute <b>%s</b> selected. Press <b>Ctrl+Enter</b> when done editing to commit changes."), name);
191 _message_context->set(Inkscape::NORMAL_MESSAGE, message);
192 g_free(message);
193 }
194 }
197 void sp_xml_tree_dialog()
198 {
199 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
201 if (!desktop) {
202 return;
203 }
205 if (dlg == NULL)
206 { // very long block
208 GtkWidget *box, *sw, *paned, *toolbar, *button;
209 GtkWidget *text_container, *attr_container, *attr_subpaned_container, *box2;
210 GtkWidget *set_attr;
212 tooltips = gtk_tooltips_new();
213 gtk_tooltips_enable(tooltips);
215 dlg = sp_window_new("", TRUE);
216 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
217 if (x == -1000 || y == -1000) {
218 x = prefs->getInt(prefs_path + "x", -1000);
219 y = prefs->getInt(prefs_path + "y", -1000);
220 }
221 if (w ==0 || h == 0) {
222 w = prefs->getInt(prefs_path + "w", 0);
223 h = prefs->getInt(prefs_path + "h", 0);
224 }
226 // if (x<0) x=0;
227 // if (y<0) y=0;
229 if (w && h) {
230 gtk_window_resize((GtkWindow *) dlg, w, h);
231 }
232 if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE))) {
233 gtk_window_move((GtkWindow *) dlg, x, y);
234 } else {
235 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
236 }
238 sp_transientize(dlg);
239 wd.win = dlg;
240 wd.stop = 0;
241 g_signal_connect ( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd );
243 gtk_signal_connect( GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg );
245 gtk_signal_connect( GTK_OBJECT(dlg), "destroy", G_CALLBACK(on_destroy), dlg);
246 gtk_signal_connect( GTK_OBJECT(dlg), "delete_event", G_CALLBACK(on_delete), dlg);
247 g_signal_connect ( G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(on_delete), dlg);
249 g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg);
250 g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg);
253 gtk_container_set_border_width(GTK_CONTAINER(dlg), 0);
254 gtk_window_set_default_size(GTK_WINDOW(dlg), 640, 384);
256 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
257 gtk_container_add(GTK_CONTAINER(dlg), vbox);
259 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
260 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
262 status = gtk_label_new(NULL);
263 gtk_misc_set_alignment(GTK_MISC(status), 0.0, 0.5);
264 gtk_widget_set_size_request(status, 1, -1);
265 gtk_label_set_markup(GTK_LABEL(status), "");
266 gtk_box_pack_start(GTK_BOX(hbox), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 4);
267 gtk_box_pack_start(GTK_BOX(hbox), status, TRUE, TRUE, 0);
269 paned = gtk_hpaned_new();
270 gtk_paned_set_position(GTK_PANED(paned), 256);
271 gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 0);
273 _message_stack = new Inkscape::MessageStack();
274 _message_context = new Inkscape::MessageContext(_message_stack);
275 _message_changed_connection = _message_stack->connectChanged(
276 sigc::bind(sigc::ptr_fun(_set_status_message), dlg)
277 );
279 /* tree view */
281 box = gtk_vbox_new(FALSE, 0);
282 gtk_paned_pack1(GTK_PANED(paned), box, FALSE, FALSE);
284 tree = SP_XMLVIEW_TREE(sp_xmlview_tree_new(NULL, NULL, NULL));
285 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(tree),
286 _("Drag to reorder nodes"), NULL );
288 g_signal_connect( G_OBJECT(tree), "tree_select_row",
289 G_CALLBACK(on_tree_select_row), NULL );
291 g_signal_connect( G_OBJECT(tree), "tree_unselect_row",
292 G_CALLBACK(on_tree_unselect_row), NULL );
294 g_signal_connect_after( G_OBJECT(tree), "tree_move",
295 G_CALLBACK(after_tree_move), NULL);
297 /* TODO: replace gtk_signal_connect_while_alive() with something
298 * else...
299 */
300 toolbar = gtk_toolbar_new();
301 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
302 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
304 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
305 NULL,
306 _("New element node"),
307 NULL,
308 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
309 INKSCAPE_STOCK_ADD_XML_ELEMENT_NODE ),
310 G_CALLBACK(cmd_new_element_node),
311 NULL);
313 gtk_signal_connect_while_alive( GTK_OBJECT(tree),
314 "tree_select_row",
315 G_CALLBACK(on_tree_select_row_enable_if_element),
316 button,
317 GTK_OBJECT(button));
319 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
320 "tree_unselect_row",
321 G_CALLBACK(on_tree_unselect_row_disable),
322 button,
323 GTK_OBJECT(button));
325 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
327 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
328 NULL, _("New text node"), NULL,
329 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
330 INKSCAPE_STOCK_ADD_XML_TEXT_NODE ),
331 G_CALLBACK(cmd_new_text_node),
332 NULL);
334 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
335 "tree_select_row",
336 G_CALLBACK(on_tree_select_row_enable_if_element),
337 button,
338 GTK_OBJECT(button));
340 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
341 "tree_unselect_row",
342 G_CALLBACK(on_tree_unselect_row_disable),
343 button,
344 GTK_OBJECT(button));
346 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
348 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
349 NULL, _("Duplicate node"), NULL,
350 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
351 INKSCAPE_STOCK_DUPLICATE_XML_NODE ),
352 G_CALLBACK(cmd_duplicate_node),
353 NULL);
355 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
356 "tree_select_row",
357 G_CALLBACK(on_tree_select_row_enable_if_mutable),
358 button,
359 GTK_OBJECT(button));
361 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
362 G_CALLBACK(on_tree_unselect_row_disable),
363 button, GTK_OBJECT(button));
365 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
367 gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
369 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
370 NULL, _("Delete node"), NULL,
371 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
372 INKSCAPE_STOCK_DELETE_XML_NODE ),
373 G_CALLBACK(cmd_delete_node), NULL );
375 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
376 G_CALLBACK(on_tree_select_row_enable_if_mutable),
377 button, GTK_OBJECT(button));
378 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
379 G_CALLBACK(on_tree_unselect_row_disable),
380 button, GTK_OBJECT(button));
381 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
383 gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
385 button = gtk_toolbar_append_item( GTK_TOOLBAR(toolbar), "<",
386 _("Unindent node"), NULL,
387 gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_IN),
388 G_CALLBACK(cmd_unindent_node), NULL);
390 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
391 G_CALLBACK(on_tree_select_row_enable_if_has_grandparent),
392 button, GTK_OBJECT(button));
394 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
395 G_CALLBACK(on_tree_unselect_row_disable),
396 button, GTK_OBJECT(button));
398 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
400 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), ">",
401 _("Indent node"), NULL,
402 gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_IN),
403 G_CALLBACK(cmd_indent_node), NULL);
404 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
405 G_CALLBACK(on_tree_select_row_enable_if_indentable),
406 button, GTK_OBJECT(button));
407 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
408 (GCallback) on_tree_unselect_row_disable,
409 button, GTK_OBJECT(button));
410 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
412 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "^",
413 _("Raise node"), NULL,
414 gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_IN),
415 G_CALLBACK(cmd_raise_node), NULL);
416 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
417 G_CALLBACK(on_tree_select_row_enable_if_not_first_child),
418 button, GTK_OBJECT(button));
419 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
420 G_CALLBACK(on_tree_unselect_row_disable),
421 button, GTK_OBJECT(button));
422 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
424 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "v",
425 _("Lower node"), NULL,
426 gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_IN),
427 G_CALLBACK(cmd_lower_node), NULL);
428 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
429 G_CALLBACK(on_tree_select_row_enable_if_not_last_child),
430 button, GTK_OBJECT(button));
431 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
432 G_CALLBACK(on_tree_unselect_row_disable),
433 button, GTK_OBJECT(button));
434 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
436 gtk_box_pack_start(GTK_BOX(box), toolbar, FALSE, TRUE, 0);
438 sw = gtk_scrolled_window_new(NULL, NULL);
439 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
440 GTK_POLICY_AUTOMATIC,
441 GTK_POLICY_AUTOMATIC );
442 gtk_box_pack_start(GTK_BOX(box), sw, TRUE, TRUE, 0);
444 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(tree));
446 /* node view */
448 box = gtk_vbox_new(FALSE, 0);
449 gtk_paned_pack2(GTK_PANED(paned), box, TRUE, TRUE);
451 /* attributes */
453 attr_container = gtk_vbox_new(FALSE, 0);
454 gtk_box_pack_start( GTK_BOX(box), GTK_WIDGET(attr_container),
455 TRUE, TRUE, 0 );
457 attributes = SP_XMLVIEW_ATTR_LIST(sp_xmlview_attr_list_new(NULL));
458 g_signal_connect( G_OBJECT(attributes), "select_row",
459 G_CALLBACK(on_attr_select_row), NULL);
460 g_signal_connect( G_OBJECT(attributes), "unselect_row",
461 G_CALLBACK(on_attr_unselect_row), NULL);
462 g_signal_connect( G_OBJECT(attributes), "row-value-changed",
463 G_CALLBACK(on_attr_row_changed), NULL);
465 toolbar = gtk_toolbar_new();
466 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
467 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
469 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
470 NULL, _("Delete attribute"), NULL,
471 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
472 INKSCAPE_STOCK_DELETE_XML_ATTRIBUTE ),
473 (GCallback) cmd_delete_attr, NULL);
475 gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "select_row",
476 (GCallback) on_attr_select_row_enable, button,
477 GTK_OBJECT(button));
479 gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "unselect_row",
480 (GCallback) on_attr_unselect_row_disable, button,
481 GTK_OBJECT(button));
483 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
484 (GCallback) on_tree_unselect_row_disable, button,
485 GTK_OBJECT(button));
487 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
489 gtk_box_pack_start( GTK_BOX(attr_container),
490 GTK_WIDGET(toolbar), FALSE, TRUE, 0 );
492 attr_subpaned_container = gtk_vpaned_new();
493 gtk_box_pack_start( GTK_BOX(attr_container),
494 GTK_WIDGET(attr_subpaned_container),
495 TRUE, TRUE, 0 );
496 gtk_widget_show(attr_subpaned_container);
498 sw = gtk_scrolled_window_new(NULL, NULL);
499 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
500 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
501 gtk_paned_pack1( GTK_PANED(attr_subpaned_container),
502 GTK_WIDGET(sw), TRUE, TRUE );
503 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(attributes));
505 toolbar = gtk_vbox_new(FALSE, 4);
506 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 4);
508 box2 = gtk_hbox_new(FALSE, 4);
509 gtk_box_pack_start( GTK_BOX(toolbar), GTK_WIDGET(box2),
510 FALSE, TRUE, 0);
512 attr_name = GTK_EDITABLE(gtk_entry_new());
513 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_name),
514 // TRANSLATORS: "Attribute" is a noun here
515 _("Attribute name"), NULL );
517 gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
518 (GCallback) on_attr_select_row_set_name_content,
519 attr_name);
521 gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
522 (GCallback) on_attr_unselect_row_clear_text,
523 attr_name);
525 gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
526 (GCallback) on_tree_unselect_row_clear_text,
527 attr_name);
529 gtk_box_pack_start( GTK_BOX(box2), GTK_WIDGET(attr_name),
530 TRUE, TRUE, 0);
532 set_attr = gtk_button_new();
533 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(set_attr),
534 // TRANSLATORS: "Set" is a verb here
535 _("Set attribute"), NULL );
536 // TRANSLATORS: "Set" is a verb here
537 GtkWidget *set_label = gtk_label_new(_("Set"));
538 gtk_container_add(GTK_CONTAINER(set_attr), set_label);
540 gtk_signal_connect( GTK_OBJECT(set_attr), "clicked",
541 (GCallback) cmd_set_attr, NULL);
542 gtk_signal_connect( GTK_OBJECT(attr_name), "changed",
543 (GCallback) on_editable_changed_enable_if_valid_xml_name,
544 set_attr );
545 gtk_widget_set_sensitive(GTK_WIDGET(set_attr), FALSE);
547 gtk_box_pack_start(GTK_BOX(box2), set_attr, FALSE, FALSE, 0);
549 sw = gtk_scrolled_window_new(NULL, NULL);
550 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
551 GTK_POLICY_AUTOMATIC,
552 GTK_POLICY_AUTOMATIC );
553 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
554 gtk_box_pack_start(GTK_BOX(toolbar), sw, TRUE, TRUE, 0);
556 attr_value =(GtkTextView *) gtk_text_view_new();
557 gtk_text_view_set_wrap_mode((GtkTextView *) attr_value, GTK_WRAP_CHAR);
558 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_value),
559 // TRANSLATORS: "Attribute" is a noun here
560 _("Attribute value"), NULL );
561 gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
562 (GCallback) on_attr_select_row_set_value_content,
563 attr_value );
564 gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
565 (GCallback) on_attr_unselect_row_clear_text,
566 attr_value );
567 gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
568 (GCallback) on_tree_unselect_row_clear_text,
569 attr_value );
570 gtk_text_view_set_editable(attr_value, TRUE);
571 gtk_container_add( GTK_CONTAINER(sw),
572 GTK_WIDGET(attr_value) );
574 gtk_paned_pack2( GTK_PANED(attr_subpaned_container),
575 GTK_WIDGET(toolbar), FALSE, TRUE );
577 /* text */
579 sw = gtk_scrolled_window_new(NULL, NULL);
580 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
581 GTK_POLICY_AUTOMATIC,
582 GTK_POLICY_AUTOMATIC );
583 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
584 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(sw), TRUE, TRUE, 0);
586 content = SP_XMLVIEW_CONTENT(sp_xmlview_content_new(NULL));
587 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(content));
589 text_container = sw;
591 /* initial show/hide */
593 gtk_widget_show_all(GTK_WIDGET(dlg));
595 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
596 (GCallback) on_tree_select_row_show_if_element,
597 attr_container, GTK_OBJECT(attr_container));
599 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
600 (GCallback) on_tree_unselect_row_hide,
601 attr_container, GTK_OBJECT(attr_container));
603 gtk_widget_hide(attr_container);
605 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
606 (GCallback) on_tree_select_row_show_if_text,
607 text_container, GTK_OBJECT(text_container));
609 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
610 (GCallback) on_tree_unselect_row_hide,
611 text_container, GTK_OBJECT(text_container));
613 gtk_widget_hide(text_container);
615 g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop",
616 G_CALLBACK(sp_xmltree_desktop_activate), dlg);
618 g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop",
619 G_CALLBACK(sp_xmltree_desktop_deactivate), dlg);
621 g_signal_connect((GObject *) dlg, "key_press_event", (GCallback) sp_xml_tree_key_press, NULL);
623 tree_reset_context();
624 } // end of if (dlg == NULL)
626 gtk_window_present((GtkWindow *) dlg);
628 g_assert(desktop != NULL);
629 set_tree_desktop(desktop);
631 } // end of sp_xml_tree_dialog()
633 static gboolean sp_xml_tree_key_press(GtkWidget */*widget*/, GdkEventKey *event)
634 {
636 unsigned int shortcut = get_group0_keyval(event) |
637 ( event->state & GDK_SHIFT_MASK ?
638 SP_SHORTCUT_SHIFT_MASK : 0 ) |
639 ( event->state & GDK_CONTROL_MASK ?
640 SP_SHORTCUT_CONTROL_MASK : 0 ) |
641 ( event->state & GDK_MOD1_MASK ?
642 SP_SHORTCUT_ALT_MASK : 0 );
644 /* fixme: if you need to add more xml-tree-specific callbacks, you should probably upgrade
645 * the sp_shortcut mechanism to take into account windows. */
646 if (shortcut == (SP_SHORTCUT_CONTROL_MASK | GDK_Return)) {
647 cmd_set_attr(NULL, NULL);
648 return true;
649 }
650 return false;
651 }
654 static void sp_xmltree_desktop_activate(Inkscape::Application */*inkscape*/,
655 SPDesktop *desktop,
656 GtkWidget */*dialog*/ )
657 {
658 set_tree_desktop(desktop);
659 }
661 static void sp_xmltree_desktop_deactivate(Inkscape::Application */*inkscape*/,
662 SPDesktop *desktop,
663 GtkWidget */*dialog*/ )
664 {
665 set_tree_desktop(NULL);
666 }
669 void set_tree_desktop(SPDesktop *desktop)
670 {
671 if ( desktop == current_desktop ) {
672 return;
673 }
675 if (current_desktop) {
676 sel_changed_connection.disconnect();
677 document_replaced_connection.disconnect();
678 }
679 current_desktop = desktop;
680 if (desktop) {
681 sel_changed_connection = sp_desktop_selection(desktop)->connectChanged(&on_desktop_selection_changed);
682 document_replaced_connection = desktop->connectDocumentReplaced(&on_document_replaced);
683 set_tree_document(sp_desktop_document(desktop));
684 } else {
685 set_tree_document(NULL);
686 }
688 } // end of set_tree_desktop()
692 void set_tree_document(SPDocument *document)
693 {
694 if (document == current_document) {
695 return;
696 }
698 if (current_document) {
699 document_uri_set_connection.disconnect();
700 }
701 current_document = document;
702 if (current_document) {
704 document_uri_set_connection = current_document->connectURISet(sigc::bind(sigc::ptr_fun(&on_document_uri_set), current_document));
705 on_document_uri_set(SP_DOCUMENT_URI(current_document), current_document);
706 set_tree_repr(sp_document_repr_root(current_document));
708 } else {
709 set_tree_repr(NULL);
710 }
711 }
715 void set_tree_repr(Inkscape::XML::Node *repr)
716 {
717 if (repr == selected_repr) {
718 return;
719 }
721 gtk_clist_freeze(GTK_CLIST(tree));
723 sp_xmlview_tree_set_repr(tree, repr);
725 if (repr) {
726 set_tree_select(get_dt_select());
727 } else {
728 set_tree_select(NULL);
729 }
731 gtk_clist_thaw(GTK_CLIST(tree));
733 propagate_tree_select(selected_repr);
735 }
739 void set_tree_select(Inkscape::XML::Node *repr)
740 {
741 if (selected_repr) {
742 Inkscape::GC::release(selected_repr);
743 }
745 selected_repr = repr;
746 if (repr) {
747 GtkCTreeNode *node;
749 Inkscape::GC::anchor(selected_repr);
751 node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), repr);
752 if (node) {
753 GtkCTreeNode *parent;
755 gtk_ctree_select(GTK_CTREE(tree), node);
757 parent = GTK_CTREE_ROW(node)->parent;
758 while (parent) {
759 gtk_ctree_expand(GTK_CTREE(tree), parent);
760 parent = GTK_CTREE_ROW(parent)->parent;
761 }
763 gtk_ctree_node_moveto(GTK_CTREE(tree), node, 0, 0.66, 0.0);
764 }
765 } else {
766 gtk_clist_unselect_all(GTK_CLIST(tree));
767 }
768 propagate_tree_select(repr);
769 }
773 void propagate_tree_select(Inkscape::XML::Node *repr)
774 {
775 if (repr && repr->type() == Inkscape::XML::ELEMENT_NODE) {
776 sp_xmlview_attr_list_set_repr(attributes, repr);
777 } else {
778 sp_xmlview_attr_list_set_repr(attributes, NULL);
779 }
781 if (repr && ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE || repr->type() == Inkscape::XML::PI_NODE ) ) {
782 sp_xmlview_content_set_repr(content, repr);
783 } else {
784 sp_xmlview_content_set_repr(content, NULL);
785 }
786 }
789 Inkscape::XML::Node *get_dt_select()
790 {
791 if (!current_desktop) {
792 return NULL;
793 }
795 return sp_desktop_selection(current_desktop)->singleRepr();
796 }
800 void set_dt_select(Inkscape::XML::Node *repr)
801 {
802 if (!current_desktop) {
803 return;
804 }
806 Inkscape::Selection *selection = sp_desktop_selection(current_desktop);
808 SPObject *object;
809 if (repr) {
810 while ( ( repr->type() != Inkscape::XML::ELEMENT_NODE )
811 && sp_repr_parent(repr) )
812 {
813 repr = sp_repr_parent(repr);
814 } // end of while loop
816 object = sp_desktop_document(current_desktop)->getObjectByRepr(repr);
817 } else {
818 object = NULL;
819 }
821 blocked++;
822 if ( object && in_dt_coordsys(*object)
823 && !(SP_IS_STRING(object) ||
824 SP_IS_ROOT(object) ) )
825 {
826 /* We cannot set selection to root or string - they are not items and selection is not
827 * equipped to deal with them */
828 selection->set(SP_ITEM(object));
829 }
830 blocked--;
832 } // end of set_dt_select()
835 void on_tree_select_row(GtkCTree *tree,
836 GtkCTreeNode *node,
837 gint /*column*/,
838 gpointer /*data*/)
839 {
840 if (blocked) {
841 return;
842 }
844 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
845 g_assert(repr != NULL);
847 if (selected_repr == repr) {
848 return;
849 }
851 if (selected_repr) {
852 Inkscape::GC::release(selected_repr);
853 selected_repr = NULL;
854 }
855 selected_repr = repr;
856 Inkscape::GC::anchor(selected_repr);
858 propagate_tree_select(selected_repr);
860 set_dt_select(selected_repr);
862 tree_reset_context();
863 }
865 void on_tree_unselect_row(GtkCTree *tree,
866 GtkCTreeNode *node,
867 gint /*column*/,
868 gpointer /*data*/)
869 {
870 if (blocked) {
871 return;
872 }
874 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
875 propagate_tree_select(NULL);
876 set_dt_select(NULL);
878 if (selected_repr && (selected_repr == repr)) {
879 Inkscape::GC::release(selected_repr);
880 selected_repr = NULL;
881 selected_attr = 0;
882 }
883 }
887 void after_tree_move(GtkCTree */*tree*/,
888 GtkCTreeNode *node,
889 GtkCTreeNode *new_parent,
890 GtkCTreeNode *new_sibling,
891 gpointer /*data*/)
892 {
893 if (GTK_CTREE_ROW(node)->parent == new_parent &&
894 GTK_CTREE_ROW(node)->sibling == new_sibling)
895 {
896 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
897 _("Drag XML subtree"));
898 } else {
899 sp_document_cancel(current_document);
900 }
901 }
904 static void on_destroy(GtkObject */*object*/, gpointer /*data*/)
905 {
906 set_tree_desktop(NULL);
907 gtk_object_destroy(GTK_OBJECT(tooltips));
908 tooltips = NULL;
909 sp_signal_disconnect_by_data(INKSCAPE, dlg);
910 wd.win = dlg = NULL;
911 wd.stop = 0;
913 _message_changed_connection.disconnect();
914 delete _message_context;
915 _message_context = NULL;
916 Inkscape::GC::release(_message_stack);
917 _message_stack = NULL;
918 _message_changed_connection.~connection();
920 status = NULL;
921 }
925 static gboolean on_delete(GtkObject */*object*/, GdkEvent */*event*/, gpointer /*data*/)
926 {
927 gtk_window_get_position((GtkWindow *) dlg, &x, &y);
928 gtk_window_get_size((GtkWindow *) dlg, &w, &h);
930 if (x<0) x=0;
931 if (y<0) y=0;
933 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
934 prefs->setInt(prefs_path + "x", x);
935 prefs->setInt(prefs_path + "y", y);
936 prefs->setInt(prefs_path + "w", w);
937 prefs->setInt(prefs_path + "h", h);
939 return FALSE; // which means, go ahead and destroy it
940 }
943 static void _set_status_message(Inkscape::MessageType /*type*/, const gchar *message, GtkWidget */*dialog*/)
944 {
945 if (status) {
946 gtk_label_set_markup(GTK_LABEL(status), message ? message : "");
947 }
948 }
951 void on_tree_select_row_enable(GtkCTree */*tree*/,
952 GtkCTreeNode */*node*/,
953 gint /*column*/,
954 gpointer data)
955 {
956 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
957 }
961 void on_tree_select_row_enable_if_element(GtkCTree *tree,
962 GtkCTreeNode *node,
963 gint /*column*/,
964 gpointer data )
965 {
966 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
968 if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
969 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
970 } else {
971 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
972 }
973 }
977 void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node,
978 gint /*column*/, gpointer data)
979 {
980 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
982 if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
983 gtk_widget_show(GTK_WIDGET(data));
984 } else {
985 gtk_widget_hide(GTK_WIDGET(data));
986 }
987 }
991 void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node,
992 gint /*column*/, gpointer data)
993 {
994 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
996 if ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE || repr->type() == Inkscape::XML::PI_NODE ) {
997 gtk_widget_show(GTK_WIDGET(data));
998 } else {
999 gtk_widget_hide(GTK_WIDGET(data));
1000 }
1001 }
1004 gboolean xml_tree_node_mutable(GtkCTreeNode *node)
1005 {
1006 // top-level is immutable, obviously
1007 if (!GTK_CTREE_ROW(node)->parent) {
1008 return false;
1009 }
1011 // if not in base level (where namedview, defs, etc go), we're mutable
1012 if (GTK_CTREE_ROW(GTK_CTREE_ROW(node)->parent)->parent) {
1013 return true;
1014 }
1016 Inkscape::XML::Node *repr;
1017 repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1018 g_assert(repr);
1020 // don't let "defs" or "namedview" disappear
1021 if ( !strcmp(repr->name(),"svg:defs") ||
1022 !strcmp(repr->name(),"sodipodi:namedview") ) {
1023 return false;
1024 }
1026 // everyone else is okay, I guess. :)
1027 return true;
1028 }
1031 void on_tree_select_row_enable_if_mutable(GtkCTree */*tree*/, GtkCTreeNode *node,
1032 gint /*column*/, gpointer data)
1033 {
1034 gtk_widget_set_sensitive(GTK_WIDGET(data), xml_tree_node_mutable(node));
1035 }
1039 void on_tree_unselect_row_disable(GtkCTree */*tree*/, GtkCTreeNode */*node*/,
1040 gint /*column*/, gpointer data)
1041 {
1042 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1043 }
1047 void on_tree_unselect_row_hide(GtkCTree */*tree*/, GtkCTreeNode */*node*/,
1048 gint /*column*/, gpointer data)
1049 {
1050 gtk_widget_hide(GTK_WIDGET(data));
1051 }
1055 void on_tree_unselect_row_clear_text(GtkCTree */*tree*/, GtkCTreeNode */*node*/,
1056 gint /*column*/, gpointer data)
1057 {
1058 if (GTK_IS_EDITABLE(data)) {
1059 gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1060 } else if (GTK_IS_TEXT_VIEW(data)) {
1061 GtkTextBuffer *tb;
1062 tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1063 gtk_text_buffer_set_text(tb, "", 0);
1064 }
1065 }
1068 void on_attr_select_row(GtkCList *list, gint row, gint /*column*/,
1069 GdkEventButton */*event*/, gpointer /*data*/)
1070 {
1071 selected_attr = sp_xmlview_attr_list_get_row_key(list, row);
1072 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(attr_value));
1074 attr_reset_context(selected_attr);
1075 }
1078 void on_attr_unselect_row(GtkCList */*list*/, gint /*row*/, gint /*column*/,
1079 GdkEventButton */*event*/, gpointer /*data*/)
1080 {
1081 selected_attr = 0;
1082 attr_reset_context(selected_attr);
1083 }
1086 void on_attr_row_changed(GtkCList *list, gint row, gpointer /*data*/)
1087 {
1088 gint attr = sp_xmlview_attr_list_get_row_key(list, row);
1090 if (attr == selected_attr) {
1091 /* if the attr changed, reselect the row in the list to sync
1092 the edit box */
1094 /*
1095 // get current attr values
1096 const gchar * name = g_quark_to_string (sp_xmlview_attr_list_get_row_key (list, row));
1097 const gchar * value = selected_repr->attribute(name);
1099 g_warning("value: '%s'",value);
1101 // get the edit box value
1102 GtkTextIter start, end;
1103 gtk_text_buffer_get_bounds ( gtk_text_view_get_buffer (attr_value),
1104 &start, &end );
1105 gchar * text = gtk_text_buffer_get_text ( gtk_text_view_get_buffer (attr_value),
1106 &start, &end, TRUE );
1107 g_warning("text: '%s'",text);
1109 // compare to edit box
1110 if (strcmp(text,value)) {
1111 // issue warning if they're different
1112 _message_stack->flash(Inkscape::WARNING_MESSAGE,
1113 _("Attribute changed in GUI while editing values!"));
1114 }
1115 g_free (text);
1117 */
1118 gtk_clist_unselect_row( GTK_CLIST(list), row, 0 );
1119 gtk_clist_select_row( GTK_CLIST(list), row, 0 );
1120 }
1121 }
1124 void on_attr_select_row_set_name_content(GtkCList *list, gint row,
1125 gint /*column*/, GdkEventButton */*event*/,
1126 gpointer data)
1127 {
1128 GtkEditable *editable = GTK_EDITABLE(data);
1129 const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1130 gtk_editable_delete_text(editable, 0, -1);
1131 gint pos = 0;
1132 gtk_editable_insert_text(editable, name, strlen(name), &pos);
1133 }
1137 void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint /*column*/,
1138 GdkEventButton */*event*/,
1139 gpointer data)
1140 {
1141 GtkTextBuffer *tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1142 const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1143 const gchar *value = selected_repr->attribute(name);
1144 if (!value) {
1145 value = "";
1146 }
1147 gtk_text_buffer_set_text(tb, value, strlen(value));
1148 }
1151 void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node,
1152 gint /*column*/, gpointer data)
1153 {
1154 gboolean indentable = FALSE;
1156 if (xml_tree_node_mutable(node)) {
1157 Inkscape::XML::Node *repr, *prev;
1158 repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1160 Inkscape::XML::Node *parent=repr->parent();
1161 if ( parent && repr != parent->firstChild() ) {
1162 g_assert(parent->firstChild());
1164 // skip to the child just before the current repr
1165 for ( prev = parent->firstChild() ;
1166 prev && prev->next() != repr ;
1167 prev = prev->next() );
1169 if (prev && prev->type() == Inkscape::XML::ELEMENT_NODE) {
1170 indentable = TRUE;
1171 }
1172 }
1173 }
1175 gtk_widget_set_sensitive(GTK_WIDGET(data), indentable);
1176 }
1180 void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree,
1181 GtkCTreeNode *node,
1182 gint /*column*/,
1183 gpointer data)
1184 {
1185 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1187 Inkscape::XML::Node *parent=repr->parent();
1188 if ( parent && repr != parent->firstChild() ) {
1189 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1190 } else {
1191 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1192 }
1193 }
1197 void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree,
1198 GtkCTreeNode *node,
1199 gint /*column*/, gpointer data)
1200 {
1201 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1203 Inkscape::XML::Node *parent=repr->parent();
1204 if ( parent && parent->parent() && repr->next() ) {
1205 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1206 } else {
1207 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1208 }
1209 }
1213 void on_tree_select_row_enable_if_has_grandparent(GtkCTree */*tree*/,
1214 GtkCTreeNode *node,
1215 gint /*column*/, gpointer data)
1216 {
1217 GtkCTreeNode *parent = GTK_CTREE_ROW(node)->parent;
1219 if (parent) {
1220 GtkCTreeNode *grandparent = GTK_CTREE_ROW(parent)->parent;
1221 if (grandparent) {
1222 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1223 } else {
1224 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1225 }
1226 } else {
1227 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1228 }
1229 }
1233 void on_attr_select_row_enable(GtkCList */*list*/, gint /*row*/, gint /*column*/,
1234 GdkEventButton */*event*/, gpointer data)
1235 {
1236 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1237 }
1241 void on_attr_unselect_row_disable(GtkCList */*list*/, gint /*row*/, gint /*column*/,
1242 GdkEventButton */*event*/, gpointer data)
1243 {
1244 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1245 }
1249 void on_attr_unselect_row_clear_text(GtkCList */*list*/, gint /*row*/, gint /*column*/,
1250 GdkEventButton */*event*/, gpointer data)
1251 {
1252 if (GTK_IS_EDITABLE(data)) {
1253 gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1254 } else if (GTK_IS_TEXT_VIEW(data)) {
1255 GtkTextBuffer *tb;
1256 tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1257 gtk_text_buffer_set_text(tb, "", 0);
1258 }
1259 }
1263 void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable,
1264 gpointer data)
1265 {
1266 gchar *text = gtk_editable_get_chars(editable, 0, -1);
1268 /* TODO: need to do checking a little more rigorous than this */
1270 if (strlen(text)) {
1271 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1272 } else {
1273 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1274 }
1275 g_free(text);
1276 }
1280 void on_desktop_selection_changed(Inkscape::Selection */*selection*/)
1281 {
1282 if (!blocked++) {
1283 set_tree_select(get_dt_select());
1284 }
1285 blocked--;
1286 }
1288 static void on_document_replaced(SPDesktop *dt, SPDocument *doc)
1289 {
1290 if (current_desktop)
1291 sel_changed_connection.disconnect();
1293 sel_changed_connection = sp_desktop_selection(dt)->connectChanged(&on_desktop_selection_changed);
1294 set_tree_document(doc);
1295 }
1297 void on_document_uri_set(gchar const */*uri*/, SPDocument *document)
1298 {
1299 gchar title[500];
1300 sp_ui_dialog_title_string(Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), title);
1301 gchar *t = g_strdup_printf("%s: %s", SP_DOCUMENT_NAME(document), title);
1302 gtk_window_set_title(GTK_WINDOW(dlg), t);
1303 g_free(t);
1304 }
1308 void on_clicked_get_editable_text(GtkWidget */*widget*/, gpointer data)
1309 {
1310 EditableDest *dest = (EditableDest *) data;
1311 dest->text = gtk_editable_get_chars(dest->editable, 0, -1);
1312 }
1314 gboolean
1315 quit_on_esc (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
1316 {
1317 switch (get_group0_keyval (event)) {
1318 case GDK_Escape: // defocus
1319 gtk_widget_destroy(w);
1320 return TRUE;
1321 }
1322 return FALSE;
1323 }
1325 void cmd_new_element_node(GtkObject */*object*/, gpointer /*data*/)
1326 {
1327 EditableDest name;
1328 GtkWidget *window, *create, *cancel, *vbox, *entry, *bbox, *sep;
1330 g_assert(selected_repr != NULL);
1332 window = sp_window_new(NULL, TRUE);
1333 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
1334 gtk_window_set_title(GTK_WINDOW(window), _("New element node..."));
1335 gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE);
1336 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1337 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(dlg));
1338 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1339 gtk_signal_connect(GTK_OBJECT(window), "destroy", gtk_main_quit, NULL);
1340 gtk_signal_connect(GTK_OBJECT(window), "key-press-event", G_CALLBACK(quit_on_esc), window);
1342 vbox = gtk_vbox_new(FALSE, 4);
1343 gtk_container_add(GTK_CONTAINER(window), vbox);
1345 entry = gtk_entry_new();
1346 gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 0);
1348 sep = gtk_hseparator_new();
1349 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, TRUE, 0);
1351 bbox = gtk_hbutton_box_new();
1352 gtk_container_set_border_width(GTK_CONTAINER(bbox), 4);
1353 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1354 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
1356 cancel = gtk_button_new_with_label(_("Cancel"));
1357 GTK_WIDGET_SET_FLAGS( GTK_WIDGET(cancel),
1358 GTK_CAN_DEFAULT );
1359 gtk_signal_connect_object( GTK_OBJECT(cancel), "clicked",
1360 G_CALLBACK(gtk_widget_destroy),
1361 GTK_OBJECT(window) );
1362 gtk_container_add(GTK_CONTAINER(bbox), cancel);
1364 create = gtk_button_new_with_label(_("Create"));
1365 gtk_widget_set_sensitive(GTK_WIDGET(create), FALSE);
1366 gtk_signal_connect( GTK_OBJECT(entry), "changed",
1367 G_CALLBACK(on_editable_changed_enable_if_valid_xml_name),
1368 create );
1369 gtk_signal_connect( GTK_OBJECT(create), "clicked",
1370 G_CALLBACK(on_clicked_get_editable_text), &name );
1371 gtk_signal_connect_object( GTK_OBJECT(create), "clicked",
1372 G_CALLBACK(gtk_widget_destroy),
1373 GTK_OBJECT(window) );
1374 GTK_WIDGET_SET_FLAGS( GTK_WIDGET(create),
1375 GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT );
1376 gtk_container_add(GTK_CONTAINER(bbox), create);
1378 gtk_widget_show_all(GTK_WIDGET(window));
1379 gtk_window_set_default(GTK_WINDOW(window), GTK_WIDGET(create));
1380 gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(entry));
1382 name.editable = GTK_EDITABLE(entry);
1383 name.text = NULL;
1385 gtk_main();
1387 if (selected_repr != NULL && name.text) {
1388 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(current_document);
1389 Inkscape::XML::Node *new_repr;
1390 new_repr = xml_doc->createElement(name.text);
1391 Inkscape::GC::release(new_repr);
1392 g_free(name.text);
1393 selected_repr->appendChild(new_repr);
1394 set_tree_select(new_repr);
1395 set_dt_select(new_repr);
1397 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1398 _("Create new element node"));
1399 }
1401 } // end of cmd_new_element_node()
1405 void cmd_new_text_node(GtkObject */*object*/, gpointer /*data*/)
1406 {
1407 g_assert(selected_repr != NULL);
1409 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(current_document);
1410 Inkscape::XML::Node *text = xml_doc->createTextNode("");
1411 selected_repr->appendChild(text);
1413 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1414 _("Create new text node"));
1416 set_tree_select(text);
1417 set_dt_select(text);
1419 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(content));
1421 }
1423 void cmd_duplicate_node(GtkObject */*object*/, gpointer /*data*/)
1424 {
1425 g_assert(selected_repr != NULL);
1427 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1428 Inkscape::XML::Node *dup = selected_repr->duplicate(parent->document());
1429 parent->addChild(dup, selected_repr);
1431 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1432 _("Duplicate node"));
1434 GtkCTreeNode *node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), dup);
1436 if (node) {
1437 gtk_ctree_select(GTK_CTREE(tree), node);
1438 }
1439 }
1443 void cmd_delete_node(GtkObject */*object*/, gpointer /*data*/)
1444 {
1445 g_assert(selected_repr != NULL);
1446 sp_repr_unparent(selected_repr);
1448 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1449 _("Delete node"));
1450 }
1454 void cmd_delete_attr(GtkObject */*object*/, gpointer /*data*/)
1455 {
1456 g_assert(selected_repr != NULL);
1457 g_assert(selected_attr != 0);
1458 selected_repr->setAttribute(g_quark_to_string(selected_attr), NULL);
1460 SPObject *updated=current_document->getObjectByRepr(selected_repr);
1461 if (updated) {
1462 // force immediate update of dependant attributes
1463 updated->updateRepr();
1464 }
1466 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1467 _("Delete attribute"));
1468 }
1472 void cmd_set_attr(GtkObject */*object*/, gpointer /*data*/)
1473 {
1474 g_assert(selected_repr != NULL);
1476 gchar *name = gtk_editable_get_chars(attr_name, 0, -1);
1477 GtkTextIter start;
1478 GtkTextIter end;
1479 gtk_text_buffer_get_bounds( gtk_text_view_get_buffer(attr_value),
1480 &start, &end );
1481 gchar *value = gtk_text_buffer_get_text( gtk_text_view_get_buffer(attr_value),
1482 &start, &end, TRUE );
1484 selected_repr->setAttribute(name, value, false);
1486 g_free(name);
1487 g_free(value);
1489 SPObject *updated = current_document->getObjectByRepr(selected_repr);
1490 if (updated) {
1491 // force immediate update of dependant attributes
1492 updated->updateRepr();
1493 }
1495 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1496 _("Change attribute"));
1498 /* TODO: actually, the row won't have been created yet. why? */
1499 gint row = sp_xmlview_attr_list_find_row_from_key(GTK_CLIST(attributes),
1500 g_quark_from_string(name));
1501 if (row != -1) {
1502 gtk_clist_select_row(GTK_CLIST(attributes), row, 0);
1503 }
1504 }
1508 void cmd_raise_node(GtkObject */*object*/, gpointer /*data*/)
1509 {
1510 g_assert(selected_repr != NULL);
1512 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1513 g_return_if_fail(parent != NULL);
1514 g_return_if_fail(parent->firstChild() != selected_repr);
1516 Inkscape::XML::Node *ref = NULL;
1517 Inkscape::XML::Node *before = parent->firstChild();
1518 while (before && before->next() != selected_repr) {
1519 ref = before;
1520 before = before->next();
1521 }
1523 parent->changeOrder(selected_repr, ref);
1525 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1526 _("Raise node"));
1528 set_tree_select(selected_repr);
1529 set_dt_select(selected_repr);
1530 }
1534 void cmd_lower_node(GtkObject */*object*/, gpointer /*data*/)
1535 {
1536 g_assert(selected_repr != NULL);
1537 g_return_if_fail(selected_repr->next() != NULL);
1538 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1540 parent->changeOrder(selected_repr, selected_repr->next());
1542 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1543 _("Lower node"));
1545 set_tree_select(selected_repr);
1546 set_dt_select(selected_repr);
1547 }
1549 void cmd_indent_node(GtkObject */*object*/, gpointer /*data*/)
1550 {
1551 Inkscape::XML::Node *repr = selected_repr;
1552 g_assert(repr != NULL);
1553 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1554 g_return_if_fail(parent != NULL);
1555 g_return_if_fail(parent->firstChild() != repr);
1557 Inkscape::XML::Node* prev = parent->firstChild();
1558 while (prev && prev->next() != repr) {
1559 prev = prev->next();
1560 }
1561 g_return_if_fail(prev != NULL);
1562 g_return_if_fail(prev->type() == Inkscape::XML::ELEMENT_NODE);
1564 Inkscape::XML::Node* ref = NULL;
1565 if (prev->firstChild()) {
1566 for( ref = prev->firstChild() ; ref->next() ; ref = ref->next() );
1567 }
1569 parent->removeChild(repr);
1570 prev->addChild(repr, ref);
1572 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1573 _("Indent node"));
1574 set_tree_select(repr);
1575 set_dt_select(repr);
1577 } // end of cmd_indent_node()
1581 void cmd_unindent_node(GtkObject */*object*/, gpointer /*data*/)
1582 {
1583 Inkscape::XML::Node *repr = selected_repr;
1584 g_assert(repr != NULL);
1585 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1586 g_return_if_fail(parent);
1587 Inkscape::XML::Node *grandparent = sp_repr_parent(parent);
1588 g_return_if_fail(grandparent);
1590 parent->removeChild(repr);
1591 grandparent->addChild(repr, parent);
1593 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1594 _("Unindent node"));
1595 set_tree_select(repr);
1596 set_dt_select(repr);
1598 } // end of cmd_unindent_node()
1601 /*
1602 Local Variables:
1603 mode:c++
1604 c-file-style:"stroustrup"
1605 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1606 indent-tabs-mode:nil
1607 fill-column:99
1608 End:
1609 */
1610 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :