FreeCAD

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

22
import FreeCAD
23
from draftutils import params
24

25
if FreeCAD.GuiUp:
26
    import FreeCADGui, os
27
    import Arch_rc # Needed for access to icons # lgtm [py/unused_import]
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
__title__ = "Arch Material Management"
40
__author__ = "Yorik van Havre"
41
__url__ = "https://www.freecad.org"
42

43
## @package ArchMaterial
44
#  \ingroup ARCH
45
#  \brief The Material object and tools
46
#
47
#  This module provides tools to add materials to
48
#  Arch objects
49

50

51
class _ArchMaterialContainer:
52

53

54
    "The Material Container"
55

56
    def __init__(self,obj):
57
        self.Type = "MaterialContainer"
58
        obj.Proxy = self
59

60
    def execute(self,obj):
61
        return
62

63
    def dumps(self):
64
        if hasattr(self,"Type"):
65
            return self.Type
66

67
    def loads(self,state):
68
        if state:
69
            self.Type = state
70

71

72
class _ViewProviderArchMaterialContainer:
73

74

75
    "A View Provider for the Material Container"
76

77
    def __init__(self,vobj):
78
        vobj.Proxy = self
79

80
    def getIcon(self):
81
        return ":/icons/Arch_Material_Group.svg"
82

83
    def attach(self,vobj):
84
        self.Object = vobj.Object
85

86
    def setupContextMenu(self, vobj, menu):
87
        actionMergeByName = QtGui.QAction(QtGui.QIcon(":/icons/Arch_Material_Group.svg"),
88
                                          translate("Arch", "Merge duplicates"),
89
                                          menu)
90
        actionMergeByName.triggered.connect(self.mergeByName)
91
        menu.addAction(actionMergeByName)
92

93
        actionReorder = QtGui.QAction(translate("Arch", "Reorder children alphabetically"),
94
                                      menu)
95
        actionReorder.triggered.connect(self.reorder)
96
        menu.addAction(actionReorder)
97

98
    def mergeByName(self):
99
        if hasattr(self,"Object"):
100
            mats = [o for o in self.Object.Group if o.isDerivedFrom("App::MaterialObject")]
101
            todelete = []
102
            for mat in mats:
103
                orig = None
104
                for om in mats:
105
                    if om.Label == mat.Label:
106
                        orig = om
107
                        break
108
                else:
109
                    if mat.Label[-1].isdigit() and mat.Label[-2].isdigit() and mat.Label[-3].isdigit():
110
                        for om in mats:
111
                            if om.Label == mat.Label[:-3].strip():
112
                                orig = om
113
                                break
114
                if orig:
115
                    for par in mat.InList:
116
                        for prop in par.PropertiesList:
117
                            if getattr(par,prop) == mat:
118
                                FreeCAD.Console.PrintMessage("Changed property '"+prop+"' of object "+par.Label+" from "+mat.Label+" to "+orig.Label+"\n")
119
                                setattr(par,prop,orig)
120
                    todelete.append(mat)
121
            for tod in todelete:
122
                if not tod.InList:
123
                    FreeCAD.Console.PrintMessage("Merging duplicate material "+tod.Label+"\n")
124
                    FreeCAD.ActiveDocument.removeObject(tod.Name)
125
                elif (len(tod.InList) == 1) and (tod.InList[0].isDerivedFrom("App::DocumentObjectGroup")):
126
                    FreeCAD.Console.PrintMessage("Merging duplicate material "+tod.Label+"\n")
127
                    FreeCAD.ActiveDocument.removeObject(tod.Name)
128
                else:
129
                    FreeCAD.Console.PrintMessage("Unable to delete material "+tod.Label+": InList not empty\n")
130

131
    def reorder(self):
132
        if hasattr(self,"Object"):
133
            if hasattr(self.Object,"Group") and self.Object.Group:
134
                g = self.Object.Group
135
                g.sort(key=lambda obj: obj.Label)
136
                self.Object.Group = g
137
                FreeCAD.ActiveDocument.recompute()
138

139
    def dumps(self):
140
        return None
141

142
    def loads(self,state):
143
        return None
144

145

146
class _ArchMaterial:
147

148

149
    "The Material object"
150

151
    def __init__(self,obj):
152

153
        self.Type = "Material"
154
        obj.Proxy = self
155
        self.setProperties(obj)
156

157
    def onDocumentRestored(self,obj):
158

159
        self.setProperties(obj)
160

161
    def setProperties(self,obj):
162

163
        if not "Description" in obj.PropertiesList:
164
            obj.addProperty("App::PropertyString","Description","Material",QT_TRANSLATE_NOOP("App::Property","A description for this material"))
165
        if not "StandardCode" in obj.PropertiesList:
166
            obj.addProperty("App::PropertyString","StandardCode","Material",QT_TRANSLATE_NOOP("App::Property","A standard code (MasterFormat, OmniClass,...)"))
167
        if not "ProductURL" in obj.PropertiesList:
168
            obj.addProperty("App::PropertyString","ProductURL","Material",QT_TRANSLATE_NOOP("App::Property","A URL where to find information about this material"))
169
        if not "Transparency" in obj.PropertiesList:
170
            obj.addProperty("App::PropertyPercent","Transparency","Material",QT_TRANSLATE_NOOP("App::Property","The transparency value of this material"))
171
        if not "Color" in obj.PropertiesList:
172
            obj.addProperty("App::PropertyColor","Color","Material",QT_TRANSLATE_NOOP("App::Property","The color of this material"))
173
        if not "SectionColor" in obj.PropertiesList:
174
            obj.addProperty("App::PropertyColor","SectionColor","Material",QT_TRANSLATE_NOOP("App::Property","The color of this material when cut"))
175

176
    def isSameColor(self,c1,c2):
177

178
        r = 4
179
        if round(c1[0],r) == round(c2[0],r):
180
            if round(c1[1],r) == round(c2[1],r):
181
                if round(c1[2],r) == round(c2[2],r):
182
                    return True
183
        return False
184

185
    def onChanged(self,obj,prop):
186

187
        d = obj.Material
188
        if prop == "Material":
189
            if "SectionColor" in obj.Material:
190
                c = tuple([float(f) for f in obj.Material['SectionColor'].strip("()").strip("[]").split(",")])
191
                if hasattr(obj,"SectionColor"):
192
                    if not self.isSameColor(obj.SectionColor,c):
193
                        obj.SectionColor = c
194
            if "DiffuseColor" in obj.Material:
195
                c = tuple([float(f) for f in obj.Material['DiffuseColor'].strip("()").strip("[]").split(",")])
196
                if hasattr(obj,"Color"):
197
                    if not self.isSameColor(obj.Color,c):
198
                        obj.Color = c
199
            if "Transparency" in obj.Material:
200
                t = int(obj.Material['Transparency'])
201
                if hasattr(obj,"Transparency"):
202
                    if obj.Transparency != t:
203
                        obj.Transparency = t
204
            if "ProductURL" in obj.Material:
205
                if hasattr(obj,"ProductURL"):
206
                    if obj.ProductURL != obj.Material["ProductURL"]:
207
                        obj.ProductURL = obj.Material["ProductURL"]
208
            if "StandardCode" in obj.Material:
209
                if hasattr(obj,"StandardCode"):
210
                    if obj.StandardCode != obj.Material["StandardCode"]:
211
                        obj.StandardCode = obj.Material["StandardCode"]
212
            if "Description" in obj.Material:
213
                if hasattr(obj,"Description"):
214
                    if obj.Description != obj.Material["Description"]:
215
                        obj.Description = obj.Material["Description"]
216
            if "Name" in obj.Material:
217
                if hasattr(obj,"Label"):
218
                    if obj.Label != obj.Material["Name"]:
219
                        obj.Label = obj.Material["Name"]
220
        elif prop == "Label":
221
            if "Name" in d:
222
                if d["Name"] == obj.Label:
223
                    return
224
            d["Name"] = obj.Label
225
        elif prop == "SectionColor":
226
            if hasattr(obj,"SectionColor"):
227
                if "SectionColor" in d:
228
                    if self.isSameColor(tuple([float(f) for f in d['SectionColor'].strip("()").strip("[]").split(",")]),obj.SectionColor[:3]):
229
                        return
230
                d["SectionColor"] = str(obj.SectionColor[:3])
231
        elif prop == "Color":
232
            if hasattr(obj,"Color"):
233
                if "DiffuseColor" in d:
234
                    if self.isSameColor(tuple([float(f) for f in d['DiffuseColor'].strip("()").strip("[]").split(",")]),obj.Color[:3]):
235
                        return
236
                d["DiffuseColor"] = str(obj.Color[:3])
237
        elif prop == "Transparency":
238
            if hasattr(obj,"Transparency"):
239
                val = str(obj.Transparency)
240
                if "Transparency" in d:
241
                    if d["Transparency"] == val:
242
                        return
243
                d["Transparency"] = val
244
        elif prop == "ProductURL":
245
            if hasattr(obj,"ProductURL"):
246
                val = obj.ProductURL
247
                if "ProductURL" in d:
248
                    if d["ProductURL"] == val:
249
                        return
250
                obj.Material["ProductURL"] = val
251
        elif prop == "StandardCode":
252
            if hasattr(obj,"StandardCode"):
253
                val = obj.StandardCode
254
                if "StandardCode" in d:
255
                    if d["StandardCode"] == val:
256
                        return
257
                d["StandardCode"] = val
258
        elif prop == "Description":
259
            if hasattr(obj,"Description"):
260
                val = obj.Description
261
                if "Description" in d:
262
                    if d["Description"] == val:
263
                        return
264
                d["Description"] = val
265
        if d and (d != obj.Material):
266
            obj.Material = d
267
            #if FreeCAD.GuiUp:
268
                #import FreeCADGui
269
                # not sure why this is needed, but it is...
270
                #FreeCADGui.ActiveDocument.resetEdit()
271

272
    def execute(self,obj):
273
        if obj.Material:
274
            if FreeCAD.GuiUp:
275
                if "DiffuseColor" in obj.Material:
276
                    c = tuple([float(f) for f in obj.Material['DiffuseColor'].strip("()").strip("[]").split(",")])
277
                    for p in obj.InList:
278
                        if hasattr(p,"Material") and ( (not hasattr(p.ViewObject,"UseMaterialColor")) or p.ViewObject.UseMaterialColor):
279
                            if p.Material.Name == obj.Name:
280
                                p.ViewObject.ShapeColor = c
281
        return
282

283
    def dumps(self):
284
        if hasattr(self,"Type"):
285
            return self.Type
286

287
    def loads(self,state):
288
        if state:
289
            self.Type = state
290

291

292
class _ViewProviderArchMaterial:
293

294
    "A View Provider for the Material object"
295

296
    def __init__(self,vobj):
297
        vobj.Proxy = self
298

299
    def getIcon(self):
300
        if hasattr(self,"icondata"):
301
            return self.icondata
302
        return ":/icons/Arch_Material.svg"
303

304
    def attach(self, vobj):
305
        self.Object = vobj.Object
306

307
    def updateData(self, obj, prop):
308
        if prop == "Color":
309
            from PySide import QtCore,QtGui
310

311
            # custom icon
312
            if hasattr(obj,"Color"):
313
                c = obj.Color
314
                matcolor = QtGui.QColor(int(c[0]*255),int(c[1]*255),int(c[2]*255))
315
                darkcolor = QtGui.QColor(int(c[0]*125),int(c[1]*125),int(c[2]*125))
316
                im = QtGui.QImage(48,48,QtGui.QImage.Format_ARGB32)
317
                im.fill(QtCore.Qt.transparent)
318
                pt = QtGui.QPainter(im)
319
                pt.setPen(QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, QtCore.Qt.FlatCap))
320
                #pt.setBrush(QtGui.QBrush(matcolor, QtCore.Qt.SolidPattern))
321
                gradient = QtGui.QLinearGradient(0,0,48,48)
322
                gradient.setColorAt(0,matcolor)
323
                gradient.setColorAt(1,darkcolor)
324
                pt.setBrush(QtGui.QBrush(gradient))
325
                pt.drawEllipse(6,6,36,36)
326
                pt.setPen(QtGui.QPen(QtCore.Qt.white, 1, QtCore.Qt.SolidLine, QtCore.Qt.FlatCap))
327
                pt.setBrush(QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern))
328
                pt.drawEllipse(12,12,12,12)
329
                pt.end()
330

331
                ba = QtCore.QByteArray()
332
                b = QtCore.QBuffer(ba)
333
                b.open(QtCore.QIODevice.WriteOnly)
334
                im.save(b,"XPM")
335
                self.icondata = ba.data().decode("latin1")
336

337
    def onChanged(self, vobj, prop):
338
        if prop == "Material":
339
            if "Father" in vobj.Object.Material:
340
                for o in FreeCAD.ActiveDocument.Objects:
341
                    if o.isDerivedFrom("App::MaterialObject"):
342
                        if o.Label == vobj.Object.Material["Father"]:
343
                            o.touch()
344

345
    def setEdit(self, vobj, mode):
346
        if mode != 0:
347
            return None
348

349
        self.taskd = _ArchMaterialTaskPanel(vobj.Object)
350
        FreeCADGui.Control.showDialog(self.taskd)
351
        self.taskd.form.FieldName.setFocus()
352
        self.taskd.form.FieldName.selectAll()
353
        return True
354

355
    def unsetEdit(self, vobj, mode):
356
        if mode != 0:
357
            return None
358

359
        FreeCADGui.Control.closeDialog()
360
        return True
361

362
    def setupContextMenu(self, vobj, menu):
363
        actionEdit = QtGui.QAction(translate("Arch", "Edit"),
364
                                   menu)
365
        actionEdit.triggered.connect(self.edit)
366
        menu.addAction(actionEdit)
367

368
    def edit(self):
369
        FreeCADGui.ActiveDocument.setEdit(self.Object, 0)
370

371
    def setTaskValue(self,widgetname,value):
372
        if hasattr(self,"taskd"):
373
            if hasattr(self.taskd,"form"):
374
                if hasattr(self.taskd.form,widgetname):
375
                    widget = getattr(self.taskd.form,widgetname)
376
                    if hasattr(widget,"setText"):
377
                        widget.setText(value)
378
                    elif hasattr(widget,"setValue"):
379
                        widget.setText(value)
380

381
    def dumps(self):
382
        return None
383

384
    def loads(self,state):
385
        return None
386

387
    def claimChildren(self):
388
        ch = []
389
        if hasattr(self,"Object"):
390
            for o in self.Object.Document.Objects:
391
                if o.isDerivedFrom("App::MaterialObject"):
392
                    if o.Material:
393
                        if "Father" in o.Material:
394
                            if o.Material["Father"] == self.Object.Label:
395
                                ch.append(o)
396
        return ch
397

398

399
class _ArchMaterialTaskPanel:
400

401
    '''The editmode TaskPanel for Arch Material objects'''
402

403
    def __init__(self,obj=None):
404
        self.cards = None
405
        self.existingmaterials = []
406
        self.obj = obj
407
        self.form = FreeCADGui.PySideUic.loadUi(":/ui/ArchMaterial.ui")
408
        colorPix = QtGui.QPixmap(16,16)
409
        colorPix.fill(QtGui.QColor(204,204,204))
410
        self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix))
411
        self.form.ButtonSectionColor.setIcon(QtGui.QIcon(colorPix))
412
        self.form.ButtonUrl.setIcon(QtGui.QIcon(":/icons/internet-web-browser.svg"))
413
        self.form.comboBox_MaterialsInDir.currentIndexChanged.connect(self.chooseMat)
414
        self.form.comboBox_FromExisting.currentIndexChanged.connect(self.fromExisting)
415
        self.form.comboFather.currentTextChanged.connect(self.setFather)
416
        self.form.ButtonColor.pressed.connect(self.getColor)
417
        self.form.ButtonSectionColor.pressed.connect(self.getSectionColor)
418
        self.form.ButtonUrl.pressed.connect(self.openUrl)
419
        self.form.ButtonEditor.pressed.connect(self.openEditor)
420
        self.form.ButtonCode.pressed.connect(self.getCode)
421
        self.fillMaterialCombo()
422
        self.fillExistingCombo()
423
        try:
424
            from bimcommands import BimClassification
425
        except Exception:
426
            self.form.ButtonCode.hide()
427
        else:
428
            self.form.ButtonCode.setIcon(QtGui.QIcon(":/icons/BIM_Classification.svg"))
429
        if self.obj:
430
            if hasattr(self.obj,"Material"):
431
                self.material = self.obj.Material
432
        self.setFields()
433

434
    def setFields(self):
435
        "sets the task box contents from self.material"
436
        if 'Name' in self.material:
437
            self.form.FieldName.setText(self.material['Name'])
438
        elif self.obj:
439
            self.form.FieldName.setText(self.obj.Label)
440
        if 'Description' in self.material:
441
            self.form.FieldDescription.setText(self.material['Description'])
442
        if 'DiffuseColor' in self.material:
443
            self.form.ButtonColor.setIcon(self.getColorIcon(self.material["DiffuseColor"]))
444
        elif 'ViewColor' in self.material:
445
            self.form.ButtonColor.setIcon(self.getColorIcon(self.material["ViewColor"]))
446
        elif 'Color' in self.material:
447
            self.form.ButtonColor.setIcon(self.getColorIcon(self.material["Color"]))
448
        if 'SectionColor' in self.material:
449
            self.form.ButtonSectionColor.setIcon(self.getColorIcon(self.material["SectionColor"]))
450
        if 'StandardCode' in self.material:
451
            self.form.FieldCode.setText(self.material['StandardCode'])
452
        if 'ProductURL' in self.material:
453
            self.form.FieldUrl.setText(self.material['ProductURL'])
454
        if 'Transparency' in self.material:
455
            self.form.SpinBox_Transparency.setValue(int(self.material["Transparency"]))
456
        if "Father" in self.material:
457
            father = self.material["Father"]
458
        else:
459
            father = None
460
        found = False
461
        self.form.comboFather.addItem("None")
462
        for o in FreeCAD.ActiveDocument.Objects:
463
            if o.isDerivedFrom("App::MaterialObject"):
464
                if o != self.obj:
465
                    self.form.comboFather.addItem(o.Label)
466
                    if o.Label == father:
467
                        self.form.comboFather.setCurrentIndex(self.form.comboFather.count()-1)
468
                        found = True
469
        if father and not found:
470
            self.form.comboFather.addItem(father)
471
            self.form.comboFather.setCurrentIndex(self.form.comboFather.count()-1)
472

473
    def getColorIcon(self,color):
474
        if color:
475
            if "(" in color:
476
                c = tuple([float(f) for f in color.strip("()").split(",")])
477
                qcolor = QtGui.QColor()
478
                qcolor.setRgbF(c[0],c[1],c[2])
479
                colorPix = QtGui.QPixmap(16,16)
480
                colorPix.fill(qcolor)
481
                icon = QtGui.QIcon(colorPix)
482
                return icon
483
        return QtGui.QIcon()
484

485
    def getFields(self):
486
        "sets self.material from the contents of the task box"
487
        self.material['Name'] = self.form.FieldName.text()
488
        self.material['Description'] = self.form.FieldDescription.text()
489
        self.material['DiffuseColor'] = self.getColorFromIcon(self.form.ButtonColor.icon())
490
        self.material['ViewColor'] = self.material['DiffuseColor']
491
        self.material['Color'] = self.material['DiffuseColor']
492
        self.material['SectionColor'] = self.getColorFromIcon(self.form.ButtonSectionColor.icon())
493
        self.material['StandardCode'] = self.form.FieldCode.text()
494
        self.material['ProductURL'] = self.form.FieldUrl.text()
495
        self.material['Transparency'] = str(self.form.SpinBox_Transparency.value())
496

497
    def getColorFromIcon(self,icon):
498
        "gets pixel color from the given icon"
499
        pixel = icon.pixmap(16,16).toImage().pixel(0,0)
500
        return str(QtGui.QColor(pixel).getRgbF())
501

502
    def accept(self):
503
        self.getFields()
504
        if self.obj:
505
            if hasattr(self.obj,"Material"):
506
                self.obj.Material = self.material
507
                self.obj.Label = self.material['Name']
508
        FreeCAD.ActiveDocument.recompute()
509
        FreeCADGui.ActiveDocument.resetEdit()
510
        return True
511

512
    def reject(self):
513
        FreeCADGui.ActiveDocument.resetEdit()
514
        return True
515

516
    def chooseMat(self, card):
517
        "sets self.material from a card"
518
        card = self.form.comboBox_MaterialsInDir.currentText()
519
        if card in self.cards:
520
            import importFCMat
521
            self.material = importFCMat.read(self.cards[card])
522
            self.setFields()
523

524
    def fromExisting(self,index):
525
        "sets the contents from an existing material"
526
        if index > 0:
527
            if index <= len(self.existingmaterials):
528
                m = self.existingmaterials[index-1]
529
                if m.Material:
530
                    self.material = m.Material
531
                    self.setFields()
532

533
    def setFather(self, text):
534
        "sets the father"
535
        if text:
536
            if text == "None":
537
                if "Father" in self.material:
538
                    # for some have Father at first and change to none
539
                    self.material.pop("Father")
540
            else:
541
                self.material["Father"] = text
542

543
    def getColor(self):
544
        self.getColorForButton(self.form.ButtonColor)
545

546
    def getSectionColor(self):
547
        self.getColorForButton(self.form.ButtonSectionColor)
548

549
    def getColorForButton(self,button):
550
        "opens a color picker dialog"
551
        icon = button.icon()
552
        pixel = icon.pixmap(16,16).toImage().pixel(0,0)
553
        color = QtGui.QColorDialog.getColor(QtGui.QColor(pixel))
554
        if color.isValid():
555
            colorPix = QtGui.QPixmap(16,16)
556
            colorPix.fill(color)
557
            button.setIcon(QtGui.QIcon(colorPix))
558

559
    def fillMaterialCombo(self):
560
        "fills the combo with the existing FCMat cards"
561
        # look for cards in both resources dir and a Materials sub-folder in the user folder.
562
        # User cards with same name will override system cards
563
        resources_mat_path = os.path.join(FreeCAD.getResourceDir(), "Mod", "Material", "Resources", "Materials")
564
        resources_mat_path_std = os.path.join(resources_mat_path, "Standard")
565
        user_mat_path = os.path.join(FreeCAD.ConfigGet("UserAppData"), "Material")
566

567
        paths = [resources_mat_path_std]
568
        if os.path.exists(user_mat_path):
569
            paths.append(user_mat_path)
570
        self.cards = {}
571
        for p in paths:
572
            for root, _, f_names in os.walk(p):
573
                for f in f_names:
574
                    b,e = os.path.splitext(f)
575
                    if e.upper() == ".FCMAT":
576
                        self.cards[b] = os.path.join(root, f)
577
        if self.cards:
578
            for k in sorted(self.cards):
579
                self.form.comboBox_MaterialsInDir.addItem(k)
580

581
    def fillExistingCombo(self):
582
        "fills the existing materials combo"
583
        self.existingmaterials = []
584
        for obj in FreeCAD.ActiveDocument.Objects:
585
            if obj.isDerivedFrom("App::MaterialObject"):
586
                if obj != self.obj:
587
                    self.existingmaterials.append(obj)
588
        for m in self.existingmaterials:
589
            self.form.comboBox_FromExisting.addItem(m.Label)
590

591

592
    def openEditor(self):
593
        "opens the full material editor from the material module"
594
        self.getFields()
595
        if self.material:
596
            import MaterialEditor
597
            self.material = MaterialEditor.editMaterial(self.material)
598
            self.setFields()
599

600
    def openUrl(self):
601
        self.getFields()
602
        if self.material:
603
            if 'ProductURL' in self.material:
604
                QtGui.QDesktopServices.openUrl(self.material['ProductURL'])
605

606
    def getCode(self):
607
        FreeCADGui.Selection.addSelection(self.obj)
608
        FreeCADGui.runCommand("BIM_Classification")
609

610

611
class _ArchMultiMaterial:
612

613
    "The MultiMaterial object"
614

615
    def __init__(self,obj):
616
        self.Type = "MultiMaterial"
617
        obj.Proxy = self
618
        obj.addProperty("App::PropertyString","Description","Arch",QT_TRANSLATE_NOOP("App::Property","A description for this material"))
619
        obj.addProperty("App::PropertyStringList","Names","Arch",QT_TRANSLATE_NOOP("App::Property","The list of layer names"))
620
        obj.addProperty("App::PropertyLinkList","Materials","Arch",QT_TRANSLATE_NOOP("App::Property","The list of layer materials"))
621
        obj.addProperty("App::PropertyFloatList","Thicknesses","Arch",QT_TRANSLATE_NOOP("App::Property","The list of layer thicknesses"))
622

623
    def dumps(self):
624
        if hasattr(self,"Type"):
625
            return self.Type
626

627
    def loads(self,state):
628
        if state:
629
            self.Type = state
630

631
class _ViewProviderArchMultiMaterial:
632

633
    "A View Provider for the MultiMaterial object"
634

635
    def __init__(self,vobj):
636
        vobj.Proxy = self
637

638
    def getIcon(self):
639
        return ":/icons/Arch_Material_Multi.svg"
640

641
    def attach(self, vobj):
642
        self.Object = vobj.Object
643

644
    def setEdit(self, vobj, mode):
645
        if mode != 0:
646
            return None
647

648
        taskd = _ArchMultiMaterialTaskPanel(vobj.Object)
649
        FreeCADGui.Control.showDialog(taskd)
650
        return True
651

652
    def unsetEdit(self, vobj, mode):
653
        if mode != 0:
654
            return None
655

656
        FreeCADGui.Control.closeDialog()
657
        return True
658

659
    def doubleClicked(self,vobj):
660
        self.edit()
661

662
    def setupContextMenu(self, vobj, menu):
663
        actionEdit = QtGui.QAction(translate("Arch", "Edit"),
664
                                   menu)
665
        actionEdit.triggered.connect(self.edit)
666
        menu.addAction(actionEdit)
667

668
    def edit(self):
669
        FreeCADGui.ActiveDocument.setEdit(self.Object, 0)
670

671
    def dumps(self):
672
        return None
673

674
    def loads(self,state):
675
        return None
676

677
    def isShow(self):
678
        return True
679

680
if FreeCAD.GuiUp:
681

682
    class MultiMaterialDelegate(QtGui.QStyledItemDelegate):
683

684
        def __init__(self, parent=None, *args):
685
            self.mats = []
686
            for obj in FreeCAD.ActiveDocument.Objects:
687
                if obj.isDerivedFrom("App::MaterialObject"):
688
                    self.mats.append(obj)
689
            QtGui.QStyledItemDelegate.__init__(self, parent, *args)
690

691
        def createEditor(self,parent,option,index):
692
            if index.column() == 0:
693
                editor = QtGui.QComboBox(parent)
694
                editor.setEditable(True)
695
            elif index.column() == 1:
696
                editor = QtGui.QComboBox(parent)
697
            elif index.column() == 2:
698
                ui = FreeCADGui.UiLoader()
699
                editor = ui.createWidget("Gui::InputField")
700
                editor.setSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Minimum)
701
                editor.setParent(parent)
702
            else:
703
                editor = QtGui.QLineEdit(parent)
704
            return editor
705

706
        def setEditorData(self, editor, index):
707
            if index.column() == 0:
708
                import ArchWindow
709
                editor.addItems([index.data()]+ArchWindow.WindowPartTypes)
710
            elif index.column() == 1:
711
                idx = -1
712
                for i,m in enumerate(self.mats):
713
                    editor.addItem(m.Label)
714
                    if m.Label == index.data():
715
                        idx = i
716
                editor.setCurrentIndex(idx)
717
            else:
718
                QtGui.QStyledItemDelegate.setEditorData(self, editor, index)
719

720
        def setModelData(self, editor, model, index):
721
            if index.column() == 0:
722
                if editor.currentIndex() == -1:
723
                    model.setData(index, "")
724
                else:
725
                    model.setData(index, editor.currentText())
726
            elif index.column() == 1:
727
                if editor.currentIndex() == -1:
728
                    model.setData(index, "")
729
                else:
730
                    model.setData(index, self.mats[editor.currentIndex()].Label)
731
            else:
732
                QtGui.QStyledItemDelegate.setModelData(self, editor, model, index)
733

734

735
class _ArchMultiMaterialTaskPanel:
736

737
    '''The editmode TaskPanel for MultiMaterial objects'''
738

739
    def __init__(self,obj=None):
740
        self.obj = obj
741
        self.form = FreeCADGui.PySideUic.loadUi(":/ui/ArchMultiMaterial.ui")
742
        self.model = QtGui.QStandardItemModel()
743
        self.model.setHorizontalHeaderLabels([translate("Arch","Name"),translate("Arch","Material"),translate("Arch","Thickness")])
744
        self.form.tree.setModel(self.model)
745
        self.form.tree.setUniformRowHeights(True)
746
        self.form.tree.setItemDelegate(MultiMaterialDelegate())
747
        self.form.chooseCombo.currentIndexChanged.connect(self.fromExisting)
748
        self.form.addButton.pressed.connect(self.addLayer)
749
        self.form.upButton.pressed.connect(self.upLayer)
750
        self.form.downButton.pressed.connect(self.downLayer)
751
        self.form.delButton.pressed.connect(self.delLayer)
752
        self.form.invertButton.pressed.connect(self.invertLayer)
753
        self.model.itemChanged.connect(self.recalcThickness)
754
        self.fillExistingCombo()
755
        self.fillData()
756

757
    def fillData(self,obj=None):
758
        if not obj:
759
            obj = self.obj
760
        if obj:
761
            self.model.clear()
762
            self.model.setHorizontalHeaderLabels([translate("Arch","Name"),translate("Arch","Material"),translate("Arch","Thickness")])
763
            # restore widths
764
            self.form.tree.setColumnWidth(0,params.get_param_arch("MultiMaterialColumnWidth0"))
765
            self.form.tree.setColumnWidth(1,params.get_param_arch("MultiMaterialColumnWidth1"))
766
            for i in range(len(obj.Names)):
767
                item1 = QtGui.QStandardItem(obj.Names[i])
768
                item2 = QtGui.QStandardItem(obj.Materials[i].Label)
769
                item3 = QtGui.QStandardItem(FreeCAD.Units.Quantity(obj.Thicknesses[i],FreeCAD.Units.Length).getUserPreferred()[0])
770
                self.model.appendRow([item1,item2,item3])
771
            self.form.nameField.setText(obj.Label)
772

773
    def fillExistingCombo(self):
774
        "fills the existing multimaterials combo"
775
        import Draft
776
        self.existingmaterials = []
777
        for obj in FreeCAD.ActiveDocument.Objects:
778
            if Draft.getType(obj) == "MultiMaterial":
779
                if obj != self.obj:
780
                    self.existingmaterials.append(obj)
781
        for m in self.existingmaterials:
782
            self.form.chooseCombo.addItem(m.Label)
783

784
    def fromExisting(self,index):
785
        "sets the contents from an existing material"
786
        if index > 0:
787
            if index <= len(self.existingmaterials):
788
                m = self.existingmaterials[index-1]
789
                if m:
790
                    self.fillData(m)
791

792
    def addLayer(self):
793
        item1 = QtGui.QStandardItem(translate("Arch","New layer"))
794
        item2 = QtGui.QStandardItem()
795
        item3 = QtGui.QStandardItem()
796
        self.model.appendRow([item1,item2,item3])
797

798
    def delLayer(self):
799
        sel = self.form.tree.selectedIndexes()
800
        if sel:
801
            row = sel[0].row()
802
            if row >= 0:
803
                self.model.takeRow(row)
804
        self.recalcThickness()
805

806
    def moveLayer(self,mvt=0):
807
        sel = self.form.tree.selectedIndexes()
808
        if sel and mvt:
809
            row = sel[0].row()
810
            if row >= 0:
811
                if row+mvt >= 0:
812
                    data = self.model.takeRow(row)
813
                    self.model.insertRow(row+mvt,data)
814
                    ind = self.model.index(row+mvt,0)
815
                    self.form.tree.setCurrentIndex(ind)
816

817
    def upLayer(self):
818
        self.moveLayer(mvt=-1)
819

820
    def downLayer(self):
821
        self.moveLayer(mvt=1)
822

823
    def invertLayer(self):
824
        items = [self.model.takeRow(row) for row in range(self.model.rowCount()-1,-1,-1)]
825
        items.reverse()
826
        for item in items:
827
            self.model.insertRow(0,item)
828

829
    def recalcThickness(self,item=None):
830
        prefix = translate("Arch","Total thickness")+": "
831
        th = 0
832
        suffix = ""
833
        for row in range(self.model.rowCount()):
834
            thick = 0
835
            d = self.model.item(row,2).text()
836
            try:
837
                d = float(d)
838
            except Exception:
839
                thick = FreeCAD.Units.Quantity(d).Value
840
            else:
841
                thick = FreeCAD.Units.Quantity(d,FreeCAD.Units.Length).Value
842
            th += abs(thick)
843
            if not thick:
844
                suffix = " ("+translate("Arch","depends on the object")+")"
845
        val = FreeCAD.Units.Quantity(th,FreeCAD.Units.Length).UserString
846
        self.form.labelTotalThickness.setText(prefix + val + suffix)
847

848
    def accept(self):
849
        # store widths
850
        params.set_param_arch("MultiMaterialColumnWidth0",self.form.tree.columnWidth(0))
851
        params.set_param_arch("MultiMaterialColumnWidth1",self.form.tree.columnWidth(1))
852
        if self.obj:
853
            mats = []
854
            for m in FreeCAD.ActiveDocument.Objects:
855
                if m.isDerivedFrom("App::MaterialObject"):
856
                    mats.append(m)
857
            names = []
858
            materials = []
859
            thicknesses = []
860
            for row in range(self.model.rowCount()):
861
                name = self.model.item(row,0).text()
862
                mat = None
863
                ml = self.model.item(row,1).text()
864
                for m in mats:
865
                    if m.Label == ml:
866
                        mat = m
867
                d = self.model.item(row,2).text()
868
                try:
869
                    d = float(d)
870
                except Exception:
871
                    thick = FreeCAD.Units.Quantity(d).Value
872
                else:
873
                    thick = FreeCAD.Units.Quantity(d,FreeCAD.Units.Length).Value
874
                if round(thick,32) == 0:
875
                    thick = 0.0
876
                if name and mat:
877
                    names.append(name)
878
                    materials.append(mat)
879
                    thicknesses.append(thick)
880
            self.obj.Names = names
881
            self.obj.Materials = materials
882
            self.obj.Thicknesses = thicknesses
883
            if self.form.nameField.text():
884
                self.obj.Label = self.form.nameField.text()
885
        FreeCAD.ActiveDocument.recompute()
886
        FreeCADGui.ActiveDocument.resetEdit()
887
        return True
888

889
    def reject(self):
890
        FreeCADGui.ActiveDocument.resetEdit()
891
        return True
892

893

894

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

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

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

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