summaryrefslogtreecommitdiffstats
path: root/src/dialogs/xml-tree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dialogs/xml-tree.cpp')
-rw-r--r--src/dialogs/xml-tree.cpp1575
1 files changed, 1575 insertions, 0 deletions
diff --git a/src/dialogs/xml-tree.cpp b/src/dialogs/xml-tree.cpp
new file mode 100644
index 000000000..079a09b5a
--- /dev/null
+++ b/src/dialogs/xml-tree.cpp
@@ -0,0 +1,1575 @@
+#define __SP_XMLVIEW_TREE_C__
+
+/**
+ * \brief XML View
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * MenTaLguY <mental@rydia.net>
+ * bulia byak <buliabyak@users.sf.net>
+ *
+ * Copyright (C) 1999-2005 Authors
+ * Copyright (C) 2004 David Turner
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gtk/gtkmain.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkhpaned.h>
+#include <gtk/gtkvpaned.h>
+#include <gtk/gtkhseparator.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtktoolbar.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkarrow.h>
+
+#include <glibmm/i18n.h>
+#include "helper/window.h"
+#include "macros.h"
+#include "../inkscape.h"
+#include "../document.h"
+#include "../desktop-handles.h"
+#include "desktop.h"
+#include "../selection.h"
+#include "../sp-string.h"
+#include "../sp-tspan.h"
+#include "../sp-root.h"
+#include "../event-context.h"
+#include "in-dt-coordsys.h"
+
+
+#include "../widgets/sp-xmlview-tree.h"
+#include "../widgets/sp-xmlview-content.h"
+#include "../widgets/sp-xmlview-attr-list.h"
+
+#include "../inkscape-stock.h"
+#include "widgets/icon.h"
+
+#include "dialog-events.h"
+#include "../prefs-utils.h"
+#include "../verbs.h"
+#include "../interface.h"
+
+#include "shortcuts.h"
+#include <gdk/gdkkeysyms.h>
+
+#include "message-stack.h"
+#include "message-context.h"
+
+struct EditableDest {
+ GtkEditable *editable;
+ gchar *text;
+};
+
+static GtkWidget *dlg = NULL;
+static sigc::connection sel_changed_connection;
+static sigc::connection document_uri_set_connection;
+static sigc::connection document_replaced_connection;
+static win_data wd;
+// impossible original values to make sure they are read from prefs
+static gint x = -1000, y = -1000, w = 0, h = 0;
+static gchar *prefs_path = "dialogs.xml";
+static GtkWidget *status = NULL;
+static Inkscape::MessageStack *_message_stack = NULL;
+static Inkscape::MessageContext *_message_context = NULL;
+static sigc::connection _message_changed_connection;
+
+static GtkTooltips *tooltips = NULL;
+static GtkEditable *attr_name = NULL;
+static GtkTextView *attr_value = NULL;
+static SPXMLViewTree *tree = NULL;
+static SPXMLViewAttrList *attributes = NULL;
+static SPXMLViewContent *content = NULL;
+
+static gint blocked = 0;
+static SPDesktop *current_desktop = NULL;
+static SPDocument *current_document = NULL;
+static gint selected_attr = 0;
+static Inkscape::XML::Node *selected_repr = NULL;
+
+static void sp_xmltree_desktop_change( Inkscape::Application *inkscape, SPDesktop *desktop, GtkWidget *dialog );
+
+static void set_tree_desktop(SPDesktop *desktop);
+static void set_tree_document(SPDocument *document);
+static void set_tree_repr(Inkscape::XML::Node *repr);
+
+static void set_tree_select(Inkscape::XML::Node *repr);
+static void propagate_tree_select(Inkscape::XML::Node *repr);
+
+static Inkscape::XML::Node *get_dt_select();
+static void set_dt_select(Inkscape::XML::Node *repr);
+
+static void on_tree_select_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_unselect_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void after_tree_move(GtkCTree *tree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling, gpointer data);
+static void on_destroy(GtkObject *object, gpointer data);
+static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data);
+
+static void on_tree_select_row_enable_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+
+static void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+static void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data);
+
+static void on_attr_select_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
+static void on_attr_unselect_row(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
+static void on_attr_row_changed( GtkCList *list, gint row, gpointer data );
+
+static void on_attr_select_row_enable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
+static void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
+
+static void on_attr_select_row_set_name_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
+static void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
+static void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column, GdkEventButton *event, gpointer data);
+
+static void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable, gpointer data);
+
+static void on_desktop_selection_changed(Inkscape::Selection *selection);
+static void on_document_replaced(SPDesktop *dt, SPDocument *document);
+static void on_document_uri_set(gchar const *uri, SPDocument *document);
+
+static void on_clicked_get_editable_text(GtkWidget *widget, gpointer data);
+
+static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog);
+
+static void cmd_new_element_node(GtkObject *object, gpointer data);
+static void cmd_new_text_node(GtkObject *object, gpointer data);
+static void cmd_duplicate_node(GtkObject *object, gpointer data);
+static void cmd_delete_node(GtkObject *object, gpointer data);
+
+static void cmd_raise_node(GtkObject *object, gpointer data);
+static void cmd_lower_node(GtkObject *object, gpointer data);
+static void cmd_indent_node(GtkObject *object, gpointer data);
+static void cmd_unindent_node(GtkObject *object, gpointer data);
+
+static void cmd_delete_attr(GtkObject *object, gpointer data);
+static void cmd_set_attr(GtkObject *object, gpointer data);
+
+static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event);
+
+
+/*
+ * \brief Sets the XML status bar when the tree is selected.
+ */
+void tree_reset_context()
+{
+ _message_context->set(Inkscape::NORMAL_MESSAGE,
+ _("<b>Click</b> to select nodes, <b>drag</b> to rearrange."));
+}
+
+
+/*
+ * \brief Sets the XML status bar, depending on which attr is selected.
+ */
+void attr_reset_context(gint attr)
+{
+ if (attr == 0) {
+ _message_context->set(Inkscape::NORMAL_MESSAGE,
+ _("<b>Click</b> attribute to edit."));
+ }
+ else {
+ const gchar *name = g_quark_to_string(attr);
+ gchar *message = g_strdup_printf(_("Attribute <b>%s</b> selected. Press <b>Ctrl+Enter</b> when done editing to commit changes."), name);
+ _message_context->set(Inkscape::NORMAL_MESSAGE, message);
+ g_free(message);
+ }
+}
+
+
+void sp_xml_tree_dialog()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+ if (!desktop) {
+ return;
+ }
+
+ if (dlg == NULL)
+ { // very long block
+
+ GtkWidget *box, *sw, *paned, *toolbar, *button;
+ GtkWidget *text_container, *attr_container, *attr_subpaned_container, *box2;
+ GtkWidget *set_attr;
+
+ tooltips = gtk_tooltips_new();
+ gtk_tooltips_enable(tooltips);
+
+ dlg = sp_window_new("", TRUE);
+ if (x == -1000 || y == -1000) {
+ x = prefs_get_int_attribute(prefs_path, "x", 0);
+ y = prefs_get_int_attribute(prefs_path, "y", 0);
+ }
+ if (w ==0 || h == 0) {
+ w = prefs_get_int_attribute(prefs_path, "w", 0);
+ h = prefs_get_int_attribute(prefs_path, "h", 0);
+ }
+ if (x != 0 || y != 0) {
+ gtk_window_move((GtkWindow *) dlg, x, y);
+ } else {
+ gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
+ }
+
+ if (w && h) {
+ gtk_window_resize((GtkWindow *) dlg, w, h);
+ }
+ sp_transientize(dlg);
+ wd.win = dlg;
+ wd.stop = 0;
+ g_signal_connect ( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd );
+
+ gtk_signal_connect( GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg );
+
+ gtk_signal_connect( GTK_OBJECT(dlg), "destroy", G_CALLBACK(on_destroy), dlg);
+ gtk_signal_connect( GTK_OBJECT(dlg), "delete_event", G_CALLBACK(on_delete), dlg);
+ g_signal_connect ( G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(on_delete), dlg);
+
+ g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg);
+ g_signal_connect ( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg);
+
+
+ gtk_container_set_border_width(GTK_CONTAINER(dlg), 0);
+ gtk_window_set_default_size(GTK_WINDOW(dlg), 640, 384);
+
+ GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(dlg), vbox);
+
+ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
+
+ status = gtk_label_new(NULL);
+ gtk_misc_set_alignment(GTK_MISC(status), 0.0, 0.5);
+ gtk_widget_set_size_request(status, 1, -1);
+ gtk_label_set_markup(GTK_LABEL(status), "");
+ gtk_box_pack_start(GTK_BOX(hbox), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 4);
+ gtk_box_pack_start(GTK_BOX(hbox), status, TRUE, TRUE, 0);
+
+ paned = gtk_hpaned_new();
+ gtk_paned_set_position(GTK_PANED(paned), 256);
+ gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 0);
+
+ _message_stack = new Inkscape::MessageStack();
+ _message_context = new Inkscape::MessageContext(_message_stack);
+ _message_changed_connection = _message_stack->connectChanged(
+ sigc::bind(sigc::ptr_fun(_set_status_message), dlg)
+ );
+
+ /* tree view */
+
+ box = gtk_vbox_new(FALSE, 0);
+ gtk_paned_pack1(GTK_PANED(paned), box, FALSE, FALSE);
+
+ tree = SP_XMLVIEW_TREE(sp_xmlview_tree_new(NULL, NULL, NULL));
+ gtk_tooltips_set_tip( tooltips, GTK_WIDGET(tree),
+ _("Drag to reorder nodes"), NULL );
+
+ g_signal_connect( G_OBJECT(tree), "tree_select_row",
+ G_CALLBACK(on_tree_select_row), NULL );
+
+ g_signal_connect( G_OBJECT(tree), "tree_unselect_row",
+ G_CALLBACK(on_tree_unselect_row), NULL );
+
+ g_signal_connect_after( G_OBJECT(tree), "tree_move",
+ G_CALLBACK(after_tree_move), NULL);
+
+ /* TODO: replace gtk_signal_connect_while_alive() with something
+ * else...
+ */
+ toolbar = gtk_toolbar_new();
+ gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
+ gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
+
+ button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
+ NULL,
+ _("New element node"),
+ NULL,
+ sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
+ INKSCAPE_STOCK_ADD_XML_ELEMENT_NODE ),
+ G_CALLBACK(cmd_new_element_node),
+ NULL);
+
+ gtk_signal_connect_while_alive( GTK_OBJECT(tree),
+ "tree_select_row",
+ G_CALLBACK(on_tree_select_row_enable_if_element),
+ button,
+ GTK_OBJECT(button));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree),
+ "tree_unselect_row",
+ G_CALLBACK(on_tree_unselect_row_disable),
+ button,
+ GTK_OBJECT(button));
+
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
+ NULL, _("New text node"), NULL,
+ sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
+ INKSCAPE_STOCK_ADD_XML_TEXT_NODE ),
+ G_CALLBACK(cmd_new_text_node),
+ NULL);
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree),
+ "tree_select_row",
+ G_CALLBACK(on_tree_select_row_enable_if_element),
+ button,
+ GTK_OBJECT(button));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree),
+ "tree_unselect_row",
+ G_CALLBACK(on_tree_unselect_row_disable),
+ button,
+ GTK_OBJECT(button));
+
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
+ NULL, _("Duplicate node"), NULL,
+ sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
+ INKSCAPE_STOCK_DUPLICATE_XML_NODE ),
+ G_CALLBACK(cmd_duplicate_node),
+ NULL);
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree),
+ "tree_select_row",
+ G_CALLBACK(on_tree_select_row_enable_if_mutable),
+ button,
+ GTK_OBJECT(button));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ G_CALLBACK(on_tree_unselect_row_disable),
+ button, GTK_OBJECT(button));
+
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
+
+ button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
+ NULL, _("Delete node"), NULL,
+ sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
+ INKSCAPE_STOCK_DELETE_XML_NODE ),
+ G_CALLBACK(cmd_delete_node), NULL );
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
+ G_CALLBACK(on_tree_select_row_enable_if_mutable),
+ button, GTK_OBJECT(button));
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ G_CALLBACK(on_tree_unselect_row_disable),
+ button, GTK_OBJECT(button));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
+
+ button = gtk_toolbar_append_item( GTK_TOOLBAR(toolbar), "<",
+ _("Unindent node"), NULL,
+ gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_IN),
+ G_CALLBACK(cmd_unindent_node), NULL);
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
+ G_CALLBACK(on_tree_select_row_enable_if_has_grandparent),
+ button, GTK_OBJECT(button));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ G_CALLBACK(on_tree_unselect_row_disable),
+ button, GTK_OBJECT(button));
+
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), ">",
+ _("Indent node"), NULL,
+ gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_IN),
+ G_CALLBACK(cmd_indent_node), NULL);
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
+ G_CALLBACK(on_tree_select_row_enable_if_indentable),
+ button, GTK_OBJECT(button));
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ (GCallback) on_tree_unselect_row_disable,
+ button, GTK_OBJECT(button));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "^",
+ _("Raise node"), NULL,
+ gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_IN),
+ G_CALLBACK(cmd_raise_node), NULL);
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
+ G_CALLBACK(on_tree_select_row_enable_if_not_first_child),
+ button, GTK_OBJECT(button));
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ G_CALLBACK(on_tree_unselect_row_disable),
+ button, GTK_OBJECT(button));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "v",
+ _("Lower node"), NULL,
+ gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_IN),
+ G_CALLBACK(cmd_lower_node), NULL);
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
+ G_CALLBACK(on_tree_select_row_enable_if_not_last_child),
+ button, GTK_OBJECT(button));
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ G_CALLBACK(on_tree_unselect_row_disable),
+ button, GTK_OBJECT(button));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ gtk_box_pack_start(GTK_BOX(box), toolbar, FALSE, TRUE, 0);
+
+ sw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC );
+ gtk_box_pack_start(GTK_BOX(box), sw, TRUE, TRUE, 0);
+
+ gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(tree));
+
+ /* node view */
+
+ box = gtk_vbox_new(FALSE, 0);
+ gtk_paned_pack2(GTK_PANED(paned), box, TRUE, TRUE);
+
+ /* attributes */
+
+ attr_container = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start( GTK_BOX(box), GTK_WIDGET(attr_container),
+ TRUE, TRUE, 0 );
+
+ attributes = SP_XMLVIEW_ATTR_LIST(sp_xmlview_attr_list_new(NULL));
+ g_signal_connect( G_OBJECT(attributes), "select_row",
+ G_CALLBACK(on_attr_select_row), NULL);
+ g_signal_connect( G_OBJECT(attributes), "unselect_row",
+ G_CALLBACK(on_attr_unselect_row), NULL);
+ g_signal_connect( G_OBJECT(attributes), "row-value-changed",
+ G_CALLBACK(on_attr_row_changed), NULL);
+
+ toolbar = gtk_toolbar_new();
+ gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
+ gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);
+
+ button = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
+ NULL, _("Delete attribute"), NULL,
+ sp_icon_new( GTK_ICON_SIZE_LARGE_TOOLBAR,
+ INKSCAPE_STOCK_DELETE_XML_ATTRIBUTE ),
+ (GCallback) cmd_delete_attr, NULL);
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "select_row",
+ (GCallback) on_attr_select_row_enable, button,
+ GTK_OBJECT(button));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(attributes), "unselect_row",
+ (GCallback) on_attr_unselect_row_disable, button,
+ GTK_OBJECT(button));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ (GCallback) on_tree_unselect_row_disable, button,
+ GTK_OBJECT(button));
+
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+ gtk_box_pack_start( GTK_BOX(attr_container),
+ GTK_WIDGET(toolbar), FALSE, TRUE, 0 );
+
+ attr_subpaned_container = gtk_vpaned_new();
+ gtk_box_pack_start( GTK_BOX(attr_container),
+ GTK_WIDGET(attr_subpaned_container),
+ TRUE, TRUE, 0 );
+ gtk_widget_show(attr_subpaned_container);
+
+ sw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_paned_pack1( GTK_PANED(attr_subpaned_container),
+ GTK_WIDGET(sw), TRUE, TRUE );
+ gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(attributes));
+
+ toolbar = gtk_vbox_new(FALSE, 4);
+ gtk_container_set_border_width(GTK_CONTAINER(toolbar), 4);
+
+ box2 = gtk_hbox_new(FALSE, 4);
+ gtk_box_pack_start( GTK_BOX(toolbar), GTK_WIDGET(box2),
+ FALSE, TRUE, 0);
+
+ attr_name = GTK_EDITABLE(gtk_entry_new());
+ gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_name),
+ // TRANSLATORS: "Attribute" is a noun here
+ _("Attribute name"), NULL );
+
+ gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
+ (GCallback) on_attr_select_row_set_name_content,
+ attr_name);
+
+ gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
+ (GCallback) on_attr_unselect_row_clear_text,
+ attr_name);
+
+ gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
+ (GCallback) on_tree_unselect_row_clear_text,
+ attr_name);
+
+ gtk_box_pack_start( GTK_BOX(box2), GTK_WIDGET(attr_name),
+ TRUE, TRUE, 0);
+
+ set_attr = gtk_button_new();
+ gtk_tooltips_set_tip( tooltips, GTK_WIDGET(set_attr),
+ // TRANSLATORS: "Set" is a verb here
+ _("Set attribute"), NULL );
+ // TRANSLATORS: "Set" is a verb here
+ GtkWidget *set_label = gtk_label_new(_("Set"));
+ gtk_container_add(GTK_CONTAINER(set_attr), set_label);
+
+ gtk_signal_connect( GTK_OBJECT(set_attr), "clicked",
+ (GCallback) cmd_set_attr, NULL);
+ gtk_signal_connect( GTK_OBJECT(attr_name), "changed",
+ (GCallback) on_editable_changed_enable_if_valid_xml_name,
+ set_attr );
+ gtk_widget_set_sensitive(GTK_WIDGET(set_attr), FALSE);
+
+ gtk_box_pack_start(GTK_BOX(box2), set_attr, FALSE, FALSE, 0);
+
+ sw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC );
+ gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
+ gtk_box_pack_start(GTK_BOX(toolbar), sw, TRUE, TRUE, 0);
+
+ attr_value =(GtkTextView *) gtk_text_view_new();
+ gtk_text_view_set_wrap_mode((GtkTextView *) attr_value, GTK_WRAP_CHAR);
+ gtk_tooltips_set_tip( tooltips, GTK_WIDGET(attr_value),
+ // TRANSLATORS: "Attribute" is a noun here
+ _("Attribute value"), NULL );
+ gtk_signal_connect( GTK_OBJECT(attributes), "select_row",
+ (GCallback) on_attr_select_row_set_value_content,
+ attr_value );
+ gtk_signal_connect( GTK_OBJECT(attributes), "unselect_row",
+ (GCallback) on_attr_unselect_row_clear_text,
+ attr_value );
+ gtk_signal_connect( GTK_OBJECT(tree), "tree_unselect_row",
+ (GCallback) on_tree_unselect_row_clear_text,
+ attr_value );
+ gtk_text_view_set_editable(attr_value, TRUE);
+ gtk_container_add( GTK_CONTAINER(sw),
+ GTK_WIDGET(attr_value) );
+
+ gtk_paned_pack2( GTK_PANED(attr_subpaned_container),
+ GTK_WIDGET(toolbar), FALSE, TRUE );
+
+ /* text */
+
+ sw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(sw),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC );
+ gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN );
+ gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(sw), TRUE, TRUE, 0);
+
+ content = SP_XMLVIEW_CONTENT(sp_xmlview_content_new(NULL));
+ gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(content));
+
+ text_container = sw;
+
+ /* initial show/hide */
+
+ gtk_widget_show_all(GTK_WIDGET(dlg));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
+ (GCallback) on_tree_select_row_show_if_element,
+ attr_container, GTK_OBJECT(attr_container));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ (GCallback) on_tree_unselect_row_hide,
+ attr_container, GTK_OBJECT(attr_container));
+
+ gtk_widget_hide(attr_container);
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_select_row",
+ (GCallback) on_tree_select_row_show_if_text,
+ text_container, GTK_OBJECT(text_container));
+
+ gtk_signal_connect_while_alive(GTK_OBJECT(tree), "tree_unselect_row",
+ (GCallback) on_tree_unselect_row_hide,
+ text_container, GTK_OBJECT(text_container));
+
+ gtk_widget_hide(text_container);
+
+ g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop",
+ G_CALLBACK(sp_xmltree_desktop_change), dlg);
+
+ g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop",
+ G_CALLBACK(sp_xmltree_desktop_change), dlg);
+
+ g_signal_connect((GObject *) dlg, "key_press_event", (GCallback) sp_xml_tree_key_press, NULL);
+
+ tree_reset_context();
+ } // end of if (dlg == NULL)
+
+ gtk_window_present((GtkWindow *) dlg);
+
+ g_assert(desktop != NULL);
+ set_tree_desktop(desktop);
+
+} // end of sp_xml_tree_dialog()
+
+static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event)
+{
+
+ unsigned int shortcut = get_group0_keyval(event) |
+ ( event->state & GDK_SHIFT_MASK ?
+ SP_SHORTCUT_SHIFT_MASK : 0 ) |
+ ( event->state & GDK_CONTROL_MASK ?
+ SP_SHORTCUT_CONTROL_MASK : 0 ) |
+ ( event->state & GDK_MOD1_MASK ?
+ SP_SHORTCUT_ALT_MASK : 0 );
+
+ /* fixme: if you need to add more xml-tree-specific callbacks, you should probably upgrade
+ * the sp_shortcut mechanism to take into account windows. */
+ if (shortcut == (SP_SHORTCUT_CONTROL_MASK | GDK_Return)) {
+ cmd_set_attr(NULL, NULL);
+ return true;
+ }
+ return false;
+}
+
+
+static void sp_xmltree_desktop_change(Inkscape::Application *inkscape,
+ SPDesktop *desktop,
+ GtkWidget *dialog )
+{
+ if (!desktop) {
+ return;
+ }
+ set_tree_desktop(desktop);
+}
+
+
+void set_tree_desktop(SPDesktop *desktop)
+{
+ if ( desktop == current_desktop ) {
+ return;
+ }
+
+ if (current_desktop) {
+ sel_changed_connection.disconnect();
+ document_replaced_connection.disconnect();
+ }
+ current_desktop = desktop;
+ if (desktop) {
+ sel_changed_connection = SP_DT_SELECTION(desktop)->connectChanged(&on_desktop_selection_changed);
+ document_replaced_connection = desktop->connectDocumentReplaced(&on_document_replaced);
+ set_tree_document(SP_DT_DOCUMENT(desktop));
+ } else {
+ set_tree_document(NULL);
+ }
+
+} // end of set_tree_desktop()
+
+
+
+void set_tree_document(SPDocument *document)
+{
+ if (document == current_document) {
+ return;
+ }
+
+ if (current_document) {
+ document_uri_set_connection.disconnect();
+ }
+ current_document = document;
+ if (current_document) {
+
+ document_uri_set_connection = current_document->connectURISet(sigc::bind(sigc::ptr_fun(&on_document_uri_set), current_document));
+ on_document_uri_set(SP_DOCUMENT_URI(current_document), current_document);
+ set_tree_repr(sp_document_repr_root(current_document));
+
+ } else {
+ set_tree_repr(NULL);
+ }
+}
+
+
+
+void set_tree_repr(Inkscape::XML::Node *repr)
+{
+ if (repr == selected_repr) {
+ return;
+ }
+
+ gtk_clist_freeze(GTK_CLIST(tree));
+
+ sp_xmlview_tree_set_repr(tree, repr);
+
+ if (repr) {
+ set_tree_select(get_dt_select());
+ } else {
+ set_tree_select(NULL);
+ }
+
+ gtk_clist_thaw(GTK_CLIST(tree));
+
+ propagate_tree_select(selected_repr);
+
+}
+
+
+
+void set_tree_select(Inkscape::XML::Node *repr)
+{
+ if (selected_repr) {
+ Inkscape::GC::release(selected_repr);
+ }
+
+ selected_repr = repr;
+ if (repr) {
+ GtkCTreeNode *node;
+
+ Inkscape::GC::anchor(selected_repr);
+
+ node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), repr);
+ if (node) {
+ GtkCTreeNode *parent;
+
+ gtk_ctree_select(GTK_CTREE(tree), node);
+
+ parent = GTK_CTREE_ROW(node)->parent;
+ while (parent) {
+ gtk_ctree_expand(GTK_CTREE(tree), parent);
+ parent = GTK_CTREE_ROW(parent)->parent;
+ }
+
+ gtk_ctree_node_moveto(GTK_CTREE(tree), node, 0, 0.66, 0.0);
+ }
+ } else {
+ gtk_clist_unselect_all(GTK_CLIST(tree));
+ }
+ propagate_tree_select(repr);
+}
+
+
+
+void propagate_tree_select(Inkscape::XML::Node *repr)
+{
+ if (repr && repr->type() == Inkscape::XML::ELEMENT_NODE) {
+ sp_xmlview_attr_list_set_repr(attributes, repr);
+ } else {
+ sp_xmlview_attr_list_set_repr(attributes, NULL);
+ }
+
+ if (repr && ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE ) ) {
+ sp_xmlview_content_set_repr(content, repr);
+ } else {
+ sp_xmlview_content_set_repr(content, NULL);
+ }
+}
+
+
+Inkscape::XML::Node *get_dt_select()
+{
+ if (!current_desktop) {
+ return NULL;
+ }
+
+ return SP_DT_SELECTION(current_desktop)->singleRepr();
+}
+
+
+
+void set_dt_select(Inkscape::XML::Node *repr)
+{
+ if (!current_desktop) {
+ return;
+ }
+
+ Inkscape::Selection *selection = SP_DT_SELECTION(current_desktop);
+
+ SPObject *object;
+ if (repr) {
+ while ( ( repr->type() != Inkscape::XML::ELEMENT_NODE )
+ && sp_repr_parent(repr) )
+ {
+ repr = sp_repr_parent(repr);
+ } // end of while loop
+
+ object = SP_DT_DOCUMENT(current_desktop)->getObjectByRepr(repr);
+ } else {
+ object = NULL;
+ }
+
+ blocked++;
+ if ( object && in_dt_coordsys(*object)
+ && !( SP_IS_TSPAN(object) ||
+ SP_IS_STRING(object) ||
+ SP_IS_ROOT(object) ) )
+ {
+ /* We cannot set selection to tspan, string, or root; failures and
+ * crashes will occur. */
+ /* TODO: when a tspan is highlighted, set selection to its parent
+ * text
+ */
+ selection->set(SP_ITEM(object));
+ }
+ blocked--;
+
+} // end of set_dt_select()
+
+
+void on_tree_select_row(GtkCTree *tree,
+ GtkCTreeNode *node,
+ gint column,
+ gpointer data)
+{
+ if (blocked) {
+ return;
+ }
+
+ Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+ g_assert(repr != NULL);
+
+ if (selected_repr == repr) {
+ return;
+ }
+
+ if (selected_repr) {
+ Inkscape::GC::release(selected_repr);
+ selected_repr = NULL;
+ }
+ selected_repr = repr;
+ Inkscape::GC::anchor(selected_repr);
+
+ propagate_tree_select(selected_repr);
+
+ set_dt_select(selected_repr);
+
+ tree_reset_context();
+}
+
+void on_tree_unselect_row(GtkCTree *tree,
+ GtkCTreeNode *node,
+ gint column,
+ gpointer data)
+{
+ if (blocked) {
+ return;
+ }
+
+ Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+ propagate_tree_select(NULL);
+ set_dt_select(NULL);
+
+ if (selected_repr && (selected_repr == repr)) {
+ Inkscape::GC::release(selected_repr);
+ selected_repr = NULL;
+ selected_attr = 0;
+ }
+}
+
+
+
+void after_tree_move(GtkCTree *tree,
+ GtkCTreeNode *node,
+ GtkCTreeNode *new_parent,
+ GtkCTreeNode *new_sibling,
+ gpointer data)
+{
+ if (GTK_CTREE_ROW(node)->parent == new_parent &&
+ GTK_CTREE_ROW(node)->sibling == new_sibling)
+ {
+ sp_document_done(current_document);
+ } else {
+ sp_document_cancel(current_document);
+ }
+}
+
+
+static void on_destroy(GtkObject *object, gpointer data)
+{
+ set_tree_desktop(NULL);
+ gtk_object_destroy(GTK_OBJECT(tooltips));
+ tooltips = NULL;
+ sp_signal_disconnect_by_data(INKSCAPE, dlg);
+ wd.win = dlg = NULL;
+ wd.stop = 0;
+
+ _message_changed_connection.disconnect();
+ delete _message_context;
+ _message_context = NULL;
+ Inkscape::GC::release(_message_stack);
+ _message_stack = NULL;
+ _message_changed_connection.~connection();
+
+ status = NULL;
+}
+
+
+
+static gboolean on_delete(GtkObject *object, GdkEvent *event, gpointer data)
+{
+ gtk_window_get_position((GtkWindow *) dlg, &x, &y);
+ gtk_window_get_size((GtkWindow *) dlg, &w, &h);
+
+ prefs_set_int_attribute(prefs_path, "x", x);
+ prefs_set_int_attribute(prefs_path, "y", y);
+ prefs_set_int_attribute(prefs_path, "w", w);
+ prefs_set_int_attribute(prefs_path, "h", h);
+
+ return FALSE; // which means, go ahead and destroy it
+}
+
+
+static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog)
+{
+ if (status) {
+ gtk_label_set_markup(GTK_LABEL(status), message ? message : "");
+ }
+}
+
+
+void on_tree_select_row_enable(GtkCTree *tree,
+ GtkCTreeNode *node,
+ gint column,
+ gpointer data)
+{
+ gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+}
+
+
+
+void on_tree_select_row_enable_if_element(GtkCTree *tree,
+ GtkCTreeNode *node,
+ gint column,
+ gpointer data )
+{
+ Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+
+ if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+ }
+}
+
+
+
+void on_tree_select_row_show_if_element(GtkCTree *tree, GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+
+ if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
+ gtk_widget_show(GTK_WIDGET(data));
+ } else {
+ gtk_widget_hide(GTK_WIDGET(data));
+ }
+}
+
+
+
+void on_tree_select_row_show_if_text(GtkCTree *tree, GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+
+ if ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE ) {
+ gtk_widget_show(GTK_WIDGET(data));
+ } else {
+ gtk_widget_hide(GTK_WIDGET(data));
+ }
+}
+
+
+gboolean xml_tree_node_mutable(GtkCTreeNode *node)
+{
+ // top-level is immutable, obviously
+ if (!GTK_CTREE_ROW(node)->parent) {
+ return false;
+ }
+
+ // if not in base level (where namedview, defs, etc go), we're mutable
+ if (GTK_CTREE_ROW(GTK_CTREE_ROW(node)->parent)->parent) {
+ return true;
+ }
+
+ Inkscape::XML::Node *repr;
+ repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+ g_assert(repr);
+
+ // don't let "defs" or "namedview" disappear
+ if ( !strcmp(repr->name(),"svg:defs") ||
+ !strcmp(repr->name(),"sodipodi:namedview") ) {
+ return false;
+ }
+
+ // everyone else is okay, I guess. :)
+ return true;
+}
+
+
+void on_tree_select_row_enable_if_mutable(GtkCTree *tree, GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ gtk_widget_set_sensitive(GTK_WIDGET(data), xml_tree_node_mutable(node));
+}
+
+
+
+void on_tree_unselect_row_disable(GtkCTree *tree, GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+}
+
+
+
+void on_tree_unselect_row_hide(GtkCTree *tree, GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ gtk_widget_hide(GTK_WIDGET(data));
+}
+
+
+
+void on_tree_unselect_row_clear_text(GtkCTree *tree, GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ if (GTK_IS_EDITABLE(data)) {
+ gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
+ } else if (GTK_IS_TEXT_VIEW(data)) {
+ GtkTextBuffer *tb;
+ tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
+ gtk_text_buffer_set_text(tb, "", 0);
+ }
+}
+
+
+void on_attr_select_row(GtkCList *list, gint row, gint column,
+ GdkEventButton *event, gpointer data)
+{
+ selected_attr = sp_xmlview_attr_list_get_row_key(list, row);
+ gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(attr_value));
+
+ attr_reset_context(selected_attr);
+}
+
+
+void on_attr_unselect_row(GtkCList *list, gint row, gint column,
+ GdkEventButton *event, gpointer data)
+{
+ selected_attr = 0;
+ attr_reset_context(selected_attr);
+}
+
+
+void on_attr_row_changed(GtkCList *list, gint row, gpointer data)
+{
+ gint attr = sp_xmlview_attr_list_get_row_key(list, row);
+
+ if (attr == selected_attr) {
+ /* if the attr changed, reselect the row in the list to sync
+ the edit box */
+
+ /*
+ // get current attr values
+ const gchar * name = g_quark_to_string (sp_xmlview_attr_list_get_row_key (list, row));
+ const gchar * value = selected_repr->attribute(name);
+
+ g_warning("value: '%s'",value);
+
+ // get the edit box value
+ GtkTextIter start, end;
+ gtk_text_buffer_get_bounds ( gtk_text_view_get_buffer (attr_value),
+ &start, &end );
+ gchar * text = gtk_text_buffer_get_text ( gtk_text_view_get_buffer (attr_value),
+ &start, &end, TRUE );
+ g_warning("text: '%s'",text);
+
+ // compare to edit box
+ if (strcmp(text,value)) {
+ // issue warning if they're different
+ _message_stack->flash(Inkscape::WARNING_MESSAGE,
+ _("Attribute changed in GUI while editing values!"));
+ }
+ g_free (text);
+
+ */
+ gtk_clist_unselect_row( GTK_CLIST(list), row, 0 );
+ gtk_clist_select_row( GTK_CLIST(list), row, 0 );
+ }
+}
+
+
+void on_attr_select_row_set_name_content(GtkCList *list, gint row,
+ gint column, GdkEventButton *event,
+ gpointer data)
+{
+ GtkEditable *editable = GTK_EDITABLE(data);
+ const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
+ gtk_editable_delete_text(editable, 0, -1);
+ gint pos = 0;
+ gtk_editable_insert_text(editable, name, strlen(name), &pos);
+}
+
+
+
+void on_attr_select_row_set_value_content(GtkCList *list, gint row, gint column,
+ GdkEventButton *event,
+ gpointer data)
+{
+ GtkTextBuffer *tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
+ const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(list, row));
+ const gchar *value = selected_repr->attribute(name);
+ if (!value) {
+ value = "";
+ }
+ gtk_text_buffer_set_text(tb, value, strlen(value));
+}
+
+
+void on_tree_select_row_enable_if_indentable(GtkCTree *tree, GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ gboolean indentable = FALSE;
+
+ if (xml_tree_node_mutable(node)) {
+ Inkscape::XML::Node *repr, *prev;
+ repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+
+ Inkscape::XML::Node *parent=repr->parent();
+ if ( parent && repr != parent->firstChild() ) {
+ g_assert(parent->firstChild());
+
+ // skip to the child just before the current repr
+ for ( prev = parent->firstChild() ;
+ prev && prev->next() != repr ;
+ prev = prev->next() );
+
+ if (prev && prev->type() == Inkscape::XML::ELEMENT_NODE) {
+ indentable = TRUE;
+ }
+ }
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(data), indentable);
+}
+
+
+
+void on_tree_select_row_enable_if_not_first_child(GtkCTree *tree,
+ GtkCTreeNode *node,
+ gint column,
+ gpointer data)
+{
+ Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+
+ Inkscape::XML::Node *parent=repr->parent();
+ if ( parent && repr != parent->firstChild() ) {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+ }
+}
+
+
+
+void on_tree_select_row_enable_if_not_last_child(GtkCTree *tree,
+ GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node);
+
+ Inkscape::XML::Node *parent=repr->parent();
+ if ( parent && parent->parent() && repr->next() ) {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+ }
+}
+
+
+
+void on_tree_select_row_enable_if_has_grandparent(GtkCTree *tree,
+ GtkCTreeNode *node,
+ gint column, gpointer data)
+{
+ GtkCTreeNode *parent = GTK_CTREE_ROW(node)->parent;
+
+ if (parent) {
+ GtkCTreeNode *grandparent = GTK_CTREE_ROW(parent)->parent;
+ if (grandparent) {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+ }
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+ }
+}
+
+
+
+void on_attr_select_row_enable(GtkCList *list, gint row, gint column,
+ GdkEventButton *event, gpointer data)
+{
+ gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+}
+
+
+
+void on_attr_unselect_row_disable(GtkCList *list, gint row, gint column,
+ GdkEventButton *event, gpointer data)
+{
+ gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+}
+
+
+
+void on_attr_unselect_row_clear_text(GtkCList *list, gint row, gint column,
+ GdkEventButton *event, gpointer data)
+{
+ if (GTK_IS_EDITABLE(data)) {
+ gtk_editable_delete_text(GTK_EDITABLE(data), 0, -1);
+ } else if (GTK_IS_TEXT_VIEW(data)) {
+ GtkTextBuffer *tb;
+ tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
+ gtk_text_buffer_set_text(tb, "", 0);
+ }
+}
+
+
+
+void on_editable_changed_enable_if_valid_xml_name(GtkEditable *editable,
+ gpointer data)
+{
+ gchar *text = gtk_editable_get_chars(editable, 0, -1);
+
+ /* TODO: need to do checking a little more rigorous than this */
+
+ if (strlen(text)) {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+ }
+ g_free(text);
+}
+
+
+
+void on_desktop_selection_changed(Inkscape::Selection *selection)
+{
+ if (!blocked++) {
+ set_tree_select(get_dt_select());
+ }
+ blocked--;
+}
+
+static void on_document_replaced(SPDesktop *dt, SPDocument *doc)
+{
+ if (current_desktop)
+ sel_changed_connection.disconnect();
+
+ sel_changed_connection = SP_DT_SELECTION(dt)->connectChanged(&on_desktop_selection_changed);
+ set_tree_document(doc);
+}
+
+void on_document_uri_set(gchar const *uri, SPDocument *document)
+{
+ gchar title[500];
+ sp_ui_dialog_title_string(Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), title);
+ gchar *t = g_strdup_printf("%s: %s", SP_DOCUMENT_NAME(document), title);
+ gtk_window_set_title(GTK_WINDOW(dlg), t);
+ g_free(t);
+}
+
+
+
+void on_clicked_get_editable_text(GtkWidget *widget, gpointer data)
+{
+ EditableDest *dest = (EditableDest *) data;
+ dest->text = gtk_editable_get_chars(dest->editable, 0, -1);
+}
+
+
+
+void cmd_new_element_node(GtkObject *object, gpointer data)
+{
+ EditableDest name;
+ GtkWidget *window, *create, *cancel, *vbox, *entry, *bbox, *sep;
+
+ g_assert(selected_repr != NULL);
+
+ window = sp_window_new(NULL, TRUE);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 4);
+ gtk_window_set_title(GTK_WINDOW(window), _("New element node..."));
+ gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(dlg));
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ gtk_signal_connect(GTK_OBJECT(window), "destroy", gtk_main_quit, NULL);
+
+ vbox = gtk_vbox_new(FALSE, 4);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ entry = gtk_entry_new();
+ gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 0);
+
+ sep = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, TRUE, 0);
+
+ bbox = gtk_hbutton_box_new();
+ gtk_container_set_border_width(GTK_CONTAINER(bbox), 4);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
+
+ cancel = gtk_button_new_with_label(_("Cancel"));
+ gtk_signal_connect_object( GTK_OBJECT(cancel), "clicked",
+ G_CALLBACK(gtk_widget_destroy),
+ GTK_OBJECT(window) );
+ gtk_container_add(GTK_CONTAINER(bbox), cancel);
+
+ create = gtk_button_new_with_label(_("Create"));
+ gtk_widget_set_sensitive(GTK_WIDGET(create), FALSE);
+ gtk_signal_connect( GTK_OBJECT(entry), "changed",
+ G_CALLBACK(on_editable_changed_enable_if_valid_xml_name),
+ create );
+ gtk_signal_connect( GTK_OBJECT(create), "clicked",
+ G_CALLBACK(on_clicked_get_editable_text), &name );
+ gtk_signal_connect_object( GTK_OBJECT(create), "clicked",
+ G_CALLBACK(gtk_widget_destroy),
+ GTK_OBJECT(window) );
+ GTK_WIDGET_SET_FLAGS( GTK_WIDGET(create),
+ GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT );
+ gtk_container_add(GTK_CONTAINER(bbox), create);
+
+ gtk_widget_show_all(GTK_WIDGET(window));
+ gtk_window_set_default(GTK_WINDOW(window), GTK_WIDGET(create));
+ gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(entry));
+
+ name.editable = GTK_EDITABLE(entry);
+ name.text = NULL;
+
+ gtk_main();
+
+ g_assert(selected_repr != NULL);
+
+ if (name.text) {
+ Inkscape::XML::Node *new_repr;
+ new_repr = sp_repr_new(name.text);
+ g_free(name.text);
+ selected_repr->appendChild(new_repr);
+ set_tree_select(new_repr);
+ set_dt_select(new_repr);
+ }
+
+} // end of cmd_new_element_node()
+
+
+
+void cmd_new_text_node(GtkObject *object, gpointer data)
+{
+ g_assert(selected_repr != NULL);
+
+ Inkscape::XML::Node *text = sp_repr_new_text("");
+ selected_repr->appendChild(text);
+
+ sp_document_done(current_document);
+
+ set_tree_select(text);
+ set_dt_select(text);
+
+ gtk_window_set_focus(GTK_WINDOW(dlg), GTK_WIDGET(content));
+
+}
+
+void cmd_duplicate_node(GtkObject *object, gpointer data)
+{
+ g_assert(selected_repr != NULL);
+
+ Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
+ Inkscape::XML::Node *dup = selected_repr->duplicate();
+ parent->addChild(dup, selected_repr);
+
+ sp_document_done(current_document);
+
+ GtkCTreeNode *node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), dup);
+
+ if (node) {
+ gtk_ctree_select(GTK_CTREE(tree), node);
+ }
+}
+
+
+
+void cmd_delete_node(GtkObject *object, gpointer data)
+{
+ g_assert(selected_repr != NULL);
+ sp_repr_unparent(selected_repr);
+
+ sp_document_done(current_document);
+}
+
+
+
+void cmd_delete_attr(GtkObject *object, gpointer data)
+{
+ g_assert(selected_repr != NULL);
+ g_assert(selected_attr != 0);
+ selected_repr->setAttribute(g_quark_to_string(selected_attr), NULL);
+
+ SPObject *updated=current_document->getObjectByRepr(selected_repr);
+ if (updated) {
+ // force immediate update of dependant attributes
+ updated->updateRepr();
+ }
+
+ sp_document_done(current_document);
+}
+
+
+
+void cmd_set_attr(GtkObject *object, gpointer data)
+{
+ g_assert(selected_repr != NULL);
+
+ gchar *name = gtk_editable_get_chars(attr_name, 0, -1);
+ GtkTextIter start;
+ GtkTextIter end;
+ gtk_text_buffer_get_bounds( gtk_text_view_get_buffer(attr_value),
+ &start, &end );
+ gchar *value = gtk_text_buffer_get_text( gtk_text_view_get_buffer(attr_value),
+ &start, &end, TRUE );
+
+ if (!sp_repr_set_attr(selected_repr, name, value)) {
+ gchar *message = g_strdup_printf(_("Cannot set <b>%s</b>: Another element with value <b>%s</b> already exists!"), name, value);
+ _message_stack->flash(Inkscape::WARNING_MESSAGE, message);
+ g_free(message);
+ }
+
+ g_free(name);
+ g_free(value);
+
+ SPObject *updated = current_document->getObjectByRepr(selected_repr);
+ if (updated) {
+ // force immediate update of dependant attributes
+ updated->updateRepr();
+ }
+
+ sp_document_done(current_document);
+
+ /* TODO: actually, the row won't have been created yet. why? */
+ gint row = sp_xmlview_attr_list_find_row_from_key(GTK_CLIST(attributes),
+ g_quark_from_string(name));
+ if (row != -1) {
+ gtk_clist_select_row(GTK_CLIST(attributes), row, 0);
+ }
+}
+
+
+
+void cmd_raise_node(GtkObject *object, gpointer data)
+{
+ g_assert(selected_repr != NULL);
+
+ Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
+ g_return_if_fail(parent != NULL);
+ g_return_if_fail(parent->firstChild() != selected_repr);
+
+ Inkscape::XML::Node *ref = NULL;
+ Inkscape::XML::Node *before = parent->firstChild();
+ while (before && before->next() != selected_repr) {
+ ref = before;
+ before = before->next();
+ }
+
+ parent->changeOrder(selected_repr, ref);
+
+ sp_document_done(current_document);
+
+ set_tree_select(selected_repr);
+ set_dt_select(selected_repr);
+}
+
+
+
+void cmd_lower_node(GtkObject *object, gpointer data)
+{
+ g_assert(selected_repr != NULL);
+ g_return_if_fail(selected_repr->next() != NULL);
+ Inkscape::XML::Node *parent = sp_repr_parent(selected_repr);
+
+ parent->changeOrder(selected_repr, selected_repr->next());
+
+ sp_document_done(current_document);
+
+ set_tree_select(selected_repr);
+ set_dt_select(selected_repr);
+}
+
+void cmd_indent_node(GtkObject *object, gpointer data)
+{
+ Inkscape::XML::Node *repr = selected_repr;
+ g_assert(repr != NULL);
+ Inkscape::XML::Node *parent = sp_repr_parent(repr);
+ g_return_if_fail(parent != NULL);
+ g_return_if_fail(parent->firstChild() != repr);
+
+ Inkscape::XML::Node* prev = parent->firstChild();
+ while (prev && prev->next() != repr) {
+ prev = prev->next();
+ }
+ g_return_if_fail(prev != NULL);
+ g_return_if_fail(prev->type() == Inkscape::XML::ELEMENT_NODE);
+
+ Inkscape::XML::Node* ref = NULL;
+ if (prev->firstChild()) {
+ for( ref = prev->firstChild() ; ref->next() ; ref = ref->next() );
+ }
+
+ parent->removeChild(repr);
+ prev->addChild(repr, ref);
+
+ sp_document_done(current_document);
+ set_tree_select(repr);
+ set_dt_select(repr);
+
+} // end of cmd_indent_node()
+
+
+
+void cmd_unindent_node(GtkObject *object, gpointer data)
+{
+ Inkscape::XML::Node *repr = selected_repr;
+ g_assert(repr != NULL);
+ Inkscape::XML::Node *parent = sp_repr_parent(repr);
+ g_return_if_fail(parent);
+ Inkscape::XML::Node *grandparent = sp_repr_parent(parent);
+ g_return_if_fail(grandparent);
+
+ parent->removeChild(repr);
+ grandparent->addChild(repr, parent);
+
+ sp_document_done(current_document);
+ set_tree_select(repr);
+ set_dt_select(repr);
+
+} // end of cmd_unindent_node()
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :