diff --git a/src/Mod/Fem/Gui/DlgSettingsFemMaterial.ui b/src/Mod/Fem/Gui/DlgSettingsFemMaterial.ui
index 7bb12a8e88..59e659f67d 100644
--- a/src/Mod/Fem/Gui/DlgSettingsFemMaterial.ui
+++ b/src/Mod/Fem/Gui/DlgSettingsFemMaterial.ui
@@ -6,7 +6,7 @@
0
0
- 505
+ 519
451
@@ -20,7 +20,7 @@
-
- Material Resources
+ Card resources
-
@@ -126,6 +126,51 @@
+ -
+
+
+ Card sorting and duplicates
+
+
+
-
+
+
-
+
+
+ Delete card duplicates
+
+
+ true
+
+
+ DeleteDuplicates
+
+
+ Mod/Material/Cards
+
+
+
+ -
+
+
+ Sort by resources (opposite would be sort by cards)
+
+
+ true
+
+
+ SortByResources
+
+
+ Mod/Material/Cards
+
+
+
+
+
+
+
+
-
diff --git a/src/Mod/Fem/Gui/DlgSettingsFemMaterialImp.cpp b/src/Mod/Fem/Gui/DlgSettingsFemMaterialImp.cpp
index d2f73c15bb..e6373a55c9 100644
--- a/src/Mod/Fem/Gui/DlgSettingsFemMaterialImp.cpp
+++ b/src/Mod/Fem/Gui/DlgSettingsFemMaterialImp.cpp
@@ -48,6 +48,8 @@ void DlgSettingsFemMaterialImp::saveSettings()
cb_use_mat_from_config_dir->onSave();
cb_use_mat_from_custom_dir->onSave();
fc_custom_mat_dir->onSave();
+ cb_delete_duplicates->onSave();
+ cb_sort_by_resources->onSave();
}
void DlgSettingsFemMaterialImp::loadSettings()
@@ -56,6 +58,8 @@ void DlgSettingsFemMaterialImp::loadSettings()
cb_use_mat_from_config_dir->onRestore();
cb_use_mat_from_custom_dir->onRestore();
fc_custom_mat_dir->onRestore();
+ cb_delete_duplicates->onRestore();
+ cb_sort_by_resources->onRestore();
}
/**
diff --git a/src/Mod/Material/MaterialEditor.py b/src/Mod/Material/MaterialEditor.py
index a1edfe5431..5502c566e7 100644
--- a/src/Mod/Material/MaterialEditor.py
+++ b/src/Mod/Material/MaterialEditor.py
@@ -32,6 +32,7 @@ from PySide import QtCore, QtGui
import FreeCAD
import FreeCADGui
+# is this still needed after the move to card utils???
if sys.version_info.major >= 3:
unicode = str
@@ -50,6 +51,9 @@ class MaterialEditor:
self.internalprops = []
self.groups = []
self.directory = FreeCAD.getResourceDir() + "Mod/Material"
+ self.materials = {}
+ self.cards = {}
+ self.icons = {}
# load the UI file from the same directory as this script
self.widget = FreeCADGui.PySideUic.loadUi(
@@ -75,7 +79,7 @@ class MaterialEditor:
buttonDeleteProperty.setEnabled(False)
standardButtons.button(QtGui.QDialogButtonBox.Ok).setAutoDefault(False)
standardButtons.button(QtGui.QDialogButtonBox.Cancel).setAutoDefault(False)
- self.updateCards()
+ self.updateCardsInCombo()
# TODO allow to enter a custom property by pressing Enter in the lineedit
# currently closes the dialog
@@ -84,7 +88,7 @@ class MaterialEditor:
buttonOpen.clicked.connect(self.openfile)
buttonSave.clicked.connect(self.savefile)
buttonURL.clicked.connect(self.openProductURL)
- comboMaterial.currentIndexChanged[str].connect(self.updateContents)
+ comboMaterial.currentIndexChanged[str].connect(self.updateMatParamsInTree)
buttonAddProperty.clicked.connect(self.addCustomProperty)
buttonDeleteProperty.clicked.connect(self.deleteCustomProperty)
treeView.clicked.connect(self.checkDeletable)
@@ -103,7 +107,7 @@ class MaterialEditor:
self.implementModel()
if d:
- self.updateContents(d)
+ self.updateMatParamsInTree(d)
def implementModel(self):
@@ -146,7 +150,7 @@ class MaterialEditor:
treeView.expandAll()
- def updateContents(self, data):
+ def updateMatParamsInTree(self, data):
'''updates the contents of the editor with the given data, can be:
- a dictionary, if the editor was called with data
@@ -191,66 +195,39 @@ class MaterialEditor:
if k:
if k in self.cards:
+ # be careful with reading from materials dict
+ # the card could be updated the dict not
from importFCMat import read
d = read(self.cards[k])
if d:
- self.updateContents(d)
+ self.updateMatParamsInTree(d)
- def getMaterialResources(self):
- self.fem_prefs = FreeCAD.ParamGet(
- "User parameter:BaseApp/Preferences/Mod/Material/Resources"
- )
- use_built_in_materials = self.fem_prefs.GetBool("UseBuiltInMaterials", True)
- use_mat_from_config_dir = self.fem_prefs.GetBool("UseMaterialsFromConfigDir", True)
- use_mat_from_custom_dir = self.fem_prefs.GetBool("UseMaterialsFromCustomDir", True)
- if use_mat_from_custom_dir:
- custom_mat_dir = self.fem_prefs.GetString("CustomMaterialsDir", "")
- # later found cards with same name will override cards
- # FreeCAD returns paths with / at the end, thus not os.sep is needed on first +
- self.resources = []
- if use_built_in_materials:
- res_dir = FreeCAD.getResourceDir()
- self.resources.append(
- res_dir + "Mod" + os.sep + "Material" + os.sep + "StandardMaterial"
- )
- if use_mat_from_config_dir:
- self.resources.append(FreeCAD.ConfigGet("UserAppData") + "Material")
- if use_mat_from_custom_dir:
- custom_mat_dir = self.fem_prefs.GetString("CustomMaterialsDir", "")
- if os.path.exists(custom_mat_dir):
- self.resources.append(custom_mat_dir)
- self.outputResources()
-
- def outputResources(self):
- print('locations to look for material cards:')
- for path in self.resources:
- print(' ' + path)
- print('\n')
-
- def outputCards(self):
- print('material cards:')
- for card in sorted(self.cards.keys()):
- print(' ' + card + ': ' + self.cards[card])
- print('\n')
-
- def updateCards(self):
+ def updateCardsInCombo(self):
'''updates the contents of the materials combo with existing material cards'''
- self.getMaterialResources()
- self.cards = {}
- for p in self.resources:
- if os.path.exists(p):
- for f in sorted(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()
- self.widget.ComboMaterial.addItem("") # add a blank item first
- for card in sorted(self.cards.keys()):
- self.widget.ComboMaterial.addItem(card) # all keys in self.cards are unicode
+ mat_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Cards")
+ sort_by_resources = mat_prefs.GetBool("SortByResources", False)
+
+ # get all available materials (fill self.materials, self.cards and self.icons)
+ from materialtools.cardutils import import_materials as getmats
+ self.materials, self.cards, self.icons = getmats()
+
+ card_name_list = [] # [ [card_name, card_path, icon_path], ... ]
+
+ if sort_by_resources is True:
+ for a_path in sorted(self.materials.keys()):
+ 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.keys()):
+ 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.widget.ComboMaterial.addItem(QtGui.QIcon(mat[2]), mat[0])
def openProductURL(self):
@@ -441,7 +418,7 @@ class MaterialEditor:
self.directory = os.path.dirname(filename)
d = read(filename)
if d:
- self.updateContents(d)
+ self.updateMatParamsInTree(d)
def savefile(self):
"Saves a FCMat file."
@@ -472,7 +449,7 @@ class MaterialEditor:
if d:
from importFCMat import write
write(filename, d)
- self.updateCards()
+ self.updateCardsInCombo()
def show(self):
return self.widget.show()
diff --git a/src/Mod/Material/materialtools/cardutils.py b/src/Mod/Material/materialtools/cardutils.py
index c4be16f95f..e28136440b 100644
--- a/src/Mod/Material/materialtools/cardutils.py
+++ b/src/Mod/Material/materialtools/cardutils.py
@@ -23,3 +23,159 @@ __title__ = "material cards utilities"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
+import os
+import sys
+from os.path import join
+
+import FreeCAD
+
+
+if sys.version_info.major >= 3:
+ unicode = str
+
+
+# ***** get resources for cards ******************************************************************
+def get_material_resources(category='Solid'):
+
+ resources = {} # { resource_path: icon_path, ... }
+
+ # TODO: move GUI preferences from FEM to a new side tab Material
+ # https://forum.freecadweb.org/viewtopic.php?f=10&t=35515
+ mat_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Resources")
+ use_built_in_materials = mat_prefs.GetBool("UseBuiltInMaterials", True)
+ use_mat_from_config_dir = mat_prefs.GetBool("UseMaterialsFromConfigDir", True)
+ use_mat_from_custom_dir = mat_prefs.GetBool("UseMaterialsFromCustomDir", True)
+
+ if use_built_in_materials:
+ if category == 'Fluid':
+ builtin_mat_dir = join(
+ FreeCAD.getResourceDir(), "Mod", "Material", "FluidMaterial"
+ )
+
+ else:
+ builtin_mat_dir = join(
+ FreeCAD.getResourceDir(), "Mod", "Material", "StandardMaterial"
+ )
+ resources[builtin_mat_dir] = ":/icons/freecad.svg"
+
+ if use_mat_from_config_dir:
+ config_mat_dir = join(
+ FreeCAD.ConfigGet("UserAppData"), "Material"
+ )
+ resources[config_mat_dir] = ":/icons/preferences-general.svg"
+
+ if use_mat_from_custom_dir:
+ custom_mat_dir = mat_prefs.GetString("CustomMaterialsDir", "")
+ if os.path.exists(custom_mat_dir):
+ resources[custom_mat_dir] = ":/icons/user.svg"
+ else:
+ FreeCAD.Console.PrintError(
+ 'Custom material directory set by user: {} does not exist.\n'
+ .format(custom_mat_dir)
+ )
+
+ return resources
+
+
+def output_resources(resources):
+ FreeCAD.Console.PrintMessage('Directories we gone look for material cards:\n')
+ for path in resources.keys():
+ FreeCAD.Console.PrintMessage(' {}\n'.format(path))
+
+
+# ***** card handling ****************************************************************************
+# used in material editor and FEM material task panels
+
+def import_materials(category='Solid'):
+
+ resources = get_material_resources(category)
+
+ materials = {}
+ cards = {}
+ icons = {}
+ for path in resources.keys():
+ materials, cards, icons = add_cards_from_a_dir(
+ materials,
+ cards,
+ icons,
+ path,
+ resources[path]
+ )
+
+ return (materials, cards, icons)
+
+
+def add_cards_from_a_dir(materials, cards, icons, mat_dir, icon):
+ # fill materials and icons
+ import glob
+ from importFCMat import read
+ dir_path_list = glob.glob(mat_dir + '/*' + ".FCMat")
+ mat_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Cards")
+ delete_duplicates = mat_prefs.GetBool("DeleteDuplicates", True)
+ # duplicates are indicated on equality of mat dict
+ # TODO if the unit is different two cards would be different too
+ for a_path in dir_path_list:
+ mat_dict = read(a_path)
+ card_name = os.path.splitext(os.path.basename(a_path))[0]
+ if delete_duplicates is False:
+ materials[a_path] = mat_dict
+ i = 1
+ while card_name in cards.values():
+ if i == 1:
+ card_name += ('_' + str(i))
+ else:
+ card_name = card_name[:-1] + str(i)
+ i += 1
+ # print(card_name)
+ cards[a_path] = card_name
+ icons[a_path] = icon
+ else:
+ if mat_dict not in materials.values():
+ materials[a_path] = mat_dict
+ cards[a_path] = card_name
+ icons[a_path] = icon
+
+ return (materials, cards, icons)
+
+
+def output_trio(trio):
+ materials, cards, icons = trio
+ FreeCAD.Console.PrintMessage('\n\n')
+ for mat_card in materials:
+ FreeCAD.Console.PrintMessage(
+ '{} --> {} -->{}\n'
+ .format(cards[mat_card], mat_card, icons[mat_card])
+ )
+ FreeCAD.Console.PrintMessage('\n\n')
+
+
+def output_cards(cards):
+ FreeCAD.Console.PrintMessage('\n\n')
+ for mat_card in cards:
+ FreeCAD.Console.PrintMessage('{} --> {}\n'.format(mat_card, cards[mat_card]))
+ FreeCAD.Console.PrintMessage('\n\n')
+
+
+def output_icons(icons):
+ FreeCAD.Console.PrintMessage('\n\n')
+ for mat_card in icons:
+ FreeCAD.Console.PrintMessage('{} --> {}\n'.format(mat_card, icons[mat_card]))
+ FreeCAD.Console.PrintMessage('\n\n')
+
+
+def output_materials(materials):
+ FreeCAD.Console.PrintMessage('\n\n')
+ for mat_card in materials:
+ FreeCAD.Console.PrintMessage('{}\n'.format(mat_card))
+ output_material_param(materials[mat_card])
+ FreeCAD.Console.PrintMessage('\n\n')
+
+
+def output_material_param(mat_dict):
+ # thus we check for None
+ if not mat_dict:
+ FreeCAD.Console.PrintMessage(' empty matdict\n')
+ else:
+ for p in mat_dict:
+ FreeCAD.Console.PrintMessage(' {} --> {}\n'.format(p, mat_dict[p]))
+ FreeCAD.Console.PrintMessage('\n')