Refactor undo/redo with FreeCAD.setActiveTransaction()
This commit is contained in:
parent
089f3e1c20
commit
eb6519ff8c
74
assembly.py
74
assembly.py
|
@ -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,6 +433,11 @@ class AsmElement(AsmBase):
|
||||||
group.Name,subname))
|
group.Name,subname))
|
||||||
|
|
||||||
element = selection.Element
|
element = selection.Element
|
||||||
|
|
||||||
|
try:
|
||||||
|
if undo:
|
||||||
|
FreeCAD.setActiveTransaction('Assembly change element' \
|
||||||
|
if element else 'Assembly create element')
|
||||||
if not element:
|
if not element:
|
||||||
elements = group.Proxy.getAssembly().getElementGroup()
|
elements = group.Proxy.getAssembly().getElementGroup()
|
||||||
# try to search the element group for an existing element
|
# try to search the element group for an existing element
|
||||||
|
@ -457,8 +452,13 @@ class AsmElement(AsmBase):
|
||||||
elements.setElementVisible(element.Name,False)
|
elements.setElementVisible(element.Name,False)
|
||||||
element.Proxy._initializing = False
|
element.Proxy._initializing = False
|
||||||
elements.cacheChildLabel()
|
elements.cacheChildLabel()
|
||||||
|
|
||||||
element.setLink(group,subname)
|
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,6 +1197,7 @@ class Assembly(AsmGroup):
|
||||||
def buildShape(self):
|
def buildShape(self):
|
||||||
obj = self.Object
|
obj = self.Object
|
||||||
if obj.BuildShape == BuildShapeNone:
|
if obj.BuildShape == BuildShapeNone:
|
||||||
|
if not obj.Shape.isNull():
|
||||||
obj.Shape = Part.Shape()
|
obj.Shape = Part.Shape()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -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
4
gui.py
|
@ -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)
|
||||||
|
|
15
solver.py
15
solver.py
|
@ -56,13 +56,12 @@ 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
|
# add dragging point
|
||||||
self.system.log('add drag point {}'.format(info.Workplane[1]))
|
self.system.log('add drag point '
|
||||||
# TODO: slvs addWhereDragged doesn't work as expected, need to
|
'{}'.format(info.Workplane[1]))
|
||||||
# investigate more
|
# TODO: slvs addWhereDragged doesn't work as expected, need
|
||||||
|
# to 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)))
|
||||||
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user