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
Beispiel #2
0
    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))
Beispiel #3
0
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
Beispiel #4
0
    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))