diff --git a/src/Mod/Material/CMakeLists.txt b/src/Mod/Material/CMakeLists.txt index 4691095406..7b34903d94 100644 --- a/src/Mod/Material/CMakeLists.txt +++ b/src/Mod/Material/CMakeLists.txt @@ -9,6 +9,7 @@ SET(Material_SRCS importFCMat.py MaterialEditor.py materials-editor.ui + MatPropDict.xml ) SOURCE_GROUP("Module" FILES ${Material_SRCS}) diff --git a/src/Mod/Material/MatPropDict.xml b/src/Mod/Material/MatPropDict.xml new file mode 100644 index 0000000000..6da8438595 --- /dev/null +++ b/src/Mod/Material/MatPropDict.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + https://en.wikipedia.org/wiki/Young%27s_modulus + + + https://en.wikipedia.org/wiki/Poisson%27s_ratio + + + https://en.wikipedia.org/wiki/Ultimate_tensile_strength + + + https://en.wikipedia.org/wiki/Compressive_strength + + + https://en.wikipedia.org/wiki/Yield_Strength + + + https://en.wikipedia.org/wiki/Ultimate_tensile_strength + + + https://en.wikipedia.org/wiki/Fracture_toughness + + + https://en.wikipedia.org/wiki/Friction#Angle_of_friction + https://en.m.wikipedia.org/wiki/Mohr%E2%80%93Coulomb_theory + + + + + + https://en.wikipedia.org/wiki/Thermal_conductivity + + + https://en.wikipedia.org/wiki/Volumetric_thermal_expansion_coefficient + + + https://en.wikipedia.org/wiki/Heat_capacity + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mod/Material/Material.py b/src/Mod/Material/Material.py index f712213993..98b33f99fd 100644 --- a/src/Mod/Material/Material.py +++ b/src/Mod/Material/Material.py @@ -94,87 +94,31 @@ def exportFCMat(fileName, matDict): configfile.write(Preamble) Config.write(configfile) - def getMaterialAttributeStructure(withSpaces=None): + + '''''' + # material properties - # see the following resources in the FreeCAD wiki for more information about the material specific properties: + # see the following resources in the FreeCAD wiki for more informations about the material specific properties: # https://www.freecadweb.org/wiki/Material_data_model # https://www.freecadweb.org/wiki/Material - materialPropertyGroups = ( - ("Meta", ( - "CardName", - "AuthorAndLicense", - "Source" - )), - ("General", ( - "Name", - "Father", - "Description", - "Density", - "Vendor", - "ProductURL", - "SpecificPrice" - )), - ("Mechanical", ( - "YoungsModulus", # https://en.wikipedia.org/wiki/Young%27s_modulus - "PoissonRatio", # https://en.wikipedia.org/wiki/Poisson%27s_ratio - "UltimateTensileStrength", # https://en.wikipedia.org/wiki/Ultimate_tensile_strength - "CompressiveStrength", # https://en.wikipedia.org/wiki/Compressive_strength - "YieldStrength", # https://en.wikipedia.org/wiki/Yield_Strength - "UltimateStrain", # https://en.wikipedia.org/wiki/Ultimate_tensile_strength - "FractureToughness", # https://en.wikipedia.org/wiki/Fracture_toughness - "AngleOfFriction" # https://en.wikipedia.org/wiki/Friction#Angle_of_friction and https://en.m.wikipedia.org/wiki/Mohr%E2%80%93Coulomb_theory - )), - ("Thermal", ( - "ThermalConductivity", # https://en.wikipedia.org/wiki/Thermal_conductivity - "ThermalExpansionCoefficient", # https://en.wikipedia.org/wiki/Volumetric_thermal_expansion_coefficient - "SpecificHeat" # https://en.wikipedia.org/wiki/Heat_capacity - )), - ("Architectural", ( - "Model", - "ExecutionInstructions", - "FireResistanceClass", - "StandardCode", - "SoundTransmissionClass", - "Color", - "Finish", - "UnitsPerQuantity", - "EnvironmentalEfficiencyClass" - )), - ("Rendering", ( - "DiffuseColor", - "AmbientColor", - "SpecularColor", - "Shininess", - "EmissiveColor", - "Transparency", - "VertexShader", - "FragmentShader", - "TexturePath", - "TextureScaling" - )), - ("Vector rendering", ( - "ViewColor", - "ViewFillPattern", - "SectionFillPattern", - "ViewLinewidth", - "SectionLinewidth" - )), - ("User defined", ( - )) - ) + + import os + import xml.etree.ElementTree as ElementTree + + infile = os.path.dirname(__file__) + os.sep + "MatPropDict.xml" + tree = ElementTree.parse(infile) + if withSpaces: # on attributes, add a space before a capital letter, will be used for better display in the ui import re - newMatProp = [] - for group in materialPropertyGroups: - newAttr = [] - for attr in group[1]: - newAttr.append(re.sub(r"(\w)([A-Z])", r"\1 \2", attr)) - newMatProp.append([group[0], newAttr]) - materialPropertyGroups = newMatProp - # print(materialPropertyGroups) - return materialPropertyGroups + root = tree.getroot() + for group in root.getchildren(): + for proper in group.getchildren(): + proper.set('Name', re.sub(r"(\w)([A-Z]+)", r"\1 \2", + proper.attrib['Name'])) + + return tree if __name__ == '__main__': diff --git a/src/Mod/Material/MaterialEditor.py b/src/Mod/Material/MaterialEditor.py index ce2a8f2271..33a5d34c72 100644 --- a/src/Mod/Material/MaterialEditor.py +++ b/src/Mod/Material/MaterialEditor.py @@ -24,6 +24,8 @@ from __future__ import print_function import FreeCAD import FreeCADGui +from Units import Unit +from Units import Quantity from Material import getMaterialAttributeStructure import os from PySide import QtCore, QtGui @@ -41,42 +43,54 @@ __url__ = "http://www.freecadweb.org" class MaterialEditor: def __init__(self, obj=None, prop=None, material=None): - """Initializes, optionally with an object name and a material property name to edit, or directly - with a material dictionary.""" + + """Initializes, optionally with an object name and a material property + name to edit, or directly with a material dictionary.""" + self.obj = obj self.prop = prop self.material = material self.customprops = [] - # load the UI file from the same directory as this script - self.widget = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + os.sep + "materials-editor.ui") - # additional UI fixes and tweaks - self.widget.ButtonURL.setIcon(QtGui.QIcon(":/icons/internet-web-browser.svg")) - self.widget.ButtonDeleteProperty.setEnabled(False) - self.widget.standardButtons.button(QtGui.QDialogButtonBox.Ok).setAutoDefault(False) - self.widget.standardButtons.button(QtGui.QDialogButtonBox.Cancel).setAutoDefault(False) - self.updateCards() - self.widget.Editor.header().resizeSection(0, 200) - self.widget.Editor.expandAll() - self.widget.Editor.setFocus() - # TODO allow to enter a custom property by pressing Enter in the lineedit (currently closes the dialog) - self.widget.Editor.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) - QtCore.QObject.connect(self.widget.ComboMaterial, QtCore.SIGNAL("currentIndexChanged(QString)"), self.updateContents) - QtCore.QObject.connect(self.widget.ButtonURL, QtCore.SIGNAL("clicked()"), self.openProductURL) - QtCore.QObject.connect(self.widget.standardButtons, QtCore.SIGNAL("accepted()"), self.accept) - QtCore.QObject.connect(self.widget.standardButtons, QtCore.SIGNAL("rejected()"), self.reject) - QtCore.QObject.connect(self.widget.ButtonAddProperty, QtCore.SIGNAL("clicked()"), self.addCustomProperty) - QtCore.QObject.connect(self.widget.EditProperty, QtCore.SIGNAL("returnPressed()"), self.addCustomProperty) - QtCore.QObject.connect(self.widget.ButtonDeleteProperty, QtCore.SIGNAL("clicked()"), self.deleteCustomProperty) - QtCore.QObject.connect(self.widget.Editor, QtCore.SIGNAL("itemDoubleClicked(QTreeWidgetItem*,int)"), self.itemClicked) - QtCore.QObject.connect(self.widget.Editor, QtCore.SIGNAL("itemChanged(QTreeWidgetItem*,int)"), self.itemChanged) - QtCore.QObject.connect(self.widget.Editor, QtCore.SIGNAL("currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)"), self.checkDeletable) - QtCore.QObject.connect(self.widget.ButtonOpen, QtCore.SIGNAL("clicked()"), self.openfile) - QtCore.QObject.connect(self.widget.ButtonSave, QtCore.SIGNAL("clicked()"), self.savefile) + self.internalprops = [] + self.groups = [] - # add material properties (the keys) to the editor - for group in getMaterialAttributeStructure(True): # get the mat file structure from material module, use Spaces for better ui - # print(group) - self.addPropertiesToGroup(group) + # load the UI file from the same directory as this script + self.widget =\ + FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + + os.sep + "materials-editor.ui") + + # additional UI fixes and tweaks + widget = self.widget + buttonURL = widget.ButtonURL + buttonDeleteProperty = widget.ButtonDeleteProperty + buttonAddProperty = widget.ButtonAddProperty + standardButtons = widget.standardButtons + buttonOpen = widget.ButtonOpen + buttonSave = widget.ButtonSave + comboMaterial = widget.ComboMaterial + treeView = widget.treeView + + buttonURL.setIcon(QtGui.QIcon(":/icons/internet-web-browser.svg")) + buttonDeleteProperty.setEnabled(False) + standardButtons.button(QtGui.QDialogButtonBox.Ok).setAutoDefault(False) + standardButtons.button(QtGui.QDialogButtonBox.Cancel).setAutoDefault(False) + self.updateCards() + # TODO allow to enter a custom property by pressing Enter in the lineedit (currently closes the dialog) + + standardButtons.rejected.connect(self.reject) + standardButtons.accepted.connect(self.accept) + buttonOpen.clicked.connect(self.openfile) + buttonSave.clicked.connect(self.savefile) + buttonURL.clicked.connect(self.openProductURL) + comboMaterial.currentIndexChanged[str].connect(self.updateContents) + buttonAddProperty.clicked.connect(self.addCustomProperty) + buttonDeleteProperty.clicked.connect(self.deleteCustomProperty) + treeView.clicked.connect(self.checkDeletable) + + model = QtGui.QStandardItemModel() + treeView.setModel(model) + treeView.setUniformRowHeights(True) + treeView.setItemDelegate(MaterialsDelegate()) # update the editor with the contents of the property, if we have one d = None @@ -84,29 +98,104 @@ class MaterialEditor: d = FreeCAD.ActiveDocument.getObject(self.obj).getPropertyByName(self.prop) elif self.material: d = self.material + + self.implementModel() if d: self.updateContents(d) - def addPropertiesToGroup(self, propertygroup=None): - "Adds property to a known group in Tree widges" - if propertygroup: - groupname = propertygroup[0] - groupproperties = propertygroup[1] - else: - return + def implementModel(self): - # parent - self.widget.Editor.addTopLevelItem(QtGui.QTreeWidgetItem([groupname, ])) - # how to expand it ? + '''implements the model with the material attribute structure.''' - # childs - for key in groupproperties: - if not self.widget.Editor.findItems(key, QtCore.Qt.MatchRecursive, 0): - top = self.widget.Editor.findItems(translate("Material", groupname), QtCore.Qt.MatchExactly, 0) - if top: - i = QtGui.QTreeWidgetItem(top[0]) - i.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) - i.setText(0, key) + widget = self.widget + treeView = widget.treeView + model = treeView.model() + model.setHorizontalHeaderLabels(["Property", "Value", + "Type", "Units"]) + + treeView.setColumnWidth(0, 250) + treeView.setColumnWidth(1, 250) + treeView.setColumnHidden(2, True) + treeView.setColumnHidden(3, True) + + tree = getMaterialAttributeStructure(True) + MatPropDict = tree.getroot() + + for group in MatPropDict.getchildren(): + gg = group.attrib['Name'] + top = QtGui.QStandardItem(gg) + model.appendRow([top]) + self.groups.append(gg) + + for proper in group.getchildren(): + properDict = proper.attrib + + pp = properDict['Name'] + item = QtGui.QStandardItem(pp) + self.internalprops.append(pp) + + it = QtGui.QStandardItem() + + tt = properDict['Type'] + itType = QtGui.QStandardItem(tt) + + try: + uu = properDict['Units'] + itUnit = QtGui.QStandardItem(uu) + except KeyError: + itUnit = QtGui.QStandardItem() + + top.appendRow([item, it, itType, itUnit]) + + top.sortChildren(0) + + treeView.expandAll() + + def updateContents(self, data): + + '''updates the contents of the editor with the given data, can be: + - the name of a card, if material is changed in editors combo box + - a dictionary, if the editor was called with data.''' + + if isinstance(data, dict): + + model = self.widget.treeView.model() + root = model.invisibleRootItem() + for gg in range(root.rowCount() - 1): + group = root.child(gg, 0) + for pp in range(group.rowCount()): + item = group.child(pp, 0) + it = group.child(pp, 1) + kk = self.collapseKey(item.text()) + + try: + value = data[kk] + it.setText(value) + del data[kk] + except KeyError: + it.setText("") + + userGroup = root.child(gg + 1, 0) + userGroup.setRowCount(0) + self.customprops = [] + + for k, i in data.items(): + k = self.expandKey(k) + item = QtGui.QStandardItem(k) + it = QtGui.QStandardItem(i) + userGroup.appendRow([item, it]) + self.customprops.append(k) + + elif isinstance(data, unicode): + + k = str(data) + if k: + if k in self.cards: + + import importFCMat + d = importFCMat.read(self.cards[k]) + if d: + self.updateContents(d) def getMaterialResources(self): self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Resources") @@ -145,11 +234,10 @@ class MaterialEditor: self.getMaterialResources() self.cards = {} for p in self.resources: - if os.path.exists(p): - for f in os.listdir(p): - b, e = os.path.splitext(f) - if e.upper() == ".FCMAT": - self.cards[b] = p + os.sep + f + for f in os.listdir(p): + b, e = os.path.splitext(f) + if e.upper() == ".FCMAT": + self.cards[b] = p + os.sep + f # self.outputCards() if self.cards: self.widget.ComboMaterial.clear() @@ -157,46 +245,26 @@ class MaterialEditor: for k, i in self.cards.items(): self.widget.ComboMaterial.addItem(k) - def updateContents(self, data): - '''updates the contents of the editor with the given data, can be: - - the name of a card, if material is changed in editors combo box - - a dictionary, if the editor was called with data''' - # print type(data) - if isinstance(data, dict): - self.clearEditor() - for k, i in data.items(): - k = self.expandKey(k) - # most material dict keys are added with addPropertiesToGroup, see tuple with all these properties at module end - slot = self.widget.Editor.findItems(k, QtCore.Qt.MatchRecursive, 0) - if len(slot) == 1: - slot = slot[0] - slot.setText(1, i) - else: - self.addCustomProperty(k, i) - elif isinstance(data, unicode): - k = str(data) - if k: - if k in self.cards: - import importFCMat - d = importFCMat.read(self.cards[k]) - if d: - self.updateContents(d) - def openProductURL(self): - "opens the contents of the ProductURL field in an external browser" - url = str(self.widget.Editor.findItems(translate("Material", "Product URL"), QtCore.Qt.MatchRecursive, 0)[0].text(1)) + "opens the contents of the ProductURL field in an external browser." + + model = self.widget.treeView.model() + item = model.findItems(translate("Material", "Product URL"), + QtCore.Qt.MatchRecursive, 0)[0] + group = item.parent() + it = group.child(item.row(), 1) + url = it.text() if url: QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode)) def accept(self): - "if we are editing a property, set the property values" - if self.prop and self.obj: - d = self.getDict() - o = FreeCAD.ActiveDocument.getObject(self.obj) - setattr(o, self.prop, d) + "" + QtGui.QDialog.accept(self.widget) def reject(self): + "" + QtGui.QDialog.reject(self.widget) def expandKey(self, key): @@ -219,94 +287,121 @@ class MaterialEditor: nk += l return nk - def clearEditor(self): - "Clears the contents of the editor" - for i1 in range(self.widget.Editor.topLevelItemCount()): - w = self.widget.Editor.topLevelItem(i1) - for i2 in range(w.childCount()): - c = w.child(i2) - c.setText(1, "") - for k in self.customprops: - self.deleteCustomProperty(k) - def addCustomProperty(self, key=None, value=None): - "Adds a custom property to the editor, optionally with a value" + "Adds a custom property to the editor, optionally with a value." + if not key: - key = str(self.widget.EditProperty.text()) + key = self.widget.EditProperty.text() + if key: - if key not in self.customprops: - if not self.widget.Editor.findItems(key, QtCore.Qt.MatchRecursive, 0): - top = self.widget.Editor.findItems(translate("Material", "User defined"), QtCore.Qt.MatchExactly, 0) - if top: - i = QtGui.QTreeWidgetItem(top[0]) - i.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) - i.setText(0, key) - self.customprops.append(key) - self.widget.EditProperty.setText("") - if value: - i.setText(1, value) + model = self.widget.treeView.model() + item = model.findItems(key, QtCore.Qt.MatchRecursive, 0) + if not item: + + top = model.findItems(translate("Material", "User defined"), + QtCore.Qt.MatchExactly, 0)[0] + item = QtGui.QStandardItem(key) + it = QtGui.QStandardItem(value) + top.appendRow([item, it]) + self.customprops.append(key) def deleteCustomProperty(self, key=None): - "Deletes a custom property from the editor" + + '''Deletes a custom property from the editor, + or deletes the value of an internal property.''' + + widget = self.widget + treeView = widget.treeView + model = treeView.model() + buttonDeleteProperty = widget.ButtonDeleteProperty + if not key: - key = str(self.widget.Editor.currentItem().text(0)) + + index = treeView.selectedIndexes()[0] + item = model.itemFromIndex(index) + key = item.text() + if key: - if key in self.customprops: - i = self.widget.Editor.findItems(key, QtCore.Qt.MatchRecursive, 0) - if i: - top = self.widget.Editor.findItems(translate("Material", "User defined"), QtCore.Qt.MatchExactly, 0) - if top: - top = top[0] - ii = top.indexOfChild(i[0]) - if ii >= 0: - top.takeChild(ii) - self.customprops.remove(key) + item = model.findItems(key, QtCore.Qt.MatchRecursive, 0) + if item: - def itemClicked(self, item, column): - "Edits an item if it is not in the first column" - if column > 0: - self.widget.Editor.editItem(item, column) + index = model.indexFromItem(item[0]) + topIndex = index.parent() + top = model.itemFromIndex(topIndex) + row = item[0].row() - def itemChanged(self, item, column): - "Handles text changes" - if item.text(0) == "Section Fill Pattern": - if column == 1: - self.setTexture(item.text(1)) + if key in self.customprops: + top.takeRow(row) + self.customprops.remove(key) + buttonDeleteProperty.setProperty("text", "Delete property") + + elif key in self.internalprops: + it = top.child(row, 1) + it.setText("") + buttonDeleteProperty.setProperty("text", "Delete value") + + buttonDeleteProperty.setEnabled(False) + + def checkDeletable(self, index): + + '''Checks if the current item is a custom or an internal property, + and enable the delete property or delete value button.''' + + widget = self.widget + buttonDeleteProperty = widget.ButtonDeleteProperty + treeView = widget.treeView + model = treeView.model() + ind = treeView.selectedIndexes()[0] + item = model.itemFromIndex(ind) + text = item.text() + + if text in self.customprops: + buttonDeleteProperty.setEnabled(True) + buttonDeleteProperty.setProperty("text", "Delete property") + + elif text in self.internalprops: + indParent = ind.parent() + group = model.itemFromIndex(indParent) + row = item.row() + it = group.child(row, 1) + buttonDeleteProperty.setProperty("text", "Delete value") + if it.text(): + buttonDeleteProperty.setEnabled(True) + else: + buttonDeleteProperty.setEnabled(False) - def checkDeletable(self, current, previous): - "Checks if the current item is a custom property, if yes enable the delete button" - if str(current.text(0)) in self.customprops: - self.widget.ButtonDeleteProperty.setEnabled(True) else: - self.widget.ButtonDeleteProperty.setEnabled(False) + buttonDeleteProperty.setEnabled(False) + buttonDeleteProperty.setProperty("text", "Delete property") def getDict(self): - "returns a dictionary from the contents of the editor" + "returns a dictionary from the contents of the editor." + + model = self.widget.treeView.model() + root = model.invisibleRootItem() + d = {} - for i1 in range(self.widget.Editor.topLevelItemCount()): - w = self.widget.Editor.topLevelItem(i1) - for i2 in range(w.childCount()): - c = w.child(i2) - # TODO the following should be translated back to english, since text(0) could be translated - matkey = self.collapseKey(str(c.text(0))) - matvalue = unicode(c.text(1)) + for gg in range(root.rowCount()): + group = root.child(gg) + for row in range(group.rowCount()): + kk = group.child(row, 0).text() + ii = group.child(row, 1).text() + + # TODO the following should be translated back to english,since text(0) could be translated + matkey = self.collapseKey(str(kk)) + matvalue = unicode(ii) if matvalue or (matkey == 'Name'): # use only keys which are not empty and the name even if empty d[matkey] = matvalue # self.outputDict(d) return d - # ??? after return ??? - if d: - self.updateContents(d) - self.widget.Editor.topLevelItem(6).child(4).setToolTip(1, self.getPatternsList()) - def outputDict(self, d): print('MaterialEditor dictionary') for param in d: print(' ' + param + ' : ' + d[param]) - def setTexture(self, pattern): + '''def setTexture(self, pattern): "displays a texture preview if needed" self.widget.PreviewVector.hide() if pattern: @@ -318,28 +413,36 @@ class MaterialEditor: pattern = DrawingPatterns.buildFileSwatch(pattern, size=96, png=True) if pattern: self.widget.PreviewVector.setPixmap(QtGui.QPixmap(pattern)) - self.widget.PreviewVector.show() + self.widget.PreviewVector.show()''' def openfile(self): "Opens a FCMat file" filetuple = QtGui.QFileDialog.getOpenFileName(QtGui.QApplication.activeWindow(), 'Open FreeCAD Material file', '*.FCMat') filename = filetuple[0] # a tuple of two empty strings returns True, so use the filename directly if filename: - self.clearEditor() import importFCMat d = importFCMat.read(filename) if d: self.updateContents(d) def savefile(self): - "Saves a FCMat file" - name = self.widget.Editor.findItems(translate("Material", "Name"), QtCore.Qt.MatchRecursive, 0)[0].text(1) + "Saves a FCMat file." + + model = self.widget.treeView.model() + item = model.findItems(translate("Material", "Name"), + QtCore.Qt.MatchRecursive, 0)[0] + group = item.parent() + it = group.child(item.row(), 1) + name = it.text() if sys.version_info.major < 3: if isinstance(name,unicode): name = name.encode("utf8") if not name: name = "Material" - filetuple = QtGui.QFileDialog.getSaveFileName(QtGui.QApplication.activeWindow(), 'Save FreeCAD Material file', name + '.FCMat') + filetuple =\ + QtGui.QFileDialog.getSaveFileName(QtGui.QApplication.activeWindow(), + 'Save FreeCAD Material file', + name + '.FCMat') filename = filetuple[0] # a tuple of two empty strings returns True, so use the filename directly if filename: d = self.getDict() @@ -347,6 +450,7 @@ class MaterialEditor: if d: import importFCMat importFCMat.write(filename, d) + self.updateCards() def show(self): return self.widget.show() @@ -355,6 +459,179 @@ class MaterialEditor: return self.widget.exec_() +class MaterialsDelegate(QtGui.QStyledItemDelegate): + + '''provides display and editing facilities for data items from a model.''' + + def __init__(self): + "" + + super(MaterialsDelegate, self).__init__() + + def createEditor(self, parent, option, index): + + '''returns the widget used to change data from the model.''' + + model = index.model() + column = index.column() + + item = model.itemFromIndex(index) + group = item.parent() + if not group: + return + + if column == 1: + + row = index.row() + TT = group.child(row, 2) + + if TT: + Type = TT.text() + UU = group.child(row, 3) + if UU: + Units = UU.text() + else: + Units = None + + else: + Type = "String" + Units = None + + VV = group.child(row, 1) + Value = VV.text() + + editor = matProperWidget(parent, Type, Units, Value) + + elif column == 0: + + if group.text() == "User defined": + editor = matProperWidget(parent) + + else: + return + + else: + + return + + return editor + + def setEditorData(self, editor, index): + + '''provides the widget with data to manipulate.''' + + Type = editor.property('Type') + model = index.model() + item = model.itemFromIndex(index) + + if Type == "Color": + + color = editor.property('color') + color = color.getRgb() + item.setText(str(color)) + + elif Type == "File": + + lineEdit = editor.children()[1] + item.setText(lineEdit.text()) + + else: + + super(MaterialsDelegate, self).setEditorData(editor, index) + + +ui = FreeCADGui.UiLoader() + + +def matProperWidget(parent=None, Type="String", Units=None, Value=None, + minimum=None, maximum=None, stepsize=None, precision=None): + + '''customs widgets for the material stuff.''' + + if Type == "String": + + widget = ui.createWidget("Gui::PrefLineEdit") + + elif Type == "URL": + + widget = ui.createWidget("Gui::PrefLineEdit") + + elif Type == "File": + + widget = ui.createWidget("Gui::FileChooser") + if Value: + lineEdit = widget.children()[1] + lineEdit.setText(Value) + + elif Type == "Quantity": + + widget = ui.createWidget("Gui::InputField") + if Units: + vv = string2tuple(Units) + unit = Unit(vv[0], vv[1], vv[2], vv[3], + vv[4], vv[5], vv[6], vv[7]) + quantity = Quantity(1, unit) + widget.setProperty('unit', quantity.getUserPreferred()[2]) + + elif Type == "Integer": + + widget = ui.createWidget("Gui::UIntSpinBox") + + elif Type == "Float": + + widget = ui.createWidget("Gui::PrefDoubleSpinBox") + + elif Type == "Enumerator": + + widget = ui.createWidget("Gui::PrefComboBox") + + elif Type == "Boolean": + + widget = ui.createWidget("Gui::PrefComboBox") + widget.insertItems(0, ['', 'False', 'True']) + + elif Type == "Vector": + + widget = ui.createWidget("Gui::PrefLineEdit") + + elif Type == "Color": + + widget = ui.createWidget("Gui::PrefColorButton") + if Value: + value = string2tuple(Value) + color = QtGui.QColor() + color.setRgb(value[0], value[1], value[2], value[3]) + widget.setProperty('color', color) + + else: + + widget = QtGui.QLineEdit() + + if minimum is not None: + widget.setProperty('minimum', minimum) + if maximum is not None: + widget.setProperty('maximum', maximum) + if stepsize is not None: + widget.setProperty('stepsize', stepsize) + if precision is not None: + widget.setProperty('precision', precision) + + widget.setProperty('Type', Type) + + widget.setParent(parent) + + return widget + + +def string2tuple(string): + "provisionally" + value = string[1:-1] + value = value.split(',') + value = [int(v) for v in value] + value = tuple(value) + return value + + def translate(context, text): "translates text" return text # TODO use Qt translation mechanism here diff --git a/src/Mod/Material/importFCMat.py b/src/Mod/Material/importFCMat.py index f139ec56c7..6fcbccf338 100644 --- a/src/Mod/Material/importFCMat.py +++ b/src/Mod/Material/importFCMat.py @@ -22,8 +22,7 @@ import FreeCAD -# import Material -from Material import getMaterialAttributeStructure +import Material import os import sys if sys.version_info.major >= 3: @@ -105,15 +104,19 @@ def write(filename, dictionary): "writes the given dictionary to the given file" # sort the data into sections contents = [] - for key in getMaterialAttributeStructure(): # get the mat file structure from material module - contents.append({"keyname": key[0]}) - if key[0] == "Meta": + tree = Material.getMaterialAttributeStructure() + MatPropDict = tree.getroot() + for group in MatPropDict.getchildren(): + groupName = group.attrib['Name'] + contents.append({"keyname": groupName}) + if groupName == "Meta": header = contents[-1] - elif key[0] == "User defined": + elif groupName == "User defined": user = contents[-1] - for p in key[1]: - contents[-1][p] = "" - for k, i in dictionary.items(): + for proper in group.getchildren(): + properName = proper.attrib['Name'] + contents[-1][properName] = "" + for k, i in dictionary.iteritems(): found = False for group in contents: if not found: diff --git a/src/Mod/Material/materials-editor.ui b/src/Mod/Material/materials-editor.ui index 4ef6dde150..1b2058ca47 100644 --- a/src/Mod/Material/materials-editor.ui +++ b/src/Mod/Material/materials-editor.ui @@ -143,44 +143,7 @@ QLayout::SetMaximumSize - - - - 0 - 0 - - - - - 0 - 300 - - - - true - - - 2 - - - true - - - 150 - - - true - - - - Property - - - - - Value - - +