Merge pull request #8607 from Roy-043/Arch-fix-Arch_Schedule-recompute-issue

[Arch] fix Arch_Schedule recompute issue
This commit is contained in:
Yorik van Havre
2023-02-28 09:36:57 +01:00
committed by GitHub
2 changed files with 133 additions and 46 deletions

View File

@@ -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()

View File

@@ -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>