diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index e9076d55ee..722b5b287c 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -401,6 +401,7 @@ SET(FemGuiPythonUI_SRCS Resources/ui/FlowVelocity.ui Resources/ui/InitialFlowVelocity.ui Resources/ui/Material.ui + Resources/ui/MaterialReinforcement.ui Resources/ui/MeshBoundaryLayer.ui Resources/ui/MeshGmsh.ui Resources/ui/MeshGroup.ui diff --git a/src/Mod/Fem/Gui/Resources/ui/MaterialReinforcement.ui b/src/Mod/Fem/Gui/Resources/ui/MaterialReinforcement.ui new file mode 100755 index 0000000000..67fa6f6ec1 --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/ui/MaterialReinforcement.ui @@ -0,0 +1,183 @@ + + + FemMaterial + + + + 0 + 0 + 396 + 448 + + + + FEM material + + + Qt::LeftToRight + + + + + + + 16777215 + 1677215 + + + + Matrix Material + + + + + + + + + Choose + + + + + + + + Material + + + + + + + Name + + + + + + + TextLabel + + + + + + + Edit + + + + + + + Properties + + + + + + + + + Description + + + true + + + + + + + + + + + 16777215 + 1677215 + + + + Reinforcement Material + + + + + + + + + Choose + + + + + + + + Material + + + + + + + Name + + + + + + + TextLabel + + + + + + + Edit + + + + + + + Properties + + + + + + + + + Description + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py index 0a5c89f602..c3b40fd86d 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py @@ -33,6 +33,15 @@ import FemGui # needed to display the icons in TreeView False if False else FemGui.__name__ # flake8, dummy FemGui usage, returns 'FemGui' +# task panel +# from . import FemSelectionWidgets +from PySide import QtCore +from PySide import QtGui +import sys +if sys.version_info.major >= 3: + unicode = str + + class _ViewProviderFemMaterialReinforced: "A View Provider for the FemMaterialReinfocement object" def __init__(self, vobj): @@ -58,9 +67,19 @@ class _ViewProviderFemMaterialReinforced: return def setEdit(self, vobj, mode=0): - # avoid edit mode by return False - # https://forum.freecadweb.org/viewtopic.php?t=12139&start=10#p161062 - return False + # hide all meshes + for o in FreeCAD.ActiveDocument.Objects: + if o.isDerivedFrom("Fem::FemMeshObject"): + o.ViewObject.hide() + # hide all meshes + for o in FreeCAD.ActiveDocument.Objects: + if o.isDerivedFrom("Fem::FemMeshObject"): + o.ViewObject.hide() + # show task panel + taskd = _TaskPanelFemMaterialReinforced(self.Object) + taskd.obj = vobj.Object + FreeCADGui.Control.showDialog(taskd) + return True def unsetEdit(self, vobj, mode=0): FreeCADGui.Control.closeDialog() @@ -87,3 +106,395 @@ class _ViewProviderFemMaterialReinforced: def __setstate__(self, state): return None + + +class _TaskPanelFemMaterialReinforced: + '''The editmode TaskPanel for FemMaterialReinforced objects''' + + if sys.version_info.major >= 3: + unicode = str + + def __init__(self, obj): + + FreeCAD.Console.PrintMessage('\n') # empty line on start task panel + self.obj = obj + + # init matrix and reinforcement material + self.material_m = self.obj.Material + self.card_path_m = '' + self.has_transient_mat_m = False + self.material_r = self.obj.Reinforcement + self.card_path_r = '' + self.has_transient_mat_r = False + # 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 + + # init for collecting all mat data and icons + self.materials = {} # { card_path : FreeCAD material dict } + self.cards = {} # { card_path : card_names, ... } + self.icons = {} # { card_path : icon_path } + + # parameter widget + self.parameterWidget = FreeCADGui.PySideUic.loadUi( + FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/MaterialReinforcement.ui" + ) + + # globals + QtCore.QObject.connect( + self.parameterWidget.cb_materials_m, + QtCore.SIGNAL("activated(int)"), + self.choose_material_m + ) + QtCore.QObject.connect( + self.parameterWidget.pb_edit_m, + QtCore.SIGNAL("clicked()"), + self.edit_material_m + ) + QtCore.QObject.connect( + self.parameterWidget.cb_materials_r, + QtCore.SIGNAL("activated(int)"), + self.choose_material_r + ) + QtCore.QObject.connect( + self.parameterWidget.pb_edit_r, + QtCore.SIGNAL("clicked()"), + self.edit_material_r + ) + + # 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() + # fill the material comboboxes with material cards + self.add_cards_to_combo_boxes() + + # search for exact the mat_card_m and mat_card_r in all known cards + # choose the current matrix material + self.card_path_m = self.get_material_card(self.material_m) + FreeCAD.Console.PrintLog('card_path: {}'.format(self.card_path_m)) + if not self.card_path_m: + # 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 cannot be found in material directories. " + "Add document material.\n" + ) + self.card_path_m = '_Document_Matrix_Material' + self.materials[self.card_path_m] = self.material_m + self.parameterWidget.cb_materials_m.addItem( + QtGui.QIcon(":/icons/help-browser.svg"), + self.card_path_m, + self.card_path_m + ) + index = self.parameterWidget.cb_materials_m.findData(self.card_path_m) + # print(index) + # fill input fields and set the current material in the cb widget + self.choose_material_m(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_m.findData(self.card_path_m) + # set the current material in the cb widget + self.choose_material_m(index) + + # choose the current reinforcement material + self.card_path_r = self.get_material_card(self.material_r) + FreeCAD.Console.PrintLog('card_path: {}'.format(self.card_path_r)) + if not self.card_path_r: + # 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 cannot be found in material directories. " + "Add document material.\n" + ) + self.card_path_r = '_Document_Reinforcement_Material' + self.materials[self.card_path_r] = self.material_r + self.parameterWidget.cb_materials_r.addItem( + QtGui.QIcon(":/icons/help-browser.svg"), + self.card_path_r, + self.card_path_r + ) + index = self.parameterWidget.cb_materials_r.findData(self.card_path_r) + # set the current material in the cb widget + self.choose_material_r(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_r.findData(self.card_path_r) + # print(index) + # fill input fields and set the current material in the cb widget + self.choose_material_r(index) + + # set up the form + self.form = self.parameterWidget + + # leave task panel *************************************************************************** + def accept(self): + from materialtools.cardutils import check_mat_units as checkunits + if checkunits(self.material_m) is True and checkunits(self.material_r) is True: + self.obj.Material = self.material_m + self.obj.Reinforcement = self.material_r + else: + error_message = ( + 'Due to some wrong material quantity units in the changed ' + 'material data, the task panel changes where not accepted.\n' + ) + FreeCAD.Console.PrintError(error_message) + QtGui.QMessageBox.critical(None, "Material data not changed", error_message) + self.recompute_and_set_back_all() + return True + + def reject(self): + self.recompute_and_set_back_all() + return True + + def recompute_and_set_back_all(self): + guidoc = FreeCADGui.getDocument(self.obj.Document) + guidoc.Document.recompute() + guidoc.resetEdit() + self.output_obj_mat_param() + + def output_obj_mat_param(self): + self.print_mat_dict(self.obj.Material) + self.print_mat_dict(self.obj.Reinforcement) + print('\n') + + def print_mat_dict(self, mat_dict): + if 'Name' in mat_dict: + print('Material: {}'.format(mat_dict['Name'])) + else: + print('Matrix material: no Name') + for key in mat_dict: + print(' {}: {}'.format(key, mat_dict[key])) + + # choose material card *********************************************************************** + def get_material_card(self, material): + for a_mat in self.materials: + unmatched_items = set(self.materials[a_mat].items()) ^ set(material.items()) + # print(a_mat + ' --> unmatched_items = ' + str(len(unmatched_items))) + if len(unmatched_items) < 4: + FreeCAD.Console.PrintLog('{}\n'.format(unmatched_items)) + if len(unmatched_items) == 0: + return a_mat + return "" + + def choose_material_m(self, index): + if index < 0: + return + # get the whole card path + self.card_path_m = self.parameterWidget.cb_materials_m.itemData(index) + FreeCAD.Console.PrintMessage( + 'choose_material in FEM material task panel:\n' + ' {}\n'.format(self.card_path_m) + ) + self.material_m = self.materials[self.card_path_m] + self.parameterWidget.cb_materials_m.setCurrentIndex(index) + gen_mat_desc = "" + gen_mat_name = "" + if 'Description' in self.material_m: + gen_mat_desc = self.material_m['Description'] + if 'Name' in self.material_m: + gen_mat_name = self.material_m['Name'] + self.parameterWidget.l_description_m.setText(gen_mat_desc) + self.parameterWidget.l_name_m.setText(gen_mat_name) + + def choose_material_r(self, index): + if index < 0: + return + # get the whole card path + self.card_path_r = self.parameterWidget.cb_materials_r.itemData(index) + FreeCAD.Console.PrintMessage( + 'choose_material in FEM material task panel:\n' + ' {}\n'.format(self.card_path_r) + ) + self.material_r = self.materials[self.card_path_r] + self.parameterWidget.cb_materials_r.setCurrentIndex(index) + gen_mat_desc = "" + gen_mat_name = "" + if 'Description' in self.material_r: + gen_mat_desc = self.material_r['Description'] + if 'Name' in self.material_r: + gen_mat_name = self.material_r['Name'] + self.parameterWidget.l_description_r.setText(gen_mat_desc) + self.parameterWidget.l_name_r.setText(gen_mat_name) + + # transient material is needed if the user changed mat parameter by the mat editor + def set_transient_material_m(self): + self.card_path_m = '_Transient_Matrix_Material' + self.materials[self.card_path_m] = self.material_m # = the current matrix mat dict + index = self.parameterWidget.cb_materials_m.findData(self.card_path_m) + self.choose_material_m(index) + + def add_transient_material_m(self): + self.has_transient_mat_m = True + self.card_path_m = '_Transient_Matrix_Material' + self.parameterWidget.cb_materials_m.addItem( + QtGui.QIcon(":/icons/help-browser.svg"), + self.card_path_m, + self.card_path_m + ) + self.set_transient_material_m() + + def set_transient_material_r(self): + self.card_path_r = '_Transient_Reinforcement_Material' + self.materials[self.card_path_r] = self.material_r # = the current reinforced mat dict + index = self.parameterWidget.cb_materials_r.findData(self.card_path_r) + self.choose_material_r(index) + + def add_transient_material_r(self): + self.has_transient_mat_r = True + self.card_path_r = '_Transient_Reinforcement_Material' + self.parameterWidget.cb_materials_r.addItem( + QtGui.QIcon(":/icons/help-browser.svg"), + self.card_path_r, + self.card_path_r + ) + self.set_transient_material_r() + + # edit material parameter ******************************************************************** + # TODO, also all mat parameter checks should be moved to material editor + # and mat parameter checks should be done on analysis precheck in according to the analysis + # should be checked if all needed parameter are defined and have all right values and units + def edit_material_m(self): + # opens the material editor to choose a material or edit material params + import MaterialEditor + if self.card_path_m 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_m) + else: + new_material_params = MaterialEditor.editMaterial(card_path=self.card_path_m) + # 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_m = new_material_params + self.card_path_m = self.get_material_card(self.material_m) + FreeCAD.Console.PrintMessage('card_path: {}\n'.format(self.card_path_m)) + if not self.card_path_m: + 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_m is False: + self.add_transient_material_m() + else: + self.set_transient_material_m() + 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_m.findData(self.card_path_m) + # print(index) + # set the current material in the cb widget + self.choose_material_m(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.PrintMessage('No changes where made by the material editor.\n') + + def edit_material_r(self): + # opens the material editor to choose a material or edit material params + import MaterialEditor + if self.card_path_r 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_r) + else: + new_material_params = MaterialEditor.editMaterial(card_path=self.card_path_r) + # 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_r = new_material_params + self.card_path_r = self.get_material_card(self.material_r) + FreeCAD.Console.PrintMessage('card_path: {}\n'.format(self.card_path_r)) + if not self.card_path_r: + 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_r is False: + self.add_transient_material_r() + else: + self.set_transient_material_r() + 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_r.findData(self.card_path_r) + # print(index) + # set the current material in the cb widget + self.choose_material_r(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.PrintMessage('No changes where made by the material editor.\n') + + # fill the combo box with cards ************************************************************** + def add_cards_to_combo_boxes(self): + # fill comboboxes, in combo box the card name is used not the material name + self.parameterWidget.cb_materials_m.clear() + self.parameterWidget.cb_materials_r.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.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.parameterWidget.cb_materials_m.addItem(QtGui.QIcon(mat[2]), mat[0], mat[1]) + self.parameterWidget.cb_materials_r.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 ist used