Merge lp:~inkscape+alexander/inkscape/clones into lp:~inkscape.dev/inkscape/trunk
- clones
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~inkscape+alexander/inkscape/clones |
Merge into: | lp:~inkscape.dev/inkscape/trunk |
Diff against target: |
184 lines (+80/-11) 5 files modified
src/menus-skeleton.h (+1/-0) src/object-set.h (+14/-2) src/selection-chemistry.cpp (+59/-9) src/verbs.cpp (+5/-0) src/verbs.h (+1/-0) |
To merge this branch: | bzr merge lp:~inkscape+alexander/inkscape/clones |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mc | code, refactor | Pending | |
Martin Owens | Pending | ||
Review via email: mp+310059@code.launchpad.net |
This proposal supersedes a proposal from 2016-10-27.
This proposal has been superseded by a proposal from 2016-11-04.
Commit message
Add "Edit->
Description of the change
I added "Edit->
Mc... rewrote the function and I improved it further.
Mc (mc...) wrote : Posted in a previous version of this proposal | # |
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.
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).
Mc (mc...) wrote : Posted in a previous version of this proposal | # |
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/
Tavmjong Bah (tavmjong-free) wrote : | # |
Please get rid of gratuitous spacing differences. It makes it much harder to see what is really being changed.
Alexander Brock (brock-alexander) wrote : | # |
@mc...: Thank you for rewriting the unlinkRecursive function. I checked out your version, tested it, found some problems and fixed them:
1.
unlinked = unlinked || tmp_set.
From the C++ standard: "Unlike |, || guarantees left-to-right evaluation; moreover, the second operand is not evaluated if the first operand evaluates to true."
So if unlinked is already true then the unlinkRecursive function is not called, preventing groups of clones from beeing unlinked. I changed it:
unlinked = tmp_set.
2.
if(SP_IS_GROUP(it)) {
......
} else if(dynamic_
This causes two problems: First, if an Object is a group masked (or clipped) by a clone that clone would not be unlinked.
Second, if the object is not SPUse, SPText or SPTRef it still is necessary to run the code, it might be clipped or masked by a clone of some object.
I removed the else if so the code runs unconditionally.
3.
unlinked = unlinked || tmp_set.unlink();
This causes calls to DocumentUndo::done (also see 1.), so I changed it:
unlinked = tmp_set.
- 15205. By Alexander Brock <email address hidden>
-
Add "Edit->
Clone-> Unlink Clones recursively" function (ObjectSet: :unlinkRecursiv e) - 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:
:unlinkRecursiv e() and add tests for it.
Unmerged revisions
Preview Diff
1 | === modified file 'src/menus-skeleton.h' | |||
2 | --- src/menus-skeleton.h 2016-04-15 14:39:49 +0000 | |||
3 | +++ src/menus-skeleton.h 2016-11-04 14:19:19 +0000 | |||
4 | @@ -66,6 +66,7 @@ | |||
5 | 66 | " <verb verb-id=\"EditClone\" />\n" | 66 | " <verb verb-id=\"EditClone\" />\n" |
6 | 67 | " <verb verb-id=\"DialogClonetiler\" />\n" | 67 | " <verb verb-id=\"DialogClonetiler\" />\n" |
7 | 68 | " <verb verb-id=\"EditUnlinkClone\" />\n" | 68 | " <verb verb-id=\"EditUnlinkClone\" />\n" |
8 | 69 | " <verb verb-id=\"EditUnlinkCloneRecursive\" />\n" | ||
9 | 69 | " <verb verb-id=\"EditRelinkClone\" />\n" | 70 | " <verb verb-id=\"EditRelinkClone\" />\n" |
10 | 70 | " <verb verb-id=\"EditCloneSelectOriginal\" />\n" | 71 | " <verb verb-id=\"EditCloneSelectOriginal\" />\n" |
11 | 71 | " <verb verb-id=\"EditCloneOriginalPathLPE\" />\n" | 72 | " <verb verb-id=\"EditCloneOriginalPathLPE\" />\n" |
12 | 72 | 73 | ||
13 | === modified file 'src/object-set.h' | |||
14 | --- src/object-set.h 2016-11-03 23:28:50 +0000 | |||
15 | +++ src/object-set.h 2016-11-04 14:19:19 +0000 | |||
16 | @@ -330,7 +330,19 @@ | |||
17 | 330 | void deleteItems(); | 330 | void deleteItems(); |
18 | 331 | void duplicate(bool suppressDone = false, bool duplicateLayer = false); | 331 | void duplicate(bool suppressDone = false, bool duplicateLayer = false); |
19 | 332 | void clone(); | 332 | void clone(); |
21 | 333 | void unlink(); | 333 | |
22 | 334 | /** | ||
23 | 335 | * @brief Unlink all directly selected clones. | ||
24 | 336 | * @param skip_undo If this is set to true the call to DocumentUndo::done is omitted. | ||
25 | 337 | * @return True if anything was unlinked, otherwise false. | ||
26 | 338 | */ | ||
27 | 339 | bool unlink(const bool skip_undo = false); | ||
28 | 340 | /** | ||
29 | 341 | * @brief Recursively unlink any clones present in the current selection, | ||
30 | 342 | * including clones which are used to clip other objects, groups of clones etc. | ||
31 | 343 | * @return true if anything was unlinked, otherwise false. | ||
32 | 344 | */ | ||
33 | 345 | bool unlinkRecursive(const bool skip_undo = false); | ||
34 | 334 | void relink(); | 346 | void relink(); |
35 | 335 | void cloneOriginal(); | 347 | void cloneOriginal(); |
36 | 336 | void cloneOriginalPathLPE(); | 348 | void cloneOriginalPathLPE(); |
37 | @@ -376,7 +388,7 @@ | |||
38 | 376 | void createBitmapCopy(); | 388 | void createBitmapCopy(); |
39 | 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); |
40 | 378 | void editMask(bool clip); | 390 | void editMask(bool clip); |
42 | 379 | void unsetMask(bool apply_clip_path); | 391 | void unsetMask(const bool apply_clip_path, const bool skip_undo = false); |
43 | 380 | void setClipGroup(); | 392 | void setClipGroup(); |
44 | 381 | 393 | ||
45 | 382 | // moves | 394 | // moves |
46 | 383 | 395 | ||
47 | === modified file 'src/selection-chemistry.cpp' | |||
48 | --- src/selection-chemistry.cpp 2016-11-02 23:08:41 +0000 | |||
49 | +++ src/selection-chemistry.cpp 2016-11-04 14:19:19 +0000 | |||
50 | @@ -2653,12 +2653,12 @@ | |||
51 | 2653 | } | 2653 | } |
52 | 2654 | 2654 | ||
53 | 2655 | 2655 | ||
55 | 2656 | void ObjectSet::unlink() | 2656 | bool ObjectSet::unlink(const bool skip_undo) |
56 | 2657 | { | 2657 | { |
57 | 2658 | if (isEmpty()) { | 2658 | if (isEmpty()) { |
58 | 2659 | if(desktop()) | 2659 | if(desktop()) |
59 | 2660 | desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>clones</b> to unlink.")); | 2660 | desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>clones</b> to unlink.")); |
61 | 2661 | return; | 2661 | return false; |
62 | 2662 | } | 2662 | } |
63 | 2663 | 2663 | ||
64 | 2664 | // Get a copy of current selection. | 2664 | // Get a copy of current selection. |
65 | @@ -2715,8 +2715,56 @@ | |||
66 | 2715 | desktop()->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection.")); | 2715 | desktop()->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection.")); |
67 | 2716 | } | 2716 | } |
68 | 2717 | 2717 | ||
71 | 2718 | DocumentUndo::done(document(), SP_VERB_EDIT_UNLINK_CLONE, | 2718 | if (!skip_undo) { |
72 | 2719 | _("Unlink clone")); | 2719 | DocumentUndo::done(document(), SP_VERB_EDIT_UNLINK_CLONE, |
73 | 2720 | _("Unlink clone")); | ||
74 | 2721 | } | ||
75 | 2722 | return unlinked; | ||
76 | 2723 | } | ||
77 | 2724 | |||
78 | 2725 | bool ObjectSet::unlinkRecursive(const bool skip_undo) { | ||
79 | 2726 | if (isEmpty()){ | ||
80 | 2727 | if (desktop()) | ||
81 | 2728 | desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>clones</b> to unlink.")); | ||
82 | 2729 | return false; | ||
83 | 2730 | } | ||
84 | 2731 | bool unlinked = false; | ||
85 | 2732 | ObjectSet tmp_set(document()); | ||
86 | 2733 | std::vector<SPItem*> items_(items().begin(), items().end()); | ||
87 | 2734 | for (auto& it:items_){ | ||
88 | 2735 | if (SP_IS_GROUP(it)) { | ||
89 | 2736 | std::vector<SPObject*> c = it->childList(false); | ||
90 | 2737 | tmp_set.setList(c); | ||
91 | 2738 | unlinked = tmp_set.unlinkRecursive(true) || unlinked; | ||
92 | 2739 | } | ||
93 | 2740 | tmp_set.set(it); | ||
94 | 2741 | bool has_clip = false; | ||
95 | 2742 | bool has_mask = false; | ||
96 | 2743 | Inkscape::URIReference *clip = it->clip_ref; | ||
97 | 2744 | Inkscape::URIReference *mask = it->mask_ref; | ||
98 | 2745 | if ((NULL != clip) && (NULL != clip->getObject())) { | ||
99 | 2746 | tmp_set.unsetMask(true,true); | ||
100 | 2747 | has_clip = true; | ||
101 | 2748 | } | ||
102 | 2749 | if ((NULL != mask) && (NULL != mask->getObject())) { | ||
103 | 2750 | tmp_set.unsetMask(false,true); | ||
104 | 2751 | has_mask = true; | ||
105 | 2752 | } | ||
106 | 2753 | unlinked = tmp_set.unlink(true) || unlinked; | ||
107 | 2754 | if (has_mask) | ||
108 | 2755 | tmp_set.setMask(false,false,true); | ||
109 | 2756 | if (has_clip) | ||
110 | 2757 | tmp_set.setMask(true,false,true); | ||
111 | 2758 | } | ||
112 | 2759 | if (!unlinked) { | ||
113 | 2760 | if(desktop()) | ||
114 | 2761 | desktop()->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection.")); | ||
115 | 2762 | } | ||
116 | 2763 | if (!skip_undo) { | ||
117 | 2764 | DocumentUndo::done(document(), SP_VERB_EDIT_UNLINK_CLONE_RECURSIVE, | ||
118 | 2765 | _("Unlink clone recursively")); | ||
119 | 2766 | } | ||
120 | 2767 | return unlinked; | ||
121 | 2720 | } | 2768 | } |
122 | 2721 | 2769 | ||
123 | 2722 | void ObjectSet::cloneOriginal() | 2770 | void ObjectSet::cloneOriginal() |
124 | @@ -3960,7 +4008,7 @@ | |||
125 | 3960 | } | 4008 | } |
126 | 3961 | } | 4009 | } |
127 | 3962 | 4010 | ||
129 | 3963 | void ObjectSet::unsetMask(bool apply_clip_path) { | 4011 | void ObjectSet::unsetMask(const bool apply_clip_path, const bool skip_undo) { |
130 | 3964 | SPDocument *doc = document(); | 4012 | SPDocument *doc = document(); |
131 | 3965 | Inkscape::XML::Document *xml_doc = doc->getReprDoc(); | 4013 | Inkscape::XML::Document *xml_doc = doc->getReprDoc(); |
132 | 3966 | 4014 | ||
133 | @@ -4082,10 +4130,12 @@ | |||
134 | 4082 | // rebuild selection | 4130 | // rebuild selection |
135 | 4083 | addList(items_to_select); | 4131 | addList(items_to_select); |
136 | 4084 | 4132 | ||
141 | 4085 | if (apply_clip_path) { | 4133 | if (!skip_undo) { |
142 | 4086 | DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_CLIPPATH, _("Release clipping path")); | 4134 | if (apply_clip_path) { |
143 | 4087 | } else { | 4135 | DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_CLIPPATH, _("Release clipping path")); |
144 | 4088 | DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_MASK, _("Release mask")); | 4136 | } else { |
145 | 4137 | DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_MASK, _("Release mask")); | ||
146 | 4138 | } | ||
147 | 4089 | } | 4139 | } |
148 | 4090 | } | 4140 | } |
149 | 4091 | 4141 | ||
150 | 4092 | 4142 | ||
151 | === modified file 'src/verbs.cpp' | |||
152 | --- src/verbs.cpp 2016-11-02 22:42:43 +0000 | |||
153 | +++ src/verbs.cpp 2016-11-04 14:19:19 +0000 | |||
154 | @@ -1009,6 +1009,9 @@ | |||
155 | 1009 | case SP_VERB_EDIT_UNLINK_CLONE: | 1009 | case SP_VERB_EDIT_UNLINK_CLONE: |
156 | 1010 | dt->selection->unlink(); | 1010 | dt->selection->unlink(); |
157 | 1011 | break; | 1011 | break; |
158 | 1012 | case SP_VERB_EDIT_UNLINK_CLONE_RECURSIVE: | ||
159 | 1013 | dt->selection->unlinkRecursive(); | ||
160 | 1014 | break; | ||
161 | 1012 | case SP_VERB_EDIT_RELINK_CLONE: | 1015 | case SP_VERB_EDIT_RELINK_CLONE: |
162 | 1013 | dt->selection->relink(); | 1016 | dt->selection->relink(); |
163 | 1014 | break; | 1017 | break; |
164 | @@ -2530,6 +2533,8 @@ | |||
165 | 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")), |
166 | 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"), |
167 | 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")), |
168 | 2536 | new EditVerb(SP_VERB_EDIT_UNLINK_CLONE_RECURSIVE, "EditUnlinkCloneRecursive", N_("Unlink Clones _recursively"), | ||
169 | 2537 | N_("Unlink all clones in the selection, even if they are in groups."), INKSCAPE_ICON("edit-clone-unlink")), | ||
170 | 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"), |
171 | 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), |
172 | 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"), |
173 | 2536 | 2541 | ||
174 | === modified file 'src/verbs.h' | |||
175 | --- src/verbs.h 2016-10-08 06:16:53 +0000 | |||
176 | +++ src/verbs.h 2016-11-04 14:19:19 +0000 | |||
177 | @@ -83,6 +83,7 @@ | |||
178 | 83 | SP_VERB_EDIT_DUPLICATE, | 83 | SP_VERB_EDIT_DUPLICATE, |
179 | 84 | SP_VERB_EDIT_CLONE, | 84 | SP_VERB_EDIT_CLONE, |
180 | 85 | SP_VERB_EDIT_UNLINK_CLONE, | 85 | SP_VERB_EDIT_UNLINK_CLONE, |
181 | 86 | SP_VERB_EDIT_UNLINK_CLONE_RECURSIVE, | ||
182 | 86 | SP_VERB_EDIT_RELINK_CLONE, | 87 | SP_VERB_EDIT_RELINK_CLONE, |
183 | 87 | SP_VERB_EDIT_CLONE_SELECT_ORIGINAL, | 88 | SP_VERB_EDIT_CLONE_SELECT_ORIGINAL, |
184 | 88 | SP_VERB_EDIT_CLONE_ORIGINAL_PATH_LPE, | 89 | SP_VERB_EDIT_CLONE_ORIGINAL_PATH_LPE, |
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.