Material: MaterialEditor migrate to model/view

This commit is contained in:
caceres
2018-07-29 19:56:32 +01:00
committed by Yorik van Havre
parent 65c06fce5c
commit 7be816033a
6 changed files with 594 additions and 275 deletions

View File

@@ -9,6 +9,7 @@ SET(Material_SRCS
importFCMat.py
MaterialEditor.py
materials-editor.ui
MatPropDict.xml
)
SOURCE_GROUP("Module" FILES ${Material_SRCS})

View File

@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<MatPropDict>
<Group Name="Meta">
<Property Name="CardName" Type="String">
</Property>
<Property Name="AuthorAndLicense" Type="String">
</Property>
<Property Name="Source" Type="String">
</Property>
</Group>
<Group Name="General">
<Property Name="Name" Type="String">
</Property>
<Property Name="Father" Type="String">
</Property>
<Property Name="Description" Type="String">
</Property>
<Property Name="Density" Type="Quantity" Units="(-3, 1, 0, 0, 0, 0, 0, 0)">
</Property>
<Property Name="Vendor" Type="String">
</Property>
<Property Name="ProductURL" Type="URL">
</Property>
<Property Name="SpecificPrice" Type="Float">
</Property>
</Group>
<Group Name="Mechanical">
<Property Name="YoungsModulus" Type="Quantity" Units="(-1, 1, -2, 0, 0, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Young%27s_modulus</Reference>
</Property>
<Property Name="PoissonRatio" Type="Float">
<Reference>https://en.wikipedia.org/wiki/Poisson%27s_ratio</Reference>
</Property>
<Property Name="UltimateTensileStrength" Type="Quantity" Units="(-1, 1, -2, 0, 0, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Ultimate_tensile_strength</Reference>
</Property>
<Property Name="CompressiveStrength" Type="Quantity" Units="(-1, 1, -2, 0, 0, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Compressive_strength</Reference>
</Property>
<Property Name="YieldStrength" Type="Quantity" Units="(-1, 1, -2, 0, 0, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Yield_Strength</Reference>
</Property>
<Property Name="UltimateStrain" Type="Quantity" Units="(-1, 1, -2, 0, 0, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Ultimate_tensile_strength</Reference>
</Property>
<Property Name="FractureToughness" Type="Quantity" Units="(-1, 1, -2, 0, 0, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Fracture_toughness</Reference>
</Property>
<Property Name="AngleOfFriction" Type="Quantity" Units="(0, 0, 0, 0, 0, 0, 0, 1)">
<Reference>https://en.wikipedia.org/wiki/Friction#Angle_of_friction</Reference>
<Reference>https://en.m.wikipedia.org/wiki/Mohr%E2%80%93Coulomb_theory</Reference>
</Property>
</Group>
<Group Name="Thermal">
<Property Name="ThermalConductivity" Type="Quantity" Units="(1, 1, -3, 0, -1, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Thermal_conductivity</Reference>
</Property>
<Property Name="ThermalExpansionCoefficient" Type="Quantity" Units="(0, 0, 0, 0, -1, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Volumetric_thermal_expansion_coefficient</Reference>
</Property>
<Property Name="SpecificHeat" Type="Quantity" Units="(2, 1, -2, 0, -1, 0, 0, 0)">
<Reference>https://en.wikipedia.org/wiki/Heat_capacity</Reference>
</Property>
</Group>
<Group Name="Architectural">
<Property Name="Model" Type="String">
</Property>
<Property Name="ExecutionInstructions" Type="String">
</Property>
<Property Name="FireResistanceClass" Type="String">
</Property>
<Property Name="StandardCode" Type="String">
</Property>
<Property Name="SoundTransmissionClass" Type="String">
</Property>
<Property Name="Color" Type="Color">
</Property>
<Property Name="Finish" Type="String">
</Property>
<Property Name="UnitsPerQuantity" Type="Float">
</Property>
<Property Name="EnvironmentalEfficiencyClass" Type="String">
</Property>
</Group>
<Group Name="Rendering">
<Property Name="DiffuseColor" Type="Color">
</Property>
<Property Name="AmbientColor" Type="Color">
</Property>
<Property Name="SpecularColor" Type="Color">
</Property>
<Property Name="Shininess" Type="Float">
</Property>
<Property Name="EmissiveColor" Type="Color">
</Property>
<Property Name="Transparency" Type="Float">
</Property>
<Property Name="VertexShader" Type="String">
</Property>
<Property Name="FragmentShader" Type="String">
</Property>
<Property Name="TexturePath" Type="File">
</Property>
<Property Name="TextureScaling" Type="Float">
</Property>
</Group>
<Group Name="Vector rendering">
<Property Name="ViewColor" Type="Color">
</Property>
<Property Name="ViewFillPattern" Type="Boolean">
</Property>
<Property Name="SectionFillPattern" Type="File">
</Property>
<Property Name="ViewLinewidth" Type="Quantity" Units="(1, 0, 0, 0, 0, 0, 0, 0)">
</Property>
<Property Name="SectionLinewidth" Type="Quantity" Units="(1, 0, 0, 0, 0, 0, 0, 0)">
</Property>
</Group>
<Group Name="User defined">
</Group>
</MatPropDict>

View File

@@ -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__':

View File

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

View File

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

View File

@@ -143,44 +143,7 @@
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QTreeWidget" name="Editor">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>300</height>
</size>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="columnCount">
<number>2</number>
</property>
<attribute name="headerVisible">
<bool>true</bool>
</attribute>
<attribute name="headerDefaultSectionSize">
<number>150</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Property</string>
</property>
</column>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
<widget class="QTreeView" name="treeView">
</widget>
</item>
</layout>