Material: MaterialEditor migrate to model/view
This commit is contained in:
@@ -9,6 +9,7 @@ SET(Material_SRCS
|
||||
importFCMat.py
|
||||
MaterialEditor.py
|
||||
materials-editor.ui
|
||||
MatPropDict.xml
|
||||
)
|
||||
SOURCE_GROUP("Module" FILES ${Material_SRCS})
|
||||
|
||||
|
||||
131
src/Mod/Material/MatPropDict.xml
Normal file
131
src/Mod/Material/MatPropDict.xml
Normal 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>
|
||||
@@ -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__':
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user