1. === modified file 'src/desktop.cpp'
  2. --- src/desktop.cpp 2016-07-25 05:27:21 +0000
  3. +++ src/desktop.cpp 2017-06-04 04:46:56 +0000
  4. @@ -123,6 +123,7 @@
  5. waiting_cursor( false ),
  6. showing_dialogs ( false ),
  7. guides_active( false ),
  8. + on_live_extension(false),
  9. gr_item( NULL ),
  10. gr_point_type( POINT_LG_BEGIN ),
  11. gr_point_i( 0 ),
  12. === modified file 'src/desktop.h'
  13. --- src/desktop.h 2016-07-25 05:27:21 +0000
  14. +++ src/desktop.h 2017-06-04 04:49:21 +0000
  15. @@ -191,9 +191,9 @@
  16. unsigned int interaction_disabled_counter;
  17. bool waiting_cursor;
  18. bool showing_dialogs;
  19. -
  20. /// \todo fixme: This has to be implemented in different way */
  21. guint guides_active : 1;
  22. + bool on_live_extension;
  23. // storage for selected dragger used by GrDrag as it's
  24. // created and deleted by tools
  25. === modified file 'src/extension/execution-env.cpp'
  26. --- src/extension/execution-env.cpp 2016-04-12 10:35:15 +0000
  27. +++ src/extension/execution-env.cpp 2017-05-31 00:21:54 +0000
  28. @@ -23,6 +23,8 @@
  29. #include "selection.h"
  30. #include "effect.h"
  31. #include "document.h"
  32. +#include "desktop.h"
  33. +#include "inkscape.h"
  34. #include "document-undo.h"
  35. #include "desktop.h"
  36. #include "ui/view/view.h"
  37. @@ -54,19 +56,6 @@
  38. _show_working(show_working),
  39. _show_errors(show_errors)
  40. {
  41. - SPDesktop *desktop = (SPDesktop *)_doc;
  42. - sp_namedview_document_from_window(desktop);
  43. -
  44. - if (desktop != NULL) {
  45. - std::vector<SPItem*> selected = desktop->getSelection()->itemList();
  46. - for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); ++x){
  47. - Glib::ustring selected_id;
  48. - selected_id = (*x)->getId();
  49. - _selected.insert(_selected.end(), selected_id);
  50. - //std::cout << "Selected: " << selected_id << std::endl;
  51. - }
  52. - }
  53. -
  54. genDocCache();
  55. return;
  56. @@ -183,24 +172,14 @@
  57. void
  58. ExecutionEnv::reselect (void) {
  59. - if (_doc == NULL) { return; }
  60. - SPDocument * doc = _doc->doc();
  61. - if (doc == NULL) { return; }
  62. -
  63. - SPDesktop *desktop = (SPDesktop *)_doc;
  64. - sp_namedview_document_from_window(desktop);
  65. -
  66. - if (desktop == NULL) { return; }
  67. -
  68. - Inkscape::Selection * selection = desktop->getSelection();
  69. -
  70. - for (std::list<Glib::ustring>::iterator i = _selected.begin(); i != _selected.end(); ++i) {
  71. - SPObject * obj = doc->getObjectById(i->c_str());
  72. - if (obj != NULL) {
  73. - selection->add(obj);
  74. + SPDesktop *desktop = SP_ACTIVE_DESKTOP;
  75. + Inkscape::Selection * selection = NULL;
  76. + if(desktop) {
  77. + selection = desktop->getSelection();
  78. + if (!desktop->on_live_extension) {
  79. + selection->restoreBackup();
  80. }
  81. }
  82. -
  83. return;
  84. }
  85. === modified file 'src/extension/execution-env.h'
  86. --- src/extension/execution-env.h 2014-03-27 01:33:44 +0000
  87. +++ src/extension/execution-env.h 2017-05-30 21:15:29 +0000
  88. @@ -54,9 +54,6 @@
  89. Glib::RefPtr<Glib::MainLoop> _mainloop;
  90. /** \brief The document that we're working on. */
  91. Inkscape::UI::View::View * _doc;
  92. - /** \brief A list of the IDs of all the selected objects before
  93. - we started to work on this document. */
  94. - std::list<Glib::ustring> _selected;
  95. /** \brief A document cache if we were passed one. */
  96. Implementation::ImplementationDocumentCache * _docCache;
  97. === modified file 'src/extension/implementation/script.cpp'
  98. --- src/extension/implementation/script.cpp 2016-06-03 07:50:21 +0000
  99. +++ src/extension/implementation/script.cpp 2017-05-31 00:24:00 +0000
  100. @@ -422,11 +422,29 @@
  101. SPDesktop *desktop = (SPDesktop *) view;
  102. sp_namedview_document_from_window(desktop);
  103. -
  104. + Inkscape::Preferences *prefs = Inkscape::Preferences::get();
  105. + bool sort_attributes = prefs->getBool("/options/svgoutput/sort_attributes", false);
  106. + bool incorrect_style_properties_remove = prefs->getBool("/options/svgoutput/incorrect_style_properties_remove", false);
  107. + bool incorrect_attributes_remove = prefs->getBool("/options/svgoutput/incorrect_attributes_remove", false);
  108. + bool usenamedcolors = prefs->getBool("/options/svgoutput/usenamedcolors", false);
  109. + bool forcerepeatcommands = prefs->getBool("/options/svgoutput/forcerepeatcommands", false);
  110. + bool style_defaults_remove = prefs->getBool("/options/svgoutput/style_defaults_remove", false);
  111. + prefs->setBool("/options/svgoutput/sort_attributes", false);
  112. + prefs->setBool("/options/svgoutput/incorrect_style_properties_remove", false);
  113. + prefs->setBool("/options/svgoutput/incorrect_attributes_remove", false);
  114. + prefs->setBool("/options/svgoutput/usenamedcolors", false);
  115. + prefs->setBool("/options/svgoutput/forcerepeatcommands", false);
  116. + prefs->setBool("/options/svgoutput/style_defaults_remove", false);
  117. Inkscape::Extension::save(
  118. Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
  119. view->doc(), _filename.c_str(), false, false, false, Inkscape::Extension::FILE_SAVE_METHOD_TEMPORARY);
  120. + prefs->setBool("/options/svgoutput/sort_attributes", sort_attributes);
  121. + prefs->setBool("/options/svgoutput/incorrect_style_properties_remove", incorrect_style_properties_remove);
  122. + prefs->setBool("/options/svgoutput/incorrect_attributes_remove", incorrect_attributes_remove);
  123. + prefs->setBool("/options/svgoutput/usenamedcolors", usenamedcolors);
  124. + prefs->setBool("/options/svgoutput/forcerepeatcommands", forcerepeatcommands);
  125. + prefs->setBool("/options/svgoutput/style_defaults_remove", style_defaults_remove);
  126. return;
  127. }
  128. @@ -688,59 +706,14 @@
  129. /// \todo Popup dialog here
  130. return;
  131. }
  132. -
  133. - std::vector<SPItem*> selected =
  134. - desktop->getSelection()->itemList(); //desktop should not be NULL since doc was checked and desktop is a casted pointer
  135. - for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); ++x){
  136. - Glib::ustring selected_id;
  137. - selected_id += "--id=";
  138. - selected_id += (*x)->getId();
  139. - params.push_front(selected_id);
  140. - }
  141. -
  142. - {//add selected nodes
  143. - Inkscape::UI::Tools::NodeTool *tool = 0;
  144. - if (SP_ACTIVE_DESKTOP ) {
  145. - Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
  146. - if (INK_IS_NODE_TOOL(ec)) {
  147. - tool = static_cast<Inkscape::UI::Tools::NodeTool*>(ec);
  148. - }
  149. - }
  150. -
  151. - if(tool){
  152. - Inkscape::UI::ControlPointSelection *cps = tool->_selected_nodes;
  153. - for (Inkscape::UI::ControlPointSelection::iterator i = cps->begin(); i != cps->end(); ++i) {
  154. - Inkscape::UI::Node *node = dynamic_cast<Inkscape::UI::Node*>(*i);
  155. - if (node) {
  156. - std::string id = node->nodeList().subpathList().pm().item()->getId();
  157. -
  158. - int sp = 0;
  159. - bool found_sp = false;
  160. - for(Inkscape::UI::SubpathList::iterator i = node->nodeList().subpathList().begin(); i != node->nodeList().subpathList().end(); ++i,++sp){
  161. - if(&**i == &(node->nodeList())){
  162. - found_sp = true;
  163. - break;
  164. - }
  165. - }
  166. - int nl=0;
  167. - bool found_nl = false;
  168. - for (Inkscape::UI::NodeList::iterator j = node->nodeList().begin(); j != node->nodeList().end(); ++j, ++nl){
  169. - if(&*j==node){
  170. - found_nl = true;
  171. - break;
  172. - }
  173. - }
  174. - std::ostringstream ss;
  175. - ss<< "--selected-nodes=" << id << ":" << sp << ":" << nl;
  176. - Glib::ustring selected = ss.str();
  177. -
  178. - if(found_nl && found_sp)params.push_front(selected);
  179. - else g_warning("Something went wrong while trying to pass selected nodes to extension. Please report a bug.");
  180. - }
  181. - }
  182. - }
  183. - }//end add selected nodes
  184. -
  185. + if (desktop) {
  186. + Inkscape::Selection * selection = desktop->getSelection();
  187. + if (!selection->isEmpty()) {
  188. + selection->setBackup();
  189. + }
  190. + params = selection->params;
  191. + module->paramListString(params);
  192. + }
  193. file_listener fileout;
  194. int data_read = execute(command, params, dc->_filename, fileout);
  195. fileout.toFile(tempfilename_out);
  196. @@ -784,6 +757,7 @@
  197. layer = document->getObjectById(g_quark_to_string(nv->default_layer_id));
  198. }
  199. }
  200. + desktop->showGrids(nv->grids_visible);
  201. }
  202. sp_namedview_update_layers_from_document(desktop);
  203. @@ -792,6 +766,14 @@
  204. //set the current layer
  205. desktop->setCurrentLayer(layer);
  206. }
  207. + SPDesktop *desktop = SP_ACTIVE_DESKTOP;
  208. + if (desktop) {
  209. + Inkscape::Selection * selection = desktop->getSelection();
  210. + if (selection && selection->isEmpty() && !desktop->on_live_extension) {
  211. + selection->restoreBackup();
  212. + selection->emptyBackup();
  213. + }
  214. + }
  215. }
  216. mydoc->release();
  217. }
  218. @@ -827,12 +809,10 @@
  219. g_warning("Error on copy_doc: NULL pointer input.");
  220. return;
  221. }
  222. -
  223. // For copying attributes in root and in namedview
  224. using Inkscape::Util::List;
  225. using Inkscape::XML::AttributeRecord;
  226. std::vector<gchar const *> attribs;
  227. -
  228. // Must explicitly copy root attributes. This must be done first since
  229. // copying grid lines calls "SPGuide::set()" which needs to know the
  230. // width, height, and viewBox of the root element.
  231. @@ -853,80 +833,33 @@
  232. oldroot->setAttribute(name, newroot->attribute(name));
  233. }
  234. -
  235. // Question: Why is the "sodipodi:namedview" special? Treating it as a normal
  236. // elmement results in crashes.
  237. // Seems to be a bug:
  238. // http://inkscape.13.x6.nabble.com/Effect-that-modifies-the-document-properties-tt2822126.html
  239. std::vector<Inkscape::XML::Node *> delete_list;
  240. - Inkscape::XML::Node * oldroot_namedview = NULL;
  241. - Inkscape::XML::Node * newroot_namedview = NULL;
  242. // Make list
  243. for (Inkscape::XML::Node * child = oldroot->firstChild();
  244. child != NULL;
  245. child = child->next()) {
  246. if (!strcmp("sodipodi:namedview", child->name())) {
  247. - oldroot_namedview = child;
  248. for (Inkscape::XML::Node * oldroot_namedview_child = child->firstChild();
  249. oldroot_namedview_child != NULL;
  250. oldroot_namedview_child = oldroot_namedview_child->next()) {
  251. delete_list.push_back(oldroot_namedview_child);
  252. }
  253. - } else {
  254. - delete_list.push_back(child);
  255. + break;
  256. }
  257. }
  258. - if(!oldroot_namedview)
  259. - {
  260. - g_warning("Error on copy_doc: No namedview on destination document.");
  261. - return;
  262. - }
  263. -
  264. // Unparent (delete)
  265. for (unsigned int i = 0; i < delete_list.size(); i++) {
  266. sp_repr_unparent(delete_list[i]);
  267. }
  268. -
  269. - // Copy
  270. - for (Inkscape::XML::Node * child = newroot->firstChild();
  271. - child != NULL;
  272. - child = child->next()) {
  273. - if (!strcmp("sodipodi:namedview", child->name())) {
  274. - newroot_namedview = child;
  275. - for (Inkscape::XML::Node * newroot_namedview_child = child->firstChild();
  276. - newroot_namedview_child != NULL;
  277. - newroot_namedview_child = newroot_namedview_child->next()) {
  278. - oldroot_namedview->appendChild(newroot_namedview_child->duplicate(oldroot->document()));
  279. - }
  280. - } else {
  281. - oldroot->appendChild(child->duplicate(oldroot->document()));
  282. - }
  283. - }
  284. -
  285. attribs.clear();
  286. -
  287. - // Must explicitly copy namedview attributes.
  288. - // Make a list of all attributes of the old namedview node.
  289. - for (List<AttributeRecord const> iter = oldroot_namedview->attributeList(); iter; ++iter) {
  290. - attribs.push_back(g_quark_to_string(iter->key));
  291. - }
  292. -
  293. - // Delete the attributes of the old namedview node.
  294. - for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); ++it) {
  295. - oldroot_namedview->setAttribute(*it, NULL);
  296. - }
  297. -
  298. - // Set the new attributes.
  299. - for (List<AttributeRecord const> iter = newroot_namedview->attributeList(); iter; ++iter) {
  300. - gchar const *name = g_quark_to_string(iter->key);
  301. - oldroot_namedview->setAttribute(name, newroot_namedview->attribute(name));
  302. - }
  303. -
  304. - /** \todo Restore correct layer */
  305. - /** \todo Restore correct selection */
  306. + oldroot->mergeFrom(newroot, "id", true, true);
  307. }
  308. /** \brief This function checks the stderr file, and if it has data,
  309. === modified file 'src/extension/internal/bitmap/imagemagick.cpp'
  310. --- src/extension/internal/bitmap/imagemagick.cpp 2015-12-09 20:01:20 +0000
  311. +++ src/extension/internal/bitmap/imagemagick.cpp 2017-05-31 00:25:18 +0000
  312. @@ -65,6 +65,16 @@
  313. _imageItems(NULL)
  314. {
  315. SPDesktop *desktop = (SPDesktop*)view;
  316. + Inkscape::Selection * selection = NULL;
  317. + if (desktop) {
  318. + selection = desktop->getSelection();
  319. + if (selection && !selection->params.empty()) {
  320. + selection->restoreBackup();
  321. + if (!desktop->on_live_extension) {
  322. + selection->emptyBackup();
  323. + }
  324. + }
  325. + }
  326. const std::vector<SPItem*> selectedItemList = desktop->selection->itemList();
  327. int selectCount = selectedItemList.size();
  328. === modified file 'src/extension/internal/bluredge.cpp'
  329. --- src/extension/internal/bluredge.cpp 2016-06-11 17:25:23 +0000
  330. +++ src/extension/internal/bluredge.cpp 2017-05-31 00:25:13 +0000
  331. @@ -53,7 +53,7 @@
  332. void
  333. BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *desktop, Inkscape::Extension::Implementation::ImplementationDocumentCache * /*docCache*/)
  334. {
  335. - Inkscape::Selection * selection = static_cast<SPDesktop *>(desktop)->selection;
  336. +
  337. float width = module->get_param_float("blur-width");
  338. int steps = module->get_param_int("num-steps");
  339. @@ -62,6 +62,17 @@
  340. double old_offset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px");
  341. // TODO need to properly refcount the items, at least
  342. + SPDesktop *deskt = static_cast<SPDesktop *>(desktop);
  343. + Inkscape::Selection * selection = NULL;
  344. + if (deskt) {
  345. + selection = deskt->selection;
  346. + if (selection && !selection->params.empty()) {
  347. + selection->restoreBackup();
  348. + if (!deskt->on_live_extension) {
  349. + selection->emptyBackup();
  350. + }
  351. + }
  352. + }
  353. std::vector<SPItem*> items(selection->itemList());
  354. selection->clear();
  355. === modified file 'src/extension/internal/filter/filter.cpp'
  356. --- src/extension/internal/filter/filter.cpp 2016-11-11 20:30:37 +0000
  357. +++ src/extension/internal/filter/filter.cpp 2017-05-31 00:25:26 +0000
  358. @@ -122,8 +122,17 @@
  359. }
  360. //printf("Calling filter effect\n");
  361. - Inkscape::Selection * selection = ((SPDesktop *)document)->selection;
  362. -
  363. + SPDesktop *desktop = (SPDesktop *)document;
  364. + Inkscape::Selection * selection = NULL;
  365. + if (desktop) {
  366. + selection = desktop->selection;
  367. + if (selection && !selection->params.empty()) {
  368. + selection->restoreBackup();
  369. + if (!desktop->on_live_extension) {
  370. + selection->emptyBackup();
  371. + }
  372. + }
  373. + }
  374. // TODO need to properly refcount the items, at least
  375. std::vector<SPItem*> items(selection->itemList());
  376. === modified file 'src/extension/internal/grid.cpp'
  377. --- src/extension/internal/grid.cpp 2016-06-11 17:25:23 +0000
  378. +++ src/extension/internal/grid.cpp 2017-05-31 00:25:34 +0000
  379. @@ -87,7 +87,17 @@
  380. void
  381. Grid::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document, Inkscape::Extension::Implementation::ImplementationDocumentCache * /*docCache*/)
  382. {
  383. - Inkscape::Selection * selection = ((SPDesktop *)document)->selection;
  384. + SPDesktop *desktop = ((SPDesktop *)document);
  385. + Inkscape::Selection * selection = NULL;
  386. + if (desktop) {
  387. + selection = desktop->getSelection();
  388. + if (selection && !selection->params.empty()) {
  389. + selection->restoreBackup();
  390. + if (!desktop->on_live_extension) {
  391. + selection->emptyBackup();
  392. + }
  393. + }
  394. + }
  395. Geom::Rect bounding_area = Geom::Rect(Geom::Point(0,0), Geom::Point(100,100));
  396. if (selection->isEmpty()) {
  397. === modified file 'src/extension/prefdialog.cpp'
  398. --- src/extension/prefdialog.cpp 2016-06-11 17:25:23 +0000
  399. +++ src/extension/prefdialog.cpp 2017-06-04 19:49:54 +0000
  400. @@ -19,6 +19,8 @@
  401. // Used to get SP_ACTIVE_DESKTOP
  402. #include "inkscape.h"
  403. #include "desktop.h"
  404. +#include "document.h"
  405. +#include "document-undo.h"
  406. #include "effect.h"
  407. #include "implementation/implementation.h"
  408. @@ -64,7 +66,13 @@
  409. controls = _effect->get_imp()->prefs_effect(_effect, SP_ACTIVE_DESKTOP, &_signal_param_change, NULL);
  410. _signal_param_change.connect(sigc::mem_fun(this, &PrefDialog::param_change));
  411. }
  412. -
  413. + SPDesktop *desktop = SP_ACTIVE_DESKTOP;
  414. + if (desktop) {
  415. + Inkscape::Selection * selection = desktop->getSelection();
  416. + if (selection) {
  417. + selection->emptyBackup();
  418. + }
  419. + }
  420. hbox->pack_start(*controls, true, true, 6);
  421. hbox->show();
  422. @@ -140,10 +148,14 @@
  423. if (_effect != NULL && _effect->no_live_preview) {
  424. set_modal(false);
  425. }
  426. -
  427. + Inkscape::Preferences *prefs = Inkscape::Preferences::get();
  428. + gint transient_policy = prefs->getIntLimited( "/options/transientpolicy/value", 1, 0, 2);
  429. + prefs->setInt( "/options/transientpolicy/value", 0);
  430. GtkWidget *dlg = GTK_WIDGET(gobj());
  431. sp_transientize(dlg);
  432. -
  433. + prefs->setInt( "/options/transientpolicy/value", transient_policy);
  434. + set_position(Gtk::WindowPosition::WIN_POS_CENTER_ON_PARENT);
  435. + set_modal(false);
  436. return;
  437. }
  438. @@ -196,11 +208,28 @@
  439. void
  440. PrefDialog::preview_toggle (void) {
  441. + SPDesktop *desktop = SP_ACTIVE_DESKTOP;
  442. + SPDocument *document = SP_ACTIVE_DOCUMENT;
  443. + Inkscape::Selection * selection = NULL;
  444. + bool modified = document->isModifiedSinceSave();
  445. + if(desktop) {
  446. + selection = desktop->getSelection();
  447. + if (!selection->isEmpty()) {
  448. + selection->setBackup();
  449. + }
  450. + }
  451. if(_param_preview->get_bool(NULL, NULL)) {
  452. - set_modal(true);
  453. if (_exEnv == NULL) {
  454. + set_modal(true);
  455. + if (desktop && selection) {
  456. + desktop->on_live_extension = true;
  457. +
  458. + }
  459. _exEnv = new ExecutionEnv(_effect, SP_ACTIVE_DESKTOP, NULL, false, false);
  460. _exEnv->run();
  461. + if (desktop && selection) {
  462. + selection->clear();
  463. + }
  464. }
  465. } else {
  466. set_modal(false);
  467. @@ -209,8 +238,13 @@
  468. _exEnv->undo();
  469. delete _exEnv;
  470. _exEnv = NULL;
  471. + if (desktop && selection) {
  472. + selection->restoreBackup();
  473. + desktop->on_live_extension = false;
  474. + }
  475. }
  476. }
  477. + document->setModifiedSinceSave(modified);
  478. }
  479. void
  480. @@ -231,9 +265,12 @@
  481. bool
  482. PrefDialog::param_timer_expire (void) {
  483. if (_exEnv != NULL) {
  484. + SPDocument *document = SP_ACTIVE_DOCUMENT;
  485. + bool modified = document->isModifiedSinceSave();
  486. _exEnv->cancel();
  487. _exEnv->undo();
  488. _exEnv->run();
  489. + document->setModifiedSinceSave(modified);
  490. }
  491. return false;
  492. @@ -243,12 +280,12 @@
  493. PrefDialog::on_response (int signal) {
  494. if (signal == Gtk::RESPONSE_OK) {
  495. if (_exEnv == NULL) {
  496. - if (_effect != NULL) {
  497. - _effect->effect(SP_ACTIVE_DESKTOP);
  498. - } else {
  499. - // Shutdown run()
  500. - return;
  501. - }
  502. + if (_effect != NULL) {
  503. + _effect->effect(SP_ACTIVE_DESKTOP);
  504. + } else {
  505. + // Shutdown run()
  506. + return;
  507. + }
  508. } else {
  509. if (_exEnv->wait()) {
  510. _exEnv->commit();
  511. @@ -257,6 +294,7 @@
  512. }
  513. delete _exEnv;
  514. _exEnv = NULL;
  515. +
  516. }
  517. }
  518. @@ -267,7 +305,16 @@
  519. if ((signal == Gtk::RESPONSE_CANCEL || signal == Gtk::RESPONSE_DELETE_EVENT) && _effect != NULL) {
  520. delete this;
  521. }
  522. -
  523. + SPDesktop *desktop = SP_ACTIVE_DESKTOP;
  524. + Inkscape::Selection * selection = NULL;
  525. + if(desktop) {
  526. + selection = desktop->getSelection();
  527. + desktop->on_live_extension = false;
  528. + if (selection && selection->isEmpty()) {
  529. + selection->restoreBackup();
  530. + selection->emptyBackup();
  531. + }
  532. + }
  533. return;
  534. }
  535. === modified file 'src/selection.cpp'
  536. --- src/selection.cpp 2016-02-08 07:32:51 +0000
  537. +++ src/selection.cpp 2017-06-04 04:25:27 +0000
  538. @@ -22,6 +22,7 @@
  539. #include "macros.h"
  540. #include "inkscape.h"
  541. #include "document.h"
  542. +#include "desktop.h"
  543. #include "layer-model.h"
  544. #include "selection.h"
  545. #include <2geom/rect.h>
  546. @@ -34,6 +35,12 @@
  547. #include "box3d.h"
  548. #include "box3d.h"
  549. #include "persp3d.h"
  550. +#include "ui/tools/node-tool.h"
  551. +#include "ui/tool/multi-path-manipulator.h"
  552. +#include "ui/tool/path-manipulator.h"
  553. +#include "ui/tool/control-point-selection.h"
  554. +#include "sp-path.h"
  555. +#include "sp-defs.h"
  556. #include <sigc++/functors/mem_fun.h>
  557. @@ -541,6 +548,125 @@
  558. return parents.size();
  559. }
  560. +void
  561. +Selection::emptyBackup(){
  562. + _selected_ids.clear();
  563. + _seldata.clear();
  564. + params.clear();
  565. +}
  566. +
  567. +void
  568. +Selection::setBackup ()
  569. +{
  570. + SPDesktop *desktop = SP_ACTIVE_DESKTOP;
  571. + if (desktop) {
  572. + std::vector<SPItem*> selected_items = itemList();
  573. + _selected_ids.clear();
  574. + _seldata.clear();
  575. + params.clear();
  576. + for(std::vector<SPItem*>::const_iterator x = selected_items.begin(); x != selected_items.end(); ++x){
  577. + std::string selected_id;
  578. + selected_id += "--id=";
  579. + selected_id += (*x)->getId();
  580. + params.push_front(selected_id);
  581. + _selected_ids.push_back((*x)->getId());
  582. + }
  583. + Inkscape::UI::Tools::NodeTool *tool = 0;
  584. +
  585. + Inkscape::UI::Tools::ToolBase *ec = desktop->event_context;
  586. + if (INK_IS_NODE_TOOL(ec)) {
  587. + tool = static_cast<Inkscape::UI::Tools::NodeTool*>(ec);
  588. + }
  589. + if(tool){
  590. + Inkscape::UI::ControlPointSelection *cps = tool->_selected_nodes;
  591. + std::list<Inkscape::UI::SelectableControlPoint *> points_list = cps->_points_list;
  592. + for (std::list<Inkscape::UI::SelectableControlPoint *>::iterator i = points_list.begin(); i != points_list.end(); ++i) {
  593. + Inkscape::UI::Node *node = dynamic_cast<Inkscape::UI::Node*>(*i);
  594. + if (node) {
  595. + std::string id = node->nodeList().subpathList().pm().item()->getId();
  596. +
  597. + int sp = 0;
  598. + bool found_sp = false;
  599. + for(Inkscape::UI::SubpathList::iterator i = node->nodeList().subpathList().begin(); i != node->nodeList().subpathList().end(); ++i,++sp){
  600. + if(&**i == &(node->nodeList())){
  601. + found_sp = true;
  602. + break;
  603. + }
  604. + }
  605. + int nl=0;
  606. + bool found_nl = false;
  607. + for (Inkscape::UI::NodeList::iterator j = node->nodeList().begin(); j != node->nodeList().end(); ++j, ++nl){
  608. + if(&*j==node){
  609. + found_nl = true;
  610. + break;
  611. + }
  612. + }
  613. + std::ostringstream ss;
  614. + ss<< "--selected-nodes=" << id << ":" << sp << ":" << nl;
  615. + Glib::ustring selected_nodes = ss.str();
  616. +
  617. + if(found_nl && found_sp) {
  618. + _seldata.push_back(std::make_pair(id,std::make_pair(sp,nl)));
  619. + params.push_back(selected_nodes);
  620. + } else {
  621. + g_warning("Something went wrong while trying to pass selected nodes to extension. Please report a bug.");
  622. + }
  623. + }
  624. + }
  625. + }
  626. + }//end add selected nodes
  627. +}
  628. +
  629. +void
  630. +Selection::restoreBackup()
  631. +{
  632. + SPDesktop *desktop = SP_ACTIVE_DESKTOP;
  633. + if (desktop) {
  634. + Inkscape::UI::Tools::NodeTool *tool = 0;
  635. + Inkscape::UI::Tools::ToolBase *ec = desktop->event_context;
  636. + if (INK_IS_NODE_TOOL(ec)) {
  637. + tool = static_cast<Inkscape::UI::Tools::NodeTool*>(ec);
  638. + }
  639. + clear();
  640. + std::vector<std::string>::reverse_iterator rit = _selected_ids.rbegin();
  641. + for (; rit!= _selected_ids.rend(); ++rit){
  642. + SPObject * obj = desktop->doc()->getObjectById(rit->c_str());
  643. + SPDefs * defs = desktop->getDocument()->getDefs();
  644. + if (obj && !defs->isAncestorOf(obj)) {
  645. + add(obj);
  646. + }
  647. + }
  648. + if (tool) {
  649. + Inkscape::UI::ControlPointSelection *cps = tool->_selected_nodes;
  650. + cps->selectAll();
  651. + std::list<Inkscape::UI::SelectableControlPoint *> points_list = cps->_points_list;
  652. + cps->clear();
  653. + Inkscape::UI::Node * node = dynamic_cast<Inkscape::UI::Node*>(*points_list.begin());
  654. + if (node) {
  655. + Inkscape::UI::SubpathList sp = node->nodeList().subpathList();
  656. + for (std::vector<std::pair<std::string, std::pair<int, int> > >::iterator l = _seldata.begin(); l != _seldata.end(); ++l) {
  657. + SPPath * path = dynamic_cast<SPPath *>(desktop->doc()->getObjectById(l->first));
  658. + gint sp_count = 0;
  659. + for (Inkscape::UI::SubpathList::iterator j = sp.begin(); j != sp.end(); ++j, ++sp_count) {
  660. + if(sp_count == l->second.first) {
  661. + gint nt_count = 0;
  662. + for (Inkscape::UI::NodeList::iterator k = (*j)->begin(); k != (*j)->end(); ++k, ++nt_count) {
  663. + if(nt_count == l->second.second) {
  664. + k->select(true);
  665. + break;
  666. + }
  667. + }
  668. + break;
  669. + }
  670. + }
  671. + }
  672. + }
  673. + points_list.clear();
  674. + }
  675. + }
  676. +}
  677. +
  678. +
  679. }
  680. /*
  681. === modified file 'src/selection.h'
  682. --- src/selection.h 2015-04-29 22:29:17 +0000
  683. +++ src/selection.h 2017-05-31 00:21:11 +0000
  684. @@ -328,13 +328,29 @@
  685. {
  686. return _modified_signal.slots().insert(_modified_signal.slots().begin(), slot);
  687. }
  688. + /**
  689. + * Set a backup of current selection and store it also to be command line readable by extension system
  690. + */
  691. + void setBackup();
  692. + /**
  693. + * Clear backup of current selection
  694. + */
  695. + void emptyBackup();
  696. + /**
  697. + * Restore a selection from a existing backup
  698. + */
  699. + void restoreBackup();
  700. + /**
  701. + * Here store a paramlist when set backup
  702. + */
  703. + std::list<std::string> params;
  704. private:
  705. /** no copy. */
  706. Selection(Selection const &);
  707. /** no assign. */
  708. void operator=(Selection const &);
  709. -
  710. +
  711. /** Issues modification notification signals. */
  712. static int _emit_modified(Selection *selection);
  713. /** Schedules an item modification signal to be sent. */
  714. @@ -381,7 +397,8 @@
  715. SPObject* _selection_context;
  716. unsigned int _flags;
  717. unsigned int _idle;
  718. -
  719. + std::vector<std::pair<std::string, std::pair<int, int> > > _seldata;
  720. + std::vector<std::string> _selected_ids;
  721. std::map<SPObject *, sigc::connection> _modified_connections;
  722. std::map<SPObject *, sigc::connection> _release_connections;
  723. sigc::connection _context_release_connection;
  724. === modified file 'src/ui/tool/control-point-selection.h'
  725. --- src/ui/tool/control-point-selection.h 2016-03-13 23:50:24 +0000
  726. +++ src/ui/tool/control-point-selection.h 2017-05-30 21:15:29 +0000
  727. @@ -118,6 +118,8 @@
  728. void getOriginalPoints(std::vector<Inkscape::SnapCandidatePoint> &pts);
  729. void getUnselectedPoints(std::vector<Inkscape::SnapCandidatePoint> &pts);
  730. void setOriginalPoints();
  731. + //the purpose of this list is to keep track of first and last selected
  732. + std::list<SelectableControlPoint *> _points_list;
  733. private:
  734. // The functions below are invoked from SelectableControlPoint.
  735. @@ -141,8 +143,7 @@
  736. double _rotationRadius(Geom::Point const &);
  737. set_type _points;
  738. - //the purpose of this list is to keep track of first and last selected
  739. - std::list<SelectableControlPoint *> _points_list;
  740. +
  741. set_type _all_points;
  742. INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Point> _original_positions;
  743. INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Affine> _last_trans;
  744. === modified file 'src/ui/tool/selectable-control-point.cpp'
  745. --- src/ui/tool/selectable-control-point.cpp 2014-03-27 01:33:44 +0000
  746. +++ src/ui/tool/selectable-control-point.cpp 2017-05-30 21:15:29 +0000
  747. @@ -87,6 +87,15 @@
  748. return true;
  749. }
  750. +void SelectableControlPoint::select(bool toselect)
  751. +{
  752. + if (toselect) {
  753. + _selection.insert(this);
  754. + } else {
  755. + _selection.erase(this);
  756. + }
  757. +}
  758. +
  759. void SelectableControlPoint::_takeSelection()
  760. {
  761. _selection.clear();
  762. === modified file 'src/ui/tool/selectable-control-point.h'
  763. --- src/ui/tool/selectable-control-point.h 2014-08-08 20:20:44 +0000
  764. +++ src/ui/tool/selectable-control-point.h 2017-05-30 21:15:29 +0000
  765. @@ -28,8 +28,10 @@
  766. virtual Geom::Rect bounds() const {
  767. return Geom::Rect(position(), position());
  768. }
  769. + virtual void select(bool toselect);
  770. friend class NodeList;
  771. +
  772. protected:
  773. SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
  774. === modified file 'src/xml/node.h'
  775. --- src/xml/node.h 2014-12-16 14:05:47 +0000
  776. +++ src/xml/node.h 2017-05-30 21:15:29 +0000
  777. @@ -384,6 +384,20 @@
  778. */
  779. virtual void changeOrder(Node *child, Node *after)=0;
  780. + /**
  781. + * @brief Remove all elements that not in src node
  782. + * @param src The node to check for elemments into this node
  783. + * @param key The attribute to use as the identity attribute
  784. + */
  785. + virtual void cleanOriginal(Node *src, gchar const *key)=0;
  786. +
  787. +
  788. + /**
  789. + * @brief Compare 2 nodes equality
  790. + * @param other The other node to compare
  791. + * @param recursive Recursive mode check
  792. + */
  793. + virtual bool equal(Node const *other, bool recursive)=0;
  794. /**
  795. * @brief Merge all children of another node with the current
  796. *
  797. @@ -397,8 +411,11 @@
  798. *
  799. * @param src The node to merge into this node
  800. * @param key The attribute to use as the identity attribute
  801. + * @param noid If true process noid items
  802. + * @param key If clean callback to cleanOriginal
  803. */
  804. - virtual void mergeFrom(Node const *src, char const *key)=0;
  805. +
  806. + virtual void mergeFrom(Node const *src, char const *key, bool extension = false, bool clean = false)=0;
  807. /*@}*/
  808. === modified file 'src/xml/simple-node.cpp'
  809. --- src/xml/simple-node.cpp 2014-12-16 14:05:47 +0000
  810. +++ src/xml/simple-node.cpp 2017-05-30 21:15:29 +0000
  811. @@ -318,7 +318,7 @@
  812. // Check usefulness of attributes on elements in the svg namespace, optionally don't add them to tree.
  813. Glib::ustring element = g_quark_to_string(_name);
  814. - // g_message("setAttribute: %s: %s: %s", element.c_str(), name, value);
  815. + //g_message("setAttribute: %s: %s: %s", element.c_str(), name, value);
  816. gchar* cleaned_value = g_strdup( value );
  817. // Only check elements in SVG name space and don't block setting attribute to NULL.
  818. @@ -648,28 +648,112 @@
  819. }
  820. }
  821. -void SimpleNode::mergeFrom(Node const *src, gchar const *key) {
  822. +void SimpleNode::cleanOriginal(Node *src, gchar const *key){
  823. + std::vector<Node *> to_delete;
  824. + for ( Node *child = this->firstChild() ; child != NULL ; child = child->next() )
  825. + {
  826. + gchar const *id = child->attribute(key);
  827. + if (id) {
  828. + Node *rch = sp_repr_lookup_child(src, key, id);
  829. + if (rch) {
  830. + child->cleanOriginal(rch, key);
  831. + } else {
  832. + to_delete.push_back(child);
  833. + }
  834. + } else {
  835. + to_delete.push_back(child);
  836. + }
  837. + }
  838. + for ( std::vector<Node *>::iterator i = to_delete.begin(); i != to_delete.end(); ++i) {
  839. + removeChild(*i);
  840. + }
  841. +}
  842. +
  843. +bool SimpleNode::equal(Node const *other, bool recursive) {
  844. + if(strcmp(name(),other->name())!= 0){
  845. + return false;
  846. + }
  847. + if (!(strcmp("sodipodi:namedview", name()))) {
  848. + return true;
  849. + }
  850. + guint orig_length = 0;
  851. + guint other_length = 0;
  852. +
  853. + if(content() && other->content() && strcmp(content(), other->content()) != 0){
  854. + return false;
  855. + }
  856. + for (List<AttributeRecord const> orig_attr = attributeList(); orig_attr; ++orig_attr) {
  857. + for (List<AttributeRecord const> other_attr = other->attributeList(); other_attr; ++other_attr) {
  858. + const gchar * key_orig = g_quark_to_string(orig_attr->key);
  859. + const gchar * key_other = g_quark_to_string(other_attr->key);
  860. + if (!strcmp(key_orig, key_other) &&
  861. + !strcmp(orig_attr->value, other_attr->value))
  862. + {
  863. + other_length++;
  864. + break;
  865. + }
  866. + }
  867. + orig_length++;
  868. + }
  869. + if (orig_length != other_length) {
  870. + return false;
  871. + }
  872. + if (recursive) {
  873. + //NOTE: for faster the childs need to be in the same order
  874. + Node const *other_child = other->firstChild();
  875. + for ( Node *child = firstChild();
  876. + child;
  877. + child = child->next())
  878. + {
  879. + if (!child->equal(other_child, recursive)) {
  880. + return false;
  881. + }
  882. + other_child = other_child->next();
  883. + if(!other_child) {
  884. + return false;
  885. + }
  886. + }
  887. + }
  888. + return true;
  889. +}
  890. +
  891. +void SimpleNode::mergeFrom(Node const *src, gchar const *key, bool extension, bool clean) {
  892. g_return_if_fail(src != NULL);
  893. g_return_if_fail(key != NULL);
  894. g_assert(src != this);
  895. setContent(src->content());
  896. + if(_parent) {
  897. + setPosition(src->position());
  898. + }
  899. +
  900. + if (clean) {
  901. + Node * srcp = const_cast<Node *>(src);
  902. + cleanOriginal(srcp, key);
  903. + }
  904. for ( Node const *child = src->firstChild() ; child != NULL ; child = child->next() )
  905. {
  906. gchar const *id = child->attribute(key);
  907. if (id) {
  908. Node *rch=sp_repr_lookup_child(this, key, id);
  909. - if (rch) {
  910. - rch->mergeFrom(child, key);
  911. + if (rch && (!extension || rch->equal(child, false))) {
  912. + rch->mergeFrom(child, key, extension);
  913. } else {
  914. + if(rch) {
  915. + removeChild(rch);
  916. + }
  917. + guint pos = child->position();
  918. rch = child->duplicate(_document);
  919. appendChild(rch);
  920. + rch->setPosition(pos);
  921. rch->release();
  922. }
  923. } else {
  924. + guint pos = child->position();
  925. Node *rch=child->duplicate(_document);
  926. appendChild(rch);
  927. + rch->setPosition(pos);
  928. rch->release();
  929. }
  930. }
  931. === modified file 'src/xml/simple-node.h'
  932. --- src/xml/simple-node.h 2014-12-16 14:05:47 +0000
  933. +++ src/xml/simple-node.h 2017-05-30 21:15:29 +0000
  934. @@ -91,7 +91,9 @@
  935. char const *content() const;
  936. void setContent(char const *value);
  937. - void mergeFrom(Node const *src, char const *key);
  938. + void cleanOriginal(Node *src, gchar const *key);
  939. + bool equal(Node const *other, bool recursive);
  940. + void mergeFrom(Node const *src, char const *key, bool extension = false, bool clean = false);
  941. Inkscape::Util::List<AttributeRecord const> attributeList() const {
  942. return _attributes;
  1. More ...
 
 

936

O.92 extensionImprovements diff V27

-

PasteBin

Lines
1004
Words
3591
Tamaño
36,6 KB
Creado
Revisions
29
Tipo
text/plain
General Public License v2 (GPLv2)
su_v wrote :

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.

su_v wrote :

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).

su_v wrote :

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.

Jabiertxo Arraiza Cenoz wrote :

su_v: this bugs fixed in last patch v09

su_v wrote :

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.

su_v wrote :

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).

Jabiertxo Arraiza Cenoz wrote :

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...

su_v wrote :

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).

Jabiertxo Arraiza Cenoz wrote :

Updated to v1.1 with your fixes

Jabiertxo Arraiza Cenoz wrote :

Thanks!

su_v wrote :

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

Jabiertxo Arraiza Cenoz wrote :

thanks so much for testing!

Jabiertxo Arraiza Cenoz wrote :

Updated to v1.2
TODO: fix selected nodes part 2.1 and 2.2

Jabiertxo Arraiza Cenoz wrote :

Updated to v1.3
Fixed part 2.1 and 2.2.

su_v wrote :

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.

Jabiertxo Arraiza Cenoz wrote :

Fixed in 1.4. Thanks so much for your hard testing!

su_v wrote :

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.

Jabiertxo Arraiza Cenoz wrote :

Fixed 4 in v1.5. Thanks for testing!

su_v wrote :

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.

Jabiertxo Arraiza Cenoz wrote :

Fixed in v16. Apologyes for not test enoght. Thanks so much for your HARD work!

su_v wrote :

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.

su_v wrote :

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.

su_v wrote :

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).

su_v wrote :

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.

Jabiertxo Arraiza Cenoz wrote :

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.

Jabiertxo Arraiza Cenoz wrote :

New code with v1.8

Jabiertxo Arraiza Cenoz wrote :

Updated to V20

Jabiertxo Arraiza Cenoz wrote :

Updated to V21

Jabiertxo Arraiza Cenoz wrote :

Updated to V22

Jabiertxo Arraiza Cenoz wrote :

Updated to V23

Jabiertxo Arraiza Cenoz wrote :

Updated to v24

Jabiertxo Arraiza Cenoz wrote :

Updated to v25

Jabiertxo Arraiza Cenoz wrote :

Updated to v26

Jabiertxo Arraiza Cenoz wrote :

V27

Jabiertxo Arraiza Cenoz wrote :

Created new branch to merge on master

Jabiertxo Arraiza Cenoz wrote :

Created a MR to master: https://gitlab.com/inkscape/inkscape/merge_requests/208

THANKS su_v!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Please log in to leave a comment!