06103e9b32958be78fde5c6afb5bd31300fa7dbf
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_change( Inkscape::Application *inkscape, SPDesktop *desktop, GtkWidget *dialog );
102 static void set_tree_desktop(SPDesktop *desktop);
103 static void set_tree_document(SPDocument *document);
104 static void set_tree_repr(Inkscape::XML::Node *repr);
106 static void set_tree_select(Inkscape::XML::Node *repr);
107 static void propagate_tree_select(Inkscape::XML::Node *repr);
109 static Inkscape::XML::Node *get_dt_select();
110 static void set_dt_select(Inkscape::XML::Node *repr);
112 static void on_tree_select_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
113 static void on_tree_unselect_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
114 static void after_tree_move(GtkCTree *tree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling, gpointer data);
115 static void on_destroy(GtkObject *object, gpointer data);
116 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data);
118 static void on_tree_select_row_enable_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
119 static void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
120 static void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
121 static void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
122 static void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
123 static void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
124 static void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
125 static void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
127 static void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
128 static void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
129 static void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
131 static void on_attr_select_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
132 static void on_attr_unselect_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
133 static void on_attr_row_changed( GtkCList *list, gint row, gpointer data );
135 static void on_attr_select_row_enable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
136 static void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
138 static void on_attr_select_row_set_name_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
139 static void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
140 static void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
142 static void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable, gpointer data);
144 static void on_desktop_selection_changed(Inkscape::Selection *selection);
145 static void on_document_replaced(SPDesktop *dt, SPDocument *document);
146 static void on_document_uri_set(gchar const *uri, SPDocument *document);
148 static void on_clicked_get_editable_text(GtkWidget *widget, gpointer data);
150 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog);
152 static void cmd_new_element_node(GtkObject *object, gpointer data);
153 static void cmd_new_text_node(GtkObject *object, gpointer data);
154 static void cmd_duplicate_node(GtkObject *object, gpointer data);
155 static void cmd_delete_node(GtkObject *object, gpointer data);
157 static void cmd_raise_node(GtkObject *object, gpointer data);
158 static void cmd_lower_node(GtkObject *object, gpointer data);
159 static void cmd_indent_node(GtkObject *object, gpointer data);
160 static void cmd_unindent_node(GtkObject *object, gpointer data);
162 static void cmd_delete_attr(GtkObject *object, gpointer data);
163 static void cmd_set_attr(GtkObject *object, gpointer data);
165 static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event);
168 /*
169 * \brief Sets the XML status bar when the tree is selected.
170 */
171 void tree_reset_context()
172 {
173 _message_context->set(Inkscape::NORMAL_MESSAGE,
174 _("<b>Click</b> to select nodes, <b>drag</b> to rearrange."));
175 }
178 /*
179 * \brief Sets the XML status bar, depending on which attr is selected.
180 */
181 void attr_reset_context(gint attr)
182 {
183 if (attr == 0) {
184 _message_context->set(Inkscape::NORMAL_MESSAGE,
185 _("<b>Click</b> attribute to edit."));
186 }
187 else {
188 const gchar *name = g_quark_to_string(attr);
189 gchar *message = g_strdup_printf(_("Attribute <b>%s</b> selected. Press <b>Ctrl+Enter</b> when done editing to commit changes."), name);
190 _message_context->set(Inkscape::NORMAL_MESSAGE, message);
191 g_free(message);
192 }
193 }
196 void sp_xml_tree_dialog()
197 {
198 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
200 if (!desktop) {
201 return;
202 }
204 if (dlg == NULL)
205 { // very long block
207 GtkWidget *box, *sw, *paned, *toolbar, *button;
208 GtkWidget *text_container, *attr_container, *attr_subpaned_container, *box2;
209 GtkWidget *set_attr;
211 tooltips = gtk_tooltips_new();
212 gtk_tooltips_enable(tooltips);
214 dlg = sp_window_new("", TRUE);
215 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
216 if (x == -1000 || y == -1000) {
217 x = prefs->getInt(prefs_path + "x", -1000);
218 y = prefs->getInt(prefs_path + "y", -1000);
219 }
220 if (w ==0 || h == 0) {
221 w = prefs->getInt(prefs_path + "w", 0);
222 h = prefs->getInt(prefs_path + "h", 0);
223 }
225 // if (x<0) x=0;
226 // if (y<0) y=0;
228 if (w && h) {
229 gtk_window_resize((GtkWindow *) dlg, w, h);
230 }
231 if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE))) {
232 gtk_window_move((GtkWindow *) dlg, x, y);
233 } else {
234 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
235 }
237 sp_transientize(dlg);
238 wd.win = dlg;
239 wd.stop = 0;
240 g_signal_connect ( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd );
242 gtk_signal_connect( GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg );
244 gtk_signal_connect( GTK_OBJECT(dlg), "destroy", G_CALLBACK(on_destroy), dlg);
245 gtk_signal_connect( GTK_OBJECT(dlg), "delete_event", G_CALLBACK(on_delete), dlg);
246 g_signal_connect ( G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(on_delete), dlg);
248 g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg);
249 g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg);
252 gtk_container_set_border_width(GTK_CONTAINER(dlg), 0);
253 gtk_window_set_default_size(GTK_WINDOW(dlg), 640, 384);
255 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
256 gtk_container_add(GTK_CONTAINER(dlg), vbox);
258 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
259 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
261 status = gtk_label_new(NULL);
262 gtk_misc_set_alignment(GTK_MISC(status), 0.0, 0.5);
263 gtk_widget_set_size_request(status, 1, -1);
264 gtk_label_set_markup(GTK_LABEL(status), "");
265 gtk_box_pack_start(GTK_BOX(hbox), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 4);
266 gtk_box_pack_start(GTK_BOX(hbox), status, TRUE, TRUE, 0);
268 paned = gtk_hpaned_new();
269 gtk_paned_set_position(GTK_PANED(paned), 256);
270 gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 0);
272 _message_stack = new Inkscape::MessageStack();
273 _message_context = new Inkscape::MessageContext(_message_stack);
274 _message_changed_connection = _message_stack->connectChanged(
275 sigc::bind(sigc::ptr_fun(_set_status_message), dlg)
276 );
278 /* tree view */
280 box = gtk_vbox_new(FALSE, 0);
281 gtk_paned_pack1(GTK_PANED(paned), box, FALSE, FALSE);
283 tree = SP_XMLVIEW_TREE(sp_xmlview_tree_new(NULL, NULL, NULL));
284 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(tree),
285 _("Drag to reorder nodes"), NULL );
287 g_signal_connect( G_OBJECT(tree), "tree_select_row",
288 G_CALLBACK(on_tree_select_row), NULL );
290 g_signal_connect( G_OBJECT(tree), "tree_unselect_row",
291 G_CALLBACK(on_tree_unselect_row), NULL );
293 g_signal_connect_after( G_OBJECT(tree), "tree_move",
294 G_CALLBACK(after_tree_move), NULL);
296 /* TODO: replace gtk_signal_connect_while_alive() with something
297 * else...
298 */
299 toolbar = gtk_toolbar_new();
300 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
301 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
303 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
304 NULL,
305 _("New element node"),
306 NULL,
307 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
308 INKSCAPE_STOCK_ADD_XML_ELEMENT_NODE ),
309 G_CALLBACK(cmd_new_element_node),
310 NULL);
312 gtk_signal_connect_while_alive( GTK_OBJECT(tree),
313 "tree_select_row",
314 G_CALLBACK(on_tree_select_row_enable_if_element),
315 button,
316 GTK_OBJECT(button));
318 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
319 "tree_unselect_row",
320 G_CALLBACK(on_tree_unselect_row_disable),
321 button,
322 GTK_OBJECT(button));
324 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
326 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
327 NULL, _("New text node"), NULL,
328 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
329 INKSCAPE_STOCK_ADD_XML_TEXT_NODE ),
330 G_CALLBACK(cmd_new_text_node),
331 NULL);
333 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
334 "tree_select_row",
335 G_CALLBACK(on_tree_select_row_enable_if_element),
336 button,
337 GTK_OBJECT(button));
339 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
340 "tree_unselect_row",
341 G_CALLBACK(on_tree_unselect_row_disable),
342 button,
343 GTK_OBJECT(button));
345 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
347 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
348 NULL, _("Duplicate node"), NULL,
349 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
350 INKSCAPE_STOCK_DUPLICATE_XML_NODE ),
351 G_CALLBACK(cmd_duplicate_node),
352 NULL);
354 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
355 "tree_select_row",
356 G_CALLBACK(on_tree_select_row_enable_if_mutable),
357 button,
358 GTK_OBJECT(button));
360 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
361 G_CALLBACK(on_tree_unselect_row_disable),
362 button, GTK_OBJECT(button));
364 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
366 gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
368 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
369 NULL, _("Delete node"), NULL,
370 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
371 INKSCAPE_STOCK_DELETE_XML_NODE ),
372 G_CALLBACK(cmd_delete_node), NULL );
374 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
375 G_CALLBACK(on_tree_select_row_enable_if_mutable),
376 button, GTK_OBJECT(button));
377 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
378 G_CALLBACK(on_tree_unselect_row_disable),
379 button, GTK_OBJECT(button));
380 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
382 gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
384 button = gtk_toolbar_append_item( GTK_TOOLBAR(toolbar), "<",
385 _("Unindent node"), NULL,
386 gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_IN),
387 G_CALLBACK(cmd_unindent_node), NULL);
389 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
390 G_CALLBACK(on_tree_select_row_enable_if_has_grandparent),
391 button, GTK_OBJECT(button));
393 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
394 G_CALLBACK(on_tree_unselect_row_disable),
395 button, GTK_OBJECT(button));
397 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
399 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), ">",
400 _("Indent node"), NULL,
401 gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_IN),
402 G_CALLBACK(cmd_indent_node), NULL);
403 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
404 G_CALLBACK(on_tree_select_row_enable_if_indentable),
405 button, GTK_OBJECT(button));
406 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
407 (GCallback) on_tree_unselect_row_disable,
408 button, GTK_OBJECT(button));
409 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
411 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "^",
412 _("Raise node"), NULL,
413 gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_IN),
414 G_CALLBACK(cmd_raise_node), NULL);
415 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
416 G_CALLBACK(on_tree_select_row_enable_if_not_first_child),
417 button, GTK_OBJECT(button));
418 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
419 G_CALLBACK(on_tree_unselect_row_disable),
420 button, GTK_OBJECT(button));
421 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
423 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "v",
424 _("Lower node"), NULL,
425 gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_IN),
426 G_CALLBACK(cmd_lower_node), NULL);
427 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
428 G_CALLBACK(on_tree_select_row_enable_if_not_last_child),
429 button, GTK_OBJECT(button));
430 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
431 G_CALLBACK(on_tree_unselect_row_disable),
432 button, GTK_OBJECT(button));
433 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
435 gtk_box_pack_start(GTK_BOX(box), toolbar, FALSE, TRUE, 0);
437 sw = gtk_scrolled_window_new(NULL, NULL);
438 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
439 GTK_POLICY_AUTOMATIC,
440 GTK_POLICY_AUTOMATIC );
441 gtk_box_pack_start(GTK_BOX(box), sw, TRUE, TRUE, 0);
443 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(tree));
445 /* node view */
447 box = gtk_vbox_new(FALSE, 0);
448 gtk_paned_pack2(GTK_PANED(paned), box, TRUE, TRUE);
450 /* attributes */
452 attr_container = gtk_vbox_new(FALSE, 0);
453 gtk_box_pack_start( GTK_BOX(box), GTK_WIDGET(attr_container),
454 TRUE, TRUE, 0 );
456 attributes = SP_XMLVIEW_ATTR_LIST(sp_xmlview_attr_list_new(NULL));
457 g_signal_connect( G_OBJECT(attributes), "select_row",
458 G_CALLBACK(on_attr_select_row), NULL);
459 g_signal_connect( G_OBJECT(attributes), "unselect_row",
460 G_CALLBACK(on_attr_unselect_row), NULL);
461 g_signal_connect( G_OBJECT(attributes), "row-value-changed",
462 G_CALLBACK(on_attr_row_changed), NULL);
464 toolbar = gtk_toolbar_new();
465 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
466 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
468 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
469 NULL, _("Delete attribute"), NULL,
470 sp_icon_new( Inkscape::ICON_SIZE_LARGE_TOOLBAR,
471 INKSCAPE_STOCK_DELETE_XML_ATTRIBUTE ),
472 (GCallback) cmd_delete_attr, NULL);
474 gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "select_row",
475 (GCallback) on_attr_select_row_enable, button,
476 GTK_OBJECT(button));
478 gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "unselect_row",
479 (GCallback) on_attr_unselect_row_disable, button,
480 GTK_OBJECT(button));
482 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
483 (GCallback) on_tree_unselect_row_disable, button,
484 GTK_OBJECT(button));
486 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
488 gtk_box_pack_start( GTK_BOX(attr_container),
489 GTK_WIDGET(toolbar), FALSE, TRUE, 0 );
491 attr_subpaned_container = gtk_vpaned_new();
492 gtk_box_pack_start( GTK_BOX(attr_container),
493 GTK_WIDGET(attr_subpaned_container),
494 TRUE, TRUE, 0 );
495 gtk_widget_show(attr_subpaned_container);
497 sw = gtk_scrolled_window_new(NULL, NULL);
498 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
499 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
500 gtk_paned_pack1( GTK_PANED(attr_subpaned_container),
501 GTK_WIDGET(sw), TRUE, TRUE );
502 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(attributes));
504 toolbar = gtk_vbox_new(FALSE, 4);
505 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 4);
507 box2 = gtk_hbox_new(FALSE, 4);
508 gtk_box_pack_start( GTK_BOX(toolbar), GTK_WIDGET(box2),
509 FALSE, TRUE, 0);
511 attr_name = GTK_EDITABLE(gtk_entry_new());
512 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_name),
513 // TRANSLATORS: "Attribute" is a noun here
514 _("Attribute name"), NULL );
516 gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
517 (GCallback) on_attr_select_row_set_name_content,
518 attr_name);
520 gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
521 (GCallback) on_attr_unselect_row_clear_text,
522 attr_name);
524 gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
525 (GCallback) on_tree_unselect_row_clear_text,
526 attr_name);
528 gtk_box_pack_start( GTK_BOX(box2), GTK_WIDGET(attr_name),
529 TRUE, TRUE, 0);
531 set_attr = gtk_button_new();
532 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(set_attr),
533 // TRANSLATORS: "Set" is a verb here
534 _("Set attribute"), NULL );
535 // TRANSLATORS: "Set" is a verb here
536 GtkWidget *set_label = gtk_label_new(_("Set"));
537 gtk_container_add(GTK_CONTAINER(set_attr), set_label);
539 gtk_signal_connect( GTK_OBJECT(set_attr), "clicked",
540 (GCallback) cmd_set_attr, NULL);
541 gtk_signal_connect( GTK_OBJECT(attr_name), "changed",
542 (GCallback) on_editable_changed_enable_if_valid_xml_name,
543 set_attr );
544 gtk_widget_set_sensitive(GTK_WIDGET(set_attr), FALSE);
546 gtk_box_pack_start(GTK_BOX(box2), set_attr, FALSE, FALSE, 0);
548 sw = gtk_scrolled_window_new(NULL, NULL);
549 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
550 GTK_POLICY_AUTOMATIC,
551 GTK_POLICY_AUTOMATIC );
552 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
553 gtk_box_pack_start(GTK_BOX(toolbar), sw, TRUE, TRUE, 0);
555 attr_value =(GtkTextView *) gtk_text_view_new();
556 gtk_text_view_set_wrap_mode((GtkTextView *) attr_value, GTK_WRAP_CHAR);
557 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_value),
558 // TRANSLATORS: "Attribute" is a noun here
559 _("Attribute value"), NULL );
560 gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
561 (GCallback) on_attr_select_row_set_value_content,
562 attr_value );
563 gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
564 (GCallback) on_attr_unselect_row_clear_text,
565 attr_value );
566 gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
567 (GCallback) on_tree_unselect_row_clear_text,
568 attr_value );
569 gtk_text_view_set_editable(attr_value, TRUE);
570 gtk_container_add( GTK_CONTAINER(sw),
571 GTK_WIDGET(attr_value) );
573 gtk_paned_pack2( GTK_PANED(attr_subpaned_container),
574 GTK_WIDGET(toolbar), FALSE, TRUE );
576 /* text */
578 sw = gtk_scrolled_window_new(NULL, NULL);
579 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
580 GTK_POLICY_AUTOMATIC,
581 GTK_POLICY_AUTOMATIC );
582 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
583 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(sw), TRUE, TRUE, 0);
585 content = SP_XMLVIEW_CONTENT(sp_xmlview_content_new(NULL));
586 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(content));
588 text_container = sw;
590 /* initial show/hide */
592 gtk_widget_show_all(GTK_WIDGET(dlg));
594 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
595 (GCallback) on_tree_select_row_show_if_element,
596 attr_container, GTK_OBJECT(attr_container));
598 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
599 (GCallback) on_tree_unselect_row_hide,
600 attr_container, GTK_OBJECT(attr_container));
602 gtk_widget_hide(attr_container);
604 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
605 (GCallback) on_tree_select_row_show_if_text,
606 text_container, GTK_OBJECT(text_container));
608 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
609 (GCallback) on_tree_unselect_row_hide,
610 text_container, GTK_OBJECT(text_container));
612 gtk_widget_hide(text_container);
614 g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop",
615 G_CALLBACK(sp_xmltree_desktop_change), dlg);
617 g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop",
618 G_CALLBACK(sp_xmltree_desktop_change), dlg);
620 g_signal_connect((GObject *) dlg, "key_press_event", (GCallback) sp_xml_tree_key_press, NULL);
622 tree_reset_context();
623 } // end of if (dlg == NULL)
625 gtk_window_present((GtkWindow *) dlg);
627 g_assert(desktop != NULL);
628 set_tree_desktop(desktop);
630 } // end of sp_xml_tree_dialog()
632 static gboolean sp_xml_tree_key_press(GtkWidget */*widget*/, GdkEventKey *event)
633 {
635 unsigned int shortcut = get_group0_keyval(event) |
636 ( event->state & GDK_SHIFT_MASK ?
637 SP_SHORTCUT_SHIFT_MASK : 0 ) |
638 ( event->state & GDK_CONTROL_MASK ?
639 SP_SHORTCUT_CONTROL_MASK : 0 ) |
640 ( event->state & GDK_MOD1_MASK ?
641 SP_SHORTCUT_ALT_MASK : 0 );
643 /* fixme: if you need to add more xml-tree-specific callbacks, you should probably upgrade
644 * the sp_shortcut mechanism to take into account windows. */
645 if (shortcut == (SP_SHORTCUT_CONTROL_MASK | GDK_Return)) {
646 cmd_set_attr(NULL, NULL);
647 return true;
648 }
649 return false;
650 }
653 static void sp_xmltree_desktop_change(Inkscape::Application */*inkscape*/,
654 SPDesktop *desktop,
655 GtkWidget */*dialog*/ )
656 {
657 if (!desktop) {
658 return;
659 }
660 set_tree_desktop(desktop);
661 }
664 void set_tree_desktop(SPDesktop *desktop)
665 {
666 if ( desktop == current_desktop ) {
667 return;
668 }
670 if (current_desktop) {
671 sel_changed_connection.disconnect();
672 document_replaced_connection.disconnect();
673 }
674 current_desktop = desktop;
675 if (desktop) {
676 sel_changed_connection = sp_desktop_selection(desktop)->connectChanged(&on_desktop_selection_changed);
677 document_replaced_connection = desktop->connectDocumentReplaced(&on_document_replaced);
678 set_tree_document(sp_desktop_document(desktop));
679 } else {
680 set_tree_document(NULL);
681 }
683 } // end of set_tree_desktop()
687 void set_tree_document(SPDocument *document)
688 {
689 if (document == current_document) {
690 return;
691 }
693 if (current_document) {
694 document_uri_set_connection.disconnect();
695 }
696 current_document = document;
697 if (current_document) {
699 document_uri_set_connection = current_document->connectURISet(sigc::bind(sigc::ptr_fun(&on_document_uri_set), current_document));
700 on_document_uri_set(SP_DOCUMENT_URI(current_document), current_document);
701 set_tree_repr(sp_document_repr_root(current_document));
703 } else {
704 set_tree_repr(NULL);
705 }
706 }
710 void set_tree_repr(Inkscape::XML::Node *repr)
711 {
712 if (repr == selected_repr) {
713 return;
714 }
716 gtk_clist_freeze(GTK_CLIST(tree));
718 sp_xmlview_tree_set_repr(tree, repr);
720 if (repr) {
721 set_tree_select(get_dt_select());
722 } else {
723 set_tree_select(NULL);
724 }
726 gtk_clist_thaw(GTK_CLIST(tree));
728 propagate_tree_select(selected_repr);
730 }
734 void set_tree_select(Inkscape::XML::Node *repr)
735 {
736 if (selected_repr) {
737 Inkscape::GC::release(selected_repr);
738 }
740 selected_repr = repr;
741 if (repr) {
742 GtkCTreeNode *node;
744 Inkscape::GC::anchor(selected_repr);
746 node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), repr);
747 if (node) {
748 GtkCTreeNode *parent;
750 gtk_ctree_select(GTK_CTREE(tree), node);
752 parent = GTK_CTREE_ROW(node)->parent;
753 while (parent) {
754 gtk_ctree_expand(GTK_CTREE(tree), parent);
755 parent = GTK_CTREE_ROW(parent)->parent;
756 }
758 gtk_ctree_node_moveto(GTK_CTREE(tree), node, 0, 0.66, 0.0);
759 }
760 } else {
761 gtk_clist_unselect_all(GTK_CLIST(tree));
762 }
763 propagate_tree_select(repr);
764 }
768 void propagate_tree_select(Inkscape::XML::Node *repr)
769 {
770 if (repr && repr->type() == Inkscape::XML::ELEMENT_NODE) {
771 sp_xmlview_attr_list_set_repr(attributes, repr);
772 } else {
773 sp_xmlview_attr_list_set_repr(attributes, NULL);
774 }
776 if (repr && ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE || repr->type() == Inkscape::XML::PI_NODE ) ) {
777 sp_xmlview_content_set_repr(content, repr);
778 } else {
779 sp_xmlview_content_set_repr(content, NULL);
780 }
781 }
784 Inkscape::XML::Node *get_dt_select()
785 {
786 if (!current_desktop) {
787 return NULL;
788 }
790 return sp_desktop_selection(current_desktop)->singleRepr();
791 }
795 void set_dt_select(Inkscape::XML::Node *repr)
796 {
797 if (!current_desktop) {
798 return;
799 }
801 Inkscape::Selection *selection = sp_desktop_selection(current_desktop);
803 SPObject *object;
804 if (repr) {
805 while ( ( repr->type() != Inkscape::XML::ELEMENT_NODE )
806 && sp_repr_parent(repr) )
807 {
808 repr = sp_repr_parent(repr);
809 } // end of while loop
811 object = sp_desktop_document(current_desktop)->getObjectByRepr(repr);
812 } else {
813 object = NULL;
814 }
816 blocked++;
817 if ( object && in_dt_coordsys(*object)
818 && !(SP_IS_STRING(object) ||
819 SP_IS_ROOT(object) ) )
820 {
821 /* We cannot set selection to root or string - they are not items and selection is not
822 * equipped to deal with them */
823 selection->set(SP_ITEM(object));
824 }
825 blocked--;
827 } // end of set_dt_select()
830 void on_tree_select_row(GtkCTree *tree,
831 GtkCTreeNode *node,
832 gint /*column*/,
833 gpointer /*data*/)
834 {
835 if (blocked) {
836 return;
837 }
839 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
840 g_assert(repr != NULL);
842 if (selected_repr == repr) {
843 return;
844 }
846 if (selected_repr) {
847 Inkscape::GC::release(selected_repr);
848 selected_repr = NULL;
849 }
850 selected_repr = repr;
851 Inkscape::GC::anchor(selected_repr);
853 propagate_tree_select(selected_repr);
855 set_dt_select(selected_repr);
857 tree_reset_context();
858 }
860 void on_tree_unselect_row(GtkCTree *tree,
861 GtkCTreeNode *node,
862 gint /*column*/,
863 gpointer /*data*/)
864 {
865 if (blocked) {
866 return;
867 }
869 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
870 propagate_tree_select(NULL);
871 set_dt_select(NULL);
873 if (selected_repr && (selected_repr == repr)) {
874 Inkscape::GC::release(selected_repr);
875 selected_repr = NULL;
876 selected_attr = 0;
877 }
878 }
882 void after_tree_move(GtkCTree */*tree*/,
883 GtkCTreeNode *node,
884 GtkCTreeNode *new_parent,
885 GtkCTreeNode *new_sibling,
886 gpointer /*data*/)
887 {
888 if (GTK_CTREE_ROW(node)->parent == new_parent &&
889 GTK_CTREE_ROW(node)->sibling == new_sibling)
890 {
891 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
892 _("Drag XML subtree"));
893 } else {
894 sp_document_cancel(current_document);
895 }
896 }
899 static void on_destroy(GtkObject */*object*/, gpointer /*data*/)
900 {
901 set_tree_desktop(NULL);
902 gtk_object_destroy(GTK_OBJECT(tooltips));
903 tooltips = NULL;
904 sp_signal_disconnect_by_data(INKSCAPE, dlg);
905 wd.win = dlg = NULL;
906 wd.stop = 0;
908 _message_changed_connection.disconnect();
909 delete _message_context;
910 _message_context = NULL;
911 Inkscape::GC::release(_message_stack);
912 _message_stack = NULL;
913 _message_changed_connection.~connection();
915 status = NULL;
916 }
920 static gboolean on_delete(GtkObject */*object*/, GdkEvent */*event*/, gpointer /*data*/)
921 {
922 gtk_window_get_position((GtkWindow *) dlg, &x, &y);
923 gtk_window_get_size((GtkWindow *) dlg, &w, &h);
925 if (x<0) x=0;
926 if (y<0) y=0;
928 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
929 prefs->setInt(prefs_path + "x", x);
930 prefs->setInt(prefs_path + "y", y);
931 prefs->setInt(prefs_path + "w", w);
932 prefs->setInt(prefs_path + "h", h);
934 return FALSE; // which means, go ahead and destroy it
935 }
938 static void _set_status_message(Inkscape::MessageType /*type*/, const gchar *message, GtkWidget */*dialog*/)
939 {
940 if (status) {
941 gtk_label_set_markup(GTK_LABEL(status), message ? message : "");
942 }
943 }
946 void on_tree_select_row_enable(GtkCTree */*tree*/,
947 GtkCTreeNode */*node*/,
948 gint /*column*/,
949 gpointer data)
950 {
951 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
952 }
956 void on_tree_select_row_enable_if_element(GtkCTree *tree,
957 GtkCTreeNode *node,
958 gint /*column*/,
959 gpointer data )
960 {
961 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
963 if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
964 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
965 } else {
966 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
967 }
968 }
972 void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node,
973 gint /*column*/, gpointer data)
974 {
975 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
977 if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
978 gtk_widget_show(GTK_WIDGET(data));
979 } else {
980 gtk_widget_hide(GTK_WIDGET(data));
981 }
982 }
986 void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node,
987 gint /*column*/, gpointer data)
988 {
989 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
991 if ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE || repr->type() == Inkscape::XML::PI_NODE ) {
992 gtk_widget_show(GTK_WIDGET(data));
993 } else {
994 gtk_widget_hide(GTK_WIDGET(data));
995 }
996 }
999 gboolean xml_tree_node_mutable(GtkCTreeNode *node)
1000 {
1001 // top-level is immutable, obviously
1002 if (!GTK_CTREE_ROW(node)->parent) {
1003 return false;
1004 }
1006 // if not in base level (where namedview, defs, etc go), we're mutable
1007 if (GTK_CTREE_ROW(GTK_CTREE_ROW(node)->parent)->parent) {
1008 return true;
1009 }
1011 Inkscape::XML::Node *repr;
1012 repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1013 g_assert(repr);
1015 // don't let "defs" or "namedview" disappear
1016 if ( !strcmp(repr->name(),"svg:defs") ||
1017 !strcmp(repr->name(),"sodipodi:namedview") ) {
1018 return false;
1019 }
1021 // everyone else is okay, I guess. :)
1022 return true;
1023 }
1026 void on_tree_select_row_enable_if_mutable(GtkCTree */*tree*/, GtkCTreeNode *node,
1027 gint /*column*/, gpointer data)
1028 {
1029 gtk_widget_set_sensitive(GTK_WIDGET(data), xml_tree_node_mutable(node));
1030 }
1034 void on_tree_unselect_row_disable(GtkCTree */*tree*/, GtkCTreeNode */*node*/,
1035 gint /*column*/, gpointer data)
1036 {
1037 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1038 }
1042 void on_tree_unselect_row_hide(GtkCTree */*tree*/, GtkCTreeNode */*node*/,
1043 gint /*column*/, gpointer data)
1044 {
1045 gtk_widget_hide(GTK_WIDGET(data));
1046 }
1050 void on_tree_unselect_row_clear_text(GtkCTree */*tree*/, GtkCTreeNode */*node*/,
1051 gint /*column*/, gpointer data)
1052 {
1053 if (GTK_IS_EDITABLE(data)) {
1054 gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1055 } else if (GTK_IS_TEXT_VIEW(data)) {
1056 GtkTextBuffer *tb;
1057 tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1058 gtk_text_buffer_set_text(tb, "", 0);
1059 }
1060 }
1063 void on_attr_select_row(GtkCList *list, gint row, gint /*column*/,
1064 GdkEventButton */*event*/, gpointer /*data*/)
1065 {
1066 selected_attr = sp_xmlview_attr_list_get_row_key(list, row);
1067 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(attr_value));
1069 attr_reset_context(selected_attr);
1070 }
1073 void on_attr_unselect_row(GtkCList */*list*/, gint /*row*/, gint /*column*/,
1074 GdkEventButton */*event*/, gpointer /*data*/)
1075 {
1076 selected_attr = 0;
1077 attr_reset_context(selected_attr);
1078 }
1081 void on_attr_row_changed(GtkCList *list, gint row, gpointer /*data*/)
1082 {
1083 gint attr = sp_xmlview_attr_list_get_row_key(list, row);
1085 if (attr == selected_attr) {
1086 /* if the attr changed, reselect the row in the list to sync
1087 the edit box */
1089 /*
1090 // get current attr values
1091 const gchar * name = g_quark_to_string (sp_xmlview_attr_list_get_row_key (list, row));
1092 const gchar * value = selected_repr->attribute(name);
1094 g_warning("value: '%s'",value);
1096 // get the edit box value
1097 GtkTextIter start, end;
1098 gtk_text_buffer_get_bounds ( gtk_text_view_get_buffer (attr_value),
1099 &start, &end );
1100 gchar * text = gtk_text_buffer_get_text ( gtk_text_view_get_buffer (attr_value),
1101 &start, &end, TRUE );
1102 g_warning("text: '%s'",text);
1104 // compare to edit box
1105 if (strcmp(text,value)) {
1106 // issue warning if they're different
1107 _message_stack->flash(Inkscape::WARNING_MESSAGE,
1108 _("Attribute changed in GUI while editing values!"));
1109 }
1110 g_free (text);
1112 */
1113 gtk_clist_unselect_row( GTK_CLIST(list), row, 0 );
1114 gtk_clist_select_row( GTK_CLIST(list), row, 0 );
1115 }
1116 }
1119 void on_attr_select_row_set_name_content(GtkCList *list, gint row,
1120 gint /*column*/, GdkEventButton */*event*/,
1121 gpointer data)
1122 {
1123 GtkEditable *editable = GTK_EDITABLE(data);
1124 const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1125 gtk_editable_delete_text(editable, 0, -1);
1126 gint pos = 0;
1127 gtk_editable_insert_text(editable, name, strlen(name), &pos);
1128 }
1132 void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint /*column*/,
1133 GdkEventButton */*event*/,
1134 gpointer data)
1135 {
1136 GtkTextBuffer *tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1137 const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1138 const gchar *value = selected_repr->attribute(name);
1139 if (!value) {
1140 value = "";
1141 }
1142 gtk_text_buffer_set_text(tb, value, strlen(value));
1143 }
1146 void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node,
1147 gint /*column*/, gpointer data)
1148 {
1149 gboolean indentable = FALSE;
1151 if (xml_tree_node_mutable(node)) {
1152 Inkscape::XML::Node *repr, *prev;
1153 repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1155 Inkscape::XML::Node *parent=repr->parent();
1156 if ( parent && repr != parent->firstChild() ) {
1157 g_assert(parent->firstChild());
1159 // skip to the child just before the current repr
1160 for ( prev = parent->firstChild() ;
1161 prev && prev->next() != repr ;
1162 prev = prev->next() );
1164 if (prev && prev->type() == Inkscape::XML::ELEMENT_NODE) {
1165 indentable = TRUE;
1166 }
1167 }
1168 }
1170 gtk_widget_set_sensitive(GTK_WIDGET(data), indentable);
1171 }
1175 void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree,
1176 GtkCTreeNode *node,
1177 gint /*column*/,
1178 gpointer data)
1179 {
1180 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1182 Inkscape::XML::Node *parent=repr->parent();
1183 if ( parent && repr != parent->firstChild() ) {
1184 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1185 } else {
1186 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1187 }
1188 }
1192 void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree,
1193 GtkCTreeNode *node,
1194 gint /*column*/, gpointer data)
1195 {
1196 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1198 Inkscape::XML::Node *parent=repr->parent();
1199 if ( parent && parent->parent() && repr->next() ) {
1200 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1201 } else {
1202 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1203 }
1204 }
1208 void on_tree_select_row_enable_if_has_grandparent(GtkCTree */*tree*/,
1209 GtkCTreeNode *node,
1210 gint /*column*/, gpointer data)
1211 {
1212 GtkCTreeNode *parent = GTK_CTREE_ROW(node)->parent;
1214 if (parent) {
1215 GtkCTreeNode *grandparent = GTK_CTREE_ROW(parent)->parent;
1216 if (grandparent) {
1217 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1218 } else {
1219 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1220 }
1221 } else {
1222 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1223 }
1224 }
1228 void on_attr_select_row_enable(GtkCList */*list*/, gint /*row*/, gint /*column*/,
1229 GdkEventButton */*event*/, gpointer data)
1230 {
1231 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1232 }
1236 void on_attr_unselect_row_disable(GtkCList */*list*/, gint /*row*/, gint /*column*/,
1237 GdkEventButton */*event*/, gpointer data)
1238 {
1239 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1240 }
1244 void on_attr_unselect_row_clear_text(GtkCList */*list*/, gint /*row*/, gint /*column*/,
1245 GdkEventButton */*event*/, gpointer data)
1246 {
1247 if (GTK_IS_EDITABLE(data)) {
1248 gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1249 } else if (GTK_IS_TEXT_VIEW(data)) {
1250 GtkTextBuffer *tb;
1251 tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1252 gtk_text_buffer_set_text(tb, "", 0);
1253 }
1254 }
1258 void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable,
1259 gpointer data)
1260 {
1261 gchar *text = gtk_editable_get_chars(editable, 0, -1);
1263 /* TODO: need to do checking a little more rigorous than this */
1265 if (strlen(text)) {
1266 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1267 } else {
1268 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1269 }
1270 g_free(text);
1271 }
1275 void on_desktop_selection_changed(Inkscape::Selection */*selection*/)
1276 {
1277 if (!blocked++) {
1278 set_tree_select(get_dt_select());
1279 }
1280 blocked--;
1281 }
1283 static void on_document_replaced(SPDesktop *dt, SPDocument *doc)
1284 {
1285 if (current_desktop)
1286 sel_changed_connection.disconnect();
1288 sel_changed_connection = sp_desktop_selection(dt)->connectChanged(&on_desktop_selection_changed);
1289 set_tree_document(doc);
1290 }
1292 void on_document_uri_set(gchar const */*uri*/, SPDocument *document)
1293 {
1294 gchar title[500];
1295 sp_ui_dialog_title_string(Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), title);
1296 gchar *t = g_strdup_printf("%s: %s", SP_DOCUMENT_NAME(document), title);
1297 gtk_window_set_title(GTK_WINDOW(dlg), t);
1298 g_free(t);
1299 }
1303 void on_clicked_get_editable_text(GtkWidget */*widget*/, gpointer data)
1304 {
1305 EditableDest *dest = (EditableDest *) data;
1306 dest->text = gtk_editable_get_chars(dest->editable, 0, -1);
1307 }
1309 gboolean
1310 quit_on_esc (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
1311 {
1312 switch (get_group0_keyval (event)) {
1313 case GDK_Escape: // defocus
1314 gtk_widget_destroy(w);
1315 return TRUE;
1316 }
1317 return FALSE;
1318 }
1320 void cmd_new_element_node(GtkObject */*object*/, gpointer /*data*/)
1321 {
1322 EditableDest name;
1323 GtkWidget *window, *create, *cancel, *vbox, *entry, *bbox, *sep;
1325 g_assert(selected_repr != NULL);
1327 window = sp_window_new(NULL, TRUE);
1328 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
1329 gtk_window_set_title(GTK_WINDOW(window), _("New element node..."));
1330 gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE);
1331 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1332 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(dlg));
1333 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1334 gtk_signal_connect(GTK_OBJECT(window), "destroy", gtk_main_quit, NULL);
1335 gtk_signal_connect(GTK_OBJECT(window), "key-press-event", G_CALLBACK(quit_on_esc), window);
1337 vbox = gtk_vbox_new(FALSE, 4);
1338 gtk_container_add(GTK_CONTAINER(window), vbox);
1340 entry = gtk_entry_new();
1341 gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 0);
1343 sep = gtk_hseparator_new();
1344 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, TRUE, 0);
1346 bbox = gtk_hbutton_box_new();
1347 gtk_container_set_border_width(GTK_CONTAINER(bbox), 4);
1348 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1349 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
1351 cancel = gtk_button_new_with_label(_("Cancel"));
1352 GTK_WIDGET_SET_FLAGS( GTK_WIDGET(cancel),
1353 GTK_CAN_DEFAULT );
1354 gtk_signal_connect_object( GTK_OBJECT(cancel), "clicked",
1355 G_CALLBACK(gtk_widget_destroy),
1356 GTK_OBJECT(window) );
1357 gtk_container_add(GTK_CONTAINER(bbox), cancel);
1359 create = gtk_button_new_with_label(_("Create"));
1360 gtk_widget_set_sensitive(GTK_WIDGET(create), FALSE);
1361 gtk_signal_connect( GTK_OBJECT(entry), "changed",
1362 G_CALLBACK(on_editable_changed_enable_if_valid_xml_name),
1363 create );
1364 gtk_signal_connect( GTK_OBJECT(create), "clicked",
1365 G_CALLBACK(on_clicked_get_editable_text), &name );
1366 gtk_signal_connect_object( GTK_OBJECT(create), "clicked",
1367 G_CALLBACK(gtk_widget_destroy),
1368 GTK_OBJECT(window) );
1369 GTK_WIDGET_SET_FLAGS( GTK_WIDGET(create),
1370 GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT );
1371 gtk_container_add(GTK_CONTAINER(bbox), create);
1373 gtk_widget_show_all(GTK_WIDGET(window));
1374 gtk_window_set_default(GTK_WINDOW(window), GTK_WIDGET(create));
1375 gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(entry));
1377 name.editable = GTK_EDITABLE(entry);
1378 name.text = NULL;
1380 gtk_main();
1382 if (selected_repr != NULL && name.text) {
1383 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(current_document);
1384 Inkscape::XML::Node *new_repr;
1385 new_repr = xml_doc->createElement(name.text);
1386 Inkscape::GC::release(new_repr);
1387 g_free(name.text);
1388 selected_repr->appendChild(new_repr);
1389 set_tree_select(new_repr);
1390 set_dt_select(new_repr);
1392 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1393 _("Create new element node"));
1394 }
1396 } // end of cmd_new_element_node()
1400 void cmd_new_text_node(GtkObject */*object*/, gpointer /*data*/)
1401 {
1402 g_assert(selected_repr != NULL);
1404 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(current_document);
1405 Inkscape::XML::Node *text = xml_doc->createTextNode("");
1406 selected_repr->appendChild(text);
1408 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1409 _("Create new text node"));
1411 set_tree_select(text);
1412 set_dt_select(text);
1414 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(content));
1416 }
1418 void cmd_duplicate_node(GtkObject */*object*/, gpointer /*data*/)
1419 {
1420 g_assert(selected_repr != NULL);
1422 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1423 Inkscape::XML::Node *dup = selected_repr->duplicate(parent->document());
1424 parent->addChild(dup, selected_repr);
1426 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1427 _("Duplicate node"));
1429 GtkCTreeNode *node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), dup);
1431 if (node) {
1432 gtk_ctree_select(GTK_CTREE(tree), node);
1433 }
1434 }
1438 void cmd_delete_node(GtkObject */*object*/, gpointer /*data*/)
1439 {
1440 g_assert(selected_repr != NULL);
1441 sp_repr_unparent(selected_repr);
1443 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1444 _("Delete node"));
1445 }
1449 void cmd_delete_attr(GtkObject */*object*/, gpointer /*data*/)
1450 {
1451 g_assert(selected_repr != NULL);
1452 g_assert(selected_attr != 0);
1453 selected_repr->setAttribute(g_quark_to_string(selected_attr), NULL);
1455 SPObject *updated=current_document->getObjectByRepr(selected_repr);
1456 if (updated) {
1457 // force immediate update of dependant attributes
1458 updated->updateRepr();
1459 }
1461 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1462 _("Delete attribute"));
1463 }
1467 void cmd_set_attr(GtkObject */*object*/, gpointer /*data*/)
1468 {
1469 g_assert(selected_repr != NULL);
1471 gchar *name = gtk_editable_get_chars(attr_name, 0, -1);
1472 GtkTextIter start;
1473 GtkTextIter end;
1474 gtk_text_buffer_get_bounds( gtk_text_view_get_buffer(attr_value),
1475 &start, &end );
1476 gchar *value = gtk_text_buffer_get_text( gtk_text_view_get_buffer(attr_value),
1477 &start, &end, TRUE );
1479 selected_repr->setAttribute(name, value, false);
1481 g_free(name);
1482 g_free(value);
1484 SPObject *updated = current_document->getObjectByRepr(selected_repr);
1485 if (updated) {
1486 // force immediate update of dependant attributes
1487 updated->updateRepr();
1488 }
1490 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1491 _("Change attribute"));
1493 /* TODO: actually, the row won't have been created yet. why? */
1494 gint row = sp_xmlview_attr_list_find_row_from_key(GTK_CLIST(attributes),
1495 g_quark_from_string(name));
1496 if (row != -1) {
1497 gtk_clist_select_row(GTK_CLIST(attributes), row, 0);
1498 }
1499 }
1503 void cmd_raise_node(GtkObject */*object*/, gpointer /*data*/)
1504 {
1505 g_assert(selected_repr != NULL);
1507 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1508 g_return_if_fail(parent != NULL);
1509 g_return_if_fail(parent->firstChild() != selected_repr);
1511 Inkscape::XML::Node *ref = NULL;
1512 Inkscape::XML::Node *before = parent->firstChild();
1513 while (before && before->next() != selected_repr) {
1514 ref = before;
1515 before = before->next();
1516 }
1518 parent->changeOrder(selected_repr, ref);
1520 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1521 _("Raise node"));
1523 set_tree_select(selected_repr);
1524 set_dt_select(selected_repr);
1525 }
1529 void cmd_lower_node(GtkObject */*object*/, gpointer /*data*/)
1530 {
1531 g_assert(selected_repr != NULL);
1532 g_return_if_fail(selected_repr->next() != NULL);
1533 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1535 parent->changeOrder(selected_repr, selected_repr->next());
1537 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1538 _("Lower node"));
1540 set_tree_select(selected_repr);
1541 set_dt_select(selected_repr);
1542 }
1544 void cmd_indent_node(GtkObject */*object*/, gpointer /*data*/)
1545 {
1546 Inkscape::XML::Node *repr = selected_repr;
1547 g_assert(repr != NULL);
1548 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1549 g_return_if_fail(parent != NULL);
1550 g_return_if_fail(parent->firstChild() != repr);
1552 Inkscape::XML::Node* prev = parent->firstChild();
1553 while (prev && prev->next() != repr) {
1554 prev = prev->next();
1555 }
1556 g_return_if_fail(prev != NULL);
1557 g_return_if_fail(prev->type() == Inkscape::XML::ELEMENT_NODE);
1559 Inkscape::XML::Node* ref = NULL;
1560 if (prev->firstChild()) {
1561 for( ref = prev->firstChild() ; ref->next() ; ref = ref->next() );
1562 }
1564 parent->removeChild(repr);
1565 prev->addChild(repr, ref);
1567 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1568 _("Indent node"));
1569 set_tree_select(repr);
1570 set_dt_select(repr);
1572 } // end of cmd_indent_node()
1576 void cmd_unindent_node(GtkObject */*object*/, gpointer /*data*/)
1577 {
1578 Inkscape::XML::Node *repr = selected_repr;
1579 g_assert(repr != NULL);
1580 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1581 g_return_if_fail(parent);
1582 Inkscape::XML::Node *grandparent = sp_repr_parent(parent);
1583 g_return_if_fail(grandparent);
1585 parent->removeChild(repr);
1586 grandparent->addChild(repr, parent);
1588 sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
1589 _("Unindent node"));
1590 set_tree_select(repr);
1591 set_dt_select(repr);
1593 } // end of cmd_unindent_node()
1596 /*
1597 Local Variables:
1598 mode:c++
1599 c-file-style:"stroustrup"
1600 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1601 indent-tabs-mode:nil
1602 fill-column:99
1603 End:
1604 */
1605 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :