Code

DBUS. Patch for Bug #696062, dbus builds no more.
[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" // getReprDoc()
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 "display/sp-canvas.h" //text
57 //#include "2geom/svg-path-parser.h" //get_node_coordinates
59 /****************************************************************************
60      HELPER / SHORTCUT FUNCTIONS
61 ****************************************************************************/
63 /* 
64  * This function or the one below it translates the user input for an object
65  * into Inkscapes internal representation.  It is called by almost every
66  * method so it should be as fast as possible.
67  *
68  * (eg turns "rect2234" to an SPObject or Inkscape::XML::Node)
69  *
70  * If the internal representation changes (No more 'id' attributes) this is the
71  * place to adjust things.
72  */
73 Inkscape::XML::Node *
74 get_repr_by_name (SPDesktop *desk, gchar *name, GError **error)
75 {
76     /* ALTERNATIVE (is this faster if only repr is needed?)
77     Inkscape::XML::Node *node = sp_repr_lookup_name((doc->root)->repr, name);
78     */
79   Inkscape::XML::Node * node = sp_desktop_document(desk)->getObjectById(name)->getRepr();
80     if (!node)
81     {
82         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name);
83         return NULL;
84     }
85     return node;
86 }
88 /* 
89  * See comment for get_repr_by_name, above.
90  */
91 SPObject *
92 get_object_by_name (SPDesktop *desk, gchar *name, GError **error)
93 {
94     SPObject * obj = sp_desktop_document(desk)->getObjectById(name);
95     if (!obj)
96     {
97         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name);
98         return NULL;
99     }
100     return obj;
103 /*
104  * Tests for NULL strings and throws an appropriate error.
105  * Every method that takes a string parameter (other than the 
106  * name of an object, that's tested seperatly) should call this.
107  */
108 gboolean
109 dbus_check_string (gchar *string, GError ** error, const gchar * errorstr)
111     if (string == NULL)
112     {
113         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "%s", errorstr);
114         return FALSE;
115     }
116     return TRUE;
119 /* 
120  * This is used to return object values to the user
121  */
122 const gchar *
123 get_name_from_object (SPObject * obj)
125   return obj->getRepr()->attribute("id"); 
128 /*
129  * Some verbs (cut, paste) only work on the active layer.
130  * This makes sure that the document that is about to recive a command is active.
131  */
132 void
133 desktop_ensure_active (SPDesktop* desk) {
134     if (desk != SP_ACTIVE_DESKTOP)
135         inkscape_activate_desktop (desk);
136     return;
139 gdouble
140 selection_get_center_x (Inkscape::Selection *sel){
141     NRRect *box = g_new(NRRect, 1);;
142     box = sel->boundsInDocument(box);
143     return box->x0 + ((box->x1 - box->x0)/2);
146 gdouble
147 selection_get_center_y (Inkscape::Selection *sel){
148     NRRect *box = g_new(NRRect, 1);;
149     box = sel->boundsInDocument(box);
150     return box->y0 + ((box->y1 - box->y0)/2);
153 /* 
154  * This function is used along with selection_restore to
155  * take advantage of functionality provided by a selection
156  * for a single object.
157  *
158  * It saves the current selection and sets the selection to 
159  * the object specified.  Any selection verb can be used on the
160  * object and then selection_restore is called, restoring the 
161  * original selection.
162  *
163  * This should be mostly transparent to the user who need never
164  * know we never bothered to implement it seperatly.  Although
165  * they might see the selection box flicker if used in a loop.
166  */
167 const GSList *
168 selection_swap(SPDesktop *desk, gchar *name, GError **error)
170     Inkscape::Selection *sel = sp_desktop_selection(desk);
171     const GSList *oldsel = g_slist_copy((GSList *)sel->list());
172     
173     sel->set(get_object_by_name(desk, name, error));
174     return oldsel;
177 /*
178  * See selection_swap, above
179  */
180 void
181 selection_restore(SPDesktop *desk, const GSList * oldsel)
183     Inkscape::Selection *sel = sp_desktop_selection(desk);
184     sel->setList(oldsel);
187 /*
188  * Shortcut for creating a Node.
189  */
190 Inkscape::XML::Node *
191 dbus_create_node (SPDesktop *desk, const gchar *type)
193     SPDocument * doc = sp_desktop_document (desk);
194     Inkscape::XML::Document *xml_doc = doc->getReprDoc();
196     return xml_doc->createElement(type);
199 /*
200  * Called by the shape creation functions.  Gets the default style for the doc
201  * or sets it arbitrarily if none.
202  *
203  * There is probably a better way to do this (use the shape tools default styles)
204  * but I'm not sure how.
205  */
206 gchar *
207 finish_create_shape (DocumentInterface *object, GError **error, Inkscape::XML::Node *newNode, gchar *desc)
210     SPCSSAttr *style = sp_desktop_get_style(object->desk, TRUE);
211     
212     if (style) {
213         newNode->setAttribute("style", sp_repr_css_write_string(style), TRUE);
214     }
215     else {
216         newNode->setAttribute("style", "fill:#0000ff;fill-opacity:1;stroke:#c900b9;stroke-width:0;stroke-miterlimit:0;stroke-opacity:1;stroke-dasharray:none", TRUE);
217     }
219     object->desk->currentLayer()->appendChildRepr(newNode);
220     object->desk->currentLayer()->updateRepr();
222     if (object->updates)
224       Inkscape::DocumentUndo::done(sp_desktop_document(object->desk),  0, (gchar *)desc);
225     //else
226         //document_interface_pause_updates(object, error);
228     return strdup(newNode->attribute("id"));
231 /*
232  * This is the code used internally to call all the verbs.
233  *
234  * It handles error reporting and update pausing (which needs some work.)
235  * This is a good place to improve efficiency as it is called a lot.
236  *
237  * document_interface_call_verb is similar but is called by the user.
238  */
239 gboolean
240 dbus_call_verb (DocumentInterface *object, int verbid, GError **error)
241 {    
242     SPDesktop *desk2 = object->desk;
243     desktop_ensure_active (desk2);
244     
245     if ( desk2 ) {
246         Inkscape::Verb *verb = Inkscape::Verb::get( verbid );
247         if ( verb ) {
248             SPAction *action = verb->get_action(desk2);
249             if ( action ) {
250                 //if (!object->updates)
251                     //document_interface_pause_updates (object, error);
252                 sp_action_perform( action, NULL );
253                 if (object->updates)
254                     Inkscape::DocumentUndo::done(sp_desktop_document(desk2),  verb->get_code(), g_strdup(verb->get_tip()));
255                 //if (!object->updates)
256                     //document_interface_pause_updates (object, error);
257                 return TRUE;
258             }
259         }
260     }
261     g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb failed to execute");
262     return FALSE;
265 /****************************************************************************
266      DOCUMENT INTERFACE CLASS STUFF
267 ****************************************************************************/
269 G_DEFINE_TYPE(DocumentInterface, document_interface, G_TYPE_OBJECT)
271 static void
272 document_interface_finalize (GObject *object)
274         G_OBJECT_CLASS (document_interface_parent_class)->finalize (object);
278 static void
279 document_interface_class_init (DocumentInterfaceClass *klass)
281         GObjectClass *object_class;
282         object_class = G_OBJECT_CLASS (klass);
283         object_class->finalize = document_interface_finalize;
286 static void
287 document_interface_init (DocumentInterface *object)
289         object->desk = NULL;
293 DocumentInterface *
294 document_interface_new (void)
296         return (DocumentInterface*)g_object_new (TYPE_DOCUMENT_INTERFACE, NULL);
299 /* 
300  * Error stuff...
301  *
302  * To add a new error type, edit here and in the .h InkscapeError enum.
303  */
304 GQuark
305 inkscape_error_quark (void)
307   static GQuark quark = 0;
308   if (!quark)
309     quark = g_quark_from_static_string ("inkscape_error");
311   return quark;
314 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
316 GType
317 inkscape_error_get_type (void)
319         static GType etype = 0;
321         if (etype == 0)
322         {
323                 static const GEnumValue values[] =
324                 {
326                         ENUM_ENTRY (INKSCAPE_ERROR_SELECTION, "Incompatible_Selection"),
327                         ENUM_ENTRY (INKSCAPE_ERROR_OBJECT, "Incompatible_Object"),
328                         ENUM_ENTRY (INKSCAPE_ERROR_VERB, "Failed_Verb"),
329                         ENUM_ENTRY (INKSCAPE_ERROR_OTHER, "Generic_Error"),
330                         { 0, 0, 0 }
331                 };
333                 etype = g_enum_register_static ("InkscapeError", values);
334         }
336         return etype;
339 /****************************************************************************
340      MISC FUNCTIONS
341 ****************************************************************************/
343 gboolean
344 document_interface_delete_all (DocumentInterface *object, GError **error)
346     sp_edit_clear_all (object->desk);
347     return TRUE;
350 gboolean
351 document_interface_call_verb (DocumentInterface *object, gchar *verbid, GError **error)
353     SPDesktop *desk2 = object->desk;
354     desktop_ensure_active (object->desk);
355     if ( desk2 ) {
356         Inkscape::Verb *verb = Inkscape::Verb::getbyid( verbid );
357         if ( verb ) {
358             SPAction *action = verb->get_action(desk2);
359             if ( action ) {
360                 sp_action_perform( action, NULL );
361                 if (object->updates) {
362                     Inkscape::DocumentUndo::done(sp_desktop_document(desk2),  verb->get_code(), g_strdup(verb->get_tip()));
363                 }
364             }
365         }
366     }
367     g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb '%s' failed to execute or was not found.", verbid);
368     return FALSE;
372 /****************************************************************************
373      CREATION FUNCTIONS
374 ****************************************************************************/
376 gchar* 
377 document_interface_rectangle (DocumentInterface *object, int x, int y, 
378                               int width, int height, GError **error)
382     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:rect");
383     sp_repr_set_int(newNode, "x", x);  //could also use newNode->setAttribute()
384     sp_repr_set_int(newNode, "y", y);
385     sp_repr_set_int(newNode, "width", width);
386     sp_repr_set_int(newNode, "height", height);
387     return finish_create_shape (object, error, newNode, (gchar *)"create rectangle");
390 gchar*
391 document_interface_ellipse_center (DocumentInterface *object, int cx, int cy, 
392                                    int rx, int ry, GError **error)
394     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
395     newNode->setAttribute("sodipodi:type", "arc");
396     sp_repr_set_int(newNode, "sodipodi:cx", cx);
397     sp_repr_set_int(newNode, "sodipodi:cy", cy);
398     sp_repr_set_int(newNode, "sodipodi:rx", rx);
399     sp_repr_set_int(newNode, "sodipodi:ry", ry);
400     return finish_create_shape (object, error, newNode, (gchar *)"create circle");
403 gchar* 
404 document_interface_polygon (DocumentInterface *object, int cx, int cy, 
405                             int radius, int rotation, int sides, 
406                             GError **error)
408     gdouble rot = ((rotation / 180.0) * 3.14159265) - ( 3.14159265 / 2.0);
409     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
410     newNode->setAttribute("inkscape:flatsided", "true");
411     newNode->setAttribute("sodipodi:type", "star");
412     sp_repr_set_int(newNode, "sodipodi:cx", cx);
413     sp_repr_set_int(newNode, "sodipodi:cy", cy);
414     sp_repr_set_int(newNode, "sodipodi:r1", radius);
415     sp_repr_set_int(newNode, "sodipodi:r2", radius);
416     sp_repr_set_int(newNode, "sodipodi:sides", sides);
417     sp_repr_set_int(newNode, "inkscape:randomized", 0);
418     sp_repr_set_svg_double(newNode, "sodipodi:arg1", rot);
419     sp_repr_set_svg_double(newNode, "sodipodi:arg2", rot);
420     sp_repr_set_svg_double(newNode, "inkscape:rounded", 0);
422     return finish_create_shape (object, error, newNode, (gchar *)"create polygon");
425 gchar* 
426 document_interface_star (DocumentInterface *object, int cx, int cy, 
427                          int r1, int r2, int sides, gdouble rounded,
428                          gdouble arg1, gdouble arg2, GError **error)
430     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
431     newNode->setAttribute("inkscape:flatsided", "false");
432     newNode->setAttribute("sodipodi:type", "star");
433     sp_repr_set_int(newNode, "sodipodi:cx", cx);
434     sp_repr_set_int(newNode, "sodipodi:cy", cy);
435     sp_repr_set_int(newNode, "sodipodi:r1", r1);
436     sp_repr_set_int(newNode, "sodipodi:r2", r2);
437     sp_repr_set_int(newNode, "sodipodi:sides", sides);
438     sp_repr_set_int(newNode, "inkscape:randomized", 0);
439     sp_repr_set_svg_double(newNode, "sodipodi:arg1", arg1);
440     sp_repr_set_svg_double(newNode, "sodipodi:arg2", arg2);
441     sp_repr_set_svg_double(newNode, "inkscape:rounded", rounded);
443     return finish_create_shape (object, error, newNode, (gchar *)"create star");
446 gchar* 
447 document_interface_ellipse (DocumentInterface *object, int x, int y, 
448                             int width, int height, GError **error)
450     int rx = width/2;
451     int ry = height/2;
452     return document_interface_ellipse_center (object, x+rx, y+ry, rx, ry, error);
455 gchar* 
456 document_interface_line (DocumentInterface *object, int x, int y, 
457                               int x2, int y2, GError **error)
459     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
460     std::stringstream out;
461     // Not sure why this works.
462         out << "m " << x << "," << y << " " << x2 - x << "," << y2 - y;
463     newNode->setAttribute("d", out.str().c_str());
464     return finish_create_shape (object, error, newNode, (gchar *)"create line");
467 gchar* 
468 document_interface_spiral (DocumentInterface *object, int cx, int cy, 
469                            int r, int revolutions, GError **error)
471     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
472     newNode->setAttribute("sodipodi:type", "spiral");
473     sp_repr_set_int(newNode, "sodipodi:cx", cx);
474     sp_repr_set_int(newNode, "sodipodi:cy", cy);
475     sp_repr_set_int(newNode, "sodipodi:radius", r);
476     sp_repr_set_int(newNode, "sodipodi:revolution", revolutions);
477     sp_repr_set_int(newNode, "sodipodi:t0", 0);
478     sp_repr_set_int(newNode, "sodipodi:argument", 0);
479     sp_repr_set_int(newNode, "sodipodi:expansion", 1);
480     gchar * retval = finish_create_shape (object, error, newNode, (gchar *)"create spiral");
481     //Makes sure there is no fill for spirals by default.
482     gchar* newString = g_strconcat(newNode->attribute("style"), ";fill:none", NULL);
483     newNode->setAttribute("style", newString);
484     g_free(newString);
485     return retval;
488 gboolean
489 document_interface_text (DocumentInterface *object, int x, int y, gchar *text, GError **error)
491     //FIXME: Not selectable (aka broken).  Needs to be rewritten completely.
493     SPDesktop *desktop = object->desk;
494     SPCanvasText * canvas_text = (SPCanvasText *) sp_canvastext_new(sp_desktop_tempgroup(desktop), desktop, Geom::Point(0,0), "");
495     sp_canvastext_set_text (canvas_text, text);
496     sp_canvastext_set_coords (canvas_text, x, y);
498     return TRUE;
501 gchar *
502 document_interface_image (DocumentInterface *object, int x, int y, gchar *filename, GError **error)
504     gchar * uri = g_filename_to_uri (filename, FALSE, error);
505     if (!uri)
506         return FALSE;
507     
508     Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:image");
509     sp_repr_set_int(newNode, "x", x);
510     sp_repr_set_int(newNode, "y", y);
511     newNode->setAttribute("xlink:href", uri);
512     
513     object->desk->currentLayer()->appendChildRepr(newNode);
514     object->desk->currentLayer()->updateRepr();
516     if (object->updates)
517         Inkscape::DocumentUndo::done(sp_desktop_document(object->desk),  0, "Imported bitmap.");
519     //g_free(uri);
520     return strdup(newNode->attribute("id"));
523 gchar *document_interface_node (DocumentInterface *object, gchar *type, GError **error)
525     SPDocument * doc = sp_desktop_document (object->desk);
526     Inkscape::XML::Document *xml_doc = doc->getReprDoc();
528     Inkscape::XML::Node *newNode =  xml_doc->createElement(type);
530     object->desk->currentLayer()->appendChildRepr(newNode);
531     object->desk->currentLayer()->updateRepr();
533     if (object->updates)
534         Inkscape::DocumentUndo::done(sp_desktop_document(object->desk),  0, (gchar *)"created empty node");
535     //else
536         //document_interface_pause_updates(object, error);
538     return strdup(newNode->attribute("id"));
541 /****************************************************************************
542      ENVIORNMENT FUNCTIONS
543 ****************************************************************************/
544 gdouble
545 document_interface_document_get_width (DocumentInterface *object)
547   return sp_desktop_document(object->desk)->getWidth();
550 gdouble
551 document_interface_document_get_height (DocumentInterface *object)
553   return sp_desktop_document(object->desk)->getHeight();
556 gchar *
557 document_interface_document_get_css (DocumentInterface *object, GError **error)
559     SPCSSAttr *current = (object->desk)->current;
560     return sp_repr_css_write_string(current);
563 gboolean 
564 document_interface_document_merge_css (DocumentInterface *object,
565                                        gchar *stylestring, GError **error)
567     SPCSSAttr * style = sp_repr_css_attr_new();
568     sp_repr_css_attr_add_from_string (style, stylestring);
569     sp_desktop_set_style (object->desk, style);
570     return TRUE;
573 gboolean 
574 document_interface_document_set_css (DocumentInterface *object,
575                                      gchar *stylestring, GError **error)
577     SPCSSAttr * style = sp_repr_css_attr_new();
578     sp_repr_css_attr_add_from_string (style, stylestring);
579     //Memory leak?
580     object->desk->current = style;
581     return TRUE;
584 gboolean 
585 document_interface_document_resize_to_fit_selection (DocumentInterface *object,
586                                                      GError **error)
588     return dbus_call_verb (object, SP_VERB_FIT_CANVAS_TO_SELECTION, error);
589     return TRUE;
592 /****************************************************************************
593      OBJECT FUNCTIONS
594 ****************************************************************************/
596 gboolean
597 document_interface_set_attribute (DocumentInterface *object, char *shape, 
598                                   char *attribute, char *newval, GError **error)
600     Inkscape::XML::Node *newNode = get_repr_by_name(object->desk, shape, error);
602     /* ALTERNATIVE (is this faster?)
603     Inkscape::XML::Node *newnode = sp_repr_lookup_name((doc->root)->repr, name);
604     */
605     if (!dbus_check_string(newval, error, "New value string was empty."))
606         return FALSE;
607         
608     if (!newNode)
609         return FALSE;
610         
611     newNode->setAttribute(attribute, newval, TRUE);
612     return TRUE;
615 gboolean 
616 document_interface_set_int_attribute (DocumentInterface *object, 
617                                       char *shape, char *attribute, 
618                                       int newval, GError **error)
620     Inkscape::XML::Node *newNode = get_repr_by_name (object->desk, shape, error);
621     if (!newNode)
622         return FALSE;
623         
624     sp_repr_set_int (newNode, attribute, newval);
625     return TRUE;
629 gboolean
630 document_interface_set_double_attribute (DocumentInterface *object, 
631                                          char *shape, char *attribute, 
632                                          double newval, GError **error)
634     Inkscape::XML::Node *newNode = get_repr_by_name (object->desk, shape, error);
635     
636     if (!dbus_check_string (attribute, error, "New value string was empty."))
637         return FALSE;
638     if (!newNode)
639         return FALSE;
640     
641     sp_repr_set_svg_double (newNode, attribute, newval);
642     return TRUE;
645 gchar *
646 document_interface_get_attribute (DocumentInterface *object, char *shape, 
647                                   char *attribute, GError **error)
649     Inkscape::XML::Node *newNode = get_repr_by_name(object->desk, shape, error);
651     if (!dbus_check_string (attribute, error, "Attribute name empty."))
652         return NULL;
653     if (!newNode)
654         return NULL;
655         
656     return g_strdup(newNode->attribute(attribute));
659 gboolean
660 document_interface_move (DocumentInterface *object, gchar *name, gdouble x, 
661                          gdouble y, GError **error)
663     const GSList *oldsel = selection_swap(object->desk, name, error);
664     if (!oldsel)
665         return FALSE;
666     sp_selection_move (object->desk, x, 0 - y);
667     selection_restore(object->desk, oldsel);
668     return TRUE;
671 gboolean
672 document_interface_move_to (DocumentInterface *object, gchar *name, gdouble x, 
673                          gdouble y, GError **error)
675     const GSList *oldsel = selection_swap(object->desk, name, error);
676     if (!oldsel)
677         return FALSE;
678     Inkscape::Selection * sel = sp_desktop_selection(object->desk);
679     sp_selection_move (object->desk, x - selection_get_center_x(sel),
680                                      0 - (y - selection_get_center_y(sel)));
681     selection_restore(object->desk, oldsel);
682     return TRUE;
685 gboolean
686 document_interface_object_to_path (DocumentInterface *object, 
687                                    char *shape, GError **error)
689     const GSList *oldsel = selection_swap(object->desk, shape, error);
690     if (!oldsel)
691         return FALSE;
692     dbus_call_verb (object, SP_VERB_OBJECT_TO_CURVE, error);
693     selection_restore(object->desk, oldsel);
694     return TRUE;
697 gchar *
698 document_interface_get_path (DocumentInterface *object, char *pathname, GError **error)
700     Inkscape::XML::Node *node = get_repr_by_name(object->desk, pathname, error);
701     
702     if (!node)
703         return NULL;
704         
705     if (node->attribute("d") == NULL)
706     {
707         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object is not a path.");
708         return NULL;
709     }
710     return strdup(node->attribute("d"));
713 gboolean 
714 document_interface_transform (DocumentInterface *object, gchar *shape,
715                               gchar *transformstr, GError **error)
717     //FIXME: This should merge transformations.
718     gchar trans[] = "transform";
719     document_interface_set_attribute (object, shape, trans, transformstr, error);
720     return TRUE;
723 gchar *
724 document_interface_get_css (DocumentInterface *object, gchar *shape,
725                             GError **error)
727     gchar style[] = "style";
728     return document_interface_get_attribute (object, shape, style, error);
731 gboolean 
732 document_interface_modify_css (DocumentInterface *object, gchar *shape,
733                                gchar *cssattrb, gchar *newval, GError **error)
735     // Doesn't like non-variable strings for some reason.
736     gchar style[] = "style";
737     Inkscape::XML::Node *node = get_repr_by_name(object->desk, shape, error);
738     
739     if (!dbus_check_string (cssattrb, error, "Attribute string empty."))
740         return FALSE;
741     if (!node)
742         return FALSE;
743         
744     SPCSSAttr * oldstyle = sp_repr_css_attr (node, style);
745     sp_repr_css_set_property(oldstyle, cssattrb, newval);
746     node->setAttribute (style, sp_repr_css_write_string (oldstyle), TRUE);
747     return TRUE;
750 gboolean 
751 document_interface_merge_css (DocumentInterface *object, gchar *shape,
752                                gchar *stylestring, GError **error)
754     gchar style[] = "style";
755     
756     Inkscape::XML::Node *node = get_repr_by_name(object->desk, shape, error);
757     
758     if (!dbus_check_string (stylestring, error, "Style string empty."))
759         return FALSE;
760     if (!node)
761         return FALSE;
762         
763     SPCSSAttr * newstyle = sp_repr_css_attr_new();
764     sp_repr_css_attr_add_from_string (newstyle, stylestring);
766     SPCSSAttr * oldstyle = sp_repr_css_attr (node, style);
768     sp_repr_css_merge(oldstyle, newstyle);
769     node->setAttribute (style, sp_repr_css_write_string (oldstyle), TRUE);
770     return TRUE;
773 gboolean 
774 document_interface_set_color (DocumentInterface *object, gchar *shape,
775                               int r, int g, int b, gboolean fill, GError **error)
777     gchar style[15];
778     if (r<0 || r>255 || g<0 || g>255 || b<0 || b>255)
779     {
780         g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Given (%d,%d,%d).  All values must be between 0-255 inclusive.", r, g, b);
781         return FALSE;
782     }
783     
784     if (fill)
785         snprintf(style, 15, "fill:#%.2x%.2x%.2x", r, g, b);
786     else
787         snprintf(style, 15, "stroke:#%.2x%.2x%.2x", r, g, b);
788     
789     if (strcmp(shape, "document") == 0)
790         return document_interface_document_merge_css (object, style, error);
791     
792     return document_interface_merge_css (object, shape, style, error);
795 gboolean 
796 document_interface_move_to_layer (DocumentInterface *object, gchar *shape, 
797                               gchar *layerstr, GError **error)
799     const GSList *oldsel = selection_swap(object->desk, shape, error);
800     if (!oldsel)
801         return FALSE;
802         
803     document_interface_selection_move_to_layer(object, layerstr, error);
804     selection_restore(object->desk, oldsel);
805     return TRUE;
808 GArray *
809 document_interface_get_node_coordinates (DocumentInterface *object, gchar *shape)
811     //FIXME: Needs lot's of work.
812 /*
813     Inkscape::XML::Node *shapenode = get_repr_by_name (object->desk, shape, error);
814     if (shapenode == NULL || shapenode->attribute("d") == NULL) {
815         return FALSE;
816     }
817     char * path = strdup(shapenode->attribute("d"));
818     printf("PATH: %s\n", path);
819     
820     Geom::parse_svg_path (path);
821     return NULL;
822     */
823     return NULL;
827 /****************************************************************************
828      FILE I/O FUNCTIONS
829 ****************************************************************************/
831 gboolean 
832 document_interface_save (DocumentInterface *object, GError **error)
834     SPDocument * doc = sp_desktop_document(object->desk);
835     printf("1:  %s\n2:  %s\n3:  %s\n", doc->getURI(), doc->getBase(), doc->getName());
836     if (doc->getURI())
837       return document_interface_save_as (object, doc->getURI(), error);
838     return FALSE;
841 gboolean 
842 document_interface_load (DocumentInterface *object, 
843                         gchar *filename, GError **error)
845     desktop_ensure_active (object->desk);
846     const Glib::ustring file(filename);
847     sp_file_open(file, NULL, TRUE, TRUE);
848     if (object->updates)
849         Inkscape::DocumentUndo::done(sp_desktop_document(object->desk),  SP_VERB_FILE_OPEN, "Opened File");
850     return TRUE;
853 gboolean 
854 document_interface_save_as (DocumentInterface *object, 
855                            const gchar *filename, GError **error)
857     SPDocument * doc = sp_desktop_document(object->desk);
858     #ifdef WITH_GNOME_VFS
859     const Glib::ustring file(filename);
860     return file_save_remote(doc, file, NULL, TRUE, TRUE);
861     #endif
862     if (!doc || strlen(filename)<1) //Safety check
863         return false;
865     try {
866         Inkscape::Extension::save(NULL, doc, filename,
867                  false, false, true, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS);
868     } catch (...) {
869         //SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
870         return false;
871     }
873     //SP_ACTIVE_DESKTOP->event_log->rememberFileSave();
874     //SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, "Document saved.");
875     return true;
878 gboolean
879 document_interface_mark_as_unmodified (DocumentInterface *object, GError **error)
881     SPDocument * doc = sp_desktop_document(object->desk);
882     if (doc)
883         doc->modified_since_save = FALSE;
884     return TRUE;
887 /*
888 gboolean 
889 document_interface_print_to_file (DocumentInterface *object, GError **error)
891     SPDocument * doc = sp_desktop_document(object->desk);
892     sp_print_document_to_file (doc, g_strdup("/home/soren/test.pdf"));
893                                
894     return TRUE;
896 */
897 /****************************************************************************
898      PROGRAM CONTROL FUNCTIONS
899 ****************************************************************************/
901 gboolean
902 document_interface_close (DocumentInterface *object, GError **error)
904     return dbus_call_verb (object, SP_VERB_FILE_CLOSE_VIEW, error);
907 gboolean
908 document_interface_exit (DocumentInterface *object, GError **error)
910     return dbus_call_verb (object, SP_VERB_FILE_QUIT, error);
913 gboolean
914 document_interface_undo (DocumentInterface *object, GError **error)
916     return dbus_call_verb (object, SP_VERB_EDIT_UNDO, error);
919 gboolean
920 document_interface_redo (DocumentInterface *object, GError **error)
922     return dbus_call_verb (object, SP_VERB_EDIT_REDO, error);
927 /****************************************************************************
928      UPDATE FUNCTIONS 
929      FIXME: This would work better by adding a flag to SPDesktop to prevent
930      updating but that would be very intrusive so for now there is a workaround.
931      Need to make sure it plays well with verbs because they are used so much.
932 ****************************************************************************/
934 void
935 document_interface_pause_updates (DocumentInterface *object, GError **error)
937     object->updates = FALSE;
938     object->desk->canvas->drawing_disabled = 1;
939     //object->desk->canvas->need_redraw = 0;
940     //object->desk->canvas->need_repick = 0;
941     //sp_desktop_document(object->desk)->root->uflags = FALSE;
942     //sp_desktop_document(object->desk)->root->mflags = FALSE;
945 void
946 document_interface_resume_updates (DocumentInterface *object, GError **error)
948     object->updates = TRUE;
949     object->desk->canvas->drawing_disabled = 0;
950     //object->desk->canvas->need_redraw = 1;
951     //object->desk->canvas->need_repick = 1;
952     //sp_desktop_document(object->desk)->root->uflags = TRUE;
953     //sp_desktop_document(object->desk)->root->mflags = TRUE;
954     //sp_desktop_document(object->desk)->_updateDocument();
955     //FIXME: use better verb than rect.
956     Inkscape::DocumentUndo::done(sp_desktop_document(object->desk),  SP_VERB_CONTEXT_RECT, "Multiple actions");
959 void
960 document_interface_update (DocumentInterface *object, GError **error)
962     sp_desktop_document(object->desk)->root->uflags = TRUE;
963     sp_desktop_document(object->desk)->root->mflags = TRUE;
964     object->desk->enableInteraction();
965     sp_desktop_document(object->desk)->_updateDocument();
966     object->desk->disableInteraction();
967     sp_desktop_document(object->desk)->root->uflags = FALSE;
968     sp_desktop_document(object->desk)->root->mflags = FALSE;
969     //Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions");
972 /****************************************************************************
973      SELECTION FUNCTIONS FIXME: use call_verb where appropriate (once update system is tested.)
974 ****************************************************************************/
976 gboolean
977 document_interface_selection_get (DocumentInterface *object, char ***out, GError **error)
979     Inkscape::Selection * sel = sp_desktop_selection(object->desk);
980     GSList const *oldsel = sel->list();
982     int size = g_slist_length((GSList *) oldsel);
984     *out = g_new0 (char *, size + 1);
986     int i = 0;
987     for (GSList const *iter = oldsel; iter != NULL; iter = iter->next) {
988       (*out)[i] = g_strdup(SP_OBJECT(iter->data)->getRepr()->attribute("id"));
989         i++;
990     }
991     (*out)[i] = NULL;
993     return TRUE;
996 gboolean
997 document_interface_selection_add (DocumentInterface *object, char *name, GError **error)
999     SPObject * obj = get_object_by_name(object->desk, name, error);
1000     if (!obj)
1001         return FALSE;
1002     
1003     Inkscape::Selection *selection = sp_desktop_selection(object->desk);
1005     selection->add(obj);
1006     return TRUE;
1009 gboolean
1010 document_interface_selection_add_list (DocumentInterface *object, 
1011                                        char **names, GError **error)
1013     int i;
1014     for (i=0;names[i] != NULL;i++) {
1015         document_interface_selection_add(object, names[i], error);       
1016     }
1017     return TRUE;
1020 gboolean
1021 document_interface_selection_set (DocumentInterface *object, char *name, GError **error)
1023     SPDocument * doc = sp_desktop_document (object->desk);
1024     Inkscape::Selection *selection = sp_desktop_selection(object->desk);
1025     selection->set(doc->getObjectById(name));
1026     return TRUE;
1029 gboolean
1030 document_interface_selection_set_list (DocumentInterface *object, 
1031                                        gchar **names, GError **error)
1033     sp_desktop_selection(object->desk)->clear();
1034     int i;
1035     for (i=0;names[i] != NULL;i++) {
1036         document_interface_selection_add(object, names[i], error);       
1037     }
1038     return TRUE;
1041 gboolean
1042 document_interface_selection_rotate (DocumentInterface *object, int angle, GError **error)
1044     Inkscape::Selection *selection = sp_desktop_selection(object->desk);
1045     sp_selection_rotate(selection, angle);
1046     return TRUE;
1049 gboolean
1050 document_interface_selection_delete (DocumentInterface *object, GError **error)
1052     //sp_selection_delete (object->desk);
1053     return dbus_call_verb (object, SP_VERB_EDIT_DELETE, error);
1056 gboolean
1057 document_interface_selection_clear (DocumentInterface *object, GError **error)
1059     sp_desktop_selection(object->desk)->clear();
1060     return TRUE;
1063 gboolean
1064 document_interface_select_all (DocumentInterface *object, GError **error)
1066     //sp_edit_select_all (object->desk);
1067     return dbus_call_verb (object, SP_VERB_EDIT_SELECT_ALL, error);
1070 gboolean
1071 document_interface_select_all_in_all_layers(DocumentInterface *object, 
1072                                             GError **error)
1074     //sp_edit_select_all_in_all_layers (object->desk);
1075     return dbus_call_verb (object, SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS, error);
1078 gboolean
1079 document_interface_selection_box (DocumentInterface *object, int x, int y,
1080                                   int x2, int y2, gboolean replace, 
1081                                   GError **error)
1083     //FIXME: implement.
1084     return FALSE;
1087 gboolean
1088 document_interface_selection_invert (DocumentInterface *object, GError **error)
1090     //sp_edit_invert (object->desk);
1091     return dbus_call_verb (object, SP_VERB_EDIT_INVERT, error);
1094 gboolean
1095 document_interface_selection_group (DocumentInterface *object, GError **error)
1097     //sp_selection_group (object->desk);
1098     return dbus_call_verb (object, SP_VERB_SELECTION_GROUP, error);
1100 gboolean
1101 document_interface_selection_ungroup (DocumentInterface *object, GError **error)
1103     //sp_selection_ungroup (object->desk);
1104     return dbus_call_verb (object, SP_VERB_SELECTION_UNGROUP, error);
1106  
1107 gboolean
1108 document_interface_selection_cut (DocumentInterface *object, GError **error)
1110     //desktop_ensure_active (object->desk);
1111     //sp_selection_cut (object->desk);
1112     return dbus_call_verb (object, SP_VERB_EDIT_CUT, error);
1115 gboolean
1116 document_interface_selection_copy (DocumentInterface *object, GError **error)
1118     //desktop_ensure_active (object->desk);
1119     //sp_selection_copy ();
1120     return dbus_call_verb (object, SP_VERB_EDIT_COPY, error);
1122 /*
1123 gboolean
1124 document_interface_selection_paste (DocumentInterface *object, GError **error)
1126     desktop_ensure_active (object->desk);
1127                     if (!object->updates)
1128                     document_interface_pause_updates (object, error);
1129     sp_selection_paste (object->desk, TRUE);
1130                     if (!object->updates)
1131                     document_interface_pause_updates (object, error);
1132     return TRUE;
1133     //return dbus_call_verb (object, SP_VERB_EDIT_PASTE, error);
1135 */
1136 gboolean
1137 document_interface_selection_paste (DocumentInterface *object, GError **error)
1139     return dbus_call_verb (object, SP_VERB_EDIT_PASTE, error);
1142 gboolean
1143 document_interface_selection_scale (DocumentInterface *object, gdouble grow, GError **error)
1145     Inkscape::Selection *selection = sp_desktop_selection(object->desk);
1146     if (!selection)
1147     {
1148         return FALSE;
1149     }     
1150     sp_selection_scale (selection, grow);
1151     return TRUE;
1154 gboolean
1155 document_interface_selection_move (DocumentInterface *object, gdouble x, gdouble y, GError **error)
1157     sp_selection_move (object->desk, x, 0 - y); //switching coordinate systems.
1158     return TRUE;
1161 gboolean
1162 document_interface_selection_move_to (DocumentInterface *object, gdouble x, gdouble y, GError **error)
1164     Inkscape::Selection * sel = sp_desktop_selection(object->desk);
1166     Geom::OptRect sel_bbox = sel->bounds();
1167     if (sel_bbox) {
1168         Geom::Point m( x - selection_get_center_x(sel) , 0 - (y - selection_get_center_y(sel)) );
1169         sp_selection_move_relative(sel, m, true);
1170     }
1171     return TRUE;
1174 //FIXME: does not paste in new layer.
1175 // This needs to use lower level cut_impl and paste_impl (messy)
1176 // See the built-in sp_selection_to_next_layer and duplicate.
1177 gboolean 
1178 document_interface_selection_move_to_layer (DocumentInterface *object,
1179                                             gchar *layerstr, GError **error)
1181     SPDesktop * dt = object->desk;
1183     Inkscape::Selection *selection = sp_desktop_selection(dt);
1185     // check if something is selected
1186     if (selection->isEmpty())
1187         return FALSE;
1189     SPObject *next = get_object_by_name(object->desk, layerstr, error);
1190     
1191     if (!next)
1192         return FALSE;
1194     if (strcmp("layer", (next->getRepr())->attribute("inkscape:groupmode")) == 0) {
1196         sp_selection_cut(dt);
1198         dt->setCurrentLayer(next);
1200         sp_selection_paste(dt, TRUE);
1201         }
1202     return TRUE;
1205 GArray *
1206 document_interface_selection_get_center (DocumentInterface *object)
1208     Inkscape::Selection * sel = sp_desktop_selection(object->desk);
1210     if (sel) 
1211     {
1212         gdouble x = selection_get_center_x(sel);
1213         gdouble y = selection_get_center_y(sel);
1214         GArray * intArr = g_array_new (TRUE, TRUE, sizeof(double));
1216         g_array_append_val (intArr, x);
1217         g_array_append_val (intArr, y);
1218         return intArr;
1219     }
1221     return NULL;
1224 gboolean 
1225 document_interface_selection_to_path (DocumentInterface *object, GError **error)
1227     return dbus_call_verb (object, SP_VERB_OBJECT_TO_CURVE, error);    
1231 gchar *
1232 document_interface_selection_combine (DocumentInterface *object, gchar *cmd,
1233                                       GError **error)
1235     if (strcmp(cmd, "union") == 0)
1236         dbus_call_verb (object, SP_VERB_SELECTION_UNION, error);
1237     else if (strcmp(cmd, "intersection") == 0)
1238         dbus_call_verb (object, SP_VERB_SELECTION_INTERSECT, error);
1239     else if (strcmp(cmd, "difference") == 0)
1240         dbus_call_verb (object, SP_VERB_SELECTION_DIFF, error);
1241     else if (strcmp(cmd, "exclusion") == 0)
1242         dbus_call_verb (object, SP_VERB_SELECTION_SYMDIFF, error);
1243     else
1244         return NULL;
1246     if (sp_desktop_selection(object->desk)->singleRepr() != NULL)
1247         return g_strdup((sp_desktop_selection(object->desk)->singleRepr())->attribute("id"));
1248     return NULL;
1251 gboolean
1252 document_interface_selection_divide (DocumentInterface *object, char ***out, GError **error)
1254     dbus_call_verb (object, SP_VERB_SELECTION_CUT, error);
1256     return document_interface_selection_get (object, out, error);
1259 gboolean
1260 document_interface_selection_change_level (DocumentInterface *object, gchar *cmd,
1261                                       GError **error)
1263     if (strcmp(cmd, "raise") == 0)
1264         return dbus_call_verb (object, SP_VERB_SELECTION_RAISE, error);
1265     if (strcmp(cmd, "lower") == 0)
1266         return dbus_call_verb (object, SP_VERB_SELECTION_LOWER, error);
1267     if ((strcmp(cmd, "to_top") == 0) || (strcmp(cmd, "to_front") == 0))
1268         return dbus_call_verb (object, SP_VERB_SELECTION_TO_FRONT, error);
1269     if ((strcmp(cmd, "to_bottom") == 0) || (strcmp(cmd, "to_back") == 0))
1270         return dbus_call_verb (object, SP_VERB_SELECTION_TO_BACK, error);
1271     return TRUE;
1274 /****************************************************************************
1275      LAYER FUNCTIONS
1276 ****************************************************************************/
1278 gchar *
1279 document_interface_layer_new (DocumentInterface *object, GError **error)
1281     SPDesktop * dt = object->desk;
1282     SPObject *new_layer = Inkscape::create_layer(dt->currentRoot(), dt->currentLayer(), Inkscape::LPOS_BELOW);
1283     dt->setCurrentLayer(new_layer);
1284     return g_strdup(get_name_from_object (new_layer));
1287 gboolean 
1288 document_interface_layer_set (DocumentInterface *object,
1289                               gchar *layerstr, GError **error)
1291     SPObject * obj = get_object_by_name (object->desk, layerstr, error);
1292     
1293     if (!obj)
1294         return FALSE;
1295         
1296     object->desk->setCurrentLayer (obj);
1297     return TRUE;
1300 gchar **
1301 document_interface_layer_get_all (DocumentInterface *object)
1303     //FIXME: implement.
1304     return NULL;
1307 gboolean 
1308 document_interface_layer_change_level (DocumentInterface *object,
1309                                        gchar *cmd, GError **error)
1311     if (strcmp(cmd, "raise") == 0)
1312         return dbus_call_verb (object, SP_VERB_LAYER_RAISE, error);
1313     if (strcmp(cmd, "lower") == 0)
1314         return dbus_call_verb (object, SP_VERB_LAYER_LOWER, error);
1315     if ((strcmp(cmd, "to_top") == 0) || (strcmp(cmd, "to_front") == 0))
1316         return dbus_call_verb (object, SP_VERB_LAYER_TO_TOP, error);
1317     if ((strcmp(cmd, "to_bottom") == 0) || (strcmp(cmd, "to_back") == 0))
1318         return dbus_call_verb (object, SP_VERB_LAYER_TO_BOTTOM, error);
1319     return TRUE;
1322 gboolean 
1323 document_interface_layer_next (DocumentInterface *object, GError **error)
1325     return dbus_call_verb (object, SP_VERB_LAYER_NEXT, error);
1328 gboolean 
1329 document_interface_layer_previous (DocumentInterface *object, GError **error)
1331     return dbus_call_verb (object, SP_VERB_LAYER_PREV, error);