summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2018-11-20 13:41:00 +0000
committerTavmjong Bah <tavmjong@free.fr>2018-11-20 13:41:00 +0000
commited4afe5ba3d3616c58a42459b472f8170c8a4585 (patch)
treeea5a2364e4a4759c681ff0c4f91ed0dd575ba008 /src
parentPossible fix to build breakage on Macs. (diff)
downloadinkscape-ed4afe5ba3d3616c58a42459b472f8170c8a4585.tar.gz
inkscape-ed4afe5ba3d3616c58a42459b472f8170c8a4585.zip
Add a shell mode.
Diffstat (limited to 'src')
-rw-r--r--src/inkscape-application.cpp202
-rw-r--r--src/inkscape-application.h10
2 files changed, 158 insertions, 54 deletions
diff --git a/src/inkscape-application.cpp b/src/inkscape-application.cpp
index e99f7071c..00b4ba1f4 100644
--- a/src/inkscape-application.cpp
+++ b/src/inkscape-application.cpp
@@ -46,6 +46,7 @@ InkscapeApplication::InkscapeApplication()
Gio::APPLICATION_HANDLES_OPEN | // Use default file opening.
Gio::APPLICATION_NON_UNIQUE ) // Allows different instances of Inkscape to run at same time.
, _with_gui(true)
+ , _use_shell(false)
{
// ==================== Initializations =====================
@@ -98,7 +99,7 @@ InkscapeApplication::InkscapeApplication()
add_main_option_entry(OPTION_TYPE_BOOL, "vacuum-defs", '\0', N_("Process: Remove unused definitions from the <defs> section(s) of document."), "");
add_main_option_entry(OPTION_TYPE_STRING, "select", '\0', N_("Process: Select objects: comma separated list of IDs."), N_("OBJECT-ID[,OBJECT-ID]*"));
add_main_option_entry(OPTION_TYPE_STRING, "verb", '\0', N_("Process: Verb(s) to call when Inkscape opens."), N_("VERB-ID[,VERB-ID]*"));
- //add_main_option_entry(OPTION_TYPE_BOOL, "shell", '\0', N_("Process: Start Inkscape in interative shell mode."), "");
+ add_main_option_entry(OPTION_TYPE_BOOL, "shell", '\0', N_("Process: Start Inkscape in interative shell mode."), "");
// Export - File and File Type
add_main_option_entry(OPTION_TYPE_STRING, "export-type", '\0', N_("Export: File type:[svg,png,ps,psf,tex,emf,wmf,xaml]"), "[...]");
@@ -215,9 +216,16 @@ InkscapeApplication::on_activate()
on_startup2();
if (_with_gui) {
- create_window();
+ if (_use_shell) {
+ shell(); // Shell will create its own windows.
+ } else {
+ create_window();
+ }
} else {
std::cerr << "InkscapeApplication::on_activate: Without GUI" << std::endl;
+ if (_use_shell) {
+ shell2();
+ }
// Create blank document?
}
}
@@ -259,8 +267,12 @@ InkscapeApplication::on_open(const Gio::Application::type_vec_files& files, cons
activate_action( action.first, action.second );
}
- // Save... can't use action yet.
- _file_export.do_export(doc, file->get_path());
+ if (_use_shell) {
+ shell2();
+ } else {
+ // Save... can't use action yet.
+ _file_export.do_export(doc, file->get_path());
+ }
// Remove from our application... we only have one in command-line mode.
_documents.pop_back();
@@ -275,7 +287,7 @@ InkscapeApplication::on_open(const Gio::Application::type_vec_files& files, cons
// Gtk::Application::on_open(files, hint);
}
-void
+SPDesktop*
InkscapeApplication::create_window(const Glib::RefPtr<Gio::File>& file)
{
SPDesktop* desktop = nullptr;
@@ -290,8 +302,137 @@ InkscapeApplication::create_window(const Glib::RefPtr<Gio::File>& file)
// Add to Gtk::Window to app window list.
add_window(*desktop->getToplevel());
+
+ return (desktop); // Temp: Need to track desktop for shell mode.
}
+
+void
+InkscapeApplication::parse_actions(const Glib::ustring& input, action_vector_t& action_vector)
+{
+ // Split action list
+ std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*;\\s*", input);
+ for (auto token : tokens) {
+ std::vector<Glib::ustring> tokens2 = Glib::Regex::split_simple("\\s*:\\s*", token);
+ std::string action;
+ std::string value;
+ if (tokens2.size() > 0) {
+ action = tokens2[0];
+ }
+ if (tokens2.size() > 1) {
+ value = tokens2[1];
+ }
+
+ Glib::RefPtr<Gio::Action> action_ptr = lookup_action(action);
+ if (action_ptr) {
+ // Doesn't seem to be a way to test this using the C++ binding without Glib-CRITICAL errors.
+ const GVariantType* gtype = g_action_get_parameter_type(action_ptr->gobj());
+ if (gtype) {
+ // With value.
+ Glib::VariantType type = action_ptr->get_parameter_type();
+ if (type.get_string() == "s") {
+ action_vector.push_back(
+ std::make_pair( action, Glib::Variant<Glib::ustring>::create(value) ));
+ } else if (type.get_string() == "i") {
+ action_vector.push_back(
+ std::make_pair( action, Glib::Variant<int>::create(std::stoi(value))));
+ } else if (type.get_string() == "d") {
+ action_vector.push_back(
+ std::make_pair( action, Glib::Variant<double>::create(std::stod(value))));
+ } else {
+ std::cerr << "InkscapeApplication::parse_actions: unhandled action value: "
+ << action << ": " << type.get_string() << std::endl;
+ }
+ } else {
+ // Stateless (i.e. no value).
+ action_vector.push_back( std::make_pair( action, Glib::VariantBase() ) );
+ }
+ } else {
+ // Assume a verb
+ // std::cerr << "InkscapeApplication::parse_actions: '"
+ // << action << "' is not a valid action! Assuming verb!" << std::endl;
+ action_vector.push_back(
+ std::make_pair("verb", Glib::Variant<Glib::ustring>::create(action)));
+ }
+ }
+}
+
+// Interactively trigger actions. This is a travesty! Due to most verbs requiring a desktop we must
+// create one even in shell mode!
+void
+InkscapeApplication::shell()
+{
+ std::cout << "Inkscape interactive shell mode. Type 'quit' to quit." << std::endl;
+ std::cout << " Input of the form:" << std::endl;
+ std::cout << "> filename action1:arg1; action2:arg2; verb1; verb2; ..." << std::endl;
+
+ std::string input;
+ while (true) {
+ std::cout << "> ";
+ std::getline(std::cin, input);
+
+ if (input == "quit") break;
+
+ // Get filename which must be first and separated by space (and not contain ':' or ';').
+ // Regex works on Glib::ustrings and will give bad results if one tries to use std::string.
+ Glib::ustring input_u = input;
+ Glib::ustring filename;
+ Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create("^\\s*([^:;\\s]+)\\s+(.*)");
+ Glib::MatchInfo match_info;
+ regex->match(input_u, match_info);
+ if (match_info.matches()) {
+ filename = match_info.fetch(1);
+ input_u = match_info.fetch(2);
+ } else {
+ std::cerr << "InkscapeApplication::shell: Failed to find file in |"
+ << input << "|" << std::endl;
+ }
+
+ // Create desktop.
+ SPDesktop* desktop = nullptr;
+ if (!filename.empty()) {
+ Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(filename);
+ desktop = create_window(file);
+ }
+
+ // Find and execute actions (verbs).
+ action_vector_t action_vector;
+ parse_actions(input_u, action_vector);
+ for (auto action: action_vector) {
+ activate_action( action.first, action.second );
+ }
+
+ if (desktop) {
+ desktop->destroy();
+ }
+ }
+
+ quit(); // Must quit or segfault.
+}
+
+// Once we don't need to create a window just to process verbs!
+void
+InkscapeApplication::shell2()
+{
+ std::cout << "Inkscape interactive shell mode. Type 'quit' to quit." << std::endl;
+ std::cout << " Input of the form:" << std::endl;
+ std::cout << "> action1:arg1; action2;arg2; verb1; verb2; ..." << std::endl;
+ std::cout << "Only verbs that don't require a desktop may be used." << std::endl;
+
+ std::string input;
+ while (true) {
+ std::cout << "> ";
+ std::cin >> input;
+ if (input == "quit") break;
+ action_vector_t action_vector;
+ parse_actions(input, action_vector);
+ for (auto action: action_vector) {
+ activate_action( action.first, action.second );
+ }
+ }
+}
+
+
// ========================= Callbacks ==========================
/*
@@ -338,9 +479,10 @@ InkscapeApplication::on_handle_local_options(const Glib::RefPtr<Glib::VariantDic
// For options without arguments.
auto base = Glib::VariantBase();
- // ====================== GUI =====================
+ // ================== GUI and Shell ================
if (options->contains("without-gui")) _with_gui = false;
if (options->contains("with-gui")) _with_gui = true;
+ if (options->contains("shell")) _use_shell = true;
// Some options should preclude using gui!
if (options->contains("query-id") ||
@@ -362,52 +504,7 @@ InkscapeApplication::on_handle_local_options(const Glib::RefPtr<Glib::VariantDic
Glib::ustring actions;
if (options->contains("actions")) {
options->lookup_value("actions", actions);
-
- // Split action list
- std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*;\\s*", actions);
- for (auto token : tokens) {
- std::vector<Glib::ustring> tokens2 = Glib::Regex::split_simple("\\s*:\\s*", token);
- std::string action;
- std::string value;
- if (tokens2.size() > 0) {
- action = tokens2[0];
- }
- if (tokens2.size() > 1) {
- value = tokens2[1];
- }
-
- Glib::RefPtr<Gio::Action> action_ptr = lookup_action(action);
- if (action_ptr) {
- // Doesn't seem to be a way to test this using the C++ binding without Glib-CRITICAL errors.
- const GVariantType* gtype = g_action_get_parameter_type(action_ptr->gobj());
- if (gtype) {
- // With value.
- Glib::VariantType type = action_ptr->get_parameter_type();
- if (type.get_string() == "s") {
- _command_line_actions.push_back(
- std::make_pair( action, Glib::Variant<Glib::ustring>::create(value) ));
- } else if (type.get_string() == "i") {
- _command_line_actions.push_back(
- std::make_pair( action, Glib::Variant<int>::create(std::stoi(value))));
- } else if (type.get_string() == "d") {
- _command_line_actions.push_back(
- std::make_pair( action, Glib::Variant<double>::create(std::stod(value))));
- } else {
- std::cerr << "InkscapeApplication::on_handle_local_options: unhandled action value: "
- << action << ": " << type.get_string() << std::endl;
- }
- } else {
- // Stateless (i.e. no value).
- _command_line_actions.push_back( std::make_pair( action, Glib::VariantBase() ) );
- }
- } else {
- // Assume a verb
- std::cerr << "InkscapeApplication::on_handle_local_options: '"
- << action << "' is not a valid action!" << std::endl;
- _command_line_actions.push_back(
- std::make_pair("verb", Glib::Variant<Glib::ustring>::create(action)));
- }
- }
+ parse_actions(actions, _command_line_actions);
}
@@ -475,6 +572,7 @@ InkscapeApplication::on_handle_local_options(const Glib::RefPtr<Glib::VariantDic
}
}
+
// ==================== EXPORT =====================
if (options->contains("export-file")) {
options->lookup_value("export-file", _file_export.export_filename);
diff --git a/src/inkscape-application.h b/src/inkscape-application.h
index b176c2921..28c89810a 100644
--- a/src/inkscape-application.h
+++ b/src/inkscape-application.h
@@ -26,6 +26,8 @@
#include "helper/action.h"
#include "io/file-export-cmd.h" // File export (non-verb)
+typedef std::vector<std::pair<std::string, Glib::VariantBase> > action_vector_t;
+
class InkscapeApplication : public Gtk::Application
{
protected:
@@ -43,7 +45,10 @@ protected:
void on_open(const Gio::Application::type_vec_files& files, const Glib::ustring& hint) override;
private:
- void create_window(const Glib::RefPtr<Gio::File>& file = Glib::RefPtr<Gio::File>());
+ SPDesktop* create_window(const Glib::RefPtr<Gio::File>& file = Glib::RefPtr<Gio::File>());
+ void parse_actions(const Glib::ustring& input, action_vector_t& action_vector);
+ void shell();
+ void shell2();
private:
// Callbacks
@@ -57,13 +62,14 @@ private:
Glib::RefPtr<Gtk::Builder> _builder;
bool _with_gui;
+ bool _use_shell;
InkFileExportCmd _file_export;
// Documents are owned by the application which is responsible for opening/saving/exporting. WIP
std::vector<SPDocument*> _documents;
// Actions from the command line or file.
- std::vector<std::pair<std::string, Glib::VariantBase> > _command_line_actions;
+ action_vector_t _command_line_actions;
};
#endif // INKSCAPE_APPLICATION_H