document-interface.cpp revision 36bb2154f1627a17c3591eb4d7f89335e8b5dadd
/*
* This is where the implementation of the DBus based document API lives.
* All the methods in here (except in the helper section) are
* designed to be called remotly via DBus. application-interface.cpp
* has the methods used to connect to the bus and get a document instance.
*
* Documentation for these methods is in document-interface.xml
* which is the "gold standard" as to how the interface should work.
*
* Authors:
* Soren Berg <Glimmer07@gmail.com>
*
* Copyright (C) 2009 Soren Berg
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "document-interface.h"
#include <string.h>
#include <dbus/dbus-glib.h>
#include "desktop-handles.h" //sp_desktop_document()
#include "desktop-style.h" //sp_desktop_get_style
#include "display/canvas-text.h" //text
#include "display/sp-canvas.h" //text
#include "document.h" // getReprDoc()
#include "file.h" //IO
#include "inkscape.h" //inkscape_find_desktop_by_dkey, activate desktops
#include "layer-fns.h" //LPOS_BELOW
#include "live_effects/parameter/text.h" //text
#include "print.h" //IO
#include "selection-chemistry.h"// lots of selection functions
#include "selection.h" //selection struct
#include "sp-ellipse.h"
#include "sp-object.h"
#include "sp-root.h"
#include "style.h" //style_write
#include "file.h" //IO
#include "print.h" //IO
#include "live_effects/parameter/text.h" //text
#include "display/canvas-text.h" //text
#include "display/sp-canvas.h" //text
#include "text-editing.h"
#include "verbs.h"
//#include "2geom/svg-path-parser.h" //get_node_coordinates
#include <glib.h>
#include <dbus/dbus-glib.h>
#if 0
#include <libxml/xpathInternals.h>
#endif
enum
{
};
/****************************************************************************
HELPER / SHORTCUT FUNCTIONS
****************************************************************************/
/*
* This function or the one below it translates the user input for an object
* into Inkscapes internal representation. It is called by almost every
* method so it should be as fast as possible.
*
* (eg turns "rect2234" to an SPObject or Inkscape::XML::Node)
*
* If the internal representation changes (No more 'id' attributes) this is the
* place to adjust things.
*/
{
/* ALTERNATIVE (is this faster if only repr is needed?)
Inkscape::XML::Node *node = sp_repr_lookup_name((doc->root)->repr, name);
*/
if (!obj)
{
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name);
return NULL;
}
}
/*
* See comment for get_repr_by_name, above.
*/
SPObject *
{
if (!obj)
{
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name);
return NULL;
}
return obj;
}
/*
* Tests for NULL strings and throws an appropriate error.
* Every method that takes a string parameter (other than the
* name of an object, that's tested seperatly) should call this.
*/
{
{
return FALSE;
}
return TRUE;
}
/*
* This is used to return object values to the user
*/
const gchar *
{
}
/*
* Some verbs (cut, paste) only work on the active layer.
* This makes sure that the document that is about to recive a command is active.
*/
void
if (desk != SP_ACTIVE_DESKTOP)
return;
}
}
}
/*
* This function is used along with selection_restore to
* take advantage of functionality provided by a selection
* for a single object.
*
* It saves the current selection and sets the selection to
* the object specified. Any selection verb can be used on the
* object and then selection_restore is called, restoring the
* original selection.
*
* This should be mostly transparent to the user who need never
* know we never bothered to implement it seperatly. Although
* they might see the selection box flicker if used in a loop.
*/
const GSList *
{
return oldsel;
}
/*
* See selection_swap, above
*/
void
{
}
/*
* Shortcut for creating a Node.
*/
{
}
/*
* Called by the shape creation functions. Gets the default style for the doc
* or sets it arbitrarily if none.
*
* There is probably a better way to do this (use the shape tools default styles)
* but I'm not sure how.
*/
gchar *finish_create_shape (DocumentInterface *object, GError ** /*error*/, Inkscape::XML::Node *newNode, gchar *desc)
{
if (style) {
}
else {
newNode->setAttribute("style", "fill:#0000ff;fill-opacity:1;stroke:#c900b9;stroke-width:0;stroke-miterlimit:0;stroke-opacity:1;stroke-dasharray:none", TRUE);
}
//} else {
//document_interface_pause_updates(object, error);
}
}
/*
* This is the code used internally to call all the verbs.
*
* It handles error reporting and update pausing (which needs some work.)
* This is a good place to improve efficiency as it is called a lot.
*
* document_interface_call_verb is similar but is called by the user.
*/
{
if ( desk2 ) {
if ( verb ) {
if ( action ) {
//if (!object->updates)
//document_interface_pause_updates (object, error);
Inkscape::DocumentUndo::done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip()));
//if (!object->updates)
//document_interface_pause_updates (object, error);
return TRUE;
}
}
}
return FALSE;
}
/****************************************************************************
DOCUMENT INTERFACE CLASS STUFF
****************************************************************************/
static void
{
}
static void
{
g_signal_new ("object_moved",
0,
}
static void
{
}
document_interface_new (void)
{
}
/*
* Error stuff...
*
* To add a new error type, edit here and in the .h InkscapeError enum.
*/
inkscape_error_quark (void)
{
if (!quark)
return quark;
}
GType inkscape_error_get_type(void)
{
if (etype == 0) {
static const GEnumValue values[] =
{
{ 0, 0, 0 }
};
}
return etype;
}
/****************************************************************************
MISC FUNCTIONS
****************************************************************************/
{
return TRUE;
}
{
if ( desk2 ) {
if ( verb ) {
if ( action ) {
Inkscape::DocumentUndo::done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip()));
}
return TRUE;
}
}
}
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb '%s' failed to execute or was not found.", verbid);
return FALSE;
}
/****************************************************************************
CREATION FUNCTIONS
****************************************************************************/
{
}
{
}
{
}
{
}
{
}
{
// Not sure why this works.
}
{
//Makes sure there is no fill for spirals by default.
return retval;
}
{
//just a workaround so i can get an spitem from the name
return name;
}
gchar *
{
if (!uri)
return FALSE;
//g_free(uri);
}
{
//} else {
//document_interface_pause_updates(object, error);
}
}
/****************************************************************************
ENVIORNMENT FUNCTIONS
****************************************************************************/
{
}
{
}
{
return sp_repr_css_write_string(current);
}
{
return TRUE;
}
{
//Memory leak?
return TRUE;
}
{
return TRUE;
}
double x0,
double y0,
double x1,
double y1,
double border,
{
y0,
x1,
y1,
border, false);
return TRUE;
}
GArray *
{
return dArr;
}
/****************************************************************************
OBJECT FUNCTIONS
****************************************************************************/
{
/* ALTERNATIVE (is this faster?)
Inkscape::XML::Node *newnode = sp_repr_lookup_name((doc->root)->repr, name);
*/
return FALSE;
if (!newNode)
return FALSE;
return TRUE;
}
{
if (!newNode)
return FALSE;
return TRUE;
}
{
return FALSE;
if (!newNode)
return FALSE;
return TRUE;
}
gchar *
{
return NULL;
if (!newNode)
return NULL;
}
{
if (!oldsel)
return FALSE;
return TRUE;
}
{
if (!oldsel)
return FALSE;
0 - (y - selection_get_center_y(sel)));
return TRUE;
}
{
if (!oldsel)
return FALSE;
return TRUE;
}
gchar *
{
if (!node)
return NULL;
{
return NULL;
}
}
{
//FIXME: This should merge transformations.
return TRUE;
}
gchar *
{
}
{
// Doesn't like non-variable strings for some reason.
return FALSE;
if (!node)
return FALSE;
return TRUE;
}
{
return FALSE;
if (!node)
return FALSE;
return TRUE;
}
{
if (r<0 || r>255 || g<0 || g>255 || b<0 || b>255)
{
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Given (%d,%d,%d). All values must be between 0-255 inclusive.", r, g, b);
return FALSE;
}
if (fill)
else
}
{
if (!oldsel)
return FALSE;
return TRUE;
}
{
//FIXME: Needs lot's of work.
/*
Inkscape::XML::Node *shapenode = get_repr_by_name (object->desk, shape, error);
if (shapenode == NULL || shapenode->attribute("d") == NULL) {
return FALSE;
}
char * path = strdup(shapenode->attribute("d"));
printf("PATH: %s\n", path);
Geom::parse_svg_path (path);
return NULL;
*/
return NULL;
}
{
//TODO verify object type
if (!text_obj)
return FALSE;
return TRUE;
}
{
//void sp_te_apply_style(SPItem *text, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPCSSAttr const *css)
//TODO verify object type
if (!text_obj)
return FALSE;
end,
css);
return TRUE;
}
/****************************************************************************
FILE I/O FUNCTIONS
****************************************************************************/
{
return FALSE;
}
{
}
return TRUE;
}
gchar *
{
}
{
#ifdef WITH_GNOME_VFS
#endif
return false;
}
try {
} catch (...) {
//SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
return false;
}
//SP_ACTIVE_DESKTOP->event_log->rememberFileSave();
//SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, "Document saved.");
return true;
}
{
if (doc) {
}
return TRUE;
}
/*
gboolean
document_interface_print_to_file (DocumentInterface *object, GError **error)
{
SPDocument * doc = sp_desktop_document(object->desk);
return TRUE;
}
*/
/****************************************************************************
PROGRAM CONTROL FUNCTIONS
****************************************************************************/
{
}
{
}
{
}
{
}
/****************************************************************************
UPDATE FUNCTIONS
FIXME: This would work better by adding a flag to SPDesktop to prevent
updating but that would be very intrusive so for now there is a workaround.
Need to make sure it plays well with verbs because they are used so much.
****************************************************************************/
{
//object->desk->canvas->need_redraw = 0;
//object->desk->canvas->need_repick = 0;
//sp_desktop_document(object->desk)->root->uflags = FALSE;
//sp_desktop_document(object->desk)->root->mflags = FALSE;
}
{
//object->desk->canvas->need_redraw = 1;
//object->desk->canvas->need_repick = 1;
//sp_desktop_document(object->desk)->root->uflags = TRUE;
//sp_desktop_document(object->desk)->root->mflags = TRUE;
//sp_desktop_document(object->desk)->_updateDocument();
//FIXME: use better verb than rect.
Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions");
}
{
//Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions");
}
/****************************************************************************
SELECTION FUNCTIONS FIXME: use call_verb where appropriate (once update system is tested.)
****************************************************************************/
gboolean document_interface_selection_get(DocumentInterface *object, char ***out, GError ** /*error*/)
{
int i = 0;
i++;
}
return TRUE;
}
{
if (!obj)
return FALSE;
return TRUE;
}
{
int i;
}
return TRUE;
}
gboolean document_interface_selection_set(DocumentInterface *object, char *name, GError ** /*error*/)
{
return TRUE;
}
{
int i;
}
return TRUE;
}
gboolean document_interface_selection_rotate(DocumentInterface *object, int angle, GError ** /*error*/)
{
return TRUE;
}
{
//sp_selection_delete (object->desk);
}
{
return TRUE;
}
{
//sp_edit_select_all (object->desk);
}
{
//sp_edit_select_all_in_all_layers (object->desk);
}
GError ** /*error*/)
{
//FIXME: implement.
return FALSE;
}
{
//sp_edit_invert (object->desk);
}
{
//sp_selection_group (object->desk);
}
{
//sp_selection_ungroup (object->desk);
}
{
//desktop_ensure_active (object->desk);
//sp_selection_cut (object->desk);
}
{
//desktop_ensure_active (object->desk);
//sp_selection_copy ();
}
/*
gboolean
document_interface_selection_paste (DocumentInterface *object, GError **error)
{
desktop_ensure_active (object->desk);
if (!object->updates)
document_interface_pause_updates (object, error);
sp_selection_paste (object->desk, TRUE);
if (!object->updates)
document_interface_pause_updates (object, error);
return TRUE;
//return dbus_call_verb (object, SP_VERB_EDIT_PASTE, error);
}
*/
{
}
gboolean document_interface_selection_scale(DocumentInterface *object, gdouble grow, GError ** /*error*/)
{
if (!selection)
{
return FALSE;
}
return TRUE;
}
gboolean document_interface_selection_move(DocumentInterface *object, gdouble x, gdouble y, GError ** /*error*/)
{
return TRUE;
}
gboolean document_interface_selection_move_to(DocumentInterface *object, gdouble x, gdouble y, GError ** /*error*/)
{
if (sel_bbox) {
sp_selection_move_relative(sel, m, true);
}
return TRUE;
}
//FIXME: does not paste in new layer.
// This needs to use lower level cut_impl and paste_impl (messy)
// See the built-in sp_selection_to_next_layer and duplicate.
{
// check if something is selected
return FALSE;
if (!next)
return FALSE;
}
return TRUE;
}
GArray *
{
if (sel)
{
g_array_append_val (intArr, x);
g_array_append_val (intArr, y);
return intArr;
}
return NULL;
}
{
}
gchar *
{
else
return NULL;
return NULL;
}
{
}
{
return TRUE;
}
/****************************************************************************
LAYER FUNCTIONS
****************************************************************************/
{
SPObject *new_layer = Inkscape::create_layer(dt->currentRoot(), dt->currentLayer(), Inkscape::LPOS_BELOW);
}
{
if (!obj)
return FALSE;
return TRUE;
}
{
//FIXME: implement.
return NULL;
}
{
return TRUE;
}
{
}
{
}
//////////////signals
{
//DocumentInterface *obj;
g_print("Ping!\n");
return TRUE;
}
//////////tree
document_interface_get_children (DocumentInterface *object, char *name, char ***out, GError **error)
{
int i = 0;
i++;
}
return TRUE;
}
{
}
#if 0
//just pseudo code
document_interface_get_xpath (DocumentInterface *object, char *xpath_expression, char ***out, GError **error){
//xpathresult result = xpatheval(repr, xpath_selection);
//convert resut to a string array we can return via dbus
return TRUE;
}
#endif
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :