=== modified file 'src/desktop.cpp'
--- src/desktop.cpp 2016-07-25 05:27:21 +0000
+++ src/desktop.cpp 2017-06-04 04:46:56 +0000
@@ -123,6 +123,7 @@
waiting_cursor( false ),
showing_dialogs ( false ),
guides_active( false ),
+ on_live_extension(false),
gr_item( NULL ),
gr_point_type( POINT_LG_BEGIN ),
gr_point_i( 0 ),
=== modified file 'src/desktop.h'
--- src/desktop.h 2016-07-25 05:27:21 +0000
+++ src/desktop.h 2017-06-04 04:49:21 +0000
@@ -191,9 +191,9 @@
unsigned int interaction_disabled_counter;
bool waiting_cursor;
bool showing_dialogs;
-
/// \todo fixme: This has to be implemented in different way */
guint guides_active : 1;
+ bool on_live_extension;
// storage for selected dragger used by GrDrag as it's
// created and deleted by tools
=== modified file 'src/extension/execution-env.cpp'
--- src/extension/execution-env.cpp 2016-04-12 10:35:15 +0000
+++ src/extension/execution-env.cpp 2017-05-31 00:21:54 +0000
@@ -23,6 +23,8 @@
#include "selection.h"
#include "effect.h"
#include "document.h"
+#include "desktop.h"
+#include "inkscape.h"
#include "document-undo.h"
#include "desktop.h"
#include "ui/view/view.h"
@@ -54,19 +56,6 @@
_show_working(show_working),
_show_errors(show_errors)
{
- SPDesktop *desktop = (SPDesktop *)_doc;
- sp_namedview_document_from_window(desktop);
-
- if (desktop != NULL) {
- std::vector<SPItem*> selected = desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); ++x){
- Glib::ustring selected_id;
- selected_id = (*x)->getId();
- _selected.insert(_selected.end(), selected_id);
- //std::cout << "Selected: " << selected_id << std::endl;
- }
- }
-
genDocCache();
return;
@@ -183,24 +172,14 @@
void
ExecutionEnv::reselect (void) {
- if (_doc == NULL) { return; }
- SPDocument * doc = _doc->doc();
- if (doc == NULL) { return; }
-
- SPDesktop *desktop = (SPDesktop *)_doc;
- sp_namedview_document_from_window(desktop);
-
- if (desktop == NULL) { return; }
-
- Inkscape::Selection * selection = desktop->getSelection();
-
- for (std::list<Glib::ustring>::iterator i = _selected.begin(); i != _selected.end(); ++i) {
- SPObject * obj = doc->getObjectById(i->c_str());
- if (obj != NULL) {
- selection->add(obj);
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::Selection * selection = NULL;
+ if(desktop) {
+ selection = desktop->getSelection();
+ if (!desktop->on_live_extension) {
+ selection->restoreBackup();
}
}
-
return;
}
=== modified file 'src/extension/execution-env.h'
--- src/extension/execution-env.h 2014-03-27 01:33:44 +0000
+++ src/extension/execution-env.h 2017-05-30 21:15:29 +0000
@@ -54,9 +54,6 @@
Glib::RefPtr<Glib::MainLoop> _mainloop;
/** \brief The document that we're working on. */
Inkscape::UI::View::View * _doc;
- /** \brief A list of the IDs of all the selected objects before
- we started to work on this document. */
- std::list<Glib::ustring> _selected;
/** \brief A document cache if we were passed one. */
Implementation::ImplementationDocumentCache * _docCache;
=== modified file 'src/extension/implementation/script.cpp'
--- src/extension/implementation/script.cpp 2016-06-03 07:50:21 +0000
+++ src/extension/implementation/script.cpp 2017-05-31 00:24:00 +0000
@@ -422,11 +422,29 @@
SPDesktop *desktop = (SPDesktop *) view;
sp_namedview_document_from_window(desktop);
-
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool sort_attributes = prefs->getBool("/options/svgoutput/sort_attributes", false);
+ bool incorrect_style_properties_remove = prefs->getBool("/options/svgoutput/incorrect_style_properties_remove", false);
+ bool incorrect_attributes_remove = prefs->getBool("/options/svgoutput/incorrect_attributes_remove", false);
+ bool usenamedcolors = prefs->getBool("/options/svgoutput/usenamedcolors", false);
+ bool forcerepeatcommands = prefs->getBool("/options/svgoutput/forcerepeatcommands", false);
+ bool style_defaults_remove = prefs->getBool("/options/svgoutput/style_defaults_remove", false);
+ prefs->setBool("/options/svgoutput/sort_attributes", false);
+ prefs->setBool("/options/svgoutput/incorrect_style_properties_remove", false);
+ prefs->setBool("/options/svgoutput/incorrect_attributes_remove", false);
+ prefs->setBool("/options/svgoutput/usenamedcolors", false);
+ prefs->setBool("/options/svgoutput/forcerepeatcommands", false);
+ prefs->setBool("/options/svgoutput/style_defaults_remove", false);
Inkscape::Extension::save(
Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
view->doc(), _filename.c_str(), false, false, false, Inkscape::Extension::FILE_SAVE_METHOD_TEMPORARY);
+ prefs->setBool("/options/svgoutput/sort_attributes", sort_attributes);
+ prefs->setBool("/options/svgoutput/incorrect_style_properties_remove", incorrect_style_properties_remove);
+ prefs->setBool("/options/svgoutput/incorrect_attributes_remove", incorrect_attributes_remove);
+ prefs->setBool("/options/svgoutput/usenamedcolors", usenamedcolors);
+ prefs->setBool("/options/svgoutput/forcerepeatcommands", forcerepeatcommands);
+ prefs->setBool("/options/svgoutput/style_defaults_remove", style_defaults_remove);
return;
}
@@ -688,59 +706,14 @@
/// \todo Popup dialog here
return;
}
-
- std::vector<SPItem*> selected =
- desktop->getSelection()->itemList(); //desktop should not be NULL since doc was checked and desktop is a casted pointer
- for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); ++x){
- Glib::ustring selected_id;
- selected_id += "--id=";
- selected_id += (*x)->getId();
- params.push_front(selected_id);
- }
-
- {//add selected nodes
- Inkscape::UI::Tools::NodeTool *tool = 0;
- if (SP_ACTIVE_DESKTOP ) {
- Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
- if (INK_IS_NODE_TOOL(ec)) {
- tool = static_cast<Inkscape::UI::Tools::NodeTool*>(ec);
- }
- }
-
- if(tool){
- Inkscape::UI::ControlPointSelection *cps = tool->_selected_nodes;
- for (Inkscape::UI::ControlPointSelection::iterator i = cps->begin(); i != cps->end(); ++i) {
- Inkscape::UI::Node *node = dynamic_cast<Inkscape::UI::Node*>(*i);
- if (node) {
- std::string id = node->nodeList().subpathList().pm().item()->getId();
-
- int sp = 0;
- bool found_sp = false;
- for(Inkscape::UI::SubpathList::iterator i = node->nodeList().subpathList().begin(); i != node->nodeList().subpathList().end(); ++i,++sp){
- if(&**i == &(node->nodeList())){
- found_sp = true;
- break;
- }
- }
- int nl=0;
- bool found_nl = false;
- for (Inkscape::UI::NodeList::iterator j = node->nodeList().begin(); j != node->nodeList().end(); ++j, ++nl){
- if(&*j==node){
- found_nl = true;
- break;
- }
- }
- std::ostringstream ss;
- ss<< "--selected-nodes=" << id << ":" << sp << ":" << nl;
- Glib::ustring selected = ss.str();
-
- if(found_nl && found_sp)params.push_front(selected);
- else g_warning("Something went wrong while trying to pass selected nodes to extension. Please report a bug.");
- }
- }
- }
- }//end add selected nodes
-
+ if (desktop) {
+ Inkscape::Selection * selection = desktop->getSelection();
+ if (!selection->isEmpty()) {
+ selection->setBackup();
+ }
+ params = selection->params;
+ module->paramListString(params);
+ }
file_listener fileout;
int data_read = execute(command, params, dc->_filename, fileout);
fileout.toFile(tempfilename_out);
@@ -784,6 +757,7 @@
layer = document->getObjectById(g_quark_to_string(nv->default_layer_id));
}
}
+ desktop->showGrids(nv->grids_visible);
}
sp_namedview_update_layers_from_document(desktop);
@@ -792,6 +766,14 @@
//set the current layer
desktop->setCurrentLayer(layer);
}
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ Inkscape::Selection * selection = desktop->getSelection();
+ if (selection && selection->isEmpty() && !desktop->on_live_extension) {
+ selection->restoreBackup();
+ selection->emptyBackup();
+ }
+ }
}
mydoc->release();
}
@@ -827,12 +809,10 @@
g_warning("Error on copy_doc: NULL pointer input.");
return;
}
-
// For copying attributes in root and in namedview
using Inkscape::Util::List;
using Inkscape::XML::AttributeRecord;
std::vector<gchar const *> attribs;
-
// Must explicitly copy root attributes. This must be done first since
// copying grid lines calls "SPGuide::set()" which needs to know the
// width, height, and viewBox of the root element.
@@ -853,80 +833,33 @@
oldroot->setAttribute(name, newroot->attribute(name));
}
-
// Question: Why is the "sodipodi:namedview" special? Treating it as a normal
// elmement results in crashes.
// Seems to be a bug:
// http://inkscape.13.x6.nabble.com/Effect-that-modifies-the-document-properties-tt2822126.html
std::vector<Inkscape::XML::Node *> delete_list;
- Inkscape::XML::Node * oldroot_namedview = NULL;
- Inkscape::XML::Node * newroot_namedview = NULL;
// Make list
for (Inkscape::XML::Node * child = oldroot->firstChild();
child != NULL;
child = child->next()) {
if (!strcmp("sodipodi:namedview", child->name())) {
- oldroot_namedview = child;
for (Inkscape::XML::Node * oldroot_namedview_child = child->firstChild();
oldroot_namedview_child != NULL;
oldroot_namedview_child = oldroot_namedview_child->next()) {
delete_list.push_back(oldroot_namedview_child);
}
- } else {
- delete_list.push_back(child);
+ break;
}
}
- if(!oldroot_namedview)
- {
- g_warning("Error on copy_doc: No namedview on destination document.");
- return;
- }
-
// Unparent (delete)
for (unsigned int i = 0; i < delete_list.size(); i++) {
sp_repr_unparent(delete_list[i]);
}
-
- // Copy
- for (Inkscape::XML::Node * child = newroot->firstChild();
- child != NULL;
- child = child->next()) {
- if (!strcmp("sodipodi:namedview", child->name())) {
- newroot_namedview = child;
- for (Inkscape::XML::Node * newroot_namedview_child = child->firstChild();
- newroot_namedview_child != NULL;
- newroot_namedview_child = newroot_namedview_child->next()) {
- oldroot_namedview->appendChild(newroot_namedview_child->duplicate(oldroot->document()));
- }
- } else {
- oldroot->appendChild(child->duplicate(oldroot->document()));
- }
- }
-
attribs.clear();
-
- // Must explicitly copy namedview attributes.
- // Make a list of all attributes of the old namedview node.
- for (List<AttributeRecord const> iter = oldroot_namedview->attributeList(); iter; ++iter) {
- attribs.push_back(g_quark_to_string(iter->key));
- }
-
- // Delete the attributes of the old namedview node.
- for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); ++it) {
- oldroot_namedview->setAttribute(*it, NULL);
- }
-
- // Set the new attributes.
- for (List<AttributeRecord const> iter = newroot_namedview->attributeList(); iter; ++iter) {
- gchar const *name = g_quark_to_string(iter->key);
- oldroot_namedview->setAttribute(name, newroot_namedview->attribute(name));
- }
-
- /** \todo Restore correct layer */
- /** \todo Restore correct selection */
+ oldroot->mergeFrom(newroot, "id", true, true);
}
/** \brief This function checks the stderr file, and if it has data,
=== modified file 'src/extension/internal/bitmap/imagemagick.cpp'
--- src/extension/internal/bitmap/imagemagick.cpp 2015-12-09 20:01:20 +0000
+++ src/extension/internal/bitmap/imagemagick.cpp 2017-05-31 00:25:18 +0000
@@ -65,6 +65,16 @@
_imageItems(NULL)
{
SPDesktop *desktop = (SPDesktop*)view;
+ Inkscape::Selection * selection = NULL;
+ if (desktop) {
+ selection = desktop->getSelection();
+ if (selection && !selection->params.empty()) {
+ selection->restoreBackup();
+ if (!desktop->on_live_extension) {
+ selection->emptyBackup();
+ }
+ }
+ }
const std::vector<SPItem*> selectedItemList = desktop->selection->itemList();
int selectCount = selectedItemList.size();
=== modified file 'src/extension/internal/bluredge.cpp'
--- src/extension/internal/bluredge.cpp 2016-06-11 17:25:23 +0000
+++ src/extension/internal/bluredge.cpp 2017-05-31 00:25:13 +0000
@@ -53,7 +53,7 @@
void
BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *desktop, Inkscape::Extension::Implementation::ImplementationDocumentCache * /*docCache*/)
{
- Inkscape::Selection * selection = static_cast<SPDesktop *>(desktop)->selection;
+
float width = module->get_param_float("blur-width");
int steps = module->get_param_int("num-steps");
@@ -62,6 +62,17 @@
double old_offset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px");
// TODO need to properly refcount the items, at least
+ SPDesktop *deskt = static_cast<SPDesktop *>(desktop);
+ Inkscape::Selection * selection = NULL;
+ if (deskt) {
+ selection = deskt->selection;
+ if (selection && !selection->params.empty()) {
+ selection->restoreBackup();
+ if (!deskt->on_live_extension) {
+ selection->emptyBackup();
+ }
+ }
+ }
std::vector<SPItem*> items(selection->itemList());
selection->clear();
=== modified file 'src/extension/internal/filter/filter.cpp'
--- src/extension/internal/filter/filter.cpp 2016-11-11 20:30:37 +0000
+++ src/extension/internal/filter/filter.cpp 2017-05-31 00:25:26 +0000
@@ -122,8 +122,17 @@
}
//printf("Calling filter effect\n");
- Inkscape::Selection * selection = ((SPDesktop *)document)->selection;
-
+ SPDesktop *desktop = (SPDesktop *)document;
+ Inkscape::Selection * selection = NULL;
+ if (desktop) {
+ selection = desktop->selection;
+ if (selection && !selection->params.empty()) {
+ selection->restoreBackup();
+ if (!desktop->on_live_extension) {
+ selection->emptyBackup();
+ }
+ }
+ }
// TODO need to properly refcount the items, at least
std::vector<SPItem*> items(selection->itemList());
=== modified file 'src/extension/internal/grid.cpp'
--- src/extension/internal/grid.cpp 2016-06-11 17:25:23 +0000
+++ src/extension/internal/grid.cpp 2017-05-31 00:25:34 +0000
@@ -87,7 +87,17 @@
void
Grid::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document, Inkscape::Extension::Implementation::ImplementationDocumentCache * /*docCache*/)
{
- Inkscape::Selection * selection = ((SPDesktop *)document)->selection;
+ SPDesktop *desktop = ((SPDesktop *)document);
+ Inkscape::Selection * selection = NULL;
+ if (desktop) {
+ selection = desktop->getSelection();
+ if (selection && !selection->params.empty()) {
+ selection->restoreBackup();
+ if (!desktop->on_live_extension) {
+ selection->emptyBackup();
+ }
+ }
+ }
Geom::Rect bounding_area = Geom::Rect(Geom::Point(0,0), Geom::Point(100,100));
if (selection->isEmpty()) {
=== modified file 'src/extension/prefdialog.cpp'
--- src/extension/prefdialog.cpp 2016-06-11 17:25:23 +0000
+++ src/extension/prefdialog.cpp 2017-06-04 19:49:54 +0000
@@ -19,6 +19,8 @@
// Used to get SP_ACTIVE_DESKTOP
#include "inkscape.h"
#include "desktop.h"
+#include "document.h"
+#include "document-undo.h"
#include "effect.h"
#include "implementation/implementation.h"
@@ -64,7 +66,13 @@
controls = _effect->get_imp()->prefs_effect(_effect, SP_ACTIVE_DESKTOP, &_signal_param_change, NULL);
_signal_param_change.connect(sigc::mem_fun(this, &PrefDialog::param_change));
}
-
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ Inkscape::Selection * selection = desktop->getSelection();
+ if (selection) {
+ selection->emptyBackup();
+ }
+ }
hbox->pack_start(*controls, true, true, 6);
hbox->show();
@@ -140,10 +148,14 @@
if (_effect != NULL && _effect->no_live_preview) {
set_modal(false);
}
-
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gint transient_policy = prefs->getIntLimited( "/options/transientpolicy/value", 1, 0, 2);
+ prefs->setInt( "/options/transientpolicy/value", 0);
GtkWidget *dlg = GTK_WIDGET(gobj());
sp_transientize(dlg);
-
+ prefs->setInt( "/options/transientpolicy/value", transient_policy);
+ set_position(Gtk::WindowPosition::WIN_POS_CENTER_ON_PARENT);
+ set_modal(false);
return;
}
@@ -196,11 +208,28 @@
void
PrefDialog::preview_toggle (void) {
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPDocument *document = SP_ACTIVE_DOCUMENT;
+ Inkscape::Selection * selection = NULL;
+ bool modified = document->isModifiedSinceSave();
+ if(desktop) {
+ selection = desktop->getSelection();
+ if (!selection->isEmpty()) {
+ selection->setBackup();
+ }
+ }
if(_param_preview->get_bool(NULL, NULL)) {
- set_modal(true);
if (_exEnv == NULL) {
+ set_modal(true);
+ if (desktop && selection) {
+ desktop->on_live_extension = true;
+
+ }
_exEnv = new ExecutionEnv(_effect, SP_ACTIVE_DESKTOP, NULL, false, false);
_exEnv->run();
+ if (desktop && selection) {
+ selection->clear();
+ }
}
} else {
set_modal(false);
@@ -209,8 +238,13 @@
_exEnv->undo();
delete _exEnv;
_exEnv = NULL;
+ if (desktop && selection) {
+ selection->restoreBackup();
+ desktop->on_live_extension = false;
+ }
}
}
+ document->setModifiedSinceSave(modified);
}
void
@@ -231,9 +265,12 @@
bool
PrefDialog::param_timer_expire (void) {
if (_exEnv != NULL) {
+ SPDocument *document = SP_ACTIVE_DOCUMENT;
+ bool modified = document->isModifiedSinceSave();
_exEnv->cancel();
_exEnv->undo();
_exEnv->run();
+ document->setModifiedSinceSave(modified);
}
return false;
@@ -243,12 +280,12 @@
PrefDialog::on_response (int signal) {
if (signal == Gtk::RESPONSE_OK) {
if (_exEnv == NULL) {
- if (_effect != NULL) {
- _effect->effect(SP_ACTIVE_DESKTOP);
- } else {
- // Shutdown run()
- return;
- }
+ if (_effect != NULL) {
+ _effect->effect(SP_ACTIVE_DESKTOP);
+ } else {
+ // Shutdown run()
+ return;
+ }
} else {
if (_exEnv->wait()) {
_exEnv->commit();
@@ -257,6 +294,7 @@
}
delete _exEnv;
_exEnv = NULL;
+
}
}
@@ -267,7 +305,16 @@
if ((signal == Gtk::RESPONSE_CANCEL || signal == Gtk::RESPONSE_DELETE_EVENT) && _effect != NULL) {
delete this;
}
-
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::Selection * selection = NULL;
+ if(desktop) {
+ selection = desktop->getSelection();
+ desktop->on_live_extension = false;
+ if (selection && selection->isEmpty()) {
+ selection->restoreBackup();
+ selection->emptyBackup();
+ }
+ }
return;
}
=== modified file 'src/selection.cpp'
--- src/selection.cpp 2016-02-08 07:32:51 +0000
+++ src/selection.cpp 2017-06-04 04:25:27 +0000
@@ -22,6 +22,7 @@
#include "macros.h"
#include "inkscape.h"
#include "document.h"
+#include "desktop.h"
#include "layer-model.h"
#include "selection.h"
#include <2geom/rect.h>
@@ -34,6 +35,12 @@
#include "box3d.h"
#include "box3d.h"
#include "persp3d.h"
+#include "ui/tools/node-tool.h"
+#include "ui/tool/multi-path-manipulator.h"
+#include "ui/tool/path-manipulator.h"
+#include "ui/tool/control-point-selection.h"
+#include "sp-path.h"
+#include "sp-defs.h"
#include <sigc++/functors/mem_fun.h>
@@ -541,6 +548,125 @@
return parents.size();
}
+void
+Selection::emptyBackup(){
+ _selected_ids.clear();
+ _seldata.clear();
+ params.clear();
+}
+
+void
+Selection::setBackup ()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ std::vector<SPItem*> selected_items = itemList();
+ _selected_ids.clear();
+ _seldata.clear();
+ params.clear();
+ for(std::vector<SPItem*>::const_iterator x = selected_items.begin(); x != selected_items.end(); ++x){
+ std::string selected_id;
+ selected_id += "--id=";
+ selected_id += (*x)->getId();
+ params.push_front(selected_id);
+ _selected_ids.push_back((*x)->getId());
+ }
+ Inkscape::UI::Tools::NodeTool *tool = 0;
+
+ Inkscape::UI::Tools::ToolBase *ec = desktop->event_context;
+ if (INK_IS_NODE_TOOL(ec)) {
+ tool = static_cast<Inkscape::UI::Tools::NodeTool*>(ec);
+ }
+ if(tool){
+ Inkscape::UI::ControlPointSelection *cps = tool->_selected_nodes;
+ std::list<Inkscape::UI::SelectableControlPoint *> points_list = cps->_points_list;
+ for (std::list<Inkscape::UI::SelectableControlPoint *>::iterator i = points_list.begin(); i != points_list.end(); ++i) {
+ Inkscape::UI::Node *node = dynamic_cast<Inkscape::UI::Node*>(*i);
+ if (node) {
+ std::string id = node->nodeList().subpathList().pm().item()->getId();
+
+ int sp = 0;
+ bool found_sp = false;
+ for(Inkscape::UI::SubpathList::iterator i = node->nodeList().subpathList().begin(); i != node->nodeList().subpathList().end(); ++i,++sp){
+ if(&**i == &(node->nodeList())){
+ found_sp = true;
+ break;
+ }
+ }
+ int nl=0;
+ bool found_nl = false;
+ for (Inkscape::UI::NodeList::iterator j = node->nodeList().begin(); j != node->nodeList().end(); ++j, ++nl){
+ if(&*j==node){
+ found_nl = true;
+ break;
+ }
+ }
+ std::ostringstream ss;
+ ss<< "--selected-nodes=" << id << ":" << sp << ":" << nl;
+ Glib::ustring selected_nodes = ss.str();
+
+ if(found_nl && found_sp) {
+ _seldata.push_back(std::make_pair(id,std::make_pair(sp,nl)));
+ params.push_back(selected_nodes);
+ } else {
+ g_warning("Something went wrong while trying to pass selected nodes to extension. Please report a bug.");
+ }
+ }
+ }
+ }
+ }//end add selected nodes
+}
+
+void
+Selection::restoreBackup()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ Inkscape::UI::Tools::NodeTool *tool = 0;
+ Inkscape::UI::Tools::ToolBase *ec = desktop->event_context;
+ if (INK_IS_NODE_TOOL(ec)) {
+ tool = static_cast<Inkscape::UI::Tools::NodeTool*>(ec);
+ }
+ clear();
+ std::vector<std::string>::reverse_iterator rit = _selected_ids.rbegin();
+ for (; rit!= _selected_ids.rend(); ++rit){
+ SPObject * obj = desktop->doc()->getObjectById(rit->c_str());
+ SPDefs * defs = desktop->getDocument()->getDefs();
+ if (obj && !defs->isAncestorOf(obj)) {
+ add(obj);
+ }
+ }
+ if (tool) {
+ Inkscape::UI::ControlPointSelection *cps = tool->_selected_nodes;
+ cps->selectAll();
+ std::list<Inkscape::UI::SelectableControlPoint *> points_list = cps->_points_list;
+ cps->clear();
+ Inkscape::UI::Node * node = dynamic_cast<Inkscape::UI::Node*>(*points_list.begin());
+ if (node) {
+ Inkscape::UI::SubpathList sp = node->nodeList().subpathList();
+ for (std::vector<std::pair<std::string, std::pair<int, int> > >::iterator l = _seldata.begin(); l != _seldata.end(); ++l) {
+ SPPath * path = dynamic_cast<SPPath *>(desktop->doc()->getObjectById(l->first));
+ gint sp_count = 0;
+ for (Inkscape::UI::SubpathList::iterator j = sp.begin(); j != sp.end(); ++j, ++sp_count) {
+ if(sp_count == l->second.first) {
+ gint nt_count = 0;
+ for (Inkscape::UI::NodeList::iterator k = (*j)->begin(); k != (*j)->end(); ++k, ++nt_count) {
+ if(nt_count == l->second.second) {
+ k->select(true);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ points_list.clear();
+ }
+ }
+}
+
+
}
/*
=== modified file 'src/selection.h'
--- src/selection.h 2015-04-29 22:29:17 +0000
+++ src/selection.h 2017-05-31 00:21:11 +0000
@@ -328,13 +328,29 @@
{
return _modified_signal.slots().insert(_modified_signal.slots().begin(), slot);
}
+ /**
+ * Set a backup of current selection and store it also to be command line readable by extension system
+ */
+ void setBackup();
+ /**
+ * Clear backup of current selection
+ */
+ void emptyBackup();
+ /**
+ * Restore a selection from a existing backup
+ */
+ void restoreBackup();
+ /**
+ * Here store a paramlist when set backup
+ */
+ std::list<std::string> params;
private:
/** no copy. */
Selection(Selection const &);
/** no assign. */
void operator=(Selection const &);
-
+
/** Issues modification notification signals. */
static int _emit_modified(Selection *selection);
/** Schedules an item modification signal to be sent. */
@@ -381,7 +397,8 @@
SPObject* _selection_context;
unsigned int _flags;
unsigned int _idle;
-
+ std::vector<std::pair<std::string, std::pair<int, int> > > _seldata;
+ std::vector<std::string> _selected_ids;
std::map<SPObject *, sigc::connection> _modified_connections;
std::map<SPObject *, sigc::connection> _release_connections;
sigc::connection _context_release_connection;
=== modified file 'src/ui/tool/control-point-selection.h'
--- src/ui/tool/control-point-selection.h 2016-03-13 23:50:24 +0000
+++ src/ui/tool/control-point-selection.h 2017-05-30 21:15:29 +0000
@@ -118,6 +118,8 @@
void getOriginalPoints(std::vector<Inkscape::SnapCandidatePoint> &pts);
void getUnselectedPoints(std::vector<Inkscape::SnapCandidatePoint> &pts);
void setOriginalPoints();
+ //the purpose of this list is to keep track of first and last selected
+ std::list<SelectableControlPoint *> _points_list;
private:
// The functions below are invoked from SelectableControlPoint.
@@ -141,8 +143,7 @@
double _rotationRadius(Geom::Point const &);
set_type _points;
- //the purpose of this list is to keep track of first and last selected
- std::list<SelectableControlPoint *> _points_list;
+
set_type _all_points;
INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Point> _original_positions;
INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Affine> _last_trans;
=== modified file 'src/ui/tool/selectable-control-point.cpp'
--- src/ui/tool/selectable-control-point.cpp 2014-03-27 01:33:44 +0000
+++ src/ui/tool/selectable-control-point.cpp 2017-05-30 21:15:29 +0000
@@ -87,6 +87,15 @@
return true;
}
+void SelectableControlPoint::select(bool toselect)
+{
+ if (toselect) {
+ _selection.insert(this);
+ } else {
+ _selection.erase(this);
+ }
+}
+
void SelectableControlPoint::_takeSelection()
{
_selection.clear();
=== modified file 'src/ui/tool/selectable-control-point.h'
--- src/ui/tool/selectable-control-point.h 2014-08-08 20:20:44 +0000
+++ src/ui/tool/selectable-control-point.h 2017-05-30 21:15:29 +0000
@@ -28,8 +28,10 @@
virtual Geom::Rect bounds() const {
return Geom::Rect(position(), position());
}
+ virtual void select(bool toselect);
friend class NodeList;
+
protected:
SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
=== modified file 'src/xml/node.h'
--- src/xml/node.h 2014-12-16 14:05:47 +0000
+++ src/xml/node.h 2017-05-30 21:15:29 +0000
@@ -384,6 +384,20 @@
*/
virtual void changeOrder(Node *child, Node *after)=0;
+ /**
+ * @brief Remove all elements that not in src node
+ * @param src The node to check for elemments into this node
+ * @param key The attribute to use as the identity attribute
+ */
+ virtual void cleanOriginal(Node *src, gchar const *key)=0;
+
+
+ /**
+ * @brief Compare 2 nodes equality
+ * @param other The other node to compare
+ * @param recursive Recursive mode check
+ */
+ virtual bool equal(Node const *other, bool recursive)=0;
/**
* @brief Merge all children of another node with the current
*
@@ -397,8 +411,11 @@
*
* @param src The node to merge into this node
* @param key The attribute to use as the identity attribute
+ * @param noid If true process noid items
+ * @param key If clean callback to cleanOriginal
*/
- virtual void mergeFrom(Node const *src, char const *key)=0;
+
+ virtual void mergeFrom(Node const *src, char const *key, bool extension = false, bool clean = false)=0;
/*@}*/
=== modified file 'src/xml/simple-node.cpp'
--- src/xml/simple-node.cpp 2014-12-16 14:05:47 +0000
+++ src/xml/simple-node.cpp 2017-05-30 21:15:29 +0000
@@ -318,7 +318,7 @@
// Check usefulness of attributes on elements in the svg namespace, optionally don't add them to tree.
Glib::ustring element = g_quark_to_string(_name);
- // g_message("setAttribute: %s: %s: %s", element.c_str(), name, value);
+ //g_message("setAttribute: %s: %s: %s", element.c_str(), name, value);
gchar* cleaned_value = g_strdup( value );
// Only check elements in SVG name space and don't block setting attribute to NULL.
@@ -648,28 +648,112 @@
}
}
-void SimpleNode::mergeFrom(Node const *src, gchar const *key) {
+void SimpleNode::cleanOriginal(Node *src, gchar const *key){
+ std::vector<Node *> to_delete;
+ for ( Node *child = this->firstChild() ; child != NULL ; child = child->next() )
+ {
+ gchar const *id = child->attribute(key);
+ if (id) {
+ Node *rch = sp_repr_lookup_child(src, key, id);
+ if (rch) {
+ child->cleanOriginal(rch, key);
+ } else {
+ to_delete.push_back(child);
+ }
+ } else {
+ to_delete.push_back(child);
+ }
+ }
+ for ( std::vector<Node *>::iterator i = to_delete.begin(); i != to_delete.end(); ++i) {
+ removeChild(*i);
+ }
+}
+
+bool SimpleNode::equal(Node const *other, bool recursive) {
+ if(strcmp(name(),other->name())!= 0){
+ return false;
+ }
+ if (!(strcmp("sodipodi:namedview", name()))) {
+ return true;
+ }
+ guint orig_length = 0;
+ guint other_length = 0;
+
+ if(content() && other->content() && strcmp(content(), other->content()) != 0){
+ return false;
+ }
+ for (List<AttributeRecord const> orig_attr = attributeList(); orig_attr; ++orig_attr) {
+ for (List<AttributeRecord const> other_attr = other->attributeList(); other_attr; ++other_attr) {
+ const gchar * key_orig = g_quark_to_string(orig_attr->key);
+ const gchar * key_other = g_quark_to_string(other_attr->key);
+ if (!strcmp(key_orig, key_other) &&
+ !strcmp(orig_attr->value, other_attr->value))
+ {
+ other_length++;
+ break;
+ }
+ }
+ orig_length++;
+ }
+ if (orig_length != other_length) {
+ return false;
+ }
+ if (recursive) {
+ //NOTE: for faster the childs need to be in the same order
+ Node const *other_child = other->firstChild();
+ for ( Node *child = firstChild();
+ child;
+ child = child->next())
+ {
+ if (!child->equal(other_child, recursive)) {
+ return false;
+ }
+ other_child = other_child->next();
+ if(!other_child) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void SimpleNode::mergeFrom(Node const *src, gchar const *key, bool extension, bool clean) {
g_return_if_fail(src != NULL);
g_return_if_fail(key != NULL);
g_assert(src != this);
setContent(src->content());
+ if(_parent) {
+ setPosition(src->position());
+ }
+
+ if (clean) {
+ Node * srcp = const_cast<Node *>(src);
+ cleanOriginal(srcp, key);
+ }
for ( Node const *child = src->firstChild() ; child != NULL ; child = child->next() )
{
gchar const *id = child->attribute(key);
if (id) {
Node *rch=sp_repr_lookup_child(this, key, id);
- if (rch) {
- rch->mergeFrom(child, key);
+ if (rch && (!extension || rch->equal(child, false))) {
+ rch->mergeFrom(child, key, extension);
} else {
+ if(rch) {
+ removeChild(rch);
+ }
+ guint pos = child->position();
rch = child->duplicate(_document);
appendChild(rch);
+ rch->setPosition(pos);
rch->release();
}
} else {
+ guint pos = child->position();
Node *rch=child->duplicate(_document);
appendChild(rch);
+ rch->setPosition(pos);
rch->release();
}
}
=== modified file 'src/xml/simple-node.h'
--- src/xml/simple-node.h 2014-12-16 14:05:47 +0000
+++ src/xml/simple-node.h 2017-05-30 21:15:29 +0000
@@ -91,7 +91,9 @@
char const *content() const;
void setContent(char const *value);
- void mergeFrom(Node const *src, char const *key);
+ void cleanOriginal(Node *src, gchar const *key);
+ bool equal(Node const *other, bool recursive);
+ void mergeFrom(Node const *src, char const *key, bool extension = false, bool clean = false);
Inkscape::Util::List<AttributeRecord const> attributeList() const {
return _attributes;
-
Testing patch v07 with Inkscape 0.92.x r15429, I noticed that with the patched build, it is no longer possible for extensions to actually remove existing objects from the document.
Simple debug extension for testing: download
* delete_objects.inx
* delete_objects.py
from https://gitlab.com/su-v/inx-debug/tree/master/src
I noticed this while testing boolean operations (https://gitlab.com/su-v/inx-pathops), where - depending on the source, the top-most path, and the chosen operation - sometimes objects are expected to "disappear" in the final result.
The unpatched build (0.92.x r15429) does not expose this issue.
A second (more serious, AFAIU) side-effect of the proposed changes: if the extension returns an object with an original id, but e.g. a different SVG type (originally rect, or circle; now path), or adds new attributes, then the attributes are "merged" (not replaced), while the element type is unchanged, which produces incorrect results (and invalid (?) SVG elements).
Exposed again by the pathops extension which converts shapes (or text) to paths, while preserving the id. It is even worse if the document does not use 'px' (1 SVG uu ~ 1 CSS px) as document scale - the hybrid elements (for example a rect with the original rect attributes (x, y, width, height) and new attributes (path data 'd', a transform attribute) merged in) displays incorrectly scaled and positioned.
ISTM that the proposed change (as is) breaks (some) extensions and may produce corrupted results in those cases.
I will try to create a reduced test case which does not rely on the inx-pathops extension (and an externally spawned inkscape process to modify elements).
Simple debug extension for testing comment #2: download
* convert_rects.inx
* convert_rects.py
from https://gitlab.com/su-v/inx-debug/tree/master/src
Draw a rectangle, inspect its attributes in the XML Editor. Select it and apply the debug extension: notice that with patched build, the resulting object is still a rect, but one with a 'd' attribute added. Inkscape renders this result still as rectangle, even though the extension's intent was to produce a path that describes the rect's geometric bbox (parallel to x-, y-axes, ignoring attributes like rounded corners), while preserving the style and the original id.
su_v: this bugs fixed in last patch v09
Testing patch v09 with 0.92.x r15429:
It is not possible to change the stack order of objects via extension - use the bundled 'Extensions > Arrange > Restack' to reproduce.
Works as expected with unpatched build.
Testing patch v09 with 0.92.x r15429:
An extension which uses one of the selected objects (e.g. the top-most path) to clip another selected object (e.g. a bitmap image) will result in having the clipping path (which is now in the defs, inside a 'clipPath' element) selected after the document is reloaded from the extension. Objects in the defs section are normally not selectable (on-canvas) or part of such a selection.
This likely is exposed in various different scenarios which are difficult to anticipate (certainly not limited to clips).
Both bugs seems solved, also added selection nodes, once we are comfortable with this i do a migration to the 0.93 branch and start with the improvements you point in the branch merge.
Also there is a problem to hide the selection because we lost it. We have two solutions one is create a static var but seems a bad idea, other is store the items id in preferences...
v10 failed to compile on legacy Mac OS X 10.7: see
https://gist.github.com/su-v/065e9df40024d92df156ee14bca16068
for details.
I will test the fixes and the changes related to selected nodes later this week and report back (here or on irc).
Tests comparing actual time spent to reload large files returned from script extensions are still pending (I did not have the time during the weekend for it, unfortunately).
Updated to v1.1 with your fixes
Thanks!
Testing patch v11 with 0.92.x r15432:
1) Crash with Objects, Layers dialog
Converting groups to sublayers (or sublayers to groups) crashes patched build if Objects dialog (or Layers dialog) was opened once earlier in the current session.
Simple debug extension to reproduce the crash: download
* groups_and_layers.inx
* groups_and_layers.py
from https://gitlab.com/su-v/inx-debug/tree/master/src
The 'About' tab of the extension's dialog has more details about how to reproduce the crash.
It seems likely to me that similar crashes can possibly be triggered by signals managed in/by other dialogs, but I haven't tested beyond what is detailed above at the moment.
2) Selected nodes
2.1) Unrelated to patch:
If the preferences setting to sort attributes is set to true [1], inkscape 0.92.x does not provide information about selected nodes as command line arguments to the extension script (patched or unpatched build).
2.2) Selection order:
The order of the command line arguments passed to the extension script seems arbitrary, and most of the time does not match an explicit selection order the user made with the node tool (select one node, shift-click for each additional node). The extension 'Debug > Selected Nodes Info' can be used to visualize the order of the command line arguments (one per selected node) on-canvas.
2.3) Preserve selection:
The selected nodes remain highlighted when Live Preview is toggled on (not usable since canvas is blocked in preview mode), the selection however is lost when toggling Live Preview off again, unlike when applying the effect, which AFAICT retains the selected nodes based on the node index per sub-path. The extension 'Debug > Selected Nodes Modify' can be used to test retained node selection when adding or deleting selected nodes via extension.
Simple debug extensions: download
* selected_nodes_info.inx
* selected_nodes_info.py
* selected_nodes_modify.inx
* selected_nodes_modify.py
from https://gitlab.com/su-v/inx-debug/tree/master/src
3) Performance improvements
Tests still pending, sorry.
--
[1] commit which added the pref (without GUI, see src/preferences-skeleton.h):
https://bazaar.launchpad.net/~inkscape.dev/inkscape/trunk/revision/14980
thanks so much for testing!
Updated to v1.2
TODO: fix selected nodes part 2.1 and 2.2
Updated to v1.3
Fixed part 2.1 and 2.2.
Testing patch v12, v13 with 0.92.x r15432:
With v13, extensions cannot add new attributes to objects (e.g. a 'rx' to a rect with originally only a 'ry'; or a 'ry' to a rect with sharp corners (no 'rx', no 'ry' originally). AFAICT works as expected with v11, v12 and unpatched build.
Please let me know if you need a demo extension for this.
Fixed in 1.4. Thanks so much for your hard testing!
Thanks for the quick fix in v14.
Something I noticed in passing, but did not look further into yet or mention so far:
4) Live Preview
Toggling live preview on and off modifies document status (as modified), without entry in undo history (dialog), and not "undoable" with repeated undo commands - it is not possible to return to the 'clean' document state anymore. AFAICT this happens since patch v4 (it does not happen with v1; I don't have archived builds patched with v2 and v3 unfortunately).
Steps to reproduce:
1. Launch patched build of 0.92.x
2. In the new document, open 'Extensions > Render > Gear > Gear...'
3. Toggle Live Preview on
--> Document status changes (see '*' in the window title bar prefixed to the document name)
4. Toggle Live Preview off
--> Document status remains 'changed'
--> Closing the document prompts for saving changes
Does not reproduce with unpatched build 0.92.x r15432: toggling Live Preview on (and off again) does not affect the document status.
Fixed 4 in v1.5. Thanks for testing!
Testing patch v15 with 0.92.x r15432:
Live Preview now makes the document forget about earlier changes, and allows to close the document with unsaved changes (no prompt).
Steps to reproduce:
1) launch patched builds of 0.92.x (default prefs, default new document)
2) draw a rect, deselect
--> document is marked as modified
3) open 'Extensions > Render > Gear > Gear...'
4) toggle live preview on and off
--> document is no longer marked as modified, though the rect drawn earlier in step 2 was never saved.
Reproduces in new documents as well as when editing existing documents. This risks loss of data.
Fixed in v16. Apologyes for not test enoght. Thanks so much for your HARD work!
Testing patch v16 with 0.92.x r15432:
Three issues so far (based on using the patched build for otherwise unrelated work) to report:
1) inconsistencies with retained object selection order
2) failure to add/modify/delete XML comments (<!-- some text -->)
3) crash with specific preference settings when modifying (transforming) objects which have a custom rotation center
I'll provide details in separate follow-up comments.
1) inconsistencies with retained object selection order
Modifying a slice of the selection list ('slice' as in a subset of the selection; in Python: id_list[0:2] to take for example the first two items of a list) exposes that the order of the list is unexpectedly reshuffled (based on the slice indexes), both when previewing an effect or applying it. This can produce unexpected results depending on what an extension script does.
Simple debug extension: download
* object_selection_order.inx
* object_selection_order.py
from https://gitlab.com/su-v/inx-debug/tree/master/src
Two reduced test cases: download
* object-selection-order-1.svg
* object-selection-order-2.svg
from https://gitlab.com/su-v/inx-debug/tree/master/files
Steps to reproduce:
1) launch patched build with default prefs
2) open object-selection-order-2.svg
3) select all with 'Ctrl+A'
4) open 'Extensions > Debug > Object Selection Order'
5) with default settings, activate 'Live Preview'
--> the selection order as originally passed to the extension via command line arguments is superimposed with red labels centered on each object's geometric bbox. 'Ctrl+A' for me usually selects following the reversed stack order (the top-most object in the bottom-right corner has index '0', the bottom-most one in the top-left corner has '99'; the objects in the example are stacked in columns.
6) with live preview still active, switch to the next action «Color indexed selected object(s)».
--> based on the default slice indexes (0,1,1) this will recolor the first object (index '0') with a lighter reddish color.
7) repeatedly toggled Live Preview off and on again
--> watch what happens on-canvas: with each cycle, a different object is now passed as 'first' one to the extension script.
8) repeat above tests using other slice indices (e.g. with a longer, consecutive slice (0,10,1) or one with a larger increment (0,100,10), and compare different actions. De- and reselect between tests to start with a known initial state.
Notes:
* Only modifying selected objects triggers the reshuffling - adding text, or modifying other parts of the SVG source does not affect it.
* Some object types, or more likely their initial state, can affect the observed behavior: unstyled clones of rectangle with unset fill and stroke for example don't expose the issue when recoloring them, or hiding them. They do however also expose it when previewing the result of 'move to the defs section' (see action in the extension). The other test file (object-selection-order-1.svg) demonstrates such behavior.
* Differences to unpatched build of 0.92.x: unpatched builds also (and always have) reversed the selection order with each live preview cycle, but at least this was consistent, and more easily to anticipate. Now that the selection is retained after previewing or applying an extension, I think it is crucial that the behavior is consistent in all aspects.
2) failure to add/modify/delete XML comments (<!-- some text -->)
While investigating the circumstances of bug #1693578, I noticed that the patched build behaves differently with regard to manipulations of XML comments via extension scripts.
Simple debug extension: download
* add_comments.inx
* add_comments.py
from https://gitlab.com/su-v/inx-debug/tree/master/src
Use the extension in combination with the XML editor to monitor changes/results. The patched build can neither add nor delete comments (unless the entire parent container group is deleted), nor change e.g. their location within the stack order (append to or insert into the parent container, or a sibling group).
Off-topic:
As mentioned in bug #1693578, inkscape (patched or unpatched) temporarily fails to properly handle comments added to the document root - this aspect is not related to the patch, and not what the test case is about (the patched build disables updating XML comments via extension entirely).
3) crash with specific preference settings when modifying (transforming) objects which have a custom rotation center
This is an obscure one - it requires a combination of specific circumstances to reproduce.
1. Simple debug extension: download
* scale_objects.inx
* scale_objects.py
from https://gitlab.com/su-v/inx-debug/tree/master/src
2. Inkscape Preferences > Input/Output > SVG output:
Enable removing inappropriate or non-useful style properties on reading (or writing).
3. Create a drawing with an object (shape or path) which has such [inappropriate, non-useful] style properties. This can be for example:
- a short text (e.g. a single letter) converted to path (Shift+Ctrl+C), ungrouped (Ctrl+U) and combined (Ctrl+K)
- a shape or path which originally had a few non-standard stroke properties (e.g. rounded caps, joins), and the stroke color was removed later on (stroke:none), while keeping the other stroke-specific properties.
4. Custom rotation center: select an object from step (3) above, switch to the rotation handles and drag the object's rotation center to a custom location. Position the object near the SVG origin (inside the page area, near top-left page corner)
Steps to reproduce the crash:
1) Open 'Extensions > Debug > Scale Objects'
2) Select the object created in above steps
3) Duplicate the selection, repeat twice (Ctrl+A, Ctrl+D, Ctrl+A)
--> 4 objects in total are now selected
4) with default extension options, toggle on Live Preview
--> this will uniformly up-scale the four objects (with interpolated scale factor)
5) with Live Preview still toggled on, switch between the 3 available actions (scale uniformly XY, scale X only, scale Y only)
--> after the first or second switch to a different action, the patched build usually crashes.
The crash does not reproduce with unpatched 0.92.x r15432. The circumstances might be obscure, but I encountered it while working on unrelated things (so it's not entirely unlikely that it would be exposed to other users as well). Possibly the underlying issue is elsewhere in the code, and only exposed by the changes of the patch for retaining the object selection.
Dear suv. Thanks so much for your hard test!!!
The last 3 bugs seems fixed in r.17.
Also need to test ordering when elements are reordered and insert sets od 1,3 and 6 elements for example at "random position". You want to do this test? Its important because if do wrong results is hard to fix it.
Cheers, Jabier.
New code with v1.8
Updated to V20
Updated to V21
Updated to V22
Updated to V23
Updated to v24
Updated to v25
Updated to v26
V27
Created new branch to merge on master
Created a MR to master: https://gitlab.com/inkscape/inkscape/merge_requests/208
THANKS su_v!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!