FreeCAD

Форк
0
/
ArchSchedule.py 
747 строк · 29.4 Кб
1
# -*- coding: utf8 -*-
2
#***************************************************************************
3
#*   Copyright (c) 2015 Yorik van Havre <yorik@uncreated.net>              *
4
#*                                                                         *
5
#*   This program is free software; you can redistribute it and/or modify  *
6
#*   it under the terms of the GNU Lesser General Public License (LGPL)    *
7
#*   as published by the Free Software Foundation; either version 2 of     *
8
#*   the License, or (at your option) any later version.                   *
9
#*   for detail see the LICENCE text file.                                 *
10
#*                                                                         *
11
#*   This program is distributed in the hope that it will be useful,       *
12
#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
#*   GNU Library General Public License for more details.                  *
15
#*                                                                         *
16
#*   You should have received a copy of the GNU Library General Public     *
17
#*   License along with this program; if not, write to the Free Software   *
18
#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
19
#*   USA                                                                   *
20
#*                                                                         *
21
#***************************************************************************
22

23
import FreeCAD
24
from draftutils import params
25

26
if FreeCAD.GuiUp:
27
    import FreeCADGui
28
    from PySide import QtCore, QtGui
29
    from draftutils.translate import translate
30
    from PySide.QtCore import QT_TRANSLATE_NOOP
31
else:
32
    # \cond
33
    def translate(ctxt,txt):
34
        return txt
35
    def QT_TRANSLATE_NOOP(ctxt,txt):
36
        return txt
37
    # \endcond
38

39
## @package ArchSchedule
40
#  \ingroup ARCH
41
#  \brief The Schedule object and tools
42
#
43
#  This module provides tools to build Schedule objects.
44
#  Schedules are objects that can count and gather information
45
#  about objects in the document, and fill a spreadsheet with the result
46

47
__title__ = "Arch Schedule"
48
__author__ = "Yorik van Havre"
49
__url__ = "https://www.freecad.org"
50

51

52
verbose = True # change this for silent recomputes
53

54

55

56
class _ArchScheduleDocObserver:
57

58
    "doc observer to monitor all recomputes"
59

60
    # https://forum.freecad.org/viewtopic.php?style=3&p=553377#p553377
61

62
    def __init__(self, doc, schedule):
63
        self.doc = doc
64
        self.schedule = schedule
65

66
    def slotRecomputedDocument(self, doc):
67
        if doc != self.doc:
68
            return
69
        try:
70
            self.schedule.Proxy.execute(self.schedule)
71
        except:
72
            pass
73

74

75
class _ArchSchedule:
76

77
    "the Arch Schedule object"
78

79
    def __init__(self,obj):
80

81
        self.setProperties(obj)
82
        obj.Proxy = self
83
        self.Type = "Schedule"
84

85
    def onDocumentRestored(self,obj):
86

87
        self.setProperties(obj)
88
        if hasattr(obj, "Result"):
89
            self.update_properties_0v21(obj)
90

91
    def update_properties_0v21(self,obj):
92
        sp = obj.Result
93
        if sp is not None:
94
            self.setSchedulePropertySpreadsheet(sp, obj)
95
        obj.removeProperty("Result")
96
        from draftutils.messages import _wrn
97
        _wrn("v0.21, " + obj.Label + ", " + translate("Arch", "removed property 'Result', and added property 'AutoUpdate'"))
98
        if sp is not None:
99
            _wrn("v0.21, " + sp.Label + ", " + translate("Arch", "added property 'Schedule'"))
100

101
    def setProperties(self,obj):
102

103
        if not "Description" in obj.PropertiesList:
104
            obj.addProperty("App::PropertyStringList","Description",       "Arch",QT_TRANSLATE_NOOP("App::Property","The description column"))
105
        if not "Value" in obj.PropertiesList:
106
            obj.addProperty("App::PropertyStringList","Value",             "Arch",QT_TRANSLATE_NOOP("App::Property","The values column"))
107
        if not "Unit" in obj.PropertiesList:
108
            obj.addProperty("App::PropertyStringList","Unit",              "Arch",QT_TRANSLATE_NOOP("App::Property","The units column"))
109
        if not "Objects" in obj.PropertiesList:
110
            obj.addProperty("App::PropertyStringList","Objects",           "Arch",QT_TRANSLATE_NOOP("App::Property","The objects column"))
111
        if not "Filter" in obj.PropertiesList:
112
            obj.addProperty("App::PropertyStringList","Filter",            "Arch",QT_TRANSLATE_NOOP("App::Property","The filter column"))
113
        if not "CreateSpreadsheet" in obj.PropertiesList:
114
            obj.addProperty("App::PropertyBool",      "CreateSpreadsheet", "Arch",QT_TRANSLATE_NOOP("App::Property","If True, a spreadsheet containing the results is recreated when needed"))
115
        if not "DetailedResults" in obj.PropertiesList:
116
            obj.addProperty("App::PropertyBool",      "DetailedResults",   "Arch",QT_TRANSLATE_NOOP("App::Property","If True, additional lines with each individual object are added to the results"))
117
        if not "AutoUpdate" in obj.PropertiesList:
118
            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"))
119
            obj.AutoUpdate = True
120

121
        # To add the doc observer:
122
        self.onChanged(obj,"AutoUpdate")
123

124
    def setSchedulePropertySpreadsheet(self, sp, obj):
125
        if not hasattr(sp, "Schedule"):
126
            sp.addProperty(
127
                "App::PropertyLink",
128
                "Schedule",
129
                "Arch",
130
                QT_TRANSLATE_NOOP("App::Property", "The BIM Schedule that uses this spreadsheet"))
131
        sp.Schedule = obj
132

133
    def getSpreadSheet(self, obj, force=False):
134

135
        """Get the spreadsheet and store it in self.spreadsheet.
136

137
        If force is True the spreadsheet is created if required.
138
        """
139
        try: # Required as self.spreadsheet may get deleted.
140
            if getattr(self, "spreadsheet", None) is not None \
141
                    and getattr(self.spreadsheet, "Schedule", None) == obj:
142
                return self.spreadsheet
143
        except:
144
            pass
145
        else:
146
            for o in FreeCAD.ActiveDocument.Objects:
147
                if o.TypeId == "Spreadsheet::Sheet" \
148
                        and getattr(o, "Schedule", None) == obj:
149
                    self.spreadsheet = o
150
                    return self.spreadsheet
151
            if force:
152
                self.spreadsheet = FreeCAD.ActiveDocument.addObject("Spreadsheet::Sheet", "Result")
153
                self.setSchedulePropertySpreadsheet(self.spreadsheet, obj)
154
                return self.spreadsheet
155
            else:
156
                return None
157

158
    def onChanged(self,obj,prop):
159

160
        if prop == "CreateSpreadsheet":
161
            if obj.CreateSpreadsheet:
162
                self.getSpreadSheet(obj, force=True)
163
            else:
164
                sp = self.getSpreadSheet(obj)
165
                if sp is not None:
166
                    FreeCAD.ActiveDocument.removeObject(sp.Name)
167
                    self.spreadsheet = None
168
        elif prop == "AutoUpdate":
169
            if obj.AutoUpdate:
170
                if getattr(self, "docObserver", None) is None:
171
                    self.docObserver = _ArchScheduleDocObserver(FreeCAD.ActiveDocument, obj)
172
                    FreeCAD.addDocumentObserver(self.docObserver)
173
            elif getattr(self, "docObserver", None) is not None:
174
                FreeCAD.removeDocumentObserver(self.docObserver)
175
                self.docObserver = None
176

177
    def setSpreadsheetData(self,obj,force=False):
178

179
        """Fills a spreadsheet with the stored data"""
180

181
        if not hasattr(self,"data"):
182
            self.execute(obj)
183
        if not hasattr(self,"data"):
184
            return
185
        if not self.data:
186
            return
187
        if not (obj.CreateSpreadsheet or force):
188
            return
189
        sp = self.getSpreadSheet(obj, force=True)
190
        sp.clearAll()
191
        # clearAll removes the custom property, we need to re-add it:
192
        self.setSchedulePropertySpreadsheet(sp, obj)
193
        # set headers
194
        sp.set("A1","Description")
195
        sp.set("B1","Value")
196
        sp.set("C1","Unit")
197
        sp.setStyle('A1:C1', 'bold', 'add')
198
        # write contents
199
        for k,v in self.data.items():
200
            sp.set(k,v)
201
        # recompute
202
        sp.recompute()
203
        sp.purgeTouched()   # Remove the confusing blue checkmark from the spreadsheet.
204
        for o in sp.InList: # Also recompute TechDraw views.
205
            o.TypeId == "TechDraw::DrawViewSpreadsheet"
206
            o.recompute()
207

208
    def execute(self,obj):
209

210
        # verify the data
211

212
        if not obj.Description:
213
            # empty description column
214
            return
215
        for p in [obj.Value,obj.Unit,obj.Objects,obj.Filter]:
216
            # different number of items in each column
217
            if len(obj.Description) != len(p):
218
                return
219

220
        self.data = {} # store all results in self.data, so it lives even without spreadsheet
221
        li = 1 # row index - starts at 2 to leave 2 blank rows for the title
222

223
        for i in range(len(obj.Description)):
224
            li += 1
225
            if not obj.Description[i]:
226
                # blank line
227
                continue
228
            # write description
229
            self.data["A"+str(li)] = obj.Description[i]
230
            if verbose:
231
                l= "OPERATION: "+obj.Description[i]
232
                print("")
233
                print (l)
234
                print (len(l)*"=")
235

236
            # build set of valid objects
237

238
            objs = obj.Objects[i]
239
            val = obj.Value[i]
240
            if val:
241
                import Draft,Arch
242
                if objs:
243
                    objs = objs.split(";")
244
                    objs = [FreeCAD.ActiveDocument.getObject(o) for o in objs]
245
                    objs = [o for o in objs if o is not None]
246
                else:
247
                    objs = FreeCAD.ActiveDocument.Objects
248
                if len(objs) == 1:
249
                    # remove object itself if the object is a group
250
                    if objs[0].isDerivedFrom("App::DocumentObjectGroup"):
251
                        objs = objs[0].Group
252
                objs = Draft.get_group_contents(objs)
253
                objs = Arch.pruneIncluded(objs,strict=True)
254
                # Remove all schedules and spreadsheets:
255
                objs = [o for o in objs if Draft.get_type(o) not in ["Schedule", "Spreadsheet::Sheet"]]
256
                if obj.Filter[i]:
257
                    # apply filters
258
                    nobjs = []
259
                    for o in objs:
260
                        props = [p.upper() for p in o.PropertiesList]
261
                        ok = True
262
                        for f in obj.Filter[i].split(";"):
263
                            args = [a.strip() for a in f.strip().split(":")]
264
                            if args[0][0] == "!":
265
                                inv = True
266
                                prop = args[0][1:].upper()
267
                            else:
268
                                inv = False
269
                                prop = args[0].upper()
270
                            fval = args[1].upper()
271
                            if prop == "TYPE":
272
                                prop = "IFCTYPE"
273
                            if inv:
274
                                if prop in props:
275
                                    csprop = o.PropertiesList[props.index(prop)]
276
                                    if fval in getattr(o,csprop).upper():
277
                                        ok = False
278
                            else:
279
                                if not (prop in props):
280
                                    ok = False
281
                                else:
282
                                    csprop = o.PropertiesList[props.index(prop)]
283
                                    if not (fval in getattr(o,csprop).upper()):
284
                                        ok = False
285
                        if ok:
286
                            nobjs.append(o)
287
                    objs = nobjs
288

289
                # perform operation: count or retrieve property
290

291
                if val.upper() == "COUNT":
292
                    val = len(objs)
293
                    if verbose:
294
                        print (val, ",".join([o.Label for o in objs]))
295
                    self.data["B"+str(li)] = str(val)
296
                    if obj.DetailedResults:
297
                        # additional blank line...
298
                        li += 1
299
                        self.data["A"+str(li)] = " "
300
                else:
301
                    vals = val.split(".")
302
                    if vals[0][0].islower():
303
                        # old-style: first member is not a property
304
                        vals = vals[1:]
305
                    sumval = 0
306

307
                    # get unit
308
                    tp = None
309
                    unit = None
310
                    q = None
311
                    if obj.Unit[i]:
312
                        unit = obj.Unit[i]
313
                        unit = unit.replace("^","")  # get rid of existing power symbol
314
                        unit = unit.replace("2","^2")
315
                        unit = unit.replace("3","^3")
316
                        unit = unit.replace("²","^2")
317
                        unit = unit.replace("³","^3")
318
                        if "2" in unit:
319
                            tp = FreeCAD.Units.Area
320
                        elif "3" in unit:
321
                            tp = FreeCAD.Units.Volume
322
                        elif "deg" in unit:
323
                            tp = FreeCAD.Units.Angle
324
                        else:
325
                            tp = FreeCAD.Units.Length
326

327
                    # format value
328
                    dv = params.get_param("Decimals",path="Units")
329
                    fs = "{:."+str(dv)+"f}" # format string
330
                    for o in objs:
331
                        if verbose:
332
                            l = o.Name+" ("+o.Label+"):"
333
                            print (l+(40-len(l))*" ",end="")
334
                        try:
335
                            d = o
336
                            for v in vals:
337
                                d = getattr(d,v)
338
                            if hasattr(d,"Value"):
339
                                d = d.Value
340
                        except Exception:
341
                            FreeCAD.Console.PrintWarning(translate("Arch","Unable to retrieve value from object")+": "+o.Name+"."+".".join(vals)+"\n")
342
                        else:
343
                            if verbose:
344
                                if tp and unit:
345
                                    v = fs.format(FreeCAD.Units.Quantity(d,tp).getValueAs(unit).Value)
346
                                    print(v,unit)
347
                                else:
348
                                    print(fs.format(d))
349
                            if obj.DetailedResults:
350
                                li += 1
351
                                self.data["A"+str(li)] = o.Name+" ("+o.Label+")"
352
                                if tp and unit:
353
                                    q = FreeCAD.Units.Quantity(d,tp)
354
                                    self.data["B"+str(li)] = str(q.getValueAs(unit).Value)
355
                                    self.data["C"+str(li)] = unit
356
                                else:
357
                                    self.data["B"+str(li)] = str(d)
358

359
                            if not sumval:
360
                                sumval = d
361
                            else:
362
                                sumval += d
363
                    val = sumval
364
                    if tp:
365
                        q = FreeCAD.Units.Quantity(val,tp)
366

367
                    # write data
368
                    if obj.DetailedResults:
369
                        li += 1
370
                        self.data["A"+str(li)] = "TOTAL"
371
                    if q and unit:
372
                        self.data["B"+str(li)] = str(q.getValueAs(unit).Value)
373
                        self.data["C"+str(li)] = unit
374
                    else:
375
                        self.data["B"+str(li)] = str(val)
376
                    if verbose:
377
                        if tp and unit:
378
                            v = fs.format(FreeCAD.Units.Quantity(val,tp).getValueAs(unit).Value)
379
                            print("TOTAL:"+34*" "+v+" "+unit)
380
                        else:
381
                            v = fs.format(val)
382
                            print("TOTAL:"+34*" "+v)
383
        self.setSpreadsheetData(obj)
384

385
    def dumps(self):
386

387
        return self.Type
388

389
    def loads(self,state):
390

391
        if state:
392
            self.Type = state
393

394

395
class _ViewProviderArchSchedule:
396

397
    "A View Provider for Schedules"
398

399
    def __init__(self,vobj):
400
        vobj.Proxy = self
401

402
    def getIcon(self):
403
        if self.Object.AutoUpdate is False:
404
            import TechDrawGui
405
            return ":/icons/TechDraw_TreePageUnsync.svg"
406
        import Arch_rc
407
        return ":/icons/Arch_Schedule.svg"
408

409
    def isShow(self):
410
        return True
411

412
    def attach(self, vobj):
413
        self.Object = vobj.Object
414

415
    def setEdit(self, vobj, mode=0):
416
        if mode != 0:
417
            return None
418

419
        self.taskd = ArchScheduleTaskPanel(vobj.Object)
420
        return True
421

422
    def unsetEdit(self, vobj, mode):
423
        if mode != 0:
424
            return None
425

426
        return True
427

428
    def doubleClicked(self, vobj):
429
        self.edit()
430

431
    def setupContextMenu(self, vobj, menu):
432
        actionEdit = QtGui.QAction(translate("Arch", "Edit"),
433
                                   menu)
434
        QtCore.QObject.connect(actionEdit,
435
                               QtCore.SIGNAL("triggered()"),
436
                               self.edit)
437
        menu.addAction(actionEdit)
438

439
        if self.Object.CreateSpreadsheet is True:
440
            msg = translate("Arch", "Remove spreadsheet")
441
        else:
442
            msg = translate("Arch", "Attach spreadsheet")
443
        actionToggleSpreadsheet = QtGui.QAction(QtGui.QIcon(":/icons/Arch_Schedule.svg"),
444
                                                msg,
445
                                                menu)
446
        QtCore.QObject.connect(actionToggleSpreadsheet,
447
                               QtCore.SIGNAL("triggered()"),
448
                               self.toggleSpreadsheet)
449
        menu.addAction(actionToggleSpreadsheet)
450

451
    def edit(self):
452
        FreeCADGui.ActiveDocument.setEdit(self.Object, 0)
453

454
    def toggleSpreadsheet(self):
455
        self.Object.CreateSpreadsheet = not self.Object.CreateSpreadsheet
456

457
    def claimChildren(self):
458
        if hasattr(self,"Object"):
459
            return [self.Object.Proxy.getSpreadSheet(self.Object)]
460

461
    def dumps(self):
462
        return None
463

464
    def loads(self,state):
465
        return None
466

467
    def getDisplayModes(self,vobj):
468
        return ["Default"]
469

470
    def getDefaultDisplayMode(self):
471
        return "Default"
472

473
    def setDisplayMode(self,mode):
474
        return mode
475

476

477
class ArchScheduleTaskPanel:
478

479
    '''The editmode TaskPanel for Schedules'''
480

481
    def __init__(self,obj=None):
482

483
        """Sets the panel up"""
484

485
        self.obj = obj
486
        self.form = FreeCADGui.PySideUic.loadUi(":/ui/ArchSchedule.ui")
487
        self.form.setWindowIcon(QtGui.QIcon(":/icons/Arch_Schedule.svg"))
488

489
        # set icons
490
        self.form.buttonAdd.setIcon(QtGui.QIcon(":/icons/list-add.svg"))
491
        self.form.buttonDel.setIcon(QtGui.QIcon(":/icons/list-remove.svg"))
492
        self.form.buttonClear.setIcon(QtGui.QIcon(":/icons/delete.svg"))
493
        self.form.buttonImport.setIcon(QtGui.QIcon(":/icons/document-open.svg"))
494
        self.form.buttonExport.setIcon(QtGui.QIcon(":/icons/document-save.svg"))
495
        self.form.buttonSelect.setIcon(QtGui.QIcon(":/icons/edit-select-all.svg"))
496

497
        # restore widths
498
        self.form.list.setColumnWidth(0,params.get_param_arch("ScheduleColumnWidth0"))
499
        self.form.list.setColumnWidth(1,params.get_param_arch("ScheduleColumnWidth1"))
500
        self.form.list.setColumnWidth(2,params.get_param_arch("ScheduleColumnWidth2"))
501
        self.form.list.setColumnWidth(3,params.get_param_arch("ScheduleColumnWidth3"))
502
        w = params.get_param_arch("ScheduleDialogWidth")
503
        h = params.get_param_arch("ScheduleDialogHeight")
504
        self.form.resize(w,h)
505

506
        # set delegate - Not using custom delegates for now...
507
        #self.form.list.setItemDelegate(ScheduleDelegate())
508
        #self.form.list.setEditTriggers(QtGui.QAbstractItemView.DoubleClicked)
509

510
        # connect slots
511
        QtCore.QObject.connect(self.form.buttonAdd, QtCore.SIGNAL("clicked()"), self.add)
512
        QtCore.QObject.connect(self.form.buttonDel, QtCore.SIGNAL("clicked()"), self.remove)
513
        QtCore.QObject.connect(self.form.buttonClear, QtCore.SIGNAL("clicked()"), self.clear)
514
        QtCore.QObject.connect(self.form.buttonImport, QtCore.SIGNAL("clicked()"), self.importCSV)
515
        QtCore.QObject.connect(self.form.buttonExport, QtCore.SIGNAL("clicked()"), self.export)
516
        QtCore.QObject.connect(self.form.buttonSelect, QtCore.SIGNAL("clicked()"), self.select)
517
        QtCore.QObject.connect(self.form.buttonBox, QtCore.SIGNAL("accepted()"), self.accept)
518
        QtCore.QObject.connect(self.form.buttonBox, QtCore.SIGNAL("rejected()"), self.reject)
519
        QtCore.QObject.connect(self.form, QtCore.SIGNAL("rejected()"), self.reject)
520
        self.form.list.clearContents()
521

522
        if self.obj:
523
            for p in [obj.Value,obj.Unit,obj.Objects,obj.Filter]:
524
                if len(obj.Description) != len(p):
525
                    return
526
            self.form.list.setRowCount(len(obj.Description))
527
            for i in range(5):
528
                for j in range(len(obj.Description)):
529
                    item = QtGui.QTableWidgetItem([obj.Description,obj.Value,obj.Unit,obj.Objects,obj.Filter][i][j])
530
                    self.form.list.setItem(j,i,item)
531
            self.form.lineEditName.setText(self.obj.Label)
532
            self.form.checkDetailed.setChecked(self.obj.DetailedResults)
533
            self.form.checkSpreadsheet.setChecked(self.obj.CreateSpreadsheet)
534

535
        # center over FreeCAD window
536
        mw = FreeCADGui.getMainWindow()
537
        self.form.move(mw.frameGeometry().topLeft() + mw.rect().center() - self.form.rect().center())
538

539
        # maintain above FreeCAD window
540
        self.form.setWindowFlags(self.form.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
541

542
        self.form.show()
543

544
    def add(self):
545

546
        """Adds a new row below the last one"""
547

548
        self.form.list.insertRow(self.form.list.currentRow()+1)
549

550
    def remove(self):
551

552
        """Removes the current row"""
553

554
        if self.form.list.currentRow() >= 0:
555
            self.form.list.removeRow(self.form.list.currentRow())
556

557
    def clear(self):
558

559
        """Clears the list"""
560

561
        self.form.list.clearContents()
562
        self.form.list.setRowCount(0)
563

564
    def importCSV(self):
565

566
        """Imports a CSV file"""
567

568
        filename = QtGui.QFileDialog.getOpenFileName(QtGui.QApplication.activeWindow(), translate("Arch","Import CSV file"), None, "CSV files (*.csv *.CSV)")
569
        if filename:
570
            filename = filename[0]
571
            self.form.list.clearContents()
572
            import csv
573
            with open(filename,'r') as csvfile:
574
                r = 0
575
                for row in csv.reader(csvfile):
576
                    self.form.list.insertRow(r)
577
                    for i in range(5):
578
                        if len(row) > i:
579
                            t = row[i]
580
                            #t = t.replace("²","^2")
581
                            #t = t.replace("³","^3")
582
                            self.form.list.setItem(r,i,QtGui.QTableWidgetItem(t))
583
                    r += 1
584

585
    def export(self):
586

587
        """Exports the results as MD or CSV"""
588

589
        # commit latest changes
590
        self.writeValues()
591

592
        # tests
593
        if not("Up-to-date" in self.obj.State):
594
            self.obj.Proxy.execute(self.obj)
595
        if not hasattr(self.obj.Proxy,"data"):
596
            return
597
        if not self.obj.Proxy.data:
598
            return
599

600
        filename = QtGui.QFileDialog.getSaveFileName(QtGui.QApplication.activeWindow(),
601
                                                     translate("Arch","Export CSV file"),
602
                                                     None,
603
                                                     "Comma-separated values (*.csv);;TAB-separated values (*.tsv);;Markdown (*.md)");
604
        if filename:
605
            filt = filename[1]
606
            filename = filename[0]
607
            # add missing extension
608
            if (not filename.lower().endswith(".csv")) and (not filename.lower().endswith(".tsv")) and (not filename.lower().endswith(".md")):
609
                if "csv" in filt:
610
                    filename += ".csv"
611
                elif "tsv" in filt:
612
                    filename += ".tsv"
613
                else:
614
                    filename += ".md"
615
            if filename.lower().endswith(".csv"):
616
                self.exportCSV(filename,delimiter=",")
617
            elif filename.lower().endswith(".tsv"):
618
                self.exportCSV(filename,delimiter="\t")
619
            elif filename.lower().endswith(".md"):
620
                self.exportMD(filename)
621
            else:
622
                FreeCAD.Console.PrintError(translate("Arch","Unable to recognize that file type")+":"+filename+"\n")
623

624
    def getRows(self):
625

626
        """get the rows that contain data"""
627

628
        rows = []
629
        if hasattr(self.obj.Proxy,"data") and self.obj.Proxy.data:
630
            for key in self.obj.Proxy.data.keys():
631
                n = key[1:]
632
                if not n in rows:
633
                    rows.append(n)
634
        rows.sort(key=int)
635
        return rows
636

637
    def exportCSV(self,filename,delimiter="\t"):
638

639
        """Exports the results as a CSV/TSV file"""
640

641
        import csv
642
        with open(filename, 'w') as csvfile:
643
            csvfile = csv.writer(csvfile,delimiter=delimiter)
644
            csvfile.writerow([translate("Arch","Description"),translate("Arch","Value"),translate("Arch","Unit")])
645
            if self.obj.DetailedResults:
646
                csvfile.writerow(["","",""])
647
            for i in self.getRows():
648
                r = []
649
                for j in ["A","B","C"]:
650
                    if j+i in self.obj.Proxy.data:
651
                        r.append(str(self.obj.Proxy.data[j+i]))
652
                    else:
653
                        r.append("")
654
                csvfile.writerow(r)
655
        print("successfully exported ",filename)
656

657
    def exportMD(self,filename):
658

659
        """Exports the results as a Markdown file"""
660

661
        with open(filename, 'w') as mdfile:
662
            mdfile.write("| "+translate("Arch","Description")+" | "+translate("Arch","Value")+" | "+translate("Arch","Unit")+" |\n")
663
            mdfile.write("| --- | --- | --- |\n")
664
            if self.obj.DetailedResults:
665
                mdfile.write("| | | |\n")
666
            for i in self.getRows():
667
                r = []
668
                for j in ["A","B","C"]:
669
                    if j+i in self.obj.Proxy.data:
670
                        r.append(str(self.obj.Proxy.data[j+i]))
671
                    else:
672
                        r.append("")
673
                mdfile.write("| "+" | ".join(r)+" |\n")
674
        print("successfully exported ",filename)
675

676
    def select(self):
677

678
        """Adds selected objects to current row"""
679

680
        if self.form.list.currentRow() >= 0:
681
            sel = ""
682
            for o in FreeCADGui.Selection.getSelection():
683
                if o != self.obj:
684
                    if sel:
685
                        sel += ";"
686
                    sel += o.Name
687
            if sel:
688
                self.form.list.setItem(self.form.list.currentRow(),3,QtGui.QTableWidgetItem(sel))
689

690
    def accept(self):
691

692
        """Saves the changes and closes the dialog"""
693

694
        # store widths
695
        params.set_param_arch("ScheduleColumnWidth0",self.form.list.columnWidth(0))
696
        params.set_param_arch("ScheduleColumnWidth1",self.form.list.columnWidth(1))
697
        params.set_param_arch("ScheduleColumnWidth2",self.form.list.columnWidth(2))
698
        params.set_param_arch("ScheduleColumnWidth3",self.form.list.columnWidth(3))
699
        params.set_param_arch("ScheduleDialogWidth",self.form.width())
700
        params.set_param_arch("ScheduleDialogHeight",self.form.height())
701

702
        # commit values
703
        self.writeValues()
704
        self.form.hide()
705
        FreeCADGui.ActiveDocument.resetEdit()
706
        return True
707

708
    def reject(self):
709

710
        """Close dialog without saving"""
711

712
        self.form.hide()
713
        FreeCADGui.ActiveDocument.resetEdit()
714
        return True
715

716
    def writeValues(self):
717

718
        """commits values and recalculate"""
719

720
        if not self.obj:
721
            self.obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Schedule")
722
            self.obj.Label = translate("Arch","Schedule")
723
            _ArchSchedule(self.obj)
724
            if FreeCAD.GuiUp:
725
                _ViewProviderArchSchedule(self.obj.ViewObject)
726
            if hasattr(self.obj,"CreateSpreadsheet") and self.obj.CreateSpreadsheet:
727
                self.obj.Proxy.getSpreadSheet(self.obj, force=True)
728
        lists = [ [], [], [], [], [] ]
729
        for i in range(self.form.list.rowCount()):
730
            for j in range(5):
731
                cell = self.form.list.item(i,j)
732
                if cell:
733
                    lists[j].append(cell.text())
734
                else:
735
                    lists[j].append("")
736
        FreeCAD.ActiveDocument.openTransaction("Edited Schedule")
737
        self.obj.Description = lists[0]
738
        self.obj.Value = lists[1]
739
        self.obj.Unit = lists[2]
740
        self.obj.Objects = lists[3]
741
        self.obj.Filter = lists[4]
742
        self.obj.Label = self.form.lineEditName.text()
743
        self.obj.DetailedResults = self.form.checkDetailed.isChecked()
744
        self.obj.CreateSpreadsheet = self.form.checkSpreadsheet.isChecked()
745
        self.obj.AutoUpdate = self.form.checkAutoUpdate.isChecked()
746
        FreeCAD.ActiveDocument.commitTransaction()
747
        FreeCAD.ActiveDocument.recompute()
748

749

750

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.