Merge lp:~inkscape+alexander/inkscape/clones into lp:~inkscape.dev/inkscape/trunk

Proposed by Alexander Brock
Status: Superseded
Proposed branch: lp:~inkscape+alexander/inkscape/clones
Merge into: lp:~inkscape.dev/inkscape/trunk
Diff against target: 670 lines (+171/-101)
5 files modified
src/menus-skeleton.h (+1/-0)
src/object-set.h (+14/-2)
src/selection-chemistry.cpp (+150/-99)
src/verbs.cpp (+5/-0)
src/verbs.h (+1/-0)
To merge this branch: bzr merge lp:~inkscape+alexander/inkscape/clones
Reviewer Review Type Date Requested Status
Martin Owens Pending
Mc code, refactor Pending
Review via email: mp+309506@code.launchpad.net

This proposal supersedes a proposal from 2016-10-20.

This proposal has been superseded by a proposal from 2016-11-04.

Description of the change

I added "Edit->Clone->Unlink Clones recursively": It recurses into groups and unlinks every clone it finds, including clones used as clipping paths.

This is one of the features from this branch: https://code.launchpad.net/~inkscape+alexander/inkscape/flatten/+merge/260791

To post a comment you must log in.
Revision history for this message
Mc (mc...) wrote : Posted in a previous version of this proposal

Looks mostly fine, but I'm not a big fan of the _functions which seems to duplicate the code a bit and double number of functions. I'd prefer a ", bool flash = true" or something like that in the already present function and "if(doflash) desktop->messageStack()->flash(whatever)"

I'll re-read the main new function during the week-end and extensively test it.

Revision history for this message
Mc (mc...) wrote : Posted in a previous version of this proposal

Ok, so with the small change I did to the codebase, here's what I think should be done:

-> add a "bool skip_undo" flag to ::setMask(), ::unsetMask(), and ::unlink() similar to what's done in other methods in the file. (Also add it to your recursive method).

-> make a ObjectSet with no SPDesktop (just the SPDocument) containing the selection, so that it does not flash recursively.

-> make all the calls with the skip_undo flag on your ObjectSet.

review: Needs Resubmitting (code, refactor)
Revision history for this message
Alexander Brock (brock-alexander) wrote : Posted in a previous version of this proposal

> Ok, so with the small change I did to the codebase, here's what I think should
> be done:
>
> -> add a "bool skip_undo" flag to ::setMask(), ::unsetMask(), and ::unlink()
> similar to what's done in other methods in the file. (Also add it to your
> recursive method).
>
> -> make a ObjectSet with no SPDesktop (just the SPDocument) containing the
> selection, so that it does not flash recursively.
>
> -> make all the calls with the skip_undo flag on your ObjectSet.

I tried to merge your changes with my branch, failed and restarted from scratch.
I added an unlinkRecursive method to ObjectSet, added the bool skip_undo where I needed it and force-pushed the code to the old location (lp:~inkscape+alexander/inkscape/clones).

15194. By Jordi Mas

[Bug #1636086] Update Catalan translation for Inkscape 0.92.

15195. By Mc

allows for denser screens in zoom correction factors

15196. By FirasH

[Bug #1574561] Italian translation update.

15197. By Jabiertxof

Close the bounding box path LPE

15198. By Jabiertxof

Fix fill between many LPE to start up with current path

15199. By Jabiertxof

Update branding folder

15200. By Jabiertxof

Fix bug:1013141 crash deleting LPE

15201. By houz

fix none color in palettes with scrollbars

15202. By houz

fix prefs icon

15203. By Mc

Add some unit tests for object-set cppification

15204. By Mc

Revert two changes from r15177

Revision history for this message
Mc (mc...) wrote :

Good !
I did a merge proposal to your branch to propose a simpler version of the recursive function, though it can be improved and further simplified by putting the unclip/reclip business in the unlink() function where it probably belongs.
If you find the courage, you can also propose unit tests to test the function (see testfiles/src/object-set-test.cpp )

15205. By Alexander Brock <email address hidden>

Add "Edit->Clone->Unlink Clones recursively" function (ObjectSet::unlinkRecursive)

15206. By Alexander Brock <email address hidden>

Preserve clips when unlinking clones

15207. By Alexander Brock <email address hidden>

Make ObjectSet::unlink() work for clones which are both clipped and masked

15208. By Alexander Brock <email address hidden>

Remove duplicate code from unlinkRecursive() and fix issue with clones of groups

15209. By Alexander Brock <email address hidden>

Fix selection issue with ObjectSet::unlinkRecursive() and add tests for it.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/menus-skeleton.h'
--- src/menus-skeleton.h 2016-04-15 14:39:49 +0000
+++ src/menus-skeleton.h 2016-11-04 12:38:02 +0000
@@ -66,6 +66,7 @@
66" <verb verb-id=\"EditClone\" />\n"66" <verb verb-id=\"EditClone\" />\n"
67" <verb verb-id=\"DialogClonetiler\" />\n"67" <verb verb-id=\"DialogClonetiler\" />\n"
68" <verb verb-id=\"EditUnlinkClone\" />\n"68" <verb verb-id=\"EditUnlinkClone\" />\n"
69" <verb verb-id=\"EditUnlinkCloneRecursive\" />\n"
69" <verb verb-id=\"EditRelinkClone\" />\n"70" <verb verb-id=\"EditRelinkClone\" />\n"
70" <verb verb-id=\"EditCloneSelectOriginal\" />\n"71" <verb verb-id=\"EditCloneSelectOriginal\" />\n"
71" <verb verb-id=\"EditCloneOriginalPathLPE\" />\n"72" <verb verb-id=\"EditCloneOriginalPathLPE\" />\n"
7273
=== modified file 'src/object-set.h'
--- src/object-set.h 2016-11-03 23:28:50 +0000
+++ src/object-set.h 2016-11-04 12:38:02 +0000
@@ -330,7 +330,19 @@
330 void deleteItems();330 void deleteItems();
331 void duplicate(bool suppressDone = false, bool duplicateLayer = false);331 void duplicate(bool suppressDone = false, bool duplicateLayer = false);
332 void clone();332 void clone();
333 void unlink();333
334 /**
335 * @brief Unlink all directly selected clones.
336 * @param skip_undo If this is set to true the call to DocumentUndo::done is omitted.
337 * @return True if anything was unlinked, otherwise false.
338 */
339 bool unlink(bool skip_undo = false);
340 /**
341 * @brief Recursively unlink any clones present in the current selection,
342 * including clones which are used to clip other objects, groups of clones etc.
343 * @return true if anything was unlinked, otherwise false.
344 */
345 bool unlinkRecursive(const bool skip_undo = false);
334 void relink();346 void relink();
335 void cloneOriginal();347 void cloneOriginal();
336 void cloneOriginalPathLPE();348 void cloneOriginalPathLPE();
@@ -376,7 +388,7 @@
376 void createBitmapCopy();388 void createBitmapCopy();
377 void setMask(bool apply_clip_path, bool apply_to_layer = false, bool skip_undo = false);389 void setMask(bool apply_clip_path, bool apply_to_layer = false, bool skip_undo = false);
378 void editMask(bool clip);390 void editMask(bool clip);
379 void unsetMask(bool apply_clip_path);391 void unsetMask(const bool apply_clip_path, const bool skip_undo = false);
380 void setClipGroup();392 void setClipGroup();
381 393
382 // moves394 // moves
383395
=== modified file 'src/selection-chemistry.cpp'
--- src/selection-chemistry.cpp 2016-11-02 23:08:41 +0000
+++ src/selection-chemistry.cpp 2016-11-04 12:38:02 +0000
@@ -124,8 +124,8 @@
124 desktop->messageStack()->flash(msgType, msg);124 desktop->messageStack()->flash(msgType, msg);
125 } else {125 } else {
126 if (msgType == Inkscape::IMMEDIATE_MESSAGE ||126 if (msgType == Inkscape::IMMEDIATE_MESSAGE ||
127 msgType == Inkscape::WARNING_MESSAGE ||127 msgType == Inkscape::WARNING_MESSAGE ||
128 msgType == Inkscape::ERROR_MESSAGE) {128 msgType == Inkscape::ERROR_MESSAGE) {
129 g_printerr("%s\n", msg.c_str());129 g_printerr("%s\n", msg.c_str());
130 }130 }
131 }131 }
@@ -273,8 +273,8 @@
273 for(auto i = boost::rbegin(selList); i != boost::rend(selList); ++i) {273 for(auto i = boost::rbegin(selList); i != boost::rend(selList); ++i) {
274 SPItem *item = *i;274 SPItem *item = *i;
275 if( item &&275 if( item &&
276 !dt->isLayer(item) &&276 !dt->isLayer(item) &&
277 (!item->isLocked()))277 (!item->isLocked()))
278 {278 {
279 items.push_back(item);279 items.push_back(item);
280 }280 }
@@ -378,19 +378,19 @@
378void ObjectSet::deleteItems()378void ObjectSet::deleteItems()
379{379{
380 if(desktop() && tools_isactive(desktop(), TOOLS_TEXT)){380 if(desktop() && tools_isactive(desktop(), TOOLS_TEXT)){
381 if (Inkscape::UI::Tools::sp_text_delete_selection(desktop()->event_context)) {381 if (Inkscape::UI::Tools::sp_text_delete_selection(desktop()->event_context)) {
382 DocumentUndo::done(desktop()->getDocument(), SP_VERB_CONTEXT_TEXT,382 DocumentUndo::done(desktop()->getDocument(), SP_VERB_CONTEXT_TEXT,
383 _("Delete text"));383 _("Delete text"));
384 return;384 return;
385 }385 }
386 }386 }
387 387
388 if (isEmpty()) {388 if (isEmpty()) {
389 selection_display_message(desktop(),Inkscape::WARNING_MESSAGE, _("<b>Nothing</b> was deleted."));389 selection_display_message(desktop(),Inkscape::WARNING_MESSAGE, _("<b>Nothing</b> was deleted."));
390 return;390 return;
391 }391 }
392 std::vector<SPItem*> selected(items().begin(), items().end());392 std::vector<SPItem*> selected(items().begin(), items().end());
393 clear(); 393 clear();
394 sp_selection_delete_impl(selected);394 sp_selection_delete_impl(selected);
395 if(SPDesktop *d = desktop()){395 if(SPDesktop *d = desktop()){
396 d->currentLayer()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);396 d->currentLayer()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
@@ -404,7 +404,7 @@
404 tools_switch( d, tools_active( d ) );404 tools_switch( d, tools_active( d ) );
405 }405 }
406 if(document())406 if(document())
407 DocumentUndo::done(document(), SP_VERB_EDIT_DELETE,407 DocumentUndo::done(document(), SP_VERB_EDIT_DELETE,
408 _("Delete"));408 _("Delete"));
409409
410}410}
@@ -430,7 +430,7 @@
430 //TODO: understand why layer management is tied to desktop and not to document.430 //TODO: understand why layer management is tied to desktop and not to document.
431 return;431 return;
432 }432 }
433 433
434 SPDocument *doc = document();434 SPDocument *doc = document();
435 435
436 if(!doc)436 if(!doc)
@@ -586,11 +586,11 @@
586 for (auto& child: from->children) {586 for (auto& child: from->children) {
587 SPItem *item = dynamic_cast<SPItem *>(&child);587 SPItem *item = dynamic_cast<SPItem *>(&child);
588 if (item &&588 if (item &&
589 !desktop->isLayer(item) &&589 !desktop->isLayer(item) &&
590 (!onlysensitive || !item->isLocked()) &&590 (!onlysensitive || !item->isLocked()) &&
591 (!onlyvisible || !desktop->itemIsHidden(item)) &&591 (!onlyvisible || !desktop->itemIsHidden(item)) &&
592 (exclude.empty() || exclude.end() == std::find(exclude.begin(), exclude.end(), &child))592 (exclude.empty() || exclude.end() == std::find(exclude.begin(), exclude.end(), &child))
593 )593 )
594 {594 {
595 list.insert(list.begin(),item);595 list.insert(list.begin(),item);
596 }596 }
@@ -628,10 +628,10 @@
628 inlayer = PREFS_SELECTION_ALL;628 inlayer = PREFS_SELECTION_ALL;
629629
630 switch (inlayer) {630 switch (inlayer) {
631 case PREFS_SELECTION_LAYER: {631 case PREFS_SELECTION_LAYER: {
632 if ( (onlysensitive && dynamic_cast<SPItem *>(dt->currentLayer())->isLocked()) ||632 if ( (onlysensitive && dynamic_cast<SPItem *>(dt->currentLayer())->isLocked()) ||
633 (onlyvisible && dt->itemIsHidden(dynamic_cast<SPItem *>(dt->currentLayer()))) )633 (onlyvisible && dt->itemIsHidden(dynamic_cast<SPItem *>(dt->currentLayer()))) )
634 return;634 return;
635635
636 std::vector<SPItem*> all_items = sp_item_group_item_list(dynamic_cast<SPGroup *>(dt->currentLayer()));636 std::vector<SPItem*> all_items = sp_item_group_item_list(dynamic_cast<SPGroup *>(dt->currentLayer()));
637637
@@ -649,17 +649,17 @@
649 }649 }
650 }650 }
651651
652 break;652 break;
653 }653 }
654 case PREFS_SELECTION_LAYER_RECURSIVE: {654 case PREFS_SELECTION_LAYER_RECURSIVE: {
655 std::vector<SPItem*> x;655 std::vector<SPItem*> x;
656 items = get_all_items(x, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude);656 items = get_all_items(x, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude);
657 break;657 break;
658 }658 }
659 default: {659 default: {
660 std::vector<SPItem*> x;660 std::vector<SPItem*> x;
661 items = get_all_items(x, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude);661 items = get_all_items(x, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude);
662 break;662 break;
663 }663 }
664 }664 }
665665
@@ -787,7 +787,7 @@
787 }787 }
788788
789 auto item = items().begin(); // leaving this because it will be useful for789 auto item = items().begin(); // leaving this because it will be useful for
790 // future implementation of complex pop ungrouping790 // future implementation of complex pop ungrouping
791 SPItem *obj = *item;791 SPItem *obj = *item;
792 SPItem *parent_group = static_cast<SPItem*>(obj->parent);792 SPItem *parent_group = static_cast<SPItem*>(obj->parent);
793 if (!SP_IS_GROUP(parent_group) || SP_IS_LAYER(parent_group)) {793 if (!SP_IS_GROUP(parent_group) || SP_IS_LAYER(parent_group)) {
@@ -806,7 +806,7 @@
806 806
807 if(document())807 if(document())
808 DocumentUndo::done(document(), SP_VERB_SELECTION_UNGROUP_POP_SELECTION,808 DocumentUndo::done(document(), SP_VERB_SELECTION_UNGROUP_POP_SELECTION,
809 _("Pop selection from group"));809 _("Pop selection from group"));
810 810
811}811}
812812
@@ -883,7 +883,7 @@
883 ungroup_impl(this);883 ungroup_impl(this);
884 if(document())884 if(document())
885 DocumentUndo::done(document(), SP_VERB_SELECTION_UNGROUP,885 DocumentUndo::done(document(), SP_VERB_SELECTION_UNGROUP,
886 _("Ungroup"));886 _("Ungroup"));
887}887}
888888
889// TODO replace it with ObjectSet::degroup_list889// TODO replace it with ObjectSet::degroup_list
@@ -964,7 +964,7 @@
964bool sp_item_repr_compare_position_bool(SPObject const *first, SPObject const *second)964bool sp_item_repr_compare_position_bool(SPObject const *first, SPObject const *second)
965{965{
966 return sp_repr_compare_position(((SPItem*)first)->getRepr(),966 return sp_repr_compare_position(((SPItem*)first)->getRepr(),
967 ((SPItem*)second)->getRepr())<0;967 ((SPItem*)second)->getRepr())<0;
968}968}
969969
970void ObjectSet::raise(bool skip_undo){970void ObjectSet::raise(bool skip_undo){
@@ -1015,8 +1015,8 @@
1015 }1015 }
1016 if(document() && !skip_undo)1016 if(document() && !skip_undo)
1017 DocumentUndo::done(document(), SP_VERB_SELECTION_RAISE,1017 DocumentUndo::done(document(), SP_VERB_SELECTION_RAISE,
1018 //TRANSLATORS: "Raise" means "to raise an object" in the undo history1018 //TRANSLATORS: "Raise" means "to raise an object" in the undo history
1019 C_("Undo action", "Raise"));1019 C_("Undo action", "Raise"));
1020}1020}
10211021
10221022
@@ -1042,7 +1042,7 @@
1042 }1042 }
1043 if (document() && !skip_undo) {1043 if (document() && !skip_undo) {
1044 DocumentUndo::done(document(), SP_VERB_SELECTION_TO_FRONT,1044 DocumentUndo::done(document(), SP_VERB_SELECTION_TO_FRONT,
1045 _("Raise to top"));1045 _("Raise to top"));
1046 }1046 }
1047}1047}
10481048
@@ -1096,8 +1096,8 @@
1096 }1096 }
1097 if(document() && !skip_undo)1097 if(document() && !skip_undo)
1098 DocumentUndo::done(document(), SP_VERB_SELECTION_LOWER,1098 DocumentUndo::done(document(), SP_VERB_SELECTION_LOWER,
1099 //TRANSLATORS: "Lower" means "to lower an object" in the undo history1099 //TRANSLATORS: "Lower" means "to lower an object" in the undo history
1100 C_("Undo action", "Lower"));1100 C_("Undo action", "Lower"));
1101}1101}
11021102
11031103
@@ -1183,7 +1183,7 @@
1183 return NULL;1183 return NULL;
11841184
1185 if ((dynamic_cast<SPGroup *>(object) && object->firstChild()) ||1185 if ((dynamic_cast<SPGroup *>(object) && object->firstChild()) ||
1186 (dynamic_cast<SPText *>(object) && object->firstChild() && object->firstChild()->getNext() == NULL)) {1186 (dynamic_cast<SPText *>(object) && object->firstChild() && object->firstChild()->getNext() == NULL)) {
1187 // if this is a text with exactly one tspan child, merge the style of that tspan as well1187 // if this is a text with exactly one tspan child, merge the style of that tspan as well
1188 // If this is a group, merge the style of its topmost (last) child with style1188 // If this is a group, merge the style of its topmost (last) child with style
1189 auto list = object->children | boost::adaptors::reversed;1189 auto list = object->children | boost::adaptors::reversed;
@@ -1268,7 +1268,7 @@
1268 // check if something is selected1268 // check if something is selected
1269 if (isEmpty()) {1269 if (isEmpty()) {
1270 if(desktop())1270 if(desktop())
1271 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to remove live path effects from."));1271 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to remove live path effects from."));
1272 return;1272 return;
1273 }1273 }
1274 auto list= items();1274 auto list= items();
@@ -1281,7 +1281,7 @@
12811281
1282 if(document())1282 if(document())
1283 DocumentUndo::done(document(), SP_VERB_EDIT_REMOVE_LIVEPATHEFFECT,1283 DocumentUndo::done(document(), SP_VERB_EDIT_REMOVE_LIVEPATHEFFECT,
1284 _("Remove live path effect"));1284 _("Remove live path effect"));
1285}1285}
12861286
1287void ObjectSet::removeFilter()1287void ObjectSet::removeFilter()
@@ -1300,7 +1300,7 @@
1300 sp_repr_css_attr_unref(css);1300 sp_repr_css_attr_unref(css);
1301 if(document())1301 if(document())
1302 DocumentUndo::done(document(), SP_VERB_EDIT_REMOVE_FILTER,1302 DocumentUndo::done(document(), SP_VERB_EDIT_REMOVE_FILTER,
1303 _("Remove filter"));1303 _("Remove filter"));
1304}1304}
13051305
13061306
@@ -1334,8 +1334,8 @@
1334 SPItem *oldparent = dynamic_cast<SPItem *>(item->parent);1334 SPItem *oldparent = dynamic_cast<SPItem *>(item->parent);
1335 SPItem *newparent = dynamic_cast<SPItem *>(where);1335 SPItem *newparent = dynamic_cast<SPItem *>(where);
1336 sp_item_group_ungroup_handle_clones(item,1336 sp_item_group_ungroup_handle_clones(item,
1337 (oldparent->i2doc_affine())1337 (oldparent->i2doc_affine())
1338 *((newparent->i2doc_affine()).inverse()));1338 *((newparent->i2doc_affine()).inverse()));
1339 }1339 }
1340 }1340 }
1341}1341}
@@ -1345,7 +1345,7 @@
1345 if(!desktop())1345 if(!desktop())
1346 return;1346 return;
1347 SPDesktop *dt=desktop(); //TODO make it desktop-independent1347 SPDesktop *dt=desktop(); //TODO make it desktop-independent
1348 1348
1349 // check if something is selected1349 // check if something is selected
1350 if (isEmpty()) {1350 if (isEmpty()) {
1351 dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to move to the layer above."));1351 dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to move to the layer above."));
@@ -1515,7 +1515,7 @@
1515 */1515 */
15161516
1517void ObjectSet::applyAffine(Geom::Affine const &affine, bool set_i2d, bool compensate,1517void ObjectSet::applyAffine(Geom::Affine const &affine, bool set_i2d, bool compensate,
1518 bool adjust_transf_center)1518 bool adjust_transf_center)
1519{1519{
1520 if (isEmpty())1520 if (isEmpty())
1521 return;1521 return;
@@ -1559,7 +1559,7 @@
1559 old_center = item->getCenter();1559 old_center = item->getCenter();
15601560
1561#if 0 /* Re-enable this once persistent guides have a graphical indication.1561#if 0 /* Re-enable this once persistent guides have a graphical indication.
1562 At the time of writing, this is the only place to re-enable. */1562 At the time of writing, this is the only place to re-enable. */
1563 sp_item_update_cns(*item, desktop());1563 sp_item_update_cns(*item, desktop());
1564#endif1564#endif
15651565
@@ -1716,7 +1716,7 @@
17161716
1717 if(document())1717 if(document())
1718 DocumentUndo::done(document(), SP_VERB_OBJECT_FLATTEN,1718 DocumentUndo::done(document(), SP_VERB_OBJECT_FLATTEN,
1719 _("Remove transform"));1719 _("Remove transform"));
1720}1720}
17211721
1722void ObjectSet::setScaleAbsolute(double x0, double x1,double y0, double y1)1722void ObjectSet::setScaleAbsolute(double x0, double x1,double y0, double y1)
@@ -1955,20 +1955,20 @@
1955 SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke);1955 SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke);
1956 match = false;1956 match = false;
1957 if (sel_paint->isColor() && iter_paint->isColor() // color == color comparision doesnt seem to work here.1957 if (sel_paint->isColor() && iter_paint->isColor() // color == color comparision doesnt seem to work here.
1958 && (sel_paint->value.color.toRGBA32(1.0) == iter_paint->value.color.toRGBA32(1.0))) {1958 && (sel_paint->value.color.toRGBA32(1.0) == iter_paint->value.color.toRGBA32(1.0))) {
1959 match = true;1959 match = true;
1960 } else if (sel_paint->isPaintserver() && iter_paint->isPaintserver()) {1960 } else if (sel_paint->isPaintserver() && iter_paint->isPaintserver()) {
19611961
1962 SPPaintServer *sel_server =1962 SPPaintServer *sel_server =
1963 (type == SP_FILL_COLOR) ? sel->style->getFillPaintServer() : sel->style->getStrokePaintServer();1963 (type == SP_FILL_COLOR) ? sel->style->getFillPaintServer() : sel->style->getStrokePaintServer();
1964 SPPaintServer *iter_server =1964 SPPaintServer *iter_server =
1965 (type == SP_FILL_COLOR) ? iter->style->getFillPaintServer() : iter->style->getStrokePaintServer();1965 (type == SP_FILL_COLOR) ? iter->style->getFillPaintServer() : iter->style->getStrokePaintServer();
19661966
1967 if ((dynamic_cast<SPLinearGradient *>(sel_server) || dynamic_cast<SPRadialGradient *>(sel_server) ||1967 if ((dynamic_cast<SPLinearGradient *>(sel_server) || dynamic_cast<SPRadialGradient *>(sel_server) ||
1968 (dynamic_cast<SPGradient *>(sel_server) && dynamic_cast<SPGradient *>(sel_server)->getVector()->isSwatch()))1968 (dynamic_cast<SPGradient *>(sel_server) && dynamic_cast<SPGradient *>(sel_server)->getVector()->isSwatch()))
1969 &&1969 &&
1970 (dynamic_cast<SPLinearGradient *>(iter_server) || dynamic_cast<SPRadialGradient *>(iter_server) ||1970 (dynamic_cast<SPLinearGradient *>(iter_server) || dynamic_cast<SPRadialGradient *>(iter_server) ||
1971 (dynamic_cast<SPGradient *>(iter_server) && dynamic_cast<SPGradient *>(iter_server)->getVector()->isSwatch()))) {1971 (dynamic_cast<SPGradient *>(iter_server) && dynamic_cast<SPGradient *>(iter_server)->getVector()->isSwatch()))) {
1972 SPGradient *sel_vector = dynamic_cast<SPGradient *>(sel_server)->getVector();1972 SPGradient *sel_vector = dynamic_cast<SPGradient *>(sel_server)->getVector();
1973 SPGradient *iter_vector = dynamic_cast<SPGradient *>(iter_server)->getVector();1973 SPGradient *iter_vector = dynamic_cast<SPGradient *>(iter_server)->getVector();
1974 if (sel_vector == iter_vector) {1974 if (sel_vector == iter_vector) {
@@ -2119,7 +2119,7 @@
2119 for (int i = 0; i < len; i++) {2119 for (int i = 0; i < len; i++) {
2120 match = (sel_style->marker_ptrs[i]->set == iter_style->marker_ptrs[i]->set);2120 match = (sel_style->marker_ptrs[i]->set == iter_style->marker_ptrs[i]->set);
2121 if (sel_style->marker_ptrs[i]->set && iter_style->marker_ptrs[i]->set &&2121 if (sel_style->marker_ptrs[i]->set && iter_style->marker_ptrs[i]->set &&
2122 (strcmp(sel_style->marker_ptrs[i]->value, iter_style->marker_ptrs[i]->value))) {2122 (strcmp(sel_style->marker_ptrs[i]->value, iter_style->marker_ptrs[i]->value))) {
2123 match = false;2123 match = false;
2124 break;2124 break;
2125 }2125 }
@@ -2652,13 +2652,59 @@
2652 }2652 }
2653}2653}
26542654
26552655bool ObjectSet::unlinkRecursive(const bool skip_undo) {
2656void ObjectSet::unlink()2656 if(isEmpty()){
2657 if(desktop())
2658 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>clones</b> to unlink."));
2659 return false;
2660 }
2661 bool unlinked = false;
2662 ObjectSet tmp_set(document());
2663 std::vector<SPItem*> items_(items().begin(), items().end());
2664 for (auto& it:items_){
2665 if (SP_IS_GROUP(it)) {
2666 std::vector<SPObject*> c = it->childList(false);
2667 tmp_set.setList(c);
2668 unlinked = tmp_set.unlinkRecursive(true) || unlinked;
2669 }
2670 tmp_set.set(it);
2671 bool has_clip = false;
2672 bool has_mask = false;
2673 Inkscape::URIReference *clip = it->clip_ref;
2674 Inkscape::URIReference *mask = it->mask_ref;
2675 if ((NULL != clip) && (NULL != clip->getObject())) {
2676 tmp_set.unsetMask(true,true);
2677 has_clip = true;
2678 }
2679 if ((NULL != mask) && (NULL != mask->getObject())) {
2680 tmp_set.unsetMask(false,true);
2681 has_mask = true;
2682 }
2683 unlinked = tmp_set.unlink(true) || unlinked;
2684 if (has_mask)
2685 tmp_set.setMask(false,false,true);
2686 if (has_clip)
2687 tmp_set.setMask(true,false,true);
2688 }
2689 if (!unlinked) {
2690 if(desktop())
2691 desktop()->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection."));
2692 }
2693 if (!skip_undo) {
2694 DocumentUndo::done(document(), SP_VERB_EDIT_UNLINK_CLONE_RECURSIVE,
2695 _("Unlink clone recursively"));
2696 }
2697 return unlinked;
2698}
2699
2700
2701
2702bool ObjectSet::unlink(bool skip_undo)
2657{2703{
2658 if (isEmpty()) {2704 if (isEmpty()) {
2659 if(desktop())2705 if(desktop())
2660 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>clones</b> to unlink."));2706 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>clones</b> to unlink."));
2661 return;2707 return false;
2662 }2708 }
26632709
2664 // Get a copy of current selection.2710 // Get a copy of current selection.
@@ -2715,8 +2761,11 @@
2715 desktop()->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection."));2761 desktop()->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection."));
2716 }2762 }
27172763
2718 DocumentUndo::done(document(), SP_VERB_EDIT_UNLINK_CLONE,2764 if (!skip_undo) {
2719 _("Unlink clone"));2765 DocumentUndo::done(document(), SP_VERB_EDIT_UNLINK_CLONE,
2766 _("Unlink clone"));
2767 }
2768 return unlinked;
2720}2769}
27212770
2722void ObjectSet::cloneOriginal()2771void ObjectSet::cloneOriginal()
@@ -2876,8 +2925,8 @@
2876void ObjectSet::toMarker(bool apply)2925void ObjectSet::toMarker(bool apply)
2877{2926{
2878 // sp_selection_tile has similar code2927 // sp_selection_tile has similar code
2879 if (desktop() == NULL) { // TODO: We should not need desktop for that. 2928 if (desktop() == NULL) { // TODO: We should not need desktop for that.
2880 // Someone get rid of the dt2doc() call.2929 // Someone get rid of the dt2doc() call.
2881 return;2930 return;
2882 }2931 }
28832932
@@ -2901,7 +2950,7 @@
2901 Geom::Point doc_height( 0, doc->getHeight().value("px"));2950 Geom::Point doc_height( 0, doc->getHeight().value("px"));
29022951
2903 // calculate the transform to be applied to objects to move them to 0,02952 // calculate the transform to be applied to objects to move them to 0,0
2904 Geom::Point corner( r->min()[Geom::X], r->max()[Geom::Y] ); // FIXME: Inverted Y coodinate 2953 Geom::Point corner( r->min()[Geom::X], r->max()[Geom::Y] ); // FIXME: Inverted Y coodinate
2905 Geom::Point move_p = doc_height - corner;2954 Geom::Point move_p = doc_height - corner;
2906 move_p[Geom::Y] = -move_p[Geom::Y];2955 move_p[Geom::Y] = -move_p[Geom::Y];
2907 Geom::Affine move = Geom::Affine(Geom::Translate(move_p));2956 Geom::Affine move = Geom::Affine(Geom::Translate(move_p));
@@ -3007,7 +3056,7 @@
30073056
3008/*3057/*
3009 * Convert objects to <symbol>. How that happens depends on what is selected:3058 * Convert objects to <symbol>. How that happens depends on what is selected:
3010 * 3059 *
3011 * 1) A random selection of objects will be embedded into a single <symbol> element.3060 * 1) A random selection of objects will be embedded into a single <symbol> element.
3012 *3061 *
3013 * 2) Except, a single <g> will have its content directly embedded into a <symbol>; the 'id' and3062 * 2) Except, a single <g> will have its content directly embedded into a <symbol>; the 'id' and
@@ -3033,9 +3082,9 @@
30333082
3034 // Check if something is selected.3083 // Check if something is selected.
3035 if (isEmpty()) {3084 if (isEmpty()) {
3036 if (desktop())3085 if (desktop())
3037 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>objects</b> to convert to symbol."));3086 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>objects</b> to convert to symbol."));
3038 return;3087 return;
3039 }3088 }
30403089
3041 doc->ensureUpToDate();3090 doc->ensureUpToDate();
@@ -3108,9 +3157,9 @@
31083157
3109 // Move selected items to new <symbol>3158 // Move selected items to new <symbol>
3110 for (std::vector<SPObject*>::const_reverse_iterator i=items_.rbegin();i!=items_.rend();++i){3159 for (std::vector<SPObject*>::const_reverse_iterator i=items_.rbegin();i!=items_.rend();++i){
3111 Inkscape::XML::Node *repr = (*i)->getRepr();3160 Inkscape::XML::Node *repr = (*i)->getRepr();
3112 repr->parent()->removeChild(repr);3161 repr->parent()->removeChild(repr);
3113 symbol_repr->addChild(repr,NULL);3162 symbol_repr->addChild(repr,NULL);
3114 }3163 }
31153164
3116 if( single_group && transform.isTranslation() ) {3165 if( single_group && transform.isTranslation() ) {
@@ -3154,7 +3203,7 @@
3154 }3203 }
31553204
3156 SPObject* symbol = single();3205 SPObject* symbol = single();
3157 3206
3158 // Make sure we have only one object in selection.3207 // Make sure we have only one object in selection.
3159 // Require that we really have a <symbol>.3208 // Require that we really have a <symbol>.
3160 if( symbol == NULL || !dynamic_cast<SPSymbol *>( symbol )) {3209 if( symbol == NULL || !dynamic_cast<SPSymbol *>( symbol )) {
@@ -3179,14 +3228,14 @@
3179 SPObject *object = children[0];3228 SPObject *object = children[0];
3180 if ( dynamic_cast<SPGroup *>( object ) ) {3229 if ( dynamic_cast<SPGroup *>( object ) ) {
3181 if( object->getAttribute("style") == NULL ||3230 if( object->getAttribute("style") == NULL ||
3182 object->getAttribute("class") == NULL ) {3231 object->getAttribute("class") == NULL ) {
31833232
3184 group->setAttribute("transform", object->getAttribute("transform"));3233 group->setAttribute("transform", object->getAttribute("transform"));
3185 children = object->childList(false);3234 children = object->childList(false);
3186 }3235 }
3187 }3236 }
3188 }3237 }
3189 3238
3190 for (std::vector<SPObject*>::const_reverse_iterator i=children.rbegin();i!=children.rend();++i){3239 for (std::vector<SPObject*>::const_reverse_iterator i=children.rbegin();i!=children.rend();++i){
3191 Inkscape::XML::Node *repr = (*i)->getRepr();3240 Inkscape::XML::Node *repr = (*i)->getRepr();
3192 repr->parent()->removeChild(repr);3241 repr->parent()->removeChild(repr);
@@ -3291,10 +3340,10 @@
3291 prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);3340 prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
32923341
3293 gchar const *pat_id = SPPattern::produce(repr_copies, bbox, doc,3342 gchar const *pat_id = SPPattern::produce(repr_copies, bbox, doc,
3294 ( Geom::Affine(Geom::Translate(desktop()->dt2doc(Geom::Point(r->min()[Geom::X],3343 ( Geom::Affine(Geom::Translate(desktop()->dt2doc(Geom::Point(r->min()[Geom::X],
3295 r->max()[Geom::Y]))))3344 r->max()[Geom::Y]))))
3296 * parent_transform.inverse() ),3345 * parent_transform.inverse() ),
3297 parent_transform * move);3346 parent_transform * move);
32983347
3299 // restore compensation setting3348 // restore compensation setting
3300 prefs->setInt("/options/clonecompensation/value", saved_compensation);3349 prefs->setInt("/options/clonecompensation/value", saved_compensation);
@@ -3374,8 +3423,8 @@
3374 Inkscape::XML::Node *copy = child.getRepr()->duplicate(xml_doc);3423 Inkscape::XML::Node *copy = child.getRepr()->duplicate(xml_doc);
3375 SPItem *i = dynamic_cast<SPItem *>(item->parent->appendChildRepr(copy));3424 SPItem *i = dynamic_cast<SPItem *>(item->parent->appendChildRepr(copy));
33763425
3377 // FIXME: relink clones to the new canvas objects3426 // FIXME: relink clones to the new canvas objects
3378 // use SPObject::setid when mental finishes it to steal ids of3427 // use SPObject::setid when mental finishes it to steal ids of
33793428
3380 // this is needed to make sure the new item has curve (simply requestDisplayUpdate does not work)3429 // this is needed to make sure the new item has curve (simply requestDisplayUpdate does not work)
3381 doc->ensureUpToDate();3430 doc->ensureUpToDate();
@@ -3517,7 +3566,7 @@
3517 gchar *const basename = g_strdup_printf("%s-%s-%u.png",3566 gchar *const basename = g_strdup_printf("%s-%s-%u.png",
3518 doc->getName(),3567 doc->getName(),
3519 items_[0]->getRepr()->attribute("id"),3568 items_[0]->getRepr()->attribute("id"),
3520 current);3569 current);
3521 // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters,3570 // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters,
3522 // digits, and a few other chars, with "_"3571 // digits, and a few other chars, with "_"
3523 g_strcanon(basename, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.=+~$#@^&!?", '_');3572 g_strcanon(basename, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.=+~$#@^&!?", '_');
@@ -3622,12 +3671,12 @@
3622 // Do the export3671 // Do the export
3623 sp_export_png_file(doc, filepath,3672 sp_export_png_file(doc, filepath,
3624 bbox->min()[Geom::X], bbox->min()[Geom::Y],3673 bbox->min()[Geom::X], bbox->min()[Geom::Y],
3625 bbox->max()[Geom::X], bbox->max()[Geom::Y],3674 bbox->max()[Geom::X], bbox->max()[Geom::Y],
3626 width, height, res, res,3675 width, height, res, res,
3627 (guint32) 0xffffff00,3676 (guint32) 0xffffff00,
3628 NULL, NULL,3677 NULL, NULL,
3629 true, /*bool force_overwrite,*/3678 true, /*bool force_overwrite,*/
3630 items_);3679 items_);
36313680
3632 // Run filter, if any3681 // Run filter, if any
3633 if (run) {3682 if (run) {
@@ -3699,7 +3748,7 @@
3699 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to create clippath or mask from."));3748 desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to create clippath or mask from."));
3700 return;3749 return;
3701 }3750 }
3702 3751
3703 std::vector<Inkscape::XML::Node*> p(xmlNodes().begin(), xmlNodes().end());3752 std::vector<Inkscape::XML::Node*> p(xmlNodes().begin(), xmlNodes().end());
3704 3753
3705 sort(p.begin(),p.end(),sp_repr_compare_position_bool);3754 sort(p.begin(),p.end(),sp_repr_compare_position_bool);
@@ -3794,7 +3843,7 @@
3794 * If \a apply_clip_path parameter is true, clipPath is created, otherwise mask3843 * If \a apply_clip_path parameter is true, clipPath is created, otherwise mask
3795 *3844 *
3796 */3845 */
3797 void ObjectSet::setMask(bool apply_clip_path, bool apply_to_layer, bool skip_undo)3846void ObjectSet::setMask(bool apply_clip_path, bool apply_to_layer, bool skip_undo)
3798{3847{
3799 if(!desktop() && apply_to_layer)3848 if(!desktop() && apply_to_layer)
3800 return;3849 return;
@@ -3960,7 +4009,7 @@
3960 }4009 }
3961}4010}
39624011
3963void ObjectSet::unsetMask(bool apply_clip_path) {4012void ObjectSet::unsetMask(const bool apply_clip_path, const bool skip_undo) {
3964 SPDocument *doc = document();4013 SPDocument *doc = document();
3965 Inkscape::XML::Document *xml_doc = doc->getReprDoc();4014 Inkscape::XML::Document *xml_doc = doc->getReprDoc();
39664015
@@ -4010,13 +4059,13 @@
40104059
4011 SPGroup *group = dynamic_cast<SPGroup *>(*i);4060 SPGroup *group = dynamic_cast<SPGroup *>(*i);
4012 if (ungroup_masked && group) {4061 if (ungroup_masked && group) {
4013 // if we had previously enclosed masked object in group,4062 // if we had previously enclosed masked object in group,
4014 // add it to list so we can ungroup it later4063 // add it to list so we can ungroup it later
40154064
4016 // ungroup only groups we created when setting clip/mask4065 // ungroup only groups we created when setting clip/mask
4017 if (group->layerMode() == SPGroup::MASK_HELPER) {4066 if (group->layerMode() == SPGroup::MASK_HELPER) {
4018 items_to_ungroup = g_slist_prepend(items_to_ungroup, group);4067 items_to_ungroup = g_slist_prepend(items_to_ungroup, group);
4019 }4068 }
40204069
4021 }4070 }
4022 }4071 }
@@ -4082,10 +4131,12 @@
4082 // rebuild selection4131 // rebuild selection
4083 addList(items_to_select);4132 addList(items_to_select);
40844133
4085 if (apply_clip_path) {4134 if (!skip_undo) {
4086 DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_CLIPPATH, _("Release clipping path"));4135 if (apply_clip_path) {
4087 } else {4136 DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_CLIPPATH, _("Release clipping path"));
4088 DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_MASK, _("Release mask"));4137 } else {
4138 DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_MASK, _("Release mask"));
4139 }
4089 }4140 }
4090}4141}
40914142
40924143
=== modified file 'src/verbs.cpp'
--- src/verbs.cpp 2016-11-02 22:42:43 +0000
+++ src/verbs.cpp 2016-11-04 12:38:02 +0000
@@ -1009,6 +1009,9 @@
1009 case SP_VERB_EDIT_UNLINK_CLONE:1009 case SP_VERB_EDIT_UNLINK_CLONE:
1010 dt->selection->unlink();1010 dt->selection->unlink();
1011 break;1011 break;
1012 case SP_VERB_EDIT_UNLINK_CLONE_RECURSIVE:
1013 dt->selection->unlinkRecursive();
1014 break;
1012 case SP_VERB_EDIT_RELINK_CLONE:1015 case SP_VERB_EDIT_RELINK_CLONE:
1013 dt->selection->relink();1016 dt->selection->relink();
1014 break;1017 break;
@@ -2530,6 +2533,8 @@
2530 N_("Create a clone (a copy linked to the original) of selected object"), INKSCAPE_ICON("edit-clone")),2533 N_("Create a clone (a copy linked to the original) of selected object"), INKSCAPE_ICON("edit-clone")),
2531 new EditVerb(SP_VERB_EDIT_UNLINK_CLONE, "EditUnlinkClone", N_("Unlin_k Clone"),2534 new EditVerb(SP_VERB_EDIT_UNLINK_CLONE, "EditUnlinkClone", N_("Unlin_k Clone"),
2532 N_("Cut the selected clones' links to the originals, turning them into standalone objects"), INKSCAPE_ICON("edit-clone-unlink")),2535 N_("Cut the selected clones' links to the originals, turning them into standalone objects"), INKSCAPE_ICON("edit-clone-unlink")),
2536 new EditVerb(SP_VERB_EDIT_UNLINK_CLONE_RECURSIVE, "EditUnlinkCloneRecursive", N_("Unlink Clones _recursively"),
2537 N_("Unlink all clones in the selection, even if they are in groups."), INKSCAPE_ICON("edit-clone-unlink")),
2533 new EditVerb(SP_VERB_EDIT_RELINK_CLONE, "EditRelinkClone", N_("Relink to Copied"),2538 new EditVerb(SP_VERB_EDIT_RELINK_CLONE, "EditRelinkClone", N_("Relink to Copied"),
2534 N_("Relink the selected clones to the object currently on the clipboard"), NULL),2539 N_("Relink the selected clones to the object currently on the clipboard"), NULL),
2535 new EditVerb(SP_VERB_EDIT_CLONE_SELECT_ORIGINAL, "EditCloneSelectOriginal", N_("Select _Original"),2540 new EditVerb(SP_VERB_EDIT_CLONE_SELECT_ORIGINAL, "EditCloneSelectOriginal", N_("Select _Original"),
25362541
=== modified file 'src/verbs.h'
--- src/verbs.h 2016-10-08 06:16:53 +0000
+++ src/verbs.h 2016-11-04 12:38:02 +0000
@@ -83,6 +83,7 @@
83 SP_VERB_EDIT_DUPLICATE,83 SP_VERB_EDIT_DUPLICATE,
84 SP_VERB_EDIT_CLONE,84 SP_VERB_EDIT_CLONE,
85 SP_VERB_EDIT_UNLINK_CLONE,85 SP_VERB_EDIT_UNLINK_CLONE,
86 SP_VERB_EDIT_UNLINK_CLONE_RECURSIVE,
86 SP_VERB_EDIT_RELINK_CLONE,87 SP_VERB_EDIT_RELINK_CLONE,
87 SP_VERB_EDIT_CLONE_SELECT_ORIGINAL,88 SP_VERB_EDIT_CLONE_SELECT_ORIGINAL,
88 SP_VERB_EDIT_CLONE_ORIGINAL_PATH_LPE,89 SP_VERB_EDIT_CLONE_ORIGINAL_PATH_LPE,