index 76eeec509d7ea8323f9007a278b2dcdb06ef13d2..e2d7a41a2e3c01dd8e61bb485d966d49c543b249 100644 (file)
+/*
+ * 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 remotly 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, read the file 'COPYING' for more information
+ */
+
#include "document-interface.h"
#include <string.h>
HELPER / SHORTCUT FUNCTIONS
****************************************************************************/
-const gchar* intToCString(int i)
-{
- std::stringstream ss;
- ss << i;
- return ss.str().c_str();
-}
-
+/*
+ * 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 (SPDesktop *desk, gchar *name, GError **error)
{
return node;
}
+/*
+ * See comment for get_repr_by_name, above.
+ */
SPObject *
get_object_by_name (SPDesktop *desk, gchar *name, GError **error)
{
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 seperatly) should call this.
+ */
gboolean
-dbus_check_string (gchar *string, GError ** error, gchar * errorstr)
+dbus_check_string (gchar *string, GError ** error, const gchar * errorstr)
{
if (string == NULL)
{
return TRUE;
}
+/*
+ * This is used to return object values to the user
+ */
const gchar *
get_name_from_object (SPObject * obj)
{
return obj->repr->attribute("id");
}
+/*
+ * Some verbs (cut, paste) only work on the active layer.
+ * This makes sure that the document that is about to recive a command is active.
+ */
void
desktop_ensure_active (SPDesktop* desk) {
if (desk != SP_ACTIVE_DESKTOP)
box = sel->boundsInDocument(box);
return box->y0 + ((box->y1 - box->y0)/2);
}
-//move_to etc
+
+/*
+ * 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 seperatly. Although
+ * they might see the selection box flicker if used in a loop.
+ */
const GSList *
selection_swap(SPDesktop *desk, gchar *name, GError **error)
{
return oldsel;
}
+/*
+ * See selection_swap, above
+ */
void
selection_restore(SPDesktop *desk, const GSList * oldsel)
{
sel->setList(oldsel);
}
+/*
+ * Shortcut for creating a Node.
+ */
Inkscape::XML::Node *
-dbus_create_node (SPDesktop *desk, gboolean isrect)
+dbus_create_node (SPDesktop *desk, const gchar *type)
{
SPDocument * doc = sp_desktop_document (desk);
Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
- gchar *type;
- if (isrect)
- type = (gchar *)"svg:rect";
- else
- type = (gchar *)"svg:path";
+
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 *object, GError **error, Inkscape::XML::Node *newNode, gchar *desc)
{
@@ -167,6 +225,14 @@ finish_create_shape (DocumentInterface *object, GError **error, Inkscape::XML::N
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 *object, int verbid, GError **error)
{
return (DocumentInterface*)g_object_new (TYPE_DOCUMENT_INTERFACE, NULL);
}
+/*
+ * Error stuff...
+ *
+ * To add a new error type, edit here and in the .h InkscapeError enum.
+ */
GQuark
inkscape_error_quark (void)
{
return quark;
}
-/* This should really be standard. */
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
GType
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, TRUE);
+ Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "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);
document_interface_ellipse_center (DocumentInterface *object, int cx, int cy,
int rx, int ry, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, FALSE);
+ Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
newNode->setAttribute("sodipodi:type", "arc");
sp_repr_set_int(newNode, "sodipodi:cx", cx);
sp_repr_set_int(newNode, "sodipodi:cy", cy);
GError **error)
{
gdouble rot = ((rotation / 180.0) * 3.14159265) - ( 3.14159265 / 2.0);
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, FALSE);
+ Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
newNode->setAttribute("inkscape:flatsided", "true");
newNode->setAttribute("sodipodi:type", "star");
sp_repr_set_int(newNode, "sodipodi:cx", cx);
int r1, int r2, int sides, gdouble rounded,
gdouble arg1, gdouble arg2, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, FALSE);
+ Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
newNode->setAttribute("inkscape:flatsided", "false");
newNode->setAttribute("sodipodi:type", "star");
sp_repr_set_int(newNode, "sodipodi:cx", cx);
document_interface_line (DocumentInterface *object, int x, int y,
int x2, int y2, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, FALSE);
+ Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
std::stringstream out;
- printf("X2: %d\nY2 %d\n", x2, y2);
- out << "m " << x << "," << y << " " << x2 << "," << y2;
- printf ("PATH: %s\n", out.str().c_str());
+ // Not sure why this works.
+ out << "m " << x << "," << y << " " << x2 - x << "," << y2 - y;
newNode->setAttribute("d", out.str().c_str());
return finish_create_shape (object, error, newNode, (gchar *)"create line");
}
document_interface_spiral (DocumentInterface *object, int cx, int cy,
int r, int revolutions, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, FALSE);
+ Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "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:argument", 0);
sp_repr_set_int(newNode, "sodipodi:expansion", 1);
gchar * retval = finish_create_shape (object, error, newNode, (gchar *)"create spiral");
- newNode->setAttribute("style", "fill:none");
+ //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;
}
gboolean
document_interface_text (DocumentInterface *object, int x, int y, gchar *text, GError **error)
{
- //FIXME: Not selectable.
+ //FIXME: Not selectable (aka broken). Needs to be rewritten completely.
SPDesktop *desktop = object->desk;
SPCanvasText * canvas_text = (SPCanvasText *) sp_canvastext_new(sp_desktop_tempgroup(desktop), desktop, Geom::Point(0,0), "");
@@ -423,6 +495,28 @@ document_interface_text (DocumentInterface *object, int x, int y, gchar *text, G
return TRUE;
}
+gchar *
+document_interface_image (DocumentInterface *object, 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(object->desk, "svg:image");
+ sp_repr_set_int(newNode, "x", x);
+ sp_repr_set_int(newNode, "y", y);
+ newNode->setAttribute("xlink:href", uri);
+
+ object->desk->currentLayer()->appendChildRepr(newNode);
+ object->desk->currentLayer()->updateRepr();
+
+ if (object->updates)
+ sp_document_done(sp_desktop_document(object->desk), 0, "Imported bitmap.");
+
+ //g_free(uri);
+ return strdup(newNode->attribute("id"));
+}
+
gchar*
document_interface_node (DocumentInterface *object, gchar *type, GError **error)
{
return TRUE;
}
+gboolean
+document_interface_set_color (DocumentInterface *object, 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 (object, style, error);
+
+ return document_interface_merge_css (object, shape, style, error);
+}
+
gboolean
document_interface_move_to_layer (DocumentInterface *object, gchar *shape,
gchar *layerstr, GError **error)
@@ -1054,6 +1170,8 @@ document_interface_selection_move_to (DocumentInterface *object, gdouble x, gdou
}
//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 *object,
gchar *layerstr, GError **error)