def morphContainer(src_container, dst_container): if not Containers.isContainer(src_container): raise TypeError(u"{obj} is not a container".format(obj= src_container.Label)) if not Containers.isContainer(dst_container): raise TypeError(u"{obj} is not a container".format(obj= dst_container.Label)) if src_container in Containers.getContainerChain(dst_container): raise Containers.ContainerTreeError(u"Cannot morph {src} into {dst}, because {src} contains {dst}" .format(src= src_container.Label, dst= dst_container.Label)) doc = dst_container.Document #origin... if hasattr(src_container, "Origin") and hasattr(dst_container, "Origin"): if dst_container.Origin is not None: doc.removeObject(dst_container.Origin.Name) dst_container.Origin = src_container.Origin; src_container.Origin = None #content assert(len(dst_container.Group) == 0) g = src_container.Group src_container.Group = [] #withdraw first, add last - otherwise, error is thrown dst_container.Group = g if hasattr(dst_container, 'Origin'): if hasattr(dst_container, 'Proxy') and dst_container.Origin is not None: #workaround for origin not being claimed as child on Py-powered containers dst_container.Group = [dst_container.Origin] + dst_container.Group elif dst_container.Origin is not None and dst_container.Origin in dst_container.Group: #if converting Py cotainer into c++-one, undo the workaround content = dst_container.Group content.remove(dst_container.Origin) #Tip if hasattr(src_container, "Tip") and hasattr(dst_container, "Tip"): tip_list = src_container.Tip if type(tip_list) is not list: tip_list = [tip_list] if tip_list is not None else [] if type(dst_container.Tip) is list: dst_container.Tip = tip_list else: if len(tip_list) == 0: dst_container.Tip = None elif len(tip_list) == 1: dst_container.Tip = tip_list[0] else: App.Console.PrintWarning(u"Target Tip can only point to one object. Source Tip points to {num}. Last object from source tip was taken.\n" .format(num= len(tip_list))) dst_container.Tip = tip_list[-1] #other properties... properties_to_avoid = set([ # these are avoided because they need manual treatment... 'Group', 'Origin', 'ExpressionEngine', 'Tip', 'Label', #.. and these should never be copied at all 'ExtensionProxy', 'Proxy', ]) properties_to_copy = [] for prop in src_container.PropertiesList: if len(src_container.getEditorMode(prop)) == 0: # screen out read-only and hidden properties if not prop in properties_to_avoid: properties_to_copy.append(prop) print("copying properties") for prop in properties_to_copy: print(" "+prop) copyProperty(src_container, dst_container, prop) #Copy expressions for expr in src_container.ExpressionEngine: dst_container.setExpression(*expr) #redirect links substituteObjectInProperties(src_container, dst_container, doc.Objects) substituteObjectInExpressions(src_container, dst_container, doc.Objects) substituteObjectInSpreadsheets(src_container, dst_container, doc.Objects) label = src_container.Label label = label.replace(src_container.Name, dst_container.Name) Containers.withdrawObject(src_container) doc.removeObject(src_container.Name) #copy Label last, because otherwise it gets "001" at the end... dst_container.Label = label
def _replace(self, check_dag): # does the business of replacing. But does not set self.replaced flag, so that I can use return statement without caution. prop = self.relation.linking_property new = self.new_object obj = self.relation.linking_object kind = self.relation.kind printLog(u" replacing: {self}\n".format(self= self)) if check_dag: if self.check_dag() == False: raise DAGError(u"Replacement will cause a cycle: {repl}".format(repl= repr(self))) try: self.relation.self_check() except ExpressionGoneError: if new is None: return #during mass-replacements with no new object, expression may have been gone already as a result of previous replacement. Skip this. raise if kind == 'CellExpression': if self.relation.linked_object is self.new_object: printWarn(u"Replacement invoked, but nothing to do. {self}".format(self= repr(self))) return #nothing to do range = self.relation.expression_charrange oldexpr = obj.getContents(prop) #raises ValueError if not a cell if len(oldexpr) == 0 and new is None: return #during mass-replacements with no new object, expression may have been gone already as a result of previous replacement. Skip this. if not oldexpr.startswith('='): raise ReplacementError("No expression found for replacement") if new is not None: newexpr = oldexpr[0:range[0]] + new.Name + oldexpr[range[1]:] else: newexpr = '' if newexpr is not None: printLog(u" '{oldexpr}' -> '{newexpr}'\n" .format(oldexpr= oldexpr, newexpr= newexpr)) obj.set(prop, newexpr) elif kind == 'Expression': if self.relation.linked_object is self.new_object: printWarn(u"Replacement invoked, but nothing to do. {self}".format(self= repr(self))) return #nothing to do ee = dict(obj.ExpressionEngine) if not prop in ee and new is None: return #during mass-replacements with no new object, expression may have been gone already as a result of previous replacement. Skip this. if not prop in ee: raise ReplacementError("No expression found for replacement") oldexpr = ee[prop] range = self.relation.expression_charrange if new is not None: newexpr = oldexpr[0:range[0]] + new.Name + oldexpr[range[1]:] else: newexpr = '' if newexpr is not None: printLog(u" '{oldexpr}' -> '{newexpr}'\n" .format(oldexpr= oldexpr, newexpr= newexpr)) obj.setExpression(prop, newexpr) elif kind == 'Child' or kind == 'Link': if self.relation.linked_object is self.new_object: printWarn(u"Replacement invoked, but nothing to do. {self}".format(self= repr(self))) return #nothing to do if kind == 'Child': #when replacing child links, make sure the new object is not in a container. Otherwise FreeCAD throws an error. from PartOMagic.Base import Containers Containers.withdrawObject(new) typ = obj.getTypeIdOfProperty(prop) val = getattr(obj, prop) if typ.startswith('App::PropertyLinkList'): val = val[0:self.relation.list_index] + ([] if new is None else [new]) + val[self.relation.list_index+1:] elif typ.startswith('App::PropertyLink'): val = new else: raise TypeError(u"Unexpected type of property: {typ}".format(typ= typ)) setattr(obj, prop, val) elif kind == 'Sublink': typ = obj.getTypeIdOfProperty(prop) val = getattr(obj, prop) if self.relation.linked_object is self.new_object and (self.new_sublist is None or self.relation.sublist == self.new_sublist): printWarn(u'Replacement invoked, but nothing to do. {self}'.format(self= repr(self))) return #nothing to do sublist = self.new_sublist if self.new_sublist is not None else self.relation.sublist if typ.startswith('App::PropertyLinkSubList'): val = val[0:self.relation.list_index] + [(new, sublist)] + val[self.relation.list_index+1:] elif typ.startswith('App::PropertyLinkSub'): val = (new, sublist) else: raise TypeError(u"Unexpected type of property: {typ}".format(typ= typ)) setattr(obj, prop, val) else: raise TypeError(u"Unexpected kind of dependency: {kind}".format(kind= kind))
def morphContainer(src_container, dst_container): if not Containers.isContainer(src_container): raise TypeError( u"{obj} is not a container".format(obj=src_container.Label)) if not Containers.isContainer(dst_container): raise TypeError( u"{obj} is not a container".format(obj=dst_container.Label)) if src_container in Containers.getContainerChain(dst_container): raise Containers.ContainerTreeError( u"Cannot morph {src} into {dst}, because {src} contains {dst}". format(src=src_container.Label, dst=dst_container.Label)) doc = dst_container.Document #origin... if hasattr(src_container, "Origin") and hasattr(dst_container, "Origin"): if dst_container.Origin is not None: doc.removeObject(dst_container.Origin.Name) dst_container.Origin = src_container.Origin src_container.Origin = None #content assert (len(dst_container.Group) == 0) g = src_container.Group src_container.Group = [ ] #withdraw first, add last - otherwise, error is thrown dst_container.Group = g if hasattr(dst_container, 'Origin'): if hasattr(dst_container, 'Proxy') and dst_container.Origin is not None: #workaround for origin not being claimed as child on Py-powered containers dst_container.Group = [dst_container.Origin] + dst_container.Group elif dst_container.Origin is not None and dst_container.Origin in dst_container.Group: #if converting Py cotainer into c++-one, undo the workaround content = dst_container.Group content.remove(dst_container.Origin) #Tip if hasattr(src_container, "Tip") and hasattr(dst_container, "Tip"): tip_list = src_container.Tip if type(tip_list) is not list: tip_list = [tip_list] if tip_list is not None else [] if type(dst_container.Tip) is list: dst_container.Tip = tip_list else: if len(tip_list) == 0: dst_container.Tip = None elif len(tip_list) == 1: dst_container.Tip = tip_list[0] else: App.Console.PrintWarning( u"Target Tip can only point to one object. Source Tip points to {num}. Last object from source tip was taken.\n" .format(num=len(tip_list))) dst_container.Tip = tip_list[-1] #other properties... properties_to_avoid = set([ # these are avoided because they need manual treatment... 'Group', 'Origin', 'ExpressionEngine', 'Tip', 'Label', #.. and these should never be copied at all 'ExtensionProxy', 'Proxy', ]) properties_to_copy = [] for prop in src_container.PropertiesList: if len(src_container.getEditorMode( prop)) == 0: # screen out read-only and hidden properties if not prop in properties_to_avoid: properties_to_copy.append(prop) print("copying properties") for prop in properties_to_copy: print(" " + prop) copyProperty(src_container, dst_container, prop) #Copy expressions for expr in src_container.ExpressionEngine: dst_container.setExpression(*expr) #redirect links substituteObjectInProperties(src_container, dst_container, doc.Objects) substituteObjectInExpressions(src_container, dst_container, doc.Objects) substituteObjectInSpreadsheets(src_container, dst_container, doc.Objects) label = src_container.Label label = label.replace(src_container.Name, dst_container.Name) Containers.withdrawObject(src_container) doc.removeObject(src_container.Name) #copy Label last, because otherwise it gets "001" at the end... dst_container.Label = label
def _replace(self, check_dag): # does the business of replacing. But does not set self.replaced flag, so that I can use return statement without caution. prop = self.relation.linking_property new = self.new_object obj = self.relation.linking_object kind = self.relation.kind printLog(u" replacing: {self}\n".format(self=self)) if check_dag: if self.check_dag() == False: raise DAGError( u"Replacement will cause a cycle: {repl}".format( repl=repr(self))) try: self.relation.self_check() except ExpressionGoneError: if new is None: return #during mass-replacements with no new object, expression may have been gone already as a result of previous replacement. Skip this. raise if kind == 'CellExpression': if self.relation.linked_object is self.new_object: printWarn( u"Replacement invoked, but nothing to do. {self}".format( self=repr(self))) return #nothing to do range = self.relation.expression_charrange oldexpr = obj.getContents(prop) #raises ValueError if not a cell if len(oldexpr) == 0 and new is None: return #during mass-replacements with no new object, expression may have been gone already as a result of previous replacement. Skip this. if not oldexpr.startswith('='): raise ReplacementError("No expression found for replacement") if new is not None: newexpr = oldexpr[0:range[0]] + new.Name + oldexpr[range[1]:] else: newexpr = '' if newexpr is not None: printLog(u" '{oldexpr}' -> '{newexpr}'\n".format( oldexpr=oldexpr, newexpr=newexpr)) obj.set(prop, newexpr) elif kind == 'Expression': if self.relation.linked_object is self.new_object: printWarn( u"Replacement invoked, but nothing to do. {self}".format( self=repr(self))) return #nothing to do ee = dict(obj.ExpressionEngine) if not prop in ee and new is None: return #during mass-replacements with no new object, expression may have been gone already as a result of previous replacement. Skip this. if not prop in ee: raise ReplacementError("No expression found for replacement") oldexpr = ee[prop] range = self.relation.expression_charrange if new is not None: newexpr = oldexpr[0:range[0]] + new.Name + oldexpr[range[1]:] else: newexpr = '' if newexpr is not None: printLog(u" '{oldexpr}' -> '{newexpr}'\n".format( oldexpr=oldexpr, newexpr=newexpr)) obj.setExpression(prop, newexpr) elif kind == 'Child' or kind == 'Link': if self.relation.linked_object is self.new_object: printWarn( u"Replacement invoked, but nothing to do. {self}".format( self=repr(self))) return #nothing to do if kind == 'Child': #when replacing child links, make sure the new object is not in a container. Otherwise FreeCAD throws an error. from PartOMagic.Base import Containers Containers.withdrawObject(new) typ = obj.getTypeIdOfProperty(prop) val = getattr(obj, prop) if typ.startswith('App::PropertyLinkList'): val = val[0:self.relation.list_index] + ( [] if new is None else [new]) + val[self.relation.list_index + 1:] elif typ.startswith('App::PropertyLink'): val = new else: raise TypeError( u"Unexpected type of property: {typ}".format(typ=typ)) setattr(obj, prop, val) elif kind == 'Sublink': typ = obj.getTypeIdOfProperty(prop) val = getattr(obj, prop) if self.relation.linked_object is self.new_object and ( self.new_sublist is None or self.relation.sublist == self.new_sublist): printWarn( u'Replacement invoked, but nothing to do. {self}'.format( self=repr(self))) return #nothing to do sublist = self.new_sublist if self.new_sublist is not None else self.relation.sublist if typ.startswith('App::PropertyLinkSubList'): val = val[0:self.relation.list_index] + [ (new, sublist) ] + val[self.relation.list_index + 1:] elif typ.startswith('App::PropertyLinkSub'): val = (new, sublist) else: raise TypeError( u"Unexpected type of property: {typ}".format(typ=typ)) setattr(obj, prop, val) else: raise TypeError( u"Unexpected kind of dependency: {kind}".format(kind=kind))