diff --git a/src/Mod/Draft/draftfunctions/downgrade.py b/src/Mod/Draft/draftfunctions/downgrade.py index 841cda2567..e0f41dd237 100644 --- a/src/Mod/Draft/draftfunctions/downgrade.py +++ b/src/Mod/Draft/draftfunctions/downgrade.py @@ -32,6 +32,7 @@ See also the `upgrade` function. # @{ import FreeCAD as App from draftfunctions import cut +from draftmake import make_copy from draftutils import utils from draftutils import params from draftutils import gui_utils @@ -85,13 +86,33 @@ def downgrade(objects, delete=False, force=None): # actions definitions def explode(obj): - """Explode a Draft block.""" - pl = obj.Placement - for o in obj.Components: - o.Placement = pl.multiply(o.Placement) - if App.GuiUp: - o.ViewObject.Visibility = True + """Explode a Draft block or array.""" + obj_pl = obj.Placement + # block: + if getattr(obj, "Components", []): + delete_list.append(obj) + for comp in obj.Components: + comp.Placement = obj_pl.multiply(comp.Placement) + comp.Visibility = True + return True + # array: + if getattr(obj, "Base", None) is None: + return False + if not hasattr(obj, "PlacementList"): + return False + base = obj.Base delete_list.append(obj) + if getattr(obj, "ExpandArray", False): + for lnk in obj.ElementList: + new = make_copy.make_copy(base) + new.Placement = obj_pl.multiply(lnk.Placement) + new.Visibility = True + delete_list.append(lnk) + else: + for arr_pl in obj.PlacementList: + new = make_copy.make_copy(base) + new.Placement = obj_pl.multiply(arr_pl) + new.Visibility = True return True def cut2(objects): @@ -240,15 +261,22 @@ def downgrade(objects, delete=False, force=None): shapify = utils.shapify result = eval(force)(objects) else: - _msg(translate("draft","Upgrade: Unknown force method:") + " " + force) + _msg(translate("draft", "Upgrade: Unknown force method:") + " " + force) result = None else: - # applying transformation automatically # we have a block, we explode it if len(objects) == 1 and utils.get_type(objects[0]) == "Block": result = explode(objects[0]) if result: - _msg(translate("draft","Found 1 block: exploding it")) + _msg(translate("draft", "Found 1 block: exploding it")) + + # we have an array, we explode it + elif len(objects) == 1 \ + and "Array" in utils.get_type(objects[0]) \ + and hasattr(objects[0], "PlacementList"): + result = explode(objects[0]) + if result: + _msg(translate("draft", "Found 1 array: exploding it")) # we have one multi-solids compound object: extract its solids elif len(objects) == 1 \ @@ -257,7 +285,7 @@ def downgrade(objects, delete=False, force=None): result = splitCompounds(objects) # print(result) if result: - _msg(translate("draft","Found 1 multi-solids compound: exploding it")) + _msg(translate("draft", "Found 1 multi-solids compound: exploding it")) # special case, we have one parametric object: we "de-parametrize" it elif len(objects) == 1 \ @@ -266,7 +294,7 @@ def downgrade(objects, delete=False, force=None): and not objects[0].isDerivedFrom("PartDesign::Feature"): result = utils.shapify(objects[0]) if result: - _msg(translate("draft","Found 1 parametric object: breaking its dependencies")) + _msg(translate("draft", "Found 1 parametric object: breaking its dependencies")) add_list.append(result) # delete_list.append(objects[0]) @@ -274,35 +302,35 @@ def downgrade(objects, delete=False, force=None): elif len(objects) == 2: result = cut2(objects) if result: - _msg(translate("draft","Found 2 objects: subtracting them")) + _msg(translate("draft", "Found 2 objects: subtracting them")) elif len(faces) > 1: # one object with several faces: split it if len(objects) == 1: result = splitFaces(objects) if result: - _msg(translate("draft","Found several faces: splitting them")) + _msg(translate("draft", "Found several faces: splitting them")) # several objects: remove all the faces from the first one else: result = subtr(objects) if result: - _msg(translate("draft","Found several objects: subtracting them from the first one")) + _msg(translate("draft", "Found several objects: subtracting them from the first one")) # only one face: we extract its wires elif len(faces) > 0: result = getWire(objects[0]) if result: - _msg(translate("draft","Found 1 face: extracting its wires")) + _msg(translate("draft", "Found 1 face: extracting its wires")) # no faces: split wire into single edges elif not onlyedges: result = splitWires(objects) if result: - _msg(translate("draft","Found only wires: extracting their edges")) + _msg(translate("draft", "Found only wires: extracting their edges")) # no result has been obtained if not result: - _msg(translate("draft","No more downgrade possible")) + _msg(translate("draft", "No more downgrade possible")) if delete: for o in delete_list: diff --git a/src/Mod/Draft/draftobjects/array.py b/src/Mod/Draft/draftobjects/array.py index 646cdf37d3..e16facc29a 100644 --- a/src/Mod/Draft/draftobjects/array.py +++ b/src/Mod/Draft/draftobjects/array.py @@ -65,15 +65,18 @@ class Array(DraftLink): def onDocumentRestored(self, obj): super(Array, self).onDocumentRestored(obj) - if hasattr(obj, "Count"): + # Count property was added in v0.21 and PlacementList property was added + # for non-link arrays in v1.1, obj should be OK if both are present: + if hasattr(obj, "Count") and hasattr(obj, "PlacementList"): return - self.update_properties_0v21(obj) - def update_properties_0v21(self, obj): + if not hasattr(obj, "Count"): + _wrn("v0.21, " + obj.Label + ", " + translate("draft", "added property 'Count'")) + if not hasattr(obj, "PlacementList"): + _wrn("v1.1, " + obj.Label + ", " + translate("draft", "added hidden property 'PlacementList'")) + self.set_general_properties(obj) - self.execute(obj) # Required to update Count to the correct value. - _wrn("v0.21, " + obj.Label + ", " - + translate("draft", "added property 'Count'")) + self.execute(obj) # Required to update Count and/or PlacementList. def set_properties(self, obj): """Set properties only if they don't exist.""" @@ -141,6 +144,16 @@ class Array(DraftLink): obj.Count = 0 obj.setEditorMode("Count", 1) # Read only + if not self.use_link: + if "PlacementList" not in properties: + _tip = QT_TRANSLATE_NOOP("App::Property", + "The placement for each array element") + obj.addProperty("App::PropertyPlacementList", + "PlacementList", + "Objects", + _tip) + obj.PlacementList = [] + def set_ortho_properties(self, obj): """Set orthogonal properties only if they don't exist.""" properties = obj.PropertiesList diff --git a/src/Mod/Draft/draftobjects/draftlink.py b/src/Mod/Draft/draftobjects/draftlink.py index 831b1f934b..9ef85f2dc1 100644 --- a/src/Mod/Draft/draftobjects/draftlink.py +++ b/src/Mod/Draft/draftobjects/draftlink.py @@ -204,8 +204,10 @@ class DraftLink(DraftObject): and getattr(obj, 'AlwaysSyncPlacement', False): for pla,child in zip(pls,obj.ElementList): child.Placement = pla - elif obj.Count != len(pls): - obj.Count = len(pls) + else: + obj.PlacementList = pls + if obj.Count != len(pls): + obj.Count = len(pls) if obj.Base: shape = getattr(obj.Base, 'Shape', None) diff --git a/src/Mod/Draft/draftobjects/patharray.py b/src/Mod/Draft/draftobjects/patharray.py index 35c8bf94e7..bffcc51d57 100644 --- a/src/Mod/Draft/draftobjects/patharray.py +++ b/src/Mod/Draft/draftobjects/patharray.py @@ -262,6 +262,16 @@ class PathArray(DraftLink): obj.ExpandArray = False obj.setPropertyStatus('Shape', 'Transient') + if not self.use_link: + if "PlacementList" not in properties: + _tip = QT_TRANSLATE_NOOP("App::Property", + "The placement for each array element") + obj.addProperty("App::PropertyPlacementList", + "PlacementList", + "Objects", + _tip) + obj.PlacementList = [] + def set_align_properties(self, obj, properties): """Set general properties only if they don't exist.""" if "ExtraTranslation" not in properties: @@ -541,37 +551,39 @@ class PathArray(DraftLink): def onDocumentRestored(self, obj): super().onDocumentRestored(obj) - # Run updates in order: - self.ensure_updated(obj) - - def ensure_updated(self, obj): - # ReversePath was added together with several Spacing properties in v1.1. - # V1.1 props should be OK if it is present. - if hasattr(obj, "ReversePath"): + # ReversePath was added together with several Spacing properties in v1.1, + # and PlacementList property was added for non-link arrays in v1.1, + # obj should be OK if both are present: + if hasattr(obj, "ReversePath") and hasattr(obj, "PlacementList"): return - # Fuse property was added in v1.0. Check if it is already present to - # correctly issue warning. - fuse_was_present = hasattr(obj, "Fuse") - - self.set_properties(obj) if hasattr(obj, "PathObj"): _wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'PathObj' property to 'PathObject'")) + if hasattr(obj, "PathSubs"): + _wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'PathSubs' property to 'PathSubelements'")) + if hasattr(obj, "Xlate"): + _wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'Xlate' property to 'ExtraTranslation'")) + if not hasattr(obj, "Fuse"): + _wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property")) + if obj.getGroupOfProperty("Count") != "Spacing": + _wrn("v1.1, " + obj.Label + ", " + translate("draft", "moved 'Count' property to 'Spacing' subsection")) + if not hasattr(obj, "ReversePath"): + _wrn("v1.1, " + obj.Label + ", " + translate("draft", "added 'ReversePath', 'SpacingMode', 'SpacingUnit', 'UseSpacingPattern' and 'SpacingPattern' properties")) + if not hasattr(obj, "PlacementList"): + _wrn("v1.1, " + obj.Label + ", " + translate("draft", "added hidden property 'PlacementList'")) + + self.set_properties(obj) + obj.setGroupOfProperty("Count", "Spacing") + if hasattr(obj, "PathObj"): obj.PathObject = obj.PathObj obj.removeProperty("PathObj") if hasattr(obj, "PathSubs"): - _wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'PathSubs' property to 'PathSubelements'")) obj.PathSubelements = obj.PathSubs obj.removeProperty("PathSubs") if hasattr(obj, "Xlate"): - _wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'Xlate' property to 'ExtraTranslation'")) obj.ExtraTranslation = obj.Xlate obj.removeProperty("Xlate") - if not fuse_was_present: - _wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property")) - obj.setGroupOfProperty("Count", "Spacing") - _wrn("v1.1, " + obj.Label + ", " + translate("draft", "moved 'Count' to 'Spacing' subsection")) - _wrn("v1.1, " + obj.Label + ", " + translate("draft", "added 'ReversePath', 'SpacingMode', 'SpacingUnit', 'UseSpacingPattern' and 'SpacingPattern' properties")) + self.execute(obj) # Required to update PlacementList. # Alias for compatibility with v0.18 and earlier diff --git a/src/Mod/Draft/draftobjects/pathtwistedarray.py b/src/Mod/Draft/draftobjects/pathtwistedarray.py index 34e4f302e3..d772e14238 100644 --- a/src/Mod/Draft/draftobjects/pathtwistedarray.py +++ b/src/Mod/Draft/draftobjects/pathtwistedarray.py @@ -127,6 +127,16 @@ class PathTwistedArray(DraftLink): obj.ExpandArray = False obj.setPropertyStatus('Shape', 'Transient') + if not self.use_link: + if "PlacementList" not in properties: + _tip = QT_TRANSLATE_NOOP("App::Property", + "The placement for each array element") + obj.addProperty("App::PropertyPlacementList", + "PlacementList", + "Objects", + _tip) + obj.PlacementList = [] + def linkSetup(self, obj): """Set up the object as a link object.""" super().linkSetup(obj) @@ -134,11 +144,18 @@ class PathTwistedArray(DraftLink): def onDocumentRestored(self, obj): super().onDocumentRestored(obj) - # Fuse property was added in v1.0, obj should be OK if it is present: - if hasattr(obj, "Fuse"): + # Fuse property was added in v1.0 and PlacementList property was added + # for non-link arrays in v1.1, obj should be OK if both are present: + if hasattr(obj, "Fuse") and hasattr(obj, "PlacementList"): return + + if not hasattr(obj, "Fuse"): + _wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property")) + if not hasattr(obj, "PlacementList"): + _wrn("v1.1, " + obj.Label + ", " + translate("draft", "added hidden property 'PlacementList'")) + self.set_properties(obj) - _wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property")) + self.execute(obj) # Required to update PlacementList. def execute(self, obj): """Execute when the object is created or recomputed.""" diff --git a/src/Mod/Draft/draftobjects/pointarray.py b/src/Mod/Draft/draftobjects/pointarray.py index 81fde0813c..a9a53cc737 100644 --- a/src/Mod/Draft/draftobjects/pointarray.py +++ b/src/Mod/Draft/draftobjects/pointarray.py @@ -114,6 +114,16 @@ class PointArray(DraftLink): _tip) obj.setPropertyStatus('Shape', 'Transient') + if not self.use_link: + if "PlacementList" not in properties: + _tip = QT_TRANSLATE_NOOP("App::Property", + "The placement for each array element") + obj.addProperty("App::PropertyPlacementList", + "PlacementList", + "Objects", + _tip) + obj.PlacementList = [] + def execute(self, obj): """Run when the object is created or recomputed.""" if self.props_changed_placement_only(obj) \ @@ -132,18 +142,25 @@ class PointArray(DraftLink): def onDocumentRestored(self, obj): super().onDocumentRestored(obj) - # Fuse property was added in v1.0, obj should be OK if it is present: - if hasattr(obj, "Fuse"): + # Fuse property was added in v1.0 and PlacementList property was added + # for non-link arrays in v1.1, obj should be OK if both are present: + if hasattr(obj, "Fuse") and hasattr(obj, "PlacementList"): return + if not hasattr(obj, "ExtraPlacement"): _wrn("v0.19, " + obj.Label + ", " + translate("draft", "added 'ExtraPlacement' property")) - self.set_properties(obj) if hasattr(obj, "PointList"): _wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'PointList' property to 'PointObject'")) + if not hasattr(obj, "Fuse"): + _wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property")) + if not hasattr(obj, "PlacementList"): + _wrn("v1.1, " + obj.Label + ", " + translate("draft", "added hidden property 'PlacementList'")) + + self.set_properties(obj) + if hasattr(obj, "PointList"): obj.PointObject = obj.PointList obj.removeProperty("PointList") - _wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property")) - + self.execute(obj) # Required to update PlacementList. def remove_equal_vecs (vec_list): """Remove equal vectors from a list.