summaryrefslogtreecommitdiffstats
path: root/src/main-cmdlinexact.cpp
diff options
context:
space:
mode:
authorDmitry Zhulanov <dmitry.zhulanov@gmail.com>2016-09-26 17:23:14 +0000
committerDmitry Zhulanov <dmitry.zhulanov@gmail.com>2016-09-26 17:23:14 +0000
commit6efece51f99980b824b199bbeb6452f03e6736c6 (patch)
tree7fa1c7d9a0278c5770c15c5ef4251e0deb362e4e /src/main-cmdlinexact.cpp
parentRemove unused variable. (diff)
downloadinkscape-6efece51f99980b824b199bbeb6452f03e6736c6.tar.gz
inkscape-6efece51f99980b824b199bbeb6452f03e6736c6.zip
add x-verbs support
(bzr r15136.1.1)
Diffstat (limited to 'src/main-cmdlinexact.cpp')
-rw-r--r--src/main-cmdlinexact.cpp526
1 files changed, 526 insertions, 0 deletions
diff --git a/src/main-cmdlinexact.cpp b/src/main-cmdlinexact.cpp
new file mode 100644
index 000000000..9efbfe8cd
--- /dev/null
+++ b/src/main-cmdlinexact.cpp
@@ -0,0 +1,526 @@
+/*
+ * Authors:
+ * Dmitry Zhulanov <dmitry.zhulanov@gmail.com>
+ *
+ * Copyright (C) 2016 Authors
+ *
+ * Released under GNU GPL v2, read the file 'COPYING' for more information
+ *
+ * Format of xverbs.yaml
+ *
+ * verbose: yes # only "verbose: yes" enable logging
+ * run:
+ * # open document to process
+ * - xverb-id: XFileOpen, gfx_sources/loading_screen/sandclock_atlas.svg
+ * - xverb-id: XUndoLabel, fresh_document # set label for UndoToLabel xverb works
+ * # note: if something wrong with undo labels use verb EditUndo instead of XUndoLabel and UndoToLabel at all
+ *
+ * # select element to handle
+ * - xverb-id: XSelectElement, top_sand
+ *
+ * # verbs
+ * - verb-id: EditInvertInAllLayers
+ * - verb-id: EditDelete
+ * - verb-id: FitCanvasToDrawing
+ *
+ * # save element to separated svg document
+ * - xverb-id: XFileSaveAs, output/thegame/linux/data/gfx/loading_screen/top_sand.svg
+ *
+ * # also save png preview
+ * - xverb-id: XFileExportPNG, output/thegame/linux/data/gfx_preview/loading_screen/top_sand.png
+ *
+ * # return to the fresh_state of document
+ * - xverb-id: UndoToLabel, fresh_document
+ *
+ * # do any other handling
+ *
+ * # inkscape have a lot of useful verbs
+ * - verb-id: FileQuit
+ */
+
+#include <ui/view/view.h>
+#include <desktop.h>
+#include <helper/action.h>
+#include <helper/action-context.h>
+#include <selection.h>
+#include <verbs.h>
+#include <inkscape.h>
+
+#include <document.h>
+
+#include <glibmm/i18n.h>
+
+#include "main-cmdlinexact.h"
+#include "yaml.h"
+#include "extension/system.h"
+#include "file.h"
+#include <glib.h>
+#include "sp-root.h"
+#include "document-undo.h"
+#include "util/units.h"
+#include "sp-namedview.h"
+#include "resource-manager.h"
+#include "ui/dialog/font-substitution.h"
+#include "extension/db.h"
+#include "preferences.h"
+#include "helper/png-write.h"
+#include <document-undo.h>
+#include <ui/view/view-widget.h>
+#include <ui/interface.h>
+
+#define DPI_BASE Inkscape::Util::Quantity::convert(1, "in", "px")
+
+namespace
+{
+bool s_verbose = false;
+
+bool createDirForFilename( const std::string &filename )
+{
+ size_t found = filename.find_last_of("/\\");
+ std::string output_directory = filename.substr(0,found);
+
+ if( output_directory == filename )
+ return true;
+
+ if (g_mkdir_with_parents(output_directory.c_str(), 0755))
+ {
+ printf("Can't create directory %s\n", output_directory.c_str());
+ fflush(stdout);
+
+ return false;
+ }
+
+ return true;
+}
+
+void xFileOpen( const Glib::ustring &uri )
+{
+ if (s_verbose) {
+ printf("open %s\n", uri.c_str());
+ fflush(stdout);
+ }
+
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ SPDocument *old_document = desktop->getDocument();
+ desktop->setWaitingCursor();
+ Inkscape::DocumentUndo::clearRedo(old_document);
+ }
+
+ SPDocument *doc = NULL;
+ Inkscape::Extension::Extension *key = NULL;
+ try {
+ doc = Inkscape::Extension::open(key, uri.c_str());
+ } catch (std::exception &e) {
+ doc = NULL;
+ std::string exeption_mgs = e.what();
+ printf("Error: open %s:%s\n",uri.c_str(), exeption_mgs.c_str() );
+ fflush(stdout);
+ }
+
+ // Set viewBox if it doesn't exist
+ if (!doc->getRoot()->viewBox_set
+ && (doc->getRoot()->width.unit != SVGLength::PERCENT)
+ && (doc->getRoot()->height.unit != SVGLength::PERCENT)) {
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit())));
+ }
+
+ desktop->change_document(doc);
+ doc->emitResizedSignal(doc->getWidth().value("px"), doc->getHeight().value("px"));
+ if(desktop)
+ desktop->clearWaitingCursor();
+
+ doc->virgin = FALSE;
+
+ // everyone who cares now has a reference, get rid of our`s
+ doc->doUnref();
+
+ // resize the window to match the document properties
+ sp_namedview_window_from_document(desktop);
+ sp_namedview_update_layers_from_document(desktop);
+
+ if ( INKSCAPE.use_gui() ) {
+ // Perform a fixup pass for hrefs.
+ if ( Inkscape::ResourceManager::getManager().fixupBrokenLinks(doc) ) {
+ Glib::ustring msg = _("Broken links have been changed to point to existing files.");
+ desktop->showInfoDialog(msg);
+ }
+
+ // Check for font substitutions
+ Inkscape::UI::Dialog::FontSubstitution::getInstance().checkFontSubstitutions(doc);
+ }
+}
+
+void xFileSaveAs( Inkscape::ActionContext const & context, const Glib::ustring &uri )
+{
+ SPDocument *doc = context.getDocument();
+ if (s_verbose) {
+ printf("save as %s\n", uri.c_str());
+ fflush(stdout);
+ }
+
+ if( createDirForFilename( uri )) {
+ Inkscape::Extension::save(
+ Inkscape::Extension::db.get("org.inkscape.output.svg.inkscape"),
+ doc, uri.c_str(), false, false, true, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS);
+ if (s_verbose) {
+ printf("save done: %s\n", uri.c_str() );
+ fflush(stdout);
+ }
+ }
+ else
+ {
+ printf("can't create dirs for filename %s\n", uri.c_str() );
+ fflush(stdout);
+ }
+}
+
+void xFileExportPNG( Inkscape::ActionContext const & context, const Glib::ustring &uri )
+{
+ if (s_verbose) {
+ printf("export png %s\n", uri.c_str());
+ fflush(stdout);
+ }
+
+ SPDocument *doc = context.getDocument();
+
+ gdouble dpi = 200.0;
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ dpi = prefs->getDouble("/dialogs/export/defaultxdpi/value", DPI_BASE);
+
+ gdouble width = doc->getWidth().value(doc->getDisplayUnit());
+ gdouble height = doc->getHeight().value(doc->getDisplayUnit());
+
+ gdouble bmwidth = (width) * dpi / DPI_BASE;
+ gdouble bmheight = (height) * dpi / DPI_BASE;
+
+ int png_width = (int)(0.5 + bmwidth);
+ int png_height = (int)(0.5 + bmheight);
+
+ SPNamedView *nv = desktop->getNamedView();
+
+ ExportResult status = sp_export_png_file(doc, uri.c_str(),
+ Geom::Rect(Geom::Point(0,0), Geom::Point(width, height)), png_width, png_height, dpi, dpi,
+ nv->pagecolor, 0, 0, TRUE);
+}
+
+void xSelectElement( Inkscape::ActionContext const & context, const Glib::ustring &uri )
+{
+ if (context.getDocument() == NULL || context.getSelection() == NULL) { return; }
+
+ if (s_verbose) {
+ printf("select element: %s\n", uri.c_str());
+ fflush(stdout);
+ }
+
+ SPDocument * doc = context.getDocument();
+ SPObject * obj = doc->getObjectById(uri);
+
+ if (obj == NULL) {
+ printf(_("Unable to find node ID: '%s'\n"), uri.c_str());
+ fflush(stdout);
+ return;
+ }
+
+ Inkscape::Selection * selection = context.getSelection();
+ selection->add(obj);
+
+ if (s_verbose) {
+ printf("select done %s\n", uri.c_str());
+ fflush(stdout);
+ }
+}
+
+} // end of unnamed namespace
+
+namespace Inkscape {
+
+CmdLineXAction::CmdLineXAction (gchar const * arg, xaction_args_values_map_t &values_map):
+ CmdLineAction(true, arg), _values_map(values_map) {
+ this->arg = (char *)arg;
+ return;
+}
+
+bool
+CmdLineXAction::isExtended() {
+ return true;
+}
+
+void
+CmdLineXAction::doItX (ActionContext const & context) {
+ (void)(context);
+
+ if( arg == "XFileSaveAs")
+ xFileSaveAs( context, _values_map["filename"] );
+ else if (arg == "XFileOpen")
+ xFileOpen( _values_map["filename"] );
+ else if (arg == "XFileExportPNG")
+ xFileExportPNG( context, _values_map["png_filename"] );
+ else if (arg == "XSelectElement")
+ xSelectElement( context, _values_map["element-id"] );
+ else
+ {
+ printf("unknown xverb: %s", arg.c_str());
+ fflush(stdout);
+ }
+
+ return;
+}
+
+enum parser_state_t{ HANDLING_ROOT,
+ HANDLING_VERBOSE, // options
+ HANDLING_RUN, HANDLING_RUN_LIST, HANDLING_RUN_LIST_ENTRY }; // run entries
+
+struct verb_info_t
+{
+ bool xverb;
+ std::vector<std::string> args;
+};
+
+typedef std::list<verb_info_t> verbs_list_t;
+
+static void tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters = ",")
+{
+ // Skip delimiters at beginning.
+ std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
+
+ // Find first non-delimiter.
+ std::string::size_type pos = str.find_first_of(delimiters, lastPos);
+
+ while (std::string::npos != pos || std::string::npos != lastPos) {
+ // Found a token, add it to the vector.
+ tokens.push_back(str.substr(lastPos, pos - lastPos));
+
+ // Skip delimiters.
+ lastPos = str.find_first_not_of(delimiters, pos);
+
+ // Find next non-delimiter.
+ pos = str.find_first_of(delimiters, lastPos);
+ }
+}
+
+void
+CmdLineXAction::createActionsFromYAML( gchar const *yaml_filename ) {
+ FILE *fh = fopen(yaml_filename, "r");
+ if(fh == NULL) {
+ printf("Failed to open file!\n");
+ fflush(stdout);
+ return;
+ }
+
+ yaml_parser_t parser;
+ if(!yaml_parser_initialize(&parser)) {
+ printf("Failed to initialize parser!\n");
+ fflush(stdout);
+ return;
+ }
+
+ /* Set input file */
+ yaml_parser_set_input_file(&parser, fh);
+
+ parser_state_t state = HANDLING_ROOT;
+
+
+ bool handling_key = false;
+ bool handling_value = false;
+
+ std::string key;
+ verbs_list_t verbs_list;
+
+ // parse
+ yaml_token_t token;
+ do {
+ yaml_parser_scan(&parser, &token);
+ switch(token.type)
+ {
+ // avoid "warning: enumeration value", "-Wswitch"
+ case YAML_NO_TOKEN: break;
+ case YAML_STREAM_START_TOKEN: break;
+ case YAML_STREAM_END_TOKEN: break;
+ case YAML_VERSION_DIRECTIVE_TOKEN: break;
+ case YAML_TAG_DIRECTIVE_TOKEN: break;
+ case YAML_DOCUMENT_START_TOKEN: break;
+ case YAML_DOCUMENT_END_TOKEN: break;
+ case YAML_FLOW_SEQUENCE_START_TOKEN: break;
+ case YAML_FLOW_SEQUENCE_END_TOKEN: break;
+ case YAML_FLOW_MAPPING_START_TOKEN: break;
+ case YAML_FLOW_MAPPING_END_TOKEN: break;
+ case YAML_FLOW_ENTRY_TOKEN: break;
+ case YAML_ALIAS_TOKEN: break;
+ case YAML_ANCHOR_TOKEN: break;
+ case YAML_TAG_TOKEN: break;
+
+ /* Token types (read before actual token) */
+ case YAML_KEY_TOKEN:
+ handling_key = true;
+ handling_value = false;
+ break;
+ case YAML_VALUE_TOKEN:
+ handling_key = false;
+ handling_value = true;
+ break;
+
+ /* Block delimeters */
+ case YAML_BLOCK_SEQUENCE_START_TOKEN:
+ if( state == HANDLING_ROOT )
+ {
+ if( key == "run" )
+ state = HANDLING_RUN;
+ }
+ break;
+ case YAML_BLOCK_ENTRY_TOKEN:
+ if( state == HANDLING_RUN )
+ state = HANDLING_RUN_LIST;
+ else if( state == HANDLING_RUN_LIST )
+ state = HANDLING_RUN_LIST_ENTRY;
+ else if( state == HANDLING_VERBOSE )
+ state = HANDLING_ROOT;
+ break;
+ case YAML_BLOCK_END_TOKEN:
+ if( state == HANDLING_RUN_LIST_ENTRY )
+ state = HANDLING_RUN_LIST;
+ else if( state == HANDLING_RUN_LIST )
+ state = HANDLING_RUN;
+ else if( state == HANDLING_VERBOSE )
+ state = HANDLING_ROOT;
+ else if( state == HANDLING_RUN )
+ state = HANDLING_ROOT;
+ break;
+
+ /* Data */
+ case YAML_BLOCK_MAPPING_START_TOKEN:
+ break;
+ case YAML_SCALAR_TOKEN:
+ if( handling_key )
+ key = (char *)token.data.scalar.value;
+ else if ( handling_value )
+ {
+ if(state == HANDLING_RUN_LIST)
+ {
+ if(key == "xverb-id")
+ {
+ verb_info_t verb;
+ verb.xverb = true;
+
+ std::string values = (char *)token.data.scalar.value;
+ tokenize(values, verb.args);
+ for( size_t i = 0; i < verb.args.size(); ++i )
+ {
+ verb.args[i].erase(0, verb.args[i].find_first_not_of(' ')); //prefixing spaces
+ verb.args[i].erase(verb.args[i].find_last_not_of(' ')+1); //surfixing spaces
+ }
+ verbs_list.push_back(verb);
+ }
+ else if(key == "verb-id")
+ {
+ verb_info_t verb;
+ verb.xverb = false;
+ verb.args.push_back((char *)token.data.scalar.value);
+ verbs_list.push_back(verb);
+ }
+ else
+ {
+ printf("unknown verb type [%s]\n", key.c_str());
+ fflush(stdout);
+ }
+ }
+ else if(state == HANDLING_ROOT)
+ {
+ std::string value = (char *)token.data.scalar.value;
+ if( (key == "verbose") && (value == "yes") )
+ s_verbose = true;
+ }
+ }
+ break;
+ }
+ } while(token.type != YAML_STREAM_END_TOKEN);
+
+ /* Cleanup */
+ yaml_token_delete(&token);
+ yaml_parser_delete(&parser);
+ fclose(fh);
+
+ typedef std::map<std::string,int> undo_labels_map_t;
+ undo_labels_map_t undo_labels_map;
+ int undo_counter = 0;
+
+ verbs_list_t::iterator iter = verbs_list.begin();
+ for( ; iter != verbs_list.end(); ++iter )
+ {
+ verb_info_t &verb = *iter;
+ std::string &verb_word = verb.args[0];
+ if( s_verbose )
+ printf("handle %s and args count is %d\n", verb_word.c_str(), (int)verb.args.size());
+
+ if( verb.args.size() == 2 )
+ {
+ xaction_args_values_map_t values_map;
+ if (verb_word == "XFileSaveAs" || verb_word == "XFileOpen")
+ {
+ std::string &filename = verb.args[1];
+ values_map["filename"] = filename;
+ new CmdLineXAction(verb_word.c_str(), values_map);
+ }
+ else if (verb_word == "XUndoLabel")
+ undo_labels_map[verb.args[1]] = undo_counter;
+ else if (verb_word == "UndoToLabel")
+ {
+ undo_labels_map_t::iterator iter = undo_labels_map.find(verb.args[1]);
+ if(iter != undo_labels_map.end())
+ {
+ int counter = undo_counter - iter->second;
+ if( counter > 0 )
+ {
+ for(int i = 0; i < counter; ++i)
+ new CmdLineAction(true, "EditUndo");
+ undo_counter -= counter;
+ }
+ }
+ }
+ else if (verb_word == "XSelectElement")
+ {
+ ++undo_counter;
+ values_map["element-id"] = verb.args[1];
+ new CmdLineXAction(verb_word.c_str(), values_map);
+ }
+ else if (verb_word == "XFileExportPNG")
+ {
+ std::string &png_filename = verb.args[1];
+ values_map["png_filename"] = png_filename;
+ if(createDirForFilename( png_filename )) {
+ new CmdLineXAction(verb_word.c_str(), values_map);
+ }
+ }
+ }
+ else if(!verb.xverb)
+ {
+ ++undo_counter;
+ new CmdLineAction(true, verb.args[0].c_str());
+ }
+
+ else
+ {
+ printf("Unhadled verb %s\n", verb.args[0].c_str());
+ fflush(stdout);
+ }
+ }
+
+ fflush(stdout);
+ return;
+}
+
+
+} // Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :