diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:29:01 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:29:01 +0000 |
commit | 35a96bde514a8897f6f0fcc41c5833bf63df2e2a (patch) | |
tree | 657d15a03cc46bd099fc2c6546a7a4ad43815d9f /src/extension/dbus/document-interface.cpp | |
parent | Initial commit. (diff) | |
download | inkscape-35a96bde514a8897f6f0fcc41c5833bf63df2e2a.tar.xz inkscape-35a96bde514a8897f6f0fcc41c5833bf63df2e2a.zip |
Adding upstream version 1.0.2.upstream/1.0.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/extension/dbus/document-interface.cpp')
-rw-r--r-- | src/extension/dbus/document-interface.cpp | 1484 |
1 files changed, 1484 insertions, 0 deletions
diff --git a/src/extension/dbus/document-interface.cpp b/src/extension/dbus/document-interface.cpp new file mode 100644 index 0000000..2384c50 --- /dev/null +++ b/src/extension/dbus/document-interface.cpp @@ -0,0 +1,1484 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * This is where the implementation of the DBus based document API lives. + * All the methods in here (except in the helper section) are + * designed to be called remotely via DBus. application-interface.cpp + * has the methods used to connect to the bus and get a document instance. + * + * Documentation for these methods is in document-interface.xml + * which is the "gold standard" as to how the interface should work. + * + * Authors: + * Soren Berg <Glimmer07@gmail.com> + * + * Copyright (C) 2009 Soren Berg + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <glib.h> +#include <string.h> + +#include <dbus/dbus-glib.h> + +//#include "2geom/svg-path-parser.h" //get_node_coordinates +#include "inkscape-application.h" // create_window() + +#include "application-interface.h" +#include "desktop-style.h" //sp_desktop_get_style +#include "desktop.h" +#include "document-interface.h" +#include "document-undo.h" +#include "document.h" // getReprDoc() +#include "file.h" //IO +#include "inkscape.h" //inkscape_find_desktop_by_dkey, activate desktops +#include "layer-fns.h" //LPOS_BELOW +#include "layer-model.h" +#include "print.h" //IO +#include "selection-chemistry.h"// lots of selection functions +#include "selection.h" //selection struct +#include "style.h" //style_write +#include "text-editing.h" +#include "verbs.h" + +#include "helper/action-context.h" +#include "helper/action.h" //sp_action_perform + +#include "display/canvas-text.h" //text +#include "display/sp-canvas.h" //text + +#include "extension/output.h" //IO +#include "extension/system.h" //IO + +#include "live_effects/parameter/text.h" //text + +#include "object/sp-ellipse.h" +#include "object/sp-object.h" +#include "object/sp-root.h" + +#include "util/units.h" + +#include "xml/repr.h" //sp_repr_document_new + +#if 0 +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#endif + + enum + { + OBJECT_MOVED_SIGNAL, + LAST_SIGNAL + }; + + static guint signals[LAST_SIGNAL] = { 0 }; + + +/**************************************************************************** + HELPER / SHORTCUT FUNCTIONS +****************************************************************************/ + +/* + * This function or the one below it translates the user input for an object + * into Inkscapes internal representation. It is called by almost every + * method so it should be as fast as possible. + * + * (eg turns "rect2234" to an SPObject or Inkscape::XML::Node) + * + * If the internal representation changes (No more 'id' attributes) this is the + * place to adjust things. + */ +Inkscape::XML::Node * +get_repr_by_name (SPDocument *doc, gchar *name, GError **error) +{ + /* ALTERNATIVE (is this faster if only repr is needed?) + Inkscape::XML::Node *node = sp_repr_lookup_name((doc->root)->repr, name); + */ + SPObject * obj = doc->getObjectById(name); + if (!obj) + { + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name); + return NULL; + } + return obj->getRepr(); +} + +/* + * See comment for get_repr_by_name, above. + */ +SPObject * +get_object_by_name (SPDocument *doc, gchar *name, GError **error) +{ + SPObject * obj = doc->getObjectById(name); + if (!obj) + { + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name); + return NULL; + } + return obj; +} + +/* + * Tests for NULL strings and throws an appropriate error. + * Every method that takes a string parameter (other than the + * name of an object, that's tested separately) should call this. + */ +gboolean +dbus_check_string (gchar *string, GError ** error, const gchar * errorstr) +{ + if (string == NULL) + { + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "%s", errorstr); + return FALSE; + } + return TRUE; +} + +/* + * This is used to return object values to the user + */ +const gchar * +get_name_from_object (SPObject * obj) +{ + return obj->getRepr()->attribute("id"); +} + +/* + * Some verbs (cut, paste) only work on the active layer. + * This makes sure that the document that is about to receive a command is active. + */ +void +desktop_ensure_active (SPDesktop* desk) { + if (desk != SP_ACTIVE_DESKTOP) + INKSCAPE.activate_desktop (desk); + return; +} + +gdouble +selection_get_center_x (Inkscape::Selection *sel){ + Geom::OptRect box = sel->documentBounds(SPItem::GEOMETRIC_BBOX); + return box ? box->midpoint()[Geom::X] : 0; +} + +gdouble +selection_get_center_y (Inkscape::Selection *sel){ + Geom::OptRect box = sel->documentBounds(SPItem::GEOMETRIC_BBOX); + return box ? box->midpoint()[Geom::Y] : 0; +} + +/* + * This function is used along with selection_restore to + * take advantage of functionality provided by a selection + * for a single object. + * + * It saves the current selection and sets the selection to + * the object specified. Any selection verb can be used on the + * object and then selection_restore is called, restoring the + * original selection. + * + * This should be mostly transparent to the user who need never + * know we never bothered to implement it separately. Although + * they might see the selection box flicker if used in a loop. + */ +std::vector<SPObject*> +selection_swap(Inkscape::Selection *sel, gchar *name, GError **error) +{ + std::vector<SPObject*> oldsel = std::vector<SPObject*>(sel->objects().begin(), sel->objects().end()); + + sel->set(get_object_by_name(sel->layers()->getDocument(), name, error)); + return oldsel; +} + +/* + * See selection_swap, above + */ +void +selection_restore(Inkscape::Selection *sel, std::vector<SPObject*> oldsel) +{ + // ... setList used to work here + sel->clear(); + sel->add(oldsel.begin(), oldsel.end()); +} + +/* + * Shortcut for creating a Node. + */ +Inkscape::XML::Node * +dbus_create_node (SPDocument *doc, const gchar *type) +{ + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + + return xml_doc->createElement(type); +} + +/* + * Called by the shape creation functions. Gets the default style for the doc + * or sets it arbitrarily if none. + * + * There is probably a better way to do this (use the shape tools default styles) + * but I'm not sure how. + */ +gchar *finish_create_shape (DocumentInterface *doc_interface, GError ** /*error*/, Inkscape::XML::Node *newNode, gchar *desc) +{ + SPCSSAttr *style = NULL; + if (doc_interface->target.getDesktop()) { + style = sp_desktop_get_style(doc_interface->target.getDesktop(), TRUE); + } + if (style) { + Glib::ustring str; + sp_repr_css_write_string(style, str); + newNode->setAttributeOrRemoveIfEmpty("style", str); + } + else { + newNode->setAttribute("style", "fill:#0000ff;fill-opacity:1;stroke:#c900b9;stroke-width:0;stroke-miterlimit:0;stroke-opacity:1;stroke-dasharray:none", true); + } + + doc_interface->target.getSelection()->layers()->currentLayer()->appendChildRepr(newNode); + doc_interface->target.getSelection()->layers()->currentLayer()->updateRepr(); + + if (doc_interface->updates) { + Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), 0, (gchar *)desc); + } + + return strdup(newNode->attribute("id")); +} + +/* + * This is the code used internally to call all the verbs. + * + * It handles error reporting and update pausing (which needs some work.) + * This is a good place to improve efficiency as it is called a lot. + * + * document_interface_call_verb is similar but is called by the user. + */ +gboolean +dbus_call_verb (DocumentInterface *doc_interface, int verbid, GError **error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + if ( desk ) { + desktop_ensure_active (desk); + } + Inkscape::Verb *verb = Inkscape::Verb::get( verbid ); + if ( verb ) { + SPAction *action = verb->get_action(doc_interface->target); + if ( action ) { + sp_action_perform( action, NULL ); + if (doc_interface->updates) + Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), verb->get_code(), verb->get_tip()); + return TRUE; + } + } + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb failed to execute"); + return FALSE; +} + +/* + * Check that the desktop is not NULL. If it is NULL, set the error to a useful message. + */ +bool +ensure_desktop_valid(SPDesktop* desk, GError **error) +{ + if (desk) { + return true; + } + + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Document interface action requires a GUI"); + return false; +} + +/**************************************************************************** + DOCUMENT INTERFACE CLASS STUFF +****************************************************************************/ + +G_DEFINE_TYPE(DocumentInterface, document_interface, G_TYPE_OBJECT) + +static void +document_interface_finalize (GObject *object) +{ + G_OBJECT_CLASS (document_interface_parent_class)->finalize (object); +} + + +static void +document_interface_class_init (DocumentInterfaceClass *klass) +{ + GObjectClass *object_class; + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = document_interface_finalize; + signals[OBJECT_MOVED_SIGNAL] = + g_signal_new ("object_moved", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); +} + +static void +document_interface_init (DocumentInterface *doc_interface) +{ + doc_interface->target = Inkscape::ActionContext(); +} + + +DocumentInterface * +document_interface_new (void) +{ + return (DocumentInterface*)g_object_new (TYPE_DOCUMENT_INTERFACE, NULL); +} + + + +/**************************************************************************** + MISC FUNCTIONS +****************************************************************************/ + +gboolean document_interface_delete_all(DocumentInterface *doc_interface, GError ** /*error*/) +{ + sp_edit_clear_all(doc_interface->target.getSelection()); + return TRUE; +} + +gboolean +document_interface_call_verb (DocumentInterface *doc_interface, gchar *verbid, GError **error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + if ( desk ) { + desktop_ensure_active (desk); + } + Inkscape::Verb *verb = Inkscape::Verb::getbyid( verbid ); + if ( verb ) { + SPAction *action = verb->get_action(doc_interface->target); + if ( action ) { + sp_action_perform( action, NULL ); + if (doc_interface->updates) { + Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), verb->get_code(), verb->get_tip()); + } + return TRUE; + } + } + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb '%s' failed to execute or was not found.", verbid); + return FALSE; +} + + +/**************************************************************************** + CREATION FUNCTIONS +****************************************************************************/ + +gchar* +document_interface_rectangle (DocumentInterface *doc_interface, int x, int y, + int width, int height, GError **error) +{ + + + Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:rect"); + sp_repr_set_int(newNode, "x", x); //could also use newNode->setAttribute() + sp_repr_set_int(newNode, "y", y); + sp_repr_set_int(newNode, "width", width); + sp_repr_set_int(newNode, "height", height); + return finish_create_shape (doc_interface, error, newNode, (gchar *)"create rectangle"); +} + +gchar* +document_interface_ellipse_center (DocumentInterface *doc_interface, int cx, int cy, + int rx, int ry, GError **error) +{ + Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path"); + newNode->setAttribute("sodipodi:type", "arc"); + sp_repr_set_int(newNode, "sodipodi:cx", cx); + sp_repr_set_int(newNode, "sodipodi:cy", cy); + sp_repr_set_int(newNode, "sodipodi:rx", rx); + sp_repr_set_int(newNode, "sodipodi:ry", ry); + return finish_create_shape (doc_interface, error, newNode, (gchar *)"create circle"); +} + +gchar* +document_interface_polygon (DocumentInterface *doc_interface, int cx, int cy, + int radius, int rotation, int sides, + GError **error) +{ + gdouble rot = ((rotation / 180.0) * M_PI) - M_PI_2; + Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path"); + newNode->setAttribute("inkscape:flatsided", "true"); + newNode->setAttribute("sodipodi:type", "star"); + sp_repr_set_int(newNode, "sodipodi:cx", cx); + sp_repr_set_int(newNode, "sodipodi:cy", cy); + sp_repr_set_int(newNode, "sodipodi:r1", radius); + sp_repr_set_int(newNode, "sodipodi:r2", radius); + sp_repr_set_int(newNode, "sodipodi:sides", sides); + sp_repr_set_int(newNode, "inkscape:randomized", 0); + sp_repr_set_svg_double(newNode, "sodipodi:arg1", rot); + sp_repr_set_svg_double(newNode, "sodipodi:arg2", rot); + sp_repr_set_svg_double(newNode, "inkscape:rounded", 0); + + return finish_create_shape (doc_interface, error, newNode, (gchar *)"create polygon"); +} + +gchar* +document_interface_star (DocumentInterface *doc_interface, int cx, int cy, + int r1, int r2, int sides, gdouble rounded, + gdouble arg1, gdouble arg2, GError **error) +{ + Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path"); + newNode->setAttribute("inkscape:flatsided", "false"); + newNode->setAttribute("sodipodi:type", "star"); + sp_repr_set_int(newNode, "sodipodi:cx", cx); + sp_repr_set_int(newNode, "sodipodi:cy", cy); + sp_repr_set_int(newNode, "sodipodi:r1", r1); + sp_repr_set_int(newNode, "sodipodi:r2", r2); + sp_repr_set_int(newNode, "sodipodi:sides", sides); + sp_repr_set_int(newNode, "inkscape:randomized", 0); + sp_repr_set_svg_double(newNode, "sodipodi:arg1", arg1); + sp_repr_set_svg_double(newNode, "sodipodi:arg2", arg2); + sp_repr_set_svg_double(newNode, "inkscape:rounded", rounded); + + return finish_create_shape (doc_interface, error, newNode, (gchar *)"create star"); +} + +gchar* +document_interface_ellipse (DocumentInterface *doc_interface, int x, int y, + int width, int height, GError **error) +{ + int rx = width/2; + int ry = height/2; + return document_interface_ellipse_center (doc_interface, x+rx, y+ry, rx, ry, error); +} + +gchar* +document_interface_line (DocumentInterface *doc_interface, int x, int y, + int x2, int y2, GError **error) +{ + Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path"); + std::stringstream out; + // Not sure why this works. + out << "m " << x << "," << y << " " << x2 - x << "," << y2 - y; + newNode->setAttribute("d", out.str()); + return finish_create_shape (doc_interface, error, newNode, (gchar *)"create line"); +} + +gchar* +document_interface_spiral (DocumentInterface *doc_interface, int cx, int cy, + int r, int revolutions, GError **error) +{ + Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path"); + newNode->setAttribute("sodipodi:type", "spiral"); + sp_repr_set_int(newNode, "sodipodi:cx", cx); + sp_repr_set_int(newNode, "sodipodi:cy", cy); + sp_repr_set_int(newNode, "sodipodi:radius", r); + sp_repr_set_int(newNode, "sodipodi:revolution", revolutions); + sp_repr_set_int(newNode, "sodipodi:t0", 0); + sp_repr_set_int(newNode, "sodipodi:argument", 0); + sp_repr_set_int(newNode, "sodipodi:expansion", 1); + gchar * retval = finish_create_shape (doc_interface, error, newNode, (gchar *)"create spiral"); + //Makes sure there is no fill for spirals by default. + gchar* newString = g_strconcat(newNode->attribute("style"), ";fill:none", NULL); + newNode->setAttribute("style", newString); + g_free(newString); + return retval; +} + +gchar* +document_interface_text (DocumentInterface *doc_interface, int x, int y, gchar *text, GError **error) +{ + + Inkscape::XML::Node *text_node = dbus_create_node(doc_interface->target.getDocument(), "svg:text"); + sp_repr_set_int(text_node, "x", x); + sp_repr_set_int(text_node, "y", y); + //just a workaround so i can get an spitem from the name + gchar *name = finish_create_shape (doc_interface, error, text_node, (gchar *)"create text"); + + SPItem* text_obj=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error); + sp_te_set_repr_text_multiline(text_obj, text); + + return name; +} + +gchar * +document_interface_image (DocumentInterface *doc_interface, int x, int y, gchar *filename, GError **error) +{ + gchar * uri = g_filename_to_uri (filename, FALSE, error); + if (!uri) + return FALSE; + + Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:image"); + sp_repr_set_int(newNode, "x", x); + sp_repr_set_int(newNode, "y", y); + newNode->setAttribute("xlink:href", uri); + + doc_interface->target.getSelection()->layers()->currentLayer()->appendChildRepr(newNode); + doc_interface->target.getSelection()->layers()->currentLayer()->updateRepr(); + + if (doc_interface->updates) + Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), 0, "Imported bitmap."); + + //g_free(uri); + return strdup(newNode->attribute("id")); +} + +gchar *document_interface_node(DocumentInterface *doc_interface, gchar *type, GError ** /*error*/) +{ + SPDocument * doc = doc_interface->target.getDocument(); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + + Inkscape::XML::Node *newNode = xml_doc->createElement(type); + + doc_interface->target.getSelection()->layers()->currentLayer()->appendChildRepr(newNode); + doc_interface->target.getSelection()->layers()->currentLayer()->updateRepr(); + + if (doc_interface->updates) { + Inkscape::DocumentUndo::done(doc, 0, (gchar *)"created empty node"); + } + + return strdup(newNode->attribute("id")); +} + +/**************************************************************************** + ENVIRONMENT FUNCTIONS +****************************************************************************/ +gdouble +document_interface_document_get_width (DocumentInterface *doc_interface) +{ + return doc_interface->target.getDocument()->getWidth().value("px"); +} + +gdouble +document_interface_document_get_height (DocumentInterface *doc_interface) +{ + return doc_interface->target.getDocument()->getHeight().value("px"); +} + +gchar *document_interface_document_get_css(DocumentInterface *doc_interface, GError ** error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_val_if_fail(ensure_desktop_valid(desk, error), NULL); + SPCSSAttr *current = desk->current; + Glib::ustring str; + sp_repr_css_write_string(current, str); + return (str.empty() ? NULL : g_strdup (str.c_str())); +} + +gboolean document_interface_document_merge_css(DocumentInterface *doc_interface, + gchar *stylestring, GError ** error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE); + SPCSSAttr * style = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(style, stylestring); + sp_desktop_set_style(desk, style); + return TRUE; +} + +gboolean document_interface_document_set_css(DocumentInterface *doc_interface, + gchar *stylestring, GError ** error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE); + SPCSSAttr * style = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string (style, stylestring); + //Memory leak? + desk->current = style; + return TRUE; +} + +gboolean +document_interface_document_resize_to_fit_selection (DocumentInterface *doc_interface, + GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_FIT_CANVAS_TO_SELECTION, error); +} + +gboolean +document_interface_document_set_display_area (DocumentInterface *doc_interface, + double x0, + double y0, + double x1, + double y1, + double border, + GError **error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE); + desk->set_display_area (Geom::Rect( Geom::Point(x0,y0), Geom::Point(x1,y1)), border, false ); + return TRUE; +} + + +GArray * +document_interface_document_get_display_area (DocumentInterface *doc_interface) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + if (!desk) { + return NULL; + } + Geom::Rect const d = desk->get_display_area(); + + GArray * dArr = g_array_new (TRUE, TRUE, sizeof(double)); + + double x0 = d.min()[Geom::X]; + double y0 = d.min()[Geom::Y]; + double x1 = d.max()[Geom::X]; + double y1 = d.max()[Geom::Y]; + g_array_append_val (dArr, x0); // + g_array_append_val (dArr, y0); + g_array_append_val (dArr, x1); + g_array_append_val (dArr, y1); + return dArr; + +} + + +/**************************************************************************** + OBJECT FUNCTIONS +****************************************************************************/ + +gboolean +document_interface_set_attribute (DocumentInterface *doc_interface, char *shape, + char *attribute, char *newval, GError **error) +{ + Inkscape::XML::Node *newNode = get_repr_by_name(doc_interface->target.getDocument(), shape, error); + + /* ALTERNATIVE (is this faster?) + Inkscape::XML::Node *newnode = sp_repr_lookup_name((doc->root)->repr, name); + */ + if (!dbus_check_string(newval, error, "New value string was empty.")) + return FALSE; + + if (!newNode) + return FALSE; + + newNode->setAttribute(attribute, newval, true); + return TRUE; +} + +gboolean +document_interface_set_int_attribute (DocumentInterface *doc_interface, + char *shape, char *attribute, + int newval, GError **error) +{ + Inkscape::XML::Node *newNode = get_repr_by_name (doc_interface->target.getDocument(), shape, error); + if (!newNode) + return FALSE; + + sp_repr_set_int (newNode, attribute, newval); + return TRUE; +} + + +gboolean +document_interface_set_double_attribute (DocumentInterface *doc_interface, + char *shape, char *attribute, + double newval, GError **error) +{ + Inkscape::XML::Node *newNode = get_repr_by_name (doc_interface->target.getDocument(), shape, error); + + if (!dbus_check_string (attribute, error, "New value string was empty.")) + return FALSE; + if (!newNode) + return FALSE; + + sp_repr_set_svg_double (newNode, attribute, newval); + return TRUE; +} + +gchar * +document_interface_get_attribute (DocumentInterface *doc_interface, char *shape, + char *attribute, GError **error) +{ + Inkscape::XML::Node *newNode = get_repr_by_name(doc_interface->target.getDocument(), shape, error); + + if (!dbus_check_string (attribute, error, "Attribute name empty.")) + return NULL; + if (!newNode) + return NULL; + + return g_strdup(newNode->attribute(attribute)); +} + +gboolean +document_interface_move (DocumentInterface *doc_interface, gchar *name, gdouble x, + gdouble y, GError **error) +{ + std::vector<SPObject*> oldsel = selection_swap(doc_interface->target.getSelection(), name, error); + if (oldsel.empty()) + return FALSE; + doc_interface->target.getSelection()->move(x, 0 - y); + selection_restore(doc_interface->target.getSelection(), oldsel); + return TRUE; +} + +gboolean +document_interface_move_to (DocumentInterface *doc_interface, gchar *name, gdouble x, + gdouble y, GError **error) +{ + std::vector<SPObject*> oldsel = selection_swap(doc_interface->target.getSelection(), name, error); + if (oldsel.empty()) + return FALSE; + Inkscape::Selection * sel = doc_interface->target.getSelection(); + doc_interface->target.getSelection()->move(x - selection_get_center_x(sel), + 0 - (y - selection_get_center_y(sel))); + selection_restore(doc_interface->target.getSelection(), oldsel); + return TRUE; +} + +gboolean +document_interface_object_to_path (DocumentInterface *doc_interface, + char *shape, GError **error) +{ + std::vector<SPObject*> oldsel = selection_swap(doc_interface->target.getSelection(), shape, error); + if (oldsel.empty()) + return FALSE; + dbus_call_verb (doc_interface, SP_VERB_OBJECT_TO_CURVE, error); + selection_restore(doc_interface->target.getSelection(), oldsel); + return TRUE; +} + +gchar * +document_interface_get_path (DocumentInterface *doc_interface, char *pathname, GError **error) +{ + Inkscape::XML::Node *node = get_repr_by_name(doc_interface->target.getDocument(), pathname, error); + + if (!node) + return NULL; + + if (node->attribute("d") == NULL) + { + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object is not a path."); + return NULL; + } + return strdup(node->attribute("d")); +} + +gboolean +document_interface_transform (DocumentInterface *doc_interface, gchar *shape, + gchar *transformstr, GError **error) +{ + //FIXME: This should merge transformations. + gchar trans[] = "transform"; + document_interface_set_attribute (doc_interface, shape, trans, transformstr, error); + return TRUE; +} + +gchar * +document_interface_get_css (DocumentInterface *doc_interface, gchar *shape, + GError **error) +{ + gchar style[] = "style"; + return document_interface_get_attribute (doc_interface, shape, style, error); +} + +gboolean +document_interface_modify_css (DocumentInterface *doc_interface, gchar *shape, + gchar *cssattrb, gchar *newval, GError **error) +{ + // Doesn't like non-variable strings for some reason. + gchar style[] = "style"; + Inkscape::XML::Node *node = get_repr_by_name(doc_interface->target.getDocument(), shape, error); + + if (!dbus_check_string (cssattrb, error, "Attribute string empty.")) + return FALSE; + if (!node) + return FALSE; + + SPCSSAttr * oldstyle = sp_repr_css_attr (node, style); + sp_repr_css_set_property(oldstyle, cssattrb, newval); + Glib::ustring str; + sp_repr_css_write_string (oldstyle, str); + node->setAttributeOrRemoveIfEmpty (style, str); + return TRUE; +} + +gboolean +document_interface_merge_css (DocumentInterface *doc_interface, gchar *shape, + gchar *stylestring, GError **error) +{ + gchar style[] = "style"; + + Inkscape::XML::Node *node = get_repr_by_name(doc_interface->target.getDocument(), shape, error); + + if (!dbus_check_string (stylestring, error, "Style string empty.")) + return FALSE; + if (!node) + return FALSE; + + SPCSSAttr * newstyle = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string (newstyle, stylestring); + + SPCSSAttr * oldstyle = sp_repr_css_attr (node, style); + + sp_repr_css_merge(oldstyle, newstyle); + Glib::ustring str; + sp_repr_css_write_string (oldstyle, str); + node->setAttributeOrRemoveIfEmpty (style, str); + + return TRUE; +} + +gboolean +document_interface_set_color (DocumentInterface *doc_interface, gchar *shape, + int r, int g, int b, gboolean fill, GError **error) +{ + gchar style[15]; + if (r<0 || r>255 || g<0 || g>255 || b<0 || b>255) + { + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Given (%d,%d,%d). All values must be between 0-255 inclusive.", r, g, b); + return FALSE; + } + + if (fill) + snprintf(style, 15, "fill:#%.2x%.2x%.2x", r, g, b); + else + snprintf(style, 15, "stroke:#%.2x%.2x%.2x", r, g, b); + + if (strcmp(shape, "document") == 0) + return document_interface_document_merge_css (doc_interface, style, error); + + return document_interface_merge_css (doc_interface, shape, style, error); +} + +gboolean +document_interface_move_to_layer (DocumentInterface *doc_interface, gchar *shape, + gchar *layerstr, GError **error) +{ + std::vector<SPObject*> oldsel = selection_swap(doc_interface->target.getSelection(), shape, error); + if (oldsel.empty()) + return FALSE; + + document_interface_selection_move_to_layer(doc_interface, layerstr, error); + selection_restore(doc_interface->target.getSelection(), oldsel); + return TRUE; +} + +GArray *document_interface_get_node_coordinates(DocumentInterface * /*doc_interface*/, gchar * /*shape*/) +{ + //FIXME: Needs lot's of work. +/* + Inkscape::XML::Node *shapenode = get_repr_by_name (doc_interface->target.getDocument(), shape, error); + if (shapenode == NULL || shapenode->attribute("d") == NULL) { + return FALSE; + } + char * path = strdup(shapenode->attribute("d")); + printf("PATH: %s\n", path); + + Geom::parse_svg_path (path); + return NULL; + */ + return NULL; +} + + +gboolean +document_interface_set_text (DocumentInterface *doc_interface, gchar *name, gchar *text, GError **error) +{ + + SPItem* text_obj=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error); + //TODO verify object type + if (!text_obj) + return FALSE; + sp_te_set_repr_text_multiline(text_obj, text); + return TRUE; + +} + + + +gboolean +document_interface_text_apply_style (DocumentInterface *doc_interface, gchar *name, + int start_pos, int end_pos, gchar *style, gchar *styleval, + GError **error) +{ + + SPItem* text_obj=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error); + + //void sp_te_apply_style(SPItem *text, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPCSSAttr const *css) + //TODO verify object type + if (!text_obj) + return FALSE; + Inkscape::Text::Layout const *layout = te_get_layout(text_obj); + Inkscape::Text::Layout::iterator start = layout->charIndexToIterator (start_pos); + Inkscape::Text::Layout::iterator end = layout->charIndexToIterator (end_pos); + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, style, styleval); + + sp_te_apply_style(text_obj, + start, + end, + css); + return TRUE; + +} + + +/**************************************************************************** + FILE I/O FUNCTIONS +****************************************************************************/ + +gboolean +document_interface_save (DocumentInterface *doc_interface, GError **error) +{ + SPDocument * doc = doc_interface->target.getDocument(); + printf("1: %s\n2: %s\n3: %s\n", doc->getDocumentURI(), doc->getDocumentBase(), doc->getDocumentName()); + if (doc->getDocumentURI()) + return document_interface_save_as (doc_interface, doc->getDocumentURI(), error); + return FALSE; +} + +gboolean document_interface_load(DocumentInterface *doc_interface, + gchar *filename, GError ** /*error*/) +{ + if (!filename) { + return false; + } + + SPDesktop *desk = doc_interface->target.getDesktop(); + if (desk) { + desktop_ensure_active(desk); + } + + Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(filename); + + ConcreteInkscapeApplication<Gtk::Application>* app = &(ConcreteInkscapeApplication<Gtk::Application>::get_instance()); + + app->create_window(file); + + if (doc_interface->updates) { + Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), SP_VERB_FILE_OPEN, "Opened File"); + } + return TRUE; +} + +gchar * +document_interface_import (DocumentInterface *doc_interface, + gchar *filename, GError **error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + if (desk) { + desktop_ensure_active(desk); + } + const Glib::ustring file(filename); + SPDocument * doc = doc_interface->target.getDocument(); + + SPObject *new_obj = NULL; + new_obj = file_import(doc, file, NULL); + return strdup(new_obj->getRepr()->attribute("id")); +} + +gboolean +document_interface_save_as (DocumentInterface *doc_interface, + const gchar *filename, GError **error) +{ + // FIXME: Isn't there a verb we can use for this instead? + SPDocument * doc = doc_interface->target.getDocument(); + + if (!doc || strlen(filename)<1) { //Safety check + return false; + } + + try { + Inkscape::Extension::save(NULL, doc, filename, + false, false, true, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS); + } catch (...) { + // FIXME: catch ... is not usually a great idea, why is it needed here? + return false; + } + + return true; +} + +gboolean document_interface_mark_as_unmodified(DocumentInterface *doc_interface, GError ** /*error*/) +{ + SPDocument * doc = doc_interface->target.getDocument(); + if (doc) { + doc->setModifiedSinceSave(FALSE); + } + return TRUE; +} + +/* +gboolean +document_interface_print_to_file (DocumentInterface *doc_interface, GError **error) +{ + SPDocument * doc = doc_interface->target.getDocument(); + sp_print_document_to_file (doc, g_strdup("/home/soren/test.pdf")); + + return TRUE; +} +*/ +/**************************************************************************** + PROGRAM CONTROL FUNCTIONS +****************************************************************************/ + +gboolean +document_interface_close (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_FILE_CLOSE_VIEW, error); +} + +gboolean +document_interface_exit (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_FILE_QUIT, error); +} + +gboolean +document_interface_undo (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_EDIT_UNDO, error); +} + +gboolean +document_interface_redo (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_EDIT_REDO, error); +} + + + +/**************************************************************************** + UPDATE FUNCTIONS + FIXME: This would work better by adding a flag to SPDesktop to prevent + updating but that would be very intrusive so for now there is a workaround. + Need to make sure it plays well with verbs because they are used so much. +****************************************************************************/ + +void document_interface_pause_updates(DocumentInterface *doc_interface, GError ** error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_if_fail(ensure_desktop_valid(desk, error)); + doc_interface->updates = FALSE; + desk->canvas->_drawing_disabled = 1; +} + +void document_interface_resume_updates(DocumentInterface *doc_interface, GError ** error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_if_fail(ensure_desktop_valid(desk, error)); + doc_interface->updates = TRUE; + desk->canvas->_drawing_disabled = 0; + //FIXME: use better verb than rect. + Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), SP_VERB_CONTEXT_RECT, "Multiple actions"); +} + +void document_interface_update(DocumentInterface *doc_interface, GError ** error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_if_fail(ensure_desktop_valid(desk, error)); + SPDocument *doc = doc_interface->target.getDocument(); + doc->getRoot()->uflags = TRUE; + doc->getRoot()->mflags = TRUE; + desk->enableInteraction(); + doc->ensureUpToDate(); + desk->disableInteraction(); + doc->getRoot()->uflags = FALSE; + doc->getRoot()->mflags = FALSE; + //Inkscape::DocumentUndo::done(doc, SP_VERB_CONTEXT_RECT, "Multiple actions"); +} + +/**************************************************************************** + SELECTION FUNCTIONS FIXME: use call_verb where appropriate (once update system is tested.) +****************************************************************************/ + +gboolean document_interface_selection_get(DocumentInterface *doc_interface, char ***out, GError ** /*error*/) +{ + Inkscape::Selection * sel = doc_interface->target.getSelection(); + auto oldsel = sel->objects(); + + int size = oldsel.size(); + + *out = g_new0 (char *, size + 1); + + int i = 0; + for (auto iter = oldsel.begin(); iter != oldsel.end(); ++iter) { + (*out)[i] = g_strdup((*iter)->getId()); + i++; + } + (*out)[i] = NULL; + + return TRUE; +} + +gboolean +document_interface_selection_add (DocumentInterface *doc_interface, char *name, GError **error) +{ + SPObject * obj = get_object_by_name(doc_interface->target.getDocument(), name, error); + if (!obj) + return FALSE; + + Inkscape::Selection *selection = doc_interface->target.getSelection(); + + selection->add(obj); + return TRUE; +} + +gboolean +document_interface_selection_add_list (DocumentInterface *doc_interface, + char **names, GError **error) +{ + int i; + for (i=0;names[i] != NULL;i++) { + document_interface_selection_add(doc_interface, names[i], error); + } + return TRUE; +} + +gboolean document_interface_selection_set(DocumentInterface *doc_interface, char *name, GError ** /*error*/) +{ + SPDocument * doc = doc_interface->target.getDocument(); + Inkscape::Selection *selection = doc_interface->target.getSelection(); + selection->set(doc->getObjectById(name)); + return TRUE; +} + +gboolean +document_interface_selection_set_list (DocumentInterface *doc_interface, + gchar **names, GError **error) +{ + doc_interface->target.getSelection()->clear(); + int i; + for (i=0;names[i] != NULL;i++) { + document_interface_selection_add(doc_interface, names[i], error); + } + return TRUE; +} + +gboolean document_interface_selection_rotate(DocumentInterface *doc_interface, int angle, GError ** /*error*/) +{ + Inkscape::Selection *selection = doc_interface->target.getSelection(); + selection->rotate(angle); + return TRUE; +} + +gboolean +document_interface_selection_delete (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_EDIT_DELETE, error); +} + +gboolean document_interface_selection_clear(DocumentInterface *doc_interface, GError ** /*error*/) +{ + doc_interface->target.getSelection()->clear(); + return TRUE; +} + +gboolean +document_interface_select_all (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_EDIT_SELECT_ALL, error); +} + +gboolean +document_interface_select_all_in_all_layers(DocumentInterface *doc_interface, + GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS, error); +} + +gboolean document_interface_selection_box(DocumentInterface * /*doc_interface*/, int /*x*/, int /*y*/, + int /*x2*/, int /*y2*/, gboolean /*replace*/, + GError ** /*error*/) +{ + //FIXME: implement. + return FALSE; +} + +gboolean +document_interface_selection_invert (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_EDIT_INVERT, error); +} + +gboolean +document_interface_selection_group (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_SELECTION_GROUP, error); +} +gboolean +document_interface_selection_ungroup (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_SELECTION_UNGROUP, error); +} + +gboolean +document_interface_selection_cut (DocumentInterface *doc_interface, GError **error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE); + return dbus_call_verb (doc_interface, SP_VERB_EDIT_CUT, error); +} + +gboolean +document_interface_selection_copy (DocumentInterface *doc_interface, GError **error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE); + return dbus_call_verb (doc_interface, SP_VERB_EDIT_COPY, error); +} + +gboolean +document_interface_selection_paste (DocumentInterface *doc_interface, GError **error) +{ + SPDesktop *desk = doc_interface->target.getDesktop(); + g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE); + return dbus_call_verb (doc_interface, SP_VERB_EDIT_PASTE, error); +} + +gboolean document_interface_selection_scale(DocumentInterface *doc_interface, gdouble grow, GError ** /*error*/) +{ + Inkscape::Selection *selection = doc_interface->target.getSelection(); + if (!selection) + { + return FALSE; + } + selection->scale(grow); + return TRUE; +} + +gboolean document_interface_selection_move(DocumentInterface *doc_interface, gdouble x, gdouble y, GError ** /*error*/) +{ + doc_interface->target.getSelection()->move(x, 0 - y); //switching coordinate systems. + return TRUE; +} + +gboolean document_interface_selection_move_to(DocumentInterface *doc_interface, gdouble x, gdouble y, GError ** /*error*/) +{ + Inkscape::Selection * sel = doc_interface->target.getSelection(); + + Geom::OptRect sel_bbox = sel->visualBounds(); + if (sel_bbox) { + Geom::Point m( x - selection_get_center_x(sel) , 0 - (y - selection_get_center_y(sel)) ); + sel->moveRelative(m, true); + } + return TRUE; +} + +//FIXME: does not paste in new layer. +// This needs to use lower level cut_impl and paste_impl (messy) +// See the built-in sp_selection_to_next_layer and duplicate. +gboolean +document_interface_selection_move_to_layer (DocumentInterface *doc_interface, + gchar *layerstr, GError **error) +{ + SPDesktop *dt = doc_interface->target.getDesktop(); + g_return_val_if_fail(ensure_desktop_valid(dt, error), FALSE); + + Inkscape::Selection *selection = doc_interface->target.getSelection(); + + // check if something is selected + if (selection->isEmpty()) + return FALSE; + + SPObject *next = get_object_by_name(doc_interface->target.getDocument(), layerstr, error); + + if (!next) + return FALSE; + + if (strcmp("layer", (next->getRepr())->attribute("inkscape:groupmode")) == 0) { + + dt->selection->cut(); + + doc_interface->target.getSelection()->layers()->setCurrentLayer(next); + + sp_selection_paste(dt, TRUE); + } + return TRUE; +} + +GArray * +document_interface_selection_get_center (DocumentInterface *doc_interface) +{ + Inkscape::Selection * sel = doc_interface->target.getSelection(); + + if (sel) + { + gdouble x = selection_get_center_x(sel); + gdouble y = selection_get_center_y(sel); + GArray * intArr = g_array_new (TRUE, TRUE, sizeof(double)); + + g_array_append_val (intArr, x); + g_array_append_val (intArr, y); + return intArr; + } + + return NULL; +} + +gboolean +document_interface_selection_to_path (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_OBJECT_TO_CURVE, error); +} + + +gboolean +document_interface_selection_combine (DocumentInterface *doc_interface, gchar *cmd, char ***newpaths, + GError **error) +{ + if (strcmp(cmd, "union") == 0) + dbus_call_verb (doc_interface, SP_VERB_SELECTION_UNION, error); + else if (strcmp(cmd, "intersection") == 0) + dbus_call_verb (doc_interface, SP_VERB_SELECTION_INTERSECT, error); + else if (strcmp(cmd, "difference") == 0) + dbus_call_verb (doc_interface, SP_VERB_SELECTION_DIFF, error); + else if (strcmp(cmd, "exclusion") == 0) + dbus_call_verb (doc_interface, SP_VERB_SELECTION_SYMDIFF, error); + else if (strcmp(cmd, "division") == 0) + dbus_call_verb (doc_interface, SP_VERB_SELECTION_CUT, error); + else { + g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Operation command not recognised"); + return FALSE; + } + + return document_interface_selection_get (doc_interface, newpaths, error); +} + +gboolean +document_interface_selection_change_level (DocumentInterface *doc_interface, gchar *cmd, + GError **error) +{ + if (strcmp(cmd, "raise") == 0) + return dbus_call_verb (doc_interface, SP_VERB_SELECTION_RAISE, error); + if (strcmp(cmd, "lower") == 0) + return dbus_call_verb (doc_interface, SP_VERB_SELECTION_LOWER, error); + if ((strcmp(cmd, "to_top") == 0) || (strcmp(cmd, "to_front") == 0)) + return dbus_call_verb (doc_interface, SP_VERB_SELECTION_TO_FRONT, error); + if ((strcmp(cmd, "to_bottom") == 0) || (strcmp(cmd, "to_back") == 0)) + return dbus_call_verb (doc_interface, SP_VERB_SELECTION_TO_BACK, error); + return TRUE; +} + +/**************************************************************************** + LAYER FUNCTIONS +****************************************************************************/ + +gchar *document_interface_layer_new(DocumentInterface *doc_interface, GError ** /*error*/) +{ + Inkscape::LayerModel * layers = doc_interface->target.getSelection()->layers(); + SPObject *new_layer = Inkscape::create_layer(layers->currentRoot(), layers->currentLayer(), Inkscape::LPOS_BELOW); + layers->setCurrentLayer(new_layer); + return g_strdup(get_name_from_object(new_layer)); +} + +gboolean +document_interface_layer_set (DocumentInterface *doc_interface, + gchar *layerstr, GError **error) +{ + SPObject * obj = get_object_by_name (doc_interface->target.getDocument(), layerstr, error); + + if (!obj) + return FALSE; + + doc_interface->target.getSelection()->layers()->setCurrentLayer (obj); + return TRUE; +} + +gchar **document_interface_layer_get_all(DocumentInterface * /*doc_interface*/) +{ + //FIXME: implement. + return NULL; +} + +gboolean +document_interface_layer_change_level (DocumentInterface *doc_interface, + gchar *cmd, GError **error) +{ + if (strcmp(cmd, "raise") == 0) + return dbus_call_verb (doc_interface, SP_VERB_LAYER_RAISE, error); + if (strcmp(cmd, "lower") == 0) + return dbus_call_verb (doc_interface, SP_VERB_LAYER_LOWER, error); + if ((strcmp(cmd, "to_top") == 0) || (strcmp(cmd, "to_front") == 0)) + return dbus_call_verb (doc_interface, SP_VERB_LAYER_TO_TOP, error); + if ((strcmp(cmd, "to_bottom") == 0) || (strcmp(cmd, "to_back") == 0)) + return dbus_call_verb (doc_interface, SP_VERB_LAYER_TO_BOTTOM, error); + return TRUE; +} + +gboolean +document_interface_layer_next (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_LAYER_NEXT, error); +} + +gboolean +document_interface_layer_previous (DocumentInterface *doc_interface, GError **error) +{ + return dbus_call_verb (doc_interface, SP_VERB_LAYER_PREV, error); +} + + +//////////////signals + + +DocumentInterface *fugly; +gboolean dbus_send_ping (SPDesktop* desk, SPItem *item) +{ + if (!item) return TRUE; + g_signal_emit (desk->dbus_document_interface, signals[OBJECT_MOVED_SIGNAL], 0, item->getId()); + return TRUE; +} + +//////////tree + + +gboolean +document_interface_get_children (DocumentInterface *doc_interface, char *name, char ***out, GError **error) +{ + SPItem* parent=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error); + std::vector<SPObject*> children = parent->childList(false); + + int size = children.size(); + + *out = g_new0 (char *, size + 1); + + int i = 0; + for (std::vector<SPObject*>::iterator iter = children.begin(), e = children.end(); iter != e; ++iter) { + (*out)[i] = g_strdup((*iter)->getId()); + i++; + } + (*out)[i] = NULL; + + return TRUE; +} + + +gchar* +document_interface_get_parent (DocumentInterface *doc_interface, char *name, GError **error) +{ + SPItem*node=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error); + + SPObject* parent=node->parent; + + return g_strdup(parent->getRepr()->attribute("id")); + +} + +#if 0 +//just pseudo code +gboolean +document_interface_get_xpath (DocumentInterface *doc_interface, char *xpath_expression, char ***out, GError **error){ + SPDocument * doc = doc_interface->target.getDocument(); + Inkscape::XML::Document *repr = doc->getReprDoc(); + + xmlXPathObjectPtr xpathObj; + xmlXPathContextPtr xpathCtx; + xpathCtx = xmlXPathNewContext(repr);//XmlDocPtr + xpathObj = xmlXPathEvalExpression(xmlCharStrdup(xpath_expression), xpathCtx); + + //xpathresult result = xpatheval(repr, xpath_selection); + //convert result to a string array we can return via dbus + return TRUE; +} +#endif +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : |