From 02f938ebdf5096f5dd31c353d5f549fe1ffa0fc4 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 26 Apr 2015 13:57:36 -0300 Subject: [PATCH] First groundwork on Arch Schedule tool --- src/Mod/Arch/Arch.py | 1 + src/Mod/Arch/ArchMaterial.py | 12 +- src/Mod/Arch/ArchSchedule.py | 247 +++++++++++++ src/Mod/Arch/ArchSchedule.ui | 343 ++++++++++++++++++ src/Mod/Arch/ArchStairs.py | 2 + src/Mod/Arch/InitGui.py | 2 +- src/Mod/Arch/Resources/Arch.qrc | 1 + .../Arch/Resources/icons/Arch_Schedule.svg | 164 +++++++++ 8 files changed, 765 insertions(+), 7 deletions(-) create mode 100644 src/Mod/Arch/ArchSchedule.py create mode 100644 src/Mod/Arch/ArchSchedule.ui create mode 100644 src/Mod/Arch/Resources/icons/Arch_Schedule.svg diff --git a/src/Mod/Arch/Arch.py b/src/Mod/Arch/Arch.py index 714894081..1ac217006 100644 --- a/src/Mod/Arch/Arch.py +++ b/src/Mod/Arch/Arch.py @@ -49,3 +49,4 @@ from ArchEquipment import * from ArchCutPlane import * from ArchServer import * from ArchMaterial import * +from ArchSchedule import * diff --git a/src/Mod/Arch/ArchMaterial.py b/src/Mod/Arch/ArchMaterial.py index 71c71ca8e..c385e2c9d 100644 --- a/src/Mod/Arch/ArchMaterial.py +++ b/src/Mod/Arch/ArchMaterial.py @@ -120,8 +120,8 @@ class _ArchMaterial: def execute(self,obj): if obj.Material and FreeCAD.GuiUp: - if "Color" in obj.Material: - c = tuple([float(f) for f in obj.Material['Color'].strip("()").split(",")]) + if "DiffuseColor" in obj.Material: + c = tuple([float(f) for f in obj.Material['DiffuseColor'].strip("()").split(",")]) for p in obj.InList: if hasattr(p,"BaseMaterial"): if p.BaseMaterial.Name == obj.Name: @@ -191,9 +191,9 @@ class _ArchMaterialTaskPanel: self.form.FieldName.setText(self.obj.Label) if 'Description' in self.material: self.form.FieldDescription.setText(self.material['Description']) - if 'Color' in self.material: - if "(" in self.material['Color']: - c = tuple([float(f) for f in self.material['Color'].strip("()").split(",")]) + if 'DiffuseColor' in self.material: + if "(" in self.material['DiffuseColor']: + c = tuple([float(f) for f in self.material['DiffuseColor'].strip("()").split(",")]) self.color = QtGui.QColor() self.color.setRgbF(c[0],c[1],c[2]) colorPix = QtGui.QPixmap(16,16) @@ -208,7 +208,7 @@ class _ArchMaterialTaskPanel: "sets self.material from the contents of the task box" self.material['Name'] = self.form.FieldName.text() self.material['Description'] = self.form.FieldDescription.text() - self.material['Color'] = str(self.color.getRgbF()[:3]) + self.material['DiffuseColor'] = str(self.color.getRgbF()[:3]) self.material['StandardCode'] = self.form.FieldCode.text() self.material['ProductURL'] = self.form.FieldUrl.text() diff --git a/src/Mod/Arch/ArchSchedule.py b/src/Mod/Arch/ArchSchedule.py new file mode 100644 index 000000000..a8501ac61 --- /dev/null +++ b/src/Mod/Arch/ArchSchedule.py @@ -0,0 +1,247 @@ +# -*- coding: utf8 -*- + +#*************************************************************************** +#* * +#* Copyright (c) 2015 - Yorik van Havre * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** + +import FreeCAD, time +if FreeCAD.GuiUp: + import FreeCADGui, Arch_rc, os + from PySide import QtCore, QtGui + from DraftTools import translate + +__title__ = "Arch Schedule Managment" +__author__ = "Yorik van Havre" +__url__ = "http://www.freecadweb.org" + + +class _CommandArchSchedule: + "the Arch Schedule command definition" + def GetResources(self): + return {'Pixmap': 'Arch_Schedule', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Schedule","Create schedule..."), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Schedule","Creates a materials or areas schedule.")} + + def Activated(self): + taskd = _ArchScheduleTaskPanel() + FreeCADGui.Control.showDialog(taskd) + + def IsActive(self): + if FreeCAD.ActiveDocument: + return True + else: + return False + + +class _ArchScheduleTaskPanel: + '''The editmode TaskPanel for MechanicalMaterial objects''' + def __init__(self): + self.form = FreeCADGui.PySideUic.loadUi(os.path.splitext(__file__)[0]+".ui") + QtCore.QObject.connect(self.form.ComboType, QtCore.SIGNAL("currentIndexChanged(int)"), self.changeType) + + def changeType(self,idx): + "changes the type of schedule" + if idx == 0: + # quantities + self.form.GroupQuantities.maximumHeight = 1677215 + elif idx == 1: + # spaces + self.form.GroupQuantities.maximumHeight = 17 + elif idx == 2: + # windows + self.form.GroupQuantities.maximumHeight = 17 + + def accept(self): + sp = FreeCAD.ActiveDocument.addObject('Spreadsheet::Sheet','Schedule') + if self.form.ComboType.currentIndex() == 0: + self.fillMaterialsSchedule(sp) + elif self.form.ComboType.currentIndex() == 1: + self.fillSpacesSchedule(sp) + FreeCADGui.Control.closeDialog() + + def getRoles(self,roles): + "gets all objects of the given roles in the document" + objs = [] + for obj in FreeCAD.ActiveDocument.Objects: + if obj.ViewObject.isVisible(): + if hasattr(obj,"Role"): + for r in roles: + if obj.Role == r: + objs.append(obj) + break + return objs + + def getMaterials(self,objs): + "classify the given objects by material" + res = {} + for obj in objs: + if hasattr(obj,"BaseMaterial"): + if obj.BaseMaterial: + res.setdefault(obj.BaseMaterial.Name,[]).append(obj) + return res + + def getEntry(self,mat,entry): + "returns the given entry from a given material name" + res = "" + m = FreeCAD.ActiveDocument.getObject(mat) + if m: + if m.Material: + if entry in m.Material.keys(): + res = m.Material[entry].encode('utf8') + return res + + def fillMaterialsSchedule(self,sp): + "creates a materials schedule in the given spreadsheet" + + # table title + + col = self.form.FieldStartCell.text()[0] + row = int(self.form.FieldStartCell.text()[1:]) + global volunit,curunit + volunit = self.form.FieldVolumeUnit.text().encode("utf8") + curunit = self.form.FieldCurrencyUnit.text().encode("utf8") + + sec = 1 + sp.set(col+str(row), translate("Arch","Quantities schedule")) + row += 1 + sp.set(col+str(row), translate("Arch","Project") + ": " + FreeCAD.ActiveDocument.Label) + row += 1 + sp.set(col+str(row), translate("Arch","Date") + ": " + time.asctime()) + row += 2 + + # column headers + + end = 1 + sp.set(chr(ord(col)+end)+str(row), translate("Arch","Material")) + end += 1 + if self.form.CheckDescription.isChecked(): + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Description")) + end += 1 + if self.form.CheckColor.isChecked(): + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Color")) + end += 1 + if self.form.CheckFinish.isChecked(): + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Finish")) + end += 1 + if self.form.CheckUrl.isChecked(): + sp.set(chr(ord(col)+end)+str(row),translate("Arch","URL")) + end += 1 + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Item")) + end += 1 + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Volume")+" ("+volunit+")") + end += 1 + if self.form.CheckPrice.isChecked(): + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Unit price")+" ("+curunit+"/"+volunit+")") + end += 1 + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Total price")+" ("+curunit+")") + row += 2 + + # volume-based row data + + if self.form.CheckStructures.isChecked(): + row,col,sec = self.printVolume(sp,"Column",translate("Arch","Columns"),row,col,sec) + row,col,sec = self.printVolume(sp,"Beam",translate("Arch","Beams"),row,col,sec) + row,col,sec = self.printVolume(sp,"Slab",translate("Arch","Slabs"),row,col,sec) + row,col,sec = self.printVolume(sp,"Foundation",translate("Arch","Foundations"),row,col,sec) + row,col,sec = self.printVolume(sp,"Pile",None,row,col,sec) + if self.form.CheckStairs.isChecked(): + row,col,sec = self.printVolume(sp,"Stair",translate("Arch","Stairs"),row,col,sec) + row,col,sec = self.printVolume(sp,"Stair Flight",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Ramp",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Ramp Flight",None,row,col,sec) + if self.form.CheckWalls.isChecked(): + row,col,sec = self.printVolume(sp,"Wall",translate("Arch","Walls"),row,col,sec) + row,col,sec = self.printVolume(sp,"Wall Layer",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Curtain Wall",None,row,col,sec) + if self.form.CheckOthers.isChecked(): + sp.set(col+str(row), str(sec) + ". " + translate("Arch","Miscellaneous")) + sec += 1 + row += 2 + row,col,sec = self.printVolume(sp,"Chimney",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Covering",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Shading Device",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Member",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Railing",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Tendon",None,row,col,sec) + row,col,sec = self.printVolume(sp,"Undefined",None,row,col,sec) + + # TODO area: Covering Door Plate Rebar Roof Window + # TODO count: Furniture Hydro Equipment Electric Equipment + + def printVolume(self,sp,role,title,row,col,sec): + "print object type quantities to the spreadsheet" + + objs = self.getRoles([role]) + totprice = 0 + if objs: + if title: + sp.set(col+str(row), str(sec) + ". " + title) + sec += 1 + row += 2 + mats = self.getMaterials(objs) + for mat,mobjs in mats.items(): + end = 1 + sp.set(chr(ord(col)+end)+str(row),self.getEntry(mat,"Name")) + end += 1 + if self.form.CheckDescription.isChecked(): + sp.set(chr(ord(col)+end)+str(row),self.getEntry(mat,"Description")) + end += 1 + if self.form.CheckColor.isChecked(): + if self.getEntry(mat,"DiffuseColor"): + sp.setBackground(chr(ord(col)+end)+str(row),tuple([float(f) for f in self.getEntry(mat,"DiffuseColor").strip("()").split(",")])) + end += 1 + if self.form.CheckFinish.isChecked(): + sp.set(chr(ord(col)+end)+str(row),self.getEntry(mat,"Finish")) + end += 1 + if self.form.CheckUrl.isChecked(): + sp.set(chr(ord(col)+end)+str(row),self.getEntry(mat,"ProductURL")) + end += 1 + total = 0 + for mobj in mobjs: + if not self.form.CheckOnlyShowTotals.isChecked(): + v = FreeCAD.Units.Quantity(mobj.Shape.Volume,FreeCAD.Units.Volume).getValueAs(volunit.replace("³","^3")).Value + sp.set(chr(ord(col)+end)+str(row),mobj.Label) + sp.set(chr(ord(col)+end+1)+str(row),str(v)) + total += v + if self.form.CheckPrice.isChecked(): + sp.set(chr(ord(col)+end+2)+str(row),self.getEntry(mat,"SpecificPrice")) + sp.set(chr(ord(col)+end+3)+str(row),"="+chr(ord(col)+end+1)+str(row)+"*"+chr(ord(col)+end+2)+str(row)) + row += 1 + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Total")) + sp.set(chr(ord(col)+end+1)+str(row),str(total)) + if self.form.CheckPrice.isChecked(): + sp.set(chr(ord(col)+end+2)+str(row),self.getEntry(mat,"SpecificPrice")) + sp.set(chr(ord(col)+end+3)+str(row),"="+chr(ord(col)+end+1)+str(row)+"*"+chr(ord(col)+end+2)+str(row)) + try: + totprice += total * float(self.getEntry(mat,"SpecificPrice")) + except: + print "Arch.Schedule: Unable to add price" + row += 2 + if self.form.CheckPrice.isChecked(): + if totprice: + sp.set(chr(ord(col)+end)+str(row),translate("Arch","Total")+" "+title) + sp.set(chr(ord(col)+end+3)+str(row),str(totprice)) + row += 2 + return row,col,sec + + +if FreeCAD.GuiUp: + FreeCADGui.addCommand('Arch_Schedule',_CommandArchSchedule()) diff --git a/src/Mod/Arch/ArchSchedule.ui b/src/Mod/Arch/ArchSchedule.ui new file mode 100644 index 000000000..99cb644ce --- /dev/null +++ b/src/Mod/Arch/ArchSchedule.ui @@ -0,0 +1,343 @@ + + + Form + + + + 0 + 0 + 211 + 734 + + + + Form + + + + + + General + + + + + + + Quantities + + + + + Spaces + + + + + Doors and windows + + + + + + + + + + Start cell + + + + + + + A1 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Area unit + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Volume unit + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Currency unit + + + + + + + This must match what is stored in the project materials. No conversion will be done. + + + + + + + + + + + true + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + 16777215 + 1677215 + + + + Quantities + + + + + + Only show totals + + + false + + + + + + + Add material description + + + true + + + + + + + Add material color + + + true + + + + + + + Add material finish + + + false + + + + + + + Add material URL + + + + + + + Add price calculation + + + false + + + + + + + Add structures + + + true + + + + + + + Add stairs + + + true + + + + + + + Add walls + + + true + + + + + + + Add all other roles + + + true + + + + + + + Add floors + + + true + + + + + + + Add ceilings + + + true + + + + + + + Add roofs + + + true + + + + + + + Add windows and doors + + + true + + + + + + + Add panels + + + true + + + + + + + Add equipments + + + true + + + + + + + Add furniture + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/Mod/Arch/ArchStairs.py b/src/Mod/Arch/ArchStairs.py index 31f6e3e14..4b102927e 100644 --- a/src/Mod/Arch/ArchStairs.py +++ b/src/Mod/Arch/ArchStairs.py @@ -125,6 +125,8 @@ class _Stairs(ArchComponent.Component): obj.setEditorMode("RiserHeight",1) obj.setEditorMode("BlondelRatio",1) self.Type = "Stairs" + self.Role = ["Stair","Stair Flight"] + self.Role = "Stair" def execute(self,obj): diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index e2d19454b..8c733232d 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -74,7 +74,7 @@ class ArchWorkbench(Workbench): "Arch_Window","Arch_Roof","Arch_Axis", "Arch_SectionPlane","Arch_Space","Arch_Stairs", "Arch_Panel","Arch_Equipment", - "Arch_Frame","Arch_Material","Arch_CutPlane", + "Arch_Frame","Arch_Material","Arch_Schedule","Arch_CutPlane", "Arch_Add","Arch_Remove","Arch_Survey"] self.utilities = ["Arch_Component","Arch_SplitMesh","Arch_MeshToShape", "Arch_SelectNonSolidMeshes","Arch_RemoveShape", diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc index a3310217c..288ac078f 100644 --- a/src/Mod/Arch/Resources/Arch.qrc +++ b/src/Mod/Arch/Resources/Arch.qrc @@ -56,6 +56,7 @@ icons/Arch_Component.svg icons/Arch_Material.svg icons/Arch_Material_Group.svg + icons/Arch_Schedule.svg ui/archprefs-base.ui ui/archprefs-defaults.ui ui/archprefs-import.ui diff --git a/src/Mod/Arch/Resources/icons/Arch_Schedule.svg b/src/Mod/Arch/Resources/icons/Arch_Schedule.svg new file mode 100644 index 000000000..c7c414e09 --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Schedule.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + +