fe51f014469e79174d9ad6bd3f5f6b75c892f7a9
1 #define __SP_XMLVIEW_TREE_C__
3 /**
4 * \brief XML View
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * MenTaLguY <mental@rydia.net>
9 * bulia byak <buliabyak@users.sf.net>
10 *
11 * Copyright (C) 1999-2005 Authors
12 * Copyright (C) 2004 David Turner
13 *
14 * Released under GNU GPL, read the file 'COPYING' for more information
15 */
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
21 #include <gtk/gtkmain.h>
22 #include <gtk/gtkhbox.h>
23 #include <gtk/gtkvbox.h>
24 #include <gtk/gtkhpaned.h>
25 #include <gtk/gtkvpaned.h>
26 #include <gtk/gtkhseparator.h>
27 #include <gtk/gtkhbbox.h>
28 #include <gtk/gtktoolbar.h>
29 #include <gtk/gtkscrolledwindow.h>
30 #include <gtk/gtkentry.h>
31 #include <gtk/gtkarrow.h>
33 #include <glibmm/i18n.h>
34 #include "helper/window.h"
35 #include "macros.h"
36 #include "../inkscape.h"
37 #include "../document.h"
38 #include "../desktop-handles.h"
39 #include "desktop.h"
40 #include "../selection.h"
41 #include "../sp-string.h"
42 #include "../sp-tspan.h"
43 #include "../sp-root.h"
44 #include "../event-context.h"
45 #include "in-dt-coordsys.h"
48 #include "../widgets/sp-xmlview-tree.h"
49 #include "../widgets/sp-xmlview-content.h"
50 #include "../widgets/sp-xmlview-attr-list.h"
52 #include "../inkscape-stock.h"
53 #include "widgets/icon.h"
55 #include "dialog-events.h"
56 #include "../prefs-utils.h"
57 #include "../verbs.h"
58 #include "../interface.h"
60 #include "shortcuts.h"
61 #include <gdk/gdkkeysyms.h>
63 #include "message-stack.h"
64 #include "message-context.h"
66 struct EditableDest {
67 GtkEditable *editable;
68 gchar *text;
69 };
71 static GtkWidget *dlg = NULL;
72 static sigc::connection sel_changed_connection;
73 static sigc::connection document_uri_set_connection;
74 static sigc::connection document_replaced_connection;
75 static win_data wd;
76 // impossible original values to make sure they are read from prefs
77 static gint x = -1000, y = -1000, w = 0, h = 0;
78 static gchar *prefs_path = "dialogs.xml";
79 static GtkWidget *status = NULL;
80 static Inkscape::MessageStack *_message_stack = NULL;
81 static Inkscape::MessageContext *_message_context = NULL;
82 static sigc::connection _message_changed_connection;
84 static GtkTooltips *tooltips = NULL;
85 static GtkEditable *attr_name = NULL;
86 static GtkTextView *attr_value = NULL;
87 static SPXMLViewTree *tree = NULL;
88 static SPXMLViewAttrList *attributes = NULL;
89 static SPXMLViewContent *content = NULL;
91 static gint blocked = 0;
92 static SPDesktop *current_desktop = NULL;
93 static SPDocument *current_document = NULL;
94 static gint selected_attr = 0;
95 static Inkscape::XML::Node *selected_repr = NULL;
97 static void sp_xmltree_desktop_change( Inkscape::Application *inkscape, SPDesktop *desktop, GtkWidget *dialog );
99 static void set_tree_desktop(SPDesktop *desktop);
100 static void set_tree_document(SPDocument *document);
101 static void set_tree_repr(Inkscape::XML::Node *repr);
103 static void set_tree_select(Inkscape::XML::Node *repr);
104 static void propagate_tree_select(Inkscape::XML::Node *repr);
106 static Inkscape::XML::Node *get_dt_select();
107 static void set_dt_select(Inkscape::XML::Node *repr);
109 static void on_tree_select_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
110 static void on_tree_unselect_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
111 static void after_tree_move(GtkCTree *tree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling, gpointer data);
112 static void on_destroy(GtkObject *object, gpointer data);
113 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data);
115 static void on_tree_select_row_enable_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
116 static void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
117 static void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
118 static void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
119 static void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
120 static void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
121 static void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
122 static void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
124 static void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
125 static void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
126 static void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
128 static void on_attr_select_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
129 static void on_attr_unselect_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
130 static void on_attr_row_changed( GtkCList *list, gint row, gpointer data );
132 static void on_attr_select_row_enable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
133 static void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
135 static void on_attr_select_row_set_name_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
136 static void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
137 static void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
139 static void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable, gpointer data);
141 static void on_desktop_selection_changed(Inkscape::Selection *selection);
142 static void on_document_replaced(SPDesktop *dt, SPDocument *document);
143 static void on_document_uri_set(gchar const *uri, SPDocument *document);
145 static void on_clicked_get_editable_text(GtkWidget *widget, gpointer data);
147 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog);
149 static void cmd_new_element_node(GtkObject *object, gpointer data);
150 static void cmd_new_text_node(GtkObject *object, gpointer data);
151 static void cmd_duplicate_node(GtkObject *object, gpointer data);
152 static void cmd_delete_node(GtkObject *object, gpointer data);
154 static void cmd_raise_node(GtkObject *object, gpointer data);
155 static void cmd_lower_node(GtkObject *object, gpointer data);
156 static void cmd_indent_node(GtkObject *object, gpointer data);
157 static void cmd_unindent_node(GtkObject *object, gpointer data);
159 static void cmd_delete_attr(GtkObject *object, gpointer data);
160 static void cmd_set_attr(GtkObject *object, gpointer data);
162 static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event);
165 /*
166 * \brief Sets the XML status bar when the tree is selected.
167 */
168 void tree_reset_context()
169 {
170 _message_context->set(Inkscape::NORMAL_MESSAGE,
171 _("<b>Click</b> to select nodes, <b>drag</b> to rearrange."));
172 }
175 /*
176 * \brief Sets the XML status bar, depending on which attr is selected.
177 */
178 void attr_reset_context(gint attr)
179 {
180 if (attr == 0) {
181 _message_context->set(Inkscape::NORMAL_MESSAGE,
182 _("<b>Click</b> attribute to edit."));
183 }
184 else {
185 const gchar *name = g_quark_to_string(attr);
186 gchar *message = g_strdup_printf(_("Attribute <b>%s</b> selected. Press <b>Ctrl+Enter</b> when done editing to commit changes."), name);
187 _message_context->set(Inkscape::NORMAL_MESSAGE, message);
188 g_free(message);
189 }
190 }
193 void sp_xml_tree_dialog()
194 {
195 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
197 if (!desktop) {
198 return;
199 }
201 if (dlg == NULL)
202 { // very long block
204 GtkWidget *box, *sw, *paned, *toolbar, *button;
205 GtkWidget *text_container, *attr_container, *attr_subpaned_container, *box2;
206 GtkWidget *set_attr;
208 tooltips = gtk_tooltips_new();
209 gtk_tooltips_enable(tooltips);
211 dlg = sp_window_new("", TRUE);
212 if (x == -1000 || y == -1000) {
213 x = prefs_get_int_attribute(prefs_path, "x", 0);
214 y = prefs_get_int_attribute(prefs_path, "y", 0);
215 }
216 if (w ==0 || h == 0) {
217 w = prefs_get_int_attribute(prefs_path, "w", 0);
218 h = prefs_get_int_attribute(prefs_path, "h", 0);
219 }
220 if (x != 0 || y != 0) {
221 gtk_window_move((GtkWindow *) dlg, x, y);
222 } else {
223 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
224 }
226 if (w && h) {
227 gtk_window_resize((GtkWindow *) dlg, w, h);
228 }
229 sp_transientize(dlg);
230 wd.win = dlg;
231 wd.stop = 0;
232 g_signal_connect ( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd );
234 gtk_signal_connect( GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg );
236 gtk_signal_connect( GTK_OBJECT(dlg), "destroy", G_CALLBACK(on_destroy), dlg);
237 gtk_signal_connect( GTK_OBJECT(dlg), "delete_event", G_CALLBACK(on_delete), dlg);
238 g_signal_connect ( G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(on_delete), dlg);
240 g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg);
241 g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg);
244 gtk_container_set_border_width(GTK_CONTAINER(dlg), 0);
245 gtk_window_set_default_size(GTK_WINDOW(dlg), 640, 384);
247 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
248 gtk_container_add(GTK_CONTAINER(dlg), vbox);
250 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
251 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
253 status = gtk_label_new(NULL);
254 gtk_misc_set_alignment(GTK_MISC(status), 0.0, 0.5);
255 gtk_widget_set_size_request(status, 1, -1);
256 gtk_label_set_markup(GTK_LABEL(status), "");
257 gtk_box_pack_start(GTK_BOX(hbox), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 4);
258 gtk_box_pack_start(GTK_BOX(hbox), status, TRUE, TRUE, 0);
260 paned = gtk_hpaned_new();
261 gtk_paned_set_position(GTK_PANED(paned), 256);
262 gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 0);
264 _message_stack = new Inkscape::MessageStack();
265 _message_context = new Inkscape::MessageContext(_message_stack);
266 _message_changed_connection = _message_stack->connectChanged(
267 sigc::bind(sigc::ptr_fun(_set_status_message), dlg)
268 );
270 /* tree view */
272 box = gtk_vbox_new(FALSE, 0);
273 gtk_paned_pack1(GTK_PANED(paned), box, FALSE, FALSE);
275 tree = SP_XMLVIEW_TREE(sp_xmlview_tree_new(NULL, NULL, NULL));
276 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(tree),
277 _("Drag to reorder nodes"), NULL );
279 g_signal_connect( G_OBJECT(tree), "tree_select_row",
280 G_CALLBACK(on_tree_select_row), NULL );
282 g_signal_connect( G_OBJECT(tree), "tree_unselect_row",
283 G_CALLBACK(on_tree_unselect_row), NULL );
285 g_signal_connect_after( G_OBJECT(tree), "tree_move",
286 G_CALLBACK(after_tree_move), NULL);
288 /* TODO: replace gtk_signal_connect_while_alive() with something
289 * else...
290 */
291 toolbar = gtk_toolbar_new();
292 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
293 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
295 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
296 NULL,
297 _("New element node"),
298 NULL,
299 sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
300 INKSCAPE_STOCK_ADD_XML_ELEMENT_NODE ),
301 G_CALLBACK(cmd_new_element_node),
302 NULL);
304 gtk_signal_connect_while_alive( GTK_OBJECT(tree),
305 "tree_select_row",
306 G_CALLBACK(on_tree_select_row_enable_if_element),
307 button,
308 GTK_OBJECT(button));
310 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
311 "tree_unselect_row",
312 G_CALLBACK(on_tree_unselect_row_disable),
313 button,
314 GTK_OBJECT(button));
316 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
318 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
319 NULL, _("New text node"), NULL,
320 sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
321 INKSCAPE_STOCK_ADD_XML_TEXT_NODE ),
322 G_CALLBACK(cmd_new_text_node),
323 NULL);
325 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
326 "tree_select_row",
327 G_CALLBACK(on_tree_select_row_enable_if_element),
328 button,
329 GTK_OBJECT(button));
331 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
332 "tree_unselect_row",
333 G_CALLBACK(on_tree_unselect_row_disable),
334 button,
335 GTK_OBJECT(button));
337 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
339 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
340 NULL, _("Duplicate node"), NULL,
341 sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
342 INKSCAPE_STOCK_DUPLICATE_XML_NODE ),
343 G_CALLBACK(cmd_duplicate_node),
344 NULL);
346 gtk_signal_connect_while_alive(GTK_OBJECT(tree),
347 "tree_select_row",
348 G_CALLBACK(on_tree_select_row_enable_if_mutable),
349 button,
350 GTK_OBJECT(button));
352 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
353 G_CALLBACK(on_tree_unselect_row_disable),
354 button, GTK_OBJECT(button));
356 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
358 gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
360 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
361 NULL, _("Delete node"), NULL,
362 sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
363 INKSCAPE_STOCK_DELETE_XML_NODE ),
364 G_CALLBACK(cmd_delete_node), NULL );
366 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
367 G_CALLBACK(on_tree_select_row_enable_if_mutable),
368 button, GTK_OBJECT(button));
369 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
370 G_CALLBACK(on_tree_unselect_row_disable),
371 button, GTK_OBJECT(button));
372 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
374 gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
376 button = gtk_toolbar_append_item( GTK_TOOLBAR(toolbar), "<",
377 _("Unindent node"), NULL,
378 gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_IN),
379 G_CALLBACK(cmd_unindent_node), NULL);
381 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
382 G_CALLBACK(on_tree_select_row_enable_if_has_grandparent),
383 button, GTK_OBJECT(button));
385 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
386 G_CALLBACK(on_tree_unselect_row_disable),
387 button, GTK_OBJECT(button));
389 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
391 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), ">",
392 _("Indent node"), NULL,
393 gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_IN),
394 G_CALLBACK(cmd_indent_node), NULL);
395 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
396 G_CALLBACK(on_tree_select_row_enable_if_indentable),
397 button, GTK_OBJECT(button));
398 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
399 (GCallback) on_tree_unselect_row_disable,
400 button, GTK_OBJECT(button));
401 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
403 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "^",
404 _("Raise node"), NULL,
405 gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_IN),
406 G_CALLBACK(cmd_raise_node), NULL);
407 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
408 G_CALLBACK(on_tree_select_row_enable_if_not_first_child),
409 button, GTK_OBJECT(button));
410 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
411 G_CALLBACK(on_tree_unselect_row_disable),
412 button, GTK_OBJECT(button));
413 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
415 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "v",
416 _("Lower node"), NULL,
417 gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_IN),
418 G_CALLBACK(cmd_lower_node), NULL);
419 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
420 G_CALLBACK(on_tree_select_row_enable_if_not_last_child),
421 button, GTK_OBJECT(button));
422 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
423 G_CALLBACK(on_tree_unselect_row_disable),
424 button, GTK_OBJECT(button));
425 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
427 gtk_box_pack_start(GTK_BOX(box), toolbar, FALSE, TRUE, 0);
429 sw = gtk_scrolled_window_new(NULL, NULL);
430 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
431 GTK_POLICY_AUTOMATIC,
432 GTK_POLICY_AUTOMATIC );
433 gtk_box_pack_start(GTK_BOX(box), sw, TRUE, TRUE, 0);
435 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(tree));
437 /* node view */
439 box = gtk_vbox_new(FALSE, 0);
440 gtk_paned_pack2(GTK_PANED(paned), box, TRUE, TRUE);
442 /* attributes */
444 attr_container = gtk_vbox_new(FALSE, 0);
445 gtk_box_pack_start( GTK_BOX(box), GTK_WIDGET(attr_container),
446 TRUE, TRUE, 0 );
448 attributes = SP_XMLVIEW_ATTR_LIST(sp_xmlview_attr_list_new(NULL));
449 g_signal_connect( G_OBJECT(attributes), "select_row",
450 G_CALLBACK(on_attr_select_row), NULL);
451 g_signal_connect( G_OBJECT(attributes), "unselect_row",
452 G_CALLBACK(on_attr_unselect_row), NULL);
453 g_signal_connect( G_OBJECT(attributes), "row-value-changed",
454 G_CALLBACK(on_attr_row_changed), NULL);
456 toolbar = gtk_toolbar_new();
457 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
458 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
460 button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
461 NULL, _("Delete attribute"), NULL,
462 sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
463 INKSCAPE_STOCK_DELETE_XML_ATTRIBUTE ),
464 (GCallback) cmd_delete_attr, NULL);
466 gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "select_row",
467 (GCallback) on_attr_select_row_enable, button,
468 GTK_OBJECT(button));
470 gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "unselect_row",
471 (GCallback) on_attr_unselect_row_disable, button,
472 GTK_OBJECT(button));
474 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
475 (GCallback) on_tree_unselect_row_disable, button,
476 GTK_OBJECT(button));
478 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
480 gtk_box_pack_start( GTK_BOX(attr_container),
481 GTK_WIDGET(toolbar), FALSE, TRUE, 0 );
483 attr_subpaned_container = gtk_vpaned_new();
484 gtk_box_pack_start( GTK_BOX(attr_container),
485 GTK_WIDGET(attr_subpaned_container),
486 TRUE, TRUE, 0 );
487 gtk_widget_show(attr_subpaned_container);
489 sw = gtk_scrolled_window_new(NULL, NULL);
490 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
491 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
492 gtk_paned_pack1( GTK_PANED(attr_subpaned_container),
493 GTK_WIDGET(sw), TRUE, TRUE );
494 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(attributes));
496 toolbar = gtk_vbox_new(FALSE, 4);
497 gtk_container_set_border_width(GTK_CONTAINER(toolbar), 4);
499 box2 = gtk_hbox_new(FALSE, 4);
500 gtk_box_pack_start( GTK_BOX(toolbar), GTK_WIDGET(box2),
501 FALSE, TRUE, 0);
503 attr_name = GTK_EDITABLE(gtk_entry_new());
504 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_name),
505 // TRANSLATORS: "Attribute" is a noun here
506 _("Attribute name"), NULL );
508 gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
509 (GCallback) on_attr_select_row_set_name_content,
510 attr_name);
512 gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
513 (GCallback) on_attr_unselect_row_clear_text,
514 attr_name);
516 gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
517 (GCallback) on_tree_unselect_row_clear_text,
518 attr_name);
520 gtk_box_pack_start( GTK_BOX(box2), GTK_WIDGET(attr_name),
521 TRUE, TRUE, 0);
523 set_attr = gtk_button_new();
524 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(set_attr),
525 // TRANSLATORS: "Set" is a verb here
526 _("Set attribute"), NULL );
527 // TRANSLATORS: "Set" is a verb here
528 GtkWidget *set_label = gtk_label_new(_("Set"));
529 gtk_container_add(GTK_CONTAINER(set_attr), set_label);
531 gtk_signal_connect( GTK_OBJECT(set_attr), "clicked",
532 (GCallback) cmd_set_attr, NULL);
533 gtk_signal_connect( GTK_OBJECT(attr_name), "changed",
534 (GCallback) on_editable_changed_enable_if_valid_xml_name,
535 set_attr );
536 gtk_widget_set_sensitive(GTK_WIDGET(set_attr), FALSE);
538 gtk_box_pack_start(GTK_BOX(box2), set_attr, FALSE, FALSE, 0);
540 sw = gtk_scrolled_window_new(NULL, NULL);
541 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
542 GTK_POLICY_AUTOMATIC,
543 GTK_POLICY_AUTOMATIC );
544 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
545 gtk_box_pack_start(GTK_BOX(toolbar), sw, TRUE, TRUE, 0);
547 attr_value =(GtkTextView *) gtk_text_view_new();
548 gtk_text_view_set_wrap_mode((GtkTextView *) attr_value, GTK_WRAP_CHAR);
549 gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_value),
550 // TRANSLATORS: "Attribute" is a noun here
551 _("Attribute value"), NULL );
552 gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
553 (GCallback) on_attr_select_row_set_value_content,
554 attr_value );
555 gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
556 (GCallback) on_attr_unselect_row_clear_text,
557 attr_value );
558 gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
559 (GCallback) on_tree_unselect_row_clear_text,
560 attr_value );
561 gtk_text_view_set_editable(attr_value, TRUE);
562 gtk_container_add( GTK_CONTAINER(sw),
563 GTK_WIDGET(attr_value) );
565 gtk_paned_pack2( GTK_PANED(attr_subpaned_container),
566 GTK_WIDGET(toolbar), FALSE, TRUE );
568 /* text */
570 sw = gtk_scrolled_window_new(NULL, NULL);
571 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
572 GTK_POLICY_AUTOMATIC,
573 GTK_POLICY_AUTOMATIC );
574 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
575 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(sw), TRUE, TRUE, 0);
577 content = SP_XMLVIEW_CONTENT(sp_xmlview_content_new(NULL));
578 gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(content));
580 text_container = sw;
582 /* initial show/hide */
584 gtk_widget_show_all(GTK_WIDGET(dlg));
586 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
587 (GCallback) on_tree_select_row_show_if_element,
588 attr_container, GTK_OBJECT(attr_container));
590 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
591 (GCallback) on_tree_unselect_row_hide,
592 attr_container, GTK_OBJECT(attr_container));
594 gtk_widget_hide(attr_container);
596 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
597 (GCallback) on_tree_select_row_show_if_text,
598 text_container, GTK_OBJECT(text_container));
600 gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
601 (GCallback) on_tree_unselect_row_hide,
602 text_container, GTK_OBJECT(text_container));
604 gtk_widget_hide(text_container);
606 g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop",
607 G_CALLBACK(sp_xmltree_desktop_change), dlg);
609 g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop",
610 G_CALLBACK(sp_xmltree_desktop_change), dlg);
612 g_signal_connect((GObject *) dlg, "key_press_event", (GCallback) sp_xml_tree_key_press, NULL);
614 tree_reset_context();
615 } // end of if (dlg == NULL)
617 gtk_window_present((GtkWindow *) dlg);
619 g_assert(desktop != NULL);
620 set_tree_desktop(desktop);
622 } // end of sp_xml_tree_dialog()
624 static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event)
625 {
627 unsigned int shortcut = get_group0_keyval(event) |
628 ( event->state & GDK_SHIFT_MASK ?
629 SP_SHORTCUT_SHIFT_MASK : 0 ) |
630 ( event->state & GDK_CONTROL_MASK ?
631 SP_SHORTCUT_CONTROL_MASK : 0 ) |
632 ( event->state & GDK_MOD1_MASK ?
633 SP_SHORTCUT_ALT_MASK : 0 );
635 /* fixme: if you need to add more xml-tree-specific callbacks, you should probably upgrade
636 * the sp_shortcut mechanism to take into account windows. */
637 if (shortcut == (SP_SHORTCUT_CONTROL_MASK | GDK_Return)) {
638 cmd_set_attr(NULL, NULL);
639 return true;
640 }
641 return false;
642 }
645 static void sp_xmltree_desktop_change(Inkscape::Application *inkscape,
646 SPDesktop *desktop,
647 GtkWidget *dialog )
648 {
649 if (!desktop) {
650 return;
651 }
652 set_tree_desktop(desktop);
653 }
656 void set_tree_desktop(SPDesktop *desktop)
657 {
658 if ( desktop == current_desktop ) {
659 return;
660 }
662 if (current_desktop) {
663 sel_changed_connection.disconnect();
664 document_replaced_connection.disconnect();
665 }
666 current_desktop = desktop;
667 if (desktop) {
668 sel_changed_connection = SP_DT_SELECTION(desktop)->connectChanged(&on_desktop_selection_changed);
669 document_replaced_connection = desktop->connectDocumentReplaced(&on_document_replaced);
670 set_tree_document(SP_DT_DOCUMENT(desktop));
671 } else {
672 set_tree_document(NULL);
673 }
675 } // end of set_tree_desktop()
679 void set_tree_document(SPDocument *document)
680 {
681 if (document == current_document) {
682 return;
683 }
685 if (current_document) {
686 document_uri_set_connection.disconnect();
687 }
688 current_document = document;
689 if (current_document) {
691 document_uri_set_connection = current_document->connectURISet(sigc::bind(sigc::ptr_fun(&on_document_uri_set), current_document));
692 on_document_uri_set(SP_DOCUMENT_URI(current_document), current_document);
693 set_tree_repr(sp_document_repr_root(current_document));
695 } else {
696 set_tree_repr(NULL);
697 }
698 }
702 void set_tree_repr(Inkscape::XML::Node *repr)
703 {
704 if (repr == selected_repr) {
705 return;
706 }
708 gtk_clist_freeze(GTK_CLIST(tree));
710 sp_xmlview_tree_set_repr(tree, repr);
712 if (repr) {
713 set_tree_select(get_dt_select());
714 } else {
715 set_tree_select(NULL);
716 }
718 gtk_clist_thaw(GTK_CLIST(tree));
720 propagate_tree_select(selected_repr);
722 }
726 void set_tree_select(Inkscape::XML::Node *repr)
727 {
728 if (selected_repr) {
729 Inkscape::GC::release(selected_repr);
730 }
732 selected_repr = repr;
733 if (repr) {
734 GtkCTreeNode *node;
736 Inkscape::GC::anchor(selected_repr);
738 node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), repr);
739 if (node) {
740 GtkCTreeNode *parent;
742 gtk_ctree_select(GTK_CTREE(tree), node);
744 parent = GTK_CTREE_ROW(node)->parent;
745 while (parent) {
746 gtk_ctree_expand(GTK_CTREE(tree), parent);
747 parent = GTK_CTREE_ROW(parent)->parent;
748 }
750 gtk_ctree_node_moveto(GTK_CTREE(tree), node, 0, 0.66, 0.0);
751 }
752 } else {
753 gtk_clist_unselect_all(GTK_CLIST(tree));
754 }
755 propagate_tree_select(repr);
756 }
760 void propagate_tree_select(Inkscape::XML::Node *repr)
761 {
762 if (repr && repr->type() == Inkscape::XML::ELEMENT_NODE) {
763 sp_xmlview_attr_list_set_repr(attributes, repr);
764 } else {
765 sp_xmlview_attr_list_set_repr(attributes, NULL);
766 }
768 if (repr && ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE ) ) {
769 sp_xmlview_content_set_repr(content, repr);
770 } else {
771 sp_xmlview_content_set_repr(content, NULL);
772 }
773 }
776 Inkscape::XML::Node *get_dt_select()
777 {
778 if (!current_desktop) {
779 return NULL;
780 }
782 return SP_DT_SELECTION(current_desktop)->singleRepr();
783 }
787 void set_dt_select(Inkscape::XML::Node *repr)
788 {
789 if (!current_desktop) {
790 return;
791 }
793 Inkscape::Selection *selection = SP_DT_SELECTION(current_desktop);
795 SPObject *object;
796 if (repr) {
797 while ( ( repr->type() != Inkscape::XML::ELEMENT_NODE )
798 && sp_repr_parent(repr) )
799 {
800 repr = sp_repr_parent(repr);
801 } // end of while loop
803 object = SP_DT_DOCUMENT(current_desktop)->getObjectByRepr(repr);
804 } else {
805 object = NULL;
806 }
808 blocked++;
809 if ( object && in_dt_coordsys(*object)
810 && !(SP_IS_STRING(object) ||
811 SP_IS_ROOT(object) ) )
812 {
813 /* We cannot set selection to root or string - they are not items and selection is not
814 * equipped to deal with them */
815 selection->set(SP_ITEM(object));
816 }
817 blocked--;
819 } // end of set_dt_select()
822 void on_tree_select_row(GtkCTree *tree,
823 GtkCTreeNode *node,
824 gint column,
825 gpointer data)
826 {
827 if (blocked) {
828 return;
829 }
831 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
832 g_assert(repr != NULL);
834 if (selected_repr == repr) {
835 return;
836 }
838 if (selected_repr) {
839 Inkscape::GC::release(selected_repr);
840 selected_repr = NULL;
841 }
842 selected_repr = repr;
843 Inkscape::GC::anchor(selected_repr);
845 propagate_tree_select(selected_repr);
847 set_dt_select(selected_repr);
849 tree_reset_context();
850 }
852 void on_tree_unselect_row(GtkCTree *tree,
853 GtkCTreeNode *node,
854 gint column,
855 gpointer data)
856 {
857 if (blocked) {
858 return;
859 }
861 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
862 propagate_tree_select(NULL);
863 set_dt_select(NULL);
865 if (selected_repr && (selected_repr == repr)) {
866 Inkscape::GC::release(selected_repr);
867 selected_repr = NULL;
868 selected_attr = 0;
869 }
870 }
874 void after_tree_move(GtkCTree *tree,
875 GtkCTreeNode *node,
876 GtkCTreeNode *new_parent,
877 GtkCTreeNode *new_sibling,
878 gpointer data)
879 {
880 if (GTK_CTREE_ROW(node)->parent == new_parent &&
881 GTK_CTREE_ROW(node)->sibling == new_sibling)
882 {
883 sp_document_done(current_document);
884 } else {
885 sp_document_cancel(current_document);
886 }
887 }
890 static void on_destroy(GtkObject *object, gpointer data)
891 {
892 set_tree_desktop(NULL);
893 gtk_object_destroy(GTK_OBJECT(tooltips));
894 tooltips = NULL;
895 sp_signal_disconnect_by_data(INKSCAPE, dlg);
896 wd.win = dlg = NULL;
897 wd.stop = 0;
899 _message_changed_connection.disconnect();
900 delete _message_context;
901 _message_context = NULL;
902 Inkscape::GC::release(_message_stack);
903 _message_stack = NULL;
904 _message_changed_connection.~connection();
906 status = NULL;
907 }
911 static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data)
912 {
913 gtk_window_get_position((GtkWindow *) dlg, &x, &y);
914 gtk_window_get_size((GtkWindow *) dlg, &w, &h);
916 prefs_set_int_attribute(prefs_path, "x", x);
917 prefs_set_int_attribute(prefs_path, "y", y);
918 prefs_set_int_attribute(prefs_path, "w", w);
919 prefs_set_int_attribute(prefs_path, "h", h);
921 return FALSE; // which means, go ahead and destroy it
922 }
925 static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog)
926 {
927 if (status) {
928 gtk_label_set_markup(GTK_LABEL(status), message ? message : "");
929 }
930 }
933 void on_tree_select_row_enable(GtkCTree *tree,
934 GtkCTreeNode *node,
935 gint column,
936 gpointer data)
937 {
938 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
939 }
943 void on_tree_select_row_enable_if_element(GtkCTree *tree,
944 GtkCTreeNode *node,
945 gint column,
946 gpointer data )
947 {
948 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
950 if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
951 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
952 } else {
953 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
954 }
955 }
959 void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node,
960 gint column, gpointer data)
961 {
962 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
964 if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
965 gtk_widget_show(GTK_WIDGET(data));
966 } else {
967 gtk_widget_hide(GTK_WIDGET(data));
968 }
969 }
973 void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node,
974 gint column, gpointer data)
975 {
976 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
978 if ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE ) {
979 gtk_widget_show(GTK_WIDGET(data));
980 } else {
981 gtk_widget_hide(GTK_WIDGET(data));
982 }
983 }
986 gboolean xml_tree_node_mutable(GtkCTreeNode *node)
987 {
988 // top-level is immutable, obviously
989 if (!GTK_CTREE_ROW(node)->parent) {
990 return false;
991 }
993 // if not in base level (where namedview, defs, etc go), we're mutable
994 if (GTK_CTREE_ROW(GTK_CTREE_ROW(node)->parent)->parent) {
995 return true;
996 }
998 Inkscape::XML::Node *repr;
999 repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1000 g_assert(repr);
1002 // don't let "defs" or "namedview" disappear
1003 if ( !strcmp(repr->name(),"svg:defs") ||
1004 !strcmp(repr->name(),"sodipodi:namedview") ) {
1005 return false;
1006 }
1008 // everyone else is okay, I guess. :)
1009 return true;
1010 }
1013 void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node,
1014 gint column, gpointer data)
1015 {
1016 gtk_widget_set_sensitive(GTK_WIDGET(data), xml_tree_node_mutable(node));
1017 }
1021 void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node,
1022 gint column, gpointer data)
1023 {
1024 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1025 }
1029 void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node,
1030 gint column, gpointer data)
1031 {
1032 gtk_widget_hide(GTK_WIDGET(data));
1033 }
1037 void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node,
1038 gint column, gpointer data)
1039 {
1040 if (GTK_IS_EDITABLE(data)) {
1041 gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1042 } else if (GTK_IS_TEXT_VIEW(data)) {
1043 GtkTextBuffer *tb;
1044 tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1045 gtk_text_buffer_set_text(tb, "", 0);
1046 }
1047 }
1050 void on_attr_select_row(GtkCList *list, gint row, gint column,
1051 GdkEventButton *event, gpointer data)
1052 {
1053 selected_attr = sp_xmlview_attr_list_get_row_key(list, row);
1054 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(attr_value));
1056 attr_reset_context(selected_attr);
1057 }
1060 void on_attr_unselect_row(GtkCList *list, gint row, gint column,
1061 GdkEventButton *event, gpointer data)
1062 {
1063 selected_attr = 0;
1064 attr_reset_context(selected_attr);
1065 }
1068 void on_attr_row_changed(GtkCList *list, gint row, gpointer data)
1069 {
1070 gint attr = sp_xmlview_attr_list_get_row_key(list, row);
1072 if (attr == selected_attr) {
1073 /* if the attr changed, reselect the row in the list to sync
1074 the edit box */
1076 /*
1077 // get current attr values
1078 const gchar * name = g_quark_to_string (sp_xmlview_attr_list_get_row_key (list, row));
1079 const gchar * value = selected_repr->attribute(name);
1081 g_warning("value: '%s'",value);
1083 // get the edit box value
1084 GtkTextIter start, end;
1085 gtk_text_buffer_get_bounds ( gtk_text_view_get_buffer (attr_value),
1086 &start, &end );
1087 gchar * text = gtk_text_buffer_get_text ( gtk_text_view_get_buffer (attr_value),
1088 &start, &end, TRUE );
1089 g_warning("text: '%s'",text);
1091 // compare to edit box
1092 if (strcmp(text,value)) {
1093 // issue warning if they're different
1094 _message_stack->flash(Inkscape::WARNING_MESSAGE,
1095 _("Attribute changed in GUI while editing values!"));
1096 }
1097 g_free (text);
1099 */
1100 gtk_clist_unselect_row( GTK_CLIST(list), row, 0 );
1101 gtk_clist_select_row( GTK_CLIST(list), row, 0 );
1102 }
1103 }
1106 void on_attr_select_row_set_name_content(GtkCList *list, gint row,
1107 gint column, GdkEventButton *event,
1108 gpointer data)
1109 {
1110 GtkEditable *editable = GTK_EDITABLE(data);
1111 const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1112 gtk_editable_delete_text(editable, 0, -1);
1113 gint pos = 0;
1114 gtk_editable_insert_text(editable, name, strlen(name), &pos);
1115 }
1119 void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column,
1120 GdkEventButton *event,
1121 gpointer data)
1122 {
1123 GtkTextBuffer *tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1124 const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
1125 const gchar *value = selected_repr->attribute(name);
1126 if (!value) {
1127 value = "";
1128 }
1129 gtk_text_buffer_set_text(tb, value, strlen(value));
1130 }
1133 void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node,
1134 gint column, gpointer data)
1135 {
1136 gboolean indentable = FALSE;
1138 if (xml_tree_node_mutable(node)) {
1139 Inkscape::XML::Node *repr, *prev;
1140 repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1142 Inkscape::XML::Node *parent=repr->parent();
1143 if ( parent && repr != parent->firstChild() ) {
1144 g_assert(parent->firstChild());
1146 // skip to the child just before the current repr
1147 for ( prev = parent->firstChild() ;
1148 prev && prev->next() != repr ;
1149 prev = prev->next() );
1151 if (prev && prev->type() == Inkscape::XML::ELEMENT_NODE) {
1152 indentable = TRUE;
1153 }
1154 }
1155 }
1157 gtk_widget_set_sensitive(GTK_WIDGET(data), indentable);
1158 }
1162 void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree,
1163 GtkCTreeNode *node,
1164 gint column,
1165 gpointer data)
1166 {
1167 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1169 Inkscape::XML::Node *parent=repr->parent();
1170 if ( parent && repr != parent->firstChild() ) {
1171 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1172 } else {
1173 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1174 }
1175 }
1179 void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree,
1180 GtkCTreeNode *node,
1181 gint column, gpointer data)
1182 {
1183 Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
1185 Inkscape::XML::Node *parent=repr->parent();
1186 if ( parent && parent->parent() && repr->next() ) {
1187 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1188 } else {
1189 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1190 }
1191 }
1195 void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree,
1196 GtkCTreeNode *node,
1197 gint column, gpointer data)
1198 {
1199 GtkCTreeNode *parent = GTK_CTREE_ROW(node)->parent;
1201 if (parent) {
1202 GtkCTreeNode *grandparent = GTK_CTREE_ROW(parent)->parent;
1203 if (grandparent) {
1204 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1205 } else {
1206 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1207 }
1208 } else {
1209 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1210 }
1211 }
1215 void on_attr_select_row_enable(GtkCList *list, gint row, gint column,
1216 GdkEventButton *event, gpointer data)
1217 {
1218 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1219 }
1223 void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column,
1224 GdkEventButton *event, gpointer data)
1225 {
1226 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1227 }
1231 void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column,
1232 GdkEventButton *event, gpointer data)
1233 {
1234 if (GTK_IS_EDITABLE(data)) {
1235 gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
1236 } else if (GTK_IS_TEXT_VIEW(data)) {
1237 GtkTextBuffer *tb;
1238 tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
1239 gtk_text_buffer_set_text(tb, "", 0);
1240 }
1241 }
1245 void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable,
1246 gpointer data)
1247 {
1248 gchar *text = gtk_editable_get_chars(editable, 0, -1);
1250 /* TODO: need to do checking a little more rigorous than this */
1252 if (strlen(text)) {
1253 gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
1254 } else {
1255 gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
1256 }
1257 g_free(text);
1258 }
1262 void on_desktop_selection_changed(Inkscape::Selection *selection)
1263 {
1264 if (!blocked++) {
1265 set_tree_select(get_dt_select());
1266 }
1267 blocked--;
1268 }
1270 static void on_document_replaced(SPDesktop *dt, SPDocument *doc)
1271 {
1272 if (current_desktop)
1273 sel_changed_connection.disconnect();
1275 sel_changed_connection = SP_DT_SELECTION(dt)->connectChanged(&on_desktop_selection_changed);
1276 set_tree_document(doc);
1277 }
1279 void on_document_uri_set(gchar const *uri, SPDocument *document)
1280 {
1281 gchar title[500];
1282 sp_ui_dialog_title_string(Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), title);
1283 gchar *t = g_strdup_printf("%s: %s", SP_DOCUMENT_NAME(document), title);
1284 gtk_window_set_title(GTK_WINDOW(dlg), t);
1285 g_free(t);
1286 }
1290 void on_clicked_get_editable_text(GtkWidget *widget, gpointer data)
1291 {
1292 EditableDest *dest = (EditableDest *) data;
1293 dest->text = gtk_editable_get_chars(dest->editable, 0, -1);
1294 }
1298 void cmd_new_element_node(GtkObject *object, gpointer data)
1299 {
1300 EditableDest name;
1301 GtkWidget *window, *create, *cancel, *vbox, *entry, *bbox, *sep;
1303 g_assert(selected_repr != NULL);
1305 window = sp_window_new(NULL, TRUE);
1306 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
1307 gtk_window_set_title(GTK_WINDOW(window), _("New element node..."));
1308 gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE);
1309 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1310 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(dlg));
1311 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1312 gtk_signal_connect(GTK_OBJECT(window), "destroy", gtk_main_quit, NULL);
1314 vbox = gtk_vbox_new(FALSE, 4);
1315 gtk_container_add(GTK_CONTAINER(window), vbox);
1317 entry = gtk_entry_new();
1318 gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 0);
1320 sep = gtk_hseparator_new();
1321 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, TRUE, 0);
1323 bbox = gtk_hbutton_box_new();
1324 gtk_container_set_border_width(GTK_CONTAINER(bbox), 4);
1325 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1326 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
1328 cancel = gtk_button_new_with_label(_("Cancel"));
1329 gtk_signal_connect_object( GTK_OBJECT(cancel), "clicked",
1330 G_CALLBACK(gtk_widget_destroy),
1331 GTK_OBJECT(window) );
1332 gtk_container_add(GTK_CONTAINER(bbox), cancel);
1334 create = gtk_button_new_with_label(_("Create"));
1335 gtk_widget_set_sensitive(GTK_WIDGET(create), FALSE);
1336 gtk_signal_connect( GTK_OBJECT(entry), "changed",
1337 G_CALLBACK(on_editable_changed_enable_if_valid_xml_name),
1338 create );
1339 gtk_signal_connect( GTK_OBJECT(create), "clicked",
1340 G_CALLBACK(on_clicked_get_editable_text), &name );
1341 gtk_signal_connect_object( GTK_OBJECT(create), "clicked",
1342 G_CALLBACK(gtk_widget_destroy),
1343 GTK_OBJECT(window) );
1344 GTK_WIDGET_SET_FLAGS( GTK_WIDGET(create),
1345 GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT );
1346 gtk_container_add(GTK_CONTAINER(bbox), create);
1348 gtk_widget_show_all(GTK_WIDGET(window));
1349 gtk_window_set_default(GTK_WINDOW(window), GTK_WIDGET(create));
1350 gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(entry));
1352 name.editable = GTK_EDITABLE(entry);
1353 name.text = NULL;
1355 gtk_main();
1357 g_assert(selected_repr != NULL);
1359 if (name.text) {
1360 Inkscape::XML::Node *new_repr;
1361 new_repr = sp_repr_new(name.text);
1362 g_free(name.text);
1363 selected_repr->appendChild(new_repr);
1364 set_tree_select(new_repr);
1365 set_dt_select(new_repr);
1366 }
1368 } // end of cmd_new_element_node()
1372 void cmd_new_text_node(GtkObject *object, gpointer data)
1373 {
1374 g_assert(selected_repr != NULL);
1376 Inkscape::XML::Node *text = sp_repr_new_text("");
1377 selected_repr->appendChild(text);
1379 sp_document_done(current_document);
1381 set_tree_select(text);
1382 set_dt_select(text);
1384 gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(content));
1386 }
1388 void cmd_duplicate_node(GtkObject *object, gpointer data)
1389 {
1390 g_assert(selected_repr != NULL);
1392 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1393 Inkscape::XML::Node *dup = selected_repr->duplicate();
1394 parent->addChild(dup, selected_repr);
1396 sp_document_done(current_document);
1398 GtkCTreeNode *node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), dup);
1400 if (node) {
1401 gtk_ctree_select(GTK_CTREE(tree), node);
1402 }
1403 }
1407 void cmd_delete_node(GtkObject *object, gpointer data)
1408 {
1409 g_assert(selected_repr != NULL);
1410 sp_repr_unparent(selected_repr);
1412 sp_document_done(current_document);
1413 }
1417 void cmd_delete_attr(GtkObject *object, gpointer data)
1418 {
1419 g_assert(selected_repr != NULL);
1420 g_assert(selected_attr != 0);
1421 selected_repr->setAttribute(g_quark_to_string(selected_attr), NULL);
1423 SPObject *updated=current_document->getObjectByRepr(selected_repr);
1424 if (updated) {
1425 // force immediate update of dependant attributes
1426 updated->updateRepr();
1427 }
1429 sp_document_done(current_document);
1430 }
1434 void cmd_set_attr(GtkObject *object, gpointer data)
1435 {
1436 g_assert(selected_repr != NULL);
1438 gchar *name = gtk_editable_get_chars(attr_name, 0, -1);
1439 GtkTextIter start;
1440 GtkTextIter end;
1441 gtk_text_buffer_get_bounds( gtk_text_view_get_buffer(attr_value),
1442 &start, &end );
1443 gchar *value = gtk_text_buffer_get_text( gtk_text_view_get_buffer(attr_value),
1444 &start, &end, TRUE );
1446 if (!sp_repr_set_attr(selected_repr, name, value)) {
1447 gchar *message = g_strdup_printf(_("Cannot set <b>%s</b>: Another element with value <b>%s</b> already exists!"), name, value);
1448 _message_stack->flash(Inkscape::WARNING_MESSAGE, message);
1449 g_free(message);
1450 }
1452 g_free(name);
1453 g_free(value);
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);
1463 /* TODO: actually, the row won't have been created yet. why? */
1464 gint row = sp_xmlview_attr_list_find_row_from_key(GTK_CLIST(attributes),
1465 g_quark_from_string(name));
1466 if (row != -1) {
1467 gtk_clist_select_row(GTK_CLIST(attributes), row, 0);
1468 }
1469 }
1473 void cmd_raise_node(GtkObject *object, gpointer data)
1474 {
1475 g_assert(selected_repr != NULL);
1477 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1478 g_return_if_fail(parent != NULL);
1479 g_return_if_fail(parent->firstChild() != selected_repr);
1481 Inkscape::XML::Node *ref = NULL;
1482 Inkscape::XML::Node *before = parent->firstChild();
1483 while (before && before->next() != selected_repr) {
1484 ref = before;
1485 before = before->next();
1486 }
1488 parent->changeOrder(selected_repr, ref);
1490 sp_document_done(current_document);
1492 set_tree_select(selected_repr);
1493 set_dt_select(selected_repr);
1494 }
1498 void cmd_lower_node(GtkObject *object, gpointer data)
1499 {
1500 g_assert(selected_repr != NULL);
1501 g_return_if_fail(selected_repr->next() != NULL);
1502 Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
1504 parent->changeOrder(selected_repr, selected_repr->next());
1506 sp_document_done(current_document);
1508 set_tree_select(selected_repr);
1509 set_dt_select(selected_repr);
1510 }
1512 void cmd_indent_node(GtkObject *object, gpointer data)
1513 {
1514 Inkscape::XML::Node *repr = selected_repr;
1515 g_assert(repr != NULL);
1516 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1517 g_return_if_fail(parent != NULL);
1518 g_return_if_fail(parent->firstChild() != repr);
1520 Inkscape::XML::Node* prev = parent->firstChild();
1521 while (prev && prev->next() != repr) {
1522 prev = prev->next();
1523 }
1524 g_return_if_fail(prev != NULL);
1525 g_return_if_fail(prev->type() == Inkscape::XML::ELEMENT_NODE);
1527 Inkscape::XML::Node* ref = NULL;
1528 if (prev->firstChild()) {
1529 for( ref = prev->firstChild() ; ref->next() ; ref = ref->next() );
1530 }
1532 parent->removeChild(repr);
1533 prev->addChild(repr, ref);
1535 sp_document_done(current_document);
1536 set_tree_select(repr);
1537 set_dt_select(repr);
1539 } // end of cmd_indent_node()
1543 void cmd_unindent_node(GtkObject *object, gpointer data)
1544 {
1545 Inkscape::XML::Node *repr = selected_repr;
1546 g_assert(repr != NULL);
1547 Inkscape::XML::Node *parent = sp_repr_parent(repr);
1548 g_return_if_fail(parent);
1549 Inkscape::XML::Node *grandparent = sp_repr_parent(parent);
1550 g_return_if_fail(grandparent);
1552 parent->removeChild(repr);
1553 grandparent->addChild(repr, parent);
1555 sp_document_done(current_document);
1556 set_tree_select(repr);
1557 set_dt_select(repr);
1559 } // end of cmd_unindent_node()
1562 /*
1563 Local Variables:
1564 mode:c++
1565 c-file-style:"stroustrup"
1566 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1567 indent-tabs-mode:nil
1568 fill-column:99
1569 End:
1570 */
1571 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :