Code

Pot and Dutch translation update
[inkscape.git] / src / extension / dbus / document-interface.cpp
1 /*
2  * This is where the implementation of the DBus based document API lives.
3  * All the methods in here (except in the helper section) are 
4  * designed to be called remotly via DBus. application-interface.cpp
5  * has the methods used to connect to the bus and get a document instance.
6  *
7  * Documentation for these methods is in document-interface.xml
8  * which is the "gold standard" as to how the interface should work.
9  *
10  * Authors:
11  *   Soren Berg <Glimmer07@gmail.com>
12  *
13  * Copyright (C) 2009 Soren Berg
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  */
18 #include "document-interface.h"
19 #include <string.h>
21 #include "verbs.h"
22 #include "helper/action.h" //sp_action_perform
24 #include "inkscape.h" //inkscape_find_desktop_by_dkey, activate desktops
26 #include "desktop-handles.h" //sp_desktop_document()
27 #include "xml/repr.h" //sp_repr_document_new
29 #include "sp-object.h"
31 #include "document.h" // sp_document_repr_doc
33 #include "desktop-style.h" //sp_desktop_get_style
35 #include "selection.h" //selection struct
36 #include "selection-chemistry.h"// lots of selection functions
38 #include "sp-ellipse.h"
40 #include "layer-fns.h" //LPOS_BELOW
42 #include "style.h" //style_write
44 #include "file.h" //IO
46 #include "extension/system.h" //IO
48 #include "extension/output.h" //IO
50 #include "print.h" //IO
52 #include "live_effects/parameter/text.h" //text
53 #include "display/canvas-text.h" //text
55 //#include "2geom/svg-path-parser.h" //get_node_coordinates
57 /****************************************************************************
58      HELPER / SHORTCUT FUNCTIONS
59 ****************************************************************************/
61 /* 
62  * This function or the one below it translates the user input for an object
63  * into Inkscapes internal representation.  It is called by almost every
64  * method so it should be as fast as possible.
65  *
66  * (eg turns "rect2234" to an SPObject or Inkscape::XML::Node)
67  *
68  * If the internal representation changes (No more 'id' attributes) this is the
69  * place to adjust things.
70  */
71 Inkscape::XML::Node *
72 get_repr_by_name (SPDesktop *desk, gchar *name, GError **error)
73 {
74     /* ALTERNATIVE (is this faster if only repr is needed?)
75     Inkscape::XML::Node *node = sp_repr_lookup_name((doc->root)->repr, name);
76     */
77     Inkscape::XML::Node * node = sp_desktop_document(desk)->getObjectById(name)->repr;
78     if (!node)
79     {
80         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name);
81         return NULL;
82     }
83     return node;
84 }
86 /* 
87  * See comment for get_repr_by_name, above.
88  */
89 SPObject *
90 get_object_by_name (SPDesktop *desk, gchar *name, GError **error)
91 {
92     SPObject * obj = sp_desktop_document(desk)->getObjectById(name);
93     if (!obj)
94     {
95         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name);
96         return NULL;
97     }
98     return obj;
99 }
101 /*
102  * Tests for NULL strings and throws an appropriate error.
103  * Every method that takes a string parameter (other than the 
104  * name of an object, that's tested seperatly) should call this.
105  */
106 gboolean
107 dbus_check_string (gchar *string, GError ** error, const gchar * errorstr)
109     if (string == NULL)
110     {
111         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "%s", errorstr);
112         return FALSE;
113     }
114     return TRUE;
117 /* 
118  * This is used to return object values to the user
119  */
120 const gchar *
121 get_name_from_object (SPObject * obj)
123     return obj->repr->attribute("id"); 
126 /*
127  * Some verbs (cut, paste) only work on the active layer.
128  * This makes sure that the document that is about to recive a command is active.
129  */
130 void
131 desktop_ensure_active (SPDesktop* desk) {
132     if (desk != SP_ACTIVE_DESKTOP)
133         inkscape_activate_desktop (desk);
134     return;
137 gdouble
138 selection_get_center_x (Inkscape::Selection *sel){
139     NRRect *box = g_new(NRRect, 1);;
140     box = sel->boundsInDocument(box);
141     return box->x0 + ((box->x1 - box->x0)/2);
144 gdouble
145 selection_get_center_y (Inkscape::Selection *sel){
146     NRRect *box = g_new(NRRect, 1);;
147     box = sel->boundsInDocument(box);
148     return box->y0 + ((box->y1 - box->y0)/2);
151 /* 
152  * This function is used along with selection_restore to
153  * take advantage of functionality provided by a selection
154  * for a single object.
155  *
156  * It saves the current selection and sets the selection to 
157  * the object specified.  Any selection verb can be used on the
158  * object and then selection_restore is called, restoring the 
159  * original selection.
160  *
161  * This should be mostly transparent to the user who need never
162  * know we never bothered to implement it seperatly.  Although
163  * they might see the selection box flicker if used in a loop.
164  */
165 const GSList *
166 selection_swap(SPDesktop *desk, gchar *name, GError **error)
168     Inkscape::Selection *sel = sp_desktop_selection(desk);
169     const GSList *oldsel = g_slist_copy((GSList *)sel->list());
170     
171     sel->set(get_object_by_name(desk, name, error));
172     return oldsel;
175 /*
176  * See selection_swap, above
177  */
178 void
179 selection_restore(SPDesktop *desk, const GSList * oldsel)
181     Inkscape::Selection *sel = sp_desktop_selection(desk);
182     sel->setList(oldsel);
185 /*
186  * Shortcut for creating a Node.
187  */
188 Inkscape::XML::Node *
189 dbus_create_node (SPDesktop *desk, const gchar *type)
191     SPDocument * doc = sp_desktop_document (desk);
192     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
194     return xml_doc->createElement(type);
197 /*
198  * Called by the shape creation functions.  Gets the default style for the doc
199  * or sets it arbitrarily if none.
200  *
201  * There is probably a better way to do this (use the shape tools default styles)
202  * but I'm not sure how.
203  */
204 gchar *
205 finish_create_shape (DocumentInterface *object, GError **error, Inkscape::XML::Node *newNode, gchar *desc)
208     SPCSSAttr *style = sp_desktop_get_style(object->desk, TRUE);
209     
210     if (style) {
211         newNode->setAttribute("style", sp_repr_css_write_string(style), TRUE);
212     }
213     else {
214         newNode->setAttribute("style", "fill:#0000ff;fill-opacity:1;stroke:#c900b9;stroke-width:0;stroke-miterlimit:0;stroke-opacity:1;stroke-dasharray:none", TRUE);
215     }
217     object->desk->currentLayer()->appendChildRepr(newNode);
218     object->desk->currentLayer()->updateRepr();
220     if (object->updates)
221         sp_document_done(sp_desktop_document(object->desk), 0, (gchar *)desc);
222     //else
223         //document_interface_pause_updates(object, error);
225     return strdup(newNode->attribute("id"));
228 /*
229  * This is the code used internally to call all the verbs.
230  *
231  * It handles error reporting and update pausing (which needs some work.)
232  * This is a good place to improve efficiency as it is called a lot.
233  *
234  * document_interface_call_verb is similar but is called by the user.
235  */
236 gboolean
237 dbus_call_verb (DocumentInterface *object, int verbid, GError **error)
238 {    
239     SPDesktop *desk2 = object->desk;
240     desktop_ensure_active (desk2);
241     
242     if ( desk2 ) {
243         Inkscape::Verb *verb = Inkscape::Verb::get( verbid );
244         if ( verb ) {
245             SPAction *action = verb->get_action(desk2);
246             if ( action ) {
247                 //if (!object->updates)
248                     //document_interface_pause_updates (object, error);
249                 sp_action_perform( action, NULL );
250                 if (object->updates)
251                     sp_document_done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip()));
252                 //if (!object->updates)
253                     //document_interface_pause_updates (object, error);
254                 return TRUE;
255             }
256         }
257     }
258     g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb failed to execute");
259     return FALSE;
262 /****************************************************************************
263      DOCUMENT INTERFACE CLASS STUFF
264 ****************************************************************************/
266 G_DEFINE_TYPE(DocumentInterface, document_interface, G_TYPE_OBJECT)
268 static void
269 document_interface_finalize (GObject *object)
271         G_OBJECT_CLASS (document_interface_parent_class)->finalize (object);
275 static void
276 document_interface_class_init (DocumentInterfaceClass *klass)
278         GObjectClass *object_class;
279         object_class = G_OBJECT_CLASS (klass);
280         object_class->finalize = document_interface_finalize;
283 static void
284 document_interface_init (DocumentInterface *object)
286         object->desk = NULL;
290 DocumentInterface *
291 document_interface_new (void)
293         return (DocumentInterface*)g_object_new (TYPE_DOCUMENT_INTERFACE, NULL);
296 /* 
297  * Error stuff...
298  *
299  * To add a new error type, edit here and in the .h InkscapeError enum.
300  */
301 GQuark
302 inkscape_error_quark (void)
304   static GQuark quark = 0;
305   if (!quark)
306     quark = g_quark_from_static_string ("inkscape_error");
308   return quark;
311 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
313 GType
314 inkscape_error_get_type (void)
316         static GType etype = 0;
318         if (etype == 0)
319         {
320                 static const GEnumValue values[] =
321                 {
323                         ENUM_ENTRY (INKSCAPE_ERROR_SELECTION, "Incompatible_Selection"),
324                         ENUM_ENTRY (INKSCAPE_ERROR_OBJECT, "Incompatible_Object"),
325                         ENUM_ENTRY (INKSCAPE_ERROR_VERB, "Failed_Verb"),
326                         ENUM_ENTRY (INKSCAPE_ERROR_OTHER, "Generic_Error"),
327                         { 0, 0, 0 }
328                 };
330                 etype = g_enum_register_static ("InkscapeError", values);
331         }
333         return etype;
336 /****************************************************************************
337      MISC FUNCTIONS
338 ****************************************************************************/
340 gboolean
341 document_interface_delete_all (DocumentInterface *object, GError **error)
343     sp_edit_clear_all (object->desk);
344     return TRUE;
347 gboolean
348 document_interface_call_verb (DocumentInterface *object, gchar *verbid, GError **error)
350     SPDesktop *desk2 = object->desk;
351     desktop_ensure_active (object->desk);
352     if ( desk2 ) {
353         Inkscape::Verb *verb = Inkscape::Verb::getbyid( verbid );
354         if ( verb ) {
355             SPAction *action = verb->get_action(desk2);
356             if ( action ) {
357                 sp_action_perform( action, NULL );
358                 if (object->updates) {
359                     sp_document_done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip()));
360                 }
361             }
362         }
363     }
364     g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb '%s' failed to execute or was not found.", verbid);
365     return FALSE;
369 /****************************************************************************
370      CREATION FUNCTIONS
371 ****************************************************************************/
373 gchar* 
374 document_interface_rectangle (DocumentInterface *object, int x, int y, 
375                               int width, int height, GError **error)
379     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:rect");
380     sp_repr_set_int(newNode, "x", x);  //could also use newNode->setAttribute()
381     sp_repr_set_int(newNode, "y", y);
382     sp_repr_set_int(newNode, "width", width);
383     sp_repr_set_int(newNode, "height", height);
384     return finish_create_shape (object, error, newNode, (gchar *)"create rectangle");
387 gchar*
388 document_interface_ellipse_center (DocumentInterface *object, int cx, int cy, 
389                                    int rx, int ry, GError **error)
391     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
392     newNode->setAttribute("sodipodi:type", "arc");
393     sp_repr_set_int(newNode, "sodipodi:cx", cx);
394     sp_repr_set_int(newNode, "sodipodi:cy", cy);
395     sp_repr_set_int(newNode, "sodipodi:rx", rx);
396     sp_repr_set_int(newNode, "sodipodi:ry", ry);
397     return finish_create_shape (object, error, newNode, (gchar *)"create circle");
400 gchar* 
401 document_interface_polygon (DocumentInterface *object, int cx, int cy, 
402                             int radius, int rotation, int sides, 
403                             GError **error)
405     gdouble rot = ((rotation / 180.0) * 3.14159265) - ( 3.14159265 / 2.0);
406     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
407     newNode->setAttribute("inkscape:flatsided", "true");
408     newNode->setAttribute("sodipodi:type", "star");
409     sp_repr_set_int(newNode, "sodipodi:cx", cx);
410     sp_repr_set_int(newNode, "sodipodi:cy", cy);
411     sp_repr_set_int(newNode, "sodipodi:r1", radius);
412     sp_repr_set_int(newNode, "sodipodi:r2", radius);
413     sp_repr_set_int(newNode, "sodipodi:sides", sides);
414     sp_repr_set_int(newNode, "inkscape:randomized", 0);
415     sp_repr_set_svg_double(newNode, "sodipodi:arg1", rot);
416     sp_repr_set_svg_double(newNode, "sodipodi:arg2", rot);
417     sp_repr_set_svg_double(newNode, "inkscape:rounded", 0);
419     return finish_create_shape (object, error, newNode, (gchar *)"create polygon");
422 gchar* 
423 document_interface_star (DocumentInterface *object, int cx, int cy, 
424                          int r1, int r2, int sides, gdouble rounded,
425                          gdouble arg1, gdouble arg2, GError **error)
427     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
428     newNode->setAttribute("inkscape:flatsided", "false");
429     newNode->setAttribute("sodipodi:type", "star");
430     sp_repr_set_int(newNode, "sodipodi:cx", cx);
431     sp_repr_set_int(newNode, "sodipodi:cy", cy);
432     sp_repr_set_int(newNode, "sodipodi:r1", r1);
433     sp_repr_set_int(newNode, "sodipodi:r2", r2);
434     sp_repr_set_int(newNode, "sodipodi:sides", sides);
435     sp_repr_set_int(newNode, "inkscape:randomized", 0);
436     sp_repr_set_svg_double(newNode, "sodipodi:arg1", arg1);
437     sp_repr_set_svg_double(newNode, "sodipodi:arg2", arg2);
438     sp_repr_set_svg_double(newNode, "inkscape:rounded", rounded);
440     return finish_create_shape (object, error, newNode, (gchar *)"create star");
443 gchar* 
444 document_interface_ellipse (DocumentInterface *object, int x, int y, 
445                             int width, int height, GError **error)
447     int rx = width/2;
448     int ry = height/2;
449     return document_interface_ellipse_center (object, x+rx, y+ry, rx, ry, error);
452 gchar* 
453 document_interface_line (DocumentInterface *object, int x, int y, 
454                               int x2, int y2, GError **error)
456     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
457     std::stringstream out;
458     // Not sure why this works.
459         out << "m " << x << "," << y << " " << x2 - x << "," << y2 - y;
460     newNode->setAttribute("d", out.str().c_str());
461     return finish_create_shape (object, error, newNode, (gchar *)"create line");
464 gchar* 
465 document_interface_spiral (DocumentInterface *object, int cx, int cy, 
466                            int r, int revolutions, GError **error)
468     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
469     newNode->setAttribute("sodipodi:type", "spiral");
470     sp_repr_set_int(newNode, "sodipodi:cx", cx);
471     sp_repr_set_int(newNode, "sodipodi:cy", cy);
472     sp_repr_set_int(newNode, "sodipodi:radius", r);
473     sp_repr_set_int(newNode, "sodipodi:revolution", revolutions);
474     sp_repr_set_int(newNode, "sodipodi:t0", 0);
475     sp_repr_set_int(newNode, "sodipodi:argument", 0);
476     sp_repr_set_int(newNode, "sodipodi:expansion", 1);
477     gchar * retval = finish_create_shape (object, error, newNode, (gchar *)"create spiral");
478     //Makes sure there is no fill for spirals by default.
479     gchar* newString = g_strconcat(newNode->attribute("style"), ";fill:none", NULL);
480     newNode->setAttribute("style", newString);
481     g_free(newString);
482     return retval;
485 gboolean
486 document_interface_text (DocumentInterface *object, int x, int y, gchar *text, GError **error)
488     //FIXME: Not selectable (aka broken).  Needs to be rewritten completely.
490     SPDesktop *desktop = object->desk;
491     SPCanvasText * canvas_text = (SPCanvasText *) sp_canvastext_new(sp_desktop_tempgroup(desktop), desktop, Geom::Point(0,0), "");
492     sp_canvastext_set_text (canvas_text, text);
493     sp_canvastext_set_coords (canvas_text, x, y);
495     return TRUE;
498 gchar *
499 document_interface_image (DocumentInterface *object, int x, int y, gchar *filename, GError **error)
501     gchar * uri = g_filename_to_uri (filename, FALSE, error);
502     if (!uri)
503         return FALSE;
504     
505     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:image");
506     sp_repr_set_int(newNode, "x", x);
507     sp_repr_set_int(newNode, "y", y);
508     newNode->setAttribute("xlink:href", uri);
509     
510     object->desk->currentLayer()->appendChildRepr(newNode);
511     object->desk->currentLayer()->updateRepr();
513     if (object->updates)
514         sp_document_done(sp_desktop_document(object->desk), 0, "Imported bitmap.");
516     //g_free(uri);
517     return strdup(newNode->attribute("id"));
520 gchar* 
521 document_interface_node (DocumentInterface *object, gchar *type, GError **error)
523     SPDocument * doc = sp_desktop_document (object->desk);
524     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
526     Inkscape::XML::Node *newNode =  xml_doc->createElement(type);
528     object->desk->currentLayer()->appendChildRepr(newNode);
529     object->desk->currentLayer()->updateRepr();
531     if (object->updates)
532         sp_document_done(sp_desktop_document(object->desk), 0, (gchar *)"created empty node");
533     //else
534         //document_interface_pause_updates(object, error);
536     return strdup(newNode->attribute("id"));
539 /****************************************************************************
540      ENVIORNMENT FUNCTIONS
541 ****************************************************************************/
542 gdouble
543 document_interface_document_get_width (DocumentInterface *object)
545     return sp_document_width(sp_desktop_document(object->desk));
548 gdouble
549 document_interface_document_get_height (DocumentInterface *object)
551     return sp_document_height(sp_desktop_document(object->desk));
554 gchar *
555 document_interface_document_get_css (DocumentInterface *object, GError **error)
557     SPCSSAttr *current = (object->desk)->current;
558     return sp_repr_css_write_string(current);
561 gboolean 
562 document_interface_document_merge_css (DocumentInterface *object,
563                                        gchar *stylestring, GError **error)
565     SPCSSAttr * style = sp_repr_css_attr_new();
566     sp_repr_css_attr_add_from_string (style, stylestring);
567     sp_desktop_set_style (object->desk, style);
568     return TRUE;
571 gboolean 
572 document_interface_document_set_css (DocumentInterface *object,
573                                      gchar *stylestring, GError **error)
575     SPCSSAttr * style = sp_repr_css_attr_new();
576     sp_repr_css_attr_add_from_string (style, stylestring);
577     //Memory leak?
578     object->desk->current = style;
579     return TRUE;
582 gboolean 
583 document_interface_document_resize_to_fit_selection (DocumentInterface *object,
584                                                      GError **error)
586     return dbus_call_verb (object, SP_VERB_FIT_CANVAS_TO_SELECTION, error);
587     return TRUE;
590 /****************************************************************************
591      OBJECT FUNCTIONS
592 ****************************************************************************/
594 gboolean
595 document_interface_set_attribute (DocumentInterface *object, char *shape, 
596                                   char *attribute, char *newval, GError **error)
598     Inkscape::XML::Node *newNode = get_repr_by_name(object->desk, shape, error);
600     /* ALTERNATIVE (is this faster?)
601     Inkscape::XML::Node *newnode = sp_repr_lookup_name((doc->root)->repr, name);
602     */
603     if (!dbus_check_string(newval, error, "New value string was empty."))
604         return FALSE;
605         
606     if (!newNode)
607         return FALSE;
608         
609     newNode->setAttribute(attribute, newval, TRUE);
610     return TRUE;
613 gboolean 
614 document_interface_set_int_attribute (DocumentInterface *object, 
615                                       char *shape, char *attribute, 
616                                       int newval, GError **error)
618     Inkscape::XML::Node *newNode = get_repr_by_name (object->desk, shape, error);
619     if (!newNode)
620         return FALSE;
621         
622     sp_repr_set_int (newNode, attribute, newval);
623     return TRUE;
627 gboolean
628 document_interface_set_double_attribute (DocumentInterface *object, 
629                                          char *shape, char *attribute, 
630                                          double newval, GError **error)
632     Inkscape::XML::Node *newNode = get_repr_by_name (object->desk, shape, error);
633     
634     if (!dbus_check_string (attribute, error, "New value string was empty."))
635         return FALSE;
636     if (!newNode)
637         return FALSE;
638     
639     sp_repr_set_svg_double (newNode, attribute, newval);
640     return TRUE;
643 gchar *
644 document_interface_get_attribute (DocumentInterface *object, char *shape, 
645                                   char *attribute, GError **error)
647     Inkscape::XML::Node *newNode = get_repr_by_name(object->desk, shape, error);
649     if (!dbus_check_string (attribute, error, "Attribute name empty."))
650         return NULL;
651     if (!newNode)
652         return NULL;
653         
654     return g_strdup(newNode->attribute(attribute));
657 gboolean
658 document_interface_move (DocumentInterface *object, gchar *name, gdouble x, 
659                          gdouble y, GError **error)
661     const GSList *oldsel = selection_swap(object->desk, name, error);
662     if (!oldsel)
663         return FALSE;
664     sp_selection_move (object->desk, x, 0 - y);
665     selection_restore(object->desk, oldsel);
666     return TRUE;
669 gboolean
670 document_interface_move_to (DocumentInterface *object, gchar *name, gdouble x, 
671                          gdouble y, GError **error)
673     const GSList *oldsel = selection_swap(object->desk, name, error);
674     if (!oldsel)
675         return FALSE;
676     Inkscape::Selection * sel = sp_desktop_selection(object->desk);
677     sp_selection_move (object->desk, x - selection_get_center_x(sel),
678                                      0 - (y - selection_get_center_y(sel)));
679     selection_restore(object->desk, oldsel);
680     return TRUE;
683 gboolean
684 document_interface_object_to_path (DocumentInterface *object, 
685                                    char *shape, GError **error)
687     const GSList *oldsel = selection_swap(object->desk, shape, error);
688     if (!oldsel)
689         return FALSE;
690     dbus_call_verb (object, SP_VERB_OBJECT_TO_CURVE, error);
691     selection_restore(object->desk, oldsel);
692     return TRUE;
695 gchar *
696 document_interface_get_path (DocumentInterface *object, char *pathname, GError **error)
698     Inkscape::XML::Node *node = get_repr_by_name(object->desk, pathname, error);
699     
700     if (!node)
701         return NULL;
702         
703     if (node->attribute("d") == NULL)
704     {
705         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object is not a path.");
706         return NULL;
707     }
708     return strdup(node->attribute("d"));
711 gboolean 
712 document_interface_transform (DocumentInterface *object, gchar *shape,
713                               gchar *transformstr, GError **error)
715     //FIXME: This should merge transformations.
716     gchar trans[] = "transform";
717     document_interface_set_attribute (object, shape, trans, transformstr, error);
718     return TRUE;
721 gchar *
722 document_interface_get_css (DocumentInterface *object, gchar *shape,
723                             GError **error)
725     gchar style[] = "style";
726     return document_interface_get_attribute (object, shape, style, error);
729 gboolean 
730 document_interface_modify_css (DocumentInterface *object, gchar *shape,
731                                gchar *cssattrb, gchar *newval, GError **error)
733     // Doesn't like non-variable strings for some reason.
734     gchar style[] = "style";
735     Inkscape::XML::Node *node = get_repr_by_name(object->desk, shape, error);
736     
737     if (!dbus_check_string (cssattrb, error, "Attribute string empty."))
738         return FALSE;
739     if (!node)
740         return FALSE;
741         
742     SPCSSAttr * oldstyle = sp_repr_css_attr (node, style);
743     sp_repr_css_set_property(oldstyle, cssattrb, newval);
744     node->setAttribute (style, sp_repr_css_write_string (oldstyle), TRUE);
745     return TRUE;
748 gboolean 
749 document_interface_merge_css (DocumentInterface *object, gchar *shape,
750                                gchar *stylestring, GError **error)
752     gchar style[] = "style";
753     
754     Inkscape::XML::Node *node = get_repr_by_name(object->desk, shape, error);
755     
756     if (!dbus_check_string (stylestring, error, "Style string empty."))
757         return FALSE;
758     if (!node)
759         return FALSE;
760         
761     SPCSSAttr * newstyle = sp_repr_css_attr_new();
762     sp_repr_css_attr_add_from_string (newstyle, stylestring);
764     SPCSSAttr * oldstyle = sp_repr_css_attr (node, style);
766     sp_repr_css_merge(oldstyle, newstyle);
767     node->setAttribute (style, sp_repr_css_write_string (oldstyle), TRUE);
768     return TRUE;
771 gboolean 
772 document_interface_set_color (DocumentInterface *object, gchar *shape,
773                               int r, int g, int b, gboolean fill, GError **error)
775     gchar style[15];
776     if (r<0 || r>255 || g<0 || g>255 || b<0 || b>255)
777     {
778         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Given (%d,%d,%d).  All values must be between 0-255 inclusive.", r, g, b);
779         return FALSE;
780     }
781     
782     if (fill)
783         snprintf(style, 15, "fill:#%.2x%.2x%.2x", r, g, b);
784     else
785         snprintf(style, 15, "stroke:#%.2x%.2x%.2x", r, g, b);
786     
787     if (strcmp(shape, "document") == 0)
788         return document_interface_document_merge_css (object, style, error);
789     
790     return document_interface_merge_css (object, shape, style, error);
793 gboolean 
794 document_interface_move_to_layer (DocumentInterface *object, gchar *shape, 
795                               gchar *layerstr, GError **error)
797     const GSList *oldsel = selection_swap(object->desk, shape, error);
798     if (!oldsel)
799         return FALSE;
800         
801     document_interface_selection_move_to_layer(object, layerstr, error);
802     selection_restore(object->desk, oldsel);
803     return TRUE;
806 GArray *
807 document_interface_get_node_coordinates (DocumentInterface *object, gchar *shape)
809     //FIXME: Needs lot's of work.
810 /*
811     Inkscape::XML::Node *shapenode = get_repr_by_name (object->desk, shape, error);
812     if (shapenode == NULL || shapenode->attribute("d") == NULL) {
813         return FALSE;
814     }
815     char * path = strdup(shapenode->attribute("d"));
816     printf("PATH: %s\n", path);
817     
818     Geom::parse_svg_path (path);
819     return NULL;
820     */
821     return NULL;
825 /****************************************************************************
826      FILE I/O FUNCTIONS
827 ****************************************************************************/
829 gboolean 
830 document_interface_save (DocumentInterface *object, GError **error)
832     SPDocument * doc = sp_desktop_document(object->desk);
833     printf("1:  %s\n2:  %s\n3:  %s\n", doc->uri, doc->base, doc->name);
834     if (doc->uri)
835         return document_interface_save_as (object, doc->uri, error);
836     return FALSE;
839 gboolean 
840 document_interface_load (DocumentInterface *object, 
841                         gchar *filename, GError **error)
843     desktop_ensure_active (object->desk);
844     const Glib::ustring file(filename);
845     sp_file_open(file, NULL, TRUE, TRUE);
846     if (object->updates)
847         sp_document_done(sp_desktop_document(object->desk), SP_VERB_FILE_OPEN, "Opened File");
848     return TRUE;
851 gboolean 
852 document_interface_save_as (DocumentInterface *object, 
853                            gchar *filename, GError **error)
855     SPDocument * doc = sp_desktop_document(object->desk);
856     #ifdef WITH_GNOME_VFS
857     const Glib::ustring file(filename);
858     return file_save_remote(doc, file, NULL, TRUE, TRUE);
859     #endif
860     if (!doc || strlen(filename)<1) //Safety check
861         return false;
863     try {
864         Inkscape::Extension::save(NULL, doc, filename,
865                  false, false, true, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS);
866     } catch (...) {
867         //SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
868         return false;
869     }
871     //SP_ACTIVE_DESKTOP->event_log->rememberFileSave();
872     //SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, "Document saved.");
873     return true;
876 gboolean
877 document_interface_mark_as_unmodified (DocumentInterface *object, GError **error)
879     SPDocument * doc = sp_desktop_document(object->desk);
880     if (doc)
881         doc->modified_since_save = FALSE;
882     return TRUE;
885 /*
886 gboolean 
887 document_interface_print_to_file (DocumentInterface *object, GError **error)
889     SPDocument * doc = sp_desktop_document(object->desk);
890     sp_print_document_to_file (doc, g_strdup("/home/soren/test.pdf"));
891                                
892     return TRUE;
894 */
895 /****************************************************************************
896      PROGRAM CONTROL FUNCTIONS
897 ****************************************************************************/
899 gboolean
900 document_interface_close (DocumentInterface *object, GError **error)
902     return dbus_call_verb (object, SP_VERB_FILE_CLOSE_VIEW, error);
905 gboolean
906 document_interface_exit (DocumentInterface *object, GError **error)
908     return dbus_call_verb (object, SP_VERB_FILE_QUIT, error);
911 gboolean
912 document_interface_undo (DocumentInterface *object, GError **error)
914     return dbus_call_verb (object, SP_VERB_EDIT_UNDO, error);
917 gboolean
918 document_interface_redo (DocumentInterface *object, GError **error)
920     return dbus_call_verb (object, SP_VERB_EDIT_REDO, error);
925 /****************************************************************************
926      UPDATE FUNCTIONS 
927      FIXME: This would work better by adding a flag to SPDesktop to prevent
928      updating but that would be very intrusive so for now there is a workaround.
929      Need to make sure it plays well with verbs because they are used so much.
930 ****************************************************************************/
932 void
933 document_interface_pause_updates (DocumentInterface *object, GError **error)
935     object->updates = FALSE;
936     object->desk->canvas->drawing_disabled = 1;
937     //object->desk->canvas->need_redraw = 0;
938     //object->desk->canvas->need_repick = 0;
939     //sp_desktop_document(object->desk)->root->uflags = FALSE;
940     //sp_desktop_document(object->desk)->root->mflags = FALSE;
943 void
944 document_interface_resume_updates (DocumentInterface *object, GError **error)
946     object->updates = TRUE;
947     object->desk->canvas->drawing_disabled = 0;
948     //object->desk->canvas->need_redraw = 1;
949     //object->desk->canvas->need_repick = 1;
950     //sp_desktop_document(object->desk)->root->uflags = TRUE;
951     //sp_desktop_document(object->desk)->root->mflags = TRUE;
952     //sp_desktop_document(object->desk)->_updateDocument();
953     //FIXME: use better verb than rect.
954     sp_document_done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions");
957 void
958 document_interface_update (DocumentInterface *object, GError **error)
960     sp_desktop_document(object->desk)->root->uflags = TRUE;
961     sp_desktop_document(object->desk)->root->mflags = TRUE;
962     object->desk->enableInteraction();
963     sp_desktop_document(object->desk)->_updateDocument();
964     object->desk->disableInteraction();
965     sp_desktop_document(object->desk)->root->uflags = FALSE;
966     sp_desktop_document(object->desk)->root->mflags = FALSE;
967     //sp_document_done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions");
970 /****************************************************************************
971      SELECTION FUNCTIONS FIXME: use call_verb where appropriate (once update system is tested.)
972 ****************************************************************************/
974 gboolean
975 document_interface_selection_get (DocumentInterface *object, char ***out, GError **error)
977     Inkscape::Selection * sel = sp_desktop_selection(object->desk);
978     GSList const *oldsel = sel->list();
980     int size = g_slist_length((GSList *) oldsel);
982     *out = g_new0 (char *, size + 1);
984     int i = 0;
985     for (GSList const *iter = oldsel; iter != NULL; iter = iter->next) {
986         (*out)[i] = g_strdup(SP_OBJECT(iter->data)->repr->attribute("id"));
987         i++;
988     }
989     (*out)[i] = NULL;
991     return TRUE;
994 gboolean
995 document_interface_selection_add (DocumentInterface *object, char *name, GError **error)
997     SPObject * obj = get_object_by_name(object->desk, name, error);
998     if (!obj)
999         return FALSE;
1000     
1001     Inkscape::Selection *selection = sp_desktop_selection(object->desk);
1003     selection->add(obj);
1004     return TRUE;
1007 gboolean
1008 document_interface_selection_add_list (DocumentInterface *object, 
1009                                        char **names, GError **error)
1011     int i;
1012     for (i=0;names[i] != NULL;i++) {
1013         document_interface_selection_add(object, names[i], error);       
1014     }
1015     return TRUE;
1018 gboolean
1019 document_interface_selection_set (DocumentInterface *object, char *name, GError **error)
1021     SPDocument * doc = sp_desktop_document (object->desk);
1022     Inkscape::Selection *selection = sp_desktop_selection(object->desk);
1023     selection->set(doc->getObjectById(name));
1024     return TRUE;
1027 gboolean
1028 document_interface_selection_set_list (DocumentInterface *object, 
1029                                        gchar **names, GError **error)
1031     sp_desktop_selection(object->desk)->clear();
1032     int i;
1033     for (i=0;names[i] != NULL;i++) {
1034         document_interface_selection_add(object, names[i], error);       
1035     }
1036     return TRUE;
1039 gboolean
1040 document_interface_selection_rotate (DocumentInterface *object, int angle, GError **error)
1042     Inkscape::Selection *selection = sp_desktop_selection(object->desk);
1043     sp_selection_rotate(selection, angle);
1044     return TRUE;
1047 gboolean
1048 document_interface_selection_delete (DocumentInterface *object, GError **error)
1050     //sp_selection_delete (object->desk);
1051     return dbus_call_verb (object, SP_VERB_EDIT_DELETE, error);
1054 gboolean
1055 document_interface_selection_clear (DocumentInterface *object, GError **error)
1057     sp_desktop_selection(object->desk)->clear();
1058     return TRUE;
1061 gboolean
1062 document_interface_select_all (DocumentInterface *object, GError **error)
1064     //sp_edit_select_all (object->desk);
1065     return dbus_call_verb (object, SP_VERB_EDIT_SELECT_ALL, error);
1068 gboolean
1069 document_interface_select_all_in_all_layers(DocumentInterface *object, 
1070                                             GError **error)
1072     //sp_edit_select_all_in_all_layers (object->desk);
1073     return dbus_call_verb (object, SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS, error);
1076 gboolean
1077 document_interface_selection_box (DocumentInterface *object, int x, int y,
1078                                   int x2, int y2, gboolean replace, 
1079                                   GError **error)
1081     //FIXME: implement.
1082     return FALSE;
1085 gboolean
1086 document_interface_selection_invert (DocumentInterface *object, GError **error)
1088     //sp_edit_invert (object->desk);
1089     return dbus_call_verb (object, SP_VERB_EDIT_INVERT, error);
1092 gboolean
1093 document_interface_selection_group (DocumentInterface *object, GError **error)
1095     //sp_selection_group (object->desk);
1096     return dbus_call_verb (object, SP_VERB_SELECTION_GROUP, error);
1098 gboolean
1099 document_interface_selection_ungroup (DocumentInterface *object, GError **error)
1101     //sp_selection_ungroup (object->desk);
1102     return dbus_call_verb (object, SP_VERB_SELECTION_UNGROUP, error);
1104  
1105 gboolean
1106 document_interface_selection_cut (DocumentInterface *object, GError **error)
1108     //desktop_ensure_active (object->desk);
1109     //sp_selection_cut (object->desk);
1110     return dbus_call_verb (object, SP_VERB_EDIT_CUT, error);
1113 gboolean
1114 document_interface_selection_copy (DocumentInterface *object, GError **error)
1116     //desktop_ensure_active (object->desk);
1117     //sp_selection_copy ();
1118     return dbus_call_verb (object, SP_VERB_EDIT_COPY, error);
1120 /*
1121 gboolean
1122 document_interface_selection_paste (DocumentInterface *object, GError **error)
1124     desktop_ensure_active (object->desk);
1125                     if (!object->updates)
1126                     document_interface_pause_updates (object, error);
1127     sp_selection_paste (object->desk, TRUE);
1128                     if (!object->updates)
1129                     document_interface_pause_updates (object, error);
1130     return TRUE;
1131     //return dbus_call_verb (object, SP_VERB_EDIT_PASTE, error);
1133 */
1134 gboolean
1135 document_interface_selection_paste (DocumentInterface *object, GError **error)
1137     return dbus_call_verb (object, SP_VERB_EDIT_PASTE, error);
1140 gboolean
1141 document_interface_selection_scale (DocumentInterface *object, gdouble grow, GError **error)
1143     Inkscape::Selection *selection = sp_desktop_selection(object->desk);
1144     if (!selection)
1145     {
1146         return FALSE;
1147     }     
1148     sp_selection_scale (selection, grow);
1149     return TRUE;
1152 gboolean
1153 document_interface_selection_move (DocumentInterface *object, gdouble x, gdouble y, GError **error)
1155     sp_selection_move (object->desk, x, 0 - y); //switching coordinate systems.
1156     return TRUE;
1159 gboolean
1160 document_interface_selection_move_to (DocumentInterface *object, gdouble x, gdouble y, GError **error)
1162     Inkscape::Selection * sel = sp_desktop_selection(object->desk);
1164     Geom::OptRect sel_bbox = sel->bounds();
1165     if (sel_bbox) {
1166         Geom::Point m( x - selection_get_center_x(sel) , 0 - (y - selection_get_center_y(sel)) );
1167         sp_selection_move_relative(sel, m, true);
1168     }
1169     return TRUE;
1172 //FIXME: does not paste in new layer.
1173 // This needs to use lower level cut_impl and paste_impl (messy)
1174 // See the built-in sp_selection_to_next_layer and duplicate.
1175 gboolean 
1176 document_interface_selection_move_to_layer (DocumentInterface *object,
1177                                             gchar *layerstr, GError **error)
1179     SPDesktop * dt = object->desk;
1181     Inkscape::Selection *selection = sp_desktop_selection(dt);
1183     // check if something is selected
1184     if (selection->isEmpty())
1185         return FALSE;
1187     SPObject *next = get_object_by_name(object->desk, layerstr, error);
1188     
1189     if (!next)
1190         return FALSE;
1192     if (strcmp("layer", (next->repr)->attribute("inkscape:groupmode")) == 0) {
1194         sp_selection_cut(dt);
1196         dt->setCurrentLayer(next);
1198         sp_selection_paste(dt, TRUE);
1199         }
1200     return TRUE;
1203 GArray *
1204 document_interface_selection_get_center (DocumentInterface *object)
1206     Inkscape::Selection * sel = sp_desktop_selection(object->desk);
1208     if (sel) 
1209     {
1210         gdouble x = selection_get_center_x(sel);
1211         gdouble y = selection_get_center_y(sel);
1212         GArray * intArr = g_array_new (TRUE, TRUE, sizeof(double));
1214         g_array_append_val (intArr, x);
1215         g_array_append_val (intArr, y);
1216         return intArr;
1217     }
1219     return NULL;
1222 gboolean 
1223 document_interface_selection_to_path (DocumentInterface *object, GError **error)
1225     return dbus_call_verb (object, SP_VERB_OBJECT_TO_CURVE, error);    
1229 gchar *
1230 document_interface_selection_combine (DocumentInterface *object, gchar *cmd,
1231                                       GError **error)
1233     if (strcmp(cmd, "union") == 0)
1234         dbus_call_verb (object, SP_VERB_SELECTION_UNION, error);
1235     else if (strcmp(cmd, "intersection") == 0)
1236         dbus_call_verb (object, SP_VERB_SELECTION_INTERSECT, error);
1237     else if (strcmp(cmd, "difference") == 0)
1238         dbus_call_verb (object, SP_VERB_SELECTION_DIFF, error);
1239     else if (strcmp(cmd, "exclusion") == 0)
1240         dbus_call_verb (object, SP_VERB_SELECTION_SYMDIFF, error);
1241     else
1242         return NULL;
1244     if (sp_desktop_selection(object->desk)->singleRepr() != NULL)
1245         return g_strdup((sp_desktop_selection(object->desk)->singleRepr())->attribute("id"));
1246     return NULL;
1249 gboolean
1250 document_interface_selection_divide (DocumentInterface *object, char ***out, GError **error)
1252     dbus_call_verb (object, SP_VERB_SELECTION_CUT, error);
1254     return document_interface_selection_get (object, out, error);
1257 gboolean
1258 document_interface_selection_change_level (DocumentInterface *object, gchar *cmd,
1259                                       GError **error)
1261     if (strcmp(cmd, "raise") == 0)
1262         return dbus_call_verb (object, SP_VERB_SELECTION_RAISE, error);
1263     if (strcmp(cmd, "lower") == 0)
1264         return dbus_call_verb (object, SP_VERB_SELECTION_LOWER, error);
1265     if ((strcmp(cmd, "to_top") == 0) || (strcmp(cmd, "to_front") == 0))
1266         return dbus_call_verb (object, SP_VERB_SELECTION_TO_FRONT, error);
1267     if ((strcmp(cmd, "to_bottom") == 0) || (strcmp(cmd, "to_back") == 0))
1268         return dbus_call_verb (object, SP_VERB_SELECTION_TO_BACK, error);
1269     return TRUE;
1272 /****************************************************************************
1273      LAYER FUNCTIONS
1274 ****************************************************************************/
1276 gchar *
1277 document_interface_layer_new (DocumentInterface *object, GError **error)
1279     SPDesktop * dt = object->desk;
1280     SPObject *new_layer = Inkscape::create_layer(dt->currentRoot(), dt->currentLayer(), Inkscape::LPOS_BELOW);
1281     dt->setCurrentLayer(new_layer);
1282     return g_strdup(get_name_from_object (new_layer));
1285 gboolean 
1286 document_interface_layer_set (DocumentInterface *object,
1287                               gchar *layerstr, GError **error)
1289     SPObject * obj = get_object_by_name (object->desk, layerstr, error);
1290     
1291     if (!obj)
1292         return FALSE;
1293         
1294     object->desk->setCurrentLayer (obj);
1295     return TRUE;
1298 gchar **
1299 document_interface_layer_get_all (DocumentInterface *object)
1301     //FIXME: implement.
1302     return NULL;
1305 gboolean 
1306 document_interface_layer_change_level (DocumentInterface *object,
1307                                        gchar *cmd, GError **error)
1309     if (strcmp(cmd, "raise") == 0)
1310         return dbus_call_verb (object, SP_VERB_LAYER_RAISE, error);
1311     if (strcmp(cmd, "lower") == 0)
1312         return dbus_call_verb (object, SP_VERB_LAYER_LOWER, error);
1313     if ((strcmp(cmd, "to_top") == 0) || (strcmp(cmd, "to_front") == 0))
1314         return dbus_call_verb (object, SP_VERB_LAYER_TO_TOP, error);
1315     if ((strcmp(cmd, "to_bottom") == 0) || (strcmp(cmd, "to_back") == 0))
1316         return dbus_call_verb (object, SP_VERB_LAYER_TO_BOTTOM, error);
1317     return TRUE;
1320 gboolean 
1321 document_interface_layer_next (DocumentInterface *object, GError **error)
1323     return dbus_call_verb (object, SP_VERB_LAYER_NEXT, error);
1326 gboolean 
1327 document_interface_layer_previous (DocumentInterface *object, GError **error)
1329     return dbus_call_verb (object, SP_VERB_LAYER_PREV, error);