/*
* 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 remotely 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 "file.h" //IO
#include "document-interface.h"
#include "application-interface.h"
#include <string.h>
#include <dbus/dbus-glib.h>
#include "desktop.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 "document-undo.h"
#include "file.h" //IO
#include "helper/action-context.h"
#include "inkscape.h" //inkscape_find_desktop_by_dkey, activate desktops
#include "layer-fns.h" //LPOS_BELOW
#include "layer-model.h"
#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 "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.
*/
{
return oldsel;
}
/*
* See selection_swap, above
*/
void
{
// ... setList used to work here
}
/*
* 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 *doc_interface, 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);
}
if (doc_interface->updates) {
}
}
/*
* 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 ( desk ) {
}
if ( verb ) {
if ( action ) {
if (doc_interface->updates)
Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), verb->get_code(), verb->get_tip());
return TRUE;
}
}
return FALSE;
}
/*
* Check that the desktop is not NULL. If it is NULL, set the error to a useful message.
*/
bool
{
if (desk) {
return true;
}
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Document interface action requires a GUI");
return false;
}
/****************************************************************************
DOCUMENT INTERFACE CLASS STUFF
****************************************************************************/
static void
{
}
static void
{
g_signal_new ("object_moved",
0,
}
static void
{
}
document_interface_new (void)
{
}
/****************************************************************************
MISC FUNCTIONS
****************************************************************************/
{
return TRUE;
}
{
if ( desk ) {
}
if ( verb ) {
if ( action ) {
if (doc_interface->updates) {
Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), verb->get_code(), 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;
}
document_interface_text (DocumentInterface *doc_interface, int x, int y, gchar *text, GError **error)
{
//just a workaround so i can get an spitem from the name
return name;
}
gchar *
document_interface_image (DocumentInterface *doc_interface, int x, int y, gchar *filename, GError **error)
{
if (!uri)
return FALSE;
if (doc_interface->updates)
//g_free(uri);
}
{
if (doc_interface->updates) {
}
}
/****************************************************************************
ENVIRONMENT FUNCTIONS
****************************************************************************/
{
}
{
}
{
}
{
return TRUE;
}
{
//Memory leak?
return TRUE;
}
{
}
double x0,
double y0,
double x1,
double y1,
double border,
{
y0,
x1,
y1,
border, false);
return TRUE;
}
GArray *
{
if (!desk) {
return NULL;
}
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;
}
{
Inkscape::XML::Node *newNode = get_repr_by_name (doc_interface->target.getDocument(), shape, error);
if (!newNode)
return FALSE;
return TRUE;
}
{
Inkscape::XML::Node *newNode = get_repr_by_name (doc_interface->target.getDocument(), shape, error);
return FALSE;
if (!newNode)
return FALSE;
return TRUE;
}
gchar *
{
return NULL;
if (!newNode)
return NULL;
}
{
return FALSE;
return TRUE;
}
{
return FALSE;
0 - (y - selection_get_center_y(sel)));
return TRUE;
}
{
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
}
{
return FALSE;
return TRUE;
}
GArray *document_interface_get_node_coordinates(DocumentInterface * /*doc_interface*/, gchar * /*shape*/)
{
//FIXME: Needs lot's of work.
/*
Inkscape::XML::Node *shapenode = get_repr_by_name (doc_interface->target.getDocument(), 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;
}
document_interface_set_text (DocumentInterface *doc_interface, gchar *name, gchar *text, GError **error)
{
//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;
}
{
if (desk) {
}
if (doc_interface->updates) {
Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), SP_VERB_FILE_OPEN, "Opened File");
}
return TRUE;
}
gchar *
{
if (desk) {
}
}
{
// FIXME: Isn't there a verb we can use for this instead?
#ifdef WITH_GNOME_VFS
#endif
return false;
}
try {
} catch (...) {
// FIXME: catch ... is not usually a great idea, why is it needed here?
return false;
}
return true;
}
gboolean document_interface_mark_as_unmodified(DocumentInterface *doc_interface, GError ** /*error*/)
{
if (doc) {
}
return TRUE;
}
/*
gboolean
document_interface_print_to_file (DocumentInterface *doc_interface, GError **error)
{
SPDocument * doc = doc_interface->target.getDocument();
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.
****************************************************************************/
{
}
{
//FIXME: use better verb than rect.
Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), SP_VERB_CONTEXT_RECT, "Multiple actions");
}
{
doc->_updateDocument();
//Inkscape::DocumentUndo::done(doc, 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 *doc_interface, 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 *doc_interface, char *name, GError ** /*error*/)
{
return TRUE;
}
{
int i;
}
return TRUE;
}
gboolean document_interface_selection_rotate(DocumentInterface *doc_interface, int angle, GError ** /*error*/)
{
return TRUE;
}
{
}
{
return TRUE;
}
{
}
{
}
gboolean document_interface_selection_box(DocumentInterface * /*doc_interface*/, int /*x*/, int /*y*/,
GError ** /*error*/)
{
//FIXME: implement.
return FALSE;
}
{
}
{
}
{
}
{
}
{
}
{
}
gboolean document_interface_selection_scale(DocumentInterface *doc_interface, gdouble grow, GError ** /*error*/)
{
if (!selection)
{
return FALSE;
}
return TRUE;
}
gboolean document_interface_selection_move(DocumentInterface *doc_interface, gdouble x, gdouble y, GError ** /*error*/)
{
return TRUE;
}
gboolean document_interface_selection_move_to(DocumentInterface *doc_interface, 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;
}
{
}
document_interface_selection_combine (DocumentInterface *doc_interface, gchar *cmd, char ***newpaths,
{
else {
return FALSE;
}
}
{
return TRUE;
}
/****************************************************************************
LAYER FUNCTIONS
****************************************************************************/
{
SPObject *new_layer = Inkscape::create_layer(layers->currentRoot(), layers->currentLayer(), Inkscape::LPOS_BELOW);
}
{
if (!obj)
return FALSE;
return TRUE;
}
{
//FIXME: implement.
return NULL;
}
{
return TRUE;
}
{
}
{
}
//////////////signals
{
return TRUE;
}
//////////tree
document_interface_get_children (DocumentInterface *doc_interface, char *name, char ***out, GError **error)
{
int i = 0;
for (std::vector<SPObject*>::iterator iter = children.begin(), e = children.end(); iter != e; ++iter) {
i++;
}
return TRUE;
}
{
}
#if 0
//just pseudo code
document_interface_get_xpath (DocumentInterface *doc_interface, 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 :