diff --git a/src/Mod/Fem/Gui/Resources/ui/Material.ui b/src/Mod/Fem/Gui/Resources/ui/Material.ui
index 7efe5269b8..69514b5ef5 100755
--- a/src/Mod/Fem/Gui/Resources/ui/Material.ui
+++ b/src/Mod/Fem/Gui/Resources/ui/Material.ui
@@ -15,122 +15,7 @@
-
-
-
-
- 16777215
- 1677215
-
-
-
- Material
-
-
-
-
-
-
-
-
-
- Category
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- Material card
-
-
-
- -
-
-
-
-
- choose...
-
-
-
-
- -
-
-
- Material name
-
-
-
- -
-
-
- TextLabel
-
-
-
-
-
- -
-
-
- Material Description
-
-
- true
-
-
-
-
-
-
- -
-
-
-
- 16777215
- 1677215
-
-
-
- Editing material
-
-
-
-
-
-
-
-
-
- Use FreeCAD material editor
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::RightToLeft
-
-
- Use this task panel
-
-
- false
-
-
-
-
-
-
-
+
-
@@ -590,18 +475,21 @@
- -
-
-
- Qt::Vertical
+
-
+
+
+
+ 0
+ 0
+
-
-
- 20
- 40
-
+
+ Use this task panel
-
+
+ false
+
+
@@ -611,6 +499,11 @@
QLineEdit
+
+ MatGui::MaterialTreeWidget
+ QWidget
+ Mod/Material/Gui/MaterialTreeWidget.h
+
diff --git a/src/Mod/Fem/femobjects/material_common.py b/src/Mod/Fem/femobjects/material_common.py
index f230b843cc..10011c7978 100644
--- a/src/Mod/Fem/femobjects/material_common.py
+++ b/src/Mod/Fem/femobjects/material_common.py
@@ -70,6 +70,16 @@ class MaterialCommon(base_fempythonobject.BaseFemPythonObject):
value=["Solid", "Fluid"],
)
)
+ prop.append(
+ _PropHelper(
+ type="App::PropertyString",
+ name="UUID",
+ group="Material",
+ doc="Material UUID",
+ hidden=True,
+ value="",
+ )
+ )
return prop
diff --git a/src/Mod/Fem/femtaskpanels/task_material_common.py b/src/Mod/Fem/femtaskpanels/task_material_common.py
index d2c1afdc94..36a1050520 100644
--- a/src/Mod/Fem/femtaskpanels/task_material_common.py
+++ b/src/Mod/Fem/femtaskpanels/task_material_common.py
@@ -37,6 +37,8 @@ from PySide import QtGui
import FreeCAD
import FreeCADGui
from FreeCAD import Units
+import Materials
+import MatGui
from femguiutils import selection_widgets
from . import base_femtaskpanel
@@ -50,35 +52,25 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
def __init__(self, obj):
super().__init__(obj)
- self.material = self.obj.Material # FreeCAD material dictionary of current material
- self.card_path = ""
- self.materials = {} # { card_path : FreeCAD material dict, ... }
- self.cards = {} # { card_path : card_names, ... }
- self.icons = {} # { card_path : icon_path, ... }
- # mat_card is the FCMat file
- # card_name is the file name of the mat_card
- # card_path is the whole file path of the mat_card
- # material_name is the value of the key name in FreeCAD material dictionary
- # they might not match because of special letters in the material_name
- # which are changed in the card_name to english standard characters
- self.has_transient_mat = False
+ # FreeCAD material dictionary of current material
+ self.material = self.obj.Material
+ self.uuid = self.obj.UUID
+ self.material_manager = Materials.MaterialManager()
# parameter widget
self.parameterWidget = FreeCADGui.PySideUic.loadUi(
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/Material.ui"
)
- # globals
- QtCore.QObject.connect(
- self.parameterWidget.cb_materials, QtCore.SIGNAL("activated(int)"), self.choose_material
- )
+ self.material_tree = MatGui.MaterialTreeWidget(self.parameterWidget.wgt_material_tree)
+ self.material_tree.expanded = False
+ self.material_tree.IncludeEmptyFolders = False
+ self.material_tree.IncludeEmptyLibraries = False
+
QtCore.QObject.connect(
self.parameterWidget.chbu_allow_edit,
QtCore.SIGNAL("clicked()"),
self.toggleInputFieldsReadOnly,
)
- QtCore.QObject.connect(
- self.parameterWidget.pushButton_editMat, QtCore.SIGNAL("clicked()"), self.edit_material
- )
# basic properties must be provided
QtCore.QObject.connect(
self.parameterWidget.input_fd_density,
@@ -123,6 +115,11 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
QtCore.SIGNAL("editingFinished()"),
self.vtec_changed,
)
+ QtCore.QObject.connect(
+ self.parameterWidget.wgt_material_tree,
+ QtCore.SIGNAL("onMaterial(QString)"),
+ self.set_from_editor,
+ )
# init all parameter input files with read only
self.parameterWidget.chbu_allow_edit.setCheckState(QtCore.Qt.CheckState.Unchecked)
@@ -131,8 +128,8 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
# hide some groupBox according to material category
# note: input_fd_vol_expansion_coefficient is currently not used
# it might be used in future for solids
- self.parameterWidget.label_category.setText(self.obj.Category)
if self.obj.Category == "Fluid":
+ self.filter_models(self.obj.Category)
self.parameterWidget.groupBox_mechanical.setVisible(0)
self.parameterWidget.label_vol_expansion_coefficient.setVisible(0)
self.parameterWidget.input_fd_vol_expansion_coefficient.setVisible(0)
@@ -141,43 +138,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
self.parameterWidget.label_vol_expansion_coefficient.setVisible(0)
self.parameterWidget.input_fd_vol_expansion_coefficient.setVisible(0)
- # get all available materials (fill self.materials, self.cards and self.icons)
- from materialtools.cardutils import import_materials as getmats
-
- # Note: import_materials(category="Solid", ...),
- # category default to Solid, but must be given for FluidMaterial to be imported
- self.materials, self.cards, self.icons = getmats(self.obj.Category)
- # fill the material comboboxes with material cards
- self.add_cards_to_combo_box()
-
- # search for exact this mat_card in all known cards, choose the current material
- self.card_path = self.get_material_card(self.material)
- FreeCAD.Console.PrintLog(f"card_path: {self.card_path}\n")
- if not self.card_path:
- # we have not found our material in self.materials dict :-(
- # we're going to add a user-defined temporary material: a document material
- FreeCAD.Console.PrintMessage(
- "Previously used material card can not be found in material directories. "
- "Add document material.\n"
- )
- self.card_path = "_document_material"
- self.materials[self.card_path] = self.material
- self.parameterWidget.cb_materials.addItem(
- QtGui.QIcon(":/icons/help-browser.svg"), self.card_path, self.card_path
- )
- index = self.parameterWidget.cb_materials.findData(self.card_path)
- # fill input fields and set the current material in the cb widget
- self.choose_material(index)
- else:
- # we found our exact material in self.materials dict :-)
- FreeCAD.Console.PrintLog(
- "Previously used material card was found in material directories. "
- "We will use this material.\n"
- )
- index = self.parameterWidget.cb_materials.findData(self.card_path)
- # fill input fields and set the current material in the cb widget
- self.choose_material(index)
-
# geometry selection widget
self.selectionWidget = selection_widgets.GeometryElementsSelection(
obj.References, ["Solid", "Face", "Edge"], False, True
@@ -187,21 +147,21 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
self.form = [self.parameterWidget, self.selectionWidget]
# check references, has to be after initialisation of selectionWidget
+ self.material_tree.UUID = self.get_material_uuid(self.material)
+ self.check_material_keys()
+ self.set_mat_params_in_input_fields(self.material)
+
self.selectionWidget.has_equal_references_shape_types()
# leave task panel ***************************************************************************
def accept(self):
- # print(self.material)
- if self.material == {}: # happens if material editor was canceled
- FreeCAD.Console.PrintError("Empty material dictionary, nothing was changed.\n")
- self.recompute_and_set_back_all()
- return True
if self.selectionWidget.has_equal_references_shape_types():
self.do_not_set_thermal_zeros()
from materialtools.cardutils import check_mat_units as checkunits
if checkunits(self.material) is True:
self.obj.Material = self.material
+ self.obj.UUID = self.uuid
self.obj.References = self.selectionWidget.references
else:
error_message = (
@@ -249,20 +209,39 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
return False
# choose material ****************************************************************************
- def get_material_card(self, material):
- for a_mat in self.materials:
+ def filter_models(self, category):
+ material_filter = Materials.MaterialFilter()
+ models = set(Materials.ModelManager().Models.keys())
+ uuids = Materials.UUIDs()
+ if category == "Fluid":
+ material_filter.RequiredModels = [uuids.Fluid]
+ self.material_tree.setFilter(material_filter)
+
+ def get_material_uuid(self, material):
+ if self.uuid:
+ try:
+ self.material_manager.getMaterial(self.uuid)
+ return self.uuid
+ except:
+ return ""
+
+ if not self.material:
+ return ""
+
+ for a_mat in self.material_manager.Materials:
# check if every item of the current material fits to a known material card
# if all items were found we know it is the right card
# we can hereby not simply perform
# set(self.materials[a_mat].items()) ^ set(material.items())
# because entries are often identical, just appear in the set in a different order
unmatched_item = False
+ a_mat_prop = self.material_manager.getMaterial(a_mat).Properties.items()
for item in material.items():
- if item not in self.materials[a_mat].items():
+ if item not in a_mat_prop:
unmatched_item = True
# often the difference is just a decimal e.g. "120" to "120.0"
# therefore first check if the item name exists
- for a_mat_item in self.materials[a_mat].items():
+ for a_mat_item in a_mat_prop:
if item[0] == a_mat_item[0]:
# now check if we have a number value in a unit
if item[1].split() and not self.isfloat(item[1].split()[0]):
@@ -282,99 +261,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
return a_mat
return ""
- def choose_material(self, index):
- if index < 0:
- return
- self.card_path = self.parameterWidget.cb_materials.itemData(index) # returns whole path
- FreeCAD.Console.PrintMessage(f"Material card chosen:\n {self.card_path}\n")
- self.material = self.materials[self.card_path]
- self.check_material_keys()
- self.set_mat_params_in_input_fields(self.material)
- self.parameterWidget.cb_materials.setCurrentIndex(index) # set after input fields
- gen_mat_desc = ""
- gen_mat_name = ""
- if "Description" in self.material:
- gen_mat_desc = self.material["Description"]
- if "Name" in self.material:
- gen_mat_name = self.material["Name"]
- self.parameterWidget.l_mat_description.setText(gen_mat_desc)
- self.parameterWidget.l_mat_name.setText(gen_mat_name)
- # print("choose_material: done")
-
- def set_transient_material(self):
- self.card_path = "_transient_material"
- self.materials[self.card_path] = self.material # = the current input fields data
- index = self.parameterWidget.cb_materials.findData(self.card_path)
- self.choose_material(index)
-
- def add_transient_material(self):
- self.has_transient_mat = True
- self.card_path = "_transient_material"
- self.parameterWidget.cb_materials.addItem(
- QtGui.QIcon(":/icons/help-browser.svg"), self.card_path, self.card_path
- )
- self.set_transient_material()
-
- # how to edit a material *********************************************************************
- def edit_material(self):
- # opens the material editor to choose a material or edit material params
- import MaterialEditor
-
- if self.card_path not in self.cards:
- FreeCAD.Console.PrintLog(
- "Card path not in cards, material dict will be used to open Material Editor.\n"
- )
- new_material_params = MaterialEditor.editMaterial(
- material=self.material, category=self.obj.Category
- )
- else:
- new_material_params = MaterialEditor.editMaterial(
- card_path=self.card_path, category=self.obj.Category
- )
- # material editor returns the mat_dict only, not a card_path
- # if the material editor was canceled a empty dict will be returned
- # do not change the self.material
- # check if dict is not empty (do not use "is True")
- if new_material_params:
- # check material quantity units
- from materialtools.cardutils import check_mat_units as checkunits
-
- if checkunits(new_material_params) is True:
- self.material = new_material_params
- self.card_path = self.get_material_card(self.material)
- self.check_material_keys()
- self.set_mat_params_in_input_fields(self.material)
- if not self.card_path:
- FreeCAD.Console.PrintMessage(
- "Material card chosen by the material editor "
- "was not found in material directories.\n"
- "Either the card does not exist or some material "
- "parameter where changed in material editor.\n"
- )
- if self.has_transient_mat is False:
- self.add_transient_material()
- else:
- self.set_transient_material()
- else:
- # we found our exact material in self.materials dict :-)
- FreeCAD.Console.PrintLog(
- "Material card chosen by the material editor "
- "was found in material directories. "
- "The found material card will be used.\n"
- )
- index = self.parameterWidget.cb_materials.findData(self.card_path)
- # set the current material in the cb widget
- self.choose_material(index)
- else:
- error_message = (
- "Due to some wrong material quantity units in data passed "
- "by the material editor, the material data was not changed.\n"
- )
- FreeCAD.Console.PrintError(error_message)
- QtGui.QMessageBox.critical(None, "Material data not changed", error_message)
- else:
- FreeCAD.Console.PrintLog("No changes where made by the material editor.\n")
-
def toggleInputFieldsReadOnly(self):
if self.parameterWidget.chbu_allow_edit.isChecked():
self.parameterWidget.input_fd_density.setReadOnly(False)
@@ -575,11 +461,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
else:
material[matProperty] = str(value)
self.material = material
- if self.has_transient_mat is False:
- self.add_transient_material()
- else:
- self.set_transient_material()
- # print(inputfield_text)
# mechanical input fields
def ym_changed(self):
@@ -616,10 +497,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
material = self.material
material["PoissonRatio"] = str(value)
self.material = material
- if self.has_transient_mat is False:
- self.add_transient_material()
- else:
- self.set_transient_material()
# thermal input fields
def tc_changed(self):
@@ -712,29 +589,9 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
q = Units.Quantity(f"{sh_with_new_unit} {sh_new_unit}")
self.parameterWidget.input_fd_specific_heat.setText(q.UserString)
- # fill the combo box with cards **************************************************************
- def add_cards_to_combo_box(self):
- # fill combobox, in combo box the card name is used not the material name
- self.parameterWidget.cb_materials.clear()
-
- mat_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Cards")
- sort_by_resources = mat_prefs.GetBool("SortByResources", False)
-
- card_name_list = [] # [ [card_name, card_path, icon_path], ... ]
-
- if sort_by_resources is True:
- for a_path in sorted(self.materials):
- card_name_list.append([self.cards[a_path], a_path, self.icons[a_path]])
- else:
- card_names_tmp = {}
- for path, name in self.cards.items():
- card_names_tmp[name] = path
- for a_name in sorted(card_names_tmp):
- a_path = card_names_tmp[a_name]
- card_name_list.append([a_name, a_path, self.icons[a_path]])
-
- for mat in card_name_list:
- self.parameterWidget.cb_materials.addItem(QtGui.QIcon(mat[2]), mat[0], mat[1])
- # the whole card path is added to the combo box to make it unique
- # see def choose_material:
- # for assignment of self.card_path the path form the parameterWidget is used
+ def set_from_editor(self, value):
+ mat = self.material_manager.getMaterial(value)
+ self.material = mat.Properties
+ self.uuid = mat.UUID
+ self.check_material_keys()
+ self.set_mat_params_in_input_fields(self.material)