Merge pull request #8607 from Roy-043/Arch-fix-Arch_Schedule-recompute-issue
[Arch] fix Arch_Schedule recompute issue
This commit is contained in:
@@ -74,6 +74,24 @@ class CommandArchSchedule:
|
||||
return False
|
||||
|
||||
|
||||
class _ArchScheduleDocObserver:
|
||||
|
||||
"doc observer to monitor all recomputes"
|
||||
|
||||
# https://forum.freecad.org/viewtopic.php?style=3&p=553377#p553377
|
||||
|
||||
def __init__(self, doc, schedule):
|
||||
self.doc = doc
|
||||
self.schedule = schedule
|
||||
|
||||
def slotRecomputedDocument(self, doc):
|
||||
if doc != self.doc:
|
||||
return
|
||||
try:
|
||||
self.schedule.Proxy.execute(self.schedule)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class _ArchSchedule:
|
||||
|
||||
@@ -88,6 +106,18 @@ class _ArchSchedule:
|
||||
def onDocumentRestored(self,obj):
|
||||
|
||||
self.setProperties(obj)
|
||||
if hasattr(obj, "Result"):
|
||||
self.update_properties_0v21(obj)
|
||||
|
||||
def update_properties_0v21(self,obj):
|
||||
sp = obj.Result
|
||||
if sp is not None:
|
||||
self.setSchedulePropertySpreadsheet(sp, obj)
|
||||
obj.removeProperty("Result")
|
||||
from draftutils.messages import _wrn
|
||||
_wrn("v0.21, " + obj.Label + ", " + translate("Arch", "removed property 'Result', and added property 'AutoUpdate'"))
|
||||
if sp is not None:
|
||||
_wrn("v0.21, " + sp.Label + ", " + translate("Arch", "added property 'Schedule'"))
|
||||
|
||||
def setProperties(self,obj):
|
||||
|
||||
@@ -103,19 +133,67 @@ class _ArchSchedule:
|
||||
obj.addProperty("App::PropertyStringList","Filter", "Arch",QT_TRANSLATE_NOOP("App::Property","The filter column"))
|
||||
if not "CreateSpreadsheet" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyBool", "CreateSpreadsheet", "Arch",QT_TRANSLATE_NOOP("App::Property","If True, a spreadsheet containing the results is recreated when needed"))
|
||||
if not "Result" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyLink", "Result", "Arch",QT_TRANSLATE_NOOP("App::Property","The spreadsheet to print the results to"))
|
||||
if not "DetailedResults" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyBool", "DetailedResults", "Arch",QT_TRANSLATE_NOOP("App::Property","If True, additional lines with each individual object are added to the results"))
|
||||
obj.addProperty("App::PropertyBool", "DetailedResults", "Arch",QT_TRANSLATE_NOOP("App::Property","If True, additional lines with each individual object are added to the results"))
|
||||
if not "AutoUpdate" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyBool", "AutoUpdate", "Arch",QT_TRANSLATE_NOOP("App::Property","If True, the schedule and the associated spreadsheet are updated whenever the document is recomputed"))
|
||||
obj.AutoUpdate = True
|
||||
|
||||
# To add the doc observer:
|
||||
self.onChanged(obj,"AutoUpdate")
|
||||
|
||||
def setSchedulePropertySpreadsheet(self, sp, obj):
|
||||
if not hasattr(sp, "Schedule"):
|
||||
sp.addProperty(
|
||||
"App::PropertyLink",
|
||||
"Schedule",
|
||||
"Arch",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The Arch Schedule that uses this spreadsheet"))
|
||||
sp.Schedule = obj
|
||||
|
||||
def getSpreadSheet(self, obj, force=False):
|
||||
|
||||
"""Get the spreadsheet and store it in self.spreadsheet.
|
||||
|
||||
If force is True the spreadsheet is created if required.
|
||||
"""
|
||||
try: # Required as self.spreadsheet may get deleted.
|
||||
if getattr(self, "spreadsheet", None) is not None \
|
||||
and getattr(self.spreadsheet, "Schedule", None) == obj:
|
||||
return self.spreadsheet
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
for o in FreeCAD.ActiveDocument.Objects:
|
||||
if o.TypeId == "Spreadsheet::Sheet" \
|
||||
and getattr(o, "Schedule", None) == obj:
|
||||
self.spreadsheet = o
|
||||
return self.spreadsheet
|
||||
if force:
|
||||
self.spreadsheet = FreeCAD.ActiveDocument.addObject("Spreadsheet::Sheet", "Result")
|
||||
self.setSchedulePropertySpreadsheet(self.spreadsheet, obj)
|
||||
return self.spreadsheet
|
||||
else:
|
||||
return None
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
|
||||
if (prop == "CreateSpreadsheet"):
|
||||
if hasattr(obj,"CreateSpreadsheet") and obj.CreateSpreadsheet:
|
||||
if not obj.Result:
|
||||
import Spreadsheet
|
||||
sp = FreeCAD.ActiveDocument.addObject("Spreadsheet::Sheet","Result")
|
||||
obj.Result = sp
|
||||
if prop == "CreateSpreadsheet":
|
||||
if obj.CreateSpreadsheet:
|
||||
self.getSpreadSheet(obj, force=True)
|
||||
else:
|
||||
sp = self.getSpreadSheet(obj)
|
||||
if sp is not None:
|
||||
FreeCAD.ActiveDocument.removeObject(sp.Name)
|
||||
self.spreadsheet = None
|
||||
elif prop == "AutoUpdate":
|
||||
if obj.AutoUpdate:
|
||||
if getattr(self, "docObserver", None) is None:
|
||||
self.docObserver = _ArchScheduleDocObserver(FreeCAD.ActiveDocument, obj)
|
||||
FreeCAD.addDocumentObserver(self.docObserver)
|
||||
elif getattr(self, "docObserver", None) is not None:
|
||||
FreeCAD.removeDocumentObserver(self.docObserver)
|
||||
self.docObserver = None
|
||||
|
||||
def setSpreadsheetData(self,obj,force=False):
|
||||
|
||||
@@ -127,25 +205,26 @@ class _ArchSchedule:
|
||||
return
|
||||
if not self.data:
|
||||
return
|
||||
if not obj.Result:
|
||||
if obj.CreateSpreadsheet or force:
|
||||
import Spreadsheet
|
||||
sp = FreeCAD.ActiveDocument.addObject("Spreadsheet::Sheet","Result")
|
||||
obj.Result = sp
|
||||
else:
|
||||
return
|
||||
# clear spreadsheet
|
||||
obj.Result.clearAll()
|
||||
if not (obj.CreateSpreadsheet or force):
|
||||
return
|
||||
sp = self.getSpreadSheet(obj, force=True)
|
||||
sp.clearAll()
|
||||
# clearAll removes the custom property, we need to re-add it:
|
||||
self.setSchedulePropertySpreadsheet(sp, obj)
|
||||
# set headers
|
||||
obj.Result.set("A1","Description")
|
||||
obj.Result.set("B1","Value")
|
||||
obj.Result.set("C1","Unit")
|
||||
obj.Result.setStyle('A1:C1', 'bold', 'add')
|
||||
sp.set("A1","Description")
|
||||
sp.set("B1","Value")
|
||||
sp.set("C1","Unit")
|
||||
sp.setStyle('A1:C1', 'bold', 'add')
|
||||
# write contents
|
||||
for k,v in self.data.items():
|
||||
obj.Result.set(k,v)
|
||||
sp.set(k,v)
|
||||
# recompute
|
||||
obj.Result.recompute()
|
||||
sp.recompute()
|
||||
sp.purgeTouched() # Remove the confusing blue checkmark from the spreadsheet.
|
||||
for o in sp.InList: # Also recompute TechDraw views.
|
||||
o.TypeId == "TechDraw::DrawViewSpreadsheet"
|
||||
o.recompute()
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
@@ -158,9 +237,6 @@ class _ArchSchedule:
|
||||
# different number of items in each column
|
||||
if len(obj.Description) != len(p):
|
||||
return
|
||||
if not hasattr(obj,"Result"):
|
||||
# silently fail on old schedule objects
|
||||
return
|
||||
|
||||
self.data = {} # store all results in self.data, so it lives even without spreadsheet
|
||||
li = 1 # row index - starts at 2 to leave 2 blank rows for the title
|
||||
@@ -196,9 +272,8 @@ class _ArchSchedule:
|
||||
objs = objs[0].Group
|
||||
objs = Draft.get_group_contents(objs)
|
||||
objs = Arch.pruneIncluded(objs,strict=True)
|
||||
# remove the schedule object and its result from the list
|
||||
objs = [o for o in objs if not o == obj]
|
||||
objs = [o for o in objs if not o == obj.Result]
|
||||
# Remove all schedules and spreadsheets:
|
||||
objs = [o for o in objs if Draft.get_type(o) not in ["Schedule", "Spreadsheet::Sheet"]]
|
||||
if obj.Filter[i]:
|
||||
# apply filters
|
||||
nobjs = []
|
||||
@@ -318,10 +393,6 @@ class _ArchSchedule:
|
||||
self.data["C"+str(li)] = unit
|
||||
else:
|
||||
self.data["B"+str(li)] = str(val)
|
||||
if obj.DetailedResults:
|
||||
# additional blank line...
|
||||
li += 1
|
||||
self.data["A"+str(li)] = " "
|
||||
if verbose:
|
||||
if tp and unit:
|
||||
v = fs.format(FreeCAD.Units.Quantity(val,tp).getValueAs(unit).Value)
|
||||
@@ -349,6 +420,9 @@ class _ViewProviderArchSchedule:
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
if self.Object.AutoUpdate is False:
|
||||
import TechDrawGui
|
||||
return ":/icons/TechDraw_TreePageUnsync.svg"
|
||||
import Arch_rc
|
||||
return ":/icons/Arch_Schedule.svg"
|
||||
|
||||
@@ -382,23 +456,27 @@ class _ViewProviderArchSchedule:
|
||||
self.edit)
|
||||
menu.addAction(actionEdit)
|
||||
|
||||
actionAttachSpreadsheet = QtGui.QAction(QtGui.QIcon(":/icons/Arch_Schedule.svg"),
|
||||
translate("Arch", "Attach spreadsheet"),
|
||||
if self.Object.CreateSpreadsheet is True:
|
||||
msg = translate("Arch", "Remove spreadsheet")
|
||||
else:
|
||||
msg = translate("Arch", "Attach spreadsheet")
|
||||
actionToggleSpreadsheet = QtGui.QAction(QtGui.QIcon(":/icons/Arch_Schedule.svg"),
|
||||
msg,
|
||||
menu)
|
||||
QtCore.QObject.connect(actionAttachSpreadsheet,
|
||||
QtCore.QObject.connect(actionToggleSpreadsheet,
|
||||
QtCore.SIGNAL("triggered()"),
|
||||
self.attachSpreadsheet)
|
||||
menu.addAction(actionAttachSpreadsheet)
|
||||
self.toggleSpreadsheet)
|
||||
menu.addAction(actionToggleSpreadsheet)
|
||||
|
||||
def edit(self):
|
||||
FreeCADGui.ActiveDocument.setEdit(self.Object, 0)
|
||||
|
||||
def attachSpreadsheet(self):
|
||||
self.Object.Proxy.setSpreadsheetData(self.Object, force=True)
|
||||
def toggleSpreadsheet(self):
|
||||
self.Object.CreateSpreadsheet = not self.Object.CreateSpreadsheet
|
||||
|
||||
def claimChildren(self):
|
||||
if hasattr(self,"Object"):
|
||||
return [self.Object.Result]
|
||||
return [self.Object.Proxy.getSpreadSheet(self.Object)]
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
@@ -668,9 +746,7 @@ class ArchScheduleTaskPanel:
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderArchSchedule(self.obj.ViewObject)
|
||||
if hasattr(self.obj,"CreateSpreadsheet") and self.obj.CreateSpreadsheet:
|
||||
import Spreadsheet
|
||||
sp = FreeCAD.ActiveDocument.addObject("Spreadsheet::Sheet","Result")
|
||||
self.obj.Result = sp
|
||||
self.obj.Proxy.getSpreadSheet(self.obj, force=True)
|
||||
lists = [ [], [], [], [], [] ]
|
||||
for i in range(self.form.list.rowCount()):
|
||||
for j in range(5):
|
||||
@@ -688,6 +764,7 @@ class ArchScheduleTaskPanel:
|
||||
self.obj.Label = self.form.lineEditName.text()
|
||||
self.obj.DetailedResults = self.form.checkDetailed.isChecked()
|
||||
self.obj.CreateSpreadsheet = self.form.checkSpreadsheet.isChecked()
|
||||
self.obj.AutoUpdate = self.form.checkAutoUpdate.isChecked()
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
@@ -118,13 +118,23 @@ Leave blank to use all objects from the document</string>
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="checkDetailed">
|
||||
<property name="toolTip">
|
||||
<string>If this is turned on, additional lines will be filled with each object considered. If not, only the totals.</string>
|
||||
<string>If this is enabled, additional lines will be filled with each object considered. If not, only the totals.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Detailed results</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="checkAutoUpdate">
|
||||
<property name="toolTip">
|
||||
<string>If this is enabled, the schedule and the associated spreadsheet are updated whenever the document is recomputed.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
Reference in New Issue
Block a user