Code

Adding dbus descriptions to EXTRA_DIST
[inkscape.git] / src / extension / dbus / document-interface.cpp
index 76eeec509d7ea8323f9007a278b2dcdb06ef13d2..e2d7a41a2e3c01dd8e61bb485d966d49c543b249 100644 (file)
@@ -1,3 +1,20 @@
+/*
+ * 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)
 {
@@ -63,6 +83,9 @@ 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)
 {
@@ -75,8 +98,13 @@ 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)
     {
@@ -86,12 +114,19 @@ dbus_check_string (gchar *string, GError ** error, gchar * errorstr)
     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)
@@ -112,7 +147,21 @@ selection_get_center_y (Inkscape::Selection *sel){
     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)
 {
@@ -123,6 +172,9 @@ selection_swap(SPDesktop *desk, gchar *name, GError **error)
     return oldsel;
 }
 
+/*
+ * See selection_swap, above
+ */
 void
 selection_restore(SPDesktop *desk, const GSList * oldsel)
 {
@@ -130,19 +182,25 @@ 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)
 {    
@@ -227,6 +293,11 @@ document_interface_new (void)
         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)
 {
@@ -237,7 +308,6 @@ inkscape_error_quark (void)
   return quark;
 }
 
-/* This should really be standard. */
 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
 
 GType
@@ -306,7 +376,7 @@ document_interface_rectangle (DocumentInterface *object, int x, int y,
 {
 
 
-    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);
@@ -318,7 +388,7 @@ gchar*
 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);
@@ -333,7 +403,7 @@ document_interface_polygon (DocumentInterface *object, int cx, int 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);
@@ -354,7 +424,7 @@ document_interface_star (DocumentInterface *object, 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(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);
@@ -383,11 +453,10 @@ gchar*
 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");
 }
@@ -396,7 +465,7 @@ gchar*
 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);
@@ -406,14 +475,17 @@ document_interface_spiral (DocumentInterface *object, int cx, int 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)
 {
@@ -674,6 +768,28 @@ document_interface_merge_css (DocumentInterface *object, gchar *shape,
     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)