Refactor undo/redo with FreeCAD.setActiveTransaction()

This commit is contained in:
Zheng, Lei 2017-12-24 18:43:34 +08:00
parent 089f3e1c20
commit eb6519ff8c
3 changed files with 60 additions and 67 deletions

View File

@ -7,16 +7,6 @@ from .utils import logger, objName
from .constraint import Constraint, cstrName from .constraint import Constraint, cstrName
from .system import System from .system import System
def setupUndo(doc,undoDocs,name):
if undoDocs is None:
return
if doc.HasPendingTransaction or doc in undoDocs:
return
if not name:
name = 'Assembly solve'
doc.openTransaction(name)
undoDocs.add(doc)
def isTypeOf(obj,tp,resolve=False): def isTypeOf(obj,tp,resolve=False):
if not obj: if not obj:
return False return False
@ -367,7 +357,7 @@ class AsmElement(AsmBase):
Subname=link.Subname+subElement) Subname=link.Subname+subElement)
@staticmethod @staticmethod
def make(selection=None,name='Element'): def make(selection=None,name='Element',undo=False):
'''Add/get/modify an element with the given selected object''' '''Add/get/modify an element with the given selected object'''
if not selection: if not selection:
selection = AsmElement.getSelection() selection = AsmElement.getSelection()
@ -443,22 +433,32 @@ class AsmElement(AsmBase):
group.Name,subname)) group.Name,subname))
element = selection.Element element = selection.Element
if not element:
elements = group.Proxy.getAssembly().getElementGroup()
# try to search the element group for an existing element
for e in elements.Group:
sub = logger.catch('',e.Proxy.getSubName)
if sub == subname:
return e
element = elements.Document.addObject("App::FeaturePython",
name,AsmElement(elements),None,True)
ViewProviderAsmElement(element.ViewObject)
elements.setLink({-1:element})
elements.setElementVisible(element.Name,False)
element.Proxy._initializing = False
elements.cacheChildLabel()
element.setLink(group,subname) try:
if undo:
FreeCAD.setActiveTransaction('Assembly change element' \
if element else 'Assembly create element')
if not element:
elements = group.Proxy.getAssembly().getElementGroup()
# try to search the element group for an existing element
for e in elements.Group:
sub = logger.catch('',e.Proxy.getSubName)
if sub == subname:
return e
element = elements.Document.addObject("App::FeaturePython",
name,AsmElement(elements),None,True)
ViewProviderAsmElement(element.ViewObject)
elements.setLink({-1:element})
elements.setElementVisible(element.Name,False)
element.Proxy._initializing = False
elements.cacheChildLabel()
element.setLink(group,subname)
if undo:
FreeCAD.closeActiveTransaction()
except Exception:
if undo:
FreeCAD.closeActiveTransaction(True)
raise
return element return element
@ -483,7 +483,7 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
def dropObjectEx(self,vobj,_obj,owner,subname): def dropObjectEx(self,vobj,_obj,owner,subname):
AsmElement.make(AsmElement.Selection(Element=vobj.Object, AsmElement.make(AsmElement.Selection(Element=vobj.Object,
Group=owner, Subname=subname)) Group=owner, Subname=subname),undo=True)
PartInfo = namedtuple('AsmPartInfo', ('Parent','SubnameRef','Part', PartInfo = namedtuple('AsmPartInfo', ('Parent','SubnameRef','Part',
@ -747,7 +747,7 @@ class AsmElementLink(AsmBase):
return self.info return self.info
@staticmethod @staticmethod
def setPlacement(part,pla,undoDocs,undoName): def setPlacement(part,pla):
''' '''
called by solver after solving to adjust the placement. called by solver after solving to adjust the placement.
@ -756,13 +756,10 @@ class AsmElementLink(AsmBase):
''' '''
if isinstance(part,tuple): if isinstance(part,tuple):
if isinstance(part[1],int): if isinstance(part[1],int):
setupUndo(part[0].Document,undoDocs,undoName)
part[0].PlacementList = {part[1]:pla} part[0].PlacementList = {part[1]:pla}
else: else:
setupUndo(part[1].Document,undoDocs,undoName)
part[1].Placement = pla part[1].Placement = pla
else: else:
setupUndo(part.Document,undoDocs,undoName)
part.Placement = pla part.Placement = pla
MakeInfo = namedtuple('AsmElementLinkMakeInfo', MakeInfo = namedtuple('AsmElementLinkMakeInfo',
@ -777,8 +774,8 @@ class AsmElementLink(AsmBase):
link.Proxy.setLink(info.Owner,info.Subname) link.Proxy.setLink(info.Owner,info.Subname)
return link return link
def setPlacement(part,pla,undoDocs,undoName=None): def setPlacement(part,pla):
AsmElementLink.setPlacement(part,pla,undoDocs,undoName) AsmElementLink.setPlacement(part,pla)
class ViewProviderAsmElementLink(ViewProviderAsmOnTop): class ViewProviderAsmElementLink(ViewProviderAsmOnTop):
@ -989,15 +986,13 @@ class AsmConstraint(AsmGroup):
if not sel: if not sel:
sel = AsmConstraint.getSelection(typeid) sel = AsmConstraint.getSelection(typeid)
if sel.Constraint: if sel.Constraint:
if undo:
FreeCAD.setActiveTransaction('Assembly change constraint')
cstr = sel.Constraint cstr = sel.Constraint
if undo:
doc = cstr.Document
doc.openTransaction('Assembly change constraint')
else: else:
constraints = sel.Assembly.Proxy.getConstraintGroup()
if undo: if undo:
doc = constraints.Document FreeCAD.setActiveTransaction('Assembly create constraint')
doc.openTransaction('Assembly make constraint') constraints = sel.Assembly.Proxy.getConstraintGroup()
cstr = constraints.Document.addObject("App::FeaturePython", cstr = constraints.Document.addObject("App::FeaturePython",
name,AsmConstraint(constraints),None,True) name,AsmConstraint(constraints),None,True)
proxy = ViewProviderAsmConstraint(cstr.ViewObject) proxy = ViewProviderAsmConstraint(cstr.ViewObject)
@ -1016,7 +1011,7 @@ class AsmConstraint(AsmGroup):
logger.catch('solver exception when auto recompute', logger.catch('solver exception when auto recompute',
solver.solve, sel.Assembly, undo=undo) solver.solve, sel.Assembly, undo=undo)
if undo: if undo:
doc.commitTransaction() FreeCAD.closeActiveTransaction()
if sel.SelObject: if sel.SelObject:
FreeCADGui.Selection.clearSelection() FreeCADGui.Selection.clearSelection()
@ -1031,7 +1026,7 @@ class AsmConstraint(AsmGroup):
except Exception: except Exception:
if undo: if undo:
doc.abortTransaction() FreeCAD.closeActiveTransaction(True)
raise raise
@ -1202,7 +1197,8 @@ class Assembly(AsmGroup):
def buildShape(self): def buildShape(self):
obj = self.Object obj = self.Object
if obj.BuildShape == BuildShapeNone: if obj.BuildShape == BuildShapeNone:
obj.Shape = Part.Shape() if not obj.Shape.isNull():
obj.Shape = Part.Shape()
return return
shape = [] shape = []
@ -1358,7 +1354,7 @@ class Assembly(AsmGroup):
if not doc: if not doc:
raise RuntimeError('No active document') raise RuntimeError('No active document')
if undo: if undo:
doc.openTransaction('Create assembly') FreeCAD.setActiveTransaction('Create assembly')
try: try:
obj = doc.addObject( obj = doc.addObject(
"Part::FeaturePython",name,Assembly(),None,True) "Part::FeaturePython",name,Assembly(),None,True)
@ -1366,10 +1362,10 @@ class Assembly(AsmGroup):
obj.Visibility = True obj.Visibility = True
obj.purgeTouched() obj.purgeTouched()
if undo: if undo:
doc.commitTransaction() FreeCAD.closeActiveTransaction()
except Exception: except Exception:
if undo: if undo:
doc.abortTransaction() FreeCAD.closeActiveTransaction(True)
raise raise
return obj return obj
@ -1541,8 +1537,6 @@ class AsmMovingPart(object):
self.trace.recompute() self.trace.recompute()
return pla return pla
_undoName = 'Assembly move'
def move(self): def move(self):
obj = self.assembly.Object obj = self.assembly.Object
pla = obj.ViewObject.DraggingPlacement pla = obj.ViewObject.DraggingPlacement
@ -1557,7 +1551,7 @@ class AsmMovingPart(object):
# parent assembly instead # parent assembly instead
rollback.append((obj.Name,obj,obj.Placement.copy())) rollback.append((obj.Name,obj,obj.Placement.copy()))
pla = obj.Placement.multiply(movement) pla = obj.Placement.multiply(movement)
setPlacement(obj,pla,self.undos,self._undoName) setPlacement(obj,pla)
update = False update = False
else: else:
# fixed position, so reset translation # fixed position, so reset translation
@ -1573,7 +1567,7 @@ class AsmMovingPart(object):
if update: if update:
# obtain and update the part placement # obtain and update the part placement
pla = pla.multiply(self.offsetInv) pla = pla.multiply(self.offsetInv)
setPlacement(self.part,pla,self.undos,self._undoName) setPlacement(self.part,pla)
rollback.append((self.partName,self.part,self.oldPlacement.copy())) rollback.append((self.partName,self.part,self.oldPlacement.copy()))
if not gui.AsmCmdManager.AutoRecompute or \ if not gui.AsmCmdManager.AutoRecompute or \
@ -1746,14 +1740,13 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
self._movingPart.bbox) self._movingPart.bbox)
def onDragStart(self): def onDragStart(self):
self._movingPart.undos = set() FreeCAD.setActiveTransaction('Assembly move')
def onDragMotion(self): def onDragMotion(self):
return self._movingPart.move() return self._movingPart.move()
def onDragEnd(self): def onDragEnd(self):
for doc in self._movingPart.undos: FreeCAD.closeActiveTransaction()
doc.commitTransaction()
def unsetEdit(self,_vobj,_mode): def unsetEdit(self,_vobj,_mode):
self._movingPart = None self._movingPart = None
@ -1808,7 +1801,7 @@ class AsmWorkPlane(object):
info = AsmWorkPlane.getSelection(sels) info = AsmWorkPlane.getSelection(sels)
doc = info.PartGroup.Document doc = info.PartGroup.Document
if undo: if undo:
doc.openTransaction('Assembly make workplane') FreeCAD.setActiveTransaction('Assembly create workplane')
try: try:
obj = doc.addObject('Part::FeaturePython',name) obj = doc.addObject('Part::FeaturePython',name)
AsmWorkPlane(obj) AsmWorkPlane(obj)
@ -1819,7 +1812,8 @@ class AsmWorkPlane(object):
obj.Width = obj.Length obj.Width = obj.Length
obj.recompute(True) obj.recompute(True)
info.PartGroup.setLink({-1:obj}) info.PartGroup.setLink({-1:obj})
doc.commitTransaction() if undo:
FreeCAD.closeActiveTransaction()
FreeCADGui.Selection.clearSelection() FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(info.SelObj, FreeCADGui.Selection.addSelection(info.SelObj,
@ -1828,7 +1822,7 @@ class AsmWorkPlane(object):
return obj return obj
except Exception: except Exception:
if undo: if undo:
doc.abortTransaction() FreeCAD.closeActiveTransaction(True)
raise raise

4
gui.py
View File

@ -276,14 +276,14 @@ class AsmCmdUp(AsmCmdBase):
j = 0 j = 0
logger.debug('move {}:{} -> {}:{}'.format( logger.debug('move {}:{} -> {}:{}'.format(
i,objName(obj),j,objName(children[j]))) i,objName(obj),j,objName(children[j])))
parent.Document.openTransaction(cls._menuText) FreeCAD.setActiveTransaction(cls._menuText)
readonly = 'Immutable' in parent.getPropertyStatus('Group') readonly = 'Immutable' in parent.getPropertyStatus('Group')
if readonly: if readonly:
parent.setPropertyStatus('Group','-Immutable') parent.setPropertyStatus('Group','-Immutable')
parent.Group = {i:children[j],j:obj} parent.Group = {i:children[j],j:obj}
if readonly: if readonly:
parent.setPropertyStatus('Group','Immutable') parent.setPropertyStatus('Group','Immutable')
parent.Document.commitTransaction() FreeCAD.closeActiveTransaction();
# The tree view may deselect the item because of claimChildren changes, # The tree view may deselect the item because of claimChildren changes,
# so we restore the selection here # so we restore the selection here
FreeCADGui.Selection.addSelection(topParent,subname) FreeCADGui.Selection.addSelection(topParent,subname)

View File

@ -56,14 +56,13 @@ class Solver(object):
if dragPart in self._fixedParts: if dragPart in self._fixedParts:
raise RuntimeError('cannot drag fixed part') raise RuntimeError('cannot drag fixed part')
info = self._partMap.get(dragPart,None) info = self._partMap.get(dragPart,None)
if not info: if info:
raise RuntimeError('invalid dragging part') # add dragging point
self.system.log('add drag point '
# add dragging point '{}'.format(info.Workplane[1]))
self.system.log('add drag point {}'.format(info.Workplane[1])) # TODO: slvs addWhereDragged doesn't work as expected, need
# TODO: slvs addWhereDragged doesn't work as expected, need to # to investigate more
# investigate more # addDragPoint(info.Workplane[1],group=self.group)
# addDragPoint(info.Workplane[1],group=self.group)
self.system.log('solving {}'.format(objName(assembly))) self.system.log('solving {}'.format(objName(assembly)))
try: try:
@ -107,7 +106,7 @@ class Solver(object):
touched = True touched = True
self.system.log('moving {} {} {} {}'.format( self.system.log('moving {} {} {} {}'.format(
partInfo.PartName,partInfo.Params,params,pla)) partInfo.PartName,partInfo.Params,params,pla))
setPlacement(part,pla,undoDocs) setPlacement(part,pla)
if rollback is not None: if rollback is not None:
rollback.append((partInfo.PartName, rollback.append((partInfo.PartName,
part, part,
@ -216,7 +215,7 @@ def solve(objs=None,recursive=None,reportFailed=True,
if rollback is not None: if rollback is not None:
for name,part,pla in reversed(rollback): for name,part,pla in reversed(rollback):
logger.debug('roll back {} to {}'.format(name,pla)) logger.debug('roll back {} to {}'.format(name,pla))
setPlacement(part,pla,None) setPlacement(part,pla)
raise raise
return True return True