Material: Material handling enhancements

Rework of the material handling system.

This first part concntrates on a rework of the material cards.
Rather than use a fixed list of possible properties, properties can
be defined separately in their own files and mixed to provide a
complete list of possible properties. Properties can be inherited.

The cards then provide values for the properties. These can also
be inherited allowing for small changes in cards as required.

The new property definitions are more extensive than previously.
2 and 3 dimensional arrays of properties can be defined. Values
are obtained by calling an API instead of reading from a dictionary.

For compatibility, a Python dictionary of values can be obtained
similar to how it was done previously, but this is considered a
deprecated API and won't support the newer advanced features.

The editor is completely reworked. It will be able to edit older format
material cards, but can only save them in the new format.

For testing during the development phase, a system preference can
specifiy wether the old or new material editors are to be used. This
option will be removed before release.
This commit is contained in:
David Carter
2023-09-14 22:52:48 -04:00
parent 563dc0b0cc
commit 6624fa3775
397 changed files with 19222 additions and 4312 deletions

View File

@@ -47,6 +47,13 @@ runs:
testCommand: ${{ inputs.builddir }}/tests/Tests_run --gtest_output=json:${{ inputs.reportdir }}core_gtest_results.json
testLogFile: ${{ inputs.reportdir }}core_gtest_test_log.txt
testName: Core
- name: C++ Material tests
id: material
uses: ./.github/workflows/actions/runCPPTests/runSingleTest
with:
testCommand: ${{ inputs.builddir }}/tests/Material_tests_run --gtest_output=json:${{ inputs.reportdir }}material_gtest_results.json
testLogFile: ${{ inputs.reportdir }}material_gtest_test_log.txt
testName: Material
- name: C++ Mesh tests
id: mesh
uses: ./.github/workflows/actions/runCPPTests/runSingleTest

View File

@@ -51,6 +51,7 @@ CheckInterModuleDependencies()
FreeCADLibpackChecks()
SetupDoxygen()
SetupLibFmt()
SetupYamlCpp()
if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER)
SetupPython()
SetupPCL()

View File

@@ -0,0 +1,11 @@
macro(SetupYamlCpp)
# -------------------------------- YamlCpp --------------------------------
find_package(yaml-cpp REQUIRED)
if(NOT yaml-cpp_FOUND)
message(FATAL_ERROR "==================\n"
"YamlCpp not found.\n"
"==================\n")
endif(NOT yaml-cpp_FOUND)
endmacro(SetupYamlCpp)

View File

@@ -34,7 +34,6 @@
#include "DlgSettingsFemGeneralImp.h"
#include "DlgSettingsFemGmshImp.h"
#include "DlgSettingsFemInOutVtkImp.h"
#include "DlgSettingsFemMaterialImp.h"
#include "DlgSettingsFemMystranImp.h"
#include "DlgSettingsFemZ88Imp.h"
#include "PropertyFemMeshItem.h"
@@ -108,81 +107,85 @@ PyMOD_INIT_FUNC(FemGui)
// clang-format off
// addition objects
FemGui::Workbench ::init();
FemGui::Workbench ::init();
FemGui::ViewProviderFemAnalysis ::init();
FemGui::ViewProviderFemAnalysisPython ::init();
FemGui::ViewProviderFemAnalysis ::init();
FemGui::ViewProviderFemAnalysisPython ::init();
FemGui::ViewProviderFemConstraint ::init();
FemGui::ViewProviderFemConstraintPython ::init();
FemGui::ViewProviderFemConstraint ::init();
FemGui::ViewProviderFemConstraintPython ::init();
FemGui::ViewProviderFemConstraintOnBoundary ::init();
FemGui::ViewProviderFemConstraintBearing ::init();
FemGui::ViewProviderFemConstraintContact ::init();
FemGui::ViewProviderFemConstraintDisplacement ::init();
FemGui::ViewProviderFemConstraintFixed ::init();
FemGui::ViewProviderFemConstraintFluidBoundary ::init();
FemGui::ViewProviderFemConstraintForce ::init();
FemGui::ViewProviderFemConstraintGear ::init();
FemGui::ViewProviderFemConstraintHeatflux ::init();
FemGui::ViewProviderFemConstraintInitialTemperature ::init();
FemGui::ViewProviderFemConstraintPlaneRotation ::init();
FemGui::ViewProviderFemConstraintPressure ::init();
FemGui::ViewProviderFemConstraintPulley ::init();
FemGui::ViewProviderFemConstraintTemperature ::init();
FemGui::ViewProviderFemConstraintTransform ::init();
FemGui::ViewProviderFemConstraintSpring ::init();
FemGui::ViewProviderFemConstraintOnBoundary ::init();
FemGui::ViewProviderFemConstraintBearing ::init();
FemGui::ViewProviderFemConstraintContact ::init();
FemGui::ViewProviderFemConstraintDisplacement ::init();
FemGui::ViewProviderFemConstraintFixed ::init();
FemGui::ViewProviderFemConstraintFluidBoundary ::init();
FemGui::ViewProviderFemConstraintForce ::init();
FemGui::ViewProviderFemConstraintGear ::init();
FemGui::ViewProviderFemConstraintHeatflux ::init();
FemGui::ViewProviderFemConstraintInitialTemperature ::init();
FemGui::ViewProviderFemConstraintPlaneRotation ::init();
FemGui::ViewProviderFemConstraintPressure ::init();
FemGui::ViewProviderFemConstraintPulley ::init();
FemGui::ViewProviderFemConstraintTemperature ::init();
FemGui::ViewProviderFemConstraintTransform ::init();
FemGui::ViewProviderFemConstraintSpring ::init();
FemGui::ViewProviderFemMesh ::init();
FemGui::ViewProviderFemMeshPython ::init();
FemGui::ViewProviderFemMeshShape ::init();
FemGui::ViewProviderFemMeshShapeNetgen ::init();
FemGui::PropertyFemMeshItem ::init();
FemGui::ViewProviderFemMesh ::init();
FemGui::ViewProviderFemMeshPython ::init();
FemGui::ViewProviderFemMeshShape ::init();
FemGui::ViewProviderFemMeshShapeNetgen ::init();
FemGui::PropertyFemMeshItem ::init();
FemGui::ViewProviderSetElements ::init();
FemGui::ViewProviderSetFaces ::init();
FemGui::ViewProviderSetGeometry ::init();
FemGui::ViewProviderSetNodes ::init();
FemGui::ViewProviderSetElements ::init();
FemGui::ViewProviderSetFaces ::init();
FemGui::ViewProviderSetGeometry ::init();
FemGui::ViewProviderSetNodes ::init();
FemGui::ViewProviderSolver ::init();
FemGui::ViewProviderSolverPython ::init();
FemGui::ViewProviderSolver ::init();
FemGui::ViewProviderSolverPython ::init();
FemGui::ViewProviderResult ::init();
FemGui::ViewProviderResultPython ::init();
FemGui::ViewProviderResult ::init();
FemGui::ViewProviderResultPython ::init();
#ifdef FC_USE_VTK
FemGui::ViewProviderFemPostObject ::init();
FemGui::ViewProviderFemPostPipeline ::init();
FemGui::ViewProviderFemPostClip ::init();
FemGui::ViewProviderFemPostContours ::init();
FemGui::ViewProviderFemPostCut ::init();
FemGui::ViewProviderFemPostDataAlongLine ::init();
FemGui::ViewProviderFemPostDataAtPoint ::init();
FemGui::ViewProviderFemPostScalarClip ::init();
FemGui::ViewProviderFemPostWarpVector ::init();
FemGui::ViewProviderFemPostObject ::init();
FemGui::ViewProviderFemPostPipeline ::init();
FemGui::ViewProviderFemPostClip ::init();
FemGui::ViewProviderFemPostContours ::init();
FemGui::ViewProviderFemPostCut ::init();
FemGui::ViewProviderFemPostDataAlongLine ::init();
FemGui::ViewProviderFemPostDataAtPoint ::init();
FemGui::ViewProviderFemPostScalarClip ::init();
FemGui::ViewProviderFemPostWarpVector ::init();
FemGui::ViewProviderFemPostFunction ::init();
FemGui::ViewProviderFemPostFunctionProvider ::init();
FemGui::ViewProviderFemPostBoxFunction ::init();
FemGui::ViewProviderFemPostCylinderFunction ::init();
FemGui::ViewProviderFemPostPlaneFunction ::init();
FemGui::ViewProviderFemPostSphereFunction ::init();
FemGui::ViewProviderFemPostFunction ::init();
FemGui::ViewProviderFemPostFunctionProvider ::init();
FemGui::ViewProviderFemPostBoxFunction ::init();
FemGui::ViewProviderFemPostCylinderFunction ::init();
FemGui::ViewProviderFemPostPlaneFunction ::init();
FemGui::ViewProviderFemPostSphereFunction ::init();
#endif
// register preferences pages on FEM, the order here will be the order of the tabs in pref widget
new Gui::PrefPageProducer<FemGui::DlgSettingsFemGeneralImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
// register preferences pages on FEM, the order here will be the order of the tabs in pref
// widget
new Gui::PrefPageProducer<FemGui::DlgSettingsFemGeneralImp>(
QT_TRANSLATE_NOOP("QObject", "FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemGmshImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemCcxImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemElmerImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemMystranImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemMystranImp>(
QT_TRANSLATE_NOOP("QObject", "FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemZ88Imp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemMaterialImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
// register preferences pages on Import-Export
new Gui::PrefPageProducer<FemGui::DlgSettingsFemExportAbaqusImp>(QT_TRANSLATE_NOOP("QObject", "Import-Export"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemInOutVtkImp>(QT_TRANSLATE_NOOP("QObject", "Import-Export"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemExportAbaqusImp>(
QT_TRANSLATE_NOOP("QObject", "Import-Export"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemInOutVtkImp>(
QT_TRANSLATE_NOOP("QObject", "Import-Export"));
// add resources and reloads the translators
loadFemResource();

View File

@@ -1,8 +1,8 @@
# Many warnings caused by vtk
if(CMAKE_COMPILER_IS_CLANGXX)
add_compile_options(-Wno-pedantic) # needed for vtk headers
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0)
add_compile_options(-Wno-inconsistent-missing-override)
endif()
elseif(CMAKE_COMPILER_IS_GNUCXX)
@@ -15,12 +15,10 @@ else(MSVC)
add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
endif(MSVC)
if(BUILD_FEM_NETGEN)
add_definitions(-DFCWithNetgen)
endif(BUILD_FEM_NETGEN)
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
@@ -37,18 +35,15 @@ include_directories(
link_directories(${OCC_LIBRARY_DIR})
link_directories(${SMESH_LIB_PATH})
set(FemGui_LIBS
Fem
FreeCADGui
PartGui
)
generate_from_xml(ViewProviderFemMeshPy)
generate_from_xml(ViewProviderFemPostPipelinePy)
SET(Python_SRCS
ViewProviderFemMeshPy.xml
ViewProviderFemMeshPyImp.cpp
@@ -57,7 +52,6 @@ SET(Python_SRCS
)
SOURCE_GROUP("Python" FILES ${Python_SRCS})
set(FemGui_UIC_SRCS
DlgSettingsFemCcx.ui
DlgSettingsFemElmer.ui
@@ -65,7 +59,6 @@ set(FemGui_UIC_SRCS
DlgSettingsFemGeneral.ui
DlgSettingsFemGmsh.ui
DlgSettingsFemInOutVtk.ui
DlgSettingsFemMaterial.ui
DlgSettingsFemMystran.ui
DlgSettingsFemZ88.ui
TaskCreateNodeSet.ui
@@ -88,6 +81,7 @@ set(FemGui_UIC_SRCS
TaskAnalysisInfo.ui
TaskDriver.ui
)
if(BUILD_FEM_VTK)
set(FemGui_UIC_SRCS
${FemGui_UIC_SRCS}
@@ -126,9 +120,6 @@ SET(FemGui_DLG_SRCS
DlgSettingsFemInOutVtk.ui
DlgSettingsFemInOutVtkImp.cpp
DlgSettingsFemInOutVtkImp.h
DlgSettingsFemMaterial.ui
DlgSettingsFemMaterialImp.cpp
DlgSettingsFemMaterialImp.h
DlgSettingsFemMystran.ui
DlgSettingsFemMystranImp.cpp
DlgSettingsFemMystranImp.h
@@ -186,14 +177,13 @@ SET(FemGui_DLG_SRCS
)
SOURCE_GROUP("Constraint-Dialogs" FILES ${FemGui_DLG_SRCS})
set (Fem_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Fem_translation.qrc)
set(Fem_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Fem_translation.qrc)
qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts"
${CMAKE_CURRENT_BINARY_DIR}/Resources/translations)
qt_create_resource_file(${Fem_TR_QRC} ${QM_SRCS})
qt_add_resources(FemResource_SRCS Resources/Fem.qrc ${Fem_TR_QRC})
SOURCE_GROUP("Resources" FILES ${FemResource_SRCS})
SET(FemGui_SRCS_ViewProvider
ViewProviderFemMesh.cpp
ViewProviderFemMesh.h
@@ -254,7 +244,6 @@ SET(FemGui_SRCS_ViewProvider
)
SOURCE_GROUP("ViewProvider" FILES ${FemGui_SRCS_ViewProvider})
SET(FemGui_SRCS_TaskBoxes
TaskObjectName.ui
TaskObjectName.cpp
@@ -272,6 +261,7 @@ SET(FemGui_SRCS_TaskBoxes
TaskTetParameter.cpp
TaskTetParameter.h
)
if(BUILD_FEM_VTK)
SET(FemGui_SRCS_TaskBoxes
${FemGui_SRCS_TaskBoxes}
@@ -291,8 +281,8 @@ if(BUILD_FEM_VTK)
TaskPostWarpVector.ui
)
endif(BUILD_FEM_VTK)
SOURCE_GROUP("Task_Boxes" FILES ${FemGui_SRCS_TaskBoxes})
SOURCE_GROUP("Task_Boxes" FILES ${FemGui_SRCS_TaskBoxes})
SET(FemGui_SRCS_TaskDlg
TaskDlgCreateNodeSet.h
@@ -304,7 +294,6 @@ SET(FemGui_SRCS_TaskDlg
)
SOURCE_GROUP("Task_Dialogs" FILES ${FemGui_SRCS_TaskDlg})
SET(FemGui_SRCS_Module
AppFemGui.cpp
AppFemGuiPy.cpp
@@ -325,7 +314,6 @@ SET(FemGui_SRCS_Module
)
SOURCE_GROUP("Module" FILES ${FemGui_SRCS_Module})
if(BUILD_FEM_VTK)
SET(FemGui_SRCS_Post
ViewProviderFemPostObject.h
@@ -336,11 +324,10 @@ if(BUILD_FEM_VTK)
ViewProviderFemPostFunction.cpp
ViewProviderFemPostFilter.h
ViewProviderFemPostFilter.cpp
)
)
SOURCE_GROUP("PostObjects" FILES ${FemGui_SRCS_Post})
endif(BUILD_FEM_VTK)
SET(FemGui_SRCS
${Python_SRCS}
${FemGui_DLG_SRCS}
@@ -365,13 +352,10 @@ SET(FemGuiIcon_SVG
add_library(FemGui SHARED ${FemGui_SRCS} ${FemGuiIcon_SVG})
target_link_libraries(FemGui ${FemGui_LIBS} ${VTK_LIBRARIES})
fc_copy_sources(FemGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Fem" ${FemGuiIcon_SVG})
INSTALL(FILES ${FemGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Fem/Resources/icons")
# Python modules ui files, they are copied as they are, thus the need not to be added to Fem.qrc
# see https://forum.freecad.org/viewtopic.php?f=10&t=25833
SET(FemGuiPythonUI_SRCS
@@ -409,10 +393,7 @@ fc_copy_sources(FemPythonUi "${CMAKE_BINARY_DIR}/Mod/Fem" ${FemGuiPythonUI_SRCS}
INSTALL(FILES ${FemGuiPythonUI_SRCS} DESTINATION Mod/Fem/Resources/ui)
SET_BIN_DIR(FemGui FemGui /Mod/Fem)
SET_PYTHON_PREFIX_SUFFIX(FemGui)
INSTALL(TARGETS FemGui DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@@ -0,0 +1,76 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License (LGPL) *
* as published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* for detail see the LICENCE text file. *
* *
* FreeCAD is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with FreeCAD; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <Base/PyObjectBase.h>
// #include "Model.h"
#include "MaterialManagerPy.h"
#include "MaterialPy.h"
#include "ModelManagerPy.h"
#include "ModelPropertyPy.h"
#include "ModelPy.h"
namespace Materials
{
class Module: public Py::ExtensionModule<Module>
{
public:
Module()
: Py::ExtensionModule<Module>("Material")
{
initialize("This module is the Material module.");// register with Python
}
~Module() override = default;
private:
};
PyObject* initModule()
{
return Base::Interpreter().addModule(new Module);
}
}// namespace Materials
PyMOD_INIT_FUNC(Material)
{
PyObject* module = Materials::initModule();
Base::Console().Log("Loading Material module... done\n");
Base::Interpreter().addType(&Materials::MaterialManagerPy ::Type, module, "MaterialManager");
Base::Interpreter().addType(&Materials::MaterialPy ::Type, module, "Material");
Base::Interpreter().addType(&Materials::ModelManagerPy ::Type, module, "ModelManager");
Base::Interpreter().addType(&Materials::ModelPropertyPy ::Type, module, "ModelProperty");
Base::Interpreter().addType(&Materials::ModelPy ::Type, module, "Model");
PyMOD_Return(module);
}

View File

@@ -0,0 +1,99 @@
if(MSVC)
add_definitions(-DFCAppMaterial -DHAVE_ACOSH -DHAVE_ASINH -DHAVE_ATANH)
else(MSVC)
add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
endif(MSVC)
add_definitions(-DYAML_CPP_STATIC_DEFINE)
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}/src
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${Boost_INCLUDE_DIRS}
${PYTHON_INCLUDE_DIRS}
${XercesC_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
${YAML_CPP_INCLUDE_DIR}
)
link_directories(${YAML_CPP_LIBRARY_DIR})
set(Material_LIBS
${Boost_LIBRARIES}
FreeCADApp
)
include_directories(
${QtConcurrent_INCLUDE_DIRS}
)
list(APPEND Material_LIBS
${QtConcurrent_LIBRARIES}
${YAML_CPP_LIBRARIES}
)
generate_from_xml(MaterialManagerPy)
generate_from_xml(MaterialPy)
generate_from_xml(ModelManagerPy)
generate_from_xml(ModelPropertyPy)
generate_from_xml(ModelPy)
SET(Python_SRCS
Exceptions.h
MaterialManagerPy.xml
MaterialManagerPyImpl.cpp
MaterialPy.xml
MaterialPyImpl.cpp
ModelManagerPy.xml
ModelManagerPyImpl.cpp
ModelPropertyPy.xml
ModelPropertyPyImpl.cpp
ModelPy.xml
ModelPyImpl.cpp
)
SOURCE_GROUP("Python" FILES ${Python_SRCS})
SET(Material_SRCS
${Python_SRCS}
AppMaterial.cpp
FolderTree.h
MaterialConfigLoader.cpp
MaterialConfigLoader.h
MaterialLibrary.cpp
MaterialLibrary.h
MaterialLoader.cpp
MaterialLoader.h
MaterialManager.cpp
MaterialManager.h
Materials.cpp
Materials.h
MaterialValue.cpp
MaterialValue.h
Model.cpp
Model.h
ModelLibrary.cpp
ModelLibrary.h
ModelLoader.cpp
ModelLoader.h
ModelManager.cpp
ModelManager.h
ModelUuids.h
PreCompiled.cpp
PreCompiled.h
trim.h
)
if(FREECAD_USE_PCH)
add_definitions(-D_PreComp_)
GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${Material_SRCS})
ADD_MSVC_PRECOMPILED_HEADER(Material PreCompiled.h PreCompiled.cpp PCH_SRCS)
endif(FREECAD_USE_PCH)
add_library(Material SHARED ${Material_SRCS})
target_link_libraries(Material ${Material_LIBS})
SET_BIN_DIR(Material Material /Mod/Material)
SET_PYTHON_PREFIX_SUFFIX(Material)
INSTALL(TARGETS Material DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@@ -0,0 +1,154 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_EXCEPTIONS_H
#define MATERIAL_EXCEPTIONS_H
#include <Base/BaseClass.h>
#include <Base/Exception.h>
namespace Materials
{
class Uninitialized: public Base::Exception
{
public:
Uninitialized()
{}
explicit Uninitialized(const char* msg)
{
this->setMessage(msg);
}
~Uninitialized() throw() override = default;
};
class ModelNotFound: public Base::Exception
{
public:
ModelNotFound()
{}
explicit ModelNotFound(const char* msg)
{
this->setMessage(msg);
}
~ModelNotFound() throw() override = default;
};
class MaterialNotFound: public Base::Exception
{
public:
MaterialNotFound()
{}
explicit MaterialNotFound(const char* msg)
{
this->setMessage(msg);
}
~MaterialNotFound() throw() override = default;
};
class PropertyNotFound: public Base::Exception
{
public:
PropertyNotFound()
{}
explicit PropertyNotFound(const char* msg)
{
this->setMessage(msg);
}
~PropertyNotFound() throw() override = default;
};
class LibraryNotFound: public Base::Exception
{
public:
LibraryNotFound()
{}
explicit LibraryNotFound(const char* msg)
{
this->setMessage(msg);
}
~LibraryNotFound() throw() override = default;
};
class InvalidModel: public Base::Exception
{
public:
InvalidModel()
{}
explicit InvalidModel(const char* msg)
{
this->setMessage(msg);
}
~InvalidModel() throw() override = default;
};
class InvalidRow: public Base::Exception
{
public:
InvalidRow()
{}
explicit InvalidRow(char* msg)
{
this->setMessage(msg);
}
~InvalidRow() throw() override = default;
};
class InvalidColumn: public Base::Exception
{
public:
InvalidColumn()
{}
explicit InvalidColumn(char* msg)
{
this->setMessage(msg);
}
~InvalidColumn() throw() override = default;
};
class InvalidIndex: public Base::Exception
{
public:
InvalidIndex()
{}
explicit InvalidIndex(char* msg)
{
this->setMessage(msg);
}
~InvalidIndex() throw() override = default;
};
class UnknownValueType: public Base::Exception
{
public:
UnknownValueType()
{}
explicit UnknownValueType(char* msg)
{
this->setMessage(msg);
}
~UnknownValueType() throw() override = default;
};
}// namespace Materials
#endif// MATERIAL_EXCEPTIONS_H

View File

@@ -0,0 +1,87 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_FOLDERTREE_H
#define MATERIAL_FOLDERTREE_H
#include <QString>
#include <map>
namespace Materials
{
template<class T>
class FolderTreeNode
{
public:
enum NodeType
{
DataNode,
FolderNode
};
FolderTreeNode()
{}
virtual ~FolderTreeNode() = default;
NodeType getType(void) const
{
return _type;
}
void setType(NodeType type)
{
_type = type;
}
const std::map<QString, FolderTreeNode<T>*>* getFolder(void) const
{
return _folder;
}
std::map<QString, FolderTreeNode<T>*>* getFolder(void)
{
return _folder;
}
const T* getData(void) const
{
return _data;
}
void setFolder(std::map<QString, FolderTreeNode<T>*>* folder)
{
setType(FolderNode);
_folder = folder;
}
void setData(const T* data)
{
setType(DataNode);
_data = data;
}
private:
NodeType _type;
std::map<QString, FolderTreeNode<T>*>* _folder;
const T* _data;
};
}// namespace Materials
#endif// MATERIAL_FOLDERTREE_H

View File

@@ -0,0 +1,396 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QDirIterator>
#include <QFileInfo>
#include <QString>
#endif
#include <QUuid>
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <fstream>
#include "MaterialConfigLoader.h"
#include "MaterialLoader.h"
#include "Model.h"
#include "ModelUuids.h"
using namespace Materials;
MaterialConfigLoader::MaterialConfigLoader()
{}
bool MaterialConfigLoader::isConfigStyle(const QString& path)
{
std::ifstream infile(path.toStdString());
// Check the first 2 lines for a ";"
for (int i = 0; i < 2; i++) {
std::string line;
if (!std::getline(infile, line)) {
return false;
}
if (line.at(0) != ';') {
return false;
}
}
return true;
}
QString MaterialConfigLoader::getAuthorAndLicense(const QString& path)
{
std::ifstream infile(path.toStdString());
QString noAuthor;
// Skip the first line
std::string line;
if (!std::getline(infile, line)) {
return noAuthor;
}
// The second line has it in a comment
if (!std::getline(infile, line)) {
return noAuthor;
}
std::size_t found = line.find(";");
if (found != std::string::npos) {
return QString::fromStdString(trim_copy(line.substr(found + 1)));
}
return noAuthor;
}
void MaterialConfigLoader::addVectorRendering(const QSettings& fcmat, Material* finalModel)
{
QString sectionFillPattern = value(fcmat, "VectorRendering/SectionFillPattern", "");
QString sectionLinewidth = value(fcmat, "VectorRendering/SectionLinewidth", "");
QString sectionColor = value(fcmat, "VectorRendering/SectionColor", "");
QString viewColor = value(fcmat, "VectorRendering/ViewColor", "");
QString viewFillPattern = value(fcmat, "VectorRendering/ViewFillPattern", "");
QString viewLinewidth = value(fcmat, "VectorRendering/ViewLinewidth", "");
if (sectionFillPattern.length() + sectionLinewidth.length() + sectionColor.length()
+ viewColor.length() + viewFillPattern.length() + viewLinewidth.length()
> 0) {
finalModel->addAppearance(ModelUUID_Rendering_Vector);
}
// Now add the data
setAppearanceValue(finalModel, "SectionFillPattern", sectionFillPattern);
setAppearanceValue(finalModel, "SectionLinewidth", sectionLinewidth);
setAppearanceValue(finalModel, "SectionColor", sectionColor);
setAppearanceValue(finalModel, "ViewColor", viewColor);
setAppearanceValue(finalModel, "ViewFillPattern", viewFillPattern);
setAppearanceValue(finalModel, "ViewLinewidth", viewLinewidth);
}
void MaterialConfigLoader::addRendering(const QSettings& fcmat, Material* finalModel)
{
QString ambientColor = value(fcmat, "Rendering/AmbientColor", "");
QString diffuseColor = value(fcmat, "Rendering/DiffuseColor", "");
QString emissiveColor = value(fcmat, "Rendering/EmissiveColor", "");
QString shininess = value(fcmat, "Rendering/Shininess", "");
QString specularColor = value(fcmat, "Rendering/SpecularColor", "");
QString transparency = value(fcmat, "Rendering/Transparency", "");
QString texturePath = value(fcmat, "Rendering/TexturePath", "");
QString textureScaling = value(fcmat, "Rendering/TextureScaling", "");
QString fragmentShader = value(fcmat, "Rendering/FragmentShader", "");
QString vertexShader = value(fcmat, "Rendering/VertexShader", "");
// Check which model we need
bool useTexture = false;
bool useAdvanced = false;
bool useBasic = false;
if (texturePath.length() + textureScaling.length() > 0) {
useTexture = true;
}
if (fragmentShader.length() + vertexShader.length() > 0) {
useAdvanced = true;
}
if (ambientColor.length() + diffuseColor.length() + emissiveColor.length() + shininess.length()
+ specularColor.length() + transparency.length()
> 0) {
useBasic = true;
}
if (useAdvanced) {
finalModel->addAppearance(ModelUUID_Rendering_Advanced);
}
else if (useTexture) {
finalModel->addAppearance(ModelUUID_Rendering_Texture);
}
else if (useBasic) {
finalModel->addAppearance(ModelUUID_Rendering_Basic);
}
// Now add the data
setAppearanceValue(finalModel, "AmbientColor", ambientColor);
setAppearanceValue(finalModel, "DiffuseColor", diffuseColor);
setAppearanceValue(finalModel, "EmissiveColor", emissiveColor);
setAppearanceValue(finalModel, "Shininess", shininess);
setAppearanceValue(finalModel, "SpecularColor", specularColor);
setAppearanceValue(finalModel, "Transparency", transparency);
setAppearanceValue(finalModel, "TexturePath", texturePath);
setAppearanceValue(finalModel, "TextureScaling", textureScaling);
setAppearanceValue(finalModel, "FragmentShader", fragmentShader);
setAppearanceValue(finalModel, "VertexShader", vertexShader);
}
void MaterialConfigLoader::addCosts(const QSettings& fcmat, Material* finalModel)
{
QString productURL = value(fcmat, "Cost/ProductURL", "");
QString specificPrice = value(fcmat, "Cost/SpecificPrice", "");
QString vendor = value(fcmat, "Cost/Vendor", "");
if (productURL.length() + specificPrice.length() + vendor.length() > 0) {
finalModel->addPhysical(ModelUUID_Costs_Default);
}
// Now add the data
setPhysicalValue(finalModel, "ProductURL", productURL);
setPhysicalValue(finalModel, "SpecificPrice", specificPrice);
setPhysicalValue(finalModel, "Vendor", vendor);
}
void MaterialConfigLoader::addArchitectural(const QSettings& fcmat, Material* finalModel)
{
QString color = value(fcmat, "Architectural/Color", "");
QString environmentalEfficiencyClass =
value(fcmat, "Architectural/EnvironmentalEfficiencyClass", "");
QString executionInstructions = value(fcmat, "Architectural/ExecutionInstructions", "");
QString finish = value(fcmat, "Architectural/Finish", "");
QString fireResistanceClass = value(fcmat, "Architectural/FireResistanceClass", "");
QString model = value(fcmat, "Architectural/Model", "");
QString soundTransmissionClass = value(fcmat, "Architectural/SoundTransmissionClass", "");
QString unitsPerQuantity = value(fcmat, "Architectural/UnitsPerQuantity", "");
if (color.length() + environmentalEfficiencyClass.length() + executionInstructions.length()
+ finish.length() + fireResistanceClass.length() + model.length()
+ soundTransmissionClass.length() + unitsPerQuantity.length()
> 0) {
finalModel->addPhysical(ModelUUID_Architectural_Default);
}
// Now add the data
setPhysicalValue(finalModel, "Color", color);
setPhysicalValue(finalModel, "EnvironmentalEfficiencyClass", environmentalEfficiencyClass);
setPhysicalValue(finalModel, "ExecutionInstructions", executionInstructions);
setPhysicalValue(finalModel, "Finish", finish);
setPhysicalValue(finalModel, "FireResistanceClass", fireResistanceClass);
setPhysicalValue(finalModel, "Model", model);
setPhysicalValue(finalModel, "SoundTransmissionClass", soundTransmissionClass);
setPhysicalValue(finalModel, "UnitsPerQuantity", unitsPerQuantity);
}
void MaterialConfigLoader::addElectromagnetic(const QSettings& fcmat, Material* finalModel)
{
QString relativePermittivity = value(fcmat, "Electromagnetic/RelativePermittivity", "");
QString electricalConductivity = value(fcmat, "Electromagnetic/ElectricalConductivity", "");
QString relativePermeability = value(fcmat, "Electromagnetic/RelativePermeability", "");
if (relativePermittivity.length() + electricalConductivity.length()
+ relativePermeability.length()
> 0) {
finalModel->addPhysical(ModelUUID_Electromagnetic_Default);
}
// Now add the data
setPhysicalValue(finalModel, "RelativePermittivity", relativePermittivity);
setPhysicalValue(finalModel, "ElectricalConductivity", electricalConductivity);
setPhysicalValue(finalModel, "RelativePermeability", relativePermeability);
}
void MaterialConfigLoader::addThermal(const QSettings& fcmat, Material* finalModel)
{
QString specificHeat = value(fcmat, "Thermal/SpecificHeat", "");
QString thermalConductivity = value(fcmat, "Thermal/ThermalConductivity", "");
QString thermalExpansionCoefficient = value(fcmat, "Thermal/ThermalExpansionCoefficient", "");
if (specificHeat.length() + thermalConductivity.length() + thermalExpansionCoefficient.length()
> 0) {
finalModel->addPhysical(ModelUUID_Thermal_Default);
}
// Now add the data
setPhysicalValue(finalModel, "SpecificHeat", specificHeat);
setPhysicalValue(finalModel, "ThermalConductivity", thermalConductivity);
setPhysicalValue(finalModel, "ThermalExpansionCoefficient", thermalExpansionCoefficient);
}
void MaterialConfigLoader::addFluid(const QSettings& fcmat, Material* finalModel)
{
QString density = value(fcmat, "Fluidic/Density", "");
QString dynamicViscosity = value(fcmat, "Fluidic/DynamicViscosity", "");
QString kinematicViscosity = value(fcmat, "Fluidic/KinematicViscosity", "");
QString prandtlNumber = value(fcmat, "Fluidic/PrandtlNumber", "");
// Check which model we need
bool useDensity = false;
bool useFluid = false;
if (density.length() > 0) {
useDensity = true;
}
if (dynamicViscosity.length() + kinematicViscosity.length() + prandtlNumber.length() > 0) {
useFluid = true;
}
if (useFluid) {
finalModel->addPhysical(ModelUUID_Fluid_Default);
}
else if (useDensity) {
finalModel->addPhysical(ModelUUID_Mechanical_Density);
}
// Now add the data
setPhysicalValue(finalModel, "Density", density);
setPhysicalValue(finalModel, "DynamicViscosity", dynamicViscosity);
setPhysicalValue(finalModel, "KinematicViscosity", kinematicViscosity);
setPhysicalValue(finalModel, "PrandtlNumber", prandtlNumber);
}
void MaterialConfigLoader::addMechanical(const QSettings& fcmat, Material* finalModel)
{
QString density = value(fcmat, "Mechanical/Density", "");
QString bulkModulus = value(fcmat, "Mechanical/BulkModulus", "");
QString poissonRatio = value(fcmat, "Mechanical/PoissonRatio", "");
QString shearModulus = value(fcmat, "Mechanical/ShearModulus", "");
QString youngsModulus = value(fcmat, "Mechanical/YoungsModulus", "");
QString angleOfFriction = value(fcmat, "Mechanical/AngleOfFriction", "");
QString compressiveStrength = value(fcmat, "Mechanical/CompressiveStrength", "");
QString fractureToughness = value(fcmat, "Mechanical/FractureToughness", "");
QString ultimateStrain = value(fcmat, "Mechanical/UltimateStrain", "");
QString ultimateTensileStrength = value(fcmat, "Mechanical/UltimateTensileStrength", "");
QString yieldStrength = value(fcmat, "Mechanical/YieldStrength", "");
QString stiffness = value(fcmat, "Mechanical/Stiffness", "");
// Check which model we need
bool useDensity = false;
bool useIso = false;
bool useLinearElastic = false;
if (density.length() > 0) {
useDensity = true;
}
if (bulkModulus.length() + poissonRatio.length() + shearModulus.length()
+ youngsModulus.length()
> 0) {
useIso = true;
}
if (angleOfFriction.length() + compressiveStrength.length() + fractureToughness.length()
+ ultimateStrain.length() + ultimateTensileStrength.length() + yieldStrength.length()
+ stiffness.length()
> 0) {
useLinearElastic = true;
}
if (useLinearElastic) {
finalModel->addPhysical(ModelUUID_Mechanical_LinearElastic);
}
else {
if (useIso) {
finalModel->addPhysical(ModelUUID_Mechanical_IsotropicLinearElastic);
}
if (useDensity) {
finalModel->addPhysical(ModelUUID_Mechanical_Density);
}
}
// Now add the data
setPhysicalValue(finalModel, "Density", density);
setPhysicalValue(finalModel, "BulkModulus", bulkModulus);
setPhysicalValue(finalModel, "PoissonRatio", poissonRatio);
setPhysicalValue(finalModel, "ShearModulus", shearModulus);
setPhysicalValue(finalModel, "YoungsModulus", youngsModulus);
setPhysicalValue(finalModel, "AngleOfFriction", angleOfFriction);
setPhysicalValue(finalModel, "CompressiveStrength", compressiveStrength);
setPhysicalValue(finalModel, "FractureToughness", fractureToughness);
setPhysicalValue(finalModel, "UltimateStrain", ultimateStrain);
setPhysicalValue(finalModel, "UltimateTensileStrength", ultimateTensileStrength);
setPhysicalValue(finalModel, "YieldStrength", yieldStrength);
setPhysicalValue(finalModel, "Stiffness", stiffness);
}
Material* MaterialConfigLoader::getMaterialFromPath(const MaterialLibrary& library,
const QString& path)
{
QString authorAndLicense = getAuthorAndLicense(path);
QSettings fcmat(path, QSettings::IniFormat);
// General section
// QString name = value(fcmat, "Name", ""); - always get the name from the filename
QFileInfo filepath(path);
QString name =
filepath.fileName().remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive);
QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
QString description = value(fcmat, "Description", "");
QString sourceReference = value(fcmat, "ReferenceSource", "");
QString sourceURL = value(fcmat, "SourceURL", "");
Material* finalModel = new Material(library, path, uuid, name);
finalModel->setAuthorAndLicense(authorAndLicense);
finalModel->setDescription(description);
finalModel->setReference(sourceReference);
finalModel->setURL(sourceURL);
QString father = value(fcmat, "Father", "");
if (father.length() > 0) {
finalModel->addPhysical(ModelUUID_Legacy_Father);
// Now add the data
setPhysicalValue(finalModel, "Father", father);
}
QString kindOfMaterial = value(fcmat, "KindOfMaterial", "");
QString materialNumber = value(fcmat, "MaterialNumber", "");
QString norm = value(fcmat, "Norm", "");
QString standardCode = value(fcmat, "StandardCode", "");
if (kindOfMaterial.length() + materialNumber.length() + norm.length() + standardCode.length()
> 0) {
finalModel->addPhysical(ModelUUID_Legacy_MaterialStandard);
// Now add the data
setPhysicalValue(finalModel, "KindOfMaterial", kindOfMaterial);
setPhysicalValue(finalModel, "MaterialNumber", materialNumber);
setPhysicalValue(finalModel, "StandardCode", norm);// Norm is the same as StandardCode
setPhysicalValue(finalModel, "StandardCode", standardCode);
}
// Add the remaining sections
addMechanical(fcmat, finalModel);
addFluid(fcmat, finalModel);
addThermal(fcmat, finalModel);
addElectromagnetic(fcmat, finalModel);
addArchitectural(fcmat, finalModel);
addCosts(fcmat, finalModel);
addRendering(fcmat, finalModel);
addVectorRendering(fcmat, finalModel);
return finalModel;
}

View File

@@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALCONFIGLOADER_H
#define MATERIAL_MATERIALCONFIGLOADER_H
#include <QDir>
#include <QSettings>
#include <QString>
#include "Materials.h"
namespace Materials
{
class MaterialConfigLoader
{
public:
MaterialConfigLoader();
virtual ~MaterialConfigLoader() = default;
static bool isConfigStyle(const QString& path);
static Material* getMaterialFromPath(const MaterialLibrary& library, const QString& path);
private:
static QString
value(const QSettings& fcmat, const std::string& name, const std::string& defaultValue)
{
return fcmat.value(QString::fromStdString(name), QString::fromStdString(defaultValue))
.toString();
}
static void
setPhysicalValue(Material* finalModel, const std::string& name, const QString& value)
{
if (value.length() > 0) {
finalModel->setPhysicalValue(QString::fromStdString(name), value);
}
}
static void
setAppearanceValue(Material* finalModel, const std::string& name, const QString& value)
{
if (value.length() > 0) {
finalModel->setAppearanceValue(QString::fromStdString(name), value);
}
}
static QString getAuthorAndLicense(const QString& path);
static void addMechanical(const QSettings& fcmat, Material* finalModel);
static void addFluid(const QSettings& fcmat, Material* finalModel);
static void addThermal(const QSettings& fcmat, Material* finalModel);
static void addElectromagnetic(const QSettings& fcmat, Material* finalModel);
static void addArchitectural(const QSettings& fcmat, Material* finalModel);
static void addCosts(const QSettings& fcmat, Material* finalModel);
static void addRendering(const QSettings& fcmat, Material* finalModel);
static void addVectorRendering(const QSettings& fcmat, Material* finalModel);
};
}// namespace Materials
#endif// MATERIAL_MATERIALCONFIGLOADER_H

View File

@@ -0,0 +1,168 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <App/Application.h>
#include "MaterialLibrary.h"
#include "Materials.h"
#include "ModelManager.h"
using namespace Materials;
/* TRANSLATOR Material::Materials */
std::map<QString, Material*>* MaterialLibrary::_materialPathMap = nullptr;
TYPESYSTEM_SOURCE(Materials::MaterialLibrary, LibraryBase)
MaterialLibrary::MaterialLibrary()
{
if (_materialPathMap == nullptr) {
_materialPathMap = new std::map<QString, Material*>();
}
}
MaterialLibrary::MaterialLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly)
: LibraryBase(libraryName, dir, icon)
, _readOnly(readOnly)
{
if (_materialPathMap == nullptr) {
_materialPathMap = new std::map<QString, Material*>();
}
}
void MaterialLibrary::createPath(const QString& path)
{
Q_UNUSED(path)
}
Material* MaterialLibrary::saveMaterial(Material& material, const QString& path, bool saveAsCopy)
{
QString filePath = getLocalPath(path);
Base::Console().Log("\tfilePath = '%s'\n", filePath.toStdString().c_str());
QFile file(filePath);
// Update UUID if required
// if name changed true
if (material.getName() != file.fileName()) {
material.newUuid();
}
// if overwrite false having warned the user
// if old format true, but already set
QFileInfo info(file);
QDir fileDir(info.path());
if (!fileDir.exists()) {
if (!fileDir.mkpath(info.path())) {
Base::Console().Error("Unable to create directory path '%s'\n",
info.path().toStdString().c_str());
}
}
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
stream.setCodec("UTF-8");
stream.setGenerateByteOrderMark(true);
// Write the contents
material.setLibrary(*this);
material.setDirectory(getRelativePath(path));
material.save(stream, saveAsCopy);
}
return addMaterial(material, path);
}
Material* MaterialLibrary::addMaterial(const Material& material, const QString& path)
{
QString filePath = getRelativePath(path);
Material* newMaterial = new Material(material);
newMaterial->setLibrary(*this);
newMaterial->setDirectory(filePath);
try {
// If there's already a material at that path we'll replace it
Material* old = _materialPathMap->at(filePath);
delete old;
}
catch (const std::out_of_range&) {
}
(*_materialPathMap)[filePath] = newMaterial;
return newMaterial;
}
const Material& MaterialLibrary::getMaterialByPath(const QString& path) const
{
// Base::Console().Log("MaterialLibrary::getMaterialByPath(%s)\n", path.toStdString().c_str());
// for (auto itp = _materialPathMap->begin(); itp != _materialPathMap->end(); itp++) {
// Base::Console().Log("\tpath = '%s'\n", itp->first.toStdString().c_str());
// }
QString filePath = getRelativePath(path);
try {
Material* material = _materialPathMap->at(filePath);
return *material;
}
catch (std::out_of_range& e) {
throw MaterialNotFound();
}
}
const QString MaterialLibrary::getUUIDFromPath(const QString& path) const
{
QString filePath = getRelativePath(path);
try {
Material* material = _materialPathMap->at(filePath);
return material->getUUID();
}
catch (std::out_of_range& e) {
throw MaterialNotFound();
}
}
TYPESYSTEM_SOURCE(Materials::MaterialExternalLibrary, MaterialLibrary::MaterialLibrary)
MaterialExternalLibrary::MaterialExternalLibrary()
{}
MaterialExternalLibrary::MaterialExternalLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly)
: MaterialLibrary(libraryName, dir, icon, readOnly)
{}
MaterialExternalLibrary::~MaterialExternalLibrary()
{
// delete directory;
}

View File

@@ -0,0 +1,95 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALLIBRARY_H
#define MATERIAL_MATERIALLIBRARY_H
#include <Base/BaseClass.h>
#include <QDir>
#include <QString>
#include <QVariant>
#include "Model.h"
#include "ModelLibrary.h"
namespace Materials
{
class Material;
class MaterialsExport MaterialLibrary: public LibraryBase
{
TYPESYSTEM_HEADER();
public:
MaterialLibrary();
explicit MaterialLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
virtual ~MaterialLibrary() = default;
bool operator==(const MaterialLibrary& library) const
{
return LibraryBase::operator==(library);
}
bool operator!=(const MaterialLibrary& library) const
{
return !operator==(library);
}
const Material& getMaterialByPath(const QString& path) const;
void createPath(const QString& path);
Material* saveMaterial(Material& material, const QString& path, bool saveAsCopy);
Material* addMaterial(const Material& material, const QString& path);
bool isReadOnly() const
{
return _readOnly;
}
protected:
const QString getUUIDFromPath(const QString& path) const;
bool _readOnly;
static std::map<QString, Material*>* _materialPathMap;
};
class MaterialsExport MaterialExternalLibrary: public MaterialLibrary
{
TYPESYSTEM_HEADER();
public:
MaterialExternalLibrary();
explicit MaterialExternalLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
virtual ~MaterialExternalLibrary();
};
}// namespace Materials
Q_DECLARE_METATYPE(Materials::MaterialLibrary)
Q_DECLARE_METATYPE(Materials::MaterialExternalLibrary)
#endif// MATERIAL_MATERIALLIBRARY_H

View File

@@ -0,0 +1,445 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QString>
#endif
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <QDirIterator>
#include <QFileInfo>
#include "MaterialConfigLoader.h"
#include "MaterialLoader.h"
#include "Model.h"
#include "ModelManager.h"
using namespace Materials;
MaterialEntry::MaterialEntry()
{}
MaterialEntry::MaterialEntry(const MaterialLibrary& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid)
: _library(library)
, _name(modelName)
, _directory(dir)
, _uuid(modelUuid)
{}
MaterialYamlEntry::MaterialYamlEntry(const MaterialLibrary& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
const YAML::Node& modelData)
: MaterialEntry(library, modelName, dir, modelUuid)
, _model(modelData)
{}
// MaterialYamlEntry::~MaterialYamlEntry()
// {}
QString MaterialYamlEntry::yamlValue(const YAML::Node& node,
const std::string& key,
const std::string& defaultValue)
{
if (node[key]) {
return QString::fromStdString(node[key].as<std::string>());
}
return QString::fromStdString(defaultValue);
}
void MaterialYamlEntry::addToTree(std::map<QString, Material*>* materialMap)
{
std::set<QString> exclude;
exclude.insert(QString::fromStdString("General"));
exclude.insert(QString::fromStdString("Inherits"));
auto yamlModel = getModel();
auto library = getLibrary();
auto name = getName();
auto directory = getDirectory();
QString uuid = getUUID();
QString authorAndLicense = yamlValue(yamlModel["General"], "AuthorAndLicense", "");
QString description = yamlValue(yamlModel["General"], "Description", "");
Material* finalModel = new Material(library, directory, uuid, name);
finalModel->setAuthorAndLicense(authorAndLicense);
finalModel->setDescription(description);
// Add inheritance list
if (yamlModel["Inherits"]) {
auto inherits = yamlModel["Inherits"];
for (auto it = inherits.begin(); it != inherits.end(); it++) {
std::string nodeName = it->second["UUID"].as<std::string>();
finalModel->setParentUUID(
QString::fromStdString(nodeName));// Should only be one. Need to check
}
}
// Add material models
if (yamlModel["Models"]) {
auto models = yamlModel["Models"];
for (auto it = models.begin(); it != models.end(); it++) {
std::string modelName = (it->first).as<std::string>();
// Add the model uuid
auto modelNode = models[modelName];
std::string modelUUID = modelNode["UUID"].as<std::string>();
finalModel->addPhysical(QString::fromStdString(modelUUID));
// Add the property values
auto properties = yamlModel["Models"][modelName];
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
std::string propertyName = (itp->first).as<std::string>();
std::string propertyValue = (itp->second).as<std::string>();
if (finalModel->hasPhysicalProperty(QString::fromStdString(propertyName))) {
finalModel->setPhysicalValue(QString::fromStdString(propertyName),
QString::fromStdString(propertyValue));
}
else if (propertyName != "UUID") {
Base::Console().Log("\tProperty '%s' is not described by any model. Ignored\n",
propertyName.c_str());
}
}
}
}
// Add appearance models
if (yamlModel["AppearanceModels"]) {
auto models = yamlModel["AppearanceModels"];
for (auto it = models.begin(); it != models.end(); it++) {
std::string modelName = (it->first).as<std::string>();
// Add the model uuid
auto modelNode = models[modelName];
std::string modelUUID = modelNode["UUID"].as<std::string>();
finalModel->addAppearance(QString::fromStdString(modelUUID));
// Add the property values
auto properties = yamlModel["AppearanceModels"][modelName];
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
std::string propertyName = (itp->first).as<std::string>();
std::string propertyValue = (itp->second).as<std::string>();
if (finalModel->hasAppearanceProperty(QString::fromStdString(propertyName))) {
finalModel->setAppearanceValue(QString::fromStdString(propertyName),
QString::fromStdString(propertyValue));
}
else if (propertyName != "UUID") {
Base::Console().Log("\tProperty '%s' is not described by any model. Ignored\n",
propertyName.c_str());
}
}
}
}
QString path = QDir(directory).absolutePath();
// Base::Console().Log("\tPath '%s'\n", path.toStdString().c_str());
(*materialMap)[uuid] = library.addMaterial(*finalModel, path);
}
std::map<QString, MaterialEntry*>* MaterialLoader::_materialEntryMap = nullptr;
MaterialLoader::MaterialLoader(std::map<QString, Material*>* materialMap,
std::list<MaterialLibrary*>* libraryList)
: _materialMap(materialMap)
, _libraryList(libraryList)
{
loadLibraries();
}
/*
* Destroys the object and frees any allocated resources
*/
MaterialLoader::~MaterialLoader()
{}
void MaterialLoader::addLibrary(MaterialLibrary* model)
{
_libraryList->push_back(model);
}
MaterialEntry* MaterialLoader::getMaterialFromPath(MaterialLibrary& library,
const QString& path) const
{
MaterialEntry* model = nullptr;
// Used for debugging
std::string uuid;
std::string pathName = path.toStdString();
if (MaterialConfigLoader::isConfigStyle(path)) {
Base::Console().Log("Old format .FCMat file: '%s'\n", pathName.c_str());
Material* material = MaterialConfigLoader::getMaterialFromPath(library, path);
if (material) {
(*_materialMap)[material->getUUID()] = library.addMaterial(*material, path);
}
// Return the nullptr as there are no intermediate steps to take, such
// as checking inheritance
return model;
}
YAML::Node yamlroot;
try {
yamlroot = YAML::LoadFile(pathName);
const std::string uuid = yamlroot["General"]["UUID"].as<std::string>();
// Always get the name from the filename
// QString name = QString::fromStdString(yamlroot["General"]["Name"].as<std::string>());
QFileInfo filepath(path);
QString name =
filepath.fileName().remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive);
model = new MaterialYamlEntry(library, name, path, QString::fromStdString(uuid), yamlroot);
// showYaml(yamlroot);
}
catch (YAML::Exception const& e) {
Base::Console().Error("YAML parsing error: '%s'\n", pathName.c_str());
Base::Console().Error("\t'%s'\n", e.what());
showYaml(yamlroot);
}
return model;
}
void MaterialLoader::showYaml(const YAML::Node& yaml)
{
std::stringstream out;
out << yaml;
std::string logData = out.str();
Base::Console().Log("%s\n", logData.c_str());
}
void MaterialLoader::dereference(Material* material)
{
// Avoid recursion
if (material->getDereferenced()) {
return;
}
// Base::Console().Log("Dereferencing material '%s'.\n",
// material->getName().toStdString().c_str());
auto parentUUID = material->getParentUUID();
if (parentUUID.size() > 0) {
Material* parent;
try {
parent = (*_materialMap)[parentUUID];
}
catch (std::out_of_range& e) {
Base::Console().Log(
"Unable to apply inheritance for material '%s', parent '%s' not found.\n",
material->getName().toStdString().c_str(),
parentUUID.toStdString().c_str());
}
// Ensure the parent has been dereferenced
dereference(parent);
// Add physical models
auto modelVector = parent->getPhysicalModels();
for (auto model = modelVector->begin(); model != modelVector->end(); model++) {
if (!material->hasPhysicalModel(*model)) {
material->addPhysical(*model);
}
}
// Add appearance models
modelVector = parent->getAppearanceModels();
for (auto model = modelVector->begin(); model != modelVector->end(); model++) {
if (!material->hasAppearanceModel(*model)) {
material->addAppearance(*model);
}
}
// Add values
auto properties = parent->getPhysicalProperties();
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
auto name = itp->first;
auto property = static_cast<const MaterialProperty>(itp->second);
if (material->getPhysicalProperty(name).isNull()) {
material->getPhysicalProperty(name).setValue(property.getValue());
}
}
properties = parent->getAppearanceProperties();
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
auto name = itp->first;
auto property = static_cast<const MaterialProperty>(itp->second);
if (material->getAppearanceProperty(name).isNull()) {
material->getAppearanceProperty(name).setValue(property.getValue());
}
}
}
material->markDereferenced();
}
void MaterialLoader::loadLibrary(MaterialLibrary& library)
{
if (_materialEntryMap == nullptr) {
_materialEntryMap = new std::map<QString, MaterialEntry*>();
}
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
while (it.hasNext()) {
auto pathname = it.next();
QFileInfo file(pathname);
if (file.isFile()) {
if (file.suffix().toStdString() == "FCMat") {
QString libraryName = file.baseName();
auto model = getMaterialFromPath(library, file.canonicalFilePath());
if (model) {
(*_materialEntryMap)[model->getUUID()] = model;
}
}
}
}
for (auto it = _materialEntryMap->begin(); it != _materialEntryMap->end(); it++) {
it->second->addToTree(_materialMap);
}
}
void MaterialLoader::loadLibraries(void)
{
std::list<MaterialLibrary*>* _libraryList = getMaterialLibraries();
if (_libraryList) {
for (auto it = _libraryList->begin(); it != _libraryList->end(); it++) {
loadLibrary(**it);
}
}
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
dereference(it->second);
}
}
std::list<MaterialLibrary*>* MaterialLoader::getMaterialLibraries()
{
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Resources");
bool useBuiltInMaterials = param->GetBool("UseBuiltInMaterials", true);
bool useMatFromModules = param->GetBool("UseMaterialsFromWorkbenches", true);
bool useMatFromConfigDir = param->GetBool("UseMaterialsFromConfigDir", true);
bool useMatFromCustomDir = param->GetBool("UseMaterialsFromCustomDir", true);
if (useBuiltInMaterials) {
QString resourceDir = QString::fromStdString(App::Application::getResourceDir()
+ "/Mod/Material/Resources/Materials");
auto libData = new MaterialLibrary(QString::fromStdString("System"),
resourceDir,
QString::fromStdString(":/icons/freecad.svg"),
true);
_libraryList->push_back(libData);
}
if (useMatFromModules) {
auto moduleParam = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Resources/Modules");
for (auto& group : moduleParam->GetGroups()) {
// auto module = moduleParam->GetGroup(group->GetGroupName());
auto moduleName = QString::fromStdString(group->GetGroupName());
auto materialDir = QString::fromStdString(group->GetASCII("ModuleDir", ""));
auto materialIcon = QString::fromStdString(group->GetASCII("ModuleIcon", ""));
auto materialReadOnly = group->GetBool("ModuleReadOnly", true);
if (materialDir.length() > 0) {
QDir dir(materialDir);
if (dir.exists()) {
auto libData = new MaterialLibrary(moduleName,
materialDir,
materialIcon,
materialReadOnly);
_libraryList->push_back(libData);
}
}
}
}
if (useMatFromConfigDir) {
QString resourceDir =
QString::fromStdString(App::Application::getUserAppDataDir() + "/Material");
if (!resourceDir.isEmpty()) {
QDir materialDir(resourceDir);
if (materialDir.exists()) {
auto libData =
new MaterialLibrary(QString::fromStdString("User"),
resourceDir,
QString::fromStdString(":/icons/preferences-general.svg"),
false);
_libraryList->push_back(libData);
}
}
}
if (useMatFromCustomDir) {
QString resourceDir = QString::fromStdString(param->GetASCII("CustomMaterialsDir", ""));
if (!resourceDir.isEmpty()) {
QDir materialDir(resourceDir);
if (materialDir.exists()) {
auto libData = new MaterialLibrary(QString::fromStdString("Custom"),
resourceDir,
QString::fromStdString(":/icons/user.svg"),
false);
_libraryList->push_back(libData);
}
}
}
return _libraryList;
}
std::list<QString>* MaterialLoader::getMaterialFolders(const MaterialLibrary& library)
{
std::list<QString>* pathList = new std::list<QString>();
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
while (it.hasNext()) {
auto pathname = it.next();
QFileInfo file(pathname);
if (file.isDir()) {
QString path = QDir(library.getDirectory()).relativeFilePath(file.absoluteFilePath());
if (!path.startsWith(QString::fromStdString("."))) {
pathList->push_back(path);
}
}
}
return pathList;
}

View File

@@ -0,0 +1,129 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALLOADER_H
#define MATERIAL_MATERIALLOADER_H
#include <QDir>
#include <QString>
#include <yaml-cpp/yaml.h>
#include "Materials.h"
#include "trim.h"
namespace Materials
{
class MaterialEntry
{
public:
MaterialEntry();
explicit MaterialEntry(const MaterialLibrary& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid);
virtual ~MaterialEntry() = default;
virtual void addToTree(std::map<QString, Material*>* materialMap) = 0;
const MaterialLibrary& getLibrary() const
{
return _library;
}
const QString getName() const
{
return _name;
}
const QString getDirectory() const
{
return _directory;
}
const QString getUUID() const
{
return _uuid;
}
protected:
MaterialLibrary _library;
QString _name;
QString _directory;
QString _uuid;
};
class MaterialYamlEntry: public MaterialEntry
{
public:
explicit MaterialYamlEntry(const MaterialLibrary& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
const YAML::Node& modelData);
~MaterialYamlEntry() override = default;
void addToTree(std::map<QString, Material*>* materialMap) override;
const YAML::Node& getModel() const
{
return _model;
}
YAML::Node* getModelPtr()
{
return &_model;
}
private:
MaterialYamlEntry();
QString
yamlValue(const YAML::Node& node, const std::string& key, const std::string& defaultValue);
YAML::Node _model;
};
class MaterialLoader
{
public:
explicit MaterialLoader(std::map<QString, Material*>* materialMap,
std::list<MaterialLibrary*>* libraryList);
virtual ~MaterialLoader();
std::list<MaterialLibrary*>* getMaterialLibraries();
static std::list<QString>* getMaterialFolders(const MaterialLibrary& library);
static void showYaml(const YAML::Node& yaml);
private:
MaterialLoader();
void addToTree(MaterialEntry* model);
void dereference(Material* material);
MaterialEntry* getMaterialFromPath(MaterialLibrary& library, const QString& path) const;
void addLibrary(MaterialLibrary* model);
void loadLibrary(MaterialLibrary& library);
void loadLibraries(void);
static std::map<QString, MaterialEntry*>* _materialEntryMap;
std::map<QString, Material*>* _materialMap;
std::list<MaterialLibrary*>* _libraryList;
};
}// namespace Materials
#endif// MATERIAL_MATERIALLOADER_H

View File

@@ -0,0 +1,273 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <QMutexLocker>
#include <App/Application.h>
#include "Exceptions.h"
#include "MaterialLoader.h"
#include "MaterialManager.h"
#include "ModelManager.h"
using namespace Materials;
/* TRANSLATOR Material::Materials */
std::list<MaterialLibrary*>* MaterialManager::_libraryList = nullptr;
std::map<QString, Material*>* MaterialManager::_materialMap = nullptr;
QMutex MaterialManager::_mutex;
TYPESYSTEM_SOURCE(Materials::MaterialManager, Base::BaseClass)
MaterialManager::MaterialManager()
{
// TODO: Add a mutex or similar
initLibraries();
}
void MaterialManager::initLibraries()
{
QMutexLocker locker(&_mutex);
if (_materialMap == nullptr) {
// Load the models first
ModelManager* manager = new ModelManager();
Q_UNUSED(manager)
delete manager;
_materialMap = new std::map<QString, Material*>();
if (_libraryList == nullptr) {
_libraryList = new std::list<MaterialLibrary*>();
}
// Load the libraries
MaterialLoader loader(_materialMap, _libraryList);
}
}
void MaterialManager::saveMaterial(MaterialLibrary* library,
Material& material,
const QString& path,
bool saveAsCopy)
{
Material* newMaterial = library->saveMaterial(material, path, saveAsCopy);
try {
Material* old = _materialMap->at(newMaterial->getUUID());
if (old) {
delete old;
}
}
catch (const std::out_of_range&) {
}
(*_materialMap)[material.getUUID()] = newMaterial;
}
bool MaterialManager::isMaterial(const fs::path& p)
{
if (!fs::is_regular_file(p)) {
return false;
}
// check file extension
if (p.extension() == ".FCMat") {
return true;
}
return false;
}
const Material& MaterialManager::getMaterial(const QString& uuid) const
{
try {
return *(_materialMap->at(uuid));
}
catch (std::out_of_range& e) {
throw MaterialNotFound();
}
}
const Material& MaterialManager::getMaterialByPath(const QString& path) const
{
QString cleanPath = QDir::cleanPath(path);
for (auto library : *_libraryList) {
Base::Console().Log("MaterialManager::getMaterialByPath() Checking library '%s'->'%s'\n",
library->getName().toStdString().c_str(),
library->getDirectory().toStdString().c_str());
if (cleanPath.startsWith(library->getDirectory())) {
Base::Console().Log("MaterialManager::getMaterialByPath() Library '%s'\n",
library->getDirectory().toStdString().c_str());
Base::Console().Log("MaterialManager::getMaterialByPath() Path '%s'\n",
cleanPath.toStdString().c_str());
return library->getMaterialByPath(cleanPath);
}
}
Base::Console().Log("MaterialManager::getMaterialByPath() Library not found for path '%s'\n",
cleanPath.toStdString().c_str());
throw MaterialNotFound();
}
const Material& MaterialManager::getMaterialByPath(const QString& path, const QString& lib) const
{
auto library = getLibrary(lib); // May throw LibraryNotFound
return library->getMaterialByPath(path);// May throw MaterialNotFound
}
MaterialLibrary* MaterialManager::getLibrary(const QString& name) const
{
for (auto library : *_libraryList) {
if (library->getName() == name) {
return library;
}
}
throw LibraryNotFound();
}
std::list<MaterialLibrary*>* MaterialManager::getMaterialLibraries()
{
if (_libraryList == nullptr) {
if (_materialMap == nullptr) {
_materialMap = new std::map<QString, Material*>();
}
_libraryList = new std::list<MaterialLibrary*>();
// Load the libraries
MaterialLoader loader(_materialMap, _libraryList);
}
return _libraryList;
}
std::map<QString, MaterialTreeNode*>*
MaterialManager::getMaterialTree(const MaterialLibrary& library)
{
std::map<QString, MaterialTreeNode*>* materialTree = new std::map<QString, MaterialTreeNode*>();
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
auto filename = it->first;
auto material = it->second;
if (material->getLibrary() == library) {
fs::path path = material->getDirectory().toStdString();
// Start at the root
std::map<QString, MaterialTreeNode*>* node = materialTree;
for (auto itp = path.begin(); itp != path.end(); itp++) {
if (QString::fromStdString(itp->string())
.endsWith(QString::fromStdString(".FCMat"))) {
MaterialTreeNode* child = new MaterialTreeNode();
child->setData(material);
(*node)[QString::fromStdString(itp->string())] = child;
}
else {
// Add the folder only if it's not already there
QString folderName = QString::fromStdString(itp->string());
std::map<QString, MaterialTreeNode*>* mapPtr;
if (node->count(folderName) == 0) {
mapPtr = new std::map<QString, MaterialTreeNode*>();
MaterialTreeNode* child = new MaterialTreeNode();
child->setFolder(mapPtr);
(*node)[folderName] = child;
node = mapPtr;
}
else {
node = (*node)[folderName]->getFolder();
}
}
}
}
}
std::list<QString>* folderList = getMaterialFolders(library);
for (auto folder : *folderList) {
fs::path path = folder.toStdString();
// Start at the root
std::map<QString, MaterialTreeNode*>* node = materialTree;
for (auto itp = path.begin(); itp != path.end(); itp++) {
// Add the folder only if it's not already there
QString folderName = QString::fromStdString(itp->string());
if (node->count(folderName) == 0) {
std::map<QString, MaterialTreeNode*>* mapPtr =
new std::map<QString, MaterialTreeNode*>();
MaterialTreeNode* child = new MaterialTreeNode();
child->setFolder(mapPtr);
(*node)[folderName] = child;
node = mapPtr;
}
else {
node = (*node)[folderName]->getFolder();
}
}
}
delete folderList;
return materialTree;
}
std::list<QString>* MaterialManager::getMaterialFolders(const MaterialLibrary& library)
{
return MaterialLoader::getMaterialFolders(library);
}
std::map<QString, Material*>* MaterialManager::materialsWithModel(QString uuid)
{
std::map<QString, Material*>* dict = new std::map<QString, Material*>();
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
QString key = it->first;
Material* material = it->second;
if (material->hasModel(uuid)) {
(*dict)[key] = material;
}
}
return dict;
}
std::map<QString, Material*>* MaterialManager::materialsWithModelComplete(QString uuid)
{
std::map<QString, Material*>* dict = new std::map<QString, Material*>();
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
QString key = it->first;
Material* material = it->second;
if (material->isModelComplete(uuid)) {
(*dict)[key] = material;
}
}
return dict;
}

View File

@@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALMANAGER_H
#define MATERIAL_MATERIALMANAGER_H
#include <QMutex>
#include <boost/filesystem.hpp>
#include "FolderTree.h"
#include "Materials.h"
namespace fs = boost::filesystem;
namespace Materials
{
typedef FolderTreeNode<Material> MaterialTreeNode;
class MaterialsExport MaterialManager: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
MaterialManager();
virtual ~MaterialManager() = default;
std::map<QString, Material*>* getMaterials()
{
return _materialMap;
}
const Material& getMaterial(const QString& uuid) const;
const Material& getMaterialByPath(const QString& path) const;
const Material& getMaterialByPath(const QString& path, const QString& library) const;
MaterialLibrary* getLibrary(const QString& name) const;
// Library management
static std::list<MaterialLibrary*>* getMaterialLibraries();
std::map<QString, MaterialTreeNode*>* getMaterialTree(const MaterialLibrary& library);
std::list<QString>* getMaterialFolders(const MaterialLibrary& library);
void createPath(MaterialLibrary* library, const QString& path)
{
library->createPath(path);
}
void saveMaterial(MaterialLibrary* library,
Material& material,
const QString& path,
bool saveAsCopy = true);
static bool isMaterial(const fs::path& p);
std::map<QString, Material*>* materialsWithModel(QString uuid);
std::map<QString, Material*>* materialsWithModelComplete(QString uuid);
private:
static std::list<MaterialLibrary*>* _libraryList;
static std::map<QString, Material*>* _materialMap;
static QMutex _mutex;
static void initLibraries();
};
}// namespace Materials
#endif// MATERIAL_MATERIALMANAGER_H

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateMaterial xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaMaterial_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="MaterialManagerPy"
Twin="MaterialManager"
TwinPointer="MaterialManager"
Include="Mod/Material/App/MaterialManager.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material descriptions.</UserDocu>
</Documentation>
<Methode Name="getMaterial">
<Documentation>
<UserDocu>Get a material object by specifying its UUID</UserDocu>
</Documentation>
</Methode>
<Methode Name="getMaterialByPath">
<Documentation>
<UserDocu>Get a material object by specifying its path and library name</UserDocu>
</Documentation>
</Methode>
<Attribute Name="MaterialLibraries" ReadOnly="true">
<Documentation>
<UserDocu>List of Material libraries.</UserDocu>
</Documentation>
<Parameter Name="MaterialLibraries" Type="List"/>
</Attribute>
<Attribute Name="Materials" ReadOnly="true">
<Documentation>
<UserDocu>List of Materials.</UserDocu>
</Documentation>
<Parameter Name="Materials" Type="Dict"/>
</Attribute>
<Methode Name="materialsWithModel">
<Documentation>
<UserDocu>Get a list of materials implementing the specified model</UserDocu>
</Documentation>
</Methode>
<Methode Name="materialsWithModelComplete">
<Documentation>
<UserDocu>Get a list of materials implementing the specified model, with values for all properties</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateMaterial>

View File

@@ -0,0 +1,204 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include "Exceptions.h"
#include "MaterialManager.h"
#include "MaterialManagerPy.h"
#include "MaterialPy.h"
#include "Materials.h"
#include "MaterialManagerPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string MaterialManagerPy::representation() const
{
std::stringstream str;
str << "<MaterialManager object at " << getMaterialManagerPtr() << ">";
return str.str();
}
PyObject* MaterialManagerPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new MaterialManagerPy(new MaterialManager());
}
// constructor method
int MaterialManagerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
PyObject* MaterialManagerPy::getMaterial(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
try {
const Material& material =
getMaterialManagerPtr()->getMaterial(QString::fromStdString(uuid));
return new MaterialPy(new Material(material));
}
catch (const MaterialNotFound&) {
PyErr_SetString(PyExc_LookupError, "Material not found");
return nullptr;
}
}
PyObject* MaterialManagerPy::getMaterialByPath(PyObject* args)
{
char* path;
char* lib = "";
if (!PyArg_ParseTuple(args, "s|s", &path, &lib)) {
return nullptr;
}
QString libPath(QString::fromStdString(lib));
if (!libPath.isEmpty()) {
try {
const Material& material =
getMaterialManagerPtr()->getMaterialByPath(QString::fromStdString(path), libPath);
return new MaterialPy(new Material(material));
}
catch (const MaterialNotFound&) {
PyErr_SetString(PyExc_LookupError, "Material not found");
return nullptr;
}
catch (const LibraryNotFound&) {
PyErr_SetString(PyExc_LookupError, "Library not found");
return nullptr;
}
}
try {
const Material& material =
getMaterialManagerPtr()->getMaterialByPath(QString::fromStdString(path));
return new MaterialPy(new Material(material));
}
catch (const MaterialNotFound&) {
PyErr_SetString(PyExc_LookupError, "Material not found");
return nullptr;
}
}
Py::List MaterialManagerPy::getMaterialLibraries() const
{
std::list<MaterialLibrary*>* libraries = getMaterialManagerPtr()->getMaterialLibraries();
Py::List list;
for (auto it = libraries->begin(); it != libraries->end(); it++) {
MaterialLibrary* lib = *it;
Py::Tuple libTuple(3);
libTuple.setItem(0, Py::String(lib->getName().toStdString()));
libTuple.setItem(1, Py::String(lib->getDirectoryPath().toStdString()));
libTuple.setItem(2, Py::String(lib->getIconPath().toStdString()));
list.append(libTuple);
}
return list;
}
Py::Dict MaterialManagerPy::getMaterials() const
{
Py::Dict dict;
std::map<QString, Material*>* materials = getMaterialManagerPtr()->getMaterials();
for (auto it = materials->begin(); it != materials->end(); it++) {
QString key = it->first;
Material* material = it->second;
PyObject* materialPy = new MaterialPy(new Material(*material));
dict.setItem(Py::String(key.toStdString()), Py::Object(materialPy, true));
}
// return Py::new_reference_to(dict);
return dict;
}
PyObject* MaterialManagerPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int MaterialManagerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}
PyObject* MaterialManagerPy::materialsWithModel(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
std::map<QString, Material*>* materials =
getMaterialManagerPtr()->materialsWithModel(QString::fromStdString(uuid));
PyObject* dict = PyDict_New();
for (auto it = materials->begin(); it != materials->end(); it++) {
QString key = it->first;
Material* material = it->second;
PyObject* materialPy = new MaterialPy(new Material(*material));
PyDict_SetItem(dict, PyUnicode_FromString(key.toStdString().c_str()), materialPy);
}
delete materials;
return dict;
}
PyObject* MaterialManagerPy::materialsWithModelComplete(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
std::map<QString, Material*>* materials =
getMaterialManagerPtr()->materialsWithModelComplete(QString::fromStdString(uuid));
PyObject* dict = PyDict_New();
for (auto it = materials->begin(); it != materials->end(); it++) {
QString key = it->first;
Material* material = it->second;
PyObject* materialPy = new MaterialPy(new Material(*material));
PyDict_SetItem(dict, PyUnicode_FromString(key.toStdString().c_str()), materialPy);
}
delete materials;
return dict;
}

View File

@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="MaterialPy"
Twin="Material"
TwinPointer="Material"
Include="Mod/Material/App/Materials.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material descriptions.</UserDocu>
</Documentation>
<Attribute Name="LibraryName" ReadOnly="true">
<Documentation>
<UserDocu>Model library name.</UserDocu>
</Documentation>
<Parameter Name="LibraryName" Type="String"/>
</Attribute>
<Attribute Name="LibraryRoot" ReadOnly="true">
<Documentation>
<UserDocu>Model library path.</UserDocu>
</Documentation>
<Parameter Name="LibraryRoot" Type="String"/>
</Attribute>
<Attribute Name="LibraryIcon" ReadOnly="true">
<Documentation>
<UserDocu>Model icon path.</UserDocu>
</Documentation>
<Parameter Name="LibraryIcon" Type="String"/>
</Attribute>
<Attribute Name="Name" ReadOnly="true">
<Documentation>
<UserDocu>Model name.</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Directory" ReadOnly="true">
<Documentation>
<UserDocu>Model directory relative to the library root.</UserDocu>
</Documentation>
<Parameter Name="Directory" Type="String"/>
</Attribute>
<Attribute Name="UUID" ReadOnly="true">
<Documentation>
<UserDocu>Unique model identifier.</UserDocu>
</Documentation>
<Parameter Name="UUID" Type="String"/>
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Documentation>
<UserDocu>Description of the material.</UserDocu>
</Documentation>
<Parameter Name="Description" Type="String"/>
</Attribute>
<Attribute Name="URL" ReadOnly="true">
<Documentation>
<UserDocu>URL to a material reference.</UserDocu>
</Documentation>
<Parameter Name="URL" Type="String"/>
</Attribute>
<Attribute Name="Reference" ReadOnly="true">
<Documentation>
<UserDocu>Reference for material data.</UserDocu>
</Documentation>
<Parameter Name="Reference" Type="String"/>
</Attribute>
<Attribute Name="Parent" ReadOnly="true">
<Documentation>
<UserDocu>Parent material UUID.</UserDocu>
</Documentation>
<Parameter Name="Parent" Type="String"/>
</Attribute>
<Attribute Name="AuthorAndLicense" ReadOnly="true">
<Documentation>
<UserDocu>Author and license information.</UserDocu>
</Documentation>
<Parameter Name="AuthorAndLicense" Type="String"/>
</Attribute>
<Attribute Name="PhysicalModels" ReadOnly="true">
<Documentation>
<UserDocu>List of implemented models.</UserDocu>
</Documentation>
<Parameter Name="PhysicalModels" Type="List"/>
</Attribute>
<Attribute Name="AppearanceModels" ReadOnly="true">
<Documentation>
<UserDocu>List of implemented models.</UserDocu>
</Documentation>
<Parameter Name="AppearanceModels" Type="List"/>
</Attribute>
<Attribute Name="Tags" ReadOnly="true">
<Documentation>
<UserDocu>List of searchable tags.</UserDocu>
</Documentation>
<Parameter Name="Tags" Type="List"/>
</Attribute>
<Methode Name="hasPhysicalModel" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the physical model with the given UUID</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasAppearanceModel" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the appearance model with the given UUID</UserDocu>
</Documentation>
</Methode>
<Methode Name="isPhysicalModelComplete" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the physical model with the given UUID, and has values defined for each property</UserDocu>
</Documentation>
</Methode>
<Methode Name="isAppearanceModelComplete" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the appearance model with the given UUID, and has values defined for each property</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasPhysicalProperty" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the physical property with the given name</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasAppearanceProperty" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the appearance property with the given name</UserDocu>
</Documentation>
</Methode>
<Attribute Name="Properties" ReadOnly="true">
<Documentation>
<UserDocu>deprecated -- Dictionary of all material properties.</UserDocu>
</Documentation>
<Parameter Name="Properties" Type="Dict"/>
</Attribute>
<Attribute Name="PhysicalProperties" ReadOnly="true">
<Documentation>
<UserDocu>deprecated -- Dictionary of material physical properties.</UserDocu>
</Documentation>
<Parameter Name="PhysicalProperties" Type="Dict"/>
</Attribute>
<Attribute Name="AppearanceProperties" ReadOnly="true">
<Documentation>
<UserDocu>deprecated -- Dictionary of material appearance properties.</UserDocu>
</Documentation>
<Parameter Name="AppearanceProperties" Type="Dict"/>
</Attribute>
<Methode Name="getPhysicalValue" ReadOnly="true">
<Documentation>
<UserDocu>Get the value associated with the property</UserDocu>
</Documentation>
</Methode>
<Methode Name="getAppearanceValue" ReadOnly="true">
<Documentation>
<UserDocu>Get the value associated with the property</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,395 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include <QMetaType>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
#include <Gui/MetaTypes.h>
#include "Exceptions.h"
#include "MaterialPy.h"
#include "Materials.h"
#include "MaterialPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string MaterialPy::representation() const
{
MaterialPy::PointerType ptr = getMaterialPtr();
std::stringstream str;
str << "Property [Name=(";
str << ptr->getName().toStdString();
str << "), UUID=(";
str << ptr->getUUID().toStdString();
str << "), Library Name=(";
str << ptr->getLibrary().getName().toStdString();
str << "), Library Root=(";
str << ptr->getLibrary().getDirectoryPath().toStdString();
str << "), Library Icon=(";
str << ptr->getLibrary().getIconPath().toStdString();
str << "), Directory=(";
str << ptr->getDirectory().toStdString();
// str << "), URL=(";
// str << ptr->getURL();
// str << "), DOI=(";
// str << ptr->getDOI();
// str << "), Description=(";
// str << ptr->getDescription();
// str << "), Inherits=[";
// const std::vector<std::string> &inherited = getMaterialPtr()->getInheritance();
// for (auto it = inherited.begin(); it != inherited.end(); it++)
// {
// std::string uuid = *it;
// if (it != inherited.begin())
// str << "), UUID=(";
// else
// str << "UUID=(";
// str << uuid << ")";
// }
// str << "]]";
str << ")]";
return str.str();
}
PyObject* MaterialPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new MaterialPy(new Material());
}
// constructor method
int MaterialPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::String MaterialPy::getLibraryName() const
{
return Py::String(getMaterialPtr()->getLibrary().getName().toStdString());
}
Py::String MaterialPy::getLibraryRoot() const
{
return Py::String(getMaterialPtr()->getLibrary().getDirectoryPath().toStdString());
}
Py::String MaterialPy::getLibraryIcon() const
{
return Py::String(getMaterialPtr()->getLibrary().getIconPath().toStdString());
}
Py::String MaterialPy::getName() const
{
return Py::String(getMaterialPtr()->getName().toStdString());
}
Py::String MaterialPy::getDirectory() const
{
return Py::String(getMaterialPtr()->getDirectory().toStdString());
}
Py::String MaterialPy::getUUID() const
{
return Py::String(getMaterialPtr()->getUUID().toStdString());
}
Py::String MaterialPy::getDescription() const
{
return Py::String(getMaterialPtr()->getDescription().toStdString());
}
Py::String MaterialPy::getURL() const
{
return Py::String(getMaterialPtr()->getURL().toStdString());
}
Py::String MaterialPy::getReference() const
{
return Py::String(getMaterialPtr()->getReference().toStdString());
}
Py::String MaterialPy::getParent() const
{
return Py::String(getMaterialPtr()->getParentUUID().toStdString());
}
Py::String MaterialPy::getAuthorAndLicense() const
{
return Py::String(getMaterialPtr()->getAuthorAndLicense().toStdString());
}
Py::List MaterialPy::getPhysicalModels() const
{
const std::vector<QString>* models = getMaterialPtr()->getPhysicalModels();
Py::List list;
for (auto it = models->begin(); it != models->end(); it++) {
QString uuid = *it;
list.append(Py::String(uuid.toStdString()));
}
return list;
}
Py::List MaterialPy::getAppearanceModels() const
{
const std::vector<QString>* models = getMaterialPtr()->getAppearanceModels();
Py::List list;
for (auto it = models->begin(); it != models->end(); it++) {
QString uuid = *it;
list.append(Py::String(uuid.toStdString()));
}
return list;
}
Py::List MaterialPy::getTags() const
{
const std::list<QString>& tags = getMaterialPtr()->getTags();
Py::List list;
for (auto it = tags.begin(); it != tags.end(); it++) {
QString uuid = *it;
list.append(Py::String(uuid.toStdString()));
}
return list;
}
PyObject* MaterialPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int MaterialPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}
PyObject* MaterialPy::hasPhysicalModel(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
bool hasProperty = getMaterialPtr()->hasPhysicalModel(QString::fromStdString(uuid));
return hasProperty ? Py_True : Py_False;
}
PyObject* MaterialPy::hasAppearanceModel(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
bool hasProperty = getMaterialPtr()->hasAppearanceModel(QString::fromStdString(uuid));
return hasProperty ? Py_True : Py_False;
}
PyObject* MaterialPy::isPhysicalModelComplete(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
bool isComplete = getMaterialPtr()->isPhysicalModelComplete(QString::fromStdString(name));
return isComplete ? Py_True : Py_False;
}
PyObject* MaterialPy::isAppearanceModelComplete(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
bool isComplete = getMaterialPtr()->isAppearanceModelComplete(QString::fromStdString(name));
return isComplete ? Py_True : Py_False;
}
PyObject* MaterialPy::hasPhysicalProperty(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
bool hasProperty = getMaterialPtr()->hasPhysicalProperty(QString::fromStdString(name));
return hasProperty ? Py_True : Py_False;
}
PyObject* MaterialPy::hasAppearanceProperty(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
bool hasProperty = getMaterialPtr()->hasAppearanceProperty(QString::fromStdString(name));
return hasProperty ? Py_True : Py_False;
}
Py::Dict MaterialPy::getProperties() const
{
Py::Dict dict;
// Maintain backwards compatibility
dict.setItem(Py::String("CardName"), Py::String(getMaterialPtr()->getName().toStdString()));
dict.setItem(Py::String("AuthorAndLicense"),
Py::String(getMaterialPtr()->getAuthorAndLicense().toStdString()));
dict.setItem(Py::String("Name"), Py::String(getMaterialPtr()->getName().toStdString()));
dict.setItem(Py::String("Description"),
Py::String(getMaterialPtr()->getDescription().toStdString()));
dict.setItem(Py::String("ReferenceSource"),
Py::String(getMaterialPtr()->getReference().toStdString()));
dict.setItem(Py::String("SourceURL"), Py::String(getMaterialPtr()->getURL().toStdString()));
auto properties = getMaterialPtr()->getPhysicalProperties();
for (auto it = properties.begin(); it != properties.end(); it++) {
QString key = it->first;
MaterialProperty& materialProperty = it->second;
if (!materialProperty.isNull()) {
auto value = materialProperty.getString();
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
}
}
properties = getMaterialPtr()->getAppearanceProperties();
for (auto it = properties.begin(); it != properties.end(); it++) {
QString key = it->first;
MaterialProperty& materialProperty = it->second;
if (!materialProperty.isNull()) {
auto value = materialProperty.getString();
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
}
}
return dict;
}
Py::Dict MaterialPy::getPhysicalProperties() const
{
Py::Dict dict;
auto properties = getMaterialPtr()->getPhysicalProperties();
for (auto it = properties.begin(); it != properties.end(); it++) {
QString key = it->first;
MaterialProperty& materialProperty = it->second;
if (!materialProperty.isNull()) {
auto value = materialProperty.getString();
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
}
}
return dict;
}
Py::Dict MaterialPy::getAppearanceProperties() const
{
Py::Dict dict;
auto properties = getMaterialPtr()->getAppearanceProperties();
for (auto it = properties.begin(); it != properties.end(); it++) {
QString key = it->first;
MaterialProperty& materialProperty = it->second;
if (!materialProperty.isNull()) {
auto value = materialProperty.getString();
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
}
}
return dict;
}
static PyObject* _pyObjectFromVariant(const QVariant& value)
{
if (value.isNull()) {
return new PyObject();
}
if (value.userType() == QMetaType::type("Base::Quantity")) {
return new Base::QuantityPy(new Base::Quantity(value.value<Base::Quantity>()));
}
else if (value.userType() == QMetaType::Double) {
return PyFloat_FromDouble(value.toDouble());
}
else if (value.userType() == QMetaType::Float) {
return PyFloat_FromDouble(value.toFloat());
}
else if (value.userType() == QMetaType::Int) {
return PyLong_FromLong(value.toInt());
}
else if (value.userType() == QMetaType::Long) {
return PyLong_FromLong(value.toInt());
}
else if (value.userType() == QMetaType::Bool) {
return value.toBool() ? Py_True : Py_False;
}
else if (value.userType() == QMetaType::QString) {
return PyUnicode_FromString(value.toString().toStdString().c_str());
}
throw UnknownValueType();
}
PyObject* MaterialPy::getPhysicalValue(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
QVariant value = getMaterialPtr()->getPhysicalValue(QString::fromStdString(name));
return _pyObjectFromVariant(value);
}
PyObject* MaterialPy::getAppearanceValue(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
QVariant value = getMaterialPtr()->getAppearanceValue(QString::fromStdString(name));
return _pyObjectFromVariant(value);
}

View File

@@ -0,0 +1,243 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <App/Application.h>
#include "Exceptions.h"
#include "MaterialValue.h"
using namespace Materials;
/* TRANSLATOR Material::MaterialValue */
MaterialValue::MaterialValue()
: _valueType(None)
{}
MaterialValue::MaterialValue(ValueType type)
: _valueType(type)
{}
//===
Material2DArray::Material2DArray()
: MaterialValue(Array2D)
, _defaultSet(false)
{}
MaterialValue Material2DArray::getDefault() const
{
MaterialValue ret(_valueType);
ret.setValue(_value);
return ret;
}
const std::vector<QVariant>* Material2DArray::getRow(int row) const
{
try {
return _rows.at(row);
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
std::vector<QVariant>* Material2DArray::getRow(int row)
{
try {
return _rows.at(row);
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
void Material2DArray::addRow(std::vector<QVariant>* row)
{
_rows.push_back(row);
}
void Material2DArray::insertRow(int index, std::vector<QVariant>* row)
{
_rows.insert(_rows.begin() + index, row);
}
void Material2DArray::deleteRow(int row)
{
if (static_cast<std::size_t>(row) >= _rows.size() || row < 0) {
throw InvalidRow();
}
_rows.erase(_rows.begin() + row);
}
void Material2DArray::setValue(int row, int column, const QVariant& value)
{
if (row >= rows()) {
throw InvalidIndex();
}
std::vector<QVariant>* val = getRow(row);
try {
val->at(column) = value;
}
catch (const std::out_of_range&) {
throw InvalidIndex();
}
}
const QVariant Material2DArray::getValue(int row, int column)
{
try {
auto val = getRow(row);
try {
return val->at(column);
}
catch (std::out_of_range const&) {
throw InvalidIndex();
}
}
catch (const InvalidRow&) {
throw InvalidIndex();
}
}
void Material2DArray::dumpRow(const std::vector<QVariant>& row) const
{
Base::Console().Log("row: ");
for (auto column : row) {
Base::Console().Log("'%s' ", column.toString().toStdString().c_str());
}
Base::Console().Log("\n");
}
void Material2DArray::dump() const
{
for (auto row : _rows) {
dumpRow(*row);
}
}
//===
Material3DArray::Material3DArray()
: MaterialValue(Array3D)
, _defaultSet(false)
{}
MaterialValue Material3DArray::getDefault() const
{
MaterialValue ret(_valueType);
ret.setValue(_value);
return ret;
}
const std::vector<std::vector<QVariant>*>& Material3DArray::getTable(const QVariant& depth) const
{
try {
return _rowMap.at(depth);
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
const std::vector<QVariant>& Material3DArray::getRow(const QVariant& depth, int row) const
{
try {
return *(_rowMap.at(depth).at(row));
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
const std::vector<QVariant>& Material3DArray::getRow(int row) const
{
return getRow(getDefault().getValue().toString(), row);
}
std::vector<QVariant>& Material3DArray::getRow(const QVariant& depth, int row)
{
try {
return *(_rowMap.at(depth).at(row));
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
std::vector<QVariant>& Material3DArray::getRow(int row)
{
return getRow(getDefault().getValue().toString(), row);
}
void Material3DArray::addRow(const QVariant& depth, std::vector<QVariant>* row)
{
_rowMap[depth].push_back(row);
}
void Material3DArray::deleteRow(const QVariant& depth, int row)
{
Q_UNUSED(depth)
Q_UNUSED(row)
}
void Material3DArray::deleteRows(int depth)
{
Q_UNUSED(depth)
}
void Material3DArray::setValue(const QVariant& depth, int row, int column, const QVariant& value)
{
Q_UNUSED(depth)
Q_UNUSED(row)
Q_UNUSED(column)
Q_UNUSED(value)
}
void Material3DArray::setValue(int row, int column, const QVariant& value)
{
Q_UNUSED(row)
Q_UNUSED(column)
Q_UNUSED(value)
}
const QVariant Material3DArray::getValue(const QVariant& depth, int row, int column)
{
auto val = getRow(depth, row);
try {
return val.at(column);
}
catch (std::out_of_range const&) {
throw InvalidColumn();
}
}
const QVariant Material3DArray::getValue(int row, int column)
{
return getValue(getDefault().getValue().toString(), row, column);
}

View File

@@ -0,0 +1,187 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALVALUE_H
#define MATERIAL_MATERIALVALUE_H
#include <QVariant>
namespace Materials
{
class MaterialsExport MaterialValue
{
public:
enum ValueType
{
None = 0,
String = 1,
Boolean = 2,
Integer = 3,
Float = 4,
Quantity = 5,
Distribution = 6,
List = 7,
Array2D = 8,
Array3D = 9,
Color = 10,
Image = 11,
File = 12,
URL = 13
};
MaterialValue();
explicit MaterialValue(ValueType type);
virtual ~MaterialValue() = default;
ValueType getType()
{
return _valueType;
}
const QVariant getValue(void) const
{
return _value;
}
bool isNull() const
{
return _value.isNull();
}
virtual const QVariant getValueAt(const QVariant& value) const
{
Q_UNUSED(value);
return _value;
}
void setValue(const QVariant& value)
{
_value = value;
}
protected:
ValueType _valueType;
QVariant _value;
void setType(ValueType type)
{
_valueType = type;
}
};
class MaterialsExport Material2DArray: public MaterialValue
{
public:
Material2DArray();
~Material2DArray() override = default;
void setDefault(MaterialValue value)
{
_value = value.getValue();
_defaultSet = true;
}
void setDefault(const QVariant& value)
{
_value = value;
_defaultSet = true;
}
MaterialValue getDefault() const;
bool defaultSet() const
{
return _defaultSet;
}
const std::vector<QVariant>* getRow(int row) const;
std::vector<QVariant>* getRow(int row);
int rows() const
{
return _rows.size();
}
void addRow(std::vector<QVariant>* row);
void insertRow(int index, std::vector<QVariant>* row);
void deleteRow(int row);
void setValue(int row, int column, const QVariant& value);
const QVariant getValue(int row, int column);
protected:
std::vector<std::vector<QVariant>*> _rows;
bool _defaultSet;
private:
void dumpRow(const std::vector<QVariant>& row) const;
void dump() const;
};
class MaterialsExport Material3DArray: public MaterialValue
{
public:
Material3DArray();
~Material3DArray() override = default;
void setDefault(MaterialValue value)
{
_value = value.getValue();
_defaultSet = true;
}
void setDefault(const QVariant& value)
{
_value = value;
_defaultSet = true;
}
MaterialValue getDefault() const;
bool defaultSet() const
{
return _defaultSet;
}
const std::vector<std::vector<QVariant>*>& getTable(const QVariant& depth) const;
const std::vector<QVariant>& getRow(const QVariant& depth, int row) const;
const std::vector<QVariant>& getRow(int row) const;
std::vector<QVariant>& getRow(const QVariant& depth, int row);
std::vector<QVariant>& getRow(int row);
void addRow(const QVariant& depth, std::vector<QVariant>* row);
void deleteRow(const QVariant& depth, int row);
void deleteRows(int depth);
int depth() const
{
return _rowMap.size();
}
int rows(const QVariant& depth) const
{
return getTable(depth).size();
}
void setValue(const QVariant& depth, int row, int column, const QVariant& value);
void setValue(int row, int column, const QVariant& value);
const QVariant getValue(const QVariant& depth, int row, int column);
const QVariant getValue(int row, int column);
protected:
std::map<QVariant, std::vector<std::vector<QVariant>*>> _rowMap;
bool _defaultSet;
};
}// namespace Materials
Q_DECLARE_METATYPE(Materials::MaterialValue)
Q_DECLARE_METATYPE(Materials::Material2DArray)
Q_DECLARE_METATYPE(Materials::Material3DArray)
#endif// MATERIAL_MATERIALVALUE_H

View File

@@ -0,0 +1,914 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <QMetaType>
#include <QUuid>
#include <App/Application.h>
#include <Gui/MetaTypes.h>
#include "MaterialManager.h"
#include "Materials.h"
#include "ModelManager.h"
using namespace Materials;
/* TRANSLATOR Material::Materials */
TYPESYSTEM_SOURCE(Materials::MaterialProperty, Materials::ModelProperty)
MaterialProperty::MaterialProperty()
{
_valuePtr = new MaterialValue(MaterialValue::None);
}
MaterialProperty::MaterialProperty(const ModelProperty& property)
: ModelProperty(property)
, _valuePtr(nullptr)
{
setType(getPropertyType());
auto columns = property.getColumns();
for (std::vector<ModelProperty>::const_iterator it = columns.begin(); it != columns.end();
it++) {
MaterialProperty prop(*it);
addColumn(prop);
}
if (_valuePtr->getType() == MaterialValue::Array2D) {
reinterpret_cast<Material2DArray*>(_valuePtr)->setDefault(getColumnNull(0));
}
else if (_valuePtr->getType() == MaterialValue::Array3D) {
reinterpret_cast<Material3DArray*>(_valuePtr)->setDefault(getColumnNull(0));
}
}
MaterialProperty::MaterialProperty(const MaterialProperty& other)
: ModelProperty(other)
{
_modelUUID = other._modelUUID;
if (other._valuePtr != nullptr) {
_valuePtr = new MaterialValue(*(other._valuePtr));
}
else {
_valuePtr = nullptr;
}
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
_columns.push_back(*it);
}
}
MaterialProperty::~MaterialProperty()
{}
void MaterialProperty::setModelUUID(const QString& uuid)
{
_modelUUID = uuid;
}
const QVariant MaterialProperty::getValue(void) const
{
return _valuePtr->getValue();
}
MaterialValue* MaterialProperty::getMaterialValue(void)
{
return _valuePtr;
}
const QString MaterialProperty::getString(void) const
{
if (getType() == MaterialValue::Quantity) {
Base::Quantity quantity = getValue().value<Base::Quantity>();
return quantity.getUserString();
}
return getValue().toString();
}
void MaterialProperty::setPropertyType(const QString& type)
{
ModelProperty::setPropertyType(type);
setType(type);
}
void MaterialProperty::setType(const QString& type)
{
if (_valuePtr) {
delete _valuePtr;
}
if (type == QString::fromStdString("String")) {
_valuePtr = new MaterialValue(MaterialValue::String);
}
else if (type == QString::fromStdString("Boolean")) {
_valuePtr = new MaterialValue(MaterialValue::Boolean);
}
else if (type == QString::fromStdString("Integer")) {
_valuePtr = new MaterialValue(MaterialValue::Integer);
}
else if (type == QString::fromStdString("Float")) {
_valuePtr = new MaterialValue(MaterialValue::Float);
}
else if (type == QString::fromStdString("URL")) {
_valuePtr = new MaterialValue(MaterialValue::URL);
}
else if (type == QString::fromStdString("Quantity")) {
_valuePtr = new MaterialValue(MaterialValue::Quantity);
}
else if (type == QString::fromStdString("Color")) {
_valuePtr = new MaterialValue(MaterialValue::Color);
}
else if (type == QString::fromStdString("File")) {
_valuePtr = new MaterialValue(MaterialValue::File);
}
else if (type == QString::fromStdString("Image")) {
_valuePtr = new MaterialValue(MaterialValue::Image);
}
else if (type == QString::fromStdString("List")) {
_valuePtr = new MaterialValue(MaterialValue::List);
}
else if (type == QString::fromStdString("2DArray")) {
_valuePtr = new Material2DArray();
}
else if (type == QString::fromStdString("3DArray")) {
_valuePtr = new Material3DArray();
}
else {
// Error. Throw something
_valuePtr = new MaterialValue(MaterialValue::None);
std::string stringType = type.toStdString();
std::string name = getName().toStdString();
throw UnknownValueType();
}
}
MaterialProperty& MaterialProperty::getColumn(int column)
{
try {
return _columns.at(column);
}
catch (std::out_of_range const&) {
throw InvalidColumn();
}
}
MaterialValue::ValueType MaterialProperty::getColumnType(int column) const
{
try {
return _columns.at(column).getType();
}
catch (std::out_of_range const&) {
throw InvalidColumn();
}
}
QString MaterialProperty::getColumnUnits(int column) const
{
try {
return _columns.at(column).getUnits();
}
catch (std::out_of_range const&) {
throw InvalidColumn();
}
}
QVariant MaterialProperty::getColumnNull(int column) const
{
MaterialValue::ValueType valueType = getColumnType(column);
switch (valueType) {
case MaterialValue::Quantity: {
Base::Quantity q = Base::Quantity(0, getColumnUnits(column));
return QVariant::fromValue(q);
}
case MaterialValue::Float:
case MaterialValue::Integer:
return QVariant(0);
default:
break;
}
return QVariant(QString());
}
void MaterialProperty::setValue(const QVariant& value)
{
// _valueType = MaterialValue::String;
_valuePtr->setValue(value);
}
void MaterialProperty::setValue(const QString& value)
{
if (_valuePtr->getType() == MaterialValue::Boolean) {
setBoolean(value);
}
else if (_valuePtr->getType() == MaterialValue::Integer) {
setInt(value);
}
else if (_valuePtr->getType() == MaterialValue::Float) {
setFloat(value);
}
else if (_valuePtr->getType() == MaterialValue::URL) {
setURL(value);
}
else if (_valuePtr->getType() == MaterialValue::Quantity) {
// Base::Console().Log("\tParse quantity '%s'\n", value.toStdString().c_str());
try {
setQuantity(Base::Quantity::parse(value));
}
catch (const Base::ParserError& e) {
Base::Console().Log("Error '%s'\n", e.what());
// Save as a string
setString(value);
}
}
else {
setString(value);
}
}
void MaterialProperty::setString(const QString& value)
{
// _valueType = MaterialValue::String;
_valuePtr->setValue(QVariant(value));
}
void MaterialProperty::setBoolean(bool value)
{
// _valueType = MaterialValue::Boolean;
_valuePtr->setValue(QVariant(value));
}
void MaterialProperty::setBoolean(int value)
{
// _valueType = MaterialValue::Boolean;
_valuePtr->setValue(QVariant(value != 0));
}
void MaterialProperty::setBoolean(const QString& value)
{
// _valueType = MaterialValue::Boolean;
bool boolean;
std::string val = value.toStdString();
if ((val == "true") || (val == "True")) {
boolean = true;
}
else if ((val == "false") || (val == "False")) {
boolean = false;
}
else {
boolean = (std::stoi(val) != 0);
}
setBoolean(boolean);
}
void MaterialProperty::setInt(int value)
{
_valuePtr->setValue(QVariant(value));
}
void MaterialProperty::setInt(const QString& value)
{
_valuePtr->setValue(value.toInt());
}
void MaterialProperty::setFloat(double value)
{
_valuePtr->setValue(QVariant(value));
}
void MaterialProperty::setFloat(const QString& value)
{
_valuePtr->setValue(QVariant(value.toFloat()));
}
void MaterialProperty::setQuantity(const Base::Quantity& value)
{
_valuePtr->setValue(QVariant(QVariant::fromValue(value)));
}
void MaterialProperty::setQuantity(double value, const QString& units)
{
setQuantity(Base::Quantity(value, units));
}
void MaterialProperty::setQuantity(const QString& value)
{
setQuantity(Base::Quantity::parse(value));
}
void MaterialProperty::setURL(const QString& value)
{
_valuePtr->setValue(QVariant(value));
}
MaterialProperty& MaterialProperty::operator=(const MaterialProperty& other)
{
if (this == &other) {
return *this;
}
ModelProperty::operator=(other);
_modelUUID = other._modelUUID;
delete _valuePtr;
if (other._valuePtr != nullptr) {
_valuePtr = new MaterialValue(*(other._valuePtr));
}
else {
_valuePtr = nullptr;
}
_columns.clear();
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
_columns.push_back(*it);
}
return *this;
}
TYPESYSTEM_SOURCE(Materials::Material, Base::BaseClass)
Material::Material()
: _dereferenced(false)
{}
Material::Material(const MaterialLibrary& library,
const QString& directory,
const QString& uuid,
const QString& name)
: _library(library)
, _uuid(uuid)
, _name(name)
, _dereferenced(false)
, _editState(ModelEdit_None)
{
setDirectory(directory);
}
Material::Material(const Material& other)
: _library(other._library)
, _directory(other._directory)
, _uuid(other._uuid)
, _name(other._name)
, _authorAndLicense(other._authorAndLicense)
, _parentUuid(other._parentUuid)
, _description(other._description)
, _url(other._url)
, _reference(other._reference)
, _dereferenced(other._dereferenced)
, _editState(other._editState)
{
for (auto it = other._tags.begin(); it != other._tags.end(); it++) {
_tags.push_back(*it);
}
for (auto it = other._physicalUuids.begin(); it != other._physicalUuids.end(); it++) {
_physicalUuids.push_back(*it);
}
for (auto it = other._appearanceUuids.begin(); it != other._appearanceUuids.end(); it++) {
_appearanceUuids.push_back(*it);
}
for (auto it = other._allUuids.begin(); it != other._allUuids.end(); it++) {
_allUuids.push_back(*it);
}
for (auto it = other._physical.begin(); it != other._physical.end(); it++) {
_physical[it->first] = MaterialProperty(it->second);
}
for (auto it = other._appearance.begin(); it != other._appearance.end(); it++) {
_appearance[it->first] = MaterialProperty(it->second);
}
}
/*
* Destroys the object and frees any allocated resources
*/
Material::~Material()
{
// no need to delete child widgets, Qt does it all for us
}
void Material::addModel(const QString& uuid)
{
for (QString modelUUID : _allUuids) {
if (modelUUID == uuid) {
return;
}
}
_allUuids.push_back(uuid);
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
auto inheritance = model.getInheritance();
for (auto inherits = inheritance.begin(); inherits != inheritance.end(); inherits++) {
addModel(*inherits);
}
}
catch (ModelNotFound const&) {
}
}
void Material::setEditState(ModelEdit newState)
{
if (newState == ModelEdit_Extend) {
if (_editState != ModelEdit_Alter) {
_editState = newState;
}
}
else if (newState == ModelEdit_Alter) {
_editState = newState;
}
}
void Material::addPhysical(const QString& uuid)
{
if (hasPhysicalModel(uuid)) {
return;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
_physicalUuids.push_back(uuid);
addModel(uuid);
setEditStateExtend();
for (auto it = model.begin(); it != model.end(); it++) {
QString propertyName = it->first;
ModelProperty property = static_cast<ModelProperty>(it->second);
try {
_physical[propertyName] = MaterialProperty(property);
}
catch (const UnknownValueType&) {
Base::Console().Error("Property '%s' has unknown type '%s'. Ignoring\n",
property.getName().toStdString().c_str(),
property.getPropertyType().toStdString().c_str());
}
}
}
catch (ModelNotFound const&) {
}
}
void Material::addAppearance(const QString& uuid)
{
if (hasAppearanceModel(uuid)) {
return;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
_appearanceUuids.push_back(uuid);
addModel(uuid);
setEditStateExtend();
for (auto it = model.begin(); it != model.end(); it++) {
QString propertyName = it->first;
ModelProperty property = static_cast<ModelProperty>(it->second);
_appearance[propertyName] = MaterialProperty(property);
}
}
catch (ModelNotFound const&) {
}
}
void Material::setPhysicalEditState(const QString& name)
{
if (getPhysicalProperty(name).isNull()) {
setEditStateExtend();
}
else {
setEditStateAlter();
}
}
void Material::setAppearanceEditState(const QString& name)
{
if (getAppearanceProperty(name).isNull()) {
setEditStateExtend();
}
else {
setEditStateAlter();
}
}
void Material::setPhysicalValue(const QString& name, const QString& value)
{
setPhysicalEditState(name);
_physical[name].setValue(value);// may not be a string type
}
void Material::setPhysicalValue(const QString& name, int value)
{
setPhysicalEditState(name);
_physical[name].setInt(value);
}
void Material::setPhysicalValue(const QString& name, double value)
{
setPhysicalEditState(name);
_physical[name].setFloat(value);
}
void Material::setPhysicalValue(const QString& name, const Base::Quantity value)
{
setPhysicalEditState(name);
_physical[name].setQuantity(value);
}
void Material::setAppearanceValue(const QString& name, const QString& value)
{
setAppearanceEditState(name);
_appearance[name].setValue(value);// may not be a string type
}
MaterialProperty& Material::getPhysicalProperty(const QString& name)
{
try {
return _physical.at(name);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const MaterialProperty& Material::getPhysicalProperty(const QString& name) const
{
try {
return _physical.at(name);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
MaterialProperty& Material::getAppearanceProperty(const QString& name)
{
try {
return _appearance.at(name);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const MaterialProperty& Material::getAppearanceProperty(const QString& name) const
{
try {
return _appearance.at(name);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const QVariant Material::getValue(const std::map<QString, MaterialProperty>& propertyList,
const QString& name) const
{
try {
return propertyList.at(name).getValue();
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const QString Material::getValueString(const std::map<QString, MaterialProperty>& propertyList,
const QString& name) const
{
try {
if (propertyList.at(name).getType() == MaterialValue::Quantity) {
auto value = propertyList.at(name).getValue();
if (value.isNull()) {
return QString();
}
return value.value<Base::Quantity>().getUserString();
}
return propertyList.at(name).getValue().toString();
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const QVariant Material::getPhysicalValue(const QString& name) const
{
return getValue(_physical, name);
}
const QString Material::getPhysicalValueString(const QString& name) const
{
return getValueString(_physical, name);
}
const QVariant Material::getAppearanceValue(const QString& name) const
{
return getValue(_appearance, name);
}
const QString Material::getAppearanceValueString(const QString& name) const
{
return getValueString(_appearance, name);
}
bool Material::hasPhysicalProperty(const QString& name) const
{
try {
static_cast<void>(_physical.at(name));
}
catch (std::out_of_range const&) {
return false;
}
return true;
}
bool Material::hasAppearanceProperty(const QString& name) const
{
try {
static_cast<void>(_appearance.at(name));
}
catch (std::out_of_range const&) {
return false;
}
return true;
}
bool Material::hasModel(const QString& uuid) const
{
for (QString modelUUID : _allUuids) {
if (modelUUID == uuid) {
return true;
}
}
return false;
}
bool Material::hasPhysicalModel(const QString& uuid) const
{
if (!hasModel(uuid)) {
return false;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
if (model.getType() == Model::ModelType_Physical) {
return true;
}
}
catch (ModelNotFound const&) {
}
return false;
}
bool Material::hasAppearanceModel(const QString& uuid) const
{
if (!hasModel(uuid)) {
return false;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
if (model.getType() == Model::ModelType_Appearance) {
return true;
}
}
catch (ModelNotFound const&) {
}
return false;
}
bool Material::isPhysicalModelComplete(const QString& uuid) const
{
if (!hasPhysicalModel(uuid)) {
return false;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
for (auto it = model.begin(); it != model.end(); it++) {
QString propertyName = it->first;
const MaterialProperty& property = getPhysicalProperty(propertyName);
if (property.isNull()) {
return false;
}
}
}
catch (ModelNotFound const&) {
return false;
}
return true;
}
bool Material::isAppearanceModelComplete(const QString& uuid) const
{
if (!hasAppearanceModel(uuid)) {
return false;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
for (auto it = model.begin(); it != model.end(); it++) {
QString propertyName = it->first;
const MaterialProperty& property = getAppearanceProperty(propertyName);
if (property.isNull()) {
return false;
}
}
}
catch (ModelNotFound const&) {
return false;
}
return true;
}
void Material::saveGeneral(QTextStream& stream) const
{
stream << "General:\n";
stream << " UUID: \"" << _uuid << "\"\n";
stream << " Name: \"" << _name << "\"\n";
if (!_authorAndLicense.isEmpty()) {
stream << " AuthorAndLicense: \"" << _authorAndLicense << "\"\n";
}
if (!_description.isEmpty()) {
stream << " Description: \"" << _description << "\"\n";
}
if (!_url.isEmpty()) {
stream << " SourceURL: \"" << _url << "\"\n";
}
if (!_reference.isEmpty()) {
stream << " ReferenceSource: \"" << _reference << "\"\n";
}
}
void Material::saveInherits(QTextStream& stream) const
{
if (!_parentUuid.isEmpty()) {
MaterialManager manager;
stream << "Inherits:\n";
stream << " " << manager.getMaterial(_parentUuid).getName() << ":\n";
stream << " UUID: \"" << _parentUuid << "\"\n";
}
}
void Material::saveModels(QTextStream& stream) const
{
if (!_physical.empty()) {
ModelManager modelManager;
stream << "Models:\n";
for (auto itm = _physicalUuids.begin(); itm != _physicalUuids.end(); itm++) {
auto model = modelManager.getModel(*itm);
stream << " " << model.getName() << ":\n";
stream << " UUID: \"" << model.getUUID() << "\"\n";
for (auto itp = model.begin(); itp != model.end(); itp++) {
QString propertyName = itp->first;
const MaterialProperty& property = getPhysicalProperty(propertyName);
if (!property.isNull()) {
stream << " " << propertyName << ": \""
<< getPhysicalValueString(propertyName) << "\"\n";
}
}
}
}
}
void Material::saveAppearanceModels(QTextStream& stream) const
{
if (!_appearance.empty()) {
ModelManager modelManager;
stream << "AppearanceModels:\n";
for (auto itm = _appearanceUuids.begin(); itm != _appearanceUuids.end(); itm++) {
auto model = modelManager.getModel(*itm);
stream << " " << model.getName() << ":\n";
stream << " UUID: \"" << model.getUUID() << "\"\n";
for (auto itp = model.begin(); itp != model.end(); itp++) {
QString propertyName = itp->first;
const MaterialProperty& property = getAppearanceProperty(propertyName);
if (!property.isNull()) {
stream << " " << propertyName << ": \""
<< getAppearanceValueString(propertyName) << "\"\n";
}
}
}
}
}
void Material::newUuid()
{
_uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
}
void Material::save(QTextStream& stream, bool saveAsCopy)
{
Q_UNUSED(saveAsCopy)
stream << "# File created by FreeCAD\n";
saveGeneral(stream);
saveInherits(stream);
saveModels(stream);
saveAppearanceModels(stream);
}
Material& Material::operator=(const Material& other)
{
if (this == &other) {
return *this;
}
_library = other._library;
_directory = other._directory;
_uuid = other._uuid;
_name = other._name;
_authorAndLicense = other._authorAndLicense;
_parentUuid = other._parentUuid;
_description = other._description;
_url = other._url;
_reference = other._reference;
_dereferenced = other._dereferenced;
_tags.clear();
for (auto it = other._tags.begin(); it != other._tags.end(); it++) {
_tags.push_back(*it);
}
_physicalUuids.clear();
for (auto it = other._physicalUuids.begin(); it != other._physicalUuids.end(); it++) {
_physicalUuids.push_back(*it);
}
_appearanceUuids.clear();
for (auto it = other._appearanceUuids.begin(); it != other._appearanceUuids.end(); it++) {
_appearanceUuids.push_back(*it);
}
_allUuids.clear();
for (auto it = other._allUuids.begin(); it != other._allUuids.end(); it++) {
_allUuids.push_back(*it);
}
_physical.clear();
for (auto it = other._physical.begin(); it != other._physical.end(); it++) {
_physical[it->first] = MaterialProperty(it->second);
}
_appearance.clear();
for (auto it = other._appearance.begin(); it != other._appearance.end(); it++) {
_appearance[it->first] = MaterialProperty(it->second);
}
return *this;
}

View File

@@ -0,0 +1,334 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALS_H
#define MATERIAL_MATERIALS_H
#include <Base/BaseClass.h>
#include <QDir>
#include <QString>
#include <QTextStream>
#include <App/Application.h>
#include "MaterialLibrary.h"
#include "Model.h"
namespace fs = boost::filesystem;
namespace Materials
{
class MaterialsExport MaterialProperty: public ModelProperty
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
MaterialProperty();
explicit MaterialProperty(const ModelProperty& property);
explicit MaterialProperty(const MaterialProperty& property);
virtual ~MaterialProperty();
MaterialValue::ValueType getType(void) const
{
return _valuePtr->getType();
}
const QString getModelUUID(void) const;
const QVariant getValue(void) const;
bool isNull() const
{
return _valuePtr->isNull();
}
MaterialValue* getMaterialValue(void);
const QString getString(void) const;
bool getBoolean(void) const;
int getInt(void) const;
double getFloat(void) const;
const Base::Quantity& getQuantity(void) const;
const QString getURL(void) const;
MaterialProperty& getColumn(int column);
MaterialValue::ValueType getColumnType(int column) const;
QString getColumnUnits(int column) const;
QVariant getColumnNull(int column) const;
void setModelUUID(const QString& uuid);
void setPropertyType(const QString& type) override;
void setValue(const QVariant& value);
void setValue(const QString& value);
void setString(const QString& value);
void setBoolean(bool value);
void setBoolean(int value);
void setBoolean(const QString& value);
void setInt(int value);
void setInt(const QString& value);
void setFloat(double value);
void setFloat(const QString& value);
void setQuantity(const Base::Quantity& value);
void setQuantity(double value, const QString& units);
void setQuantity(const QString& value);
void setURL(const QString& value);
MaterialProperty& operator=(const MaterialProperty& other);
protected:
void setType(const QString& type);
// void setType(MaterialValue::ValueType type) { _valueType = type; }
void addColumn(MaterialProperty& column)
{
_columns.push_back(column);
}
private:
QString _modelUUID;
MaterialValue* _valuePtr;
std::vector<MaterialProperty> _columns;
};
class MaterialsExport Material: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
enum ModelEdit
{
ModelEdit_None, // No change
ModelEdit_Alter,// Existing values are changed
ModelEdit_Extend// New values added
};
Material();
explicit Material(const MaterialLibrary& library,
const QString& directory,
const QString& uuid,
const QString& name);
explicit Material(const Material& other);
virtual ~Material();
const MaterialLibrary& getLibrary() const
{
return _library;
}
const QString getDirectory() const
{
return _directory;
}
const QString getUUID() const
{
return _uuid;
}
const QString getName() const
{
return _name;
}
const QString getAuthorAndLicense() const
{
return _authorAndLicense;
}
const QString getParentUUID() const
{
return _parentUuid;
}
const QString getDescription() const
{
return _description;
}
const QString getURL() const
{
return _url;
}
const QString getReference() const
{
return _reference;
}
ModelEdit getEditState() const
{
return _editState;
}
const std::list<QString>& getTags() const
{
return _tags;
}
const std::vector<QString>* getPhysicalModels() const
{
return &_physicalUuids;
}
const std::vector<QString>* getAppearanceModels() const
{
return &_appearanceUuids;
}
void setLibrary(const MaterialLibrary& library)
{
_library = library;
}
void setDirectory(const QString& directory)
{
Base::Console().Log("Materials::setDirectory(%s)\n", directory.toStdString().c_str());
_directory = directory;
}
void setUUID(const QString& uuid)
{
_uuid = uuid;
}
void setName(const QString& name)
{
_name = name;
}
void setAuthorAndLicense(const QString& authorAndLicense)
{
_authorAndLicense = authorAndLicense;
}
void setParentUUID(const QString& uuid)
{
_parentUuid = uuid;
}
void setDescription(const QString& description)
{
_description = description;
}
void setURL(const QString& url)
{
_url = url;
}
void setReference(const QString& reference)
{
_reference = reference;
}
void setEditState(ModelEdit newState);
void setEditStateAlter()
{
setEditState(ModelEdit_Alter);
}
void setEditStateExtend()
{
setEditState(ModelEdit_Extend);
}
void setPhysicalEditState(const QString& name);
void setAppearanceEditState(const QString& name);
void resetEditState()
{
_editState = ModelEdit_None;
}
void addTag(const QString& tag)
{
Q_UNUSED(tag);
}
void removeTag(const QString& tag)
{
Q_UNUSED(tag);
}
void addPhysical(const QString& uuid);
void addAppearance(const QString& uuid);
void newUuid();
void setPhysicalValue(const QString& name, const QString& value);
void setPhysicalValue(const QString& name, int value);
void setPhysicalValue(const QString& name, double value);
void setPhysicalValue(const QString& name, const Base::Quantity value);
void setAppearanceValue(const QString& name, const QString& value);
MaterialProperty& getPhysicalProperty(const QString& name);
const MaterialProperty& getPhysicalProperty(const QString& name) const;
MaterialProperty& getAppearanceProperty(const QString& name);
const MaterialProperty& getAppearanceProperty(const QString& name) const;
const QVariant getPhysicalValue(const QString& name) const;
const QString getPhysicalValueString(const QString& name) const;
const QVariant getAppearanceValue(const QString& name) const;
const QString getAppearanceValueString(const QString& name) const;
bool hasPhysicalProperty(const QString& name) const;
bool hasAppearanceProperty(const QString& name) const;
// Test if the model is defined, and if values are provided for all properties
bool hasModel(const QString& uuid) const;
bool hasPhysicalModel(const QString& uuid) const;
bool hasAppearanceModel(const QString& uuid) const;
bool isModelComplete(const QString& uuid) const
{
return isPhysicalModelComplete(uuid) || isAppearanceModelComplete(uuid);
}
bool isPhysicalModelComplete(const QString& uuid) const;
bool isAppearanceModelComplete(const QString& uuid) const;
const std::map<QString, MaterialProperty>& getPhysicalProperties() const
{
return _physical;
}
const std::map<QString, MaterialProperty>& getAppearanceProperties() const
{
return _appearance;
}
bool getDereferenced() const
{
return _dereferenced;
}
void markDereferenced()
{
_dereferenced = true;
}
void save(QTextStream& stream, bool saveAsCopy);
Material& operator=(const Material& other);
protected:
void addModel(const QString& uuid);
const QVariant getValue(const std::map<QString, MaterialProperty>& propertyList,
const QString& name) const;
const QString getValueString(const std::map<QString, MaterialProperty>& propertyList,
const QString& name) const;
void saveGeneral(QTextStream& stream) const;
void saveInherits(QTextStream& stream) const;
void saveModels(QTextStream& stream) const;
void saveAppearanceModels(QTextStream& stream) const;
private:
MaterialLibrary _library;
QString _directory;
QString _uuid;
QString _name;
QString _authorAndLicense;
QString _parentUuid;
QString _description;
QString _url;
QString _reference;
std::list<QString> _tags;
std::vector<QString> _physicalUuids;
std::vector<QString> _appearanceUuids;
std::vector<QString> _allUuids;// Includes inherited models
std::map<QString, MaterialProperty> _physical;
std::map<QString, MaterialProperty> _appearance;
bool _dereferenced;
ModelEdit _editState;
};
}// namespace Materials
Q_DECLARE_METATYPE(Materials::Material*)
#endif// MATERIAL_MATERIALS_H

View File

@@ -0,0 +1,116 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include "Exceptions.h"
#include "Model.h"
#include "ModelLibrary.h"
#include <string>
using namespace Materials;
TYPESYSTEM_SOURCE(Materials::ModelProperty, Base::BaseClass)
ModelProperty::ModelProperty()
{}
ModelProperty::ModelProperty(const QString& name,
const QString& type,
const QString& units,
const QString& url,
const QString& description)
: _name(name)
, _propertyType(type)
, _units(units)
, _url(url)
, _description(description)
{}
ModelProperty::ModelProperty(const ModelProperty& other)
: _name(other._name)
, _propertyType(other._propertyType)
, _units(other._units)
, _url(other._url)
, _description(other._description)
, _inheritance(other._inheritance)
{
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
_columns.push_back(*it);
}
}
ModelProperty& ModelProperty::operator=(const ModelProperty& other)
{
if (this == &other) {
return *this;
}
_name = other._name;
_propertyType = other._propertyType;
_units = other._units;
_url = other._url;
_description = other._description;
_inheritance = other._inheritance;
_columns.clear();
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
_columns.push_back(*it);
}
return *this;
}
TYPESYSTEM_SOURCE(Materials::Model, Base::BaseClass)
Model::Model()
{}
Model::Model(const ModelLibrary& library,
ModelType type,
const QString& name,
const QString& directory,
const QString& uuid,
const QString& description,
const QString& url,
const QString& doi)
: _library(library)
, _type(type)
, _name(name)
, _directory(directory)
, _uuid(uuid)
, _description(description)
, _url(url)
, _doi(doi)
{}
ModelProperty& Model::operator[](const QString& key)
{
try {
return _properties.at(key);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}

View File

@@ -0,0 +1,297 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODEL_H
#define MATERIAL_MODEL_H
#include <Base/BaseClass.h>
#include <Base/Quantity.h>
#include <QDir>
#include <QString>
#include "MaterialValue.h"
#include "ModelLibrary.h"
namespace Materials
{
class MaterialsExport ModelProperty: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
ModelProperty();
explicit ModelProperty(const QString& name,
const QString& type,
const QString& units,
const QString& url,
const QString& description);
explicit ModelProperty(const ModelProperty& other);
virtual ~ModelProperty() = default;
const QString getName() const
{
return _name;
}
const QString getPropertyType() const
{
return _propertyType;
}
const QString getUnits() const
{
return _units;
}
const QString getURL() const
{
return _url;
}
const QString getDescription() const
{
return _description;
}
const QString getInheritance() const
{
return _inheritance;
}
bool isInherited() const
{
return (_inheritance.length() > 0);
}
void setName(const QString& name)
{
_name = name;
}
virtual void setPropertyType(const QString& type)
{
_propertyType = type;
}
void setUnits(const QString& units)
{
_units = units;
}
void setURL(const QString& url)
{
_url = url;
}
void setDescription(const QString& description)
{
_description = description;
}
void setInheritance(const QString& uuid)
{
_inheritance = uuid;
}
void addColumn(ModelProperty& column)
{
_columns.push_back(column);
}
const std::vector<ModelProperty>& getColumns() const
{
return _columns;
}
int columns() const
{
return _columns.size();
}
ModelProperty& operator=(const ModelProperty& other);
private:
QString _name;
QString _propertyType;
QString _units;
QString _url;
QString _description;
QString _inheritance;
std::vector<ModelProperty> _columns;
};
class MaterialsExport Model: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
enum ModelType
{
ModelType_Physical,
ModelType_Appearance
};
Model();
explicit Model(const ModelLibrary& library,
ModelType type,
const QString& name,
const QString& directory,
const QString& uuid,
const QString& description,
const QString& url,
const QString& doi);
virtual ~Model() = default;
const ModelLibrary& getLibrary() const
{
return _library;
}
const QString getBase() const
{
return (_type == ModelType_Physical) ? QString::fromStdString("Model")
: QString::fromStdString("AppearanceModel");
}
const QString getName() const
{
return _name;
}
ModelType getType() const
{
return _type;
}
const QString getDirectory() const
{
return _directory;
}
const QString getDirectoryPath() const
{
return QDir(_directory).absolutePath();
}
const QString getRelativePath() const
{
return QDir(_directory).relativeFilePath(QDir(_directory).absolutePath());
}
const QString getUUID() const
{
return _uuid;
}
const QString getDescription() const
{
return _description;
}
const QString getURL() const
{
return _url;
}
const QString getDOI() const
{
return _doi;
}
void setLibrary(const ModelLibrary& library)
{
_library = library;
}
void setType(ModelType type)
{
_type = type;
}
void setName(const QString& name)
{
_name = name;
}
void setDirectory(const QString& directory)
{
_directory = directory;
}
void setUUID(const QString& uuid)
{
_uuid = uuid;
}
void setDescription(const QString& description)
{
_description = description;
}
void setURL(const QString& url)
{
_url = url;
}
void setDOI(const QString& doi)
{
_doi = doi;
}
void addInheritance(const QString& uuid)
{
_inheritedUuids.push_back(uuid);
}
const std::vector<QString>& getInheritance() const
{
return _inheritedUuids;
}
bool operator==(const Model& m) const
{
return _uuid == m._uuid;
}
bool operator!=(const Model& m) const
{
return !operator==(m);
}
ModelProperty& operator[](const QString& key);
void addProperty(ModelProperty& property)
{
_properties[property.getName()] = property;
}
using iterator = typename std::map<QString, ModelProperty>::iterator;
using const_iterator = typename std::map<QString, ModelProperty>::const_iterator;
iterator begin()
{
return _properties.begin();
}
const_iterator begin() const noexcept
{
return _properties.begin();
}
iterator end() noexcept
{
return _properties.end();
}
const_iterator end() const noexcept
{
return _properties.end();
}
const_iterator cbegin() const noexcept
{
return _properties.cbegin();
}
const_iterator cend() const noexcept
{
return _properties.cend();
}
private:
ModelLibrary _library;
ModelType _type;
QString _name;
QString _directory;
QString _uuid;
QString _description;
QString _url;
QString _doi;
std::vector<QString> _inheritedUuids;
std::map<QString, ModelProperty> _properties;
};
}// namespace Materials
#endif// MATERIAL_MODEL_H

View File

@@ -0,0 +1,114 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <string>
#include <App/Application.h>
#include "Exceptions.h"
#include "Model.h"
#include "ModelLibrary.h"
using namespace Materials;
TYPESYSTEM_SOURCE(Materials::LibraryBase, Base::BaseClass)
LibraryBase::LibraryBase(const QString& libraryName, const QString& dir, const QString& icon)
: _name(libraryName)
, _directory(QDir::cleanPath(dir))
, _iconPath(icon)
{}
LibraryBase::LibraryBase()
{}
bool LibraryBase::operator==(const LibraryBase& library) const
{
return (_name == library._name) && (_directory == library._directory);
}
QString LibraryBase::getLocalPath(const QString& path) const
{
QString filePath = getDirectoryPath();
QString cleanPath = QDir::cleanPath(path);
QString prefix = QString::fromStdString("/") + getName();
if (cleanPath.startsWith(prefix)) {
// Remove the library name from the path
filePath += cleanPath.right(cleanPath.length() - prefix.length());
}
else {
filePath += cleanPath;
}
return filePath;
}
QString LibraryBase::getRelativePath(const QString& path) const
{
QString filePath;
QString cleanPath = QDir::cleanPath(path);
QString prefix = QString::fromStdString("/") + getName();
if (cleanPath.startsWith(prefix)) {
// Remove the library name from the path
filePath = cleanPath.right(cleanPath.length() - prefix.length());
}
else {
filePath = cleanPath;
}
prefix = getDirectoryPath();
if (filePath.startsWith(prefix)) {
// Remove the library root from the path
filePath = filePath.right(filePath.length() - prefix.length());
}
// Remove any leading '/'
if (filePath.startsWith(QString::fromStdString("/"))) {
filePath.remove(0, 1);
}
return filePath;
}
TYPESYSTEM_SOURCE(Materials::ModelLibrary, LibraryBase)
ModelLibrary::ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon)
: LibraryBase(libraryName, dir, icon)
{}
ModelLibrary::ModelLibrary()
{}
Model* ModelLibrary::addModel(const Model& model, const QString& path)
{
QString filePath = getRelativePath(path);
Model* newModel = new Model(model);
newModel->setLibrary(*this);
newModel->setDirectory(filePath);
return newModel;
}

View File

@@ -0,0 +1,100 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODELLIBRARY_H
#define MATERIAL_MODELLIBRARY_H
#include <Base/BaseClass.h>
#include <Base/Quantity.h>
#include <QDir>
#include <QString>
#include "MaterialValue.h"
namespace Materials
{
class Model;
class MaterialsExport LibraryBase: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
LibraryBase();
explicit LibraryBase(const QString& libraryName, const QString& dir, const QString& icon);
virtual ~LibraryBase() = default;
const QString getName() const
{
return _name;
}
const QString getDirectory() const
{
return _directory;
}
const QString getDirectoryPath() const
{
return QDir(_directory).absolutePath();
}
const QString getIconPath() const
{
return _iconPath;
}
bool operator==(const LibraryBase& library) const;
bool operator!=(const LibraryBase& library) const
{
return !operator==(library);
}
QString getLocalPath(const QString& path) const;
QString getRelativePath(const QString& path) const;
private:
QString _name;
QString _directory;
QString _iconPath;
};
class MaterialsExport ModelLibrary: public LibraryBase
{
TYPESYSTEM_HEADER();
public:
ModelLibrary();
explicit ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon);
virtual ~ModelLibrary() = default;
bool operator==(const ModelLibrary& library) const
{
return LibraryBase::operator==(library);
}
bool operator!=(const ModelLibrary& library) const
{
return !operator==(library);
}
Model* addModel(const Model& model, const QString& path);
};
}// namespace Materials
#endif// MATERIAL_MODELLIBRARY_H

View File

@@ -0,0 +1,417 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QString>
#endif
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <QDirIterator>
#include <QFileInfo>
#include "Model.h"
#include "ModelLoader.h"
#include "ModelManager.h"
using namespace Materials;
ModelEntry::ModelEntry(const ModelLibrary& library,
const QString& baseName,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
const YAML::Node& modelData)
: _library(library)
, _base(baseName)
, _name(modelName)
, _directory(dir)
, _uuid(modelUuid)
, _model(modelData)
, _dereferenced(false)
{}
std::map<QString, ModelEntry*>* ModelLoader::_modelEntryMap = nullptr;
ModelLoader::ModelLoader(std::map<QString, Model*>* modelMap, std::list<ModelLibrary*>* libraryList)
: _modelMap(modelMap)
, _libraryList(libraryList)
{
loadLibraries();
}
void ModelLoader::addLibrary(ModelLibrary* model)
{
_libraryList->push_back(model);
}
const QString ModelLoader::getUUIDFromPath(const QString& path)
{
QFile file(path);
if (!file.exists()) {
throw ModelNotFound();
}
try {
YAML::Node yamlroot = YAML::LoadFile(path.toStdString());
std::string base = "Model";
if (yamlroot["AppearanceModel"]) {
base = "AppearanceModel";
}
const QString uuid = QString::fromStdString(yamlroot[base]["UUID"].as<std::string>());
return uuid;
}
catch (YAML::Exception& ex) {
throw ModelNotFound();
}
}
ModelEntry* ModelLoader::getModelFromPath(const ModelLibrary& library, const QString& path) const
{
QFile file(path);
if (!file.exists()) {
throw ModelNotFound();
}
YAML::Node yamlroot;
std::string base = "Model";
std::string uuid;
std::string name;
try {
yamlroot = YAML::LoadFile(path.toStdString());
if (yamlroot["AppearanceModel"]) {
base = "AppearanceModel";
}
uuid = yamlroot[base]["UUID"].as<std::string>();
name = yamlroot[base]["Name"].as<std::string>();
}
catch (YAML::Exception const&) {
throw InvalidModel();
}
ModelEntry* model = new ModelEntry(library,
QString::fromStdString(base),
QString::fromStdString(name),
path,
QString::fromStdString(uuid),
yamlroot);
return model;
}
void ModelLoader::showYaml(const YAML::Node& yaml) const
{
std::stringstream out;
out << yaml;
std::string logData = out.str();
Base::Console().Log("%s\n", logData.c_str());
}
void ModelLoader::dereference(const QString& uuid,
ModelEntry* parent,
const ModelEntry* child,
std::map<std::pair<QString, QString>, QString>* inheritances)
{
auto parentPtr = parent->getModelPtr();
auto parentBase = parent->getBase().toStdString();
auto childYaml = child->getModel();
auto childBase = child->getBase().toStdString();
std::set<QString> exclude;
exclude.insert(QString::fromStdString("Name"));
exclude.insert(QString::fromStdString("UUID"));
exclude.insert(QString::fromStdString("URL"));
exclude.insert(QString::fromStdString("Description"));
exclude.insert(QString::fromStdString("DOI"));
exclude.insert(QString::fromStdString("Inherits"));
auto parentProperties = (*parentPtr)[parentBase];
auto childProperties = childYaml[childBase];
for (auto it = childProperties.begin(); it != childProperties.end(); it++) {
std::string name = it->first.as<std::string>();
if (exclude.count(QString::fromStdString(name)) == 0) {
// showYaml(it->second);
if (!parentProperties[name]) {
parentProperties[name] = it->second;
// parentProperties[name]["Inherits"] = childYaml[childBase]["UUID"];
(*inheritances)[std::pair<QString, QString>(uuid, QString::fromStdString(name))] =
yamlValue(childYaml[childBase], "UUID", "");
}
}
}
// showYaml(*parentPtr);
}
void ModelLoader::dereference(ModelEntry* model,
std::map<std::pair<QString, QString>, QString>* inheritances)
{
// Avoid recursion
if (model->getDereferenced()) {
return;
}
auto yamlModel = model->getModel();
auto base = model->getBase().toStdString();
if (yamlModel[base]["Inherits"]) {
auto inherits = yamlModel[base]["Inherits"];
for (auto it = inherits.begin(); it != inherits.end(); it++) {
QString nodeName = QString::fromStdString((*it)["UUID"].as<std::string>());
// This requires that all models have already been loaded undereferenced
try {
const ModelEntry* child = (*_modelEntryMap)[nodeName];
dereference(model->getUUID(), model, child, inheritances);
}
catch (const std::out_of_range& oor) {
Base::Console().Log("Unable to find '%s' in model map\n",
nodeName.toStdString().c_str());
}
}
}
model->markDereferenced();
}
QString ModelLoader::yamlValue(const YAML::Node& node,
const std::string& key,
const std::string& defaultValue)
{
if (node[key]) {
return QString::fromStdString(node[key].as<std::string>());
}
return QString::fromStdString(defaultValue);
}
void ModelLoader::addToTree(ModelEntry* model,
std::map<std::pair<QString, QString>, QString>* inheritances)
{
std::set<QString> exclude;
exclude.insert(QString::fromStdString("Name"));
exclude.insert(QString::fromStdString("UUID"));
exclude.insert(QString::fromStdString("URL"));
exclude.insert(QString::fromStdString("Description"));
exclude.insert(QString::fromStdString("DOI"));
exclude.insert(QString::fromStdString("Inherits"));
auto yamlModel = model->getModel();
auto library = model->getLibrary();
auto base = model->getBase().toStdString();
auto name = model->getName();
auto directory = model->getDirectory();
auto uuid = model->getUUID();
QString version = yamlValue(yamlModel["General"], "Version", "");
QString description = yamlValue(yamlModel[base], "Description", "");
QString url = yamlValue(yamlModel[base], "URL", "");
QString doi = yamlValue(yamlModel[base], "DOI", "");
Model::ModelType type =
(base == "Model") ? Model::ModelType_Physical : Model::ModelType_Appearance;
Model* finalModel = new Model(library, type, name, directory, uuid, description, url, doi);
// Add inheritance list
if (yamlModel[base]["Inherits"]) {
auto inherits = yamlModel[base]["Inherits"];
for (auto it = inherits.begin(); it != inherits.end(); it++) {
QString nodeName = QString::fromStdString((*it)["UUID"].as<std::string>());
finalModel->addInheritance(nodeName);
}
}
// Add property list
auto yamlProperties = yamlModel[base];
for (auto it = yamlProperties.begin(); it != yamlProperties.end(); it++) {
std::string propName = it->first.as<std::string>();
if (exclude.count(QString::fromStdString(propName)) == 0) {
// showYaml(it->second);
auto yamlProp = yamlProperties[propName];
auto propType = yamlValue(yamlProp, "Type", "");
auto propUnits = yamlValue(yamlProp, "Units", "");
auto propURL = yamlValue(yamlProp, "URL", "");
auto propDescription = yamlValue(yamlProp, "Description", "");
// auto inherits = yamlValue(yamlProp, "Inherits", "");
ModelProperty property(QString::fromStdString(propName),
propType,
propUnits,
propURL,
propDescription);
if (propType == QString::fromStdString("2DArray")
|| propType == QString::fromStdString("3DArray")) {
Base::Console().Log("Reading columns\n");
// Read the columns
auto cols = yamlProp["Columns"];
for (auto col : cols) {
std::string colName = col.first.as<std::string>();
Base::Console().Log("\tColumns '%s'\n", colName.c_str());
auto colProp = cols[colName];
auto colPropType = yamlValue(colProp, "Type", "");
auto colPropUnits = yamlValue(colProp, "Units", "");
auto colPropURL = yamlValue(colProp, "URL", "");
auto colPropDescription = yamlValue(colProp, "Description", "");
ModelProperty colProperty(QString::fromStdString(colName),
colPropType,
colPropUnits,
colPropURL,
colPropDescription);
property.addColumn(colProperty);
}
}
auto key = std::pair<QString, QString>(uuid, QString::fromStdString(propName));
if (inheritances->count(key) > 0) {
property.setInheritance((*inheritances)[key]);
}
finalModel->addProperty(property);
}
}
(*_modelMap)[uuid] = library.addModel(*finalModel, directory);
}
void ModelLoader::loadLibrary(const ModelLibrary& library)
{
if (_modelEntryMap == nullptr) {
_modelEntryMap = new std::map<QString, ModelEntry*>();
}
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
while (it.hasNext()) {
auto pathname = it.next();
QFileInfo file(pathname);
if (file.isFile()) {
if (file.suffix().toStdString() == "yml") {
QString libraryName = file.baseName();
try {
auto model = getModelFromPath(library, file.canonicalFilePath());
(*_modelEntryMap)[model->getUUID()] = model;
// showYaml(model->getModel());
}
catch (InvalidModel const&) {
Base::Console().Log("Invalid model '%s'\n", pathname.toStdString().c_str());
}
}
}
}
std::map<std::pair<QString, QString>, QString>* inheritances =
new std::map<std::pair<QString, QString>, QString>();
for (auto it = _modelEntryMap->begin(); it != _modelEntryMap->end(); it++) {
dereference(it->second, inheritances);
}
for (auto it = _modelEntryMap->begin(); it != _modelEntryMap->end(); it++) {
addToTree(it->second, inheritances);
}
// delete inheritances;
}
void ModelLoader::loadLibraries(void)
{
getModelLibraries();
if (_libraryList) {
for (auto it = _libraryList->begin(); it != _libraryList->end(); it++) {
loadLibrary(**it);
}
}
}
void ModelLoader::getModelLibraries()
{
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Resources");
bool useBuiltInMaterials = param->GetBool("UseBuiltInMaterials", true);
bool useMatFromModules = param->GetBool("UseMaterialsFromWorkbenches", true);
bool useMatFromConfigDir = param->GetBool("UseMaterialsFromConfigDir", true);
bool useMatFromCustomDir = param->GetBool("UseMaterialsFromCustomDir", true);
if (useBuiltInMaterials) {
QString resourceDir = QString::fromStdString(App::Application::getResourceDir()
+ "/Mod/Material/Resources/Models");
auto libData = new ModelLibrary(QString::fromStdString("System"),
resourceDir,
QString::fromStdString(":/icons/freecad.svg"));
_libraryList->push_back(libData);
}
if (useMatFromModules) {
auto moduleParam = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Resources/Modules");
for (auto& group : moduleParam->GetGroups()) {
// auto module = moduleParam->GetGroup(group->GetGroupName());
auto moduleName = QString::fromStdString(group->GetGroupName());
auto modelDir = QString::fromStdString(group->GetASCII("ModuleModelDir", ""));
auto modelIcon = QString::fromStdString(group->GetASCII("ModuleIcon", ""));
if (modelDir.length() > 0) {
QDir dir(modelDir);
if (dir.exists()) {
auto libData = new ModelLibrary(moduleName, modelDir, modelIcon);
_libraryList->push_back(libData);
}
}
}
}
if (useMatFromConfigDir) {
QString resourceDir =
QString::fromStdString(App::Application::getUserAppDataDir() + "/Models");
if (!resourceDir.isEmpty()) {
QDir materialDir(resourceDir);
if (materialDir.exists()) {
auto libData =
new ModelLibrary(QString::fromStdString("User"),
resourceDir,
QString::fromStdString(":/icons/preferences-general.svg"));
_libraryList->push_back(libData);
}
}
}
if (useMatFromCustomDir) {
QString resourceDir = QString::fromStdString(param->GetASCII("CustomMaterialsDir", ""));
if (!resourceDir.isEmpty()) {
QDir materialDir(resourceDir);
if (materialDir.exists()) {
auto libData = new ModelLibrary(QString::fromStdString("Custom"),
resourceDir,
QString::fromStdString(":/icons/user.svg"));
_libraryList->push_back(libData);
}
}
}
}

View File

@@ -0,0 +1,130 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODELLOADER_H
#define MATERIAL_MODELLOADER_H
#include <QDir>
#include <QString>
#include <yaml-cpp/yaml.h>
#include "Model.h"
namespace Materials
{
class ModelEntry
{
public:
explicit ModelEntry(const ModelLibrary& library,
const QString& baseName,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
const YAML::Node& modelData);
virtual ~ModelEntry() = default;
const ModelLibrary& getLibrary() const
{
return _library;
}
const QString getBase() const
{
return _base;
}
const QString getName() const
{
return _name;
}
const QString getDirectory() const
{
return _directory;
}
const QString getUUID() const
{
return _uuid;
}
const YAML::Node& getModel() const
{
return _model;
}
YAML::Node* getModelPtr()
{
return &_model;
}
bool getDereferenced() const
{
return _dereferenced;
}
void markDereferenced()
{
_dereferenced = true;
}
private:
ModelEntry();
ModelLibrary _library;
QString _base;
QString _name;
QString _directory;
QString _uuid;
YAML::Node _model;
bool _dereferenced;
};
class ModelLoader
{
public:
explicit ModelLoader(std::map<QString, Model*>* modelMap,
std::list<ModelLibrary*>* libraryList);
virtual ~ModelLoader() = default;
static const QString getUUIDFromPath(const QString& path);
private:
ModelLoader();
void getModelLibraries();
QString
yamlValue(const YAML::Node& node, const std::string& key, const std::string& defaultValue);
void addToTree(ModelEntry* model, std::map<std::pair<QString, QString>, QString>* inheritances);
void showYaml(const YAML::Node& yaml) const;
void dereference(const QString& uuid,
ModelEntry* parent,
const ModelEntry* child,
std::map<std::pair<QString, QString>, QString>* inheritances);
void dereference(ModelEntry* model,
std::map<std::pair<QString, QString>, QString>* inheritances);
ModelEntry* getModelFromPath(const ModelLibrary& library, const QString& path) const;
void addLibrary(ModelLibrary* model);
void loadLibrary(const ModelLibrary& library);
void loadLibraries(void);
static std::map<QString, ModelEntry*>* _modelEntryMap;
std::map<QString, Model*>* _modelMap;
std::list<ModelLibrary*>* _libraryList;
};
}// namespace Materials
#endif// MATERIAL_MODELLOADER_H

View File

@@ -0,0 +1,172 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <QMutexLocker>
#include <Base/Console.h>
#include "Model.h"
#include "ModelLoader.h"
#include "ModelManager.h"
using namespace Materials;
std::list<ModelLibrary*>* ModelManager::_libraryList = nullptr;
std::map<QString, Model*>* ModelManager::_modelMap = nullptr;
QMutex ModelManager::_mutex;
TYPESYSTEM_SOURCE(Materials::ModelManager, Base::BaseClass)
ModelManager::ModelManager()
{
initLibraries();
}
void ModelManager::initLibraries()
{
QMutexLocker locker(&_mutex);
if (_modelMap == nullptr) {
_modelMap = new std::map<QString, Model*>();
if (_libraryList == nullptr) {
_libraryList = new std::list<ModelLibrary*>();
}
// Load the libraries
ModelLoader loader(_modelMap, _libraryList);
}
}
bool ModelManager::isModel(const fs::path& p)
{
// if (!fs::is_regular_file(p))
// return false;
// check file extension
if (p.extension() == ".yml") {
return true;
}
return false;
}
void ModelManager::refresh()
{
_modelMap->clear();
_libraryList->clear();
// Load the libraries
ModelLoader loader(_modelMap, _libraryList);
}
const Model& ModelManager::getModel(const QString& uuid) const
{
try {
if (_modelMap == nullptr) {
throw Uninitialized();
}
return *(_modelMap->at(uuid));
}
catch (std::out_of_range const&) {
throw ModelNotFound();
}
}
const Model& ModelManager::getModelByPath(const QString& path) const
{
const QString& uuid = ModelLoader::getUUIDFromPath(path);
const Model& model = getModel(uuid);
return model;
}
const Model& ModelManager::getModelByPath(const QString& path, const QString& libraryPath) const
{
QDir modelDir(QDir::cleanPath(libraryPath + QString::fromStdString("/") + path));
QString absPath = modelDir.absolutePath();
return getModelByPath(absPath);
}
bool ModelManager::passFilter(ModelFilter filter, Model::ModelType modelType) const
{
switch (filter) {
case ModelFilter_None:
return true;
case ModelFilter_Physical:
return (modelType == Model::ModelType_Physical);
case ModelFilter_Appearance:
return (modelType == Model::ModelType_Appearance);
}
return false;
}
std::map<QString, ModelTreeNode*>* ModelManager::getModelTree(const ModelLibrary& library,
ModelFilter filter)
{
std::map<QString, ModelTreeNode*>* modelTree = new std::map<QString, ModelTreeNode*>();
for (auto it = _modelMap->begin(); it != _modelMap->end(); it++) {
auto filename = it->first;
auto model = it->second;
if (model->getLibrary() == library && passFilter(filter, model->getType())) {
fs::path path = model->getDirectory().toStdString();
Base::Console().Log("Relative path '%s'\n\t", path.string().c_str());
// Start at the root
std::map<QString, ModelTreeNode*>* node = modelTree;
for (auto itp = path.begin(); itp != path.end(); itp++) {
if (isModel(itp->string())) {
ModelTreeNode* child = new ModelTreeNode();
child->setData(model);
(*node)[QString::fromStdString(itp->string())] = child;
}
else {
// Add the folder only if it's not already there
QString folderName = QString::fromStdString(itp->string());
std::map<QString, ModelTreeNode*>* mapPtr;
if (node->count(QString::fromStdString(itp->string())) == 0) {
mapPtr = new std::map<QString, ModelTreeNode*>();
ModelTreeNode* child = new ModelTreeNode();
child->setFolder(mapPtr);
(*node)[QString::fromStdString(itp->string())] = child;
node = mapPtr;
}
else {
node = (*node)[QString::fromStdString(itp->string())]->getFolder();
}
}
Base::Console().Log("'%s' ", itp->string().c_str());
}
Base::Console().Log("\n");
}
}
return modelTree;
}

View File

@@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODELMANAGER_H
#define MATERIAL_MODELMANAGER_H
#include <QMutex>
#include <boost/filesystem.hpp>
#include "Exceptions.h"
#include "FolderTree.h"
#include "Model.h"
namespace fs = boost::filesystem;
namespace Materials
{
typedef FolderTreeNode<Model> ModelTreeNode;
class MaterialsExport ModelManager: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
enum ModelFilter
{
ModelFilter_None,
ModelFilter_Physical,
ModelFilter_Appearance
};
ModelManager();
virtual ~ModelManager() = default;
void refresh();
std::list<ModelLibrary*>* getModelLibraries()
{
return _libraryList;
}
std::map<QString, Model*>* getModels()
{
return _modelMap;
}
std::map<QString, ModelTreeNode*>* getModelTree(const ModelLibrary& library,
ModelFilter filter = ModelFilter_None);
const Model& getModel(const QString& uuid) const;
const Model& getModelByPath(const QString& path) const;
const Model& getModelByPath(const QString& path, const QString& libraryPath) const;
static bool isModel(const fs::path& p);
bool passFilter(ModelFilter filter, Model::ModelType modelType) const;
private:
static void initLibraries();
static std::list<ModelLibrary*>* _libraryList;
static std::map<QString, Model*>* _modelMap;
static QMutex _mutex;
};
}// namespace Materials
#endif// MATERIAL_MODELMANAGER_H

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="ModelManagerPy"
Twin="ModelManager"
TwinPointer="ModelManager"
Include="Mod/Material/App/ModelManager.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material model descriptions.</UserDocu>
</Documentation>
<Methode Name="getModel">
<Documentation>
<UserDocu>Get a model object by specifying its UUID</UserDocu>
</Documentation>
</Methode>
<Methode Name="getModelByPath">
<Documentation>
<UserDocu>Get a model object by specifying its path</UserDocu>
</Documentation>
</Methode>
<Attribute Name="ModelLibraries" ReadOnly="true">
<Documentation>
<UserDocu>List of model libraries.</UserDocu>
</Documentation>
<Parameter Name="ModelLibraries" Type="List"/>
</Attribute>
<Attribute Name="Models" ReadOnly="true">
<Documentation>
<UserDocu>List of model libraries.</UserDocu>
</Documentation>
<Parameter Name="Models" Type="Dict"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,163 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include "ModelManager.h"
#include "ModelManagerPy.h"
#include "ModelPy.h"
#include "ModelManagerPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string ModelManagerPy::representation() const
{
std::stringstream str;
str << "<ModelManager object at " << getModelManagerPtr() << ">";
return str.str();
}
PyObject* ModelManagerPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new ModelManagerPy(new ModelManager());
}
// constructor method
int ModelManagerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
PyObject* ModelManagerPy::getModel(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
try {
const Model model = getModelManagerPtr()->getModel(QString::fromStdString(uuid));
return new ModelPy(new Model(model));
}
catch (ModelNotFound const&) {
QString error = QString::fromStdString("Model not found:\n");
std::map<QString, Model*>* _modelMap = getModelManagerPtr()->getModels();
error += QString::fromStdString("ModelMap:\n");
for (auto itp = _modelMap->begin(); itp != _modelMap->end(); itp++) {
error += QString::fromStdString("\t_modelMap[") + itp->first
+ QString::fromStdString("] = '") + itp->second->getName()
+ QString::fromStdString("'\n");
}
error += QString::fromStdString("\tuuid = '") + QString::fromStdString(uuid)
+ QString::fromStdString("'\n");
PyErr_SetString(PyExc_LookupError, error.toStdString().c_str());
return nullptr;
}
catch (Uninitialized const&) {
PyErr_SetString(PyExc_LookupError, "Uninitialized model list");
return nullptr;
}
}
PyObject* ModelManagerPy::getModelByPath(PyObject* args)
{
char* path;
char* lib = "";
if (!PyArg_ParseTuple(args, "s|s", &path, &lib)) {
return nullptr;
}
std::string libPath(lib);
if (libPath.length() > 0) {
try {
const Model& model =
getModelManagerPtr()->getModelByPath(QString::fromStdString(path),
QString::fromStdString(libPath));
return new ModelPy(new Model(model));
}
catch (ModelNotFound const&) {
PyErr_SetString(PyExc_LookupError, "Model not found");
return nullptr;
}
}
try {
const Model& model = getModelManagerPtr()->getModelByPath(QString::fromStdString(path));
return new ModelPy(new Model(model));
}
catch (ModelNotFound const&) {
PyErr_SetString(PyExc_LookupError, "Model not found");
return nullptr;
}
}
Py::List ModelManagerPy::getModelLibraries() const
{
std::list<ModelLibrary*>* libraries = getModelManagerPtr()->getModelLibraries();
Py::List list;
for (auto it = libraries->begin(); it != libraries->end(); it++) {
ModelLibrary* lib = *it;
Py::Tuple libTuple(3);
libTuple.setItem(0, Py::String(lib->getName().toStdString()));
libTuple.setItem(1, Py::String(lib->getDirectoryPath().toStdString()));
libTuple.setItem(2, Py::String(lib->getIconPath().toStdString()));
list.append(libTuple);
}
return list;
}
Py::Dict ModelManagerPy::getModels() const
{
std::map<QString, Model*>* models = getModelManagerPtr()->getModels();
Py::Dict dict;
for (auto it = models->begin(); it != models->end(); it++) {
QString key = it->first;
Model* model = it->second;
PyObject* modelPy = new ModelPy(new Model(*model));
dict.setItem(Py::String(key.toStdString()), Py::Object(modelPy, true));
}
return dict;
}
PyObject* ModelManagerPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int ModelManagerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="ModelPropertyPy"
Twin="ModelProperty"
TwinPointer="ModelProperty"
Include="Mod/Material/App/Model.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material property descriptions.</UserDocu>
</Documentation>
<!-- <Methode Name="mirror">
<Documentation>
<UserDocu>Performs the symmetrical transformation of this geometric object</UserDocu>
</Documentation>
</Methode> -->
<Attribute Name="Name" ReadOnly="true">
<Documentation>
<UserDocu>Property name.</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Type" ReadOnly="true">
<Documentation>
<UserDocu>Property type.</UserDocu>
</Documentation>
<Parameter Name="Type" Type="String"/>
</Attribute>
<Attribute Name="Units" ReadOnly="true">
<Documentation>
<UserDocu>Property units category.</UserDocu>
</Documentation>
<Parameter Name="Units" Type="String"/>
</Attribute>
<Attribute Name="URL" ReadOnly="true">
<Documentation>
<UserDocu>URL to a detailed description of the property.</UserDocu>
</Documentation>
<Parameter Name="URL" Type="String"/>
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Documentation>
<UserDocu>Property description.</UserDocu>
</Documentation>
<Parameter Name="Description" Type="String"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,101 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include "Model.h"
#include "ModelPropertyPy.h"
#include "ModelPropertyPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string ModelPropertyPy::representation() const
{
ModelPropertyPy::PointerType ptr = getModelPropertyPtr();
std::stringstream str;
str << "Property [Name=(";
str << ptr->getName().toStdString();
str << "), Type=(";
str << ptr->getPropertyType().toStdString();
str << "), Units=(";
str << ptr->getUnits().toStdString();
str << "), URL=(";
str << ptr->getURL().toStdString();
str << "), Description=(";
str << ptr->getDescription().toStdString();
str << ")]";
return str.str();
}
PyObject* ModelPropertyPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new ModelPropertyPy(new ModelProperty());
}
// constructor method
int ModelPropertyPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::String ModelPropertyPy::getName() const
{
return Py::String(getModelPropertyPtr()->getName().toStdString());
}
Py::String ModelPropertyPy::getType() const
{
return Py::String(getModelPropertyPtr()->getPropertyType().toStdString());
}
Py::String ModelPropertyPy::getUnits() const
{
return Py::String(getModelPropertyPtr()->getUnits().toStdString());
}
Py::String ModelPropertyPy::getURL() const
{
return Py::String(getModelPropertyPtr()->getURL().toStdString());
}
Py::String ModelPropertyPy::getDescription() const
{
return Py::String(getModelPropertyPtr()->getDescription().toStdString());
}
PyObject* ModelPropertyPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int ModelPropertyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="ModelPy"
Twin="Model"
TwinPointer="Model"
Include="Mod/Material/App/Model.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material model descriptions.</UserDocu>
</Documentation>
<Attribute Name="LibraryName" ReadOnly="true">
<Documentation>
<UserDocu>Model library name.</UserDocu>
</Documentation>
<Parameter Name="LibraryName" Type="String"/>
</Attribute>
<Attribute Name="LibraryRoot" ReadOnly="true">
<Documentation>
<UserDocu>Model library path.</UserDocu>
</Documentation>
<Parameter Name="LibraryRoot" Type="String"/>
</Attribute>
<Attribute Name="LibraryIcon" ReadOnly="true">
<Documentation>
<UserDocu>Model icon path.</UserDocu>
</Documentation>
<Parameter Name="LibraryIcon" Type="String"/>
</Attribute>
<Attribute Name="Name" ReadOnly="true">
<Documentation>
<UserDocu>Model name.</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Directory" ReadOnly="true">
<Documentation>
<UserDocu>Model directory.</UserDocu>
</Documentation>
<Parameter Name="Directory" Type="String"/>
</Attribute>
<Attribute Name="UUID" ReadOnly="true">
<Documentation>
<UserDocu>Unique model identifier.</UserDocu>
</Documentation>
<Parameter Name="UUID" Type="String"/>
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Documentation>
<UserDocu>Description of the model.</UserDocu>
</Documentation>
<Parameter Name="Description" Type="String"/>
</Attribute>
<Attribute Name="URL" ReadOnly="true">
<Documentation>
<UserDocu>URL to a detailed description of the model.</UserDocu>
</Documentation>
<Parameter Name="URL" Type="String"/>
</Attribute>
<Attribute Name="DOI" ReadOnly="true">
<Documentation>
<UserDocu>Digital Object Identifier (see https://doi.org/)</UserDocu>
</Documentation>
<Parameter Name="DOI" Type="String"/>
</Attribute>
<Attribute Name="Inherited" ReadOnly="true">
<Documentation>
<UserDocu>List of inherited models identified by UUID.</UserDocu>
</Documentation>
<Parameter Name="Inherited" Type="List"/>
</Attribute>
<Attribute Name="Properties" ReadOnly="true">
<Documentation>
<UserDocu>Dictionary of model properties.</UserDocu>
</Documentation>
<Parameter Name="Properties" Type="Dict"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,172 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include "Model.h"
#include "ModelPropertyPy.h"
#include "ModelPy.h"
#include "ModelPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string ModelPy::representation() const
{
ModelPy::PointerType ptr = getModelPtr();
std::stringstream str;
str << "Property [Name=(";
str << ptr->getName().toStdString();
str << "), UUID=(";
str << ptr->getUUID().toStdString();
str << "), Library Name=(";
str << ptr->getLibrary().getName().toStdString();
str << "), Library Root=(";
str << ptr->getLibrary().getDirectoryPath().toStdString();
str << "), Library Icon=(";
str << ptr->getLibrary().getIconPath().toStdString();
str << "), Directory=(";
str << ptr->getDirectory().toStdString();
str << "), URL=(";
str << ptr->getURL().toStdString();
str << "), DOI=(";
str << ptr->getDOI().toStdString();
str << "), Description=(";
str << ptr->getDescription().toStdString();
str << "), Inherits=[";
const std::vector<QString>& inherited = getModelPtr()->getInheritance();
for (auto it = inherited.begin(); it != inherited.end(); it++) {
QString uuid = *it;
if (it != inherited.begin()) {
str << "), UUID=(";
}
else {
str << "UUID=(";
}
str << uuid.toStdString() << ")";
}
str << "]]";
return str.str();
}
PyObject* ModelPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new ModelPy(new Model());
}
// constructor method
int ModelPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::String ModelPy::getLibraryName() const
{
return Py::String(getModelPtr()->getLibrary().getName().toStdString());
}
Py::String ModelPy::getLibraryRoot() const
{
return Py::String(getModelPtr()->getLibrary().getDirectoryPath().toStdString());
}
Py::String ModelPy::getLibraryIcon() const
{
return Py::String(getModelPtr()->getLibrary().getIconPath().toStdString());
}
Py::String ModelPy::getName() const
{
return Py::String(getModelPtr()->getName().toStdString());
}
Py::String ModelPy::getDirectory() const
{
return Py::String(getModelPtr()->getDirectoryPath().toStdString());
}
Py::String ModelPy::getUUID() const
{
return Py::String(getModelPtr()->getUUID().toStdString());
}
Py::String ModelPy::getDescription() const
{
return Py::String(getModelPtr()->getDescription().toStdString());
}
Py::String ModelPy::getURL() const
{
return Py::String(getModelPtr()->getURL().toStdString());
}
Py::String ModelPy::getDOI() const
{
return Py::String(getModelPtr()->getDOI().toStdString());
}
Py::List ModelPy::getInherited() const
{
const std::vector<QString>& inherited = getModelPtr()->getInheritance();
Py::List list;
for (auto it = inherited.begin(); it != inherited.end(); it++) {
QString uuid = *it;
list.append(Py::String(uuid.toStdString()));
}
return list;
}
Py::Dict ModelPy::getProperties() const
{
// std::map<std::string, Model*> *models = getModelPtr()->getModels();
Py::Dict dict;
for (auto it = getModelPtr()->begin(); it != getModelPtr()->end(); it++) {
QString key = it->first;
ModelProperty& modelProperty = it->second;
PyObject* modelPropertyPy = new ModelPropertyPy(new ModelProperty(modelProperty));
dict.setItem(Py::String(key.toStdString()), Py::Object(modelPropertyPy, true));
}
return dict;
}
PyObject* ModelPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int ModelPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODELUUIDS_H
#define MATERIAL_MODELUUIDS_H
namespace Materials
{
// UUIDs for predefined material models
static const QString ModelUUID_Legacy_Father =
QString::fromStdString("9cdda8b6-b606-4778-8f13-3934d8668e67");
static const QString ModelUUID_Legacy_MaterialStandard =
QString::fromStdString("1e2c0088-904a-4537-925f-64064c07d700");
static const QString ModelUUID_Mechanical_Density =
QString::fromStdString("454661e5-265b-4320-8e6f-fcf6223ac3af");
static const QString ModelUUID_Mechanical_IsotropicLinearElastic =
QString::fromStdString("f6f9e48c-b116-4e82-ad7f-3659a9219c50");
static const QString ModelUUID_Mechanical_LinearElastic =
QString::fromStdString("7b561d1d-fb9b-44f6-9da9-56a4f74d7536");
static const QString ModelUUID_Mechanical_OgdenYld2004p18 =
QString::fromStdString("3ef9e427-cc25-43f7-817f-79ff0d49625f");
static const QString ModelUUID_Mechanical_OrthotropicLinearElastic =
QString::fromStdString("b19ccc6b-a431-418e-91c2-0ac8c649d146");
static const QString ModelUUID_Fluid_Default =
QString::fromStdString("1ae66d8c-1ba1-4211-ad12-b9917573b202");
static const QString ModelUUID_Thermal_Default =
QString::fromStdString("9959d007-a970-4ea7-bae4-3eb1b8b883c7");
static const QString ModelUUID_Electromagnetic_Default =
QString::fromStdString("b2eb5f48-74b3-4193-9fbb-948674f427f3");
static const QString ModelUUID_Architectural_Default =
QString::fromStdString("32439c3b-262f-4b7b-99a8-f7f44e5894c8");
static const QString ModelUUID_Costs_Default =
QString::fromStdString("881df808-8726-4c2e-be38-688bb6cce466");
static const QString ModelUUID_Rendering_Basic =
QString::fromStdString("f006c7e4-35b7-43d5-bbf9-c5d572309e6e");
static const QString ModelUUID_Rendering_Texture =
QString::fromStdString("bbdcc65b-67ca-489c-bd5c-a36e33d1c160");
static const QString ModelUUID_Rendering_Advanced =
QString::fromStdString("c880f092-cdae-43d6-a24b-55e884aacbbf");
static const QString ModelUUID_Rendering_Vector =
QString::fromStdString("fdf5a80e-de50-4157-b2e5-b6e5f88b680e");
}// namespace Materials
#endif// MATERIAL_MODELUUIDS_H

View File

@@ -0,0 +1,24 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"

View File

@@ -0,0 +1,67 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_PRECOMPILED_H
#define MATGUI_PRECOMPILED_H
#include <FCConfig.h>
#include <Mod/Material/MaterialGlobal.h>
// point at which warnings of overly long specifiers disabled (needed for VC6)
#ifdef _MSC_VER
# pragma warning( disable : 4251 )
# pragma warning( disable : 4503 )
# pragma warning( disable : 4786 ) // specifier longer then 255 chars
# pragma warning( disable : 4273 )
#endif
#ifdef FC_OS_WIN32
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
#endif
#ifdef _PreComp_
// standard
#include <cfloat>
#include <cmath>
// STL
#include <algorithm>
#include <map>
#include <sstream>
#include <string>
#include <vector>
// Qt
#include <QtGlobal>
// Boost
#include <boost/regex.hpp>
#include <boost/algorithm/string/predicate.hpp>
#endif //_PreComp_
#endif // MATGUI_PRECOMPILED_H

View File

@@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_TRIM_H
#define MATERIAL_TRIM_H
#include <string>
namespace Materials
{
// trim from start (in place)
static inline void ltrim(std::string& s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string& s)
{
s.erase(std::find_if(s.rbegin(),
s.rend(),
[](unsigned char ch) {
return !std::isspace(ch);
})
.base(),
s.end());
}
// trim from both ends (in place)
static inline void trim(std::string& s)
{
rtrim(s);
ltrim(s);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s)
{
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s)
{
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s)
{
trim(s);
return s;
}
}// namespace Materials
#endif// MATERIAL_TRIM_H

View File

@@ -1,174 +1,221 @@
IF (BUILD_GUI)
PYSIDE_WRAP_RC(Material_QRC_SRCS Resources/Material.qrc)
ENDIF (BUILD_GUI)
add_subdirectory(App)
SET(Material_SRCS
if(BUILD_GUI)
add_subdirectory(Gui)
endif(BUILD_GUI)
IF(BUILD_GUI)
PYSIDE_WRAP_RC(Material_QRC_SRCS Resources/Material.qrc)
ENDIF(BUILD_GUI)
SET(MaterialScripts_Files
Init.py
InitGui.py
Material.py
importFCMat.py
MaterialEditor.py
materials-editor.ui
TestMaterialsApp.py
Resources/ui/materials-editor.ui
Templatematerial.yml
)
SOURCE_GROUP("Module" FILES ${Material_SRCS})
SET (MaterialTools_Files
# SOURCE_GROUP("MaterialScripts" FILES ${MaterialScripts_Files})
SET(MaterialTools_Files
materialtools/__init__.py
materialtools/cardutils.py
materialtools/MaterialModels.py
)
SET (Material_Icon_Files
SET(Material_Icon_Files
Resources/icons/preview-rendered.svg
Resources/icons/preview-vector.svg
)
# collect all the material cards:
#FILE( GLOB MaterialLib_Files ./StandardMaterial/*.FCMat ./StandardMaterial/*.txt )
SET (MaterialLib_Files
StandardMaterial/None.FCMat
StandardMaterial/ABS-Generic.FCMat
StandardMaterial/Acrylic-Glass-Generic.FCMat
StandardMaterial/AlMg3F24.FCMat
StandardMaterial/AlMgSi1F31.FCMat
StandardMaterial/Aluminum-6061-T6.FCMat
StandardMaterial/Aluminum-Generic.FCMat
StandardMaterial/AlZn4-5Mg1F35.FCMat
StandardMaterial/CalculiX-Steel.FCMat
StandardMaterial/Concrete-Generic.FCMat
StandardMaterial/Copper-Generic.FCMat
StandardMaterial/Glass-E-GlassFibre.FCMat
StandardMaterial/Glass-Generic.FCMat
StandardMaterial/Glass-S2-GlassFibre.FCMat
StandardMaterial/Graphite.FCMat
StandardMaterial/Iron-Generic.FCMat
StandardMaterial/Invar-Generic.FCMat
StandardMaterial/PA6-Generic.FCMat
StandardMaterial/PET-Generic.FCMat
StandardMaterial/PLA-Generic.FCMat
StandardMaterial/PP-Generic.FCMat
StandardMaterial/PTFE-Generic.FCMat
StandardMaterial/PVC-Generic.FCMat
StandardMaterial/Reinforcement-FIB-B500.FCMat
StandardMaterial/Steel-15CrNi6.FCMat
StandardMaterial/Steel-17CrNiMo6.FCMat
StandardMaterial/Steel-1C22.FCMat
StandardMaterial/Steel-1C35.FCMat
StandardMaterial/Steel-1C45.FCMat
StandardMaterial/Steel-1C60.FCMat
StandardMaterial/Steel-20NiCrMo2.FCMat
StandardMaterial/Steel-28Mn6.FCMat
StandardMaterial/Steel-2C10.FCMat
StandardMaterial/Steel-30CrNiMo8.FCMat
StandardMaterial/Steel-34CrNiMo6.FCMat
StandardMaterial/Steel-36CrNiMo4.FCMat
StandardMaterial/Steel-36NiCrMo16.FCMat
StandardMaterial/Steel-3C15.FCMat
StandardMaterial/Steel-3C22.FCMat
StandardMaterial/Steel-3C35.FCMat
StandardMaterial/Steel-3V45.FCMat
StandardMaterial/Steel-C10.FCMat
StandardMaterial/Steel-C15.FCMat
StandardMaterial/Steel-C22E.FCMat
StandardMaterial/Steel-C25E.FCMat
StandardMaterial/Steel-C30E.FCMat
StandardMaterial/Steel-C40E.FCMat
StandardMaterial/Steel-C50E.FCMat
StandardMaterial/Steel-C55E.FCMat
StandardMaterial/Steel-C60E.FCMat
StandardMaterial/Steel-E295-GC.FCMat
StandardMaterial/Steel-E295.FCMat
StandardMaterial/Steel-E335-GC.FCMat
StandardMaterial/Steel-E335.FCMat
StandardMaterial/Steel-E360-GC.FCMat
StandardMaterial/Steel-E360.FCMat
StandardMaterial/Steel-EN-GJL-100.FCMat
StandardMaterial/Steel-EN-GJL-150.FCMat
StandardMaterial/Steel-EN-GJL-200.FCMat
StandardMaterial/Steel-EN-GJL-250.FCMat
StandardMaterial/Steel-EN-GJL-300.FCMat
StandardMaterial/Steel-EN-GJL-350.FCMat
StandardMaterial/Steel-EN-GJMB-350-10.FCMat
StandardMaterial/Steel-EN-GJMB-550-4.FCMat
StandardMaterial/Steel-EN-GJMB-650-2.FCMat
StandardMaterial/Steel-EN-GJMW-350-4.FCMat
StandardMaterial/Steel-EN-GJMW-360-12.FCMat
StandardMaterial/Steel-EN-GJMW-400-5.FCMat
StandardMaterial/Steel-EN-GJMW-450-7.FCMat
StandardMaterial/Steel-EN-GJS-400-15.FCMat
StandardMaterial/Steel-EN-GJS-500-7.FCMat
StandardMaterial/Steel-EN-GJS-600-3.FCMat
StandardMaterial/Steel-EN-GJS-700-2.FCMat
StandardMaterial/Steel-EN-GJS-800-1.FCMat
StandardMaterial/Steel-G16Mn5.FCMat
StandardMaterial/Steel-G200.FCMat
StandardMaterial/Steel-G20Mn5.FCMat
StandardMaterial/Steel-G230.FCMat
StandardMaterial/Steel-G260.FCMat
StandardMaterial/Steel-G300.FCMat
StandardMaterial/Steel-G30Mn5.FCMat
StandardMaterial/Steel-Generic.FCMat
StandardMaterial/Steel-S185.FCMat
StandardMaterial/Steel-S235JO.FCMat
StandardMaterial/Steel-S235JR.FCMat
StandardMaterial/Steel-S235JRG1.FCMat
StandardMaterial/Steel-S260NC.FCMat
StandardMaterial/Steel-S275JO.FCMat
StandardMaterial/Steel-S275JR.FCMat
StandardMaterial/Steel-S275N.FCMat
StandardMaterial/Steel-S335JO.FCMat
StandardMaterial/Steel-S335JR.FCMat
StandardMaterial/Steel-S335N.FCMat
StandardMaterial/Steel-S340MC.FCMat
StandardMaterial/Steel-S355J2G3.FCMat
StandardMaterial/Steel-S380MC.FCMat
StandardMaterial/Steel-S420MC.FCMat
StandardMaterial/Steel-S420N.FCMat
StandardMaterial/Steel-S460MC.FCMat
StandardMaterial/Steel-S460N.FCMat
StandardMaterial/Steel-S500MC.FCMat
StandardMaterial/Steel-S550MC.FCMat
StandardMaterial/Steel-S690MC.FCMat
StandardMaterial/Steel-St-37-2K.FCMat
StandardMaterial/Steel-St-E-255.FCMat
StandardMaterial/Steel-St-E-315.FCMat
StandardMaterial/Steel-St-E-380.FCMat
StandardMaterial/Steel-St-E-460.FCMat
StandardMaterial/Steel-St-E-500.FCMat
StandardMaterial/Steel-X2CrNiMoN17-13-3.FCMat
StandardMaterial/Steel-X2CrNiN24-4.FCMat
StandardMaterial/Steel-X39CrMo17-1.FCMat
StandardMaterial/Steel-X3CrNiMo13-14.FCMat
StandardMaterial/Steel-X5CrNi18-10.FCMat
StandardMaterial/Steel-X5CrNiMo17-12-2.FCMat
StandardMaterial/Steel-X6CrNiTi18-10.FCMat
StandardMaterial/TEMPLATE.FCMat
StandardMaterial/Ti-6Al-4V.FCMat
StandardMaterial/Wood-Generic.FCMat
StandardMaterial/Readme.txt
)
SOURCE_GROUP("MatLib" FILES ${MaterialLib_Files})
SET (FluidMaterial_Files
FluidMaterial/None.FCMat
FluidMaterial/Air.FCMat
FluidMaterial/Argon.FCMat
FluidMaterial/Carbon_dioxide.FCMat
FluidMaterial/Nitrogen.FCMat
FluidMaterial/Water.FCMat
FluidMaterial/Readme.md
)
SOURCE_GROUP("MatLib" FILES ${FluidMaterial_Files})
ADD_CUSTOM_TARGET(Material ALL
SOURCES ${Material_SRCS} ${Material_QRC_SRCS}
# FILE( GLOB MaterialLib_Files ./StandardMaterial/*.FCMat ./StandardMaterial/*.txt )
SET(MaterialLib_Files
Resources/Materials/StandardMaterial/Aggregate/Concrete-EN-C35_45.FCMat
Resources/Materials/StandardMaterial/Aggregate/Concrete-Generic.FCMat
Resources/Materials/StandardMaterial/Aggregate/Reinforcement-FIB-B500.FCMat
Resources/Materials/StandardMaterial/Carbon/Graphite.FCMat
Resources/Materials/StandardMaterial/Glass/Glass-E-GlassFibre.FCMat
Resources/Materials/StandardMaterial/Glass/Glass-Generic.FCMat
Resources/Materials/StandardMaterial/Glass/Glass-S2-GlassFibre.FCMat
Resources/Materials/StandardMaterial/Metal/Alloys/Invar-Generic.FCMat
Resources/Materials/StandardMaterial/Metal/Aluminum/AlMg3F24.FCMat
Resources/Materials/StandardMaterial/Metal/Aluminum/AlMgSi1F31.FCMat
Resources/Materials/StandardMaterial/Metal/Aluminum/Aluminum-6061-T6.FCMat
Resources/Materials/StandardMaterial/Metal/Aluminum/Aluminum-Generic.FCMat
Resources/Materials/StandardMaterial/Metal/Aluminum/AlZn4-5Mg1F35.FCMat
Resources/Materials/StandardMaterial/Metal/Copper/Copper-Generic.FCMat
Resources/Materials/StandardMaterial/Metal/Iron/Iron-Generic.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/CalculiX-Steel.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-15CrNi6.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-17CrNiMo6.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-1C22.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-1C35.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-1C45.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-1C60.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-20NiCrMo2.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-28Mn6.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-2C10.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-30CrNiMo8.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-34CrNiMo6.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-36CrNiMo4.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-36NiCrMo16.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-3C15.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-3C22.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-3C35.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-3V45.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C10.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C15.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C22E.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C25E.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C30E.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C40E.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C50E.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C55E.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C60E.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E295-GC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E295.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E335-GC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E335.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E360-GC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E360.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-100.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-150.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-200.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-250.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-300.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-350.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMB-350-10.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMB-550-4.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMB-650-2.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMW-350-4.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMW-360-12.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMW-400-5.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMW-450-7.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-400-15.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-500-7.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-600-3.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-700-2.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-800-1.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G16Mn5.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G200.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G20Mn5.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G230.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G260.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G300.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G30Mn5.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-Generic.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S185.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S235JO.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S235JR.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S235JRG1.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S260NC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S275JO.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S275JR.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S275N.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S335JO.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S335JR.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S335N.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S340MC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S355J2G3.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S380MC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S420MC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S420N.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S460MC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S460N.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S500MC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S550MC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S690MC.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-37-2K.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-255.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-315.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-380.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-460.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-500.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X2CrNiMoN17-13-3.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X2CrNiN24-4.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X39CrMo17-1.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X3CrNiMo13-14.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X5CrNi18-10.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X5CrNiMo17-12-2.FCMat
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X6CrNiTi18-10.FCMat
Resources/Materials/StandardMaterial/Metal/Titanium/Ti-6Al-4V.FCMat
Resources/Materials/StandardMaterial/Thermoplast/ABS-Generic.FCMat
Resources/Materials/StandardMaterial/Thermoplast/Acrylic-Glass-Generic.FCMat
Resources/Materials/StandardMaterial/Thermoplast/PA6-Generic.FCMat
Resources/Materials/StandardMaterial/Thermoplast/PET-Generic.FCMat
Resources/Materials/StandardMaterial/Thermoplast/PLA-Generic.FCMat
Resources/Materials/StandardMaterial/Thermoplast/PP-Generic.FCMat
Resources/Materials/StandardMaterial/Thermoplast/PTFE-Generic.FCMat
Resources/Materials/StandardMaterial/Thermoplast/PVC-Generic.FCMat
Resources/Materials/StandardMaterial/Wood/Wood-Generic.FCMat
)
fc_target_copy_resource(Material
SET(FluidMaterial_Files
Resources/Materials/FluidMaterial/None.FCMat
Resources/Materials/FluidMaterial/Air.FCMat
Resources/Materials/FluidMaterial/Argon.FCMat
Resources/Materials/FluidMaterial/Carbon_dioxide.FCMat
Resources/Materials/FluidMaterial/Nitrogen.FCMat
Resources/Materials/FluidMaterial/Water.FCMat
)
SET(AppearanceLib_Files
Resources/Materials/Appearance/Aluminum.FCMat
Resources/Materials/Appearance/Brass.FCMat
Resources/Materials/Appearance/Bronze.FCMat
Resources/Materials/Appearance/Chrome.FCMat
Resources/Materials/Appearance/Copper.FCMat
Resources/Materials/Appearance/DefaultAppearance.FCMat
Resources/Materials/Appearance/Emerald.FCMat
Resources/Materials/Appearance/Gold.FCMat
Resources/Materials/Appearance/Jade.FCMat
Resources/Materials/Appearance/Metalized.FCMat
Resources/Materials/Appearance/NeonGNC.FCMat
Resources/Materials/Appearance/NeonPHC.FCMat
Resources/Materials/Appearance/Obsidian.FCMat
Resources/Materials/Appearance/Pewter.FCMat
Resources/Materials/Appearance/Plaster.FCMat
Resources/Materials/Appearance/Plastic.FCMat
Resources/Materials/Appearance/Ruby.FCMat
Resources/Materials/Appearance/Satin.FCMat
Resources/Materials/Appearance/ShinyPlastic.FCMat
Resources/Materials/Appearance/Silver.FCMat
Resources/Materials/Appearance/Steel.FCMat
Resources/Materials/Appearance/Stone.FCMat
)
SET(MaterialModel_Files
Resources/Models/Architectural/Architectural.yml
Resources/Models/Costs/Costs.yml
Resources/Models/Electromagnetic/Electromagnetic.yml
Resources/Models/Fluid/Fluid.yml
Resources/Models/Legacy/Father.yml
Resources/Models/Legacy/MaterialStandard.yml
Resources/Models/Mechanical/Density.yml
Resources/Models/Mechanical/HypotheticalExample.yml
Resources/Models/Mechanical/IsotropicLinearElastic.yml
Resources/Models/Mechanical/LinearElastic.yml
Resources/Models/Mechanical/OgdenYld2004p18.yml
Resources/Models/Mechanical/OrthotropicLinearElastic.yml
Resources/Models/Rendering/AdvancedRendering.yml
Resources/Models/Rendering/BasicRendering.yml
Resources/Models/Rendering/TextureRendering.yml
Resources/Models/Rendering/VectorRendering.yml
Resources/Models/Thermal/Thermal.yml
)
ADD_CUSTOM_TARGET(MaterialScripts ALL
SOURCES ${MaterialScripts_Files} ${Material_QRC_SRCS}
)
fc_target_copy_resource(MaterialScripts
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/Mod/Material
${Material_SRCS})
${MaterialScripts_Files})
INSTALL(FILES ${MaterialScripts_Files} DESTINATION Mod/Material)
ADD_CUSTOM_TARGET(MaterialToolsLib ALL
SOURCES ${MaterialTools_Files}
@@ -191,42 +238,47 @@ fc_target_copy_resource(MaterialIconsLib
INSTALL(FILES ${MaterialTools_Files} DESTINATION Mod/Material/materialtools)
INSTALL(FILES ${Material_Icon_Files} DESTINATION Mod/Material/Resources/icons)
IF (BUILD_GUI)
fc_target_copy_resource(Material
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_BINARY_DIR}/Mod/Material
Material_rc.py)
ENDIF (BUILD_GUI)
ADD_CUSTOM_TARGET(MaterialLib ALL
SOURCES ${MaterialLib_Files}
)
ADD_CUSTOM_TARGET(FluidMaterialLib ALL
SOURCES ${FluidMaterial_Files}
)
ADD_CUSTOM_TARGET(AppearanceLib ALL
SOURCES ${AppearanceLib_Files}
)
ADD_CUSTOM_TARGET(MaterialModelLib ALL
SOURCES ${MaterialModel_Files}
)
# When a target copies files to different output directories then apparently it always builds the project
# which is very annoying. So, the trick is to split this into two targets to avoid this behaviour.
fc_target_copy_resource(MaterialLib
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material/
${MaterialLib_Files})
fc_target_copy_resource(FluidMaterialLib
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material/
${FluidMaterial_Files})
fc_target_copy_resource(AppearanceLib
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material/
${AppearanceLib_Files})
fc_target_copy_resource(MaterialModelLib
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material/
${MaterialModel_Files})
INSTALL(
FILES ${Material_SRCS} ${Material_QRC_SRCS}
DESTINATION Mod/Material
)
INSTALL(
DIRECTORY
StandardMaterial
DIRECTORY
FluidMaterial
DESTINATION
${CMAKE_INSTALL_DATADIR}/Mod/Material
FILES_MATCHING PATTERN "*.FCMat*"
)
foreach(file ${MaterialLib_Files} ${FluidMaterial_Files} ${AppearanceLib_Files} ${MaterialModel_Files})
cmake_path(REMOVE_FILENAME file OUTPUT_VARIABLE filepath)
INSTALL(
FILES ${file}
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/Material/${filepath}
)
endforeach()

View File

@@ -1,24 +0,0 @@
[General]
Name = Air
Description = Dry air properties at 20 Degrees Celsius and 1 atm
MolarMass = 28.965
Father = Gas
[Fluidic]
Density = 1.204 kg/m^3
DynamicViscosity = 1.80e-5 kg/m/s
KinematicViscosity = 1.511e-5 m^2/s
; PrandtlNumber is a nondimension number for CFD simulation
PrandtlNumber = 0.7
[Thermal]
SpecificHeat = 1.01 kJ/kg/K
ThermalConductivity = 0.02587 W/m/K
; thermal expansion coefficient of ideal gas is 1/temperature
ThermalExpansionCoefficient = 3.43e-3 1/K
[Electromagnetic]
RelativePermittivity = 1.00059
; at 18°C and 50Hz
ElectricalConductivity = 1e-12 S/m
RelativePermeability = 1.0

View File

@@ -1,24 +0,0 @@
[General]
Name = Argon
Description = Argon properties at 20 Degrees Celsius and 1 atm
MolarMass = 39.95
Father = Gas
[Fluidic]
Density = 1.641 kg/m^3
DynamicViscosity = 22.3e-6 kg/m/s
; Kinematic Viscosity = Dynamic Viscosity / Density
KinematicViscosity = 13.59-6 m^2/s
; PrandtlNumber is a nondimension number for CFD simulation
PrandtlNumber = 0.7
[Thermal]
SpecificHeat = 0.520 kJ/kg/K
ThermalConductivity = 0.018 W/m/K
; thermal expansion coefficient of ideal gas is 1/temperature
ThermalExpansionCoefficient = 3.43e-3 1/K
[Electromagnetic]
RelativePermittivity = 1.000513
ElectricalConductivity = 1e-15 S/m
RelativePermeability = 1.0

View File

@@ -1,24 +0,0 @@
[General]
Name = Carbon dioxide
Description = Carbon dioxide properties at 20 Degrees Celsius and 1 atm
MolarMass = 44.009
Father = Gas
[Fluidic]
Density = 1.8393 kg/m^3
DynamicViscosity = 14.7e-6 kg/m/s
; Kinematic Viscosity = Dynamic Viscosity / Density
KinematicViscosity = 8.09e-6 m^2/s
; PrandtlNumber is a nondimension number for CFD simulation
PrandtlNumber = 0.7651
[Thermal]
SpecificHeat = 0.8460 kJ/kg/K
ThermalConductivity = 0.016242 W/m/K
; thermal expansion coefficient of ideal gas is 1/temperature
ThermalExpansionCoefficient = 3.43e-3 1/K
[Electromagnetic]
RelativePermittivity = 1.0009217
ElectricalConductivity = 1e-12 S/m
RelativePermeability = 1.0

View File

@@ -1,24 +0,0 @@
[General]
Name = Nitrogen
Description = Nitrogen properties at 20 Degrees Celsius and 1 atm
MolarMass = 14.007
Father = Gas
[Fluidic]
Density = 1.2506 kg/m^3
DynamicViscosity = 17.58e-6 kg/m/s
; Kinematic Viscosity = Dynamic Viscosity / Density
KinematicViscosity = 14.06e-6 m^2/s
; PrandtlNumber is a nondimension number for CFD simulation
PrandtlNumber = 0.7
[Thermal]
SpecificHeat = 1.04 kJ/kg/K
ThermalConductivity = 25.83e-3 W/m/K
; thermal expansion coefficient of ideal gas is 1/temperature
ThermalExpansionCoefficient = 3.43e-3 1/K
[Electromagnetic]
RelativePermittivity = 1.00058
ElectricalConductivity = 1e-12 S/m
RelativePermeability = 1.0

View File

@@ -1,15 +0,0 @@
; None means nothing, as the starting point of making a new fluid material
[General]
Name = None
Description = "None"
[Fluidic]
Density = 0 kg/m^3
DynamicViscosity = 0 kg/m/s
KinematicViscosity = 0 m^2/s
[Thermal]
SpecificHeat = 0 J/kg/K
ThermalConductivity = 0 W/m/K
ThermalExpansionCoefficient = 0 1/K

View File

@@ -1,31 +0,0 @@
# FreeCAD fluid material library
It's intended to gather the most common fluid properties, water, air, which are useful for other modules and workbenches.
## User defined material
To prevent the database from becoming inefficiently large it is only limited to commonly used variables at 20 degrees Celsius at 1 atm.
Users can defined new material, either in Fem material card editor, or directly generate textual material file, * .FCMat, see example in this folder.
To enable new material, go to FreeCAD menu "Edit->Preference..." Cfd preference page (select on the left panel) and switch to materiai tab on the right.
Browse to your material folder, and save/apply this preference, new material will be Material with same name as FreeCAD material has higher priority, so user defined `Water` material will not appear in Fem material task panel's dropbox list, just give it a different name!
### Edit material value
Please verify the fluid material properties before use. It aims to serve as a quick reference and does not aim to be an extended look up table.
## Add new material to Material module
1. follow examples in material folders to create new material file
2. stick to the meta data definition in `src/Mod/Material/Templatematerial.yml` for property name
3. add the file name into the `src/Mod/Material/CMakeLists.txt` , so the new files can be installed to the properly place during compiling and installation.
## Changelog
CfdOF module authored 5 material types, values are taken from FM White (2011) Fluid Mechanics.
Currently, 3 (Water, Air, None) are merged into Fem module and maintained by Cfd module author, Qingfeng Xia

View File

@@ -1,26 +0,0 @@
; see meta data definition in the file: src/Mod/Material/Templatematerial.yml
[General]
Name = Water
Description = Standard distilled water properties at 20 Degrees Celsius and 1 atm
MolarMass = 18
Father = Gas
ReferenceSource = ''
[Fluidic]
Density = 998 kg/m^3
DynamicViscosity = 1.003e-3 kg/m/s
KinematicViscosity = 1.005e-6 m^2/s
; PrandtlNumber is a nondimension number for CFD simulation
PrandtlNumber = 7.56
[Thermal]
SpecificHeat = 4182 J/kg/K
ThermalConductivity = 0.591 W/m/K
; https://en.wikipedia.org/wiki/Water
ThermalExpansionCoefficient = 2.07e-4 m/m/K
[Electromagnetic]
RelativePermittivity = 80.0
; at 20°C and 50Hz
ElectricalConductivity = 5.5e-6 S/m
RelativePermeability = 0.999992

View File

@@ -0,0 +1,105 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License (LGPL) *
* as published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* for detail see the LICENCE text file. *
* *
* FreeCAD is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with FreeCAD; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <Base/PyObjectBase.h>
#include <Gui/Application.h>
#include <Gui/Language/Translator.h>
#include <Gui/WidgetFactory.h>
#include "DlgSettingsMaterial.h"
// use a different name to CreateCommand()
void CreateMaterialCommands();
void loadMaterialResource()
{
// add resources and reloads the translators
Q_INIT_RESOURCE(Material);
Q_INIT_RESOURCE(Material_translation);
Gui::Translator::instance()->refresh();
}
namespace MatGui
{
class Module: public Py::ExtensionModule<Module>
{
public:
Module()
: Py::ExtensionModule<Module>("MatGui")
{
initialize("This module is the MatGui module.");// register with Python
}
~Module() override
{}
private:
};
PyObject* initModule()
{
return Base::Interpreter().addModule(new Module);
}
}// namespace MatGui
PyMOD_INIT_FUNC(MatGui)
{
if (!Gui::Application::Instance) {
PyErr_SetString(PyExc_ImportError, "Cannot load Gui module in console application.");
PyMOD_Return(nullptr);
}
// load needed modules
try {
Base::Interpreter().runString("import Material");
}
catch (const Base::Exception& e) {
PyErr_SetString(PyExc_ImportError, e.what());
PyMOD_Return(nullptr);
}
PyObject* matGuiModule = MatGui::initModule();
Base::Console().Log("Loading GUI of Material module... done\n");
// instantiating the commands
CreateMaterialCommands();
// register preferences pages on Material, the order here will be the order of the tabs in pref
// widget
new Gui::PrefPageProducer<MatGui::DlgSettingsMaterial>(
QT_TRANSLATE_NOOP("QObject", "Material"));
// add resources and reloads the translators
loadMaterialResource();
PyMOD_Return(matGuiModule);
}

View File

@@ -0,0 +1,158 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QMessageBox>
#endif
#include <Gui/MainWindow.h>
#include <Mod/Material/App/Exceptions.h>
#include <Mod/Material/App/Materials.h>
#include "Array2D.h"
#include "ArrayDelegate.h"
#include "ArrayModel.h"
#include "ui_Array2D.h"
using namespace MatGui;
/* TRANSLATOR MatGui::Array2D */
Array2D::Array2D(const QString& propertyName, Materials::Material* material, QWidget* parent)
: QDialog(parent)
, ui(new Ui_Array2D)
{
ui->setupUi(this);
if (material->hasPhysicalProperty(propertyName)) {
_property = &(material->getPhysicalProperty(propertyName));
}
else if (material->hasAppearanceProperty(propertyName)) {
_property = &(material->getAppearanceProperty(propertyName));
}
else {
_property = nullptr;
}
if (_property) {
_value = static_cast<Materials::Material2DArray*>(_property->getMaterialValue());
}
else {
_value = nullptr;
}
setupDefault();
setupArray();
connect(ui->standardButtons, &QDialogButtonBox::accepted, this, &Array2D::accept);
connect(ui->standardButtons, &QDialogButtonBox::rejected, this, &Array2D::reject);
}
void Array2D::setupDefault()
{
if (_property == nullptr) {
return;
}
try {
Materials::MaterialProperty& column1 = _property->getColumn(0);
QString label = QString::fromStdString("Default ") + column1.getName();
ui->labelDefault->setText(label);
if (column1.getPropertyType() == QString::fromStdString("Quantity")) {
ui->editDefault->setMinimum(std::numeric_limits<double>::min());
ui->editDefault->setMaximum(std::numeric_limits<double>::max());
ui->editDefault->setUnitText(_property->getColumnUnits(0));
ui->editDefault->setValue(_value->getDefault().getValue().value<Base::Quantity>());
connect(ui->editDefault,
qOverload<const Base::Quantity&>(&Gui::QuantitySpinBox::valueChanged),
this,
&Array2D::defaultValueChanged);
}
}
catch (const Materials::PropertyNotFound&) {
return;
}
}
void Array2D::setHeaders(QStandardItemModel* model)
{
QStringList headers;
auto columns = _property->getColumns();
for (auto column = columns.begin(); column != columns.end(); column++) {
headers.append(column->getName());
}
model->setHorizontalHeaderLabels(headers);
}
void Array2D::setColumnWidths(QTableView* table)
{
int length = _property->columns();
for (int i = 0; i < length; i++) {
table->setColumnWidth(i, 100);
}
}
void Array2D::setColumnDelegates(QTableView* table)
{
int length = _property->columns();
for (int i = 0; i < length; i++) {
Materials::MaterialProperty& column = _property->getColumn(i);
table->setItemDelegateForColumn(
i,
new ArrayDelegate(column.getType(), column.getUnits(), this));
}
}
void Array2D::setupArray()
{
if (_property == nullptr) {
return;
}
auto table = ui->tableView;
auto model = new Array2DModel(_property, _value, this);
table->setModel(model);
table->setEditTriggers(QAbstractItemView::AllEditTriggers);
setColumnWidths(table);
setColumnDelegates(table);
}
void Array2D::defaultValueChanged(const Base::Quantity& value)
{
_value->setDefault(QVariant::fromValue(value));
}
void Array2D::accept()
{
QDialog::accept();
}
void Array2D::reject()
{
QDialog::reject();
}
#include "moc_Array2D.cpp"

View File

@@ -0,0 +1,68 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_ARRAY2D_H
#define MATGUI_ARRAY2D_H
#include <QAbstractTableModel>
#include <QDialog>
#include <QStandardItem>
#include <QTableView>
#include "ArrayModel.h"
#include <Mod/Material/App/Model.h>
namespace MatGui
{
class Ui_Array2D;
class Array2D: public QDialog
{
Q_OBJECT
public:
explicit Array2D(const QString& propertyName,
Materials::Material* material,
QWidget* parent = nullptr);
~Array2D() override = default;
void defaultValueChanged(const Base::Quantity& value);
void accept() override;
void reject() override;
private:
std::unique_ptr<Ui_Array2D> ui;
Materials::MaterialProperty* _property;
Materials::Material2DArray* _value;
void setupDefault();
void setHeaders(QStandardItemModel* model);
void setColumnWidths(QTableView* table);
void setColumnDelegates(QTableView* table);
void setupArray();
};
}// namespace MatGui
#endif// MATGUI_ARRAY2D_H

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MatGui::Array2D</class>
<widget class="QDialog" name="MatGui::Array2D">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>578</width>
<height>557</height>
</rect>
</property>
<property name="windowTitle">
<string>2D Array</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="labelDefault">
<property name="text">
<string>Default Value</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::QuantitySpinBox" name="editDefault" native="true">
<property name="unit" stdset="0">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableView" name="tableView"/>
</item>
<item>
<widget class="QDialogButtonBox" name="standardButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::QuantitySpinBox</class>
<extends>QWidget</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>standardButtons</sender>
<signal>accepted()</signal>
<receiver>MatGui::Array2D</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>standardButtons</sender>
<signal>rejected()</signal>
<receiver>MatGui::Array2D</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,198 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QMessageBox>
#include <QPushButton>
#endif
#include <Gui/MainWindow.h>
#include <Mod/Material/App/Exceptions.h>
#include <Mod/Material/App/Materials.h>
#include "Array3D.h"
#include "ArrayDelegate.h"
#include "ArrayModel.h"
#include "ui_Array3D.h"
using namespace MatGui;
Array3D::Array3D(const QString& propertyName, Materials::Material* material, QWidget* parent)
: QDialog(parent)
, ui(new Ui_Array3D)
{
ui->setupUi(this);
if (material->hasPhysicalProperty(propertyName)) {
_property = &(material->getPhysicalProperty(propertyName));
}
else if (material->hasAppearanceProperty(propertyName)) {
_property = &(material->getAppearanceProperty(propertyName));
}
else {
_property = nullptr;
}
if (_property) {
_value = static_cast<Materials::Material3DArray*>(_property->getMaterialValue());
}
else {
_value = nullptr;
}
setupDefault();
setupDepthArray();
setupArray();
Base::Console().Log("Material '%s'\n", material->getName().toStdString().c_str());
Base::Console().Log("\tproperty '%s'\n", propertyName.toStdString().c_str());
// connect(ui->splitter, &QSplitter::event,
// this, &Array3D::onSplitter);
connect(ui->standardButtons->button(QDialogButtonBox::Ok),
&QPushButton::clicked,
this,
&Array3D::onOk);
connect(ui->standardButtons->button(QDialogButtonBox::Cancel),
&QPushButton::clicked,
this,
&Array3D::onCancel);
}
bool Array3D::onSplitter(QEvent* e)
{
Q_UNUSED(e)
return false;
}
void Array3D::setupDefault()
{
if (_property == nullptr) {
return;
}
try {
Materials::MaterialProperty& column1 = _property->getColumn(0);
QString label = QString::fromStdString("Default ") + column1.getName();
ui->labelDefault->setText(label);
if (column1.getPropertyType() == QString::fromStdString("Quantity")) {
ui->editDefault->setMinimum(std::numeric_limits<double>::min());
ui->editDefault->setMaximum(std::numeric_limits<double>::max());
ui->editDefault->setUnitText(_property->getColumnUnits(0));
ui->editDefault->setValue(_value->getDefault().getValue().value<Base::Quantity>());
connect(ui->editDefault,
qOverload<const Base::Quantity&>(&Gui::QuantitySpinBox::valueChanged),
this,
&Array3D::defaultValueChanged);
}
}
catch (const Materials::PropertyNotFound&) {
return;
}
}
void Array3D::defaultValueChanged(const Base::Quantity& value)
{
_value->setDefault(QVariant::fromValue(value));
}
void Array3D::setDepthColumnDelegate(QTableView* table)
{
Materials::MaterialProperty& column = _property->getColumn(0);
table->setItemDelegateForColumn(0,
new ArrayDelegate(column.getType(), column.getUnits(), this));
}
void Array3D::setDepthColumnWidth(QTableView* table)
{
table->setColumnWidth(0, 100);
}
void Array3D::setupDepthArray()
{
if (_property == nullptr) {
return;
}
auto table = ui->table3D;
auto model = new Array3DDepthModel(_property, _value, this);
table->setModel(model);
table->setEditTriggers(QAbstractItemView::AllEditTriggers);
setDepthColumnWidth(table);
setDepthColumnDelegate(table);
}
void Array3D::setColumnWidths(QTableView* table)
{
int length = _property->columns();
for (int i = 0; i < length; i++) {
table->setColumnWidth(i, 100);
}
}
void Array3D::setColumnDelegates(QTableView* table)
{
int length = _property->columns();
for (int i = 0; i < length; i++) {
Materials::MaterialProperty& column = _property->getColumn(i);
table->setItemDelegateForColumn(
i,
new ArrayDelegate(column.getType(), column.getUnits(), this));
}
}
void Array3D::setupArray()
{
if (_property == nullptr) {
return;
}
auto table = ui->table2D;
auto model = new Array3DModel(_property, _value, this);
table->setModel(model);
table->setEditTriggers(QAbstractItemView::AllEditTriggers);
setColumnWidths(table);
setColumnDelegates(table);
}
void Array3D::onOk(bool checked)
{
Q_UNUSED(checked)
QDialog::accept();
}
void Array3D::onCancel(bool checked)
{
Q_UNUSED(checked)
QDialog::reject();
}
#include "moc_Array3D.cpp"

View File

@@ -0,0 +1,67 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_ARRAY3D_H
#define MATGUI_ARRAY3D_H
#include <QDialog>
#include <QStandardItem>
#include <QTableView>
namespace MatGui
{
class Ui_Array3D;
class Array3D: public QDialog
{
Q_OBJECT
public:
explicit Array3D(const QString& propertyName,
Materials::Material* material,
QWidget* parent = nullptr);
~Array3D() override = default;
void defaultValueChanged(const Base::Quantity& value);
bool onSplitter(QEvent* e);
void onOk(bool checked);
void onCancel(bool checked);
private:
std::unique_ptr<Ui_Array3D> ui;
Materials::MaterialProperty* _property;
Materials::Material3DArray* _value;
void setupDefault();
void setDepthColumnWidth(QTableView* table);
void setDepthColumnDelegate(QTableView* table);
void setupDepthArray();
void setColumnWidths(QTableView* table);
void setColumnDelegates(QTableView* table);
void setupArray();
};
}// namespace MatGui
#endif// MATGUI_ARRAY3D_H

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MatGui::Array3D</class>
<widget class="QDialog" name="MatGui::Array3D">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>915</width>
<height>709</height>
</rect>
</property>
<property name="windowTitle">
<string>3D Array</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="labelDefault">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Default Value</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::QuantitySpinBox" name="editDefault" native="true">
<property name="unit" stdset="0">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTableView" name="table3D"/>
<widget class="QTableView" name="table2D"/>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="standardButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::QuantitySpinBox</class>
<extends>QWidget</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>standardButtons</sender>
<signal>accepted()</signal>
<receiver>MatGui::Array3D</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>standardButtons</sender>
<signal>rejected()</signal>
<receiver>MatGui::Array3D</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,184 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QColorDialog>
#include <QDesktopServices>
#include <QIODevice>
#include <QItemSelectionModel>
#include <QPainter>
#include <QString>
#include <QStringList>
#include <QTextStream>
#include <QVariant>
#endif
#include <limits>
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <Base/Quantity.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/InputField.h>
#include <Gui/PrefWidgets.h>
#include <Gui/SpinBox.h>
#include <Gui/WaitCursor.h>
// #include <Gui/FileDialog.h>
#include <Mod/Material/App/Exceptions.h>
#include <Mod/Material/App/ModelManager.h>
#include "Array2D.h"
#include "Array3D.h"
#include "ArrayDelegate.h"
#include "MaterialSave.h"
using namespace MatGui;
ArrayDelegate::ArrayDelegate(Materials::MaterialValue::ValueType type,
QString units,
QObject* parent)
: QStyledItemDelegate(parent)
, _type(type)
, _units(units)
{}
void ArrayDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
if (_type == Materials::MaterialValue::Quantity) {
const AbstractArrayModel* tableModel =
reinterpret_cast<const AbstractArrayModel*>(index.model());
painter->save();
if (tableModel->newRow(index)) {
painter->drawText(option.rect, 0, QString());
}
else {
QVariant item = tableModel->data(index);
Base::Quantity quantity = item.value<Base::Quantity>();
QString text = quantity.getUserString();
painter->drawText(option.rect, 0, text);
}
painter->restore();
}
else {
QStyledItemDelegate::paint(painter, option, index);
}
}
void ArrayDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
Base::Console().Log("ArrayDelegate::setEditorData()\n");
if (_type == Materials::MaterialValue::Quantity) {
QAbstractItemModel* tableModel = const_cast<QAbstractItemModel*>(index.model());
auto item = tableModel->data(index);
// Gui::InputField* input = static_cast<Gui::InputField*>(editor);
// input->setText(item.toString());
Gui::QuantitySpinBox* input = static_cast<Gui::QuantitySpinBox*>(editor);
input->setValue(item.value<Base::Quantity>());
}
else {
QStyledItemDelegate::setEditorData(editor, index);
}
}
QWidget* ArrayDelegate::createEditor(QWidget* parent,
const QStyleOptionViewItem&,
const QModelIndex& index) const
{
Base::Console().Log("ArrayDelegate::createEditor()\n");
const QAbstractTableModel* tableModel = static_cast<const QAbstractTableModel*>(index.model());
auto item = tableModel->data(index);
QWidget* editor = createWidget(parent, item);
return editor;
}
QWidget* ArrayDelegate::createWidget(QWidget* parent, const QVariant& item) const
{
QWidget* widget = nullptr;
if (_type == Materials::MaterialValue::String || _type == Materials::MaterialValue::URL
|| _type == Materials::MaterialValue::List) {
widget = new Gui::PrefLineEdit(parent);
}
else if (_type == Materials::MaterialValue::Integer) {
Gui::UIntSpinBox* spinner = new Gui::UIntSpinBox(parent);
spinner->setMinimum(0);
spinner->setMaximum(UINT_MAX);
spinner->setValue(item.toUInt());
widget = spinner;
}
else if (_type == Materials::MaterialValue::Float) {
Gui::DoubleSpinBox* spinner = new Gui::DoubleSpinBox(parent);
// the magnetic permeability is the parameter for which many decimals matter
// the most however, even for this, 6 digits are sufficient
spinner->setDecimals(6);
// for almost all Float parameters of materials a step of 1 would be too large
spinner->setSingleStep(0.1);
spinner->setMinimum(std::numeric_limits<double>::min());
spinner->setMaximum(std::numeric_limits<double>::max());
spinner->setValue(item.toDouble());
widget = spinner;
}
else if (_type == Materials::MaterialValue::Boolean) {
Gui::PrefComboBox* combo = new Gui::PrefComboBox(parent);
combo->insertItem(0, QString::fromStdString(""));
combo->insertItem(1, QString::fromStdString("False"));
combo->insertItem(2, QString::fromStdString("True"));
combo->setCurrentText(item.toString());
widget = combo;
}
else if (_type == Materials::MaterialValue::Quantity) {
Gui::QuantitySpinBox* input = new Gui::QuantitySpinBox();
input->setMinimum(std::numeric_limits<double>::min());
input->setMaximum(std::numeric_limits<double>::max());
input->setUnitText(_units);
input->setValue(item.value<Base::Quantity>());
widget = input;
}
else {
// Default editor
widget = new QLineEdit(parent);
}
widget->setParent(parent);
return widget;
}
#include "moc_ArrayDelegate.cpp"

View File

@@ -0,0 +1,75 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_ArrayDelegate_H
#define MATGUI_ArrayDelegate_H
#include <boost/filesystem.hpp>
#include <QDialog>
#include <QDir>
#include <QStandardItem>
#include <QStyledItemDelegate>
#include <QSvgWidget>
#include <QTreeView>
#include <Mod/Material/App/MaterialManager.h>
#include <Mod/Material/App/Materials.h>
#include <Mod/Material/App/ModelManager.h>
namespace fs = boost::filesystem;
namespace MatGui
{
class ArrayDelegate: public QStyledItemDelegate
{
Q_OBJECT
public:
explicit ArrayDelegate(
Materials::MaterialValue::ValueType type = Materials::MaterialValue::None,
QString units = QString(),
QObject* parent = nullptr);
virtual ~ArrayDelegate() = default;
void paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
QWidget* createEditor(QWidget* parent,
const QStyleOptionViewItem&,
const QModelIndex& index) const override;
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
// Q_SIGNALS:
/** Emits this signal when a property has changed */
// void propertyChange(const QString &property, const QString value);
private:
Materials::MaterialValue::ValueType _type;
QString _units;
QWidget* createWidget(QWidget* parent, const QVariant& item) const;
};
}// namespace MatGui
#endif// MATGUI_ArrayDelegate_H

View File

@@ -0,0 +1,466 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QMessageBox>
#endif
#include <QMetaType>
#include <Gui/MainWindow.h>
#include <Gui/MetaTypes.h>
#include <Mod/Material/App/Exceptions.h>
#include <Mod/Material/App/Materials.h>
#include "ArrayModel.h"
using namespace MatGui;
/* TRANSLATOR MatGui::ArrayModel */
AbstractArrayModel::AbstractArrayModel(QObject* parent)
: QAbstractTableModel(parent)
{}
//===
Array2DModel::Array2DModel(Materials::MaterialProperty* property,
Materials::Material2DArray* value,
QObject* parent)
: AbstractArrayModel(parent)
, _property(property)
, _value(value)
{}
int Array2DModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid()) {
return 0;// No children
}
return _value->rows() + 1;// Will always have 1 empty row
}
bool Array2DModel::newRow(const QModelIndex& index) const
{
return (index.row() == _value->rows());
}
int Array2DModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return _property->columns();
}
QVariant Array2DModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::DisplayRole) {
try {
return _value->getValue(index.row(), index.column());
}
catch (const Materials::InvalidIndex&) {
}
try {
auto column = _property->getColumnType(index.column());
if (column == Materials::MaterialValue::Quantity) {
Base::Quantity q = Base::Quantity(0, _property->getColumnUnits(index.column()));
return QVariant::fromValue(q);
}
}
catch (const Materials::InvalidColumn&) {
}
return QString();
}
return QVariant();
}
QVariant Array2DModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole) {
if (orientation == Qt::Horizontal) {
Materials::MaterialProperty& column = _property->getColumn(section);
return QVariant(column.getName());
}
else if (orientation == Qt::Vertical) {
// Vertical header
if (section == (rowCount() - 1)) {
return QVariant(QString::fromStdString("*"));
}
return QVariant(section + 1);
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
bool Array2DModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
Q_UNUSED(role);
if (index.row() == _value->rows()) {
insertRows(index.row(), 1);
}
_value->setValue(index.row(), index.column(), value);
Q_EMIT dataChanged(index, index);
return true;
}
Qt::ItemFlags Array2DModel::flags(const QModelIndex& index) const
{
return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
}
// Resizing functions
bool Array2DModel::insertRows(int row, int count, const QModelIndex& parent)
{
beginInsertRows(parent, row, row + count - 1);
int columns = columnCount();
for (int i = 0; i < count; i++) {
std::vector<QVariant>* rowPtr = new std::vector<QVariant>();
for (int j = 0; j < columns; j++) {
rowPtr->push_back(_property->getColumnNull(j));
}
_value->insertRow(row, rowPtr);
}
endInsertRows();
return false;
}
bool Array2DModel::removeRows(int row, int count, const QModelIndex& parent)
{
beginRemoveRows(parent, row, row + count - 1);
endRemoveRows();
return false;
}
bool Array2DModel::insertColumns(int column, int count, const QModelIndex& parent)
{
Q_UNUSED(column);
Q_UNUSED(count);
Q_UNUSED(parent);
return false;
}
bool Array2DModel::removeColumns(int column, int count, const QModelIndex& parent)
{
Q_UNUSED(column);
Q_UNUSED(count);
Q_UNUSED(parent);
return false;
}
//===
Array3DDepthModel::Array3DDepthModel(Materials::MaterialProperty* property,
Materials::Material3DArray* value,
QObject* parent)
: AbstractArrayModel(parent)
, _property(property)
, _value(value)
{}
int Array3DDepthModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid()) {
return 0;// No children
}
return _value->depth() + 1;// Will always have 1 empty row
}
bool Array3DDepthModel::newRow(const QModelIndex& index) const
{
return (index.row() == _value->depth());
}
QVariant Array3DDepthModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::DisplayRole) {
try {
return _value->getValue(index.row(), index.column());
}
catch (const Materials::InvalidIndex&) {
}
try {
auto column = _property->getColumnType(index.column());
if (column == Materials::MaterialValue::Quantity) {
Base::Quantity q = Base::Quantity(0, _property->getColumnUnits(index.column()));
return QVariant::fromValue(q);
}
}
catch (const Materials::InvalidColumn&) {
}
return QString();
}
return QVariant();
}
QVariant Array3DDepthModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole) {
if (orientation == Qt::Horizontal) {
Materials::MaterialProperty& column = _property->getColumn(section);
return QVariant(column.getName());
}
else if (orientation == Qt::Vertical) {
// Vertical header
if (section == (rowCount() - 1)) {
return QVariant(QString::fromStdString("*"));
}
return QVariant(section + 1);
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
bool Array3DDepthModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
Q_UNUSED(role);
if (index.row() == _value->depth()) {
insertRows(index.row(), 1);
}
_value->setValue(index.row(), index.column(), value);
Q_EMIT dataChanged(index, index);
return true;
}
Qt::ItemFlags Array3DDepthModel::flags(const QModelIndex& index) const
{
return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
}
// Resizing functions
bool Array3DDepthModel::insertRows(int row, int count, const QModelIndex& parent)
{
beginInsertRows(parent, row, row + count - 1);
int columns = columnCount();
for (int i = 0; i < count; i++) {
std::vector<QVariant>* rowPtr = new std::vector<QVariant>();
for (int j = 0; j < columns; j++) {
rowPtr->push_back(_property->getColumnNull(j));
}
// _value->insertRow(row, rowPtr);
}
endInsertRows();
return false;
}
bool Array3DDepthModel::removeRows(int row, int count, const QModelIndex& parent)
{
beginRemoveRows(parent, row, row + count - 1);
endRemoveRows();
return false;
}
bool Array3DDepthModel::insertColumns(int column, int count, const QModelIndex& parent)
{
Q_UNUSED(column);
Q_UNUSED(count);
Q_UNUSED(parent);
return false;
}
bool Array3DDepthModel::removeColumns(int column, int count, const QModelIndex& parent)
{
Q_UNUSED(column);
Q_UNUSED(count);
Q_UNUSED(parent);
return false;
}
//===
Array3DModel::Array3DModel(Materials::MaterialProperty* property,
Materials::Material3DArray* value,
QObject* parent)
: AbstractArrayModel(parent)
, _property(property)
, _value(value)
{}
int Array3DModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid()) {
return 0;// No children
}
return _value->depth() + 1;// Will always have 1 empty row
}
int Array3DModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return _property->columns() - 1;
}
bool Array3DModel::newRow(const QModelIndex& index) const
{
return (index.row() == _value->depth());
}
QVariant Array3DModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::DisplayRole) {
Base::Console().Error("Row %d, column %d\n", index.row(), index.column());
try {
return _value->getValue(index.row(), index.column() + 1);
}
catch (const Materials::InvalidIndex&) {
}
catch (const std::exception& e) {
Base::Console().Error("The error message is: %s\n", e.what());
}
try {
auto column = _property->getColumnType(index.column() + 1);
if (column == Materials::MaterialValue::Quantity) {
Base::Quantity q = Base::Quantity(0, _property->getColumnUnits(index.column() - 1));
return QVariant::fromValue(q);
}
}
catch (const Materials::InvalidColumn&) {
}
return QString();
}
return QVariant();
}
QVariant Array3DModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole) {
if (orientation == Qt::Horizontal) {
Materials::MaterialProperty& column = _property->getColumn(section + 1);
return QVariant(column.getName());
}
else if (orientation == Qt::Vertical) {
// Vertical header
if (section == (rowCount() - 1)) {
return QVariant(QString::fromStdString("*"));
}
return QVariant(section + 1);
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
bool Array3DModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
Q_UNUSED(role);
if (index.row() == _value->depth()) {
insertRows(index.row(), 1);
}
_value->setValue(index.row(), index.column(), value);
Q_EMIT dataChanged(index, index);
return true;
}
Qt::ItemFlags Array3DModel::flags(const QModelIndex& index) const
{
return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
}
// Resizing functions
bool Array3DModel::insertRows(int row, int count, const QModelIndex& parent)
{
beginInsertRows(parent, row, row + count - 1);
int columns = columnCount();
for (int i = 0; i < count; i++) {
std::vector<QVariant>* rowPtr = new std::vector<QVariant>();
for (int j = 0; j < columns; j++) {
rowPtr->push_back(_property->getColumnNull(j));
}
// _value->insertRow(row, rowPtr);
}
endInsertRows();
return false;
}
bool Array3DModel::removeRows(int row, int count, const QModelIndex& parent)
{
beginRemoveRows(parent, row, row + count - 1);
endRemoveRows();
return false;
}
bool Array3DModel::insertColumns(int column, int count, const QModelIndex& parent)
{
Q_UNUSED(column);
Q_UNUSED(count);
Q_UNUSED(parent);
return false;
}
bool Array3DModel::removeColumns(int column, int count, const QModelIndex& parent)
{
Q_UNUSED(column);
Q_UNUSED(count);
Q_UNUSED(parent);
return false;
}

View File

@@ -0,0 +1,139 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_ARRAYMODEL_H
#define MATGUI_ARRAYMODEL_H
#include <QAbstractTableModel>
#include <QDialog>
#include <QStandardItem>
#include <QTableView>
#include <Mod/Material/App/Materials.h>
#include <Mod/Material/App/Model.h>
namespace MatGui
{
class AbstractArrayModel: public QAbstractTableModel
{
public:
explicit AbstractArrayModel(QObject* parent = nullptr);
~AbstractArrayModel() override = default;
virtual bool newRow(const QModelIndex& index) const = 0;
};
class Array2DModel: public AbstractArrayModel
{
public:
explicit Array2DModel(Materials::MaterialProperty* property = nullptr,
Materials::Material2DArray* value = nullptr,
QObject* parent = nullptr);
~Array2DModel() override = default;
// Overridden virtual functions
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
bool newRow(const QModelIndex& index) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant
headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
// Resizing functions
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
private:
Materials::MaterialProperty* _property;
Materials::Material2DArray* _value;
};
class Array3DDepthModel: public AbstractArrayModel
{
public:
explicit Array3DDepthModel(Materials::MaterialProperty* property = nullptr,
Materials::Material3DArray* value = nullptr,
QObject* parent = nullptr);
~Array3DDepthModel() override = default;
// Overridden virtual functions
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
bool newRow(const QModelIndex& index) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override
{
Q_UNUSED(parent)
return 1;
}
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant
headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
// Resizing functions
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
private:
Materials::MaterialProperty* _property;
Materials::Material3DArray* _value;
};
class Array3DModel: public AbstractArrayModel
{
public:
explicit Array3DModel(Materials::MaterialProperty* property = nullptr,
Materials::Material3DArray* value = nullptr,
QObject* parent = nullptr);
~Array3DModel() override = default;
// Overridden virtual functions
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
bool newRow(const QModelIndex& index) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant
headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
// Resizing functions
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
private:
Materials::MaterialProperty* _property;
Materials::Material3DArray* _value;
};
}// namespace MatGui
#endif// MATGUI_ARRAYMODEL_H

View File

@@ -0,0 +1,106 @@
if(MSVC)
add_definitions(-DHAVE_ACOSH -DHAVE_ATANH -DHAVE_ASINH)
else(MSVC)
add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
endif(MSVC)
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}
${Boost_INCLUDE_DIRS}
${COIN3D_INCLUDE_DIRS}
${OCC_INCLUDE_DIR}
${PYTHON_INCLUDE_DIRS}
${XercesC_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
)
link_directories(${OCC_LIBRARY_DIR})
set(MatGui_LIBS
Material
FreeCADGui
)
include_directories(
${QtConcurrent_INCLUDE_DIRS}
)
list(APPEND MatGui_LIBS
${QtConcurrent_LIBRARIES}
)
set (Material_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Material_translation.qrc)
qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts"
${CMAKE_CURRENT_BINARY_DIR}/Resources/translations)
qt_create_resource_file(${Material_TR_QRC} ${QM_SRCS})
qt_add_resources(MatGui_QRC_SRCS Resources/Material.qrc ${Material_TR_QRC})
set(MatGui_UIC_SRCS
Array2D.ui
Array3D.ui
DlgSettingsMaterial.ui
MaterialSave.ui
MaterialsEditor.ui
ModelSelect.ui
)
SET(MatGui_SRCS
${MatGui_QRC_SRCS}
${MatGui_UIC_HDRS}
AppMatGui.cpp
Array2D.cpp
Array2D.h
Array2D.ui
Array3D.cpp
Array3D.h
Array3D.ui
ArrayDelegate.cpp
ArrayDelegate.h
ArrayModel.cpp
ArrayModel.h
Command.cpp
DlgSettingsMaterial.cpp
DlgSettingsMaterial.h
DlgSettingsMaterial.ui
MaterialDelegate.cpp
MaterialDelegate.h
MaterialSave.cpp
MaterialSave.h
MaterialSave.ui
MaterialsEditor.cpp
MaterialsEditor.h
MaterialsEditor.ui
ModelSelect.cpp
ModelSelect.h
ModelSelect.ui
PreCompiled.cpp
PreCompiled.h
)
if(FREECAD_USE_PCH)
add_definitions(-D_PreComp_)
GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${MatGui_SRCS})
ADD_MSVC_PRECOMPILED_HEADER(MatGui PreCompiled.h PreCompiled.cpp PCH_SRCS)
endif(FREECAD_USE_PCH)
SET(MatGuiIcon_SVG
Resources/icons/Materials_Edit.svg
Resources/icons/MaterialWorkbench.svg
Resources/icons/preferences-material.svg
Resources/icons/preview-rendered.svg
Resources/icons/preview-vector.svg
Resources/icons/table.svg
)
add_library(MatGui SHARED ${MatGui_SRCS} ${MatGuiIcon_SVG})
target_link_libraries(MatGui ${MatGui_LIBS})
SET_BIN_DIR(MatGui MatGui /Mod/Material)
SET_PYTHON_PREFIX_SUFFIX(MatGui)
fc_copy_sources(MatGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material" ${MatGuiIcon_SVG})
INSTALL(TARGETS MatGui DESTINATION ${CMAKE_INSTALL_LIBDIR})
INSTALL(FILES ${MatGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Material/Resources/icons")

View File

@@ -0,0 +1,83 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QPointer>
#endif
#include <Gui/Command.h>
#include <Gui/MainWindow.h>
#include "MaterialSave.h"
#include "MaterialsEditor.h"
#include "ModelSelect.h"
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//===========================================================================
// Material_Edit
//===========================================================================
DEF_STD_CMD_A(CmdMaterialsEdit)
CmdMaterialsEdit::CmdMaterialsEdit()
: Command("Materials_Edit")
{
sAppModule = "Material";
sGroup = QT_TR_NOOP("Material");
sMenuText = QT_TR_NOOP("Edit...");
sToolTipText = QT_TR_NOOP("Edit material properties");
sWhatsThis = "Materials_Edit";
sStatusTip = sToolTipText;
sPixmap = "Materials_Edit";
}
void CmdMaterialsEdit::activated(int iMsg)
{
Q_UNUSED(iMsg);
Base::Console().Log("Materials_Edit\n");
static QPointer<QDialog> dlg = nullptr;
if (!dlg) {
dlg = new MatGui::MaterialsEditor(Gui::getMainWindow());
}
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
}
bool CmdMaterialsEdit::isActive()
{
// return (hasActiveDocument() && !Gui::Control().activeDialog());
return true;
}
//---------------------------------------------------------------
void CreateMaterialCommands()
{
Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager();
rcCmdMgr.addCommand(new CmdMaterialsEdit());
}

View File

@@ -24,45 +24,51 @@
#include "PreCompiled.h"
#include "DlgSettingsFemMaterialImp.h"
#include "ui_DlgSettingsFemMaterial.h"
#include "DlgSettingsMaterial.h"
#include "ui_DlgSettingsMaterial.h"
using namespace FemGui;
using namespace MatGui;
DlgSettingsFemMaterialImp::DlgSettingsFemMaterialImp(QWidget* parent)
DlgSettingsMaterial::DlgSettingsMaterial(QWidget* parent)
: PreferencePage(parent)
, ui(new Ui_DlgSettingsFemMaterialImp)
, ui(new Ui_DlgSettingsMaterial)
{
ui->setupUi(this);
}
DlgSettingsFemMaterialImp::~DlgSettingsFemMaterialImp() = default;
void DlgSettingsFemMaterialImp::saveSettings()
void DlgSettingsMaterial::saveSettings()
{
ui->cb_use_built_in_materials->onSave();
ui->cb_use_mat_from_workbenches->onSave();
ui->cb_use_mat_from_config_dir->onSave();
ui->cb_use_mat_from_custom_dir->onSave();
ui->fc_custom_mat_dir->onSave();
ui->cb_delete_duplicates->onSave();
ui->cb_sort_by_resources->onSave();
// Temporary for testing
ui->cb_legacy_editor->onSave();
}
void DlgSettingsFemMaterialImp::loadSettings()
void DlgSettingsMaterial::loadSettings()
{
ui->cb_use_built_in_materials->onRestore();
ui->cb_use_mat_from_workbenches->onRestore();
ui->cb_use_mat_from_config_dir->onRestore();
ui->cb_use_mat_from_custom_dir->onRestore();
ui->fc_custom_mat_dir->onRestore();
ui->cb_delete_duplicates->onRestore();
ui->cb_sort_by_resources->onRestore();
// Temporary for testing
ui->cb_legacy_editor->onRestore();
}
/**
* Sets the strings of the subwidgets using the current language.
*/
void DlgSettingsFemMaterialImp::changeEvent(QEvent* e)
void DlgSettingsMaterial::changeEvent(QEvent* e)
{
if (e->type() == QEvent::LanguageChange) {
ui->retranslateUi(this);
@@ -72,4 +78,4 @@ void DlgSettingsFemMaterialImp::changeEvent(QEvent* e)
}
}
#include "moc_DlgSettingsFemMaterialImp.cpp"
#include "moc_DlgSettingsMaterial.cpp"

View File

@@ -22,24 +22,24 @@
* *
***************************************************************************/
#ifndef FEMGUI_DLGSETTINGSFEMMATERIALIMP_H
#define FEMGUI_DLGSETTINGSFEMMATERIALIMP_H
#ifndef MATGUI_DLGSETTINGSMATERIAL_H
#define MATGUI_DLGSETTINGSMATERIAL_H
#include <Gui/PropertyPage.h>
#include <memory>
namespace FemGui
namespace MatGui
{
class Ui_DlgSettingsFemMaterialImp;
class Ui_DlgSettingsMaterial;
class DlgSettingsFemMaterialImp: public Gui::Dialog::PreferencePage
class DlgSettingsMaterial: public Gui::Dialog::PreferencePage
{
Q_OBJECT
public:
explicit DlgSettingsFemMaterialImp(QWidget* parent = nullptr);
~DlgSettingsFemMaterialImp() override;
explicit DlgSettingsMaterial(QWidget* parent = nullptr);
~DlgSettingsMaterial() override = default;
protected:
void saveSettings() override;
@@ -47,9 +47,9 @@ protected:
void changeEvent(QEvent* e) override;
private:
std::unique_ptr<Ui_DlgSettingsFemMaterialImp> ui;
std::unique_ptr<Ui_DlgSettingsMaterial> ui;
};
} // namespace FemGui
} // namespace MatGui
#endif // FEMGUI_DLGSETTINGSFEMMATERIALIMP_H
#endif // MATGUI_DLGSETTINGSMATERIAL_H

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FemGui::DlgSettingsFemMaterialImp</class>
<widget class="QWidget" name="FemGui::DlgSettingsFemMaterialImp">
<class>MatGui::DlgSettingsMaterial</class>
<widget class="QWidget" name="MatGui::DlgSettingsMaterial">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>434</width>
<height>229</height>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string>Material</string>
<string>General</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
@@ -44,6 +44,25 @@
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="cb_use_mat_from_workbenches">
<property name="toolTip">
<string>Use materials added by external workbenches.</string>
</property>
<property name="text">
<string>Use materials from external workbenches</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>UseMaterialsFromWorkbenches</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Material/Resources</cstring>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="cb_use_mat_from_config_dir">
<property name="toolTip">
@@ -124,9 +143,6 @@ will be listed as available.</string>
<height>0</height>
</size>
</property>
<property name="mode">
<enum>Gui::FileChooser::Directory</enum>
</property>
<property name="prefEntry" stdset="0">
<cstring>CustomMaterialsDir</cstring>
</property>
@@ -190,6 +206,31 @@ If unchecked, they will be sorted by their name.</string>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_materials_testing">
<property name="title">
<string>Testing</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="Gui::PrefCheckBox" name="cb_legacy_editor">
<property name="text">
<string>Use legacy editor</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>LegacyEditor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Material/Cards</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@@ -226,9 +267,7 @@ If unchecked, they will be sorted by their name.</string>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="Resources/Fem.qrc"/>
</resources>
<resources/>
<connections>
<connection>
<sender>cb_use_mat_from_custom_dir</sender>

View File

@@ -0,0 +1,466 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QColorDialog>
#include <QDesktopServices>
#include <QIODevice>
#include <QItemSelectionModel>
#include <QPainter>
#include <QString>
#include <QStringList>
#include <QTextStream>
#include <QVariant>
#endif
#include <limits>
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <Base/Quantity.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/InputField.h>
#include <Gui/PrefWidgets.h>
#include <Gui/SpinBox.h>
#include <Gui/WaitCursor.h>
#include <Mod/Material/App/Exceptions.h>
#include <Mod/Material/App/ModelManager.h>
#include "Array2D.h"
#include "Array3D.h"
#include "MaterialDelegate.h"
#include "MaterialSave.h"
using namespace MatGui;
MaterialDelegate::MaterialDelegate(QObject* parent)
: QStyledItemDelegate(parent)
{}
bool MaterialDelegate::editorEvent(QEvent* event,
QAbstractItemModel* model,
const QStyleOptionViewItem& option,
const QModelIndex& index)
{
if (index.column() == 1) {
if (event->type() == QEvent::MouseButtonDblClick) {
const QStandardItemModel* treeModel =
static_cast<const QStandardItemModel*>(index.model());
// Check we're not the material model root. This is also used to access the entry
// columns
auto item = treeModel->itemFromIndex(index);
auto group = item->parent();
if (!group) {
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
int row = index.row();
QString propertyName = group->child(row, 0)->text();
QString propertyType = QString::fromStdString("String");
if (group->child(row, 2)) {
propertyType = group->child(row, 2)->text();
}
std::string type = propertyType.toStdString();
if (type == "Color") {
Base::Console().Log("Edit color\n");
showColorModal(item);
// Mark as handled
return true;
}
else if (type == "2DArray") {
Base::Console().Log("Edit 2DArray\n");
showArray2DModal(propertyName, item);
// Mark as handled
return true;
}
else if (type == "3DArray") {
Base::Console().Log("Edit 3DArray\n");
showArray3DModal(propertyName, item);
// Mark as handled
return true;
}
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
void MaterialDelegate::showColorModal(QStandardItem* item)
{
QColor currentColor;// = d->col;
currentColor.setRgba(parseColor(item->text()));
QColorDialog* dlg = new QColorDialog(currentColor);
dlg->setAttribute(Qt::WA_DeleteOnClose);
if (Gui::DialogOptions::dontUseNativeColorDialog()) {
dlg->setOptions(QColorDialog::DontUseNativeDialog);
}
dlg->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, false);
dlg->setCurrentColor(currentColor);
dlg->adjustSize();
connect(dlg, &QColorDialog::finished, this, [&](int result) {
if (result == QDialog::Accepted) {
QColor color = dlg->selectedColor();
if (color.isValid()) {
QString colorText = QString(QString::fromStdString("(%1,%2,%3,%4)"))
.arg(color.red() / 255.0)
.arg(color.green() / 255.0)
.arg(color.blue() / 255.0)
.arg(color.alpha() / 255.0);
item->setText(colorText);
}
}
});
dlg->exec();
}
void MaterialDelegate::showArray2DModal(const QString& propertyName, QStandardItem* item)
{
Materials::Material* material = item->data().value<Materials::Material*>();
Array2D* dlg = new Array2D(propertyName, material);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->adjustSize();
connect(dlg, &QDialog::finished, this, [&](int result) {
if (result == QDialog::Accepted) {
Base::Console().Log("Accepted\n");
}
});
dlg->exec();
}
void MaterialDelegate::showArray3DModal(const QString& propertyName, QStandardItem* item)
{
Materials::Material* material = item->data().value<Materials::Material*>();
Array3D* dlg = new Array3D(propertyName, material);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->adjustSize();
connect(dlg, &QDialog::finished, this, [&](int result) {
if (result == QDialog::Accepted) {
Base::Console().Log("Accepted\n");
}
});
dlg->exec();
}
void MaterialDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
// Base::Console().Log("MaterialsEditor::paint()\n");
if (index.column() != 1) {
QStyledItemDelegate::paint(painter, option, index);
return;
}
const QStandardItemModel* treeModel = static_cast<const QStandardItemModel*>(index.model());
// Check we're not the material model root. This is also used to access the entry columns
auto item = treeModel->itemFromIndex(index);
auto group = item->parent();
if (!group) {
QStyledItemDelegate::paint(painter, option, index);
return;
}
int row = index.row();
QString propertyName = group->child(row, 0)->text();
QString propertyType = QString::fromStdString("String");
if (group->child(row, 2)) {
propertyType = group->child(row, 2)->text();
}
QString propertyValue = QString::fromStdString("");
if (group->child(row, 1)) {
propertyValue = group->child(row, 1)->text();
}
std::string type = propertyType.toStdString();
if (type == "Color") {
painter->save();
QColor color;
color.setRgba(parseColor(propertyValue));
int left = option.rect.left() + 5;
int width = option.rect.width() - 10;
if (option.rect.width() > 75) {
left += (option.rect.width() - 75) / 2;
width = 65;
}
painter->fillRect(left,
option.rect.top() + 5,
width,
option.rect.height() - 10,
QBrush(color));
painter->restore();
return;
}
else if (type == "2DArray" || type == "3DArray") {
// painter->save();
QImage table(QString::fromStdString(":/icons/table.svg"));
QRect target(option.rect);
if (target.width() > target.height()) {
target.setWidth(target.height());
}
else {
target.setHeight(target.width());
}
painter->drawImage(target, table, table.rect());
// painter->restore();
return;
}
QStyledItemDelegate::paint(painter, option, index);
}
QSize MaterialDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
if (index.column() != 1) {
return QStyledItemDelegate::sizeHint(option, index);
}
const QStandardItemModel* treeModel = static_cast<const QStandardItemModel*>(index.model());
// Check we're not the material model root. This is also used to access the entry columns
auto item = treeModel->itemFromIndex(index);
auto group = item->parent();
if (!group) {
return QStyledItemDelegate::sizeHint(option, index);
}
int row = index.row();
QString propertyType = QString::fromStdString("String");
if (group->child(row, 2)) {
propertyType = group->child(row, 2)->text();
}
std::string type = propertyType.toStdString();
if (type == "Color") {
return QSize(75, 23);// Standard QPushButton size
}
else if (type == "2DArray" || type == "3DArray") {
return QSize(23, 23);
}
return QStyledItemDelegate::sizeHint(option, index);
}
void MaterialDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
Base::Console().Log("MaterialsEditor::setEditorData()\n");
QVariant propertyType = editor->property("Type");
const QStandardItemModel* model = static_cast<const QStandardItemModel*>(index.model());
QStandardItem* item = model->itemFromIndex(index);
auto group = item->parent();
if (!group) {
return;
}
int row = index.row();
QString propertyName = group->child(row, 0)->text();
std::string type = propertyType.toString().toStdString();
if (type == "File") {
Gui::FileChooser* chooser = static_cast<Gui::FileChooser*>(editor);
item->setText(chooser->fileName());
}
else if (type == "Quantity") {
Gui::InputField* input = static_cast<Gui::InputField*>(editor);
item->setText(input->getQuantityString());
}
else {
QStyledItemDelegate::setEditorData(editor, index);
}
// Q_EMIT const_cast<MaterialDelegate *>(this)->propertyChange(propertyName, item->text());
}
void MaterialDelegate::setModelData(QWidget* editor,
QAbstractItemModel* model,
const QModelIndex& index) const
{
QStyledItemDelegate::setModelData(editor, model, index);
QStandardItem* item = static_cast<const QStandardItemModel*>(model)->itemFromIndex(index);
auto group = item->parent();
if (!group) {
return;
}
int row = index.row();
QString propertyName = group->child(row, 0)->text();
Q_EMIT const_cast<MaterialDelegate*>(this)->propertyChange(propertyName, item->text());
}
QWidget* MaterialDelegate::createEditor(QWidget* parent,
const QStyleOptionViewItem&,
const QModelIndex& index) const
{
Base::Console().Log("MaterialsEditor::createEditor()\n");
if (index.column() != 1) {
return nullptr;
}
const QStandardItemModel* treeModel = static_cast<const QStandardItemModel*>(index.model());
// Check we're not the material model root. This is also used to access the entry columns
auto item = treeModel->itemFromIndex(index);
auto group = item->parent();
if (!group) {
return nullptr;
}
int row = index.row();
QString propertyName = group->child(row, 0)->text();
QString propertyType = QString::fromStdString("String");
if (group->child(row, 2)) {
propertyType = group->child(row, 2)->text();
}
QString propertyValue = QString::fromStdString("");
if (group->child(row, 1)) {
propertyValue = group->child(row, 1)->text();
}
QString propertyUnits = QString::fromStdString("");
if (group->child(row, 1)) {
propertyUnits = group->child(row, 3)->text();
}
QWidget* editor =
createWidget(parent, propertyName, propertyType, propertyValue, propertyUnits);
return editor;
}
QWidget* MaterialDelegate::createWidget(QWidget* parent,
const QString& propertyName,
const QString& propertyType,
const QString& propertyValue,
const QString& propertyUnits) const
{
Q_UNUSED(propertyName);
QWidget* widget = nullptr;
std::string type = propertyType.toStdString();
if (type == "String" || type == "URL" || type == "Vector") {
widget = new Gui::PrefLineEdit(parent);
}
else if ((type == "Integer") || (type == "Int")) {
Gui::UIntSpinBox* spinner = new Gui::UIntSpinBox(parent);
spinner->setMinimum(0);
spinner->setMaximum(UINT_MAX);
spinner->setValue(propertyValue.toUInt());
widget = spinner;
}
else if (type == "Float") {
Gui::DoubleSpinBox* spinner = new Gui::DoubleSpinBox(parent);
// the magnetic permeability is the parameter for which many decimals matter
// the most however, even for this, 6 digits are sufficient
spinner->setDecimals(6);
// for almost all Float parameters of materials a step of 1 would be too large
spinner->setSingleStep(0.1);
spinner->setMinimum(std::numeric_limits<double>::min());
spinner->setMaximum(std::numeric_limits<double>::max());
spinner->setValue(propertyValue.toDouble());
widget = spinner;
}
else if (type == "Boolean") {
Gui::PrefComboBox* combo = new Gui::PrefComboBox(parent);
combo->insertItem(0, QString::fromStdString(""));
combo->insertItem(1, QString::fromStdString("False"));
combo->insertItem(2, QString::fromStdString("True"));
combo->setCurrentText(propertyValue);
widget = combo;
}
else if (type == "Quantity") {
Gui::InputField* input = new Gui::InputField();
input->setMinimum(std::numeric_limits<double>::min());
input->setMaximum(std::numeric_limits<double>::max());
input->setUnitText(propertyUnits);// TODO: Ensure this exists
input->setPrecision(6);
input->setQuantityString(propertyValue);
widget = input;
}
else if (type == "File") {
Gui::FileChooser* chooser = new Gui::FileChooser();
if (propertyValue.length() > 0) {
chooser->setFileName(propertyValue);
}
widget = chooser;
}
else {
// Default editor
widget = new QLineEdit(parent);
}
widget->setProperty("Type", propertyType);
widget->setParent(parent);
return widget;
}
QRgb MaterialDelegate::parseColor(const QString& color) const
{
QString trimmed = color;
trimmed.replace(QRegularExpression(QString::fromStdString("\\(([^<]*)\\)")),
QString::fromStdString("\\1"));
QStringList parts = trimmed.split(QString::fromStdString(","));
if (parts.length() < 4) {
return qRgba(0, 0, 0, 1);
}
int red = parts.at(0).toDouble() * 255;
int green = parts.at(1).toDouble() * 255;
int blue = parts.at(2).toDouble() * 255;
int alpha = parts.at(3).toDouble() * 255;
return qRgba(red, green, blue, alpha);
}
#include "moc_MaterialDelegate.cpp"

View File

@@ -0,0 +1,87 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_MATERIALDELEGATE_H
#define MATGUI_MATERIALDELEGATE_H
#include <boost/filesystem.hpp>
#include <QDialog>
#include <QDir>
#include <QStandardItem>
#include <QStyledItemDelegate>
#include <QSvgWidget>
#include <QTreeView>
#include <Mod/Material/App/MaterialManager.h>
#include <Mod/Material/App/Materials.h>
#include <Mod/Material/App/ModelManager.h>
namespace fs = boost::filesystem;
namespace MatGui
{
class MaterialDelegate: public QStyledItemDelegate
{
Q_OBJECT
public:
explicit MaterialDelegate(QObject* parent = nullptr);
virtual ~MaterialDelegate() = default;
QWidget* createEditor(QWidget* parent,
const QStyleOptionViewItem&,
const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
void paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
void setModelData(QWidget* editor,
QAbstractItemModel* model,
const QModelIndex& index) const override;
protected:
bool editorEvent(QEvent* event,
QAbstractItemModel* model,
const QStyleOptionViewItem& option,
const QModelIndex& index) override;
Q_SIGNALS:
/** Emits this signal when a property has changed */
void propertyChange(const QString& property, const QString value);
private:
QWidget* createWidget(QWidget* parent,
const QString& propertyName,
const QString& propertyType,
const QString& propertyValue,
const QString& propertyUnits) const;
QRgb parseColor(const QString& color) const;
void showColorModal(QStandardItem* item);
void showArray2DModal(const QString& propertyName, QStandardItem* item);
void showArray3DModal(const QString& propertyName, QStandardItem* item);
};
}// namespace MatGui
#endif// MATGUI_MATERIALDELEGATE_H

View File

@@ -0,0 +1,314 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QMessageBox>
#include <QTreeView>
#endif
#include <Gui/MainWindow.h>
#include <Mod/Material/App/MaterialLibrary.h>
#include "MaterialSave.h"
#include "ui_MaterialSave.h"
using namespace MatGui;
/* TRANSLATOR MatGui::MaterialsEditor */
MaterialSave::MaterialSave(Materials::Material* material, QWidget* parent)
: QDialog(parent)
, ui(new Ui_MaterialSave)
, _material(material)
, _selectedPath(QString::fromStdString("/"))
, _selectedUUID(QString())
{
ui->setupUi(this);
setLibraries();
createModelTree();
showSelectedTree();
if (_material->getName().length() > 0) {
ui->editFilename->setText(_material->getName() + QString::fromStdString(".FCMat"));
}
else {
ui->editFilename->setText(QString::fromStdString("NewMaterial.FCMat"));
}
_filename = QString(ui->editFilename->text());// No filename by default
connect(ui->standardButtons->button(QDialogButtonBox::Ok),
&QPushButton::clicked,
this,
&MaterialSave::onOk);
connect(ui->standardButtons->button(QDialogButtonBox::Cancel),
&QPushButton::clicked,
this,
&MaterialSave::onCancel);
connect(ui->comboLibrary,
&QComboBox::currentTextChanged,
this,
&MaterialSave::currentTextChanged);
connect(ui->buttonNewFolder, &QPushButton::clicked, this, &MaterialSave::onNewFolder);
connect(ui->editFilename, &QLineEdit::textEdited, this, &MaterialSave::onFilename);
QItemSelectionModel* selectionModel = ui->treeMaterials->selectionModel();
connect(selectionModel,
&QItemSelectionModel::selectionChanged,
this,
&MaterialSave::onSelectModel);
}
/*
* Destroys the object and frees any allocated resources
*/
MaterialSave::~MaterialSave()
{
// no need to delete child widgets, Qt does it all for us
}
void MaterialSave::onOk(bool checked)
{
Q_UNUSED(checked)
QString name = _filename.remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive);
Base::Console().Log("name '%s'\n", _filename.toStdString().c_str());
if (name != _material->getName()) {
_material->setName(name);
_material->setEditStateAlter();// ? Does a name change count?
}
auto variant = ui->comboLibrary->currentData();
auto library = variant.value<Materials::MaterialLibrary>();
QFileInfo filepath(_selectedPath + QString::fromStdString("/") + name
+ QString::fromStdString(".FCMat"));
Base::Console().Log("saveMaterial(library(%s), material(%s), path(%s))\n",
library.getName().toStdString().c_str(),
_material->getName().toStdString().c_str(),
filepath.filePath().toStdString().c_str());
_manager.saveMaterial(&library, *_material, filepath.filePath());
accept();
}
void MaterialSave::onCancel(bool checked)
{
Q_UNUSED(checked)
reject();
}
void MaterialSave::accept()
{
QDialog::accept();
}
void MaterialSave::reject()
{
QDialog::reject();
}
void MaterialSave::setLibraries()
{
std::list<Materials::MaterialLibrary*>* libraries = _manager.getMaterialLibraries();
for (Materials::MaterialLibrary* library : *libraries) {
if (!library->isReadOnly()) {
QVariant libraryVariant;
libraryVariant.setValue(*library);
ui->comboLibrary->addItem(library->getName(), libraryVariant);
}
}
}
void MaterialSave::createModelTree()
{
auto tree = ui->treeMaterials;
auto model = new QStandardItemModel();
tree->setModel(model);
tree->setHeaderHidden(true);
}
void MaterialSave::addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child)
{
parent->appendRow(child);
tree->setExpanded(child->index(), true);
}
void MaterialSave::addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child)
{
parent->appendRow(child);
tree->setExpanded(child->index(), true);
}
void MaterialSave::addMaterials(QStandardItem& parent,
const std::map<QString, Materials::MaterialTreeNode*>* modelTree,
const QIcon& folderIcon,
const QIcon& icon)
{
auto tree = ui->treeMaterials;
for (auto& mat : *modelTree) {
Materials::MaterialTreeNode* nodePtr = mat.second;
if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) {
const Materials::Material* material = nodePtr->getData();
QString uuid = material->getUUID();
Base::Console().Log("Material path '%s'\n",
material->getDirectory().toStdString().c_str());
// auto card = new QStandardItem(icon, material->getName());
auto card = new QStandardItem(icon, mat.first);
// card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
// | Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, &parent, card);
}
else {
auto node = new QStandardItem(folderIcon, mat.first);
addExpanded(tree, &parent, node);
// node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
const std::map<QString, Materials::MaterialTreeNode*>* treeMap = nodePtr->getFolder();
addMaterials(*node, treeMap, folderIcon, icon);
}
}
}
void MaterialSave::showSelectedTree()
{
auto tree = ui->treeMaterials;
auto model = static_cast<QStandardItemModel*>(tree->model());
model->clear();
if (ui->comboLibrary->count() > 0) {
auto variant = ui->comboLibrary->currentData();
auto library = variant.value<Materials::MaterialLibrary>();
QIcon icon(library.getIconPath());
QIcon folderIcon(QString::fromStdString(":/icons/folder.svg"));
_libraryName = library.getName();
_selectedPath = QString::fromStdString("/") + _libraryName;
auto lib = new QStandardItem(library.getName());
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
std::map<QString, Materials::MaterialTreeNode*>* modelTree =
_manager.getMaterialTree(library);
addMaterials(*lib, modelTree, folderIcon, icon);
}
else {
QMessageBox::warning(Gui::getMainWindow(),
QObject::tr("No writeable library"),
QObject::tr("No writeable library"));
}
}
QString MaterialSave::getPath(const QStandardItem* item) const
{
QString path = QString::fromStdString("/");
if (item) {
path = path + item->text();
if (item->parent()) {
return getPath(item->parent()) + path;
}
}
return path;
}
void MaterialSave::onSelectModel(const QItemSelection& selected, const QItemSelection& deselected)
{
// Q_UNUSED(selected);
Q_UNUSED(deselected);
_filename = QString(ui->editFilename->text());// No filename by default
QStandardItemModel* model = static_cast<QStandardItemModel*>(ui->treeMaterials->model());
QModelIndexList indexes = selected.indexes();
if (indexes.count() == 0) {
Base::Console().Log("Nothing selected\n");
_selectedPath = QString::fromStdString("/") + _libraryName;
_selectedUUID = QString();
Base::Console().Log("\tSelected path '%s'\n", _selectedPath.toStdString().c_str());
return;
}
for (auto it = indexes.begin(); it != indexes.end(); it++) {
QStandardItem* item = model->itemFromIndex(*it);
Base::Console().Log("%s\n", item->text().toStdString().c_str());
if (item) {
auto _selected = item->data(Qt::UserRole);
if (_selected.isValid()) {
Base::Console().Log("\tuuid %s\n", _selected.toString().toStdString().c_str());
_selectedPath = getPath(item->parent());
_selectedUUID = _selected.toString();
_filename = item->text();
}
else {
_selectedPath = getPath(item);
_selectedUUID = QString();
}
}
}
if (_filename.length() > 0) {
ui->editFilename->setText(_filename);
}
Base::Console().Log("\tSelected path '%s', filename = '%s'\n",
_selectedPath.toStdString().c_str(),
_filename.toStdString().c_str());
}
void MaterialSave::currentTextChanged(const QString& value)
{
Q_UNUSED(value)
showSelectedTree();
}
void MaterialSave::onNewFolder(bool checked)
{
Q_UNUSED(checked)
auto tree = ui->treeMaterials;
auto model = static_cast<QStandardItemModel*>(tree->model());
auto current = tree->currentIndex();
if (!current.isValid()) {
current = model->index(0, 0);
}
auto item = model->itemFromIndex(current);
if (item->hasChildren()) {
Base::Console().Log("Add new folder to '%s'\n", item->text().toStdString().c_str());
QIcon folderIcon(QString::fromStdString(":/icons/folder.svg"));
auto node = new QStandardItem(folderIcon, QString::fromStdString("New Folder"));
addExpanded(tree, item, node);
// node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
}
}
void MaterialSave::onFilename(const QString& text)
{
Base::Console().Log("MaterialSave::onFilename('%s')\n", text.toStdString().c_str());
_filename = text;
}
#include "moc_MaterialSave.cpp"

View File

@@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_MATERIALSAVE_H
#define MATGUI_MATERIALSAVE_H
// #include <boost/filesystem.hpp>
#include <QDialog>
#include <QItemSelection>
#include <QStandardItem>
#include <QTreeView>
#include <Mod/Material/App/MaterialManager.h>
namespace MatGui
{
class Ui_MaterialSave;
class MaterialSave: public QDialog
{
Q_OBJECT
public:
explicit MaterialSave(Materials::Material* material, QWidget* parent = nullptr);
~MaterialSave() override;
void setLibraries();
void createModelTree();
void addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child);
void addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child);
void addMaterials(QStandardItem& parent,
const std::map<QString, Materials::MaterialTreeNode*>* modelTree,
const QIcon& folderIcon,
const QIcon& icon);
void showSelectedTree();
void onSelectModel(const QItemSelection& selected, const QItemSelection& deselected);
void currentTextChanged(const QString& value);
void onNewFolder(bool checked);
void onFilename(const QString& text);
void onOk(bool checked);
void onCancel(bool checked);
void accept() override;
void reject() override;
private:
std::unique_ptr<Ui_MaterialSave> ui;
Materials::MaterialManager _manager;
Materials::Material* _material;
QString _selectedPath;
QString _selectedUUID;
QString _libraryName;
QString _filename;
QString getPath(const QStandardItem* item) const;
};
}// namespace MatGui
#endif// MATGUI_MATERIALSAVE_H

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MatGui::MaterialSave</class>
<widget class="QDialog" name="MatGui::MaterialSave">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>654</width>
<height>708</height>
</rect>
</property>
<property name="windowTitle">
<string>Save Material</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Library:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboLibrary">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="treeMaterials"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonNewFolder">
<property name="text">
<string>New Folder</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Filename:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="editFilename">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="standardButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>standardButtons</sender>
<signal>accepted()</signal>
<receiver>MatGui::MaterialSave</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>standardButtons</sender>
<signal>rejected()</signal>
<receiver>MatGui::MaterialSave</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,905 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QColorDialog>
#include <QDesktopServices>
#include <QIODevice>
#include <QItemSelectionModel>
#include <QMessageBox>
#include <QString>
#include <QStringList>
#include <QTextStream>
#include <QVariant>
#endif
#include <limits>
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <Base/Quantity.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/InputField.h>
#include <Gui/PrefWidgets.h>
#include <Gui/SpinBox.h>
#include <Gui/WaitCursor.h>
#include <Mod/Material/App/Exceptions.h>
#include <Mod/Material/App/ModelManager.h>
#include "MaterialDelegate.h"
#include "MaterialSave.h"
#include "MaterialsEditor.h"
#include "ModelSelect.h"
#include "ui_MaterialsEditor.h"
using namespace MatGui;
/* TRANSLATOR MatGui::MaterialsEditor */
MaterialsEditor::MaterialsEditor(QWidget* parent)
: QDialog(parent)
, ui(new Ui_MaterialsEditor)
, _edited(false)
{
ui->setupUi(this);
getFavorites();
getRecents();
createMaterialTree();
createPhysicalTree();
createAppearanceTree();
createPreviews();
ui->buttonURL->setIcon(QIcon(QString::fromStdString(":/icons/internet-web-browser.svg")));
connect(ui->standardButtons->button(QDialogButtonBox::Ok),
&QPushButton::clicked,
this,
&MaterialsEditor::onOk);
connect(ui->standardButtons->button(QDialogButtonBox::Cancel),
&QPushButton::clicked,
this,
&MaterialsEditor::onCancel);
connect(ui->standardButtons->button(QDialogButtonBox::Save),
&QPushButton::clicked,
this,
&MaterialsEditor::onSave);
connect(ui->buttonURL, &QPushButton::clicked, this, &MaterialsEditor::onURL);
connect(ui->buttonPhysicalAdd, &QPushButton::clicked, this, &MaterialsEditor::onPhysicalAdd);
connect(ui->buttonAppearanceAdd,
&QPushButton::clicked,
this,
&MaterialsEditor::onAppearanceAdd);
connect(ui->buttonFavorite, &QPushButton::clicked, this, &MaterialsEditor::onFavourite);
QItemSelectionModel* selectionModel = ui->treeMaterials->selectionModel();
connect(selectionModel,
&QItemSelectionModel::selectionChanged,
this,
&MaterialsEditor::onSelectMaterial);
}
void MaterialsEditor::getFavorites()
{
_favorites.clear();
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Favorites");
int count = param->GetInt("Favorites", 0);
for (int i = 0; i < count; i++) {
QString key = QString::fromLatin1("FAV%1").arg(i);
QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), ""));
_favorites.push_back(uuid);
}
}
void MaterialsEditor::saveFavorites()
{
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Favorites");
// Clear out the existing favorites
int count = param->GetInt("Favorites", 0);
for (int i = 0; i < count; i++) {
QString key = QString::fromLatin1("FAV%1").arg(i);
param->RemoveASCII(key.toStdString().c_str());
}
// Add the current values
param->SetInt("Favorites", _favorites.size());
int j = 0;
for (auto favorite : _favorites) {
QString key = QString::fromLatin1("FAV%1").arg(j);
param->SetASCII(key.toStdString().c_str(), favorite.toStdString());
j++;
}
}
void MaterialsEditor::addFavorite(const QString& uuid)
{
// Ensure it is a material. New, unsaved materials will not be
try {
const Materials::Material& material = _materialManager.getMaterial(uuid);
Q_UNUSED(material)
}
catch (const Materials::MaterialNotFound&) {
return;
}
if (!isFavorite(uuid)) {
_favorites.push_back(uuid);
saveFavorites();
refreshMaterialTree();
}
}
void MaterialsEditor::removeFavorite(const QString& uuid)
{
if (isFavorite(uuid)) {
_favorites.remove(uuid);
saveFavorites();
refreshMaterialTree();
}
}
bool MaterialsEditor::isFavorite(const QString& uuid) const
{
for (auto it : _favorites) {
if (it == uuid) {
return true;
}
}
return false;
}
void MaterialsEditor::getRecents()
{
_recents.clear();
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Recent");
_recentMax = param->GetInt("RecentMax", 5);
int count = param->GetInt("Recent", 0);
for (int i = 0; i < count; i++) {
QString key = QString::fromLatin1("MRU%1").arg(i);
QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), ""));
_recents.push_back(uuid);
}
}
void MaterialsEditor::saveRecents()
{
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Recent");
// Clear out the existing favorites
int count = param->GetInt("Recent", 0);
for (int i = 0; i < count; i++) {
QString key = QString::fromLatin1("MRU%1").arg(i);
param->RemoveASCII(key.toStdString().c_str());
}
// Add the current values
int size = _recents.size();
if (size > _recentMax) {
size = _recentMax;
}
param->SetInt("Recent", size);
int j = 0;
for (auto recent : _recents) {
QString key = QString::fromLatin1("MRU%1").arg(j);
param->SetASCII(key.toStdString().c_str(), recent.toStdString());
j++;
if (j >= size) {
break;
}
}
}
void MaterialsEditor::addRecent(const QString& uuid)
{
// Ensure it is a material. New, unsaved materials will not be
try {
const Materials::Material& material = _materialManager.getMaterial(uuid);
Q_UNUSED(material)
}
catch (const Materials::MaterialNotFound&) {
return;
}
// Ensure no duplicates
if (isRecent(uuid)) {
_recents.remove(uuid);
}
_recents.push_front(uuid);
while (_recents.size() > static_cast<std::size_t>(_recentMax)) {
_recents.pop_back();
}
saveRecents();
}
bool MaterialsEditor::isRecent(const QString& uuid) const
{
for (auto it : _recents) {
if (it == uuid) {
return true;
}
}
return false;
}
void MaterialsEditor::propertyChange(const QString& property, const QString value)
{
Base::Console().Log("MaterialsEditor::propertyChange(%s) = '%s'\n",
property.toStdString().c_str(),
value.toStdString().c_str());
if (_material.hasPhysicalProperty(property)) {
_material.setPhysicalValue(property, value);
}
else if (_material.hasAppearanceProperty(property)) {
_material.setAppearanceValue(property, value);
updatePreview();
}
_edited = true;
}
void MaterialsEditor::onURL(bool checked)
{
Q_UNUSED(checked)
Base::Console().Log("URL\n");
QString url = ui->editSourceURL->text();
if (url.length() > 0) {
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
}
}
void MaterialsEditor::onPhysicalAdd(bool checked)
{
Q_UNUSED(checked)
ModelSelect dialog(this, Materials::ModelManager::ModelFilter_Physical);
dialog.setModal(true);
if (dialog.exec() == QDialog::Accepted) {
QString selected = dialog.selectedModel();
Base::Console().Log("Selected model '%s'\n", selected.toStdString().c_str());
_material.addPhysical(selected);
updateMaterial();
}
else {
Base::Console().Log("No model selected\n");
}
}
void MaterialsEditor::onAppearanceAdd(bool checked)
{
Q_UNUSED(checked)
ModelSelect dialog(this, Materials::ModelManager::ModelFilter_Appearance);
dialog.setModal(true);
if (dialog.exec() == QDialog::Accepted) {
QString selected = dialog.selectedModel();
Base::Console().Log("Selected model '%s'\n", selected.toStdString().c_str());
_material.addAppearance(selected);
updateMaterial();
}
else {
Base::Console().Log("No model selected\n");
}
}
void MaterialsEditor::onFavourite(bool checked)
{
Q_UNUSED(checked)
Base::Console().Log("Favorite\n");
auto selected = _material.getUUID();
if (isFavorite(selected)) {
removeFavorite(selected);
}
else {
addFavorite(selected);
}
}
void MaterialsEditor::onOk(bool checked)
{
Q_UNUSED(checked)
accept();
}
void MaterialsEditor::onCancel(bool checked)
{
Q_UNUSED(checked)
reject();
}
void MaterialsEditor::onSave(bool checked)
{
Q_UNUSED(checked)
saveMaterial();
}
void MaterialsEditor::saveMaterial()
{
MaterialSave dialog(&_material, this);
dialog.setModal(true);
if (dialog.exec() == QDialog::Accepted) {
_material.resetEditState();
refreshMaterialTree();
}
}
void MaterialsEditor::accept()
{
addRecent(_material.getUUID());
QDialog::accept();
}
void MaterialsEditor::reject()
{
QDialog::reject();
}
// QIcon MaterialsEditor::errorIcon(const QIcon &icon) const {
// auto pixmap = icon.pixmap();
// }
void MaterialsEditor::addMaterials(QStandardItem& parent,
const std::map<QString, Materials::MaterialTreeNode*>* modelTree,
const QIcon& folderIcon,
const QIcon& icon)
{
auto tree = ui->treeMaterials;
for (auto& mat : *modelTree) {
Materials::MaterialTreeNode* nodePtr = mat.second;
if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) {
const Materials::Material* material = nodePtr->getData();
QString uuid = material->getUUID();
// Base::Console().Log("Material path '%s'\n",
// material->getDirectory().toStdString().c_str());
// auto card = new QStandardItem(icon, material->getName());
auto card = new QStandardItem(icon, mat.first);
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, &parent, card);
}
else {
auto node = new QStandardItem(folderIcon, mat.first);
addExpanded(tree, &parent, node);
node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
const std::map<QString, Materials::MaterialTreeNode*>* treeMap = nodePtr->getFolder();
addMaterials(*node, treeMap, folderIcon, icon);
}
}
}
void MaterialsEditor::addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child)
{
parent->appendRow(child);
tree->setExpanded(child->index(), true);
}
void MaterialsEditor::addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child)
{
parent->appendRow(child);
tree->setExpanded(child->index(), true);
}
void MaterialsEditor::createPhysicalTree()
{
auto tree = ui->treePhysicalProperties;
auto model = new QStandardItemModel();
tree->setModel(model);
QStringList headers;
headers.append(QString::fromStdString("Property"));
headers.append(QString::fromStdString("Value"));
headers.append(QString::fromStdString("Type"));
model->setHorizontalHeaderLabels(headers);
tree->setColumnWidth(0, 250);
tree->setColumnWidth(1, 250);
tree->setColumnHidden(2, true);
tree->setHeaderHidden(false);
tree->setUniformRowHeights(true);
MaterialDelegate* delegate = new MaterialDelegate(this);
tree->setItemDelegateForColumn(1, delegate);
connect(delegate, &MaterialDelegate::propertyChange, this, &MaterialsEditor::propertyChange);
}
void MaterialsEditor::createPreviews()
{
_rendered = new QSvgWidget(QString::fromStdString(":/icons/preview-rendered.svg"));
_rendered->setMaximumWidth(64);
_rendered->setMinimumHeight(64);
ui->layoutAppearance->addWidget(_rendered);
_vectored = new QSvgWidget(QString::fromStdString(":/icons/preview-vector.svg"));
_vectored->setMaximumWidth(64);
_vectored->setMinimumHeight(64);
ui->layoutAppearance->addWidget(_vectored);
updatePreview();
}
void MaterialsEditor::createAppearanceTree()
{
auto tree = ui->treeAppearance;
auto model = new QStandardItemModel();
tree->setModel(model);
QStringList headers;
headers.append(QString::fromStdString("Property"));
headers.append(QString::fromStdString("Value"));
headers.append(QString::fromStdString("Type"));
model->setHorizontalHeaderLabels(headers);
tree->setColumnWidth(0, 250);
tree->setColumnWidth(1, 250);
tree->setColumnHidden(2, true);
tree->setHeaderHidden(false);
tree->setUniformRowHeights(false);
MaterialDelegate* delegate = new MaterialDelegate(this);
tree->setItemDelegateForColumn(1, delegate);
connect(delegate, &MaterialDelegate::propertyChange, this, &MaterialsEditor::propertyChange);
}
void MaterialsEditor::addRecents(QStandardItem* parent)
{
auto tree = ui->treeMaterials;
for (auto& uuid : _recents) {
try {
const Materials::Material& material = getMaterialManager().getMaterial(uuid);
QIcon icon = QIcon(material.getLibrary().getIconPath());
auto card = new QStandardItem(icon, material.getName());
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, parent, card);
}
catch (const Materials::MaterialNotFound&) {
}
}
}
void MaterialsEditor::addFavorites(QStandardItem* parent)
{
auto tree = ui->treeMaterials;
for (auto& uuid : _favorites) {
try {
const Materials::Material& material = getMaterialManager().getMaterial(uuid);
QIcon icon = QIcon(material.getLibrary().getIconPath());
auto card = new QStandardItem(icon, material.getName());
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, parent, card);
}
catch (const Materials::MaterialNotFound&) {
}
}
}
void MaterialsEditor::fillMaterialTree()
{
auto tree = ui->treeMaterials;
auto model = static_cast<QStandardItemModel*>(tree->model());
auto lib = new QStandardItem(QString::fromStdString("Favorites"));
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
addFavorites(lib);
lib = new QStandardItem(QString::fromStdString("Recent"));
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
addRecents(lib);
auto libraries = Materials::MaterialManager::getMaterialLibraries();
for (const auto& library : *libraries) {
lib = new QStandardItem(library->getName());
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
QIcon icon(library->getIconPath());
QIcon folderIcon(QString::fromStdString(":/icons/folder.svg"));
std::map<QString, Materials::MaterialTreeNode*>* modelTree =
_materialManager.getMaterialTree(*library);
addMaterials(*lib, modelTree, folderIcon, icon);
}
}
void MaterialsEditor::createMaterialTree()
{
// Materials::ModelManager &modelManager = getModelManager();
// Q_UNUSED(modelManager)
auto tree = ui->treeMaterials;
auto model = new QStandardItemModel();
tree->setModel(model);
tree->setHeaderHidden(true);
fillMaterialTree();
}
void MaterialsEditor::refreshMaterialTree()
{
auto tree = ui->treeMaterials;
auto model = static_cast<QStandardItemModel*>(tree->model());
model->clear();
fillMaterialTree();
}
void MaterialsEditor::updatePreview() const
{
QString diffuseColor;
QString highlightColor;
QString sectionColor;
if (_material.hasAppearanceProperty(QString::fromStdString("DiffuseColor"))) {
diffuseColor = _material.getAppearanceValueString(QString::fromStdString("DiffuseColor"));
}
else if (_material.hasAppearanceProperty(QString::fromStdString("ViewColor"))) {
diffuseColor = _material.getAppearanceValueString(QString::fromStdString("ViewColor"));
}
else if (_material.hasAppearanceProperty(QString::fromStdString("Color"))) {
diffuseColor = _material.getAppearanceValueString(QString::fromStdString("Color"));
}
if (_material.hasAppearanceProperty(QString::fromStdString("SpecularColor"))) {
highlightColor =
_material.getAppearanceValueString(QString::fromStdString("SpecularColor"));
}
if (_material.hasAppearanceProperty(QString::fromStdString("SectionColor"))) {
sectionColor = _material.getAppearanceValueString(QString::fromStdString("SectionColor"));
}
if ((diffuseColor.length() + highlightColor.length()) > 0) {
auto file = QFile(QString::fromStdString(":/icons/preview-rendered.svg"));
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString svg = QTextStream(&file).readAll();
file.close();
if (diffuseColor.length() > 0) {
svg =
svg.replace(QString::fromStdString("#d3d7cf"), getColorHash(diffuseColor, 255));
svg =
svg.replace(QString::fromStdString("#555753"), getColorHash(diffuseColor, 125));
}
if (highlightColor.length() > 0) {
svg = svg.replace(QString::fromStdString("#fffffe"),
getColorHash(highlightColor, 255));
}
_rendered->load(svg.toUtf8());
}
}
if ((diffuseColor.length() + sectionColor.length()) > 0) {
auto file = QFile(QString::fromStdString(":/icons/preview-vector.svg"));
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString svg = QTextStream(&file).readAll();
file.close();
if (diffuseColor.length() > 0) {
svg =
svg.replace(QString::fromStdString("#d3d7cf"), getColorHash(diffuseColor, 255));
svg =
svg.replace(QString::fromStdString("#555753"), getColorHash(diffuseColor, 125));
}
if (sectionColor.length() > 0) {
svg =
svg.replace(QString::fromStdString("#ffffff"), getColorHash(sectionColor, 255));
}
_vectored->load(svg.toUtf8());
}
}
}
QString MaterialsEditor::getColorHash(const QString& colorString, int colorRange) const
{
/*
returns a '#000000' string from a '(0.1,0.2,0.3)' string. Optionally the string
has a fourth value for alpha (transparency)
*/
std::stringstream stream(colorString.toStdString());
char c;
stream >> c;// read "("
double red;
stream >> red;
stream >> c;// ","
double green;
stream >> green;
stream >> c;// ","
double blue;
stream >> blue;
stream >> c;// ","
double alpha = 1.0;
if (c == ',') {
stream >> alpha;
}
QColor color(static_cast<int>(red * colorRange),
static_cast<int>(green * colorRange),
static_cast<int>(blue * colorRange),
static_cast<int>(alpha * colorRange));
return color.name();
}
void MaterialsEditor::updateMaterialAppearance()
{
QTreeView* tree = ui->treeAppearance;
QStandardItemModel* treeModel = static_cast<QStandardItemModel*>(tree->model());
treeModel->clear();
QStringList headers;
headers.append(QString::fromStdString("Property"));
headers.append(QString::fromStdString("Value"));
headers.append(QString::fromStdString("Type"));
treeModel->setHorizontalHeaderLabels(headers);
tree->setColumnWidth(0, 250);
tree->setColumnWidth(1, 250);
tree->setColumnHidden(2, true);
const std::vector<QString>* models = _material.getAppearanceModels();
if (models) {
for (auto it = models->begin(); it != models->end(); it++) {
QString uuid = *it;
try {
const Materials::Model& model = getModelManager().getModel(uuid);
QString name = model.getName();
auto modelRoot = new QStandardItem(name);
modelRoot->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
addExpanded(tree, treeModel, modelRoot);
for (auto itp = model.begin(); itp != model.end(); itp++) {
QList<QStandardItem*> items;
QString key = itp->first;
auto propertyItem = new QStandardItem(key);
propertyItem->setToolTip(itp->second.getDescription());
items.append(propertyItem);
auto valueItem = new QStandardItem(_material.getAppearanceValueString(key));
valueItem->setToolTip(itp->second.getDescription());
QVariant variant;
variant.setValue(&_material);
valueItem->setData(variant);
items.append(valueItem);
auto typeItem = new QStandardItem(itp->second.getPropertyType());
items.append(typeItem);
auto unitsItem = new QStandardItem(itp->second.getUnits());
items.append(unitsItem);
modelRoot->appendRow(items);
tree->setExpanded(modelRoot->index(), true);
}
}
catch (Materials::ModelNotFound const&) {
}
}
}
}
void MaterialsEditor::updateMaterialProperties()
{
QTreeView* tree = ui->treePhysicalProperties;
QStandardItemModel* treeModel = static_cast<QStandardItemModel*>(tree->model());
treeModel->clear();
QStringList headers;
headers.append(QString::fromStdString("Property"));
headers.append(QString::fromStdString("Value"));
headers.append(QString::fromStdString("Type"));
headers.append(QString::fromStdString("Units"));
treeModel->setHorizontalHeaderLabels(headers);
tree->setColumnWidth(0, 250);
tree->setColumnWidth(1, 250);
tree->setColumnHidden(2, true);
tree->setColumnHidden(3, true);
const std::vector<QString>* models = _material.getPhysicalModels();
if (models) {
for (auto it = models->begin(); it != models->end(); it++) {
QString uuid = *it;
try {
const Materials::Model& model = getModelManager().getModel(uuid);
QString name = model.getName();
auto modelRoot = new QStandardItem(name);
modelRoot->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
addExpanded(tree, treeModel, modelRoot);
for (auto itp = model.begin(); itp != model.end(); itp++) {
QList<QStandardItem*> items;
QString key = itp->first;
Materials::ModelProperty modelProperty =
static_cast<Materials::ModelProperty>(itp->second);
auto propertyItem = new QStandardItem(key);
propertyItem->setToolTip(modelProperty.getDescription());
items.append(propertyItem);
auto valueItem = new QStandardItem(_material.getPhysicalValueString(key));
valueItem->setToolTip(modelProperty.getDescription());
QVariant variant;
variant.setValue(&_material);
valueItem->setData(variant);
items.append(valueItem);
auto typeItem = new QStandardItem(modelProperty.getPropertyType());
items.append(typeItem);
auto unitsItem = new QStandardItem(modelProperty.getUnits());
items.append(unitsItem);
// addExpanded(tree, modelRoot, propertyItem);
modelRoot->appendRow(items);
tree->setExpanded(modelRoot->index(), true);
}
}
catch (Materials::ModelNotFound const&) {
}
}
}
}
void MaterialsEditor::updateMaterial()
{
// Update the general information
ui->editName->setText(_material.getName());
ui->editAuthorLicense->setText(_material.getAuthorAndLicense());
// ui->editParent->setText(_material.getName());
ui->editSourceURL->setText(_material.getURL());
ui->editSourceReference->setText(_material.getReference());
// ui->editTags->setText(_material.getName());
ui->editDescription->setText(_material.getDescription());
updateMaterialProperties();
updateMaterialAppearance();
updatePreview();
}
void MaterialsEditor::onSelectMaterial(const QItemSelection& selected,
const QItemSelection& deselected)
{
Q_UNUSED(deselected);
// Get the UUID before changing the underlying data model
QString uuid;
QStandardItemModel* model = static_cast<QStandardItemModel*>(ui->treeMaterials->model());
QModelIndexList indexes = selected.indexes();
for (auto it = indexes.begin(); it != indexes.end(); it++) {
QStandardItem* item = model->itemFromIndex(*it);
Base::Console().Log("%s\n", item->text().toStdString().c_str());
if (item) {
uuid = item->data(Qt::UserRole).toString();
break;
}
}
if (uuid.isEmpty() || uuid == _material.getUUID()) {
Base::Console().Log("*** Unchanged material '%s'\n", uuid.toStdString().c_str());
return;
}
// Ensure data is saved (or discarded) before changing materials
if (_material.getEditState() != Materials::Material::ModelEdit_None) {
// Prompt the user to save or discard changes
Base::Console().Log("*** Material edited!!!\n");
int res = confirmSave(this);
if (res == QMessageBox::Cancel) {
return;
}
}
// Get the selected material
try {
_material = getMaterialManager().getMaterial(uuid);
}
catch (Materials::ModelNotFound const&) {
Base::Console().Log("*** Unable to load material '%s'\n", uuid.toStdString().c_str());
Materials::Material empty;
_material = empty;
}
updateMaterial();
_material.resetEditState();
}
int MaterialsEditor::confirmSave(QWidget* parent)
{
QMessageBox box(parent ? parent : this);
box.setIcon(QMessageBox::Question);
box.setWindowTitle(QObject::tr("Unsaved Material"));
box.setText(QObject::tr("Do you want to save your changes to the material before closing?"));
box.setInformativeText(QObject::tr("If you don't save, your changes will be lost."));
box.setStandardButtons(QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save);
box.setDefaultButton(QMessageBox::Save);
box.setEscapeButton(QMessageBox::Cancel);
// add shortcuts
QAbstractButton* saveBtn = box.button(QMessageBox::Save);
if (saveBtn->shortcut().isEmpty()) {
QString text = saveBtn->text();
text.prepend(QLatin1Char('&'));
saveBtn->setShortcut(QKeySequence::mnemonic(text));
}
QAbstractButton* discardBtn = box.button(QMessageBox::Discard);
if (discardBtn->shortcut().isEmpty()) {
QString text = discardBtn->text();
text.prepend(QLatin1Char('&'));
discardBtn->setShortcut(QKeySequence::mnemonic(text));
}
int res = QMessageBox::Cancel;
box.adjustSize();// Silence warnings from Qt on Windows
switch (box.exec()) {
case QMessageBox::Save:
saveMaterial();
res = QMessageBox::Save;
break;
case QMessageBox::Discard:
res = QMessageBox::Discard;
break;
}
return res;
}
#include "moc_MaterialsEditor.cpp"

View File

@@ -0,0 +1,131 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_MATERIALSEDITOR_H
#define MATGUI_MATERIALSEDITOR_H
#include <boost/filesystem.hpp>
#include <QDialog>
#include <QDir>
#include <QStandardItem>
#include <QStyledItemDelegate>
#include <QSvgWidget>
#include <QTreeView>
#include <Mod/Material/App/MaterialManager.h>
#include <Mod/Material/App/Materials.h>
#include <Mod/Material/App/ModelManager.h>
namespace fs = boost::filesystem;
namespace MatGui
{
class Ui_MaterialsEditor;
class MaterialsEditor: public QDialog
{
Q_OBJECT
public:
explicit MaterialsEditor(QWidget* parent = nullptr);
~MaterialsEditor() override = default;
void propertyChange(const QString& property, const QString value);
void onFavourite(bool checked);
void onURL(bool checked);
void onPhysicalAdd(bool checked);
void onAppearanceAdd(bool checked);
void onOk(bool checked);
void onCancel(bool checked);
void onSave(bool checked);
void accept() override;
void reject() override;
Materials::MaterialManager& getMaterialManager()
{
return _materialManager;
}
Materials::ModelManager& getModelManager()
{
return _modelManager;
}
void updateMaterialAppearance();
void updateMaterialProperties();
void updateMaterial();
void onSelectMaterial(const QItemSelection& selected, const QItemSelection& deselected);
protected:
int confirmSave(QWidget* parent);
void saveMaterial();
private:
std::unique_ptr<Ui_MaterialsEditor> ui;
Materials::MaterialManager _materialManager;
Materials::ModelManager _modelManager;
Materials::Material _material;
QSvgWidget* _rendered;
QSvgWidget* _vectored;
bool _edited;
std::list<QString> _favorites;
std::list<QString> _recents;
int _recentMax;
void getFavorites();
void saveFavorites();
void addFavorite(const QString& uuid);
void removeFavorite(const QString& uuid);
bool isFavorite(const QString& uuid) const;
void getRecents();
void saveRecents();
void addRecent(const QString& uuid);
bool isRecent(const QString& uuid) const;
void updatePreview() const;
QString getColorHash(const QString& colorString, int colorRange = 255) const;
void addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child);
void addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child);
void addRecents(QStandardItem* parent);
void addFavorites(QStandardItem* parent);
void createPreviews();
void createAppearanceTree();
void createPhysicalTree();
void createMaterialTree();
void fillMaterialTree();
void refreshMaterialTree();
void addMaterials(QStandardItem& parent,
const std::map<QString, Materials::MaterialTreeNode*>* modelTree,
const QIcon& folderIcon,
const QIcon& icon);
bool isMaterial(const fs::path& p) const
{
return Materials::MaterialManager::isMaterial(p);
}
};
}// namespace MatGui
#endif// MATGUI_MATERIALSEDITOR_H

View File

@@ -0,0 +1,288 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MatGui::MaterialsEditor</class>
<widget class="QDialog" name="MatGui::MaterialsEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>835</width>
<height>542</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Materials</string>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="treeMaterials">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
</widget>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabGeneral">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
</property>
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item row="0" column="2">
<widget class="QLineEdit" name="editName"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="labelDescription">
<property name="text">
<string>Description</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="editAuthorLicense"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelName">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelSourceReference">
<property name="text">
<string>Source Reference</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelParent">
<property name="text">
<string>Parent</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QTextEdit" name="editDescription"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelAuthorLicense">
<property name="text">
<string>Author and License</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="editParent"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Tags</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelSourceURL">
<property name="text">
<string>Source URL</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLineEdit" name="editTags"/>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="editSourceReference"/>
</item>
<item row="3" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="editSourceURL"/>
</item>
<item>
<widget class="QPushButton" name="buttonURL">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonFavorite">
<property name="text">
<string>*</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabProperties">
<attribute name="title">
<string>Properties</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_43">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_23">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonPhysicalAdd">
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonPhysicalRemove">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="treePhysicalProperties"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabAppearance">
<attribute name="title">
<string>Appearance</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_42">
<item>
<layout class="QHBoxLayout" name="layoutAppearance"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonAppearanceAdd">
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonAppearanceRemove">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="treeAppearance"/>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="standardButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,545 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QDesktopServices>
#include <QItemSelectionModel>
#include <QPushButton>
#include <QString>
#endif
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/WaitCursor.h>
#include <Mod/Material/App/ModelManager.h>
#include "ModelSelect.h"
#include "ui_ModelSelect.h"
using namespace MatGui;
/* TRANSLATOR MatGui::ModelSelect */
ModelSelect::ModelSelect(QWidget* parent, Materials::ModelManager::ModelFilter filter)
: QDialog(parent)
, _filter(filter)
, ui(new Ui_ModelSelect)
{
ui->setupUi(this);
getFavorites();
getRecents();
createModelTree();
createModelProperties();
ui->buttonURL->setIcon(QIcon(QString::fromStdString(":/icons/internet-web-browser.svg")));
ui->buttonDOI->setIcon(QIcon(QString::fromStdString(":/icons/internet-web-browser.svg")));
connect(ui->standardButtons, &QDialogButtonBox::accepted, this, &ModelSelect::accept);
connect(ui->standardButtons, &QDialogButtonBox::rejected, this, &ModelSelect::reject);
QItemSelectionModel* selectionModel = ui->treeModels->selectionModel();
connect(selectionModel,
&QItemSelectionModel::selectionChanged,
this,
&ModelSelect::onSelectModel);
connect(ui->buttonURL, &QPushButton::clicked, this, &ModelSelect::onURL);
connect(ui->buttonDOI, &QPushButton::clicked, this, &ModelSelect::onDOI);
connect(ui->buttonFavorite, &QPushButton::clicked, this, &ModelSelect::onFavourite);
ui->standardButtons->button(QDialogButtonBox::Ok)->setEnabled(false);
ui->buttonFavorite->setEnabled(false);
}
void ModelSelect::getFavorites()
{
_favorites.clear();
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Models/Favorites");
int count = param->GetInt("Favorites", 0);
for (int i = 0; i < count; i++) {
QString key = QString::fromLatin1("FAV%1").arg(i);
QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), ""));
_favorites.push_back(uuid);
}
}
void ModelSelect::saveFavorites()
{
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Models/Favorites");
// Clear out the existing favorites
int count = param->GetInt("Favorites", 0);
for (int i = 0; i < count; i++) {
QString key = QString::fromLatin1("FAV%1").arg(i);
param->RemoveASCII(key.toStdString().c_str());
}
// Add the current values
param->SetInt("Favorites", _favorites.size());
int j = 0;
for (auto favorite : _favorites) {
QString key = QString::fromLatin1("FAV%1").arg(j);
param->SetASCII(key.toStdString().c_str(), favorite.toStdString());
j++;
}
}
void ModelSelect::addFavorite(const QString& uuid)
{
if (!isFavorite(uuid)) {
_favorites.push_back(uuid);
saveFavorites();
refreshModelTree();
}
}
void ModelSelect::removeFavorite(const QString& uuid)
{
if (isFavorite(uuid)) {
_favorites.remove(uuid);
saveFavorites();
refreshModelTree();
}
}
bool ModelSelect::isFavorite(const QString& uuid) const
{
for (auto it : _favorites) {
if (it == uuid) {
return true;
}
}
return false;
}
void ModelSelect::getRecents()
{
_recents.clear();
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Models/Recent");
_recentMax = param->GetInt("RecentMax", 5);
int count = param->GetInt("Recent", 0);
for (int i = 0; i < count; i++) {
QString key = QString::fromLatin1("MRU%1").arg(i);
QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), ""));
_recents.push_back(uuid);
}
}
void ModelSelect::saveRecents()
{
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Models/Recent");
// Clear out the existing favorites
int count = param->GetInt("Recent", 0);
for (int i = 0; i < count; i++) {
QString key = QString::fromLatin1("MRU%1").arg(i);
param->RemoveASCII(key.toStdString().c_str());
}
// Add the current values
int size = _recents.size();
if (size > _recentMax) {
size = _recentMax;
}
param->SetInt("Recent", size);
int j = 0;
for (auto recent : _recents) {
QString key = QString::fromLatin1("MRU%1").arg(j);
param->SetASCII(key.toStdString().c_str(), recent.toStdString());
j++;
if (j >= size) {
break;
}
}
}
void ModelSelect::addRecent(const QString& uuid)
{
// Ensure no duplicates
if (isRecent(uuid)) {
_recents.remove(uuid);
}
_recents.push_front(uuid);
while (_recents.size() > static_cast<std::size_t>(_recentMax)) {
_recents.pop_back();
}
saveRecents();
}
bool ModelSelect::isRecent(const QString& uuid) const
{
for (auto it : _recents) {
if (it == uuid) {
return true;
}
}
return false;
}
/*
* Destroys the object and frees any allocated resources
*/
ModelSelect::~ModelSelect()
{
// no need to delete child widgets, Qt does it all for us
}
void ModelSelect::addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child)
{
parent->appendRow(child);
tree->setExpanded(child->index(), true);
}
void ModelSelect::addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child)
{
parent->appendRow(child);
tree->setExpanded(child->index(), true);
}
void ModelSelect::addModels(QStandardItem& parent,
const std::map<QString, Materials::ModelTreeNode*>* modelTree,
const QIcon& icon)
{
auto tree = ui->treeModels;
for (auto& mod : *modelTree) {
Materials::ModelTreeNode* nodePtr = mod.second;
if (nodePtr->getType() == Materials::ModelTreeNode::DataNode) {
const Materials::Model* model = nodePtr->getData();
QString uuid = model->getUUID();
auto card = new QStandardItem(icon, model->getName());
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, &parent, card);
}
else {
auto node = new QStandardItem(mod.first);
addExpanded(tree, &parent, node);
node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
const std::map<QString, Materials::ModelTreeNode*>* treeMap = nodePtr->getFolder();
addModels(*node, treeMap, icon);
}
}
}
void ModelSelect::addRecents(QStandardItem* parent)
{
auto tree = ui->treeModels;
for (auto& uuid : _recents) {
try {
const Materials::Model& model = getModelManager().getModel(uuid);
if (getModelManager().passFilter(_filter, model.getType())) {
QIcon icon = QIcon(model.getLibrary().getIconPath());
auto card = new QStandardItem(icon, model.getName());
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, parent, card);
}
}
catch (const Materials::ModelNotFound&) {
}
}
}
void ModelSelect::addFavorites(QStandardItem* parent)
{
auto tree = ui->treeModels;
for (auto& uuid : _favorites) {
try {
const Materials::Model& model = getModelManager().getModel(uuid);
if (getModelManager().passFilter(_filter, model.getType())) {
QIcon icon = QIcon(model.getLibrary().getIconPath());
auto card = new QStandardItem(icon, model.getName());
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, parent, card);
}
}
catch (const Materials::ModelNotFound&) {
}
}
}
void ModelSelect::createModelTree()
{
// Materials::ModelManager modelManager;
auto tree = ui->treeModels;
auto model = new QStandardItemModel();
tree->setModel(model);
tree->setHeaderHidden(true);
fillTree();
}
void ModelSelect::refreshModelTree()
{
auto tree = ui->treeModels;
auto model = static_cast<QStandardItemModel*>(tree->model());
model->clear();
fillTree();
}
void ModelSelect::fillTree()
{
// Materials::ModelManager modelManager;
auto tree = ui->treeModels;
auto model = static_cast<QStandardItemModel*>(tree->model());
auto lib = new QStandardItem(QString::fromStdString("Favorites"));
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
addFavorites(lib);
lib = new QStandardItem(QString::fromStdString("Recent"));
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
addRecents(lib);
std::list<Materials::ModelLibrary*>* libraries = getModelManager().getModelLibraries();
for (Materials::ModelLibrary* library : *libraries) {
lib = new QStandardItem(library->getName());
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
// auto path = library->getDirectoryPath();
std::map<QString, Materials::ModelTreeNode*>* modelTree =
getModelManager().getModelTree(*library, _filter);
// delete modelTree;
addModels(*lib, modelTree, QIcon(library->getIconPath()));
}
}
void ModelSelect::setHeaders(QStandardItemModel* model)
{
QStringList headers;
headers.append(QString::fromStdString("Inherited"));
headers.append(QString::fromStdString("Property"));
headers.append(QString::fromStdString("Units"));
headers.append(QString::fromStdString("Description"));
headers.append(QString::fromStdString("URL"));
model->setHorizontalHeaderLabels(headers);
}
void ModelSelect::setColumnWidths(QTableView* table)
{
table->setColumnWidth(0, 75);
table->setColumnWidth(1, 200);
table->setColumnWidth(2, 200);
table->setColumnWidth(3, 200);
table->setColumnWidth(4, 200);
}
void ModelSelect::createModelProperties()
{
auto table = ui->tableProperties;
auto model = new QStandardItemModel();
table->setModel(model);
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
setHeaders(model);
setColumnWidths(table);
// table->setHeaderHidden(false);
// table->setUniformRowHeights(true);
// table->setItemDelegate(new MaterialDelegate(this));
}
void ModelSelect::updateModelProperties(const Materials::Model& model)
{
QTableView* table = ui->tableProperties;
QStandardItemModel* tableModel = static_cast<QStandardItemModel*>(table->model());
tableModel->clear();
setHeaders(tableModel);
setColumnWidths(table);
for (auto itp = model.begin(); itp != model.end(); itp++) {
QList<QStandardItem*> items;
QString key = itp->first;
const Materials::ModelProperty modelProperty =
static_cast<const Materials::ModelProperty>(itp->second);
auto inherited =
new QStandardItem(QString::fromStdString(modelProperty.isInherited() ? "*" : ""));
// inherited->setToolTip(QString::fromStdString(modelProperty.getDescription()));
items.append(inherited);
auto propertyItem = new QStandardItem(key);
items.append(propertyItem);
auto unitsItem = new QStandardItem(modelProperty.getUnits());
items.append(unitsItem);
auto descriptionItem = new QStandardItem(modelProperty.getDescription());
items.append(descriptionItem);
auto urlItem = new QStandardItem(modelProperty.getURL());
items.append(urlItem);
// addExpanded(tree, modelRoot, propertyItem);
tableModel->appendRow(items);
}
}
void ModelSelect::updateMaterialModel(const QString& uuid)
{
Materials::Model model = getModelManager().getModel(uuid);
// Update the general information
ui->editName->setText(model.getName());
ui->editURL->setText(model.getURL());
ui->editDOI->setText(model.getDOI());
ui->editDescription->setText(model.getDescription());
if (model.getType() == Materials::Model::ModelType_Physical) {
ui->tabWidget->setTabText(1, QString::fromStdString("Properties"));
}
else {
ui->tabWidget->setTabText(1, QString::fromStdString("Appearance"));
}
updateModelProperties(model);
}
void ModelSelect::clearMaterialModel(void)
{
// Update the general information
ui->editName->setText(QString::fromStdString(""));
ui->editURL->setText(QString::fromStdString(""));
ui->editDOI->setText(QString::fromStdString(""));
ui->editDescription->setText(QString::fromStdString(""));
ui->tabWidget->setTabText(1, QString::fromStdString("Properties"));
QTableView* table = ui->tableProperties;
QStandardItemModel* tableModel = static_cast<QStandardItemModel*>(table->model());
tableModel->clear();
setHeaders(tableModel);
setColumnWidths(table);
}
void ModelSelect::onSelectModel(const QItemSelection& selected, const QItemSelection& deselected)
{
Q_UNUSED(deselected);
QStandardItemModel* model = static_cast<QStandardItemModel*>(ui->treeModels->model());
QModelIndexList indexes = selected.indexes();
for (auto it = indexes.begin(); it != indexes.end(); it++) {
QStandardItem* item = model->itemFromIndex(*it);
Base::Console().Log("%s\n", item->text().toStdString().c_str());
if (item) {
try {
_selected = item->data(Qt::UserRole).toString();
Base::Console().Log("\t%s\n", _selected.toStdString().c_str());
updateMaterialModel(_selected);
ui->standardButtons->button(QDialogButtonBox::Ok)->setEnabled(true);
ui->buttonFavorite->setEnabled(true);
}
catch (const std::exception& e) {
_selected = QString::fromStdString("");
Base::Console().Log("Error %s\n", e.what());
clearMaterialModel();
ui->standardButtons->button(QDialogButtonBox::Ok)->setEnabled(false);
ui->buttonFavorite->setEnabled(false);
}
}
}
}
void ModelSelect::onURL(bool checked)
{
Q_UNUSED(checked)
Base::Console().Log("URL\n");
QString url = ui->editURL->text();
if (url.length() > 0) {
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
}
}
void ModelSelect::onDOI(bool checked)
{
Q_UNUSED(checked)
Base::Console().Log("DOI\n");
QString url = QString::fromStdString("https://doi.org/") + ui->editDOI->text();
if (url.length() > 0) {
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
}
}
void ModelSelect::onFavourite(bool checked)
{
Q_UNUSED(checked)
Base::Console().Log("Favorite\n");
if (isFavorite(_selected)) {
removeFavorite(_selected);
}
else {
addFavorite(_selected);
}
}
void ModelSelect::accept()
{
addRecent(_selected);
QDialog::accept();
}
void ModelSelect::reject()
{
QDialog::reject();
}
#include "moc_ModelSelect.cpp"

View File

@@ -0,0 +1,109 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_MODELSELECT_H
#define MATGUI_MODELSELECT_H
#include <boost/filesystem.hpp>
#include <QDialog>
#include <QDir>
#include <QStandardItem>
#include <QTableView>
#include <QTreeView>
#include <Mod/Material/App/Materials.h>
namespace fs = boost::filesystem;
namespace MatGui
{
class Ui_ModelSelect;
class ModelSelect: public QDialog
{
Q_OBJECT
public:
explicit ModelSelect(
QWidget* parent = nullptr,
Materials::ModelManager::ModelFilter filter = Materials::ModelManager::ModelFilter_None);
~ModelSelect() override;
void onURL(bool checked);
void onDOI(bool checked);
void onFavourite(bool checked);
void onSelectModel(const QItemSelection& selected, const QItemSelection& deselected);
const QString& selectedModel() const
{
return _selected;
}
void accept() override;
void reject() override;
private:
void getFavorites();
void saveFavorites();
void addFavorite(const QString& uuid);
void removeFavorite(const QString& uuid);
bool isFavorite(const QString& uuid) const;
void getRecents();
void saveRecents();
void addRecent(const QString& uuid);
bool isRecent(const QString& uuid) const;
void addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child);
void addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child);
void addRecents(QStandardItem* parent);
void addFavorites(QStandardItem* parent);
void addModels(QStandardItem& parent,
const std::map<QString, Materials::ModelTreeNode*>* modelTree,
const QIcon& icon);
void updateMaterialModel(const QString& uuid);
void clearMaterialModel(void);
void createModelTree();
void refreshModelTree();
void fillTree();
void setHeaders(QStandardItemModel* model);
void setColumnWidths(QTableView* table);
void updateModelProperties(const Materials::Model& model);
void createModelProperties();
Materials::ModelManager& getModelManager()
{
return _modelManager;
}
Materials::ModelManager::ModelFilter _filter;
std::unique_ptr<Ui_ModelSelect> ui;
Materials::ModelManager _modelManager;
QString _selected;
std::list<QString> _favorites;
std::list<QString> _recents;
int _recentMax;
};
}// namespace MatGui
#endif// MATGUI_MODELSELECT_H

View File

@@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MatGui::ModelSelect</class>
<widget class="QDialog" name="MatGui::ModelSelect">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>705</width>
<height>489</height>
</rect>
</property>
<property name="windowTitle">
<string>Material Models</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="treeModels"/>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabGeneral">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>365</width>
<height>409</height>
</size>
</property>
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="labelURL">
<property name="text">
<string>URL</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Description</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelDOI">
<property name="text">
<string>DOI</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QTextEdit" name="editDescription">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="editName">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelName">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="editDOI">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonDOI">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="editURL">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonURL">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonFavorite">
<property name="toolTip">
<string>Add to favorites</string>
</property>
<property name="text">
<string>*</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabProperties">
<attribute name="title">
<string>Properties</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTableView" name="tableProperties"/>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="standardButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,24 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"

View File

@@ -0,0 +1,77 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_PRECOMPILED_H
#define MATGUI_PRECOMPILED_H
#include <FCConfig.h>
#include <Mod/Material/MaterialGlobal.h>
// point at which warnings of overly long specifiers disabled (needed for VC6)
#ifdef _MSC_VER
#pragma warning(disable : 4251)
#pragma warning(disable : 4503)
#pragma warning(disable : 4786)// specifier longer then 255 chars
#pragma warning(disable : 4273)
#endif
#ifdef FC_OS_WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#endif
#ifdef _PreComp_
// standard
#include <cfloat>
#include <cmath>
// STL
#include <algorithm>
#include <map>
#include <sstream>
#include <string>
#include <vector>
// OpenCasCade
// #include <Mod/Part/App/OpenCascadeAll.h>
// Boost
#include <boost/algorithm/string/predicate.hpp>
#include <boost/regex.hpp>
// Qt Toolkit
#ifndef __QtAll__
#include <Gui/QtAll.h>
#endif
// // Inventor includes OpenGL
// #ifndef __InventorAll__
// # include <Gui/InventorAll.h>
// #endif
#endif//_PreComp_
#endif// MATGUI_PRECOMPILED_H

View File

@@ -0,0 +1,10 @@
<RCC>
<qresource>
<file>icons/MaterialWorkbench.svg</file>
<file>icons/Materials_Edit.svg</file>
<file>icons/preferences-material.svg</file>
<file>icons/preview-rendered.svg</file>
<file>icons/preview-vector.svg</file>
<file>icons/table.svg</file>
</qresource>
</RCC>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64"
height="64"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="preview-vector.svg">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="-206.25075 : 119.68854 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="183.50001 : 140.32143 : 1"
inkscape:persp3d-origin="48 : 32 : 1"
id="perspective3792" />
<linearGradient
id="linearGradient3755">
<stop
style="stop-color:#424242;stop-opacity:1;"
offset="0"
id="stop3757" />
<stop
style="stop-color:#9f9f9f;stop-opacity:1;"
offset="1"
id="stop3759" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3755"
id="linearGradient3761"
x1="75.724594"
y1="85.023956"
x2="41.895164"
y2="13.334851"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8.7571168"
inkscape:cx="39.859065"
inkscape:cy="30.925664"
inkscape:document-units="px"
inkscape:current-layer="g3794"
showgrid="true"
showborder="true"
inkscape:window-width="800"
inkscape:window-height="836"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="0"
inkscape:snap-bbox="false"
inkscape:snap-nodes="true"
inkscape:snap-global="true">
<inkscape:grid
type="xygrid"
id="grid3002"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>$committer</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>preview-vector</dc:title>
<dc:date>2013-11-19</dc:date>
<dc:relation>http://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Material/Resources/icons/preview-vector.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-988.36218)">
<g
id="g3794"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3.29399991;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate">
<path
style="fill:#d3d7cf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 29.814326,991.36218 -8.814326,4 -1,7.00002 26,1 14.994091,-8.6577 z"
id="path3816"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
d="M 38.484871,1007.8171 40,1046.3622 l 21,-22.4044 0,-29.25647 z"
style="fill:#b7b7b7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3818"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#555753;stroke:#555753;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 59.035745,9.6627807 59.108006,34.818961 40.91531,54.264958 42.698526,19.372964 z"
id="path3022"
inkscape:connector-curvature="0"
transform="translate(0,988.36218)"
sodipodi:nodetypes="ccccc" />
<path
d="m 21,995.36218 31,5.00002 -12,46 -30,-8 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3820"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
d="m 21,995.36218 31,5.00002 -12,46 -30,-8 z"
style="color:#000000;fill:none;stroke:#888a85;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path3820-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
viewBox="0 0 16.933333 16.933333"
version="1.1"
id="svg5"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2">
<linearGradient
id="linearGradient992">
<stop
style="stop-color:#ff0000;stop-opacity:1;"
offset="0"
id="stop990" />
</linearGradient>
</defs>
<g
id="layer1">
<rect
style="fill:none;stroke:#000000;stroke-width:0.52916667;stroke-opacity:1;stroke-dasharray:none"
id="rect434"
width="14.684375"
height="14.122135"
x="1.1244792"
y="1.3559896" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="M 1.1244792,4.9609349 15.643489,5.0270807"
id="path1407" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="M 1.9182291,7.3752603 H 5.523177 v 0"
id="path2181" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="m 6.8295573,7.3421875 h 3.6049477 v 0"
id="path2181-4" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="m 11.426692,7.4083334 h 3.604948 v 0"
id="path2181-5" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="m 1.9099611,12.567709 h 3.604948 v 0"
id="path2181-2" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="m 6.8212891,12.534636 h 3.6049479 v 0"
id="path2181-4-0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="m 11.418424,12.600782 h 3.604948 v 0"
id="path2181-5-5" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="m 1.9264977,10.021094 h 3.6049479 v 0"
id="path2181-46" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="m 6.8378259,10.021094 h 3.6049471 v 0"
id="path2181-4-3" />
<path
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
d="m 11.43496,10.054167 h 3.604948 v 0"
id="path2181-5-7" />
<path
style="fill:#0000ff;stroke:#000000;stroke-width:0.25;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="M 29.5,17.805701 C 20.7,17.760754 11.657813,17.715771 9.40625,17.705739 L 5.3125,17.6875 v -5.75 -5.75 H 32 58.6875 v 5.875 5.875 L 52.09375,17.91246 C 48.467188,17.89869 38.3,17.850648 29.5,17.805701 Z"
id="path2364"
transform="scale(0.26458333)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>MaterialEditor</name>
<message>
<location filename="../../materials-editor.ui" line="14"/>
<source>Material Editor</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="22"/>
<source>Material card</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="40"/>
<source>Opens the Product URL of this material in an external browser</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="56"/>
<source>Existing material cards</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="67"/>
<source>Opens an existing material card</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="70"/>
<source>Open...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="77"/>
<source>Saves this material as a card</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="80"/>
<source>Save as...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="96"/>
<source>Material parameter</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="115"/>
<source>Add / remove parameter</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="126"/>
<source>Add property</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../materials-editor.ui" line="133"/>
<source>Delete property</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Material</name>
<message>
<location filename="../../MaterialEditor.py" line="275"/>
<source>Product URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../MaterialEditor.py" line="337"/>
<source>UserDefined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../MaterialEditor.py" line="583"/>
<source>Name</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@@ -23,3 +23,5 @@ import FreeCAD
# import for the FreeCAD Material card
FreeCAD.addImportType("FreeCAD Material Card (*.FCMat)", "importFCMat")
FreeCAD.__unit_test__ += [ "TestMaterialsApp" ]

View File

@@ -19,3 +19,7 @@
#* *
#***************************************************************************
# import FreeCADGui
# import Material_rc
# FreeCADGui.addPreferencePage(":/ui/preferences-material.ui","Material")

View File

@@ -1,135 +0,0 @@
# ***************************************************************************
# * Copyright (c) 2013-2015 Juergen Riegel <FreeCAD@juergen-riegel.net> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
import sys
import FreeCAD
# The usage description if you use this tool from the command line ("__main__")
CommandlineUsage = """Material - Tool to work with FreeCAD Material definition cards
Usage:
Material [Options] card-file-name
Options:
-c, --output-csv=filename write a comma separated grid with the material data
Exit:
0 No Error or Warning found
1 Argument error, wrong or too few Arguments given
Tool to work with FreeCAD Material definition cards
Examples:
Material "StandardMaterial/Steel.FCMat"
Author:
(c) 2013 Juergen Riegel
mail@juergen-riegel.net
Licence: LGPL
Version:
0.1
"""
# see comments in module importFCMat, there is an independent parser implementation
# for reading and writing FCMat files
# inside FreeCAD mostly the one from importFCMat.py is used
def importFCMat(fileName):
"Read a FCMat file into a dictionary"
try:
import ConfigParser as configparser
except ImportError:
import configparser
FreeCAD.Console.PrintError(
'This mat card reader is probably deprecated and not widely used in FreeCAD. '
'See comment in Material.py module.\n'
)
Config = configparser.RawConfigParser()
Config.optionxform = str
Config.read(fileName, encoding='utf-8') # respect unicode filenames
dict1 = {}
for section in Config.sections():
options = Config.options(section)
for option in options:
dict1[option] = Config.get(section, option)
return dict1
def exportFCMat(fileName, matDict):
"Write a material dictionary to a FCMat file"
try:
import ConfigParser as configparser
except ImportError:
import configparser
import string
Config = configparser.RawConfigParser()
FreeCAD.Console.PrintError(
'This mat card writer is probably deprecated and not widely used in FreeCAD. '
'See comment in Material.py module.\n'
)
# create groups
for x in matDict.keys():
grp, key = string.split(x, sep='_')
if not Config.has_section(grp):
Config.add_section(grp)
# fill groups
for x in matDict.keys():
grp, key = string.split(x, sep='_')
Config.set(grp, key, matDict[x])
Preamble = "# This is a FreeCAD material-card file\n\n"
# Writing our configuration file to 'example.cfg'
with open(fileName, 'wb') as configfile:
configfile.write(Preamble)
Config.write(configfile)
if __name__ == '__main__':
import getopt
try:
opts, args = getopt.getopt(sys.argv[1:], "c:", ["output-csv="])
except getopt.GetoptError:
# print help information and exit:
sys.stderr.write(CommandlineUsage)
sys.exit(1)
# checking on the options
for o, a in opts:
if o in ("-c", "--output-csv"):
print("writing file: " + a + "\n")
OutPath = a
# running through the files
FileName = args[0]
kv_map = importFCMat(FileName)
for k in kv_map.keys():
print(repr(k) + " : " + repr(kv_map[k]))
sys.exit(0) # no error

View File

@@ -25,12 +25,15 @@ __author__ = "Yorik van Havre, Bernd Hahnebach"
__url__ = "http://www.freecad.org"
import os
from pathlib import PurePath
import sys
from PySide import QtCore, QtGui, QtSvg
import FreeCAD
import FreeCADGui
# import Material_rc
from materialtools.cardutils import get_material_preferred_directory, get_material_preferred_save_directory
# is this still needed after the move to card utils???
unicode = str
@@ -52,17 +55,21 @@ class MaterialEditor:
self.customprops = []
self.internalprops = []
self.groups = []
self.directory = FreeCAD.getResourceDir() + "Mod/Material"
self.directory = get_material_preferred_directory()
self.save_directory = get_material_preferred_save_directory()
if self.directory is None:
self.directory = FreeCAD.getResourceDir() + "Mod/Material"
self.materials = {}
self.cards = {}
self.icons = {}
self.initialIndex = -1
self.edited = False
self.card_path = card_path
filePath = os.path.dirname(__file__) + os.sep
self.iconPath = (filePath + "Resources" + os.sep + "icons" + os.sep)
# load the UI file from the same directory as this script
self.widget = FreeCADGui.PySideUic.loadUi(filePath + "materials-editor.ui")
self.widget = FreeCADGui.PySideUic.loadUi(filePath + "Resources" + os.sep + "ui" + os.sep + "materials-editor.ui")
# remove unused Help button
self.widget.setWindowFlags(self.widget.windowFlags()
& ~QtCore.Qt.WindowContextHelpButtonHint)
@@ -104,7 +111,7 @@ class MaterialEditor:
# currently closes the dialog
standardButtons.rejected.connect(self.reject)
standardButtons.accepted.connect(self.accept)
standardButtons.button(QtGui.QDialogButtonBox.Ok).clicked.connect(self.verify)
buttonOpen.clicked.connect(self.openfile)
buttonSave.clicked.connect(self.savefile)
buttonURL.clicked.connect(self.openProductURL)
@@ -117,6 +124,7 @@ class MaterialEditor:
treeView.setModel(model)
treeView.setUniformRowHeights(True)
treeView.setItemDelegate(MaterialsDelegate())
model.itemChanged.connect(self.modelChange)
# init model
self.implementModel()
@@ -181,6 +189,7 @@ class MaterialEditor:
# top.sortChildren(0)
# treeView.expandAll()
self.edited = False
def updateMatParamsInTree(self, data):
@@ -220,10 +229,20 @@ class MaterialEditor:
it = QtGui.QStandardItem(i)
userGroup.appendRow([item, it])
self.customprops.append(k)
self.edited = False
def chooseMaterial(self, index):
if index < 0:
return
if self.verifyMaterial():
"""
Save any unchanged data
"""
self.edited = False
else:
return
self.card_path = self.widget.ComboMaterial.itemData(index)
FreeCAD.Console.PrintMessage(
"choose_material in material editor:\n"
@@ -239,6 +258,21 @@ class MaterialEditor:
else:
FreeCAD.Console.PrintError("Material card not found: {}\n".format(self.card_path))
def verifyMaterial(self):
if self.edited:
reply = QtGui.QMessageBox.question(self.widget, #FreeCADGui.getMainWindow(),
translate("Material","The document has been modified."),
translate("Material","Do you want to save your changes?"),
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel,
QtGui.QMessageBox.Save)
if reply == QtGui.QMessageBox.Cancel:
return False
if reply == QtGui.QMessageBox.Save:
self.savefile()
return True
def updateCardsInCombo(self):
"""updates the contents of the materials combo with existing material cards"""
@@ -280,6 +314,32 @@ class MaterialEditor:
if url:
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
def modelChange(self, item):
"""
Called when an item in the tree is modified. This will set edited to True, but this
will be reset in the event of mass updates, such as loading a card
"""
self.edited = True
def verify(self, button):
"""
Verify that the user wants to save any changed data before exiting
"""
if self.edited:
reply = QtGui.QMessageBox.question(self.widget, #FreeCADGui.getMainWindow(),
translate("Material","The document has been modified."),
translate("Material","Do you want to save your changes?"),
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel,
QtGui.QMessageBox.Save)
if reply == QtGui.QMessageBox.Cancel:
return
if reply == QtGui.QMessageBox.Save:
self.savefile()
self.accept()
def accept(self):
""
@@ -340,6 +400,7 @@ class MaterialEditor:
it = QtGui.QStandardItem(value)
top.appendRow([item, it])
self.customprops.append(key)
self.edited = True
def deleteCustomProperty(self, key=None):
@@ -376,6 +437,8 @@ class MaterialEditor:
it.setText("")
buttonDeleteProperty.setProperty("text", "Delete value")
self.edited = True
buttonDeleteProperty.setEnabled(False)
def onClickTree(self, index):
@@ -505,12 +568,20 @@ class MaterialEditor:
return color.name()
def openfile(self):
if self.verifyMaterial():
"""
Save any unchanged data
"""
self.edited = False
else:
return
"Opens a FCMat file"
if self.category == "Solid":
directory = self.directory + os.sep + "StandardMaterial"
else:
directory = self.directory + os.sep + "FluidMaterial"
if self.card_path is None:
if self.card_path is None or len(self.card_path) == 0:
self.card_path = directory
filetuple = QtGui.QFileDialog.getOpenFileName(
QtGui.QApplication.activeWindow(),
@@ -529,8 +600,11 @@ class MaterialEditor:
# D:/FreeCAD-build/data/Mod\Material\FluidMaterial\Air.FCMat
# To keep it simple, we take a path from the ComboMaterial and change only the
# material card filename
if self.initialIndex > -1:
path = self.widget.ComboMaterial.itemData(self.initialIndex)
#
# Using the initialIndex variable won't work before a card os selected for the
# first time, so use index 1. Index 0 is a blank entry
if self.widget.ComboMaterial.count() > 1:
path = self.widget.ComboMaterial.itemData(1)
# at first check if we have a uniform usage
# (if a character is not present, rsplit delivers the initial string)
testBackslash = path.rsplit('\\', 1)[0]
@@ -590,19 +664,27 @@ class MaterialEditor:
filetuple = QtGui.QFileDialog.getSaveFileName(
QtGui.QApplication.activeWindow(),
"Save FreeCAD Material file",
self.directory + "/" + name + ".FCMat",
self.save_directory + "/" + name + ".FCMat",
"*.FCMat"
)
# a tuple of two empty strings returns True, so use the filename directly
filename = filetuple[0]
if filename:
self.directory = os.path.dirname(filename)
# should not be resource dir but user result dir instead
# Update the directories to the current save value
self.save_directory = os.path.dirname(filename)
self.directory = self.save_directory
self.card_path = filename
d = self.getDict()
# self.outputDict(d)
if d:
# Set the card name to match the filename
path = PurePath(filename)
d["CardName"] = path.stem
from importFCMat import write
write(filename, d)
self.edited = False
self.updateCardsInCombo()
def show(self):
@@ -854,8 +936,13 @@ def translate(context, text):
def openEditor(obj=None, prop=None):
"""openEditor([obj,prop]): opens the editor, optionally with
an object name and material property name to edit"""
editor = MaterialEditor(obj, prop)
editor.exec_()
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Cards")
legacy = param.GetBool("LegacyEditor", True)
if legacy:
editor = MaterialEditor(obj, prop)
editor.exec_()
else:
FreeCADGui.runCommand('Materials_Edit',0)
def editMaterial(material=None, card_path=None, category="Solid"):

View File

@@ -0,0 +1,46 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include <FCGlobal.h>
#ifndef MATERIAL_GLOBAL_H
#define MATERIAL_GLOBAL_H
// Material
#ifndef MaterialsExport
#ifdef Material_EXPORTS
# define MaterialsExport FREECAD_DECL_EXPORT
#else
# define MaterialsExport FREECAD_DECL_IMPORT
#endif
#endif
// MatGui
#ifndef MatGuiExport
#ifdef MatGui_EXPORTS
# define MatGuiExport FREECAD_DECL_EXPORT
#else
# define MatGuiExport FREECAD_DECL_IMPORT
#endif
#endif
#endif //MATERIAL_GLOBAL_H

View File

@@ -2,5 +2,6 @@
<qresource>
<file>icons/preview-rendered.svg</file>
<file>icons/preview-vector.svg</file>
<file>ui/materials-editor.ui</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,15 @@
# File created by ConvertFCMat.py
General:
UUID: "d1f317f0-5ffa-4798-8ab3-af2ff0b5182c"
AuthorAndLicense: "(c) 2023 David Carter"
Name: "Aluminum"
Description: "Defines the Aluminum appearance properties"
AppearanceModels:
BasicRendering:
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
AmbientColor: "(0.3000, 0.3000, 0.3000, 1.0)"
DiffuseColor: "(0.3000, 0.3000, 0.3000, 1.0)"
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Shininess: "0.0900"
SpecularColor: "(0.3000, 0.3000, 0.3000, 1.0)"
Transparency: "0.0"

View File

@@ -0,0 +1,15 @@
# File created by ConvertFCMat.py
General:
UUID: "4151e19c-fd6a-4ca4-83d4-d5e17d76cb9c"
AuthorAndLicense: "(c) 2023 David Carter"
Name: "Brass"
Description: "Defines the Brass appearance properties"
AppearanceModels:
BasicRendering:
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
AmbientColor: "(0.3294, 0.2235, 0.0275, 1.0)"
DiffuseColor: "(0.7804, 0.5686, 0.1137, 1.0)"
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Shininess: "0.2179"
SpecularColor: "(0.9922, 0.9412, 0.8078, 1.0)"
Transparency: "0.0"

View File

@@ -0,0 +1,15 @@
# File created by ConvertFCMat.py
General:
UUID: "ae194589-02d4-4e9b-98a7-f523f660d510"
AuthorAndLicense: "(c) 2023 David Carter"
Name: "Bronze"
Description: "Defines the Bronze appearance properties"
AppearanceModels:
BasicRendering:
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
AmbientColor: "(0.2125, 0.1275, 0.0540, 1.0)"
DiffuseColor: "(0.7140, 0.4284, 0.1814, 1.0)"
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Shininess: "0.2000"
SpecularColor: "(0.3935, 0.2719, 0.1667, 1.0)"
Transparency: "0.0"

View File

@@ -0,0 +1,15 @@
# File created by ConvertFCMat.py
General:
UUID: "a9544b88-dde7-4d05-9bdb-c008a4e88dc1"
AuthorAndLicense: "(c) 2023 David Carter"
Name: "Chrome"
Description: "Defines the Chrome appearance properties"
AppearanceModels:
BasicRendering:
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
AmbientColor: "(0.3500, 0.3500, 0.3500, 1.0)"
DiffuseColor: "(0.9176, 0.9176, 0.9176, 1.0)"
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Shininess: "0.1000"
SpecularColor: "(0.9746, 0.9746, 0.9746, 1.0)"
Transparency: "0.0"

View File

@@ -0,0 +1,15 @@
# File created by ConvertFCMat.py
General:
UUID: "524cad9b-b841-4037-9851-badeca7dcee2"
AuthorAndLicense: "(c) 2023 David Carter"
Name: "Copper"
Description: "Defines the Copper appearance properties"
AppearanceModels:
BasicRendering:
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
AmbientColor: "(0.3300, 0.2600, 0.2300, 1.0)"
DiffuseColor: "(0.5000, 0.1100, 0.0000, 1.0)"
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Shininess: "0.9300"
SpecularColor: "(0.9500, 0.7300, 0.0000, 1.0)"
Transparency: "0.0"

View File

@@ -0,0 +1,15 @@
# File created by ConvertFCMat.py
General:
UUID: "5dbb7be6-8b63-479b-ab4c-87be02ead973"
AuthorAndLicense: "(c) 2023 David Carter"
Name: "Default Appearance"
Description: "Defines the default appearance properties"
AppearanceModels:
BasicRendering:
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
AmbientColor: "(0.2000, 0.2000, 0.2000, 1.0)"
DiffuseColor: "(0.8000, 0.8000, 0.8000, 1.0)"
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Shininess: "0.2000"
SpecularColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Transparency: "0.0"

Some files were not shown because too many files have changed in this diff Show More