diff options
| author | John Smith <john.smith7545@yahoo.com> | 2012-03-09 09:28:41 +0000 |
|---|---|---|
| committer | John Smith <removethis.john.q.public@bigmail.com> | 2012-03-09 09:28:41 +0000 |
| commit | 4af38650947ee08480d3887ada93ecff68a7157e (patch) | |
| tree | 6f71bb209540fdbbdae8b1ea00f2209931b2351f /src | |
| parent | powerstroke: - add miter size limit (diff) | |
| download | inkscape-4af38650947ee08480d3887ada93ecff68a7157e.tar.gz inkscape-4af38650947ee08480d3887ada93ecff68a7157e.zip | |
Fix for 940715 : Convert XML Editor to a dockable dialog
(bzr r11065)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dialogs/Makefile_insert | 4 | ||||
| -rw-r--r-- | src/dialogs/xml-tree.cpp | 1724 | ||||
| -rw-r--r-- | src/dialogs/xml-tree.h | 29 | ||||
| -rw-r--r-- | src/ui/dialog/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/ui/dialog/dialog-manager.cpp | 3 | ||||
| -rw-r--r-- | src/ui/dialog/xml-tree.cpp | 1202 | ||||
| -rw-r--r-- | src/ui/dialog/xml-tree.h | 268 | ||||
| -rw-r--r-- | src/verbs.cpp | 3 |
8 files changed, 1477 insertions, 1758 deletions
diff --git a/src/dialogs/Makefile_insert b/src/dialogs/Makefile_insert index 2350bfc28..ac0792a73 100644 --- a/src/dialogs/Makefile_insert +++ b/src/dialogs/Makefile_insert @@ -6,6 +6,4 @@ ink_common_sources += \ dialogs/dialog-events.cpp \ dialogs/dialog-events.h \ dialogs/find.cpp \ - dialogs/find.h \ - dialogs/xml-tree.cpp \ - dialogs/xml-tree.h + dialogs/find.h diff --git a/src/dialogs/xml-tree.cpp b/src/dialogs/xml-tree.cpp deleted file mode 100644 index 92ce03888..000000000 --- a/src/dialogs/xml-tree.cpp +++ /dev/null @@ -1,1724 +0,0 @@ -/** - * @file - * XML editor. - */ -/* Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * MenTaLguY <mental@rydia.net> - * bulia byak <buliabyak@users.sf.net> - * Johan Engelen <goejendaagh@zonnet.nl> - * David Turner - * Jon A. Cruz <jon@joncruz.org> - * Abhishek Sharma - * - * Copyright (C) 1999-2006 Authors - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "widgets/icon.h" -#include <gdk/gdkkeysyms.h> -#include <glibmm/i18n.h> - -#include "desktop.h" -#include "../desktop-handles.h" -#include "dialog-events.h" -#include "../document.h" -#include "../document-undo.h" -#include "../event-context.h" -#include "helper/window.h" -#include "../inkscape.h" -#include "../interface.h" -#include "macros.h" -#include "message-context.h" -#include "message-stack.h" -#include "../preferences.h" -#include "../selection.h" -#include "shortcuts.h" -#include "../sp-root.h" -#include "../sp-string.h" -#include "../sp-tspan.h" -#include "ui/icon-names.h" -#include "../verbs.h" -#include "../widgets/sp-xmlview-attr-list.h" -#include "../widgets/sp-xmlview-content.h" -#include "../widgets/sp-xmlview-tree.h" -#include "util/ege-appear-time-tracker.h" - -using Inkscape::DocumentUndo; -using ege::AppearTimeTracker; - -#define MIN_ONSCREEN_DISTANCE 50 - -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 Glib::ustring const 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 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_activate( Inkscape::Application *inkscape, SPDesktop *desktop, GtkWidget *dialog ); -static void sp_xmltree_desktop_deactivate( 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); - -static bool in_dt_coordsys(SPObject const &item); - -/** - * 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.")); -} - - -/** - * 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; - } - - bool wantTiming = Inkscape::Preferences::get()->getBool("/dialogs/debug/trackAppear", false); - GTimer *timer = wantTiming ? g_timer_new() : 0; - - if (dlg == NULL) - { // very long block - - GtkWidget *box, *sw, *paned, *toolbar; - GtkWidget *text_container, *attr_container, *attr_subpaned_container, *box2; - GtkWidget *set_attr; - - dlg = sp_window_new("", TRUE); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (x == -1000 || y == -1000) { - x = prefs->getInt(prefs_path + "x", -1000); - y = prefs->getInt(prefs_path + "y", -1000); - } - if (w ==0 || h == 0) { - w = prefs->getInt(prefs_path + "w", 0); - h = prefs->getInt(prefs_path + "h", 0); - } - - prefs->setInt(prefs_path + "visible", 1); - -// if (x<0) x=0; -// if (y<0) y=0; - - if (w && h) { - gtk_window_resize((GtkWindow *) dlg, w, h); - } - if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE))) { - gtk_window_move((GtkWindow *) dlg, x, y); - } else { - gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); - } - - sp_transientize(dlg); - wd.win = dlg; - wd.stop = 0; - g_signal_connect ( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd ); - - g_signal_connect( G_OBJECT(dlg), "event", G_CALLBACK(sp_dialog_event_handler), dlg ); - - g_signal_connect( G_OBJECT(dlg), "destroy", G_CALLBACK(on_destroy), dlg); - g_signal_connect( G_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_widget_set_tooltip_text( GTK_WIDGET(tree), - _("Drag to reorder nodes") ); - - 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); - - toolbar = gtk_toolbar_new(); - gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); - gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0); - - GtkToolItem *xml_element_new_button = gtk_tool_button_new ( - sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, - INKSCAPE_ICON("xml-element-new")), - NULL); - - g_signal_connect (G_OBJECT(xml_element_new_button), - "clicked", - G_CALLBACK(cmd_new_element_node), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET(xml_element_new_button), - _("New element node")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), xml_element_new_button, -1); - - g_signal_connect_object (G_OBJECT(tree), - "tree_select_row", - G_CALLBACK(on_tree_select_row_enable_if_element), - xml_element_new_button, - (GConnectFlags)0); - - g_signal_connect_object (G_OBJECT(tree), - "tree_unselect_row", - G_CALLBACK(on_tree_unselect_row_disable), - xml_element_new_button, - (GConnectFlags)0); - - gtk_widget_set_sensitive(GTK_WIDGET(xml_element_new_button), FALSE); - - GtkToolItem *xml_text_new_button = gtk_tool_button_new ( - sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, - INKSCAPE_ICON("xml-text-new")), - NULL); - - g_signal_connect (G_OBJECT(xml_text_new_button), - "clicked", - G_CALLBACK(cmd_new_text_node), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET(xml_text_new_button), - _("New text node")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), xml_text_new_button, -1); - - g_signal_connect_object(G_OBJECT(tree), - "tree_select_row", - G_CALLBACK(on_tree_select_row_enable_if_element), - xml_text_new_button, - (GConnectFlags)0); - - g_signal_connect_object(G_OBJECT(tree), - "tree_unselect_row", - G_CALLBACK(on_tree_unselect_row_disable), - xml_text_new_button, - (GConnectFlags)0); - - gtk_widget_set_sensitive(GTK_WIDGET(xml_text_new_button), FALSE); - - GtkToolItem *xml_node_duplicate_button = gtk_tool_button_new ( - sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, - INKSCAPE_ICON("xml-node-duplicate")), - NULL); - - g_signal_connect (G_OBJECT(xml_node_duplicate_button), - "clicked", - G_CALLBACK(cmd_duplicate_node), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET(xml_node_duplicate_button), - _("Duplicate node")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), xml_node_duplicate_button, -1); - - g_signal_connect_object(G_OBJECT(tree), - "tree_select_row", - G_CALLBACK(on_tree_select_row_enable_if_mutable), - xml_node_duplicate_button, - (GConnectFlags)0); - - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - G_CALLBACK(on_tree_unselect_row_disable), - xml_node_duplicate_button, - (GConnectFlags)0); - - gtk_widget_set_sensitive(GTK_WIDGET(xml_node_duplicate_button), FALSE); - - GtkToolItem *separator = gtk_separator_tool_item_new (); - gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM(separator), FALSE); - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), separator, -1); - - GtkToolItem *xml_node_delete_button = gtk_tool_button_new ( - sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, - INKSCAPE_ICON ("xml-node-delete")), - NULL); - - g_signal_connect (G_OBJECT(xml_node_delete_button), - "clicked", - G_CALLBACK(cmd_delete_node), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET(xml_node_delete_button), - Q_("nodeAsInXMLdialogTooltip|Delete node")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), xml_node_delete_button, -1); - - g_signal_connect_object(G_OBJECT(tree), "tree_select_row", - G_CALLBACK(on_tree_select_row_enable_if_mutable), - xml_node_delete_button, - (GConnectFlags)0); - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - G_CALLBACK(on_tree_unselect_row_disable), - xml_node_delete_button, - (GConnectFlags)0); - gtk_widget_set_sensitive(GTK_WIDGET(xml_node_delete_button), FALSE); - - GtkToolItem *separator2 = gtk_separator_tool_item_new (); - gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM(separator2), FALSE); - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), separator2, -1); - - GtkToolItem *unindent_node_button = gtk_tool_button_new ( - gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_IN), - "<"); - - g_signal_connect (G_OBJECT(unindent_node_button), - "clicked", - G_CALLBACK(cmd_unindent_node), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET(unindent_node_button), - _("Unindent node")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), unindent_node_button, -1); - - g_signal_connect_object(G_OBJECT(tree), "tree_select_row", - G_CALLBACK(on_tree_select_row_enable_if_has_grandparent), - unindent_node_button, - (GConnectFlags)0); - - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - G_CALLBACK(on_tree_unselect_row_disable), - unindent_node_button, - (GConnectFlags)0); - - gtk_widget_set_sensitive(GTK_WIDGET(unindent_node_button), FALSE); - - GtkToolItem *indent_node_button = gtk_tool_button_new ( - gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_IN), - ">"); - - g_signal_connect (G_OBJECT(indent_node_button), - "clicked", - G_CALLBACK(cmd_indent_node), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET(indent_node_button), - _("Indent node")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), indent_node_button, -1); - - g_signal_connect_object(G_OBJECT(tree), "tree_select_row", - G_CALLBACK(on_tree_select_row_enable_if_indentable), - indent_node_button, - (GConnectFlags)0); - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - (GCallback) on_tree_unselect_row_disable, - indent_node_button, - (GConnectFlags)0); - gtk_widget_set_sensitive(GTK_WIDGET(indent_node_button), FALSE); - - GtkToolItem *raise_node_button = gtk_tool_button_new ( - gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_IN), - "^"); - - g_signal_connect (G_OBJECT(raise_node_button), - "clicked", - G_CALLBACK(cmd_raise_node), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET (raise_node_button), - _("Raise node")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), raise_node_button, -1); - - g_signal_connect_object(G_OBJECT(tree), "tree_select_row", - G_CALLBACK(on_tree_select_row_enable_if_not_first_child), - raise_node_button, - (GConnectFlags)0); - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - G_CALLBACK(on_tree_unselect_row_disable), - raise_node_button, - (GConnectFlags)0); - gtk_widget_set_sensitive(GTK_WIDGET(raise_node_button), FALSE); - - GtkToolItem *lower_node_button = gtk_tool_button_new ( - gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN), - "v"); - - g_signal_connect (G_OBJECT(lower_node_button), - "clicked", - G_CALLBACK(cmd_lower_node), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET (lower_node_button), - _("Lower node")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), lower_node_button, -1); - - g_signal_connect_object(G_OBJECT(tree), "tree_select_row", - G_CALLBACK(on_tree_select_row_enable_if_not_last_child), - lower_node_button, - (GConnectFlags)0); - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - G_CALLBACK(on_tree_unselect_row_disable), - lower_node_button, - (GConnectFlags)0); - gtk_widget_set_sensitive(GTK_WIDGET(lower_node_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); - - GtkToolItem* xml_attribute_delete_button = gtk_tool_button_new ( - sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, - INKSCAPE_ICON ("xml-attribute-delete")), - NULL); - - g_signal_connect (G_OBJECT(xml_attribute_delete_button), - "clicked", - G_CALLBACK(cmd_delete_attr), - NULL); - - gtk_widget_set_tooltip_text (GTK_WIDGET(xml_attribute_delete_button), - _("Delete attribute")); - - gtk_toolbar_insert (GTK_TOOLBAR(toolbar), xml_attribute_delete_button, -1); - - g_signal_connect_object(G_OBJECT(attributes), "select_row", - (GCallback) on_attr_select_row_enable, - xml_attribute_delete_button, - (GConnectFlags)0); - - g_signal_connect_object(G_OBJECT(attributes), "unselect_row", - (GCallback) on_attr_unselect_row_disable, - xml_attribute_delete_button, - (GConnectFlags)0); - - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - (GCallback) on_tree_unselect_row_disable, - xml_attribute_delete_button, - (GConnectFlags)0); - - gtk_widget_set_sensitive(GTK_WIDGET(xml_attribute_delete_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_widget_set_tooltip_text( GTK_WIDGET(attr_name), - // TRANSLATORS: "Attribute" is a noun here - _("Attribute name") ); - - g_signal_connect( G_OBJECT(attributes), "select_row", - (GCallback) on_attr_select_row_set_name_content, - attr_name); - - g_signal_connect( G_OBJECT(attributes), "unselect_row", - (GCallback) on_attr_unselect_row_clear_text, - attr_name); - - g_signal_connect( G_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_widget_set_tooltip_text( GTK_WIDGET(set_attr), - // TRANSLATORS: "Set" is a verb here - _("Set attribute") ); - // TRANSLATORS: "Set" is a verb here - GtkWidget *set_label = gtk_label_new(_("Set")); - gtk_container_add(GTK_CONTAINER(set_attr), set_label); - - g_signal_connect( G_OBJECT(set_attr), "clicked", - (GCallback) cmd_set_attr, NULL); - g_signal_connect( G_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_widget_set_size_request((GtkWidget *)attr_value, 0, 60); - gtk_text_view_set_wrap_mode((GtkTextView *) attr_value, GTK_WRAP_CHAR); - gtk_widget_set_tooltip_text( GTK_WIDGET(attr_value), - // TRANSLATORS: "Attribute" is a noun here - _("Attribute value") ); - g_signal_connect( G_OBJECT(attributes), "select_row", - (GCallback) on_attr_select_row_set_value_content, - attr_value ); - g_signal_connect( G_OBJECT(attributes), "unselect_row", - (GCallback) on_attr_unselect_row_clear_text, - attr_value ); - g_signal_connect( G_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)); - - g_signal_connect_object(G_OBJECT(tree), "tree_select_row", - (GCallback) on_tree_select_row_show_if_element, - attr_container, - (GConnectFlags)0); - - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - (GCallback) on_tree_unselect_row_hide, - attr_container, - (GConnectFlags)0); - - gtk_widget_hide(attr_container); - - g_signal_connect_object(G_OBJECT(tree), "tree_select_row", - (GCallback) on_tree_select_row_show_if_text, - text_container, - (GConnectFlags)0); - - g_signal_connect_object(G_OBJECT(tree), "tree_unselect_row", - (GCallback) on_tree_unselect_row_hide, - text_container, - (GConnectFlags)0); - - gtk_widget_hide(text_container); - - g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop", - G_CALLBACK(sp_xmltree_desktop_activate), dlg); - - g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop", - G_CALLBACK(sp_xmltree_desktop_deactivate), dlg); - - g_signal_connect((GObject *) dlg, "key_press_event", (GCallback) sp_xml_tree_key_press, NULL); - - tree_reset_context(); - } // end of if (dlg == NULL) - - if ( wantTiming ) { - // Time tracker takes ownership of the timer. - AppearTimeTracker *tracker = new AppearTimeTracker(timer, GTK_WIDGET(dlg), "DialogXMLEditor"); - tracker->setAutodelete(true); - timer = 0; - } - - 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_activate(Inkscape::Application */*inkscape*/, - SPDesktop *desktop, - GtkWidget */*dialog*/ ) -{ - set_tree_desktop(desktop); -} - -static void sp_xmltree_desktop_deactivate(Inkscape::Application */*inkscape*/, - SPDesktop */*desktop*/, - GtkWidget */*dialog*/ ) -{ - set_tree_desktop(NULL); -} - - -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_desktop_selection(desktop)->connectChanged(&on_desktop_selection_changed); - document_replaced_connection = desktop->connectDocumentReplaced(&on_document_replaced); - set_tree_document(sp_desktop_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( current_document->getURI(), current_document ); - set_tree_repr(current_document->getReprRoot()); - } 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 || repr->type() == Inkscape::XML::PI_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_desktop_selection(current_desktop)->singleRepr(); -} - - - -void set_dt_select(Inkscape::XML::Node *repr) -{ - if (!current_desktop) { - return; - } - - Inkscape::Selection *selection = sp_desktop_selection(current_desktop); - - SPObject *object; - if (repr) { - while ( ( repr->type() != Inkscape::XML::ELEMENT_NODE ) - && repr->parent() ) - { - repr = repr->parent(); - } // end of while loop - - object = sp_desktop_document(current_desktop)->getObjectByRepr(repr); - } else { - object = NULL; - } - - blocked++; - if ( object && in_dt_coordsys(*object) - && !(SP_IS_STRING(object) || - SP_IS_ROOT(object) ) ) - { - /* We cannot set selection to root or string - they are not items and selection is not - * equipped to deal with them */ - 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) - { - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Drag XML subtree")); - } else { - DocumentUndo::cancel(current_document); - } -} - - -static void on_destroy(GtkObject */*object*/, gpointer /*data*/) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt(prefs_path + "visible", 0); - - set_tree_desktop(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); - - if (x<0) x=0; - if (y<0) y=0; - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt(prefs_path + "x", x); - prefs->setInt(prefs_path + "y", y); - prefs->setInt(prefs_path + "w", w); - prefs->setInt(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 || repr->type() == Inkscape::XML::PI_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_desktop_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", document->getName(), 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); -} - -gboolean -quit_on_esc (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/) -{ - switch (get_group0_keyval (event)) { - case GDK_Escape: // defocus - gtk_widget_destroy(w); - return TRUE; - } - return FALSE; -} - -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_resizable(GTK_WINDOW(window), FALSE); - 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); - g_signal_connect(G_OBJECT(window), "destroy", gtk_main_quit, NULL); - g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(quit_on_esc), window); - - 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_widget_set_can_default( GTK_WIDGET(cancel), TRUE ); - g_signal_connect_swapped( G_OBJECT(cancel), "clicked", - G_CALLBACK(gtk_widget_destroy), - G_OBJECT(window) ); - gtk_container_add(GTK_CONTAINER(bbox), cancel); - - create = gtk_button_new_with_label(_("Create")); - gtk_widget_set_sensitive(GTK_WIDGET(create), FALSE); - g_signal_connect( G_OBJECT(entry), "changed", - G_CALLBACK(on_editable_changed_enable_if_valid_xml_name), - create ); - g_signal_connect( G_OBJECT(create), "clicked", - G_CALLBACK(on_clicked_get_editable_text), &name ); - g_signal_connect_swapped( G_OBJECT(create), "clicked", - G_CALLBACK(gtk_widget_destroy), - G_OBJECT(window) ); - gtk_widget_set_can_default( GTK_WIDGET(create), TRUE ); - gtk_widget_set_receives_default( GTK_WIDGET(create), TRUE ); - 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(); - - if (selected_repr != NULL && name.text) { - Inkscape::XML::Document *xml_doc = current_document->getReprDoc(); - Inkscape::XML::Node *new_repr; - new_repr = xml_doc->createElement(name.text); - Inkscape::GC::release(new_repr); - g_free(name.text); - selected_repr->appendChild(new_repr); - set_tree_select(new_repr); - set_dt_select(new_repr); - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Create new element node")); - } - -} // end of cmd_new_element_node() - - - -void cmd_new_text_node(GtkObject */*object*/, gpointer /*data*/) -{ - g_assert(selected_repr != NULL); - - Inkscape::XML::Document *xml_doc = current_document->getReprDoc(); - Inkscape::XML::Node *text = xml_doc->createTextNode(""); - selected_repr->appendChild(text); - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Create new text node")); - - 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 = selected_repr->parent(); - Inkscape::XML::Node *dup = selected_repr->duplicate(parent->document()); - parent->addChild(dup, selected_repr); - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Duplicate node")); - - 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); - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - Q_("nodeAsInXMLinHistoryDialog|Delete node")); -} - - - -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(); - } - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Delete attribute")); -} - - - -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 ); - - selected_repr->setAttribute(name, value, false); - - g_free(name); - g_free(value); - - SPObject *updated = current_document->getObjectByRepr(selected_repr); - if (updated) { - // force immediate update of dependant attributes - updated->updateRepr(); - } - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Change attribute")); - - /* 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 = selected_repr->parent(); - 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); - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Raise node")); - - 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 = selected_repr->parent(); - - parent->changeOrder(selected_repr, selected_repr->next()); - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Lower node")); - - 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 = repr->parent(); - 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); - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Indent node")); - 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 = repr->parent(); - g_return_if_fail(parent); - Inkscape::XML::Node *grandparent = parent->parent(); - g_return_if_fail(grandparent); - - parent->removeChild(repr); - grandparent->addChild(repr, parent); - - DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, - _("Unindent node")); - set_tree_select(repr); - set_dt_select(repr); - -} // end of cmd_unindent_node() - -/** Returns true iff \a item is suitable to be included in the selection, in particular - whether it has a bounding box in the desktop coordinate system for rendering resize handles. - - Descendents of <defs> nodes (markers etc.) return false, for example. -*/ -bool in_dt_coordsys(SPObject const &item) -{ - /* Definition based on sp_item_i2doc_affine. */ - SPObject const *child = &item; - g_return_val_if_fail(child != NULL, false); - for(;;) { - if (!SP_IS_ITEM(child)) { - return false; - } - SPObject const * const parent = child->parent; - if (parent == NULL) { - break; - } - child = parent; - } - g_assert(SP_IS_ROOT(child)); - /* Relevance: Otherwise, I'm not sure whether to return true or false. */ - return true; -} - - -/* - 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/dialogs/xml-tree.h b/src/dialogs/xml-tree.h deleted file mode 100644 index 8b1a21337..000000000 --- a/src/dialogs/xml-tree.h +++ /dev/null @@ -1,29 +0,0 @@ -/** @file - * @brief XML tree editing dialog for Inkscape - */ -/* Copyright Lauris Kaplinski, 2000 - * - * Released under GNU General Public License. - * - * This is XML tree editor, which allows direct modifying of all elements - * of Inkscape document, including foreign ones. - * - */ - -#ifndef SEEN_DIALOGS_XML_TREE_H -#define SEEN_DIALOGS_XML_TREE_H - -void sp_xml_tree_dialog (void); - -#endif - -/* - 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index f91a1865c..91b1ccaf6 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -95,4 +95,6 @@ ink_common_sources += \ ui/dialog/transformation.h \ ui/dialog/undo-history.cpp \ ui/dialog/undo-history.h \ + ui/dialog/xml-tree.cpp \ + ui/dialog/xml-tree.h \ $(inkboard_dialogs) diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index 00f14ee03..2e7ffa1c2 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -50,6 +50,7 @@ #include "ui/dialog/text-edit.h" #include "ui/dialog/spellcheck.h" #include "ui/dialog/export.h" +#include "ui/dialog/xml-tree.h" #ifdef ENABLE_SVG_FONTS #include "ui/dialog/svg-fonts-dialog.h" @@ -127,6 +128,7 @@ DialogManager::DialogManager() { registerFactory("TextFont", &create<TextEdit, FloatingBehavior>); registerFactory("SpellCheck", &create<SpellCheck, FloatingBehavior>); registerFactory("Export", &create<Export, FloatingBehavior>); + registerFactory("XmlTree", &create<XmlTree, FloatingBehavior>); } else { @@ -160,6 +162,7 @@ DialogManager::DialogManager() { registerFactory("TextFont", &create<TextEdit, DockBehavior>); registerFactory("SpellCheck", &create<SpellCheck, DockBehavior>); registerFactory("Export", &create<Export, DockBehavior>); + registerFactory("XmlTree", &create<XmlTree, DockBehavior>); } } diff --git a/src/ui/dialog/xml-tree.cpp b/src/ui/dialog/xml-tree.cpp new file mode 100644 index 000000000..27064d393 --- /dev/null +++ b/src/ui/dialog/xml-tree.cpp @@ -0,0 +1,1202 @@ +/** + * @file + * XML editor. + */ +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * MenTaLguY <mental@rydia.net> + * bulia byak <buliabyak@users.sf.net> + * Johan Engelen <goejendaagh@zonnet.nl> + * David Turner + * Jon A. Cruz <jon@joncruz.org> + * Abhishek Sharma + * + * Copyright (C) 1999-2006 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + * + */ + +#include "widgets/icon.h" +#include <gdk/gdkkeysyms.h> +#include <glibmm/i18n.h> +#include <gtkmm/stock.h> + +#include "desktop.h" +#include "desktop-handles.h" +#include "dialogs/dialog-events.h" +#include "document.h" +#include "document-undo.h" +#include "event-context.h" +#include "helper/window.h" +#include "inkscape.h" +#include "interface.h" +#include "macros.h" +#include "message-context.h" +#include "message-stack.h" +#include "preferences.h" +#include "selection.h" +#include "shortcuts.h" +#include "sp-root.h" +#include "sp-string.h" +#include "sp-tspan.h" +#include "ui/icon-names.h" +#include "verbs.h" +#include "widgets/icon.h" + +#include "xml-tree.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +XmlTree::XmlTree (void) : + UI::Widget::Panel ("", "/dialogs/xml/", SP_VERB_DIALOG_XML_EDITOR), + blocked (0), + _message_stack (NULL), + _message_context (NULL), + current_desktop (NULL), + current_document (NULL), + selected_attr (0), + selected_repr (NULL), + tree (NULL), + attributes (NULL), + content (NULL), + attr_name (), + attr_value (), + status (""), + tree_toolbar(), + xml_element_new_button ( _("New element node")), + xml_text_new_button ( _("New text node")), + xml_node_delete_button ( Q_("nodeAsInXMLdialogTooltip|Delete node")), + xml_node_duplicate_button ( _("Duplicate node")), + unindent_node_button (Gtk::Stock::UNINDENT), + indent_node_button (Gtk::Stock::INDENT), + raise_node_button (Gtk::Stock::GO_UP), + lower_node_button (Gtk::Stock::GO_DOWN), + attr_toolbar(), + xml_attribute_delete_button (_("Delete attribute")), + text_container (), + attr_container (), + attr_subpaned_container (), + set_attr (_("Set")), + new_window(NULL) +{ + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (!desktop) { + return; + } + + Gtk::Box *contents = _getContents(); + contents->set_spacing(0); + contents->set_size_request(320, 260); + + status.set_alignment( 0.0, 0.5); + status.set_size_request(1, -1); + status.set_markup(""); + status_box.pack_start( status, TRUE, TRUE, 0); + contents->pack_end(status_box, false, false, 2); + + paned.set_position(256); + contents->pack_start(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), GTK_WIDGET(status.gobj()))); + + /* tree view */ + paned.pack1(left_box); + + tree = SP_XMLVIEW_TREE(sp_xmlview_tree_new(NULL, NULL, NULL)); + gtk_widget_set_tooltip_text( GTK_WIDGET(tree), _("Drag to reorder nodes") ); + + tree_toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS); + xml_element_new_button.set_icon_widget(*Gtk::manage(Glib::wrap( + sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, INKSCAPE_ICON("xml-element-new")))) ); + xml_element_new_button.set_tooltip_text(_("New element node")); + xml_element_new_button.set_sensitive(false); + tree_toolbar.add(xml_element_new_button); + + xml_text_new_button.set_icon_widget(*Gtk::manage(Glib::wrap( + sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, INKSCAPE_ICON("xml-text-new"))))); + xml_text_new_button.set_tooltip_text(_("New text node")); + xml_text_new_button.set_sensitive(false); + tree_toolbar.add(xml_text_new_button); + + xml_node_duplicate_button.set_icon_widget(*Gtk::manage(Glib::wrap( + sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, INKSCAPE_ICON("xml-node-duplicate"))))); + xml_node_duplicate_button.set_tooltip_text(_("Duplicate node")); + xml_node_duplicate_button.set_sensitive(false); + tree_toolbar.add(xml_node_duplicate_button); + + tree_toolbar.add(separator); + + xml_node_delete_button.set_icon_widget(*Gtk::manage(Glib::wrap( + sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, INKSCAPE_ICON("xml-node-delete"))))); + xml_node_delete_button.set_tooltip_text(Q_("nodeAsInXMLdialogTooltip|Delete node")); + xml_node_delete_button.set_sensitive(false); + tree_toolbar.add(xml_node_delete_button); + + tree_toolbar.add(separator2); + + unindent_node_button.set_label(_("Unindent node")); + unindent_node_button.set_tooltip_text(_("Unindent node")); + unindent_node_button.set_sensitive(false); + tree_toolbar.add(unindent_node_button); + + indent_node_button.set_label(_("Indent node")); + indent_node_button.set_tooltip_text(_("Indent node")); + indent_node_button.set_sensitive(false); + tree_toolbar.add(indent_node_button); + + raise_node_button.set_label(_("Raise node")); + raise_node_button.set_tooltip_text(_("Raise node")); + raise_node_button.set_sensitive(false); + tree_toolbar.add(raise_node_button); + + lower_node_button.set_label(_("Lower node")); + lower_node_button.set_tooltip_text(_("Lower node")); + lower_node_button.set_sensitive(false); + tree_toolbar.add(lower_node_button); + + left_box.pack_start(tree_toolbar, FALSE, TRUE, 0); + + Gtk::ScrolledWindow *tree_scroller = new Gtk::ScrolledWindow(); + tree_scroller->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + tree_scroller->add(*Gtk::manage(Glib::wrap(GTK_WIDGET(tree)))); + + left_box.pack_start(*tree_scroller); + + /* node view */ + paned.pack2(right_box); + + /* attributes */ + right_box.pack_start( attr_container, TRUE, TRUE, 0 ); + + attributes = SP_XMLVIEW_ATTR_LIST(sp_xmlview_attr_list_new(NULL)); + + attr_toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS); + xml_attribute_delete_button.set_icon_widget(*Gtk::manage(Glib::wrap(sp_icon_new (Inkscape::ICON_SIZE_LARGE_TOOLBAR, INKSCAPE_ICON("xml-attribute-delete"))))); + xml_attribute_delete_button.set_tooltip_text(_("Delete attribute")); + xml_attribute_delete_button.set_sensitive(false); + attr_toolbar.add(xml_attribute_delete_button); + + attr_container.pack_start( attr_toolbar, FALSE, TRUE, 0 ); + attr_container.pack_start( attr_subpaned_container, TRUE, TRUE, 0 ); + + Gtk::ScrolledWindow *attr_scroller = new Gtk::ScrolledWindow(); + attr_scroller->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + attr_scroller->set_size_request(0, 60); + + attr_subpaned_container.pack1( *attr_scroller ); + attr_scroller->add(*Gtk::manage(Glib::wrap(GTK_WIDGET(attributes)))); + + attr_vbox.pack_start( attr_hbox, FALSE, TRUE, 0); + + attr_name.set_tooltip_text(_("Attribute name") ); // TRANSLATORS: "Attribute" is a noun here + attr_name.set_width_chars (10); + attr_hbox.pack_start( attr_name, TRUE, TRUE, 0); + + set_attr.set_sensitive(FALSE); + attr_hbox.pack_start(set_attr, FALSE, FALSE, 0); + + Gtk::ScrolledWindow *scroller = new Gtk::ScrolledWindow(); + scroller->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + scroller->set_shadow_type(Gtk::SHADOW_IN); + + attr_vbox.pack_start(*scroller, TRUE, TRUE, 0); + + attr_value.set_size_request(0, 60); + attr_value.set_wrap_mode(Gtk::WRAP_CHAR); + attr_value.set_tooltip_text( _("Attribute value") );// TRANSLATORS: "Attribute" is a noun here + attr_value.set_editable(TRUE); + scroller->add(attr_value); + + attr_subpaned_container.pack2( attr_vbox, FALSE, TRUE ); + + /* text */ + text_container.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + right_box.pack_start(text_container, TRUE, TRUE, 0); + + content = SP_XMLVIEW_CONTENT(sp_xmlview_content_new(NULL)); + text_container.add(*Gtk::manage(Glib::wrap(GTK_WIDGET(content)))); + + /* Signal handlers */ + g_signal_connect( G_OBJECT(tree), "tree_select_row", G_CALLBACK(on_tree_select_row), this ); + g_signal_connect( G_OBJECT(tree), "tree_unselect_row", G_CALLBACK(on_tree_unselect_row), this); + g_signal_connect_after( G_OBJECT(tree), "tree_move", G_CALLBACK(after_tree_move), this); + + g_signal_connect( G_OBJECT(attributes), "select_row", G_CALLBACK(on_attr_select_row), this); + g_signal_connect( G_OBJECT(attributes), "unselect_row", G_CALLBACK(on_attr_unselect_row), this); + g_signal_connect( G_OBJECT(attributes), "row-value-changed", G_CALLBACK(on_attr_row_changed), this); + + xml_element_new_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_new_element_node)); + xml_text_new_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_new_text_node)); + xml_node_duplicate_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_duplicate_node)); + xml_node_delete_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_delete_node)); + unindent_node_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_unindent_node)); + indent_node_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_indent_node)); + raise_node_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_raise_node)); + lower_node_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_lower_node)); + xml_attribute_delete_button.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_delete_attr)); + set_attr.signal_clicked().connect(sigc::mem_fun(*this, &XmlTree::cmd_set_attr)); + attr_name.signal_changed().connect(sigc::mem_fun(*this, &XmlTree::onNameChanged)); + attr_value.signal_key_press_event().connect(sigc::mem_fun(*this, &XmlTree::sp_xml_tree_key_press), false); + + desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &XmlTree::set_tree_desktop) ); + deskTrack.connect(GTK_WIDGET(gobj())); + + /* initial show/hide */ + show_all(); + +/* + // hide() doesn't seem to work in the constructor, so moved this to present() + text_container.hide(); + attr_container.hide(); +*/ + + tree_reset_context(); + + g_assert(desktop != NULL); + set_tree_desktop(desktop); + +} + +void XmlTree::present() +{ + text_container.hide(); + attr_container.hide(); + + set_tree_select(get_dt_select()); + + UI::Widget::Panel::present(); +} + +XmlTree::~XmlTree (void) +{ + set_tree_desktop(NULL); + + _message_changed_connection.disconnect(); + delete _message_context; + _message_context = NULL; + Inkscape::GC::release(_message_stack); + _message_stack = NULL; + _message_changed_connection.~connection(); + + //status = ""; +} + +void XmlTree::setDesktop(SPDesktop *desktop) +{ + Panel::setDesktop(desktop); + deskTrack.setBase(desktop); +} + +/** + * Sets the XML status bar when the tree is selected. + */ +void XmlTree::tree_reset_context() +{ + _message_context->set(Inkscape::NORMAL_MESSAGE, + _("<b>Click</b> to select nodes, <b>drag</b> to rearrange.")); +} + + +/** + * Sets the XML status bar, depending on which attr is selected. + */ +void XmlTree::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); + } +} + +bool XmlTree::sp_xml_tree_key_press(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(); + return true; + } + return false; +} + +void XmlTree::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_desktop_selection(desktop)->connectChanged(sigc::hide(sigc::mem_fun(this, &XmlTree::on_desktop_selection_changed))); + document_replaced_connection = desktop->connectDocumentReplaced(sigc::mem_fun(this, &XmlTree::on_document_replaced)); + + set_tree_document(sp_desktop_document(desktop)); + } else { + set_tree_document(NULL); + } + +} // end of set_tree_desktop() + + +void XmlTree::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( current_document->getURI(), current_document ); + set_tree_repr(current_document->getReprRoot()); + } else { + set_tree_repr(NULL); + } +} + + + +void XmlTree::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 XmlTree::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)); + on_tree_unselect_row_disable(); + on_tree_unselect_row_hide(); + } + propagate_tree_select(repr); +} + + + +void XmlTree::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 || repr->type() == Inkscape::XML::PI_NODE ) ) { + sp_xmlview_content_set_repr(content, repr); + } else { + sp_xmlview_content_set_repr(content, NULL); + } +} + + +Inkscape::XML::Node *XmlTree::get_dt_select() +{ + if (!current_desktop) { + return NULL; + } + return sp_desktop_selection(current_desktop)->singleRepr(); +} + + + +void XmlTree::set_dt_select(Inkscape::XML::Node *repr) +{ + if (!current_desktop) { + return; + } + + Inkscape::Selection *selection = sp_desktop_selection(current_desktop); + + SPObject *object; + if (repr) { + while ( ( repr->type() != Inkscape::XML::ELEMENT_NODE ) + && repr->parent() ) + { + repr = repr->parent(); + } // end of while loop + + object = sp_desktop_document(current_desktop)->getObjectByRepr(repr); + } else { + object = NULL; + } + + blocked++; + if ( object && in_dt_coordsys(*object) + && !(SP_IS_STRING(object) || + SP_IS_ROOT(object) ) ) + { + /* We cannot set selection to root or string - they are not items and selection is not + * equipped to deal with them */ + selection->set(SP_ITEM(object)); + } + blocked--; + +} // end of set_dt_select() + + +void XmlTree::on_tree_select_row(GtkCTree *tree, + GtkCTreeNode *node, + gint column, + gpointer data) +{ + XmlTree *self = (XmlTree *)data; + + Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node); + g_assert(repr != NULL); + + if (self->selected_repr) { + Inkscape::GC::release(self->selected_repr); + self->selected_repr = NULL; + } + self->selected_repr = repr; + Inkscape::GC::anchor(self->selected_repr); + + self->propagate_tree_select(self->selected_repr); + + self->set_dt_select(self->selected_repr); + + self->tree_reset_context(); + + self->on_tree_select_row_enable(node); +} + +void XmlTree::on_tree_unselect_row(GtkCTree *tree, + GtkCTreeNode *node, + gint column, + gpointer data) +{ + XmlTree *self = (XmlTree *)data; + + if (self->blocked) { + return; + } + + + Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node); + self->propagate_tree_select(NULL); + self->set_dt_select(NULL); + + if (self->selected_repr && (self->selected_repr == repr)) { + Inkscape::GC::release(self->selected_repr); + self->selected_repr = NULL; + self->selected_attr = 0; + } + + self->on_tree_unselect_row_disable(); + self->on_tree_unselect_row_hide(); + self->on_attr_unselect_row_clear_text(); +} + + + +void XmlTree::after_tree_move(GtkCTree */*tree*/, + GtkCTreeNode *node, + GtkCTreeNode *new_parent, + GtkCTreeNode *new_sibling, + gpointer data) +{ + XmlTree *self = (XmlTree *)data; + + if (GTK_CTREE_ROW(node)->parent == new_parent && + GTK_CTREE_ROW(node)->sibling == new_sibling) + { + DocumentUndo::done(self->current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Drag XML subtree")); + } else { + DocumentUndo::cancel(self->current_document); + } +} + +void XmlTree::_set_status_message(Inkscape::MessageType /*type*/, const gchar *message, GtkWidget *widget) +{ + if (widget) { + gtk_label_set_markup(GTK_LABEL(widget), message ? message : ""); + } +} + +void XmlTree::on_tree_select_row_enable(GtkCTreeNode *node) +{ + if (!node) { + return; + } + + Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(SP_XMLVIEW_TREE(tree), node); + Inkscape::XML::Node *parent=repr->parent(); + + //on_tree_select_row_enable_if_mutable + xml_node_duplicate_button.set_sensitive(xml_tree_node_mutable(node)); + xml_node_delete_button.set_sensitive(xml_tree_node_mutable(node)); + + //on_tree_select_row_enable_if_element + if (repr->type() == Inkscape::XML::ELEMENT_NODE) { + xml_element_new_button.set_sensitive(true); + xml_text_new_button.set_sensitive(true); + + } else { + xml_element_new_button.set_sensitive(false); + xml_text_new_button.set_sensitive(false); + } + + //on_tree_select_row_enable_if_has_grandparent + { + GtkCTreeNode *parent = GTK_CTREE_ROW(node)->parent; + + if (parent) { + GtkCTreeNode *grandparent = GTK_CTREE_ROW(parent)->parent; + if (grandparent) { + unindent_node_button.set_sensitive(true); + } else { + unindent_node_button.set_sensitive(false); + } + } else { + unindent_node_button.set_sensitive(false); + } + } + // on_tree_select_row_enable_if_indentable + gboolean indentable = FALSE; + + if (xml_tree_node_mutable(node)) { + Inkscape::XML::Node *prev; + + 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; + } + } + } + + indent_node_button.set_sensitive(indentable); + + //on_tree_select_row_enable_if_not_first_child + { + if ( parent && repr != parent->firstChild() ) { + raise_node_button.set_sensitive(true); + } else { + raise_node_button.set_sensitive(false); + } + } + + //on_tree_select_row_enable_if_not_last_child + { + if ( parent && parent->parent() && repr->next() ) { + lower_node_button.set_sensitive(true); + } else { + lower_node_button.set_sensitive(false); + } + } + + //on_tree_select_row_show_if_element + if (repr->type() == Inkscape::XML::ELEMENT_NODE) { + attr_container.show(); + } else { + attr_container.hide(); + } + + //on_tree_select_row_show_if_text + if ( repr->type() == Inkscape::XML::TEXT_NODE || repr->type() == Inkscape::XML::COMMENT_NODE || repr->type() == Inkscape::XML::PI_NODE ) { + text_container.show(); + } else { + text_container.hide(); + } + +} + + +gboolean XmlTree::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 XmlTree::on_tree_unselect_row_disable() +{ + xml_text_new_button.set_sensitive(false); + xml_element_new_button.set_sensitive(false); + xml_node_delete_button.set_sensitive(false); + xml_node_duplicate_button.set_sensitive(false); + unindent_node_button.set_sensitive(false); + indent_node_button.set_sensitive(false); + raise_node_button.set_sensitive(false); + lower_node_button.set_sensitive(false); + xml_attribute_delete_button.set_sensitive(false); +} + +void XmlTree::on_tree_unselect_row_hide() +{ + attr_container.hide(); + text_container.hide(); +} + +void XmlTree::on_attr_select_row(GtkCList *list, gint row, gint column, + GdkEventButton *event, gpointer data) +{ + XmlTree *self = (XmlTree *)data; + + self->selected_attr = sp_xmlview_attr_list_get_row_key(list, row); + self->attr_value.grab_focus (); + + self->attr_reset_context(self->selected_attr); + + self->on_attr_select_row_enable(); + self->on_attr_select_row_set_name_content(row); + self->on_attr_select_row_set_value_content(row); +} + + +void XmlTree::on_attr_unselect_row(GtkCList */*list*/, gint /*row*/, gint /*column*/, + GdkEventButton */*event*/, gpointer data) +{ + XmlTree *self = (XmlTree *)data; + + self->selected_attr = 0; + self->attr_reset_context(self->selected_attr); + + self->on_attr_unselect_row_disable(); + self->on_attr_unselect_row_clear_text(); +} + + +void XmlTree::on_attr_row_changed(GtkCList *list, gint row, gpointer data) +{ + gint attr = sp_xmlview_attr_list_get_row_key(list, row); + + XmlTree *self = (XmlTree *)data; + if (attr == self->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 = self->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 (self->attr_value), + &start, &end ); + gchar * text = gtk_text_buffer_get_text ( gtk_text_view_get_buffer (self->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 XmlTree::on_attr_select_row_set_name_content(gint row) +{ + const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(GTK_CLIST(attributes), row)); + attr_name.set_text(name); +} + + +void XmlTree::on_attr_select_row_set_value_content(gint row) +{ + const gchar *name = g_quark_to_string(sp_xmlview_attr_list_get_row_key(GTK_CLIST(attributes), row)); + const gchar *value = selected_repr->attribute(name); + if (!value) { + value = ""; + } + attr_value.get_buffer()->set_text(value); +} + +void XmlTree::on_attr_select_row_enable() +{ + xml_attribute_delete_button.set_sensitive(true); +} + + + +void XmlTree::on_attr_unselect_row_disable() +{ + xml_attribute_delete_button.set_sensitive(false); +} + + +void XmlTree::on_attr_unselect_row_clear_text() +{ + attr_name.set_text(""); + attr_value.get_buffer()->set_text("", 0); +} + +void XmlTree::onNameChanged() +{ + Glib::ustring text = attr_name.get_text(); + /* TODO: need to do checking a little more rigorous than this */ + if (!text.empty()) { + set_attr.set_sensitive(true); + } else { + set_attr.set_sensitive(false); + } +} + +void XmlTree::onCreateNameChanged() +{ + Glib::ustring text = name_entry->get_text(); + /* TODO: need to do checking a little more rigorous than this */ + if (!text.empty()) { + create_button->set_sensitive(true); + } else { + create_button->set_sensitive(false); + } +} + +void XmlTree::on_desktop_selection_changed() +{ + if (!blocked++) { + Inkscape::XML::Node *node = get_dt_select(); + set_tree_select(node); + if (!node) { + on_attr_unselect_row_clear_text(); + } + } + blocked--; +} + +void XmlTree::on_document_replaced(SPDesktop *dt, SPDocument *doc) +{ + if (current_desktop) + sel_changed_connection.disconnect(); + + sel_changed_connection = sp_desktop_selection(dt)->connectChanged(sigc::hide(sigc::mem_fun(this, &XmlTree::on_desktop_selection_changed))); + set_tree_document(doc); +} + +void XmlTree::on_document_uri_set(gchar const */*uri*/, SPDocument *document) +{ +/* + * Seems to be no way to set the title on a docked dialog + gchar title[500]; + sp_ui_dialog_title_string(Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), title); + gchar *t = g_strdup_printf("%s: %s", document->getName(), title); + //gtk_window_set_title(GTK_WINDOW(dlg), t); + g_free(t); +*/ +} + +gboolean XmlTree::quit_on_esc (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/) +{ + switch (get_group0_keyval (event)) { + case GDK_Escape: // defocus + gtk_widget_destroy(w); + return TRUE; + } + return FALSE; +} + +void XmlTree::cmd_new_element_node() +{ + GtkWidget *cancel, *vbox, *bbox, *sep; + + g_assert(selected_repr != NULL); + + new_window = sp_window_new(NULL, TRUE); + gtk_container_set_border_width(GTK_CONTAINER(new_window), 4); + gtk_window_set_title(GTK_WINDOW(new_window), _("New element node...")); + gtk_window_set_resizable(GTK_WINDOW(new_window), FALSE); + gtk_window_set_position(GTK_WINDOW(new_window), GTK_WIN_POS_CENTER); + gtk_window_set_transient_for(GTK_WINDOW(new_window), GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(gobj())))); + gtk_window_set_modal(GTK_WINDOW(new_window), TRUE); + g_signal_connect(G_OBJECT(new_window), "destroy", gtk_main_quit, NULL); + g_signal_connect(G_OBJECT(new_window), "key-press-event", G_CALLBACK(quit_on_esc), new_window); + + vbox = gtk_vbox_new(FALSE, 4); + gtk_container_add(GTK_CONTAINER(new_window), vbox); + + name_entry = new Gtk::Entry(); + gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(name_entry->gobj()), 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")); + g_signal_connect_swapped( G_OBJECT(cancel), "clicked", + G_CALLBACK(gtk_widget_destroy), + G_OBJECT(new_window) ); + gtk_container_add(GTK_CONTAINER(bbox), cancel); + + create_button = new Gtk::Button(_("Create")); + create_button->set_sensitive(FALSE); + + name_entry->signal_changed().connect(sigc::mem_fun(*this, &XmlTree::onCreateNameChanged)); + + g_signal_connect_swapped( G_OBJECT(create_button->gobj()), "clicked", + G_CALLBACK(gtk_widget_destroy), + G_OBJECT(new_window) ); + create_button->set_can_default( TRUE ); + create_button->set_receives_default( TRUE ); + gtk_container_add(GTK_CONTAINER(bbox), GTK_WIDGET(create_button->gobj())); + + gtk_widget_show_all(GTK_WIDGET(new_window)); + //gtk_window_set_default(GTK_WINDOW(window), GTK_WIDGET(create)); + name_entry->grab_focus(); + + gtk_main(); + + gchar *new_name = g_strdup(name_entry->get_text().c_str()); + + if (selected_repr != NULL && new_name) { + Inkscape::XML::Document *xml_doc = current_document->getReprDoc(); + Inkscape::XML::Node *new_repr; + new_repr = xml_doc->createElement(new_name); + Inkscape::GC::release(new_repr); + g_free(new_name); + selected_repr->appendChild(new_repr); + set_tree_select(new_repr); + set_dt_select(new_repr); + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Create new element node")); + } + +} // end of cmd_new_element_node() + + + +void XmlTree::cmd_new_text_node() +{ + g_assert(selected_repr != NULL); + + Inkscape::XML::Document *xml_doc = current_document->getReprDoc(); + Inkscape::XML::Node *text = xml_doc->createTextNode(""); + selected_repr->appendChild(text); + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Create new text node")); + + set_tree_select(text); + set_dt_select(text); + + gtk_window_set_focus(GTK_WINDOW(new_window), GTK_WIDGET(content)); + +} + +void XmlTree::cmd_duplicate_node() +{ + g_assert(selected_repr != NULL); + + Inkscape::XML::Node *parent = selected_repr->parent(); + Inkscape::XML::Node *dup = selected_repr->duplicate(parent->document()); + parent->addChild(dup, selected_repr); + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Duplicate node")); + + GtkCTreeNode *node = sp_xmlview_tree_get_repr_node(SP_XMLVIEW_TREE(tree), dup); + + if (node) { + gtk_ctree_select(GTK_CTREE(tree), node); + } +} + +void XmlTree::cmd_delete_node() +{ + g_assert(selected_repr != NULL); + sp_repr_unparent(selected_repr); + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + Q_("nodeAsInXMLinHistoryDialog|Delete node")); +} + + + +void XmlTree::cmd_delete_attr() +{ + 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(); + } + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Delete attribute")); +} + + + +void XmlTree::cmd_set_attr() +{ + g_assert(selected_repr != NULL); + + gchar *name = g_strdup(attr_name.get_text().c_str()); + gchar *value = g_strdup(attr_value.get_buffer()->get_text().c_str()); + + selected_repr->setAttribute(name, value, false); + + g_free(name); + g_free(value); + + SPObject *updated = current_document->getObjectByRepr(selected_repr); + if (updated) { + // force immediate update of dependant attributes + updated->updateRepr(); + } + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Change attribute")); + + /* 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 XmlTree::cmd_raise_node() +{ + g_assert(selected_repr != NULL); + + + Inkscape::XML::Node *parent = selected_repr->parent(); + 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); + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Raise node")); + + set_tree_select(selected_repr); + set_dt_select(selected_repr); +} + + + +void XmlTree::cmd_lower_node() +{ + g_assert(selected_repr != NULL); + + g_return_if_fail(selected_repr->next() != NULL); + Inkscape::XML::Node *parent = selected_repr->parent(); + + parent->changeOrder(selected_repr, selected_repr->next()); + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Lower node")); + + set_tree_select(selected_repr); + set_dt_select(selected_repr); +} + +void XmlTree::cmd_indent_node() +{ + Inkscape::XML::Node *repr = selected_repr; + g_assert(repr != NULL); + + Inkscape::XML::Node *parent = repr->parent(); + 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); + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Indent node")); + set_tree_select(repr); + set_dt_select(repr); + +} // end of cmd_indent_node() + + + +void XmlTree::cmd_unindent_node() +{ + Inkscape::XML::Node *repr = selected_repr; + g_assert(repr != NULL); + + Inkscape::XML::Node *parent = repr->parent(); + g_return_if_fail(parent); + Inkscape::XML::Node *grandparent = parent->parent(); + g_return_if_fail(grandparent); + + parent->removeChild(repr); + grandparent->addChild(repr, parent); + + DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR, + _("Unindent node")); + set_tree_select(repr); + set_dt_select(repr); + +} // end of cmd_unindent_node() + +/** Returns true iff \a item is suitable to be included in the selection, in particular + whether it has a bounding box in the desktop coordinate system for rendering resize handles. + + Descendents of <defs> nodes (markers etc.) return false, for example. +*/ +bool XmlTree::in_dt_coordsys(SPObject const &item) +{ + /* Definition based on sp_item_i2doc_affine. */ + SPObject const *child = &item; + g_return_val_if_fail(child != NULL, false); + for(;;) { + if (!SP_IS_ITEM(child)) { + return false; + } + SPObject const * const parent = child->parent; + if (parent == NULL) { + break; + } + child = parent; + } + g_assert(SP_IS_ROOT(child)); + /* Relevance: Otherwise, I'm not sure whether to return true or false. */ + return true; +} + +} +} +} + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/xml-tree.h b/src/ui/dialog/xml-tree.h new file mode 100644 index 000000000..0f516d8dc --- /dev/null +++ b/src/ui/dialog/xml-tree.h @@ -0,0 +1,268 @@ +/** @file + * @brief XML tree editing dialog for Inkscape + */ +/* Copyright Lauris Kaplinski, 2000 + * + * Released under GNU General Public License. + * + * This is XML tree editor, which allows direct modifying of all elements + * of Inkscape document, including foreign ones. + * + */ + +#ifndef SEEN_DIALOGS_XML_TREE_H +#define SEEN_DIALOGS_XML_TREE_H + +#include <gtk/gtk.h> +#include <glibmm/i18n.h> +#include <gtkmm/expander.h> +#include <gtkmm/frame.h> +#include <gtkmm/entry.h> +#include <gtkmm/textview.h> +#include <gtkmm/toolbar.h> +#include <gtkmm/separatortoolitem.h> +#include <gtkmm/separator.h> +#include <gtkmm/scrolledwindow.h> +#include <gtkmm/paned.h> + +#include "desktop.h" +#include "ui/dialog/desktop-tracker.h" +#include "ui/widget/panel.h" +#include "widgets/sp-attribute-widget.h" + +#include "widgets/sp-xmlview-attr-list.h" +#include "widgets/sp-xmlview-content.h" +#include "widgets/sp-xmlview-tree.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +/** + * A dialog widget to view and edit the document xml + * + */ + +class XmlTree : public Widget::Panel { +public: + XmlTree (); + ~XmlTree (); + + static XmlTree &getInstance() { return *new XmlTree(); } + +private: + + /** + * Is invoked by the desktop tracker when the desktop changes. + */ + void set_tree_desktop(SPDesktop *desktop); + + /** + * Is invoked when the documnet changes + */ + void set_tree_document(SPDocument *document); + + /** + * Select a node in the xml tree + */ + void set_tree_repr(Inkscape::XML::Node *repr); + + /** + * Sets the XML status bar when the tree is selected. + */ + void tree_reset_context(); + + /** + * Sets the XML status bar, depending on which attr is selected. + */ + void attr_reset_context(gint attr); + + /** + * Is the selected tree node editable + */ + gboolean xml_tree_node_mutable(GtkCTreeNode *node); + + /** + * Callback to close the add dialog on Escape key + */ + static gboolean quit_on_esc (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/); + + /** + * Select a node in the xml tree + */ + void set_tree_select(Inkscape::XML::Node *repr); + + /** + * Set the attribute list to match the selected node in the tree + */ + void propagate_tree_select(Inkscape::XML::Node *repr); + + /** + * Find the current desktop selection + */ + Inkscape::XML::Node *get_dt_select(); + + /** + * Select the current desktop selection + */ + void set_dt_select(Inkscape::XML::Node *repr); + + /** + * Callback for a node in the tree being selected + */ + static void on_tree_select_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data); + + /** + * Callback when no node in the tree is selected + */ + static void on_tree_unselect_row(GtkCTree *tree, GtkCTreeNode *node, gint column, gpointer data); + + /** + * Callback when a node is moved in the tree + */ + static void after_tree_move(GtkCTree *tree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling, gpointer data); + + /** + * Callback functions for when attribute selection changes + */ + 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 ); + + /** + * Enable widgets based on current selections + */ + void on_tree_select_row_enable(GtkCTreeNode *node); + void on_tree_unselect_row_disable(); + void on_tree_unselect_row_hide(); + void on_attr_select_row_enable(); + void on_attr_unselect_row_disable(); + void on_attr_unselect_row_clear_text(); + void on_attr_select_row_set_value_content(gint row); + void on_attr_select_row_set_name_content(gint row); + + void onNameChanged(); + void onCreateNameChanged(); + + /** + * Callbacks for changes in desktop selection and current document + */ + void on_desktop_selection_changed(); + void on_document_replaced(SPDesktop *dt, SPDocument *document); + static void on_document_uri_set(gchar const *uri, SPDocument *document); + + static void _set_status_message(Inkscape::MessageType type, const gchar *message, GtkWidget *dialog); + + /** + * Callbacks for toolbar buttons being pressed + */ + void cmd_new_element_node(); + void cmd_new_text_node(); + void cmd_duplicate_node(); + void cmd_delete_node(); + void cmd_raise_node(); + void cmd_lower_node(); + void cmd_indent_node(); + void cmd_unindent_node(); + + void cmd_delete_attr(); + void cmd_set_attr(); + virtual void present(); + + bool sp_xml_tree_key_press(GdkEventKey *event); + + bool in_dt_coordsys(SPObject const &item); + + /** + * Can be invoked for setting the desktop. Currently not used. + */ + void setDesktop(SPDesktop *desktop); + + /** + * Flag to ensure only one operation is perfomed at once + */ + gint blocked; + + /** + * Status bar + */ + Inkscape::MessageStack *_message_stack; + Inkscape::MessageContext *_message_context; + + /** + * Signal handlers + */ + sigc::connection _message_changed_connection; + sigc::connection document_replaced_connection; + sigc::connection document_uri_set_connection; + sigc::connection sel_changed_connection; + + /** + * Current document and desktop this dialog is attached to + */ + SPDesktop *current_desktop; + SPDocument *current_document; + + gint selected_attr; + Inkscape::XML::Node *selected_repr; + + /* XmlTree Widgets */ + SPXMLViewTree *tree; + SPXMLViewAttrList *attributes; + SPXMLViewContent *content; + + Gtk::Entry attr_name; + Gtk::TextView attr_value; + + Gtk::Button *create_button; + Gtk::Entry *name_entry; + + Gtk::HPaned paned; + Gtk::VBox left_box; + Gtk::VBox right_box; + Gtk::HBox status_box; + Gtk::Label status; + Gtk::Toolbar tree_toolbar; + Gtk::ToolButton xml_element_new_button; + Gtk::ToolButton xml_text_new_button; + Gtk::ToolButton xml_node_delete_button; + Gtk::SeparatorToolItem separator; + Gtk::ToolButton xml_node_duplicate_button; + Gtk::SeparatorToolItem separator2; + Gtk::ToolButton unindent_node_button; + Gtk::ToolButton indent_node_button; + Gtk::ToolButton raise_node_button; + Gtk::ToolButton lower_node_button; + + Gtk::Toolbar attr_toolbar; + Gtk::ToolButton xml_attribute_delete_button; + + Gtk::VBox attr_vbox; + Gtk::ScrolledWindow text_container; + Gtk::HBox attr_hbox; + Gtk::VBox attr_container; + Gtk::VPaned attr_subpaned_container; + Gtk::Button set_attr; + + GtkWidget *new_window; + + DesktopTracker deskTrack; + sigc::connection desktopChangeConn; +}; + +} +} +} + +#endif + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/verbs.cpp b/src/verbs.cpp index f49aaf204..6abd119c5 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -41,7 +41,6 @@ #include "desktop-handles.h" #include "dialogs/clonetiler.h" #include "dialogs/find.h" -#include "dialogs/xml-tree.h" #include "display/curve.h" #include "document.h" #include "draw-context.h" @@ -1820,7 +1819,7 @@ void DialogVerb::perform(SPAction *action, void *data) dt->_dlg_mgr->showDialog("TextFont"); break; case SP_VERB_DIALOG_XML_EDITOR: - sp_xml_tree_dialog(); + dt->_dlg_mgr->showDialog("XmlTree"); break; case SP_VERB_DIALOG_FIND: sp_find_dialog(); |
