Merge pull request #19908 from davesrocketshop/external_modules_part1_pr2

Materials: External Modules Part 1
This commit is contained in:
Chris Hennes
2025-03-24 11:41:02 -05:00
committed by GitHub
80 changed files with 4373 additions and 1399 deletions

View File

@@ -29,15 +29,24 @@
#include <App/CleanupProcess.h>
#include "MaterialFilterPy.h"
#include "MaterialLoader.h"
#include "MaterialManagerPy.h"
#include "MaterialPy.h"
#include "MaterialManagerLocal.h"
#include "ModelManagerLocal.h"
#include "PropertyMaterial.h"
#include "Array2DPy.h"
#include "Array3DPy.h"
#include "ModelManagerPy.h"
#include "ModelPropertyPy.h"
#include "ModelPy.h"
#include "UUIDsPy.h"
#include "PropertyMaterial.h"
#include "MaterialFilterPy.h"
#include "MaterialFilterOptionsPy.h"
#include "MaterialLibraryPy.h"
#include "MaterialManagerPy.h"
#include "MaterialPropertyPy.h"
#include "MaterialPy.h"
namespace Materials
{
@@ -74,8 +83,13 @@ PyMOD_INIT_FUNC(Materials)
Base::Console().Log("Loading Material module... done\n");
Base::Interpreter().addType(&Materials::MaterialManagerPy::Type, module, "MaterialManager");
Base::Interpreter().addType(&Materials::Array2DPy::Type, module, "Array2D");
Base::Interpreter().addType(&Materials::Array3DPy::Type, module, "Array3D");
Base::Interpreter().addType(&Materials::MaterialFilterPy::Type, module, "MaterialFilter");
Base::Interpreter().addType(&Materials::MaterialFilterOptionsPy::Type, module, "MaterialFilterOptions");
Base::Interpreter().addType(&Materials::MaterialLibraryPy::Type, module, "MaterialLibrary");
Base::Interpreter().addType(&Materials::MaterialManagerPy::Type, module, "MaterialManager");
Base::Interpreter().addType(&Materials::MaterialPropertyPy::Type, module, "MaterialProperty");
Base::Interpreter().addType(&Materials::MaterialPy::Type, module, "Material");
Base::Interpreter().addType(&Materials::ModelManagerPy::Type, module, "ModelManager");
Base::Interpreter().addType(&Materials::ModelPropertyPy::Type, module, "ModelProperty");
@@ -88,22 +102,25 @@ PyMOD_INIT_FUNC(Materials)
Materials::Material ::init();
Materials::MaterialFilter ::init();
Materials::MaterialFilterOptions ::init();
Materials::MaterialManager ::init();
Materials::MaterialManagerLocal ::init();
Materials::Model ::init();
Materials::ModelManager ::init();
Materials::ModelManagerLocal ::init();
Materials::ModelUUIDs ::init();
Materials::LibraryBase ::init();
Materials::Library ::init();
Materials::MaterialLibrary ::init();
Materials::MaterialLibraryLocal ::init();
Materials::ModelLibrary ::init();
Materials::MaterialExternalLibrary ::init();
Materials::ModelProperty ::init();
Materials::MaterialProperty ::init();
Materials::MaterialValue ::init();
Materials::Material2DArray ::init();
Materials::Material3DArray ::init();
Materials::Array2D ::init();
Materials::Array3D ::init();
Materials::PropertyMaterial ::init();
// clang-format on

View File

@@ -3,8 +3,8 @@
<PythonExport
Father="BaseClassPy"
Name="Array2DPy"
Twin="Material2DArray"
TwinPointer="Material2DArray"
Twin="Array2D"
TwinPointer="Array2D"
Include="Mod/Material/App/MaterialValue.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
@@ -21,13 +21,19 @@
</Documentation>
<Parameter Name="Array" Type="List"/>
</Attribute>
<Attribute Name="Rows" ReadOnly="true">
<Attribute Name="Dimensions" ReadOnly="true">
<Documentation>
<UserDocu>The number of dimensions in the array, in this case 2.</UserDocu>
</Documentation>
<Parameter Name="Dimensions" Type="Int"/>
</Attribute>
<Attribute Name="Rows" ReadOnly="false">
<Documentation>
<UserDocu>The number of rows in the array.</UserDocu>
</Documentation>
<Parameter Name="Rows" Type="Long"/>
</Attribute>
<Attribute Name="Columns" ReadOnly="true">
<Attribute Name="Columns" ReadOnly="false">
<Documentation>
<UserDocu>The number of columns in the array.</UserDocu>
</Documentation>
@@ -43,5 +49,10 @@
<UserDocu>Get the value at the given row and column</UserDocu>
</Documentation>
</Methode>
<Methode Name="setValue" ReadOnly="true">
<Documentation>
<UserDocu>Set the value at the given row and column</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>

View File

@@ -44,7 +44,7 @@ using namespace Materials;
std::string Array2DPy::representation() const
{
std::stringstream str;
str << "<Array2D object at " << getMaterial2DArrayPtr() << ">";
str << "<Array2D object at " << getArray2DPtr() << ">";
return str.str();
}
@@ -52,7 +52,7 @@ std::string Array2DPy::representation() const
PyObject* Array2DPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
{
// never create such objects with the constructor
return new Array2DPy(new Material2DArray());
return new Array2DPy(new Array2D());
}
// constructor method
@@ -65,7 +65,7 @@ Py::List Array2DPy::getArray() const
{
Py::List list;
auto array = getMaterial2DArrayPtr()->getArray();
auto array = getArray2DPtr()->getArray();
for (auto& row : array) {
Py::List rowList;
@@ -81,14 +81,29 @@ Py::List Array2DPy::getArray() const
return list;
}
Py::Long Array2DPy::getDimensions() const
{
return Py::Long(2);
}
Py::Long Array2DPy::getRows() const
{
return Py::Long(getMaterial2DArrayPtr()->rows());
return Py::Long(getArray2DPtr()->rows());
}
void Array2DPy::setRows(Py::Long arg)
{
getArray2DPtr()->setRows(arg);
}
Py::Long Array2DPy::getColumns() const
{
return Py::Long(getMaterial2DArrayPtr()->columns());
return Py::Long(getArray2DPtr()->columns());
}
void Array2DPy::setColumns(Py::Long arg)
{
getArray2DPtr()->setColumns(arg);
}
PyObject* Array2DPy::getRow(PyObject* args)
@@ -101,7 +116,7 @@ PyObject* Array2DPy::getRow(PyObject* args)
try {
Py::List list;
auto arrayRow = getMaterial2DArrayPtr()->getRow(row);
auto arrayRow = getArray2DPtr()->getRow(row);
for (auto& column : *arrayRow) {
auto quantity =
new Base::QuantityPy(new Base::Quantity(column.value<Base::Quantity>()));
@@ -126,7 +141,7 @@ PyObject* Array2DPy::getValue(PyObject* args)
}
try {
auto value = getMaterial2DArrayPtr()->getValue(row, column);
auto value = getArray2DPtr()->getValue(row, column);
return new Base::QuantityPy(new Base::Quantity(value.value<Base::Quantity>()));
}
catch (const InvalidIndex&) {
@@ -136,6 +151,28 @@ PyObject* Array2DPy::getValue(PyObject* args)
return nullptr;
}
PyObject* Array2DPy::setValue(PyObject* args)
{
int row;
int column;
PyObject* valueObj;
if (PyArg_ParseTuple(args, "iiO!", &row, &column, &PyUnicode_Type, &valueObj)) {
Py::String item(valueObj);
try {
QVariant variant = QVariant::fromValue(Base::Quantity::parse(item.as_string()));
getArray2DPtr()->setValue(row, column, variant);
}
catch (const InvalidIndex&) {
PyErr_SetString(PyExc_IndexError, "Invalid array index");
return nullptr;
}
Py_Return;
}
PyErr_SetString(PyExc_TypeError, "Expected (integer, integer, string) arguments");
return nullptr;
}
PyObject* Array2DPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;

View File

@@ -3,8 +3,8 @@
<PythonExport
Father="BaseClassPy"
Name="Array3DPy"
Twin="Material3DArray"
TwinPointer="Material3DArray"
Twin="Array3D"
TwinPointer="Array3D"
Include="Mod/Material/App/MaterialValue.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
@@ -21,17 +21,23 @@
</Documentation>
<Parameter Name="Array" Type="List"/>
</Attribute>
<Attribute Name="Columns" ReadOnly="true">
<Attribute Name="Dimensions" ReadOnly="true">
<Documentation>
<UserDocu>The number of dimensions in the array, in this case 3.</UserDocu>
</Documentation>
<Parameter Name="Dimensions" Type="Int"/>
</Attribute>
<Attribute Name="Columns" ReadOnly="false">
<Documentation>
<UserDocu>The number of columns in the array.</UserDocu>
</Documentation>
<Parameter Name="Columns" Type="Long"/>
<Parameter Name="Columns" Type="Int"/>
</Attribute>
<Attribute Name="Depth" ReadOnly="true">
<Attribute Name="Depth" ReadOnly="false">
<Documentation>
<UserDocu>The depth of the array (3rd dimension).</UserDocu>
</Documentation>
<Parameter Name="Columns" Type="Long"/>
<Parameter Name="Depth" Type="Int"/>
</Attribute>
<Methode Name="getRows" ReadOnly="true">
<Documentation>
@@ -48,5 +54,20 @@
<UserDocu>Get the column value at the given depth</UserDocu>
</Documentation>
</Methode>
<Methode Name="setDepthValue" ReadOnly="true">
<Documentation>
<UserDocu>Set the column value at the given depth</UserDocu>
</Documentation>
</Methode>
<Methode Name="setValue" ReadOnly="true">
<Documentation>
<UserDocu>Set the value at the given depth, row, and column</UserDocu>
</Documentation>
</Methode>
<Methode Name="setRows" ReadOnly="true">
<Documentation>
<UserDocu>Set the number of rows at the given depth</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>

View File

@@ -44,7 +44,7 @@ using namespace Materials;
std::string Array3DPy::representation() const
{
std::stringstream str;
str << "<Array3D object at " << getMaterial3DArrayPtr() << ">";
str << "<Array3D object at " << getArray3DPtr() << ">";
return str.str();
}
@@ -52,7 +52,7 @@ std::string Array3DPy::representation() const
PyObject* Array3DPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
{
// never create such objects with the constructor
return new Array3DPy(new Material3DArray());
return new Array3DPy(new Array3D());
}
// constructor method
@@ -64,7 +64,7 @@ int Array3DPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
Py::List Array3DPy::getArray() const
{
Py::List list;
auto array = getMaterial3DArrayPtr()->getArray();
auto array = getArray3DPtr()->getArray();
for (auto& depth : array) {
Py::List depthList;
@@ -83,24 +83,39 @@ Py::List Array3DPy::getArray() const
return list;
}
Py::Long Array3DPy::getDimensions() const
{
return Py::Long(3);
}
Py::Long Array3DPy::getColumns() const
{
return Py::Long(getMaterial3DArrayPtr()->columns());
return Py::Long(getArray3DPtr()->columns());
}
void Array3DPy::setColumns(Py::Long arg)
{
getArray3DPtr()->setColumns(arg);
}
Py::Long Array3DPy::getDepth() const
{
return Py::Long(getMaterial3DArrayPtr()->depth());
return Py::Long(getArray3DPtr()->depth());
}
void Array3DPy::setDepth(Py::Long arg)
{
getArray3DPtr()->setDepth(arg);
}
PyObject* Array3DPy::getRows(PyObject* args)
{
int depth = getMaterial3DArrayPtr()->currentDepth();
int depth = getArray3DPtr()->currentDepth();
if (!PyArg_ParseTuple(args, "|i", &depth)) {
return nullptr;
}
return PyLong_FromLong(getMaterial3DArrayPtr()->rows(depth));
return PyLong_FromLong(getArray3DPtr()->rows(depth));
}
PyObject* Array3DPy::getValue(PyObject* args)
@@ -113,7 +128,7 @@ PyObject* Array3DPy::getValue(PyObject* args)
}
try {
auto value = getMaterial3DArrayPtr()->getValue(depth, row, column);
auto value = getArray3DPtr()->getValue(depth, row, column);
return new Base::QuantityPy(new Base::Quantity(value));
}
catch (const InvalidIndex&) {
@@ -131,7 +146,7 @@ PyObject* Array3DPy::getDepthValue(PyObject* args)
}
try {
auto value = getMaterial3DArrayPtr()->getDepthValue(depth);
auto value = getArray3DPtr()->getDepthValue(depth);
return new Base::QuantityPy(new Base::Quantity(value));
}
catch (const InvalidIndex&) {
@@ -141,6 +156,60 @@ PyObject* Array3DPy::getDepthValue(PyObject* args)
return nullptr;
}
PyObject* Array3DPy::setDepthValue(PyObject* args)
{
int depth;
PyObject* valueObj;
if (PyArg_ParseTuple(args, "iO!", &depth, &PyUnicode_Type, &valueObj)) {
Py::String item(valueObj);
try {
getArray3DPtr()->setDepthValue(depth, Base::Quantity::parse(item.as_string()));
}
catch (const InvalidIndex&) {
PyErr_SetString(PyExc_IndexError, "Invalid array index");
return nullptr;
}
Py_Return;
}
PyErr_SetString(PyExc_TypeError, "Expected (integer, string) arguments");
return nullptr;
}
PyObject* Array3DPy::setValue(PyObject* args)
{
int depth;
int row;
int column;
PyObject* valueObj;
if (PyArg_ParseTuple(args, "iiiO!", &depth, &row, &column, &PyUnicode_Type, &valueObj)) {
Py::String item(valueObj);
try {
getArray3DPtr()->setValue(depth, row, column, Base::Quantity::parse(item.as_string()));
}
catch (const InvalidIndex&) {
PyErr_SetString(PyExc_IndexError, "Invalid array index");
return nullptr;
}
Py_Return;
}
PyErr_SetString(PyExc_TypeError, "Expected (integer, integer, integer, string) arguments");
return nullptr;
}
PyObject* Array3DPy::setRows(PyObject* args)
{
int depth;
int rows;
if (!PyArg_ParseTuple(args, "ii", &depth, &rows)) {
return nullptr;
}
getArray3DPtr()->setRows(depth, rows);
Py_Return;
}
PyObject* Array3DPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;

View File

@@ -45,10 +45,13 @@ endif()
generate_from_xml(Array2DPy)
generate_from_xml(Array3DPy)
generate_from_xml(MaterialFilterPy)
generate_from_xml(MaterialFilterOptionsPy)
generate_from_xml(MaterialLibraryPy)
generate_from_xml(MaterialManagerPy)
generate_from_xml(MaterialPy)
generate_from_xml(ModelManagerPy)
generate_from_xml(ModelPropertyPy)
generate_from_xml(MaterialPropertyPy)
generate_from_xml(ModelPy)
generate_from_xml(UUIDsPy)
@@ -58,12 +61,18 @@ SET(Python_SRCS
Array2DPyImp.cpp
Array3DPy.xml
Array3DPyImp.cpp
MaterialManagerPy.xml
MaterialManagerPyImp.cpp
MaterialPy.xml
MaterialPyImp.cpp
MaterialFilterOptionsPy.xml
MaterialFilterOptionsPyImp.cpp
MaterialFilterPy.xml
MaterialFilterPyImp.cpp
MaterialLibraryPy.xml
MaterialLibraryPyImp.cpp
MaterialManagerPy.xml
MaterialManagerPyImp.cpp
MaterialPropertyPy.xml
MaterialPropertyPyImp.cpp
MaterialPy.xml
MaterialPyImp.cpp
ModelManagerPy.xml
ModelManagerPyImp.cpp
ModelPropertyPy.xml
@@ -79,6 +88,8 @@ SET(Materials_SRCS
${Python_SRCS}
AppMaterial.cpp
FolderTree.h
Library.cpp
Library.h
MaterialConfigLoader.cpp
MaterialConfigLoader.h
MaterialFilter.cpp
@@ -89,6 +100,8 @@ SET(Materials_SRCS
MaterialLoader.h
MaterialManager.cpp
MaterialManager.h
MaterialManagerLocal.cpp
MaterialManagerLocal.h
Materials.cpp
Materials.h
MaterialValue.cpp
@@ -101,12 +114,16 @@ SET(Materials_SRCS
ModelLoader.h
ModelManager.cpp
ModelManager.h
ModelManagerLocal.cpp
ModelManagerLocal.h
ModelUuids.cpp
ModelUuids.h
PreCompiled.cpp
PreCompiled.h
PropertyMaterial.cpp
PropertyMaterial.h
PyVariants.cpp
PyVariants.h
trim.h
)

View File

@@ -34,15 +34,14 @@ class Uninitialized: public Base::Exception
{
public:
Uninitialized()
: Base::Exception("Uninitalized")
{}
explicit Uninitialized(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit Uninitialized(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~Uninitialized() noexcept override = default;
};
@@ -50,17 +49,14 @@ class ModelNotFound: public Base::Exception
{
public:
ModelNotFound()
{
this->setMessage("Model not found");
}
: Base::Exception("Model not found")
{}
explicit ModelNotFound(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit ModelNotFound(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~ModelNotFound() noexcept override = default;
};
@@ -68,15 +64,14 @@ class InvalidMaterialType: public Base::Exception
{
public:
InvalidMaterialType()
: Base::Exception("Invalid material type")
{}
explicit InvalidMaterialType(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit InvalidMaterialType(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~InvalidMaterialType() noexcept override = default;
};
@@ -84,17 +79,14 @@ class MaterialNotFound: public Base::Exception
{
public:
MaterialNotFound()
{
this->setMessage("Material not found");
}
: Base::Exception("Material not found")
{}
explicit MaterialNotFound(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit MaterialNotFound(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~MaterialNotFound() noexcept override = default;
};
@@ -102,15 +94,14 @@ class MaterialExists: public Base::Exception
{
public:
MaterialExists()
: Base::Exception("Material already exists")
{}
explicit MaterialExists(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit MaterialExists(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~MaterialExists() noexcept override = default;
};
@@ -118,15 +109,14 @@ class MaterialReadError: public Base::Exception
{
public:
MaterialReadError()
: Base::Exception("Unable to read material")
{}
explicit MaterialReadError(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit MaterialReadError(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~MaterialReadError() noexcept override = default;
};
@@ -134,17 +124,14 @@ class PropertyNotFound: public Base::Exception
{
public:
PropertyNotFound()
{
this->setMessage("Property not found");
}
: Base::Exception("Property not found")
{}
explicit PropertyNotFound(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit PropertyNotFound(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~PropertyNotFound() noexcept override = default;
};
@@ -152,53 +139,104 @@ class LibraryNotFound: public Base::Exception
{
public:
LibraryNotFound()
{
this->setMessage("Library not found");
}
: Base::Exception("Library not found")
{}
explicit LibraryNotFound(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit LibraryNotFound(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~LibraryNotFound() noexcept override = default;
};
class CreationError: public Base::Exception
{
public:
CreationError()
: Base::Exception("Unable to create object")
{}
explicit CreationError(const char* msg)
: Base::Exception(msg)
{}
explicit CreationError(const QString& msg)
: Base::Exception(msg.toStdString().c_str())
{}
~CreationError() noexcept override = default;
};
class InvalidModel: public Base::Exception
{
public:
InvalidModel()
{
this->setMessage("Invalid model");
}
: Base::Exception("Invalid model")
{}
explicit InvalidModel(const char* msg)
{
this->setMessage(msg);
}
: Base::Exception(msg)
{}
explicit InvalidModel(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~InvalidModel() noexcept override = default;
};
class InvalidMaterial: public Base::Exception
{
public:
InvalidMaterial()
: Base::Exception("Invalid material")
{}
explicit InvalidMaterial(const char* msg)
: Base::Exception(msg)
{}
explicit InvalidMaterial(const QString& msg)
: Base::Exception(msg.toStdString().c_str())
{}
~InvalidMaterial() noexcept override = default;
};
class InvalidProperty: public Base::Exception
{
public:
InvalidProperty()
: Base::Exception("Invalid property")
{}
explicit InvalidProperty(const char* msg)
: Base::Exception(msg)
{}
explicit InvalidProperty(const QString& msg)
: Base::Exception(msg.toStdString().c_str())
{}
~InvalidProperty() noexcept override = default;
};
class InvalidLibrary: public Base::Exception
{
public:
InvalidLibrary()
: Base::Exception("Invalid library")
{}
explicit InvalidLibrary(const char* msg)
: Base::Exception(msg)
{}
explicit InvalidLibrary(const QString& msg)
: Base::Exception(msg.toStdString().c_str())
{}
~InvalidLibrary() noexcept override = default;
};
class InvalidIndex: public Base::Exception
{
public:
InvalidIndex()
{
this->setMessage("Invalid index");
}
explicit InvalidIndex(char* msg)
{
this->setMessage(msg);
}
: Base::Exception("Invalid index")
{}
explicit InvalidIndex(const char* msg)
: Base::Exception(msg)
{}
explicit InvalidIndex(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~InvalidIndex() noexcept override = default;
};
@@ -206,15 +244,14 @@ class UnknownValueType: public Base::Exception
{
public:
UnknownValueType()
: Base::Exception("Unkown value type")
{}
explicit UnknownValueType(const char* msg)
: Base::Exception(msg)
{}
explicit UnknownValueType(char* msg)
{
this->setMessage(msg);
}
explicit UnknownValueType(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~UnknownValueType() noexcept override = default;
};
@@ -222,18 +259,62 @@ class DeleteError: public Base::Exception
{
public:
DeleteError()
: Base::Exception("Unable to delete object")
{}
explicit DeleteError(const char* msg)
: Base::Exception(msg)
{}
explicit DeleteError(char* msg)
{
this->setMessage(msg);
}
explicit DeleteError(const QString& msg)
{
this->setMessage(msg.toStdString().c_str());
}
: Base::Exception(msg.toStdString().c_str())
{}
~DeleteError() noexcept override = default;
};
class RenameError: public Base::Exception
{
public:
RenameError()
: Base::Exception("Unable to rename object")
{}
explicit RenameError(const char* msg)
: Base::Exception(msg)
{}
explicit RenameError(const QString& msg)
: Base::Exception(msg.toStdString().c_str())
{}
~RenameError() noexcept override = default;
};
class ReplacementError: public Base::Exception
{
public:
ReplacementError()
: Base::Exception("Unable to replace object")
{}
explicit ReplacementError(const char* msg)
: Base::Exception(msg)
{}
explicit ReplacementError(const QString& msg)
: Base::Exception(msg.toStdString().c_str())
{}
~ReplacementError() noexcept override = default;
};
class ConnectionError: public Base::Exception
{
public:
ConnectionError()
: Base::Exception("Unable to connect")
{}
explicit ConnectionError(const char* msg)
: Base::Exception(msg)
{}
explicit ConnectionError(const QString& msg)
: Base::Exception(msg.toStdString().c_str())
{}
~ConnectionError() noexcept override = default;
};
} // namespace Materials
#endif // MATERIAL_EXCEPTIONS_H

View File

@@ -34,18 +34,21 @@ template<class T>
class FolderTreeNode
{
public:
enum NodeType
enum class NodeType
{
UnknownNode,
DataNode,
FolderNode
};
FolderTreeNode()
: _type(NodeType::UnknownNode)
{}
virtual ~FolderTreeNode() = default;
NodeType getType() const
{
// assert(_type == NodeType::DataNode || _type == NodeType::FolderNode);
return _type;
}
void setType(NodeType type)
@@ -53,33 +56,47 @@ public:
_type = type;
}
const std::shared_ptr<std::map<QString, std::shared_ptr<FolderTreeNode<T>>>> getFolder() const
std::shared_ptr<std::map<QString, std::shared_ptr<FolderTreeNode<T>>>> getFolder() const
{
assert(_type == NodeType::FolderNode);
return _folder;
}
std::shared_ptr<std::map<QString, std::shared_ptr<FolderTreeNode<T>>>> getFolder()
{
assert(_type == NodeType::FolderNode);
return _folder;
}
std::shared_ptr<T> getData() const
{
assert(_type == NodeType::DataNode);
return _data;
}
QString getUUID() const
{
assert(_type == NodeType::DataNode);
return _uuid;
}
void setFolder(std::shared_ptr<std::map<QString, std::shared_ptr<FolderTreeNode<T>>>> folder)
{
setType(FolderNode);
setType(NodeType::FolderNode);
_folder = folder;
}
void setData(std::shared_ptr<T> data)
{
setType(DataNode);
setType(NodeType::DataNode);
_data = data;
}
void setUUID(const QString& uuid)
{
setType(NodeType::DataNode);
_uuid = uuid;
}
private:
NodeType _type;
std::shared_ptr<std::map<QString, std::shared_ptr<FolderTreeNode<T>>>> _folder;
QString _uuid;
std::shared_ptr<T> _data;
};

View File

@@ -0,0 +1,141 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <string>
#endif
#include <App/Application.h>
#include "Exceptions.h"
#include "Library.h"
using namespace Materials;
TYPESYSTEM_SOURCE(Materials::Library, Base::BaseClass)
Library::Library(const QString& libraryName, const QString& icon, bool readOnly)
: _name(libraryName)
, _iconPath(icon)
, _readOnly(readOnly)
{}
Library::Library(const QString& libraryName, const QString& dir, const QString& icon, bool readOnly)
: _name(libraryName)
, _directory(QDir::cleanPath(dir))
, _iconPath(icon)
, _readOnly(readOnly)
{}
bool Library::operator==(const Library& library) const
{
return (getName() == library.getName()) && (_directory == library._directory);
}
void Library::validate(const Library& remote) const
{
if (getName() != remote.getName()) {
throw InvalidLibrary("Library names don't match");
}
if (getIconPath() != remote.getIconPath()) {
Base::Console().Log("Icon path 1 '%s'\n", getIconPath().toStdString().c_str());
Base::Console().Log("Icon path 2 '%s'\n", remote.getIconPath().toStdString().c_str());
throw InvalidLibrary("Library icon paths don't match");
}
// Local and remote paths will differ
if (!remote.getDirectory().isEmpty()) {
throw InvalidLibrary("Remote library should not have a path");
}
if (isReadOnly() != remote.isReadOnly()) {
throw InvalidLibrary("Library readonly settings don't match");
}
}
QString Library::getLocalPath(const QString& path) const
{
QString filePath = getDirectoryPath();
if (!(filePath.endsWith(QStringLiteral("/")) || filePath.endsWith(QStringLiteral("\\")))) {
filePath += QStringLiteral("/");
}
QString cleanPath = QDir::cleanPath(path);
QString prefix = QStringLiteral("/") + getName();
if (cleanPath.startsWith(prefix)) {
// Remove the library name from the path
filePath += cleanPath.right(cleanPath.length() - prefix.length());
}
else {
filePath += cleanPath;
}
return filePath;
}
bool Library::isRoot(const QString& path) const
{
QString localPath = getLocalPath(path);
QString cleanPath = getLocalPath(QStringLiteral(""));
return (cleanPath == localPath);
}
QString Library::getRelativePath(const QString& path) const
{
QString filePath;
QString cleanPath = QDir::cleanPath(path);
QString prefix = QStringLiteral("/") + 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(QStringLiteral("/"))) {
filePath.remove(0, 1);
}
return filePath;
}
QString Library::getLibraryPath(const QString& path, const QString& filename) const
{
QString filePath(path);
if (filePath.endsWith(filename)) {
filePath = filePath.left(filePath.length() - filename.length());
}
if (filePath.endsWith(QStringLiteral("/"))) {
filePath = filePath.left(filePath.length() - 1);
}
return filePath;
}

View File

@@ -0,0 +1,114 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef MATERIAL_LIBRARY_H
#define MATERIAL_LIBRARY_H
#include <QDir>
#include <QString>
#include <Base/BaseClass.h>
#include <Mod/Material/MaterialGlobal.h>
namespace Materials
{
class MaterialsExport Library: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
Library() = default;
Library(const QString& libraryName, const QString& icon, bool readOnly = true);
Library(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
~Library() override = default;
QString getName() const
{
return _name;
}
void setName(const QString& newName)
{
_name = newName;
}
bool sameName(const QString& name)
{
return (_name == name);
}
QString getIconPath() const
{
return _iconPath;
}
void setIconPath(const QString& icon)
{
_iconPath = icon;
}
bool isReadOnly() const
{
return _readOnly;
}
void setReadOnly(bool readOnly)
{
_readOnly = readOnly;
}
QString getDirectory() const
{
return _directory;
}
void setDirectory(const QString& directory)
{
_directory = directory;
}
QString getDirectoryPath() const
{
return QDir(_directory).absolutePath();
}
bool operator==(const Library& library) const;
bool operator!=(const Library& library) const
{
return !operator==(library);
}
QString getLocalPath(const QString& path) const;
QString getRelativePath(const QString& path) const;
QString getLibraryPath(const QString& path, const QString& filename) const;
bool isRoot(const QString& path) const;
// Validate a remote library against this one (a local library)
void validate(const Library& remote) const;
private:
QString _name;
QString _directory;
QString _iconPath;
bool _readOnly;
};
} // namespace Materials
#endif // MATERIAL_LIBRARY_H

View File

@@ -1022,7 +1022,7 @@ void MaterialConfigLoader::addLegacy(const QMap<QString, QString>& fcmat,
{
for (auto const& legacy : fcmat.keys()) {
auto name = legacy;
int last = name.lastIndexOf(QLatin1String("/"));
int last = name.lastIndexOf(QStringLiteral("/"));
if (last > 0) {
name = name.mid(last + 1);
}
@@ -1034,7 +1034,7 @@ void MaterialConfigLoader::addLegacy(const QMap<QString, QString>& fcmat,
}
std::shared_ptr<Material>
MaterialConfigLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibrary>& library,
MaterialConfigLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& path)
{
QString author = getAuthorAndLicense(path); // Place them both in the author field
@@ -1056,7 +1056,10 @@ MaterialConfigLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibrary>
QString sourceReference = value(fcmat, "ReferenceSource", "");
QString sourceURL = value(fcmat, "SourceURL", "");
std::shared_ptr<Material> finalModel = std::make_shared<Material>(library, path, uuid, name);
auto baseLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibrary>&>(library);
std::shared_ptr<Material> finalModel =
std::make_shared<Material>(baseLibrary, path, uuid, name);
finalModel->setOldFormat(true);
finalModel->setAuthor(author);

View File

@@ -36,6 +36,8 @@
namespace Materials
{
class MaterialLibraryLocal;
class MaterialConfigLoader
{
public:
@@ -45,7 +47,7 @@ public:
static bool isConfigStyle(const QString& path);
static std::shared_ptr<Material>
getMaterialFromPath(const std::shared_ptr<MaterialLibrary>& library, const QString& path);
getMaterialFromPath(const std::shared_ptr<MaterialLibraryLocal>& library, const QString& path);
private:
static QString value(const QMap<QString, QString>& fcmat,

View File

@@ -33,6 +33,8 @@
using namespace Materials;
TYPESYSTEM_SOURCE(Materials::MaterialFilterOptions, Base::BaseClass)
MaterialFilterOptions::MaterialFilterOptions()
{
auto param = App::GetApplication().GetParameterGroupByPath(
@@ -94,9 +96,8 @@ bool MaterialFilter::modelIncluded(const std::shared_ptr<Material>& material) co
bool MaterialFilter::modelIncluded(const QString& uuid) const
{
MaterialManager manager;
try {
auto material = manager.getMaterial(uuid);
auto material = MaterialManager::getManager().getMaterial(uuid);
return modelIncluded(material);
}
catch (const MaterialNotFound&) {

View File

@@ -41,8 +41,9 @@ class Material;
* This class is used to set options for a material tree search
*
*/
class MaterialsExport MaterialFilterOptions
class MaterialsExport MaterialFilterOptions: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
MaterialFilterOptions();

View File

@@ -0,0 +1,49 @@
<?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="MaterialFilterOptionsPy"
Twin="MaterialFilterOptions"
TwinPointer="MaterialFilterOptions"
Include="Mod/Material/App/MaterialFilter.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 filtering options.</UserDocu>
</Documentation>
<Attribute Name="IncludeFavorites" ReadOnly="false">
<Documentation>
<UserDocu>Include materials marked as favorite.</UserDocu>
</Documentation>
<Parameter Name="IncludeFavorites" Type="Boolean"/>
</Attribute>
<Attribute Name="IncludeRecent" ReadOnly="false">
<Documentation>
<UserDocu>Include recently used materials.</UserDocu>
</Documentation>
<Parameter Name="IncludeRecent" Type="Boolean"/>
</Attribute>
<Attribute Name="IncludeEmptyFolders" ReadOnly="false">
<Documentation>
<UserDocu>Include empty folders.</UserDocu>
</Documentation>
<Parameter Name="IncludeEmptyFolders" Type="Boolean"/>
</Attribute>
<Attribute Name="IncludeEmptyLibraries" ReadOnly="false">
<Documentation>
<UserDocu>Include empty libraries.</UserDocu>
</Documentation>
<Parameter Name="IncludeEmptyLibraries" Type="Boolean"/>
</Attribute>
<Attribute Name="IncludeLegacy" ReadOnly="false">
<Documentation>
<UserDocu>Include materials using the older legacy format.</UserDocu>
</Documentation>
<Parameter Name="IncludeLegacy" Type="Boolean"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,122 @@
/***************************************************************************
* Copyright (c) 2023-2024 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#include <QMetaType>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
#include <CXX/Objects.hxx>
#include <Gui/MetaTypes.h>
#include "MaterialFilter.h"
#include "MaterialFilterOptionsPy.h"
#include "MaterialFilterOptionsPy.cpp"
using namespace Materials;
// Forward declaration
// static PyObject* _pyObjectFromVariant(const QVariant& value);
// static Py::List getList(const QVariant& value);
// returns a string which represents the object e.g. when printed in python
std::string MaterialFilterOptionsPy::representation() const
{
std::stringstream str;
str << "<MaterialFilterOptions object at " << getMaterialFilterOptionsPtr() << ">";
return str.str();
}
PyObject* MaterialFilterOptionsPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
{
// never create such objects with the constructor
return new MaterialFilterOptionsPy(new MaterialFilterOptions());
}
// constructor method
int MaterialFilterOptionsPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::Boolean MaterialFilterOptionsPy::getIncludeFavorites() const
{
return getMaterialFilterOptionsPtr()->includeFavorites();
}
void MaterialFilterOptionsPy::setIncludeFavorites(const Py::Boolean value)
{
getMaterialFilterOptionsPtr()->setIncludeFavorites(value);
}
Py::Boolean MaterialFilterOptionsPy::getIncludeRecent() const
{
return getMaterialFilterOptionsPtr()->includeRecent();
}
void MaterialFilterOptionsPy::setIncludeRecent(const Py::Boolean value)
{
getMaterialFilterOptionsPtr()->setIncludeRecent(value);
}
Py::Boolean MaterialFilterOptionsPy::getIncludeEmptyFolders() const
{
return getMaterialFilterOptionsPtr()->includeEmptyFolders();
}
void MaterialFilterOptionsPy::setIncludeEmptyFolders(const Py::Boolean value)
{
getMaterialFilterOptionsPtr()->setIncludeEmptyFolders(value);
}
Py::Boolean MaterialFilterOptionsPy::getIncludeEmptyLibraries() const
{
return getMaterialFilterOptionsPtr()->includeEmptyLibraries();
}
void MaterialFilterOptionsPy::setIncludeEmptyLibraries(const Py::Boolean value)
{
getMaterialFilterOptionsPtr()->setIncludeEmptyLibraries(value);
}
Py::Boolean MaterialFilterOptionsPy::getIncludeLegacy() const
{
return getMaterialFilterOptionsPtr()->includeLegacy();
}
void MaterialFilterOptionsPy::setIncludeLegacy(const Py::Boolean value)
{
getMaterialFilterOptionsPtr()->setIncludeLegacy(value);
}
PyObject* MaterialFilterOptionsPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int MaterialFilterOptionsPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -41,18 +41,121 @@ using namespace Materials;
/* TRANSLATOR Material::Materials */
TYPESYSTEM_SOURCE(Materials::MaterialLibrary, Materials::LibraryBase)
TYPESYSTEM_SOURCE(Materials::MaterialLibrary, Base::BaseClass)
MaterialLibrary::MaterialLibrary(const QString& libraryName, const QString& icon, bool readOnly)
: Library(libraryName, icon, readOnly)
, _local(false)
{}
MaterialLibrary::MaterialLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly)
: LibraryBase(libraryName, dir, icon)
, _readOnly(readOnly)
, _materialPathMap(std::make_unique<std::map<QString, std::shared_ptr<Material>>>())
: Library(libraryName, dir, icon, readOnly)
, _local(false)
{}
void MaterialLibrary::createFolder(const QString& path)
bool MaterialLibrary::isLocal() const
{
return _local;
}
void MaterialLibrary::setLocal(bool local)
{
_local = local;
}
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
MaterialLibrary::getMaterialTree(const std::shared_ptr<Materials::MaterialFilter>& filter,
const Materials::MaterialFilterOptions& options) const
{
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>> materialTree =
std::make_shared<std::map<QString, std::shared_ptr<MaterialTreeNode>>>();
auto materials = MaterialManager::getManager().libraryMaterials(getName(), filter, options);
for (auto& it : *materials) {
auto uuid = std::get<0>(it);
auto path = std::get<1>(it);
auto filename = std::get<2>(it);
QStringList list = path.split(QStringLiteral("/"));
// Start at the root
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>> node =
materialTree;
for (auto& itp : list) {
if (!itp.isEmpty()) {
// Add the folder only if it's not already there
if (node->count(itp) == 0) {
auto mapPtr = std::make_shared<
std::map<QString, std::shared_ptr<MaterialTreeNode>>>();
std::shared_ptr<MaterialTreeNode> child =
std::make_shared<MaterialTreeNode>();
child->setFolder(mapPtr);
(*node)[itp] = child;
node = mapPtr;
}
else {
node = (*node)[itp]->getFolder();
}
}
}
std::shared_ptr<MaterialTreeNode> child = std::make_shared<MaterialTreeNode>();
child->setUUID(uuid);
(*node)[filename] = child;
}
// // Empty folders aren't included in _materialPathMap, so we add them by looking at the file
// // system
// if (!filter || options.includeEmptyFolders()) {
// if (isLocal()) {
// auto& materialLibrary =
// *(reinterpret_cast<const Materials::MaterialLibraryLocal*>(this));
// auto folderList = MaterialLoader::getMaterialFolders(materialLibrary);
// for (auto& folder : *folderList) {
// QStringList list = folder.split(QStringLiteral("/"));
// // Start at the root
// auto node = materialTree;
// for (auto& itp : list) {
// // Add the folder only if it's not already there
// if (node->count(itp) == 0) {
// std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
// mapPtr = std::make_shared<
// std::map<QString, std::shared_ptr<MaterialTreeNode>>>();
// std::shared_ptr<MaterialTreeNode> child =
// std::make_shared<MaterialTreeNode>();
// child->setFolder(mapPtr);
// (*node)[itp] = child;
// node = mapPtr;
// }
// else {
// node = (*node)[itp]->getFolder();
// }
// }
// }
// }
// }
return materialTree;
}
/* TRANSLATOR Material::Materials */
TYPESYSTEM_SOURCE(Materials::MaterialLibraryLocal, Materials::MaterialLibrary)
MaterialLibraryLocal::MaterialLibraryLocal(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly)
: MaterialLibrary(libraryName, dir, icon, readOnly)
, _materialPathMap(std::make_unique<std::map<QString, std::shared_ptr<Material>>>())
{
setLocal(true);
}
void MaterialLibraryLocal::createFolder(const QString& path)
{
QString filePath = getLocalPath(path);
@@ -65,8 +168,42 @@ void MaterialLibrary::createFolder(const QString& path)
}
}
void MaterialLibraryLocal::renameFolder(const QString& oldPath, const QString& newPath)
{
QString filePath = getLocalPath(oldPath);
QString newFilePath = getLocalPath(newPath);
QDir fileDir(filePath);
if (fileDir.exists()) {
if (!fileDir.rename(filePath, newFilePath)) {
Base::Console().Error("Unable to rename directory path '%s'\n",
filePath.toStdString().c_str());
}
}
updatePaths(oldPath, newPath);
}
void MaterialLibraryLocal::deleteRecursive(const QString& path)
{
if (isRoot(path)) {
return;
}
QString filePath = getLocalPath(path);
auto manager = MaterialManager::getManager();
QFileInfo info(filePath);
if (info.isDir()) {
deleteDir(manager, filePath);
}
else {
deleteFile(manager, filePath);
}
}
// This accepts the filesystem path as returned from getLocalPath
void MaterialLibrary::deleteDir(MaterialManager& manager, const QString& path)
void MaterialLibraryLocal::deleteDir(MaterialManager& manager, const QString& path)
{
// Remove the children first
QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
@@ -105,7 +242,7 @@ void MaterialLibrary::deleteDir(MaterialManager& manager, const QString& path)
}
// This accepts the filesystem path as returned from getLocalPath
void MaterialLibrary::deleteFile(MaterialManager& manager, const QString& path)
void MaterialLibraryLocal::deleteFile(MaterialManager& manager, const QString& path)
{
if (QFile::remove(path)) {
// Remove from the map
@@ -125,25 +262,7 @@ void MaterialLibrary::deleteFile(MaterialManager& manager, const QString& path)
}
}
void MaterialLibrary::deleteRecursive(const QString& path)
{
if (isRoot(path)) {
return;
}
QString filePath = getLocalPath(path);
MaterialManager manager;
QFileInfo info(filePath);
if (info.isDir()) {
deleteDir(manager, filePath);
}
else {
deleteFile(manager, filePath);
}
}
void MaterialLibrary::updatePaths(const QString& oldPath, const QString& newPath)
void MaterialLibraryLocal::updatePaths(const QString& oldPath, const QString& newPath)
{
// Update the path map
QString op = getRelativePath(oldPath);
@@ -162,27 +281,12 @@ void MaterialLibrary::updatePaths(const QString& oldPath, const QString& newPath
_materialPathMap = std::move(pathMap);
}
void MaterialLibrary::renameFolder(const QString& oldPath, const QString& newPath)
{
QString filePath = getLocalPath(oldPath);
QString newFilePath = getLocalPath(newPath);
QDir fileDir(filePath);
if (fileDir.exists()) {
if (!fileDir.rename(filePath, newFilePath)) {
Base::Console().Error("Unable to rename directory path '%s'\n",
filePath.toStdString().c_str());
}
}
updatePaths(oldPath, newPath);
}
std::shared_ptr<Material> MaterialLibrary::saveMaterial(const std::shared_ptr<Material>& material,
const QString& path,
bool overwrite,
bool saveAsCopy,
bool saveInherited)
std::shared_ptr<Material>
MaterialLibraryLocal::saveMaterial(const std::shared_ptr<Material>& material,
const QString& path,
bool overwrite,
bool saveAsCopy,
bool saveInherited)
{
QString filePath = getLocalPath(path);
QFile file(filePath);
@@ -220,7 +324,7 @@ std::shared_ptr<Material> MaterialLibrary::saveMaterial(const std::shared_ptr<Ma
return addMaterial(material, path);
}
bool MaterialLibrary::fileExists(const QString& path) const
bool MaterialLibraryLocal::fileExists(const QString& path) const
{
QString filePath = getLocalPath(path);
QFileInfo info(filePath);
@@ -228,137 +332,41 @@ bool MaterialLibrary::fileExists(const QString& path) const
return info.exists();
}
std::shared_ptr<Material> MaterialLibrary::addMaterial(const std::shared_ptr<Material>& material,
const QString& path)
std::shared_ptr<Material>
MaterialLibraryLocal::addMaterial(const std::shared_ptr<Material>& material, const QString& path)
{
QString filePath = getRelativePath(path);
QFileInfo info(filePath);
std::shared_ptr<Material> newMaterial = std::make_shared<Material>(*material);
newMaterial->setLibrary(getptr());
newMaterial->setDirectory(filePath);
newMaterial->setDirectory(getLibraryPath(filePath, info.fileName()));
newMaterial->setFilename(info.fileName());
(*_materialPathMap)[filePath] = newMaterial;
return newMaterial;
}
std::shared_ptr<Material> MaterialLibrary::getMaterialByPath(const QString& path) const
std::shared_ptr<Material> MaterialLibraryLocal::getMaterialByPath(const QString& path) const
{
QString filePath = getRelativePath(path);
try {
auto material = _materialPathMap->at(filePath);
return material;
}
catch (std::out_of_range&) {
throw MaterialNotFound();
auto search = _materialPathMap->find(filePath);
if (search != _materialPathMap->end()) {
return search->second;
}
throw MaterialNotFound();
}
QString MaterialLibrary::getUUIDFromPath(const QString& path) const
QString MaterialLibraryLocal::getUUIDFromPath(const QString& path) const
{
QString filePath = getRelativePath(path);
try {
auto material = _materialPathMap->at(filePath);
return material->getUUID();
}
catch (std::out_of_range&) {
throw MaterialNotFound();
auto search = _materialPathMap->find(filePath);
if (search != _materialPathMap->end()) {
return search->second->getUUID();
}
throw MaterialNotFound();
}
bool MaterialLibrary::materialInTree(const std::shared_ptr<Material>& material,
const std::shared_ptr<Materials::MaterialFilter>& filter,
const Materials::MaterialFilterOptions& options) const
{
if (!filter) {
// If there's no filter we always include
return true;
}
// filter out old format files
if (material->isOldFormat() && !options.includeLegacy()) {
return false;
}
// filter based on models
return filter->modelIncluded(material);
}
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
MaterialLibrary::getMaterialTree(const std::shared_ptr<Materials::MaterialFilter>& filter,
const Materials::MaterialFilterOptions& options) const
{
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>> materialTree =
std::make_shared<std::map<QString, std::shared_ptr<MaterialTreeNode>>>();
for (auto& it : *_materialPathMap) {
auto filename = it.first;
auto material = it.second;
if (materialInTree(material, filter, options)) {
QStringList list = filename.split(QStringLiteral("/"));
// Start at the root
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>> node =
materialTree;
for (auto& itp : list) {
if (itp.endsWith(QStringLiteral(".FCMat"))) {
std::shared_ptr<MaterialTreeNode> child = std::make_shared<MaterialTreeNode>();
child->setData(material);
(*node)[itp] = child;
}
else {
// Add the folder only if it's not already there
if (node->count(itp) == 0) {
auto mapPtr = std::make_shared<
std::map<QString, std::shared_ptr<MaterialTreeNode>>>();
std::shared_ptr<MaterialTreeNode> child =
std::make_shared<MaterialTreeNode>();
child->setFolder(mapPtr);
(*node)[itp] = child;
node = mapPtr;
}
else {
node = (*node)[itp]->getFolder();
}
}
}
}
}
// Empty folders aren't included in _materialPathMap, so we add them by looking at the file
// system
if (!filter || options.includeEmptyFolders()) {
auto folderList = MaterialLoader::getMaterialFolders(*this);
for (auto& folder : *folderList) {
QStringList list = folder.split(QStringLiteral("/"));
// Start at the root
auto node = materialTree;
for (auto& itp : list) {
// Add the folder only if it's not already there
if (node->count(itp) == 0) {
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>> mapPtr =
std::make_shared<std::map<QString, std::shared_ptr<MaterialTreeNode>>>();
std::shared_ptr<MaterialTreeNode> child = std::make_shared<MaterialTreeNode>();
child->setFolder(mapPtr);
(*node)[itp] = child;
node = mapPtr;
}
else {
node = (*node)[itp]->getFolder();
}
}
}
}
return materialTree;
}
TYPESYSTEM_SOURCE(Materials::MaterialExternalLibrary, Materials::MaterialLibrary)
MaterialExternalLibrary::MaterialExternalLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly)
: MaterialLibrary(libraryName, dir, icon, readOnly)
{}

View File

@@ -31,6 +31,7 @@
#include <Base/BaseClass.h>
#include <Mod/Material/MaterialGlobal.h>
#include "Library.h"
#include "Materials.h"
#include "Model.h"
#include "ModelLibrary.h"
@@ -43,29 +44,50 @@ class MaterialManager;
class MaterialFilter;
class MaterialFilterOptions;
class MaterialsExport MaterialLibrary: public LibraryBase,
public std::enable_shared_from_this<MaterialLibrary>
class MaterialsExport MaterialLibrary
: public Library,
public std::enable_shared_from_this<MaterialLibrary>
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
MaterialLibrary() = default;
MaterialLibrary(const MaterialLibrary&) = delete;
MaterialLibrary(const QString& libraryName, const QString& icon, bool readOnly = true);
MaterialLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
MaterialLibrary(const MaterialLibrary&) = delete;
~MaterialLibrary() override = default;
bool operator==(const MaterialLibrary& library) const
bool isLocal() const;
void setLocal(bool local);
virtual std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
getMaterialTree(const std::shared_ptr<Materials::MaterialFilter>& filter,
const Materials::MaterialFilterOptions& options) const;
// Use this to get a shared_ptr for *this
std::shared_ptr<MaterialLibrary> getptr()
{
return LibraryBase::operator==(library);
return shared_from_this();
}
bool operator!=(const MaterialLibrary& library) const
{
return !operator==(library);
}
std::shared_ptr<Material> getMaterialByPath(const QString& path) const;
protected:
bool _local;
};
class MaterialsExport MaterialLibraryLocal: public MaterialLibrary
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
MaterialLibraryLocal() = default;
MaterialLibraryLocal(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
~MaterialLibraryLocal() override = default;
void createFolder(const QString& path);
void renameFolder(const QString& oldPath, const QString& newPath);
@@ -79,50 +101,39 @@ public:
bool fileExists(const QString& path) const;
std::shared_ptr<Material> addMaterial(const std::shared_ptr<Material>& material,
const QString& path);
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
getMaterialTree(const std::shared_ptr<Materials::MaterialFilter>& filter,
const Materials::MaterialFilterOptions& options) const;
std::shared_ptr<Material> getMaterialByPath(const QString& path) const;
bool isReadOnly() const
bool operator==(const MaterialLibrary& library) const
{
return _readOnly;
return library.isLocal() ? Library::operator==(library) : false;
}
bool operator!=(const MaterialLibrary& library) const
{
return !operator==(library);
}
// Use this to get a shared_ptr for *this
std::shared_ptr<MaterialLibrary> getptr()
bool operator==(const MaterialLibraryLocal& library) const
{
return shared_from_this();
return Library::operator==(library);
}
bool operator!=(const MaterialLibraryLocal& library) const
{
return !operator==(library);
}
protected:
void deleteDir(MaterialManager& manager, const QString& path);
void deleteFile(MaterialManager& manager, const QString& path);
void updatePaths(const QString& oldPath, const QString& newPath);
QString getUUIDFromPath(const QString& path) const;
bool materialInTree(const std::shared_ptr<Material>& material,
const std::shared_ptr<Materials::MaterialFilter>& filter,
const Materials::MaterialFilterOptions& options) const;
bool _readOnly;
std::unique_ptr<std::map<QString, std::shared_ptr<Material>>> _materialPathMap;
};
class MaterialsExport MaterialExternalLibrary: public MaterialLibrary
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
MaterialExternalLibrary() = default;
MaterialExternalLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
~MaterialExternalLibrary() override = default;
};
} // namespace Materials
Q_DECLARE_METATYPE(std::shared_ptr<Materials::MaterialLibrary>)
Q_DECLARE_METATYPE(std::shared_ptr<Materials::MaterialLibraryLocal>)
#endif // MATERIAL_MATERIALLIBRARY_H

View File

@@ -0,0 +1,49 @@
<?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="MaterialLibraryPy"
Twin="MaterialLibrary"
TwinPointer="MaterialLibrary"
Include="Mod/Material/App/MaterialLibrary.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 library.</UserDocu>
</Documentation>
<Attribute Name="Name" ReadOnly="false">
<Documentation>
<UserDocu>Name of the library</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Icon" ReadOnly="false">
<Documentation>
<UserDocu>String value of the icon.</UserDocu>
</Documentation>
<Parameter Name="Icon" Type="String"/>
</Attribute>
<Attribute Name="Directory" ReadOnly="false">
<Documentation>
<UserDocu>Local directory where the library is located. For non-local libraries this will be empty</UserDocu>
</Documentation>
<Parameter Name="Directory" Type="String"/>
</Attribute>
<Attribute Name="ReadOnly" ReadOnly="false">
<Documentation>
<UserDocu>True if the library is local.</UserDocu>
</Documentation>
<Parameter Name="ReadOnly" Type="Boolean"/>
</Attribute>
<Attribute Name="Local" ReadOnly="false">
<Documentation>
<UserDocu>True if the library is local.</UserDocu>
</Documentation>
<Parameter Name="Local" Type="Boolean"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,125 @@
/***************************************************************************
* Copyright (c) 2023-2024 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#include <QMetaType>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
#include <CXX/Objects.hxx>
#include <Gui/MetaTypes.h>
#include "MaterialLibrary.h"
#include "MaterialLibraryPy.h"
#include "MaterialLibraryPy.cpp"
using namespace Materials;
// Forward declaration
// static PyObject* _pyObjectFromVariant(const QVariant& value);
// static Py::List getList(const QVariant& value);
// returns a string which represents the object e.g. when printed in python
std::string MaterialLibraryPy::representation() const
{
std::stringstream str;
str << "<MaterialLibrary object at " << getMaterialLibraryPtr() << ">";
return str.str();
}
PyObject* MaterialLibraryPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
{
// never create such objects with the constructor
return new MaterialLibraryPy(new MaterialLibrary());
}
// constructor method
int MaterialLibraryPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::String MaterialLibraryPy::getName() const
{
auto filterName = getMaterialLibraryPtr()->getName();
return {filterName.toStdString()};
}
void MaterialLibraryPy::setName(const Py::String value)
{
getMaterialLibraryPtr()->setName(QString::fromStdString(value));
}
Py::String MaterialLibraryPy::getIcon() const
{
auto path = getMaterialLibraryPtr()->getIconPath();
return {path.toStdString()};
}
void MaterialLibraryPy::setIcon(const Py::String value)
{
getMaterialLibraryPtr()->setIconPath(QString::fromStdString(value));
}
Py::String MaterialLibraryPy::getDirectory() const
{
auto path = getMaterialLibraryPtr()->getDirectory();
return {path.toStdString()};
}
void MaterialLibraryPy::setDirectory(const Py::String value)
{
getMaterialLibraryPtr()->setDirectory(QString::fromStdString(value));
}
Py::Boolean MaterialLibraryPy::getReadOnly() const
{
return getMaterialLibraryPtr()->isReadOnly();
}
void MaterialLibraryPy::setReadOnly(Py::Boolean value)
{
getMaterialLibraryPtr()->setReadOnly(value);
}
Py::Boolean MaterialLibraryPy::getLocal() const
{
return getMaterialLibraryPtr()->isLocal();
}
void MaterialLibraryPy::setLocal(Py::Boolean value)
{
getMaterialLibraryPtr()->setLocal(value);
}
PyObject* MaterialLibraryPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int MaterialLibraryPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -45,7 +45,7 @@
using namespace Materials;
MaterialEntry::MaterialEntry(const std::shared_ptr<MaterialLibrary>& library,
MaterialEntry::MaterialEntry(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid)
@@ -55,7 +55,7 @@ MaterialEntry::MaterialEntry(const std::shared_ptr<MaterialLibrary>& library,
, _uuid(modelUuid)
{}
MaterialYamlEntry::MaterialYamlEntry(const std::shared_ptr<MaterialLibrary>& library,
MaterialYamlEntry::MaterialYamlEntry(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
@@ -98,9 +98,9 @@ std::shared_ptr<QList<QVariant>> MaterialYamlEntry::readImageList(const YAML::No
return readList(node, true);
}
std::shared_ptr<Material2DArray> MaterialYamlEntry::read2DArray(const YAML::Node& node, int columns)
std::shared_ptr<Array2D> MaterialYamlEntry::read2DArray(const YAML::Node& node, int columns)
{
auto array2d = std::make_shared<Material2DArray>();
auto array2d = std::make_shared<Array2D>();
array2d->setColumns(columns);
if (node.size() == 1 || node.size() == 2) {
@@ -126,9 +126,9 @@ std::shared_ptr<Material2DArray> MaterialYamlEntry::read2DArray(const YAML::Node
return array2d;
}
std::shared_ptr<Material3DArray> MaterialYamlEntry::read3DArray(const YAML::Node& node, int columns)
std::shared_ptr<Array3D> MaterialYamlEntry::read3DArray(const YAML::Node& node, int columns)
{
auto array3d = std::make_shared<Material3DArray>();
auto array3d = std::make_shared<Array3D>();
array3d->setColumns(columns - 1); // First column is third dimension
if (node.size() == 1 || node.size() == 2) {
@@ -347,16 +347,16 @@ MaterialLoader::MaterialLoader(
: _materialMap(materialMap)
, _libraryList(libraryList)
{
loadLibraries();
loadLibraries(libraryList);
}
void MaterialLoader::addLibrary(const std::shared_ptr<MaterialLibrary>& model)
void MaterialLoader::addLibrary(const std::shared_ptr<MaterialLibraryLocal>& model)
{
_libraryList->push_back(model);
}
std::shared_ptr<MaterialEntry>
MaterialLoader::getMaterialFromYAML(const std::shared_ptr<MaterialLibrary>& library,
MaterialLoader::getMaterialFromYAML(const std::shared_ptr<MaterialLibraryLocal>& library,
YAML::Node& yamlroot,
const QString& path)
{
@@ -387,18 +387,20 @@ MaterialLoader::getMaterialFromYAML(const std::shared_ptr<MaterialLibrary>& libr
}
std::shared_ptr<MaterialEntry>
MaterialLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibrary>& library,
MaterialLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& path) const
{
std::shared_ptr<MaterialEntry> model = nullptr;
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
// Used for debugging
std::string pathName = path.toStdString();
if (MaterialConfigLoader::isConfigStyle(path)) {
auto material = MaterialConfigLoader::getMaterialFromPath(library, path);
auto material = MaterialConfigLoader::getMaterialFromPath(materialLibrary, path);
if (material) {
(*_materialMap)[material->getUUID()] = library->addMaterial(material, path);
(*_materialMap)[material->getUUID()] = materialLibrary->addMaterial(material, path);
}
// Return the nullptr as there are no intermediate steps to take, such
@@ -417,7 +419,7 @@ MaterialLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibrary>& libr
try {
yamlroot = YAML::Load(fin);
model = getMaterialFromYAML(library, yamlroot, path);
model = getMaterialFromYAML(materialLibrary, yamlroot, path);
}
catch (YAML::Exception const& e) {
Base::Console().Error("YAML parsing error: '%s'\n", pathName.c_str());
@@ -511,7 +513,7 @@ void MaterialLoader::dereference(const std::shared_ptr<Material>& material)
dereference(_materialMap, material);
}
void MaterialLoader::loadLibrary(const std::shared_ptr<MaterialLibrary>& library)
void MaterialLoader::loadLibrary(const std::shared_ptr<MaterialLibraryLocal>& library)
{
if (_materialEntryMap == nullptr) {
_materialEntryMap = std::make_unique<std::map<QString, std::shared_ptr<MaterialEntry>>>();
@@ -541,12 +543,16 @@ void MaterialLoader::loadLibrary(const std::shared_ptr<MaterialLibrary>& library
}
}
void MaterialLoader::loadLibraries()
void MaterialLoader::loadLibraries(
const std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>& libraryList)
{
auto _libraryList = getMaterialLibraries();
if (_libraryList) {
for (auto& it : *_libraryList) {
loadLibrary(it);
if (libraryList) {
for (auto& it : *libraryList) {
if (it->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(it);
loadLibrary(materialLibrary);
}
}
}
@@ -555,92 +561,8 @@ void MaterialLoader::loadLibraries()
}
}
std::shared_ptr<std::list<std::shared_ptr<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 =
std::make_shared<MaterialLibrary>(QStringLiteral("System"),
resourceDir,
QStringLiteral(":/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 = std::make_shared<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()) {
// Try creating the user dir if it doesn't exist
if (!materialDir.mkpath(resourceDir)) {
Base::Console().Log("Unable to create user library '%s'\n",
resourceDir.toStdString().c_str());
}
}
if (materialDir.exists()) {
auto libData = std::make_shared<MaterialLibrary>(
QStringLiteral("User"),
resourceDir,
QStringLiteral(":/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 =
std::make_shared<MaterialLibrary>(QStringLiteral("Custom"),
resourceDir,
QStringLiteral(":/icons/user.svg"),
false);
_libraryList->push_back(libData);
}
}
}
return _libraryList;
}
std::shared_ptr<std::list<QString>>
MaterialLoader::getMaterialFolders(const MaterialLibrary& library)
MaterialLoader::getMaterialFolders(const MaterialLibraryLocal& library)
{
std::shared_ptr<std::list<QString>> pathList = std::make_shared<std::list<QString>>();
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);

View File

@@ -33,12 +33,14 @@
namespace Materials
{
class MaterialLibrary;
class MaterialLibraryLocal;
class MaterialEntry
{
public:
MaterialEntry() = default;
MaterialEntry(const std::shared_ptr<MaterialLibrary>& library,
MaterialEntry(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid);
@@ -47,7 +49,7 @@ public:
virtual void
addToTree(std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> materialMap) = 0;
std::shared_ptr<MaterialLibrary> getLibrary() const
std::shared_ptr<MaterialLibraryLocal> getLibrary() const
{
return _library;
}
@@ -65,7 +67,7 @@ public:
}
protected:
std::shared_ptr<MaterialLibrary> _library;
std::shared_ptr<MaterialLibraryLocal> _library;
QString _name;
QString _directory;
QString _uuid;
@@ -74,7 +76,7 @@ protected:
class MaterialYamlEntry: public MaterialEntry
{
public:
MaterialYamlEntry(const std::shared_ptr<MaterialLibrary>& library,
MaterialYamlEntry(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
@@ -101,8 +103,8 @@ private:
static std::shared_ptr<QList<QVariant>> readList(const YAML::Node& node,
bool isImageList = false);
static std::shared_ptr<QList<QVariant>> readImageList(const YAML::Node& node);
static std::shared_ptr<Material2DArray> read2DArray(const YAML::Node& node, int columns);
static std::shared_ptr<Material3DArray> read3DArray(const YAML::Node& node, int columns);
static std::shared_ptr<Array2D> read2DArray(const YAML::Node& node, int columns);
static std::shared_ptr<Array3D> read3DArray(const YAML::Node& node, int columns);
YAML::Node _model;
};
@@ -114,14 +116,14 @@ public:
const std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>& libraryList);
~MaterialLoader() = default;
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> getMaterialLibraries();
static std::shared_ptr<std::list<QString>> getMaterialFolders(const MaterialLibrary& library);
static std::shared_ptr<std::list<QString>>
getMaterialFolders(const MaterialLibraryLocal& library);
static void showYaml(const YAML::Node& yaml);
static void
dereference(const std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>& materialMap,
const std::shared_ptr<Material>& material);
static std::shared_ptr<MaterialEntry>
getMaterialFromYAML(const std::shared_ptr<MaterialLibrary>& library,
getMaterialFromYAML(const std::shared_ptr<MaterialLibraryLocal>& library,
YAML::Node& yamlroot,
const QString& path);
@@ -131,10 +133,11 @@ private:
void addToTree(std::shared_ptr<MaterialEntry> model);
void dereference(const std::shared_ptr<Material>& material);
std::shared_ptr<MaterialEntry>
getMaterialFromPath(const std::shared_ptr<MaterialLibrary>& library, const QString& path) const;
void addLibrary(const std::shared_ptr<MaterialLibrary>& model);
void loadLibrary(const std::shared_ptr<MaterialLibrary>& library);
void loadLibraries();
getMaterialFromPath(const std::shared_ptr<MaterialLibraryLocal>& library, const QString& path) const;
void addLibrary(const std::shared_ptr<MaterialLibraryLocal>& model);
void loadLibrary(const std::shared_ptr<MaterialLibraryLocal>& library);
void loadLibraries(
const std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>& libraryList);
static std::unique_ptr<std::map<QString, std::shared_ptr<MaterialEntry>>> _materialEntryMap;
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> _materialMap;

View File

@@ -24,8 +24,8 @@
#include <random>
#endif
#include <QMutex>
#include <QDirIterator>
#include <QMutex>
#include <QMutexLocker>
#include <App/Application.h>
@@ -35,6 +35,7 @@
#include "MaterialConfigLoader.h"
#include "MaterialLoader.h"
#include "MaterialManager.h"
#include "MaterialManagerLocal.h"
#include "ModelManager.h"
#include "ModelUuids.h"
@@ -45,100 +46,56 @@ using namespace Materials;
/* TRANSLATOR Material::Materials */
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> MaterialManager::_libraryList =
nullptr;
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> MaterialManager::_materialMap =
nullptr;
QMutex MaterialManager::_mutex;
TYPESYSTEM_SOURCE(Materials::MaterialManager, Base::BaseClass)
QMutex MaterialManager::_mutex;
MaterialManager* MaterialManager::_manager = nullptr;
std::unique_ptr<MaterialManagerLocal> MaterialManager::_localManager;
MaterialManager::MaterialManager()
{}
MaterialManager::~MaterialManager()
{}
MaterialManager& MaterialManager::getManager()
{
// TODO: Add a mutex or similar
initLibraries();
if (!_manager) {
initManagers();
}
return *_manager;
}
void MaterialManager::initLibraries()
void MaterialManager::initManagers()
{
QMutexLocker locker(&_mutex);
if (_materialMap == nullptr) {
// Load the models first
auto manager = std::make_unique<ModelManager>();
Q_UNUSED(manager)
_materialMap = std::make_shared<std::map<QString, std::shared_ptr<Material>>>();
if (_libraryList == nullptr) {
_libraryList = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>();
}
// Load the libraries
MaterialLoader loader(_materialMap, _libraryList);
if (!_manager) {
// Can't use smart pointers for this since the constructor is private
_manager = new MaterialManager();
}
if (!_localManager) {
_localManager = std::make_unique<MaterialManagerLocal>();
}
}
void MaterialManager::cleanup()
{
QMutexLocker locker(&_mutex);
if (_libraryList) {
_libraryList->clear();
_libraryList = nullptr;
}
if (_materialMap) {
for (auto& it : *_materialMap) {
// This is needed to resolve cyclic dependencies
it.second->setLibrary(nullptr);
}
_materialMap->clear();
_materialMap = nullptr;
if (_localManager) {
_localManager->cleanup();
}
}
void MaterialManager::refresh()
{
// This is very expensive and can be improved using observers?
cleanup();
initLibraries();
_localManager->refresh();
}
void MaterialManager::saveMaterial(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Material>& material,
const QString& path,
bool overwrite,
bool saveAsCopy,
bool saveInherited) const
{
auto newMaterial = library->saveMaterial(material, path, overwrite, saveAsCopy, saveInherited);
(*_materialMap)[newMaterial->getUUID()] = newMaterial;
}
bool MaterialManager::isMaterial(const fs::path& p) const
{
if (!fs::is_regular_file(p)) {
return false;
}
// check file extension
if (p.extension() == ".FCMat") {
return true;
}
return false;
}
bool MaterialManager::isMaterial(const QFileInfo& file) const
{
if (!file.isFile()) {
return false;
}
// check file extension
if (file.suffix() == QStringLiteral("FCMat")) {
return true;
}
return false;
}
//=====
//
// Defaults
//
//=====
std::shared_ptr<App::Material> MaterialManager::defaultAppearance()
{
@@ -149,7 +106,7 @@ std::shared_ptr<App::Material> MaterialManager::defaultAppearance()
uint32_t packed = color.getPackedRGB();
packed = hGrp->GetUnsigned(parameter, packed);
color.setPackedRGB(packed);
color.a = 1.0; // The default color sets fully transparent, not opaque
color.a = 1.0; // The default color sets fully transparent, not opaque
};
auto intRandom = [](int min, int max) -> int {
static std::mt19937 generator;
@@ -187,9 +144,9 @@ std::shared_ptr<Material> MaterialManager::defaultMaterial()
MaterialManager manager;
auto mat = defaultAppearance();
auto material = manager.getMaterial(defaultMaterialUUID());
auto material = getManager().getMaterial(defaultMaterialUUID());
if (!material) {
material = manager.getMaterial(QLatin1String("7f9fd73b-50c9-41d8-b7b2-575a030c1eeb"));
material = getManager().getMaterial(QStringLiteral("7f9fd73b-50c9-41d8-b7b2-575a030c1eeb"));
}
if (material->hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Basic)) {
material->getAppearanceProperty(QStringLiteral("DiffuseColor"))
@@ -218,14 +175,178 @@ QString MaterialManager::defaultMaterialUUID()
return QString::fromStdString(uuid);
}
//=====
//
// Library management
//
//=====
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> MaterialManager::getLibraries()
{
auto libraries = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>();
auto localLibraries = _localManager->getLibraries();
for (auto& local : *localLibraries) {
libraries->push_back(local);
}
return libraries;
}
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> MaterialManager::getLocalLibraries()
{
return _localManager->getLibraries();
}
std::shared_ptr<MaterialLibrary> MaterialManager::getLibrary(const QString& name) const
{
return _localManager->getLibrary(name);
}
void MaterialManager::createLibrary(const QString& libraryName, const QString& icon, bool readOnly)
{
throw CreationError("Local library requires a path");
}
void MaterialManager::createLocalLibrary(const QString& libraryName,
const QString& directory,
const QString& icon,
bool readOnly)
{
_localManager->createLibrary(libraryName, directory, icon, readOnly);
}
void MaterialManager::renameLibrary(const QString& libraryName, const QString& newName)
{
_localManager->renameLibrary(libraryName, newName);
}
void MaterialManager::changeIcon(const QString& libraryName, const QString& icon)
{
_localManager->changeIcon(libraryName, icon);
}
void MaterialManager::removeLibrary(const QString& libraryName)
{
_localManager->removeLibrary(libraryName);
}
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
MaterialManager::libraryMaterials(const QString& libraryName)
{
return _localManager->libraryMaterials(libraryName);
}
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
MaterialManager::libraryMaterials(const QString& libraryName,
const std::shared_ptr<MaterialFilter>& filter,
const MaterialFilterOptions& options)
{
return _localManager->libraryMaterials(libraryName, filter, options);
}
bool MaterialManager::isLocalLibrary(const QString& libraryName)
{
return true;
}
//=====
//
// Folder management
//
//=====
std::shared_ptr<std::list<QString>>
MaterialManager::getMaterialFolders(const std::shared_ptr<MaterialLibrary>& library) const
{
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
return _localManager->getMaterialFolders(materialLibrary);
}
return std::make_shared<std::list<QString>>();
}
void MaterialManager::createFolder(const std::shared_ptr<MaterialLibrary>& library,
const QString& path)
{
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
_localManager->createFolder(materialLibrary, path);
}
}
void MaterialManager::renameFolder(const std::shared_ptr<MaterialLibrary>& library,
const QString& oldPath,
const QString& newPath)
{
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
_localManager->renameFolder(materialLibrary, oldPath, newPath);
}
}
void MaterialManager::deleteRecursive(const std::shared_ptr<MaterialLibrary>& library,
const QString& path)
{
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
_localManager->deleteRecursive(materialLibrary, path);
}
}
//=====
//
// Tree management
//
//=====
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
MaterialManager::getMaterialTree(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Materials::MaterialFilter>& filter) const
{
MaterialFilterOptions options;
return library->getMaterialTree(filter, options);
}
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
MaterialManager::getMaterialTree(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Materials::MaterialFilter>& filter,
const MaterialFilterOptions& options) const
{
return library->getMaterialTree(filter, options);
}
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
MaterialManager::getMaterialTree(const std::shared_ptr<MaterialLibrary>& library) const
{
std::shared_ptr<Materials::MaterialFilter> filter;
MaterialFilterOptions options;
return library->getMaterialTree(filter, options);
}
//=====
//
// Material management
//
//=====
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>
MaterialManager::getLocalMaterials() const
{
return _localManager->getLocalMaterials();
}
std::shared_ptr<Material> MaterialManager::getMaterial(const QString& uuid) const
{
try {
return _materialMap->at(uuid);
}
catch (std::out_of_range&) {
throw MaterialNotFound();
}
return _localManager->getMaterial(uuid);
}
std::shared_ptr<Material> MaterialManager::getMaterial(const App::Material& material)
@@ -237,65 +358,13 @@ std::shared_ptr<Material> MaterialManager::getMaterial(const App::Material& mate
std::shared_ptr<Material> MaterialManager::getMaterialByPath(const QString& path) const
{
QString cleanPath = QDir::cleanPath(path);
for (auto& library : *_libraryList) {
if (cleanPath.startsWith(library->getDirectory())) {
try {
return library->getMaterialByPath(cleanPath);
}
catch (const MaterialNotFound&) {
}
// See if it's a new file saved by the old editor
{
QMutexLocker locker(&_mutex);
if (MaterialConfigLoader::isConfigStyle(path)) {
auto material = MaterialConfigLoader::getMaterialFromPath(library, path);
if (material) {
(*_materialMap)[material->getUUID()] = library->addMaterial(material, path);
}
return material;
}
}
}
}
// Older workbenches may try files outside the context of a library
{
QMutexLocker locker(&_mutex);
if (MaterialConfigLoader::isConfigStyle(path)) {
auto material = MaterialConfigLoader::getMaterialFromPath(nullptr, path);
return material;
}
}
throw MaterialNotFound();
return _localManager->getMaterialByPath(path);
}
std::shared_ptr<Material> MaterialManager::getMaterialByPath(const QString& path,
const QString& lib) const
{
auto library = getLibrary(lib); // May throw LibraryNotFound
return library->getMaterialByPath(path); // May throw MaterialNotFound
}
bool MaterialManager::exists(const QString& uuid) const
{
try {
auto material = getMaterial(uuid);
if (material) {
return true;
}
}
catch (const MaterialNotFound&) {
}
return false;
return _localManager->getMaterialByPath(path, lib);
}
std::shared_ptr<Material>
@@ -308,105 +377,69 @@ MaterialManager::getParent(const std::shared_ptr<Material>& material) const
return getMaterial(material->getParentUUID());
}
bool MaterialManager::exists(const QString& uuid) const
{
return _localManager->exists(uuid);
}
bool MaterialManager::exists(const std::shared_ptr<MaterialLibrary>& library,
const QString& uuid) const
{
try {
auto material = getMaterial(uuid);
if (material) {
return (*material->getLibrary() == *library);
}
}
catch (const MaterialNotFound&) {
}
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
return _localManager->exists(materialLibrary, uuid);
}
return false;
}
std::shared_ptr<MaterialLibrary> MaterialManager::getLibrary(const QString& name) const
void MaterialManager::remove(const QString& uuid) const
{
for (auto& library : *_libraryList) {
if (library->getName() == name) {
return library;
}
}
throw LibraryNotFound();
_localManager->remove(uuid);
}
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>
MaterialManager::getMaterialLibraries() const
void MaterialManager::saveMaterial(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Material>& material,
const QString& path,
bool overwrite,
bool saveAsCopy,
bool saveInherited) const
{
if (_libraryList == nullptr) {
if (_materialMap == nullptr) {
_materialMap = std::make_shared<std::map<QString, std::shared_ptr<Material>>>();
}
_libraryList = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>();
// Load the libraries
MaterialLoader loader(_materialMap, _libraryList);
}
return _libraryList;
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
_localManager
->saveMaterial(materialLibrary, material, path, overwrite, saveAsCopy, saveInherited);
}
std::shared_ptr<std::list<QString>>
MaterialManager::getMaterialFolders(const std::shared_ptr<MaterialLibrary>& library) const
bool MaterialManager::isMaterial(const fs::path& p) const
{
return MaterialLoader::getMaterialFolders(*library);
return _localManager->isMaterial(p);
}
bool MaterialManager::isMaterial(const QFileInfo& file) const
{
return _localManager->isMaterial(file);
}
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>
MaterialManager::materialsWithModel(const QString& uuid) const
{
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> dict =
std::make_shared<std::map<QString, std::shared_ptr<Material>>>();
for (auto& it : *_materialMap) {
QString key = it.first;
auto material = it.second;
if (material->hasModel(uuid)) {
(*dict)[key] = material;
}
}
return dict;
return _localManager->materialsWithModel(uuid);
}
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>
MaterialManager::materialsWithModelComplete(const QString& uuid) const
{
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> dict =
std::make_shared<std::map<QString, std::shared_ptr<Material>>>();
for (auto& it : *_materialMap) {
QString key = it.first;
auto material = it.second;
if (material->isModelComplete(uuid)) {
(*dict)[key] = material;
}
}
return dict;
return _localManager->materialsWithModelComplete(uuid);
}
void MaterialManager::dereference() const
{
// First clear the inheritences
for (auto& it : *_materialMap) {
auto material = it.second;
material->clearDereferenced();
material->clearInherited();
}
// Run the dereference again
for (auto& it : *_materialMap) {
dereference(it.second);
}
_localManager->dereference();
}
void MaterialManager::dereference(std::shared_ptr<Material> material) const
{
MaterialLoader::dereference(_materialMap, material);
_localManager->dereference(material);
}

View File

@@ -26,13 +26,14 @@
#include <filesystem>
#include <Base/Parameter.h>
#include <Mod/Material/MaterialGlobal.h>
#include "FolderTree.h"
#include "Materials.h"
#include "MaterialLibrary.h"
#include "MaterialFilter.h"
#include "MaterialLibrary.h"
namespace fs = std::filesystem;
@@ -45,78 +46,78 @@ class Material;
namespace Materials
{
class MaterialManagerExternal;
class MaterialManagerLocal;
class MaterialFilter;
class MaterialFilterOptions;
class MaterialsExport MaterialManager: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
MaterialManager();
~MaterialManager() override = default;
~MaterialManager() override;
static MaterialManager& getManager();
static void cleanup();
static void refresh();
// Defaults
static std::shared_ptr<App::Material> defaultAppearance();
static std::shared_ptr<Material> defaultMaterial();
static QString defaultMaterialUUID();
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> getMaterials() const
{
return _materialMap;
}
// Library management
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> getLibraries();
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> getLocalLibraries();
std::shared_ptr<MaterialLibrary> getLibrary(const QString& name) const;
void createLibrary(const QString& libraryName, const QString& icon, bool readOnly = true);
void createLocalLibrary(const QString& libraryName,
const QString& directory,
const QString& icon,
bool readOnly = true);
void renameLibrary(const QString& libraryName, const QString& newName);
void changeIcon(const QString& libraryName, const QString& icon);
void removeLibrary(const QString& libraryName);
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
libraryMaterials(const QString& libraryName);
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
libraryMaterials(const QString& libraryName,
const std::shared_ptr<MaterialFilter>& filter,
const MaterialFilterOptions& options);
bool isLocalLibrary(const QString& libraryName);
// Folder management
std::shared_ptr<std::list<QString>>
getMaterialFolders(const std::shared_ptr<MaterialLibrary>& library) const;
void createFolder(const std::shared_ptr<MaterialLibrary>& library, const QString& path);
void renameFolder(const std::shared_ptr<MaterialLibrary>& library,
const QString& oldPath,
const QString& newPath);
void deleteRecursive(const std::shared_ptr<MaterialLibrary>& library, const QString& path);
// Tree management
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
getMaterialTree(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Materials::MaterialFilter>& filter) const;
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
getMaterialTree(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Materials::MaterialFilter>& filter,
const MaterialFilterOptions& options) const;
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
getMaterialTree(const std::shared_ptr<MaterialLibrary>& library) const;
// Material management
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> getLocalMaterials() const;
std::shared_ptr<Material> getMaterial(const QString& uuid) const;
static std::shared_ptr<Material> getMaterial(const App::Material& material);
std::shared_ptr<Material> getMaterialByPath(const QString& path) const;
std::shared_ptr<Material> getMaterialByPath(const QString& path, const QString& library) const;
std::shared_ptr<Material> getParent(const std::shared_ptr<Material>& material) const;
std::shared_ptr<MaterialLibrary> getLibrary(const QString& name) const;
bool exists(const QString& uuid) const;
bool exists(const std::shared_ptr<MaterialLibrary>& library, const QString& uuid) const;
// Library management
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> getMaterialLibraries() const;
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
getMaterialTree(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Materials::MaterialFilter>& filter) const
{
MaterialFilterOptions options;
return library->getMaterialTree(filter, options);
}
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
getMaterialTree(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Materials::MaterialFilter>& filter,
const MaterialFilterOptions& options) const
{
return library->getMaterialTree(filter, options);
}
std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>
getMaterialTree(const std::shared_ptr<MaterialLibrary>& library) const
{
std::shared_ptr<Materials::MaterialFilter> filter;
MaterialFilterOptions options;
return library->getMaterialTree(filter, options);
}
std::shared_ptr<std::list<QString>>
getMaterialFolders(const std::shared_ptr<MaterialLibrary>& library) const;
void createFolder(const std::shared_ptr<MaterialLibrary>& library, const QString& path) const
{
library->createFolder(path);
}
void renameFolder(const std::shared_ptr<MaterialLibrary>& library,
const QString& oldPath,
const QString& newPath) const
{
library->renameFolder(oldPath, newPath);
}
void deleteRecursive(const std::shared_ptr<MaterialLibrary>& library, const QString& path) const
{
library->deleteRecursive(path);
dereference();
}
void remove(const QString& uuid) const
{
_materialMap->erase(uuid);
}
void remove(const QString& uuid) const;
void saveMaterial(const std::shared_ptr<MaterialLibrary>& library,
const std::shared_ptr<Material>& material,
@@ -136,13 +137,15 @@ public:
void dereference() const;
private:
static std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> _libraryList;
static std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> _materialMap;
static QMutex _mutex;
MaterialManager();
static void initManagers();
static void initLibraries();
static MaterialManager* _manager;
static std::unique_ptr<MaterialManagerLocal> _localManager;
static QMutex _mutex;
};
} // namespace Materials
#endif // MATERIAL_MATERIALMANAGER_H
#endif // MATERIAL_MATERIALMANAGER_H

View File

@@ -0,0 +1,593 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <random>
#endif
#include <QDirIterator>
#include <QMutex>
#include <QMutexLocker>
#include <App/Application.h>
#include <App/Material.h>
#include "Exceptions.h"
#include "MaterialConfigLoader.h"
#include "MaterialFilter.h"
#include "MaterialLibrary.h"
#include "MaterialLoader.h"
#include "MaterialManagerLocal.h"
#include "ModelManager.h"
#include "ModelUuids.h"
using namespace Materials;
/* TRANSLATOR Material::Materials */
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>
MaterialManagerLocal::_libraryList = nullptr;
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> MaterialManagerLocal::_materialMap =
nullptr;
QMutex MaterialManagerLocal::_mutex;
TYPESYSTEM_SOURCE(Materials::MaterialManagerLocal, Base::BaseClass)
MaterialManagerLocal::MaterialManagerLocal()
{
// TODO: Add a mutex or similar
initLibraries();
}
void MaterialManagerLocal::initLibraries()
{
QMutexLocker locker(&_mutex);
if (_materialMap == nullptr) {
// Load the models first
ModelManager::getManager();
_materialMap = std::make_shared<std::map<QString, std::shared_ptr<Material>>>();
if (_libraryList == nullptr) {
_libraryList = getConfiguredLibraries();
}
// Load the libraries
MaterialLoader loader(_materialMap, _libraryList);
}
}
void MaterialManagerLocal::cleanup()
{
QMutexLocker locker(&_mutex);
if (_libraryList) {
_libraryList->clear();
_libraryList = nullptr;
}
if (_materialMap) {
for (auto& it : *_materialMap) {
// This is needed to resolve cyclic dependencies
it.second->setLibrary(nullptr);
}
_materialMap->clear();
_materialMap = nullptr;
}
}
void MaterialManagerLocal::refresh()
{
// This is very expensive and can be improved using observers?
cleanup();
initLibraries();
}
//=====
//
// Library management
//
//=====
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> MaterialManagerLocal::getLibraries()
{
if (_libraryList == nullptr) {
initLibraries();
}
return _libraryList;
}
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>
MaterialManagerLocal::getMaterialLibraries()
{
if (_libraryList == nullptr) {
initLibraries();
}
return _libraryList;
}
std::shared_ptr<MaterialLibrary> MaterialManagerLocal::getLibrary(const QString& name) const
{
for (auto& library : *_libraryList) {
if (library->isLocal() && library->sameName(name)) {
return library;
}
}
throw LibraryNotFound();
}
void MaterialManagerLocal::createLibrary(const QString& libraryName,
const QString& directory,
const QString& icon,
bool readOnly)
{
QDir dir;
if (!dir.exists(directory)) {
if (!dir.mkpath(directory)) {
throw CreationError("Unable to create library path");
}
}
auto materialLibrary =
std::make_shared<MaterialLibraryLocal>(libraryName, directory, icon, readOnly);
_libraryList->push_back(materialLibrary);
// This needs to be persisted somehow
}
void MaterialManagerLocal::renameLibrary(const QString& libraryName, const QString& newName)
{
for (auto& library : *_libraryList) {
if (library->isLocal() && library->sameName(libraryName)) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
materialLibrary->setName(newName);
return;
}
}
throw LibraryNotFound();
}
void MaterialManagerLocal::changeIcon(const QString& libraryName, const QString& icon)
{
for (auto& library : *_libraryList) {
if (library->isLocal() && library->sameName(libraryName)) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
materialLibrary->setIconPath(icon);
return;
}
}
throw LibraryNotFound();
}
void MaterialManagerLocal::removeLibrary(const QString& libraryName)
{
for (auto& library : *_libraryList) {
if (library->isLocal() && library->sameName(libraryName)) {
_libraryList->remove(library);
// At this point we should rebuild the material map
return;
}
}
throw LibraryNotFound();
}
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
MaterialManagerLocal::libraryMaterials(const QString& libraryName)
{
auto materials = std::make_shared<std::vector<std::tuple<QString, QString, QString>>>();
for (auto& it : *_materialMap) {
// This is needed to resolve cyclic dependencies
auto library = it.second->getLibrary();
if (library->sameName(libraryName)) {
materials->push_back(std::tuple<QString, QString, QString>(it.first,
it.second->getDirectory(),
it.second->getName()));
}
}
return materials;
}
bool MaterialManagerLocal::passFilter(const std::shared_ptr<Material>& material,
const std::shared_ptr<Materials::MaterialFilter>& filter,
const Materials::MaterialFilterOptions& options) const
{
if (!filter) {
// If there's no filter we always include
return true;
}
// filter out old format files
if (material->isOldFormat() && !options.includeLegacy()) {
return false;
}
// filter based on models
return filter->modelIncluded(material);
}
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
MaterialManagerLocal::libraryMaterials(const QString& libraryName,
const std::shared_ptr<MaterialFilter>& filter,
const MaterialFilterOptions& options)
{
auto materials = std::make_shared<std::vector<std::tuple<QString, QString, QString>>>();
for (auto& it : *_materialMap) {
// This is needed to resolve cyclic dependencies
auto library = it.second->getLibrary();
if (library->sameName(libraryName)) {
if (passFilter(it.second, filter, options)) {
materials->push_back(std::tuple<QString, QString, QString>(it.first,
it.second->getDirectory(),
it.second->getName()));
}
}
}
return materials;
}
//=====
//
// Folder management
//
//=====
std::shared_ptr<std::list<QString>>
MaterialManagerLocal::getMaterialFolders(const std::shared_ptr<MaterialLibraryLocal>& library) const
{
// auto materialLibrary =
// reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
return MaterialLoader::getMaterialFolders(*library);
}
void MaterialManagerLocal::createFolder(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& path)
{
library->createFolder(path);
}
void MaterialManagerLocal::renameFolder(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& oldPath,
const QString& newPath)
{
library->renameFolder(oldPath, newPath);
}
void MaterialManagerLocal::deleteRecursive(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& path)
{
library->deleteRecursive(path);
dereference();
}
//=====
//
// Material management
//
//=====
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>
MaterialManagerLocal::getLocalMaterials() const
{
return _materialMap;
}
std::shared_ptr<Material> MaterialManagerLocal::getMaterial(const QString& uuid) const
{
try {
return _materialMap->at(uuid);
}
catch (std::out_of_range&) {
throw MaterialNotFound();
}
}
std::shared_ptr<Material> MaterialManagerLocal::getMaterialByPath(const QString& path) const
{
QString cleanPath = QDir::cleanPath(path);
for (auto& library : *_libraryList) {
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
if (cleanPath.startsWith(materialLibrary->getDirectory())) {
try {
return materialLibrary->getMaterialByPath(cleanPath);
}
catch (const MaterialNotFound&) {
}
// See if it's a new file saved by the old editor
{
QMutexLocker locker(&_mutex);
if (MaterialConfigLoader::isConfigStyle(path)) {
auto material =
MaterialConfigLoader::getMaterialFromPath(materialLibrary, path);
if (material) {
(*_materialMap)[material->getUUID()] =
materialLibrary->addMaterial(material, path);
}
return material;
}
}
}
}
}
// Older workbenches may try files outside the context of a library
{
QMutexLocker locker(&_mutex);
if (MaterialConfigLoader::isConfigStyle(path)) {
auto material = MaterialConfigLoader::getMaterialFromPath(nullptr, path);
return material;
}
}
throw MaterialNotFound();
}
std::shared_ptr<Material> MaterialManagerLocal::getMaterialByPath(const QString& path,
const QString& lib) const
{
auto library = getLibrary(lib); // May throw LibraryNotFound
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
return materialLibrary->getMaterialByPath(path); // May throw MaterialNotFound
}
throw LibraryNotFound();
}
bool MaterialManagerLocal::exists(const QString& uuid) const
{
try {
auto material = getMaterial(uuid);
if (material) {
return true;
}
}
catch (const MaterialNotFound&) {
}
return false;
}
bool MaterialManagerLocal::exists(const std::shared_ptr<MaterialLibrary>& library,
const QString& uuid) const
{
try {
auto material = getMaterial(uuid);
if (material && material->getLibrary()->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(
*(material->getLibrary()));
return (*materialLibrary == *library);
}
}
catch (const MaterialNotFound&) {
}
return false;
}
void MaterialManagerLocal::remove(const QString& uuid)
{
_materialMap->erase(uuid);
}
void MaterialManagerLocal::saveMaterial(const std::shared_ptr<MaterialLibraryLocal>& library,
const std::shared_ptr<Material>& material,
const QString& path,
bool overwrite,
bool saveAsCopy,
bool saveInherited) const
{
if (library->isLocal()) {
auto newMaterial =
library->saveMaterial(material, path, overwrite, saveAsCopy, saveInherited);
(*_materialMap)[newMaterial->getUUID()] = newMaterial;
}
}
bool MaterialManagerLocal::isMaterial(const fs::path& p) const
{
if (!fs::is_regular_file(p)) {
return false;
}
// check file extension
if (p.extension() == ".FCMat") {
return true;
}
return false;
}
bool MaterialManagerLocal::isMaterial(const QFileInfo& file) const
{
if (!file.isFile()) {
return false;
}
// check file extension
if (file.suffix() == QStringLiteral("FCMat")) {
return true;
}
return false;
}
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>
MaterialManagerLocal::materialsWithModel(const QString& uuid) const
{
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> dict =
std::make_shared<std::map<QString, std::shared_ptr<Material>>>();
for (auto& it : *_materialMap) {
QString key = it.first;
auto material = it.second;
if (material->hasModel(uuid)) {
(*dict)[key] = material;
}
}
return dict;
}
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>
MaterialManagerLocal::materialsWithModelComplete(const QString& uuid) const
{
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> dict =
std::make_shared<std::map<QString, std::shared_ptr<Material>>>();
for (auto& it : *_materialMap) {
QString key = it.first;
auto material = it.second;
if (material->isModelComplete(uuid)) {
(*dict)[key] = material;
}
}
return dict;
}
void MaterialManagerLocal::dereference() const
{
// First clear the inheritences
for (auto& it : *_materialMap) {
auto material = it.second;
material->clearDereferenced();
material->clearInherited();
}
// Run the dereference again
for (auto& it : *_materialMap) {
dereference(it.second);
}
}
void MaterialManagerLocal::dereference(std::shared_ptr<Material> material) const
{
MaterialLoader::dereference(_materialMap, material);
}
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>
MaterialManagerLocal::getConfiguredLibraries()
{
auto libraryList = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>();
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 =
std::make_shared<MaterialLibraryLocal>(QStringLiteral("System"),
resourceDir,
QStringLiteral(":/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 = std::make_shared<MaterialLibraryLocal>(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()) {
// Try creating the user dir if it doesn't exist
if (!materialDir.mkpath(resourceDir)) {
Base::Console().Log("Unable to create user library '%s'\n",
resourceDir.toStdString().c_str());
}
}
if (materialDir.exists()) {
auto libData = std::make_shared<MaterialLibraryLocal>(
QStringLiteral("User"),
resourceDir,
QStringLiteral(":/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 = std::make_shared<MaterialLibraryLocal>(
QStringLiteral("Custom"),
resourceDir,
QStringLiteral(":/icons/user.svg"),
false);
libraryList->push_back(libData);
}
}
}
return libraryList;
}

View File

@@ -0,0 +1,131 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef MATERIAL_MATERIALMANAGERLOCAL_H
#define MATERIAL_MATERIALMANAGERLOCAL_H
#include <memory>
#include <filesystem>
#include <Mod/Material/MaterialGlobal.h>
#include "FolderTree.h"
#include "Materials.h"
namespace fs = std::filesystem;
class QMutex;
namespace App
{
class Material;
}
namespace Materials
{
class MaterialLibrary;
class MaterialLibraryLocal;
class MaterialFilter;
class MaterialFilterOptions;
class MaterialsExport MaterialManagerLocal: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
MaterialManagerLocal();
~MaterialManagerLocal() override = default;
static void cleanup();
static void refresh();
// Library management
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> getLibraries();
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> getMaterialLibraries();
std::shared_ptr<MaterialLibrary> getLibrary(const QString& name) const;
void createLibrary(const QString& libraryName,
const QString& directory,
const QString& icon,
bool readOnly = true);
void renameLibrary(const QString& libraryName, const QString& newName);
void changeIcon(const QString& libraryName, const QString& icon);
void removeLibrary(const QString& libraryName);
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
libraryMaterials(const QString& libraryName);
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
libraryMaterials(const QString& libraryName,
const std::shared_ptr<MaterialFilter>& filter,
const MaterialFilterOptions& options);
// Folder management
std::shared_ptr<std::list<QString>>
getMaterialFolders(const std::shared_ptr<MaterialLibraryLocal>& library) const;
void createFolder(const std::shared_ptr<MaterialLibraryLocal>& library, const QString& path);
void renameFolder(const std::shared_ptr<MaterialLibraryLocal>& library,
const QString& oldPath,
const QString& newPath);
void deleteRecursive(const std::shared_ptr<MaterialLibraryLocal>& library, const QString& path);
// Material management
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> getLocalMaterials() const;
std::shared_ptr<Material> getMaterial(const QString& uuid) const;
std::shared_ptr<Material> getMaterialByPath(const QString& path) const;
std::shared_ptr<Material> getMaterialByPath(const QString& path, const QString& library) const;
bool exists(const QString& uuid) const;
bool exists(const std::shared_ptr<MaterialLibrary>& library, const QString& uuid) const;
void remove(const QString& uuid);
void saveMaterial(const std::shared_ptr<MaterialLibraryLocal>& library,
const std::shared_ptr<Material>& material,
const QString& path,
bool overwrite,
bool saveAsCopy,
bool saveInherited) const;
bool isMaterial(const fs::path& p) const;
bool isMaterial(const QFileInfo& file) const;
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>
materialsWithModel(const QString& uuid) const;
std::shared_ptr<std::map<QString, std::shared_ptr<Material>>>
materialsWithModelComplete(const QString& uuid) const;
void dereference(std::shared_ptr<Material> material) const;
void dereference() const;
protected:
static std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> getConfiguredLibraries();
bool passFilter(const std::shared_ptr<Material>& material,
const std::shared_ptr<Materials::MaterialFilter>& filter,
const Materials::MaterialFilterOptions& options) const;
private:
static std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> _libraryList;
static std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> _materialMap;
static QMutex _mutex;
static void initLibraries();
};
} // namespace Materials
#endif // MATERIAL_MATERIALMANAGERLOCAL_H

View File

@@ -10,7 +10,7 @@
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
Delete="false">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material descriptions.</UserDocu>

View File

@@ -47,7 +47,7 @@ std::string MaterialManagerPy::representation() const
PyObject* MaterialManagerPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
{
// never create such objects with the constructor
return new MaterialManagerPy(new MaterialManager());
return new MaterialManagerPy(&(MaterialManager::getManager()));
}
// constructor method
@@ -136,15 +136,25 @@ PyObject* MaterialManagerPy::inheritMaterial(PyObject* args)
Py::List MaterialManagerPy::getMaterialLibraries() const
{
auto libraries = getMaterialManagerPtr()->getMaterialLibraries();
auto libraries = getMaterialManagerPtr()->getLibraries();
Py::List list;
for (auto it = libraries->begin(); it != libraries->end(); it++) {
auto 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()));
if (lib->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(lib);
libTuple.setItem(0, Py::String(materialLibrary->getName().toStdString()));
libTuple.setItem(1, Py::String(materialLibrary->getDirectoryPath().toStdString()));
libTuple.setItem(2, Py::String(materialLibrary->getIconPath().toStdString()));
}
else
{
libTuple.setItem(0, Py::String());
libTuple.setItem(1, Py::String());
libTuple.setItem(2, Py::String());
}
list.append(libTuple);
}
@@ -156,7 +166,7 @@ Py::Dict MaterialManagerPy::getMaterials() const
{
Py::Dict dict;
auto materials = getMaterialManagerPtr()->getMaterials();
auto materials = getMaterialManagerPtr()->getLocalMaterials();
for (auto it = materials->begin(); it != materials->end(); it++) {
QString key = it->first;
@@ -284,17 +294,19 @@ PyObject* MaterialManagerPy::save(PyObject* args, PyObject* kwds)
return Py_None;
}
void addMaterials(Py::List& list,
void addMaterials(MaterialManager *manager,
Py::List& list,
const std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>>& tree)
{
for (auto& node : *tree) {
if (node.second->getType() == MaterialTreeNode::DataNode) {
auto material = node.second->getData();
if (node.second->getType() == MaterialTreeNode::NodeType::DataNode) {
auto uuid = node.second->getUUID();
auto material = manager->getMaterial(uuid);
PyObject* materialPy = new MaterialPy(new Material(*material));
list.append(Py::Object(materialPy, true));
}
else {
addMaterials(list, node.second->getFolder());
addMaterials(manager, list, node.second->getFolder());
}
}
}
@@ -327,13 +339,13 @@ PyObject* MaterialManagerPy::filterMaterials(PyObject* args, PyObject* kwds)
auto filter = std::make_shared<MaterialFilter>(*(static_cast<MaterialFilterPy*>(filterPy)->getMaterialFilterPtr()));
auto libraries = getMaterialManagerPtr()->getMaterialLibraries();
auto libraries = getMaterialManagerPtr()->getLibraries();
Py::List list;
for (auto lib : *libraries) {
auto tree = getMaterialManagerPtr()->getMaterialTree(lib, filter, options);
if (tree->size() > 0) {
addMaterials(list, tree);
addMaterials(getMaterialManagerPtr(), list, tree);
}
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="ModelPropertyPy"
Name="MaterialPropertyPy"
Twin="MaterialProperty"
TwinPointer="MaterialProperty"
Include="Mod/Material/App/Materials.h"
Namespace="Materials"
FatherInclude="Mod/Material/App/Model.h"
FatherNamespace="Materials"
Constructor="true"
Delete="false">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material property descriptions.</UserDocu>
</Documentation>
<Attribute Name="Value" ReadOnly="true">
<Documentation>
<UserDocu>The value of the material property.</UserDocu>
</Documentation>
<Parameter Name="Value" Type="Object"/>
</Attribute>
<Attribute Name="Empty" ReadOnly="true">
<Documentation>
<UserDocu>The property value is undefined.</UserDocu>
</Documentation>
<Parameter Name="Empty" Type="Boolean"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,74 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#include "Model.h"
#include "PyVariants.h"
#include "ModelPropertyPy.h"
#include "MaterialPropertyPy.h"
#include "MaterialPropertyPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string MaterialPropertyPy::representation() const
{
std::stringstream str;
str << "<MaterialProperty object at " << getMaterialPropertyPtr() << ">";
return str.str();
}
PyObject* MaterialPropertyPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
{
// never create such objects with the constructor
return new MaterialPropertyPy(new MaterialProperty());
}
// constructor method
int MaterialPropertyPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::Object MaterialPropertyPy::getValue() const
{
auto value = getMaterialPropertyPtr()->getValue();
return Py::Object(_pyObjectFromVariant(value), true);
}
Py::Boolean MaterialPropertyPy::getEmpty() const
{
return getMaterialPropertyPtr()->isEmpty();
}
PyObject* MaterialPropertyPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int MaterialPropertyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -39,7 +39,7 @@
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Directory" ReadOnly="true">
<Attribute Name="Directory" ReadOnly="false">
<Documentation>
<UserDocu>Model directory relative to the library root.</UserDocu>
</Documentation>
@@ -69,7 +69,7 @@
</Documentation>
<Parameter Name="Reference" Type="String"/>
</Attribute>
<Attribute Name="Parent" ReadOnly="true">
<Attribute Name="Parent" ReadOnly="false">
<Documentation>
<UserDocu>Parent material UUID.</UserDocu>
</Documentation>
@@ -210,6 +210,17 @@
<UserDocu>Set the value associated with the property</UserDocu>
</Documentation>
</Methode>
<Methode Name="setValue" ReadOnly="true">
<Documentation>
<UserDocu>Set the value associated with the property</UserDocu>
</Documentation>
</Methode>
<Attribute Name="PropertyObjects" ReadOnly="true">
<Documentation>
<UserDocu>Dictionary of MaterialProperty objects.</UserDocu>
</Documentation>
<Parameter Name="PropertyObjects" Type="Dict"/>
</Attribute>
<Methode Name="keys" NoArgs="true">
<Documentation>
<UserDocu>Property keys</UserDocu>

View File

@@ -36,15 +36,15 @@
#include "MaterialLibrary.h"
#include "MaterialPy.h"
#include "MaterialValue.h"
#include "PyVariants.h"
#include "ModelPropertyPy.h"
#include "MaterialPropertyPy.h"
#include "MaterialPy.cpp"
using namespace Materials;
// Forward declaration
static PyObject* _pyObjectFromVariant(const QVariant& value);
static Py::List getList(const QVariant& value);
// returns a string which represents the object e.g. when printed in python
std::string MaterialPy::representation() const
{
@@ -68,19 +68,34 @@ int MaterialPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
Py::String MaterialPy::getLibraryName() const
{
auto library = getMaterialPtr()->getLibrary();
return {library ? library->getName().toStdString() : ""};
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
return {materialLibrary ? materialLibrary->getName().toStdString() : ""};
}
return "";
}
Py::String MaterialPy::getLibraryRoot() const
{
auto library = getMaterialPtr()->getLibrary();
return {library ? library->getDirectoryPath().toStdString() : ""};
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
return {materialLibrary ? materialLibrary->getDirectoryPath().toStdString() : ""};
}
return "";
}
Py::String MaterialPy::getLibraryIcon() const
{
auto library = getMaterialPtr()->getLibrary();
return {library ? library->getIconPath().toStdString() : ""};
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
return {materialLibrary ? materialLibrary->getIconPath().toStdString() : ""};
}
return "";
}
Py::String MaterialPy::getName() const
@@ -98,6 +113,11 @@ Py::String MaterialPy::getDirectory() const
return {getMaterialPtr()->getDirectory().toStdString()};
}
void MaterialPy::setDirectory(Py::String arg)
{
getMaterialPtr()->setDirectory(QString::fromStdString(arg));
}
Py::String MaterialPy::getUUID() const
{
return {getMaterialPtr()->getUUID().toStdString()};
@@ -138,6 +158,11 @@ Py::String MaterialPy::getParent() const
return {getMaterialPtr()->getParentUUID().toStdString()};
}
void MaterialPy::setParent(Py::String arg)
{
getMaterialPtr()->setParentUUID(QString::fromStdString(arg));
}
Py::String MaterialPy::getAuthorAndLicense() const
{
return {getMaterialPtr()->getAuthorAndLicense().toStdString()};
@@ -438,52 +463,6 @@ Py::Dict MaterialPy::getLegacyProperties() const
return dict;
}
static Py::List getList(const QVariant& value)
{
auto listValue = value.value<QList<QVariant>>();
Py::List list;
for (auto& it : listValue) {
list.append(Py::Object(_pyObjectFromVariant(it)));
}
return list;
}
static PyObject* _pyObjectFromVariant(const QVariant& value)
{
if (value.isNull()) {
Py_RETURN_NONE;
}
if (value.userType() == qMetaTypeId<Base::Quantity>()) {
return new Base::QuantityPy(new Base::Quantity(value.value<Base::Quantity>()));
}
if (value.userType() == QMetaType::Double) {
return PyFloat_FromDouble(value.toDouble());
}
if (value.userType() == QMetaType::Float) {
return PyFloat_FromDouble(value.toFloat());
}
if (value.userType() == QMetaType::Int) {
return PyLong_FromLong(value.toInt());
}
if (value.userType() == QMetaType::Long) {
return PyLong_FromLong(value.toInt());
}
if (value.userType() == QMetaType::Bool) {
return Py::new_reference_to(Py::Boolean(value.toBool()));
}
if (value.userType() == QMetaType::QString) {
return PyUnicode_FromString(value.toString().toStdString().c_str());
}
if (value.userType() == qMetaTypeId<QList<QVariant>>()) {
return Py::new_reference_to(getList(value));
}
throw UnknownValueType();
}
PyObject* MaterialPy::getPhysicalValue(PyObject* args)
{
char* name;
@@ -502,13 +481,13 @@ PyObject* MaterialPy::getPhysicalValue(PyObject* args)
if (property->getType() == MaterialValue::Array2D) {
auto value =
std::static_pointer_cast<Materials::Material2DArray>(property->getMaterialValue());
return new Array2DPy(new Material2DArray(*value));
std::static_pointer_cast<Materials::Array2D>(property->getMaterialValue());
return new Array2DPy(new Array2D(*value));
}
if (property->getType() == MaterialValue::Array3D) {
auto value =
std::static_pointer_cast<Materials::Material3DArray>(property->getMaterialValue());
return new Array3DPy(new Material3DArray(*value));
std::static_pointer_cast<Materials::Array3D>(property->getMaterialValue());
return new Array3DPy(new Array3D(*value));
}
QVariant value = property->getValue();
@@ -523,8 +502,7 @@ PyObject* MaterialPy::setPhysicalValue(PyObject* args)
return nullptr;
}
getMaterialPtr()->setPhysicalValue(QString::fromStdString(name),
QString::fromStdString(value));
getMaterialPtr()->setPhysicalValue(QString::fromStdString(name), QString::fromStdString(value));
Py_INCREF(Py_None);
return Py_None;
}
@@ -536,7 +514,27 @@ PyObject* MaterialPy::getAppearanceValue(PyObject* args)
return nullptr;
}
QVariant value = getMaterialPtr()->getAppearanceValue(QString::fromStdString(name));
if (!getMaterialPtr()->hasAppearanceProperty(QString::fromStdString(name))) {
Py_RETURN_NONE;
}
auto property = getMaterialPtr()->getAppearanceProperty(QString::fromStdString(name));
if (!property) {
Py_RETURN_NONE;
}
if (property->getType() == MaterialValue::Array2D) {
auto value =
std::static_pointer_cast<Materials::Array2D>(property->getMaterialValue());
return new Array2DPy(new Array2D(*value));
}
if (property->getType() == MaterialValue::Array3D) {
auto value =
std::static_pointer_cast<Materials::Array3D>(property->getMaterialValue());
return new Array3DPy(new Array3D(*value));
}
QVariant value = property->getValue();
return _pyObjectFromVariant(value);
}
@@ -553,6 +551,93 @@ PyObject* MaterialPy::setAppearanceValue(PyObject* args)
Py_INCREF(Py_None);
return Py_None;
}
PyObject* MaterialPy::setValue(PyObject* args)
{
char* name;
char* value;
PyObject* listObj;
PyObject* arrayObj;
if (PyArg_ParseTuple(args, "ss", &name, &value)) {
getMaterialPtr()->setValue(QString::fromStdString(name), QString::fromStdString(value));
Py_Return;
}
PyErr_Clear();
if (PyArg_ParseTuple(args, "sO!", &name, &PyList_Type, &listObj)) {
QList<QVariant> variantList;
Py::List list(listObj);
for (auto itemObj : list) {
Py::String item(itemObj);
QString value(QString::fromStdString(item.as_string()));
QVariant variant = QVariant::fromValue(value);
variantList.append(variant);
}
getMaterialPtr()->setValue(QString::fromStdString(name), variantList);
Py_Return;
}
PyErr_Clear();
if (PyArg_ParseTuple(args, "sO!", &name, &(Array2DPy::Type), &arrayObj)) {
auto array = static_cast<Array2DPy*>(arrayObj);
auto shared = std::make_shared<Array2D>(*array->getArray2DPtr());
getMaterialPtr()->setValue(QString::fromStdString(name), shared);
Py_Return;
}
PyErr_Clear();
if (PyArg_ParseTuple(args, "sO!", &name, &(Array3DPy::Type), &arrayObj)) {
auto array = static_cast<Array3DPy*>(arrayObj);
auto shared = std::make_shared<Array3D>(*array->getArray3DPtr());
getMaterialPtr()->setValue(QString::fromStdString(name), shared);
Py_Return;
}
PyErr_SetString(PyExc_TypeError, "Either a string, a list, or an array are expected");
return nullptr;
}
Py::Dict MaterialPy::getPropertyObjects() const
{
Py::Dict dict;
auto properties = getMaterialPtr()->getPhysicalProperties();
for (auto& it : properties) {
QString key = it.first;
auto materialProperty = it.second;
// if (materialProperty->getType() == MaterialValue::Array2D) {
// auto value = std::static_pointer_cast<Materials::Array2D>(
// materialProperty->getMaterialValue());
// dict.setItem(Py::String(key.toStdString()),
// Py::Object(new Array2DPy(new Array2D(*value)), true));
// }
// else if (materialProperty->getType() == MaterialValue::Array3D) {
// auto value = std::static_pointer_cast<Materials::Array3D>(
// materialProperty->getMaterialValue());
// dict.setItem(Py::String(key.toStdString()),
// Py::Object(new Array3DPy(new Array3D(*value)), true));
// }
// else {
dict.setItem(
Py::String(key.toStdString()),
Py::Object(new MaterialPropertyPy(new MaterialProperty(materialProperty)), true));
// }
}
properties = getMaterialPtr()->getAppearanceProperties();
for (auto& it : properties) {
QString key = it.first;
auto materialProperty = it.second;
dict.setItem(
Py::String(key.toStdString()),
Py::Object(new MaterialPropertyPy(new MaterialProperty(materialProperty)), true));
}
return dict;
}
PyObject* MaterialPy::keys()
{
@@ -584,4 +669,4 @@ PyObject* MaterialPy::mapping_subscript(PyObject* self, PyObject* key)
{
Py::Dict dict = static_cast<MaterialPy*>(self)->getProperties();
return Py::new_reference_to(dict.getItem(Py::Object(key)));
}
}

View File

@@ -102,6 +102,44 @@ bool MaterialValue::operator==(const MaterialValue& other) const
return (_valueType == other._valueType) && (_value == other._value);
}
void MaterialValue::validate(const MaterialValue& other) const
{
if (_valueType != other._valueType) {
throw InvalidProperty("Material property value types don't match");
}
if (_valueType == Quantity) {
auto q1 = _value.value<Base::Quantity>();
auto q2 = other._value.value<Base::Quantity>();
if (q1.isValid()) {
if (!q2.isValid()) {
throw InvalidProperty("Invalid remote Material property quantity value");
}
if (q1.getUserString() != q2.getUserString()) {
// Direct comparisons of the quantities may have precision issues
// throw InvalidProperty("Material property quantity values don't match");
}
}
else {
if (q2.isValid()) {
throw InvalidProperty("Remote Material property quantity should not have a value");
}
}
}
else if (_valueType == Array2D) {
auto a1 = static_cast<const Materials::Array2D*>(this);
auto a2 = static_cast<const Materials::Array2D*>(&other);
a1->validate(*a2);
}
else if (_valueType == Array3D) {
auto a1 = static_cast<const Materials::Array3D*>(this);
auto a2 = static_cast<const Materials::Array3D*>(&other);
a1->validate(*a2);
}
else if (!(_value.isNull() && other._value.isNull()) && (_value != other._value)) {
throw InvalidProperty("Material property values don't match");
}
}
QString MaterialValue::escapeString(const QString& source)
{
QString res = source;
@@ -205,6 +243,11 @@ void MaterialValue::setList(const QList<QVariant>& value)
}
bool MaterialValue::isNull() const
{
return isEmpty();
}
bool MaterialValue::isEmpty() const
{
if (_value.isNull()) {
return true;
@@ -317,24 +360,24 @@ const Base::QuantityFormat MaterialValue::getQuantityFormat()
//===
TYPESYSTEM_SOURCE(Materials::Material2DArray, Materials::MaterialValue)
TYPESYSTEM_SOURCE(Materials::Array2D, Materials::MaterialValue)
Material2DArray::Material2DArray()
: MaterialValue(Array2D, Array2D)
Array2D::Array2D()
: MaterialValue(MaterialValue::Array2D, MaterialValue::Array2D)
, _columns(0)
{
// Initialize separatelt to prevent recursion
// setType(Array2D);
}
Material2DArray::Material2DArray(const Material2DArray& other)
Array2D::Array2D(const Array2D& other)
: MaterialValue(other)
, _columns(other._columns)
{
deepCopy(other);
}
Material2DArray& Material2DArray::operator=(const Material2DArray& other)
Array2D& Array2D::operator=(const Array2D& other)
{
if (this == &other) {
return *this;
@@ -348,7 +391,7 @@ Material2DArray& Material2DArray::operator=(const Material2DArray& other)
return *this;
}
void Material2DArray::deepCopy(const Material2DArray& other)
void Array2D::deepCopy(const Array2D& other)
{
// Deep copy
for (auto& row : other._rows) {
@@ -361,26 +404,55 @@ void Material2DArray::deepCopy(const Material2DArray& other)
}
}
bool Material2DArray::isNull() const
bool Array2D::isNull() const
{
return isEmpty();
}
bool Array2D::isEmpty() const
{
return rows() <= 0;
}
void Material2DArray::validateRow(int row) const
void Array2D::validateRow(int row) const
{
if (row < 0 || row >= rows()) {
throw InvalidIndex();
}
}
void Material2DArray::validateColumn(int column) const
void Array2D::validateColumn(int column) const
{
if (column < 0 || column >= columns()) {
throw InvalidIndex();
}
}
std::shared_ptr<QList<QVariant>> Material2DArray::getRow(int row) const
void Array2D::validate(const Array2D& other) const
{
if (rows() != other.rows()) {
Base::Console().Log("Local row count %d, remote %d\n", rows(), other.rows());
throw InvalidProperty("Material property value row counts don't match");
}
if (columns() != other.columns()) {
Base::Console().Log("Local column count %d, remote %d\n", columns(), other.columns());
throw InvalidProperty("Material property value column counts don't match");
}
try {
for (int i = 0; i < rows(); i++) {
for (int j = 0; j < columns(); j++) {
if (getValue(i, j) != other.getValue(i, j)) {
throw InvalidProperty("Material property values don't match");
}
}
}
}
catch (const InvalidIndex&) {
throw InvalidProperty("Material property value invalid array index");
}
}
std::shared_ptr<QList<QVariant>> Array2D::getRow(int row) const
{
validateRow(row);
@@ -392,7 +464,7 @@ std::shared_ptr<QList<QVariant>> Material2DArray::getRow(int row) const
}
}
std::shared_ptr<QList<QVariant>> Material2DArray::getRow(int row)
std::shared_ptr<QList<QVariant>> Array2D::getRow(int row)
{
validateRow(row);
@@ -404,17 +476,17 @@ std::shared_ptr<QList<QVariant>> Material2DArray::getRow(int row)
}
}
void Material2DArray::addRow(const std::shared_ptr<QList<QVariant>>& row)
void Array2D::addRow(const std::shared_ptr<QList<QVariant>>& row)
{
_rows.push_back(row);
}
void Material2DArray::insertRow(int index, const std::shared_ptr<QList<QVariant>>& row)
void Array2D::insertRow(int index, const std::shared_ptr<QList<QVariant>>& row)
{
_rows.insert(_rows.begin() + index, row);
}
void Material2DArray::deleteRow(int row)
void Array2D::deleteRow(int row)
{
if (row >= static_cast<int>(_rows.size()) || row < 0) {
throw InvalidIndex();
@@ -422,7 +494,18 @@ void Material2DArray::deleteRow(int row)
_rows.erase(_rows.begin() + row);
}
void Material2DArray::setValue(int row, int column, const QVariant& value)
void Array2D::setRows(int rowCount)
{
while (rows() < rowCount) {
auto row = std::make_shared<QList<QVariant>>();
for (int i = 0; i < columns(); i++) {
row->append(QVariant());
}
addRow(row);
}
}
void Array2D::setValue(int row, int column, const QVariant& value)
{
validateRow(row);
validateColumn(column);
@@ -436,7 +519,7 @@ void Material2DArray::setValue(int row, int column, const QVariant& value)
}
}
QVariant Material2DArray::getValue(int row, int column) const
QVariant Array2D::getValue(int row, int column) const
{
validateColumn(column);
@@ -449,7 +532,7 @@ QVariant Material2DArray::getValue(int row, int column) const
}
}
void Material2DArray::dumpRow(const std::shared_ptr<QList<QVariant>>& row)
void Array2D::dumpRow(const std::shared_ptr<QList<QVariant>>& row)
{
Base::Console().Log("row: ");
for (auto& column : *row) {
@@ -458,14 +541,14 @@ void Material2DArray::dumpRow(const std::shared_ptr<QList<QVariant>>& row)
Base::Console().Log("\n");
}
void Material2DArray::dump() const
void Array2D::dump() const
{
for (auto& row : _rows) {
dumpRow(row);
}
}
QString Material2DArray::getYAMLString() const
QString Array2D::getYAMLString() const
{
if (isNull()) {
return QString();
@@ -511,10 +594,10 @@ QString Material2DArray::getYAMLString() const
//===
TYPESYSTEM_SOURCE(Materials::Material3DArray, Materials::MaterialValue)
TYPESYSTEM_SOURCE(Materials::Array3D, Materials::MaterialValue)
Material3DArray::Material3DArray()
: MaterialValue(Array3D, Array3D)
Array3D::Array3D()
: MaterialValue(MaterialValue::Array3D, MaterialValue::Array3D)
, _currentDepth(0)
, _columns(0)
{
@@ -522,26 +605,71 @@ Material3DArray::Material3DArray()
// setType(Array3D);
}
bool Material3DArray::isNull() const
Array3D::Array3D(const Array3D& other)
: MaterialValue(other)
, _currentDepth(other._currentDepth)
, _columns(other._columns)
{
deepCopy(other);
}
Array3D& Array3D::operator=(const Array3D& other)
{
if (this == &other) {
return *this;
}
MaterialValue::operator=(other);
_columns = other._columns;
_currentDepth = other._currentDepth;
deepCopy(other);
return *this;
}
void Array3D::deepCopy(const Array3D& other)
{
// Deep copy
_rowMap.clear();
for (auto& depthTable : other._rowMap) {
auto depth = addDepth(depthTable.first);
auto rows = depthTable.second;
for (auto row : *rows) {
auto newRow = std::make_shared<QList<Base::Quantity>>();
for (auto column : *row) {
newRow->append(column);
}
addRow(depth, newRow);
}
}
}
bool Array3D::isNull() const
{
return isEmpty();
}
bool Array3D::isEmpty() const
{
return depth() <= 0;
}
void Material3DArray::validateDepth(int level) const
void Array3D::validateDepth(int level) const
{
if (level < 0 || level >= depth()) {
throw InvalidIndex();
}
}
void Material3DArray::validateColumn(int column) const
void Array3D::validateColumn(int column) const
{
if (column < 0 || column >= columns()) {
throw InvalidIndex();
}
}
void Material3DArray::validateRow(int level, int row) const
void Array3D::validateRow(int level, int row) const
{
validateDepth(level);
@@ -550,8 +678,18 @@ void Material3DArray::validateRow(int level, int row) const
}
}
void Array3D::validate(const Array3D& other) const
{
if (depth() != other.depth()) {
throw InvalidProperty("Material property value row counts don't match");
}
if (columns() != other.columns()) {
throw InvalidProperty("Material property value column counts don't match");
}
}
const std::shared_ptr<QList<std::shared_ptr<QList<Base::Quantity>>>>&
Material3DArray::getTable(const Base::Quantity& depth) const
Array3D::getTable(const Base::Quantity& depth) const
{
for (auto& it : _rowMap) {
if (std::get<0>(it) == depth) {
@@ -563,7 +701,7 @@ Material3DArray::getTable(const Base::Quantity& depth) const
}
const std::shared_ptr<QList<std::shared_ptr<QList<Base::Quantity>>>>&
Material3DArray::getTable(int depthIndex) const
Array3D::getTable(int depthIndex) const
{
try {
return std::get<1>(_rowMap.at(depthIndex));
@@ -573,7 +711,7 @@ Material3DArray::getTable(int depthIndex) const
}
}
std::shared_ptr<QList<Base::Quantity>> Material3DArray::getRow(int depth, int row) const
std::shared_ptr<QList<Base::Quantity>> Array3D::getRow(int depth, int row) const
{
validateRow(depth, row);
@@ -585,13 +723,13 @@ std::shared_ptr<QList<Base::Quantity>> Material3DArray::getRow(int depth, int ro
}
}
std::shared_ptr<QList<Base::Quantity>> Material3DArray::getRow(int row) const
std::shared_ptr<QList<Base::Quantity>> Array3D::getRow(int row) const
{
// Check if we can convert otherwise throw error
return getRow(_currentDepth, row);
}
std::shared_ptr<QList<Base::Quantity>> Material3DArray::getRow(int depth, int row)
std::shared_ptr<QList<Base::Quantity>> Array3D::getRow(int depth, int row)
{
validateRow(depth, row);
@@ -603,12 +741,12 @@ std::shared_ptr<QList<Base::Quantity>> Material3DArray::getRow(int depth, int ro
}
}
std::shared_ptr<QList<Base::Quantity>> Material3DArray::getRow(int row)
std::shared_ptr<QList<Base::Quantity>> Array3D::getRow(int row)
{
return getRow(_currentDepth, row);
}
void Material3DArray::addRow(int depth, const std::shared_ptr<QList<Base::Quantity>>& row)
void Array3D::addRow(int depth, const std::shared_ptr<QList<Base::Quantity>>& row)
{
try {
getTable(depth)->push_back(row);
@@ -618,12 +756,12 @@ void Material3DArray::addRow(int depth, const std::shared_ptr<QList<Base::Quanti
}
}
void Material3DArray::addRow(const std::shared_ptr<QList<Base::Quantity>>& row)
void Array3D::addRow(const std::shared_ptr<QList<Base::Quantity>>& row)
{
addRow(_currentDepth, row);
}
int Material3DArray::addDepth(int depth, const Base::Quantity& value)
int Array3D::addDepth(int depth, const Base::Quantity& value)
{
if (depth == this->depth()) {
// Append to the end
@@ -639,7 +777,7 @@ int Material3DArray::addDepth(int depth, const Base::Quantity& value)
return depth;
}
int Material3DArray::addDepth(const Base::Quantity& value)
int Array3D::addDepth(const Base::Quantity& value)
{
auto rowVector = std::make_shared<QList<std::shared_ptr<QList<Base::Quantity>>>>();
auto entry = std::make_pair(value, rowVector);
@@ -648,13 +786,22 @@ int Material3DArray::addDepth(const Base::Quantity& value)
return depth() - 1;
}
void Material3DArray::deleteDepth(int depth)
void Array3D::deleteDepth(int depth)
{
deleteRows(depth); // This may throw an InvalidIndex
_rowMap.erase(_rowMap.begin() + depth);
}
void Material3DArray::insertRow(int depth,
void Array3D::setDepth(int depthCount)
{
Base::Quantity dummy;
dummy.setInvalid();
while (depth() < depthCount) {
addDepth(dummy);
}
}
void Array3D::insertRow(int depth,
int row,
const std::shared_ptr<QList<Base::Quantity>>& rowData)
{
@@ -667,12 +814,12 @@ void Material3DArray::insertRow(int depth,
}
}
void Material3DArray::insertRow(int row, const std::shared_ptr<QList<Base::Quantity>>& rowData)
void Array3D::insertRow(int row, const std::shared_ptr<QList<Base::Quantity>>& rowData)
{
insertRow(_currentDepth, row, rowData);
}
void Material3DArray::deleteRow(int depth, int row)
void Array3D::deleteRow(int depth, int row)
{
auto table = getTable(depth);
if (row >= static_cast<int>(table->size()) || row < 0) {
@@ -681,23 +828,23 @@ void Material3DArray::deleteRow(int depth, int row)
table->erase(table->begin() + row);
}
void Material3DArray::deleteRow(int row)
void Array3D::deleteRow(int row)
{
deleteRow(_currentDepth, row);
}
void Material3DArray::deleteRows(int depth)
void Array3D::deleteRows(int depth)
{
auto table = getTable(depth);
table->clear();
}
void Material3DArray::deleteRows()
void Array3D::deleteRows()
{
deleteRows(_currentDepth);
}
int Material3DArray::rows(int depth) const
int Array3D::rows(int depth) const
{
if (depth < 0 || (depth == 0 && this->depth() == 0)) {
return 0;
@@ -707,7 +854,21 @@ int Material3DArray::rows(int depth) const
return getTable(depth)->size();
}
void Material3DArray::setValue(int depth, int row, int column, const Base::Quantity& value)
void Array3D::setRows(int depth, int rowCount)
{
Base::Quantity dummy;
dummy.setInvalid();
while (rows(depth) < rowCount) {
auto row = std::make_shared<QList<Base::Quantity>>();
for (int i = 0; i < columns(); i++) {
row->append(dummy);
}
addRow(depth, row);
}
}
void Array3D::setValue(int depth, int row, int column, const Base::Quantity& value)
{
validateRow(depth, row);
validateColumn(column);
@@ -721,12 +882,12 @@ void Material3DArray::setValue(int depth, int row, int column, const Base::Quant
}
}
void Material3DArray::setValue(int row, int column, const Base::Quantity& value)
void Array3D::setValue(int row, int column, const Base::Quantity& value)
{
setValue(_currentDepth, row, column, value);
}
void Material3DArray::setDepthValue(int depth, const Base::Quantity& value)
void Array3D::setDepthValue(int depth, const Base::Quantity& value)
{
try {
auto oldRows = getTable(depth);
@@ -737,13 +898,13 @@ void Material3DArray::setDepthValue(int depth, const Base::Quantity& value)
}
}
void Material3DArray::setDepthValue(const Base::Quantity& value)
void Array3D::setDepthValue(const Base::Quantity& value)
{
setDepthValue(_currentDepth, value);
}
Base::Quantity Material3DArray::getValue(int depth, int row, int column) const
Base::Quantity Array3D::getValue(int depth, int row, int column) const
{
// getRow validates depth and row. Do that first
auto val = getRow(depth, row);
@@ -757,12 +918,12 @@ Base::Quantity Material3DArray::getValue(int depth, int row, int column) const
}
}
Base::Quantity Material3DArray::getValue(int row, int column) const
Base::Quantity Array3D::getValue(int row, int column) const
{
return getValue(_currentDepth, row, column);
}
Base::Quantity Material3DArray::getDepthValue(int depth) const
Base::Quantity Array3D::getDepthValue(int depth) const
{
validateDepth(depth);
@@ -774,12 +935,12 @@ Base::Quantity Material3DArray::getDepthValue(int depth) const
}
}
int Material3DArray::currentDepth() const
int Array3D::currentDepth() const
{
return _currentDepth;
}
void Material3DArray::setCurrentDepth(int depth)
void Array3D::setCurrentDepth(int depth)
{
validateDepth(depth);
@@ -794,7 +955,7 @@ void Material3DArray::setCurrentDepth(int depth)
}
}
QString Material3DArray::getYAMLString() const
QString Array3D::getYAMLString() const
{
if (isNull()) {
return QString();

View File

@@ -91,6 +91,7 @@ public:
return _value.value<QList<QVariant>>();
}
virtual bool isNull() const;
virtual bool isEmpty() const;
virtual const QVariant getValueAt(const QVariant& value) const
{
@@ -111,6 +112,8 @@ public:
// The precision is based on the value from the original materials editor
static const int PRECISION = 6;
void validate(const MaterialValue& other) const;
protected:
MaterialValue(ValueType type, ValueType inherited);
@@ -133,18 +136,19 @@ private:
static QMap<QString, ValueType> _typeMap;
};
class MaterialsExport Material2DArray: public MaterialValue
class MaterialsExport Array2D: public MaterialValue
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
Material2DArray();
Material2DArray(const Material2DArray& other);
~Material2DArray() override = default;
Array2D();
Array2D(const Array2D& other);
~Array2D() override = default;
Material2DArray& operator=(const Material2DArray& other);
Array2D& operator=(const Array2D& other);
bool isNull() const override;
bool isEmpty() const override;
const QList<std::shared_ptr<QList<QVariant>>>& getArray() const
{
@@ -153,6 +157,7 @@ public:
void validateRow(int row) const;
void validateColumn(int column) const;
void validate(const Array2D& other) const;
std::shared_ptr<QList<QVariant>> getRow(int row) const;
std::shared_ptr<QList<QVariant>> getRow(int row);
@@ -171,6 +176,7 @@ public:
void addRow(const std::shared_ptr<QList<QVariant>>& row);
void insertRow(int index, const std::shared_ptr<QList<QVariant>>& row);
void deleteRow(int row);
void setRows(int rowCount);
void setValue(int row, int column, const QVariant& value);
QVariant getValue(int row, int column) const;
@@ -178,7 +184,7 @@ public:
QString getYAMLString() const override;
protected:
void deepCopy(const Material2DArray& other);
void deepCopy(const Array2D& other);
QList<std::shared_ptr<QList<QVariant>>> _rows;
int _columns;
@@ -188,15 +194,19 @@ private:
void dump() const;
};
class MaterialsExport Material3DArray: public MaterialValue
class MaterialsExport Array3D: public MaterialValue
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
Material3DArray();
~Material3DArray() override = default;
Array3D();
Array3D(const Array3D& other);
~Array3D() override = default;
Array3D& operator=(const Array3D& other);
bool isNull() const override;
bool isEmpty() const override;
const QList<
std::pair<Base::Quantity, std::shared_ptr<QList<std::shared_ptr<QList<Base::Quantity>>>>>>&
@@ -208,6 +218,7 @@ public:
void validateDepth(int level) const;
void validateColumn(int column) const;
void validateRow(int level, int row) const;
void validate(const Array3D& other) const;
const std::shared_ptr<QList<std::shared_ptr<QList<Base::Quantity>>>>&
getTable(const Base::Quantity& depth) const;
@@ -245,6 +256,8 @@ public:
{
_columns = size;
}
void setDepth(int depthCount);
void setRows(int depth, int rowCount);
void setValue(int depth, int row, int column, const Base::Quantity& value);
void setValue(int row, int column, const Base::Quantity& value);
@@ -260,6 +273,8 @@ public:
QString getYAMLString() const override;
protected:
void deepCopy(const Array3D& other);
QList<std::pair<Base::Quantity, std::shared_ptr<QList<std::shared_ptr<QList<Base::Quantity>>>>>>
_rowMap;
int _currentDepth;
@@ -269,7 +284,7 @@ protected:
} // namespace Materials
Q_DECLARE_METATYPE(Materials::MaterialValue)
Q_DECLARE_METATYPE(std::shared_ptr<Materials::Material2DArray>)
Q_DECLARE_METATYPE(std::shared_ptr<Materials::Material3DArray>)
Q_DECLARE_METATYPE(std::shared_ptr<Materials::Array2D>)
Q_DECLARE_METATYPE(std::shared_ptr<Materials::Array3D>)
#endif // MATERIAL_MATERIALVALUE_H

View File

@@ -65,11 +65,11 @@ void MaterialProperty::copyValuePtr(const std::shared_ptr<MaterialValue>& value)
{
if (value->getType() == MaterialValue::Array2D) {
_valuePtr =
std::make_shared<Material2DArray>(*(std::static_pointer_cast<Material2DArray>(value)));
std::make_shared<Array2D>(*(std::static_pointer_cast<Array2D>(value)));
}
else if (value->getType() == MaterialValue::Array3D) {
_valuePtr =
std::make_shared<Material3DArray>(*(std::static_pointer_cast<Material3DArray>(value)));
std::make_shared<Array3D>(*(std::static_pointer_cast<Array3D>(value)));
}
else {
_valuePtr = std::make_shared<MaterialValue>(*value);
@@ -132,7 +132,7 @@ QString MaterialProperty::getString() const
if (value.isNull()) {
return {};
}
return QString(QLatin1String("%L1")).arg(value.toFloat(), 0, 'g', MaterialValue::PRECISION);
return QString(QStringLiteral("%L1")).arg(value.toFloat(), 0, 'g', MaterialValue::PRECISION);
}
return getValue().toString();
}
@@ -177,7 +177,7 @@ QString MaterialProperty::getDictionaryString() const
}
if (getType() == MaterialValue::Quantity) {
auto quantity = getValue().value<Base::Quantity>();
auto string = QString(QLatin1String("%1 %2"))
auto string = QString(QStringLiteral("%1 %2"))
.arg(quantity.getValue(), 0, 'g', MaterialValue::PRECISION)
.arg(QString::fromStdString(quantity.getUnit().getString()));
return string;
@@ -187,7 +187,7 @@ QString MaterialProperty::getDictionaryString() const
if (value.isNull()) {
return {};
}
return QString(QLatin1String("%1")).arg(value.toFloat(), 0, 'g', MaterialValue::PRECISION);
return QString(QStringLiteral("%1")).arg(value.toFloat(), 0, 'g', MaterialValue::PRECISION);
}
return getValue().toString();
}
@@ -205,12 +205,12 @@ void MaterialProperty::setType(const QString& type)
throw UnknownValueType();
}
if (mappedType == MaterialValue::Array2D) {
auto arrayPtr = std::make_shared<Material2DArray>();
auto arrayPtr = std::make_shared<Array2D>();
arrayPtr->setColumns(columns());
_valuePtr = arrayPtr;
}
else if (mappedType == MaterialValue::Array3D) {
auto arrayPtr = std::make_shared<Material3DArray>();
auto arrayPtr = std::make_shared<Array3D>();
// First column is third dimension
arrayPtr->setColumns(columns() - 1);
_valuePtr = arrayPtr;
@@ -448,6 +448,17 @@ bool MaterialProperty::operator==(const MaterialProperty& other) const
return false;
}
void MaterialProperty::validate(const MaterialProperty& other) const {
_valuePtr->validate(*other._valuePtr);
if (_columns.size() != other._columns.size()) {
throw InvalidProperty("Model property column counts don't match");
}
for (size_t i = 0; i < _columns.size(); i++) {
_columns[i].validate(other._columns[i]);
}
}
TYPESYSTEM_SOURCE(Materials::Material, Base::BaseClass)
Material::Material()
@@ -476,6 +487,7 @@ Material::Material(const std::shared_ptr<MaterialLibrary>& library,
Material::Material(const Material& other)
: _library(other._library)
, _directory(other._directory)
, _filename(other._filename)
, _uuid(other._uuid)
, _name(other._name)
, _author(other._author)
@@ -513,6 +525,31 @@ Material::Material(const Material& other)
}
}
QString Material::getDirectory() const
{
return _directory;
}
void Material::setDirectory(const QString& directory)
{
_directory = directory;
}
QString Material::getFilename() const
{
return _filename;
}
void Material::setFilename(const QString& filename)
{
_filename = filename;
}
QString Material::getFilePath() const
{
return QDir(_directory + QStringLiteral("/") + _filename).absolutePath();
}
QString Material::getAuthorAndLicense() const
{
QString authorAndLicense;
@@ -521,7 +558,7 @@ QString Material::getAuthorAndLicense() const
if (!_author.isNull()) {
authorAndLicense = _author;
if (!_license.isNull()) {
authorAndLicense += QLatin1String(" ") + _license;
authorAndLicense += QStringLiteral(" ") + _license;
}
}
else if (!_license.isNull()) {
@@ -541,7 +578,7 @@ void Material::addModel(const QString& uuid)
_allUuids << uuid;
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -641,7 +678,7 @@ void Material::addPhysical(const QString& uuid)
return;
}
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -688,7 +725,7 @@ void Material::removePhysical(const QString& uuid)
return;
}
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -718,7 +755,7 @@ void Material::addAppearance(const QString& uuid)
return;
}
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -759,7 +796,7 @@ void Material::removeAppearance(const QString& uuid)
return;
}
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -938,6 +975,22 @@ void Material::setValue(const QString& name, const QVariant& value)
if (hasPhysicalProperty(name)) {
setPhysicalValue(name, value);
}
else if (hasAppearanceProperty(name)) {
setAppearanceValue(name, value);
}
else {
throw PropertyNotFound();
}
}
void Material::setValue(const QString& name, const std::shared_ptr<MaterialValue>& value)
{
if (hasPhysicalProperty(name)) {
setPhysicalValue(name, value);
}
else if (hasAppearanceProperty(name)) {
setAppearanceValue(name, value);
}
else {
throw PropertyNotFound();
}
@@ -1045,7 +1098,7 @@ Material::getValueString(const std::map<QString, std::shared_ptr<MaterialPropert
if (value.isNull()) {
return {};
}
return QString(QLatin1String("%L1"))
return QString(QStringLiteral("%L1"))
.arg(value.toFloat(), 0, 'g', MaterialValue::PRECISION);
}
return property->getValue().toString();
@@ -1141,7 +1194,7 @@ bool Material::hasPhysicalModel(const QString& uuid) const
return false;
}
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -1161,7 +1214,7 @@ bool Material::hasAppearanceModel(const QString& uuid) const
return false;
}
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -1181,7 +1234,7 @@ bool Material::isPhysicalModelComplete(const QString& uuid) const
return false;
}
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -1207,7 +1260,7 @@ bool Material::isAppearanceModelComplete(const QString& uuid) const
return false;
}
ModelManager manager;
auto manager = ModelManager::getManager();
try {
auto model = manager.getModel(uuid);
@@ -1252,10 +1305,8 @@ void Material::saveGeneral(QTextStream& stream) const
void Material::saveInherits(QTextStream& stream) const
{
if (!_parentUuid.isEmpty()) {
MaterialManager manager;
try {
auto material = manager.getMaterial(_parentUuid);
auto material = MaterialManager::getManager().getMaterial(_parentUuid);
stream << "Inherits:\n";
stream << " " << material->getName() << ":\n";
@@ -1314,8 +1365,8 @@ void Material::saveModels(QTextStream& stream, bool saveInherited) const
return;
}
ModelManager modelManager;
MaterialManager materialManager;
auto modelManager = ModelManager::getManager();
auto materialManager = MaterialManager::getManager();
bool inherited = saveInherited && (_parentUuid.size() > 0);
std::shared_ptr<Material> parent;
@@ -1368,8 +1419,8 @@ void Material::saveAppearanceModels(QTextStream& stream, bool saveInherited) con
return;
}
ModelManager modelManager;
MaterialManager materialManager;
auto modelManager = ModelManager::getManager();
auto materialManager = MaterialManager::getManager();
bool inherited = saveInherited && (_parentUuid.size() > 0);
std::shared_ptr<Material> parent;
@@ -1421,7 +1472,7 @@ void Material::newUuid()
QString Material::getModelByName(const QString& name) const
{
ModelManager manager;
auto manager = ModelManager::getManager();
for (auto& it : _allUuids) {
try {
@@ -1442,8 +1493,7 @@ void Material::save(QTextStream& stream, bool overwrite, bool saveAsCopy, bool s
if (saveInherited && !saveAsCopy) {
// Check to see if we're an original or if we're already in the list of
// models
MaterialManager materialManager;
if (materialManager.exists(_uuid) && !overwrite) {
if (MaterialManager::getManager().exists(_uuid) && !overwrite) {
// Make a new version based on the current
setParentUUID(_uuid);
}
@@ -1494,6 +1544,7 @@ Material& Material::operator=(const Material& other)
_library = other._library;
_directory = other._directory;
_filename = other._filename;
_uuid = other._uuid;
_name = other._name;
_author = other._author;
@@ -1548,20 +1599,20 @@ Material& Material::operator=(const App::Material& other)
addAppearance(ModelUUIDs::ModelUUID_Rendering_Basic);
}
getAppearanceProperty(QLatin1String("AmbientColor"))->setColor(other.ambientColor);
getAppearanceProperty(QLatin1String("DiffuseColor"))->setColor(other.diffuseColor);
getAppearanceProperty(QLatin1String("SpecularColor"))->setColor(other.specularColor);
getAppearanceProperty(QLatin1String("EmissiveColor"))->setColor(other.emissiveColor);
getAppearanceProperty(QLatin1String("Shininess"))->setFloat(other.shininess);
getAppearanceProperty(QLatin1String("Transparency"))->setFloat(other.transparency);
getAppearanceProperty(QStringLiteral("AmbientColor"))->setColor(other.ambientColor);
getAppearanceProperty(QStringLiteral("DiffuseColor"))->setColor(other.diffuseColor);
getAppearanceProperty(QStringLiteral("SpecularColor"))->setColor(other.specularColor);
getAppearanceProperty(QStringLiteral("EmissiveColor"))->setColor(other.emissiveColor);
getAppearanceProperty(QStringLiteral("Shininess"))->setFloat(other.shininess);
getAppearanceProperty(QStringLiteral("Transparency"))->setFloat(other.transparency);
if (!other.image.empty() || !other.imagePath.empty()) {
if (!hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Texture)) {
addAppearance(ModelUUIDs::ModelUUID_Rendering_Texture);
}
getAppearanceProperty(QLatin1String("TextureImage"))->setString(other.image);
getAppearanceProperty(QLatin1String("TexturePath"))->setString(other.imagePath);
getAppearanceProperty(QStringLiteral("TextureImage"))->setString(other.image);
getAppearanceProperty(QStringLiteral("TexturePath"))->setString(other.imagePath);
}
return *this;
@@ -1574,7 +1625,7 @@ QStringList Material::normalizeModels(const QStringList& models)
{
QStringList normalized;
ModelManager manager;
auto manager = ModelManager::getManager();
for (auto& uuid : models) {
auto model = manager.getModel(uuid);
@@ -1652,32 +1703,32 @@ App::Material Material::getMaterialAppearance() const
App::Material material(App::Material::DEFAULT);
bool custom = false;
if (hasAppearanceProperty(QLatin1String("AmbientColor"))) {
material.ambientColor = getAppearanceProperty(QLatin1String("AmbientColor"))->getColor();
if (hasAppearanceProperty(QStringLiteral("AmbientColor"))) {
material.ambientColor = getAppearanceProperty(QStringLiteral("AmbientColor"))->getColor();
custom = true;
}
if (hasAppearanceProperty(QLatin1String("DiffuseColor"))) {
material.diffuseColor = getAppearanceProperty(QLatin1String("DiffuseColor"))->getColor();
if (hasAppearanceProperty(QStringLiteral("DiffuseColor"))) {
material.diffuseColor = getAppearanceProperty(QStringLiteral("DiffuseColor"))->getColor();
custom = true;
}
if (hasAppearanceProperty(QLatin1String("SpecularColor"))) {
material.specularColor = getAppearanceProperty(QLatin1String("SpecularColor"))->getColor();
if (hasAppearanceProperty(QStringLiteral("SpecularColor"))) {
material.specularColor = getAppearanceProperty(QStringLiteral("SpecularColor"))->getColor();
custom = true;
}
if (hasAppearanceProperty(QLatin1String("EmissiveColor"))) {
material.emissiveColor = getAppearanceProperty(QLatin1String("EmissiveColor"))->getColor();
if (hasAppearanceProperty(QStringLiteral("EmissiveColor"))) {
material.emissiveColor = getAppearanceProperty(QStringLiteral("EmissiveColor"))->getColor();
custom = true;
}
if (hasAppearanceProperty(QLatin1String("Shininess"))) {
material.shininess = getAppearanceProperty(QLatin1String("Shininess"))->getFloat();
if (hasAppearanceProperty(QStringLiteral("Shininess"))) {
material.shininess = getAppearanceProperty(QStringLiteral("Shininess"))->getFloat();
custom = true;
}
if (hasAppearanceProperty(QLatin1String("Transparency"))) {
material.transparency = getAppearanceProperty(QLatin1String("Transparency"))->getFloat();
if (hasAppearanceProperty(QStringLiteral("Transparency"))) {
material.transparency = getAppearanceProperty(QStringLiteral("Transparency"))->getFloat();
custom = true;
}
if (hasAppearanceProperty(QLatin1String("TextureImage"))) {
auto property = getAppearanceProperty(QLatin1String("TextureImage"));
if (hasAppearanceProperty(QStringLiteral("TextureImage"))) {
auto property = getAppearanceProperty(QStringLiteral("TextureImage"));
if (!property->isNull()) {
Base::Console().Log("Has 'TextureImage'\n");
material.image = property->getString().toStdString();
@@ -1685,8 +1736,8 @@ App::Material Material::getMaterialAppearance() const
custom = true;
}
else if (hasAppearanceProperty(QLatin1String("TexturePath"))) {
auto property = getAppearanceProperty(QLatin1String("TexturePath"));
else if (hasAppearanceProperty(QStringLiteral("TexturePath"))) {
auto property = getAppearanceProperty(QStringLiteral("TexturePath"));
if (!property->isNull()) {
Base::Console().Log("Has 'TexturePath'\n");
material.imagePath = property->getString().toStdString();
@@ -1702,3 +1753,98 @@ App::Material Material::getMaterialAppearance() const
return material;
}
void Material::validate(const std::shared_ptr<Material>& other) const
{
try {
_library->validate(*(other->_library));
}
catch (const InvalidLibrary& e) {
throw InvalidMaterial(e.what());
}
if (_directory != other->_directory) {
throw InvalidMaterial("Model directories don't match");
}
if (!other->_filename.isEmpty()) {
throw InvalidMaterial("Remote filename is not empty");
}
if (_uuid != other->_uuid) {
throw InvalidMaterial("Model UUIDs don't match");
}
if (_name != other->_name) {
throw InvalidMaterial("Model names don't match");
}
if (_author != other->_author) {
throw InvalidMaterial("Model authors don't match");
}
if (_license != other->_license) {
throw InvalidMaterial("Model licenses don't match");
}
if (_parentUuid != other->_parentUuid) {
throw InvalidMaterial("Model parents don't match");
}
if (_description != other->_description) {
throw InvalidMaterial("Model descriptions don't match");
}
if (_url != other->_url) {
throw InvalidMaterial("Model URLs don't match");
}
if (_reference != other->_reference) {
throw InvalidMaterial("Model references don't match");
}
if (_tags.size() != other->_tags.size()) {
Base::Console().Log("Local tags count %d\n", _tags.size());
Base::Console().Log("Remote tags count %d\n", other->_tags.size());
throw InvalidMaterial("Material tags counts don't match");
}
if (!other->_tags.contains(_tags)) {
throw InvalidMaterial("Material tags don't match");
}
if (_physicalUuids.size() != other->_physicalUuids.size()) {
Base::Console().Log("Local physical model count %d\n", _physicalUuids.size());
Base::Console().Log("Remote physical model count %d\n", other->_physicalUuids.size());
throw InvalidMaterial("Material physical model counts don't match");
}
if (!other->_physicalUuids.contains(_physicalUuids)) {
throw InvalidMaterial("Material physical models don't match");
}
if (_physicalUuids.size() != other->_physicalUuids.size()) {
Base::Console().Log("Local appearance model count %d\n", _physicalUuids.size());
Base::Console().Log("Remote appearance model count %d\n", other->_physicalUuids.size());
throw InvalidMaterial("Material appearance model counts don't match");
}
if (!other->_physicalUuids.contains(_physicalUuids)) {
throw InvalidMaterial("Material appearance models don't match");
}
if (_allUuids.size() != other->_allUuids.size()) {
Base::Console().Log("Local model count %d\n", _allUuids.size());
Base::Console().Log("Remote model count %d\n", other->_allUuids.size());
throw InvalidMaterial("Material model counts don't match");
}
if (!other->_allUuids.contains(_allUuids)) {
throw InvalidMaterial("Material models don't match");
}
// Need to compare properties
if (_physical.size() != other->_physical.size()) {
throw InvalidMaterial("Material physical property counts don't match");
}
for (auto& property : _physical) {
auto& remote = other->_physical[property.first];
property.second->validate(*remote);
}
if (_appearance.size() != other->_appearance.size()) {
throw InvalidMaterial("Material appearance property counts don't match");
}
for (auto& property : _appearance) {
auto& remote = other->_appearance[property.first];
property.second->validate(*remote);
}
}

View File

@@ -80,6 +80,10 @@ public:
{
return _valuePtr->isNull();
}
bool isEmpty() const
{
return _valuePtr->isEmpty();
}
std::shared_ptr<MaterialValue> getMaterialValue();
std::shared_ptr<MaterialValue> getMaterialValue() const;
QString getString() const;
@@ -109,6 +113,10 @@ public:
MaterialValue::ValueType getColumnType(int column) const;
QString getColumnUnits(int column) const;
QVariant getColumnNull(int column) const;
const std::vector<MaterialProperty>& getColumns() const
{
return _columns;
}
void setModelUUID(const QString& uuid);
void setPropertyType(const QString& type) override;
@@ -140,6 +148,11 @@ public:
return !operator==(other);
}
void validate(const MaterialProperty& other) const;
// Define precision for displaying floating point values
static int const PRECISION;
protected:
void setType(const QString& type);
// void setType(MaterialValue::ValueType type) { _valueType = type; }
@@ -180,10 +193,9 @@ public:
{
return _library;
}
QString getDirectory() const
{
return _directory;
}
QString getDirectory() const;
QString getFilename() const;
QString getFilePath() const;
QString getUUID() const
{
return _uuid;
@@ -240,10 +252,8 @@ public:
{
_library = library;
}
void setDirectory(const QString& directory)
{
_directory = directory;
}
void setDirectory(const QString& directory);
void setFilename(const QString& filename);
void setUUID(const QString& uuid)
{
_uuid = uuid;
@@ -303,6 +313,7 @@ public:
void setValue(const QString& name, const QString& value);
void setValue(const QString& name, const QVariant& value);
void setValue(const QString& name, const std::shared_ptr<MaterialValue>& value);
/*
* Legacy values are thosed contained in old format files that don't fit in the new
@@ -432,6 +443,8 @@ public:
return getTypeId() == other.getTypeId() && _uuid == other._uuid;
}
void validate(const std::shared_ptr<Material>& other) const;
protected:
void addModel(const QString& uuid);
static void removeUUID(QSet<QString>& uuidList, const QString& uuid);
@@ -455,6 +468,7 @@ protected:
private:
std::shared_ptr<MaterialLibrary> _library;
QString _directory;
QString _filename;
QString _uuid;
QString _name;
QString _author;

View File

@@ -101,11 +101,49 @@ bool ModelProperty::operator==(const ModelProperty& other) const
return true;
}
return (_name == other._name) && (_displayName == other._displayName) && (_propertyType == other._propertyType)
&& (_units == other._units) && (_url == other._url) && (_description == other._description)
return (_name == other._name) && (_displayName == other._displayName)
&& (_propertyType == other._propertyType) && (_units == other._units)
&& (_url == other._url) && (_description == other._description)
&& (_inheritance == other._inheritance);
}
void ModelProperty::validate(const ModelProperty& other) const
{
if (_name != other._name) {
throw InvalidProperty("Model names don't match");
}
if (getDisplayName() != other.getDisplayName()) {
Base::Console().Log("Local display name '%s'\n", getDisplayName().toStdString().c_str());
Base::Console().Log("Remote display name '%s'\n",
other.getDisplayName().toStdString().c_str());
throw InvalidProperty("Model display names don't match");
}
if (_propertyType != other._propertyType) {
throw InvalidProperty("Model property types don't match");
}
if (_units != other._units) {
throw InvalidProperty("Model units don't match");
}
if (_url != other._url) {
throw InvalidProperty("Model URLs don't match");
}
if (_description != other._description) {
throw InvalidProperty("Model descriptions don't match");
}
if (_inheritance != other._inheritance) {
throw InvalidProperty("Model inheritance don't match");
}
if (_columns.size() != other._columns.size()) {
Base::Console().Log("Local property column count %d\n", _columns.size());
Base::Console().Log("Remote property column count %d\n", other._columns.size());
throw InvalidProperty("Model property column counts don't match");
}
for (size_t i = 0; i < _columns.size(); i++) {
_columns[i].validate(other._columns[i]);
}
}
TYPESYSTEM_SOURCE(Materials::Model, Base::BaseClass)
Model::Model()
@@ -129,6 +167,31 @@ Model::Model(std::shared_ptr<ModelLibrary> library,
, _doi(doi)
{}
QString Model::getDirectory() const
{
return _directory;
}
void Model::setDirectory(const QString& directory)
{
_directory = directory;
}
QString Model::getFilename() const
{
return _filename;
}
void Model::setFilename(const QString& filename)
{
_filename = filename;
}
QString Model::getFilePath() const
{
return QDir(_directory + QStringLiteral("/") + _filename).absolutePath();
}
ModelProperty& Model::operator[](const QString& key)
{
try {
@@ -138,3 +201,54 @@ ModelProperty& Model::operator[](const QString& key)
throw PropertyNotFound();
}
}
void Model::validate(const std::shared_ptr<Model>& other) const
{
try {
_library->validate(*(other->_library));
}
catch (const InvalidLibrary& e)
{
throw InvalidModel(e.what());
}
// std::map<QString, ModelProperty> _properties;
if (_type != other->_type) {
throw InvalidModel("Model types don't match");
}
if (_name != other->_name) {
throw InvalidModel("Model names don't match");
}
if (_directory != other->_directory) {
throw InvalidModel("Model directories don't match");
}
if (!other->_filename.isEmpty()) {
throw InvalidModel("Remote filename is not empty");
}
if (_uuid != other->_uuid) {
throw InvalidModel("Model UUIDs don't match");
}
if (_description != other->_description) {
throw InvalidModel("Model descriptions don't match");
}
if (_url != other->_url) {
throw InvalidModel("Model URLs don't match");
}
if (_doi != other->_doi) {
throw InvalidModel("Model DOIs don't match");
}
if (_inheritedUuids != other->_inheritedUuids) {
throw InvalidModel("Model inherited UUIDs don't match");
}
// Need to compare properties
if (_properties.size() != other->_properties.size()) {
// Base::Console().Log("Local property count %d\n", _properties.size());
// Base::Console().Log("Remote property count %d\n", other->_properties.size());
throw InvalidModel("Model property counts don't match");
}
for (auto& property : _properties) {
auto& remote = other->_properties[property.first];
property.second.validate(remote);
}
}

View File

@@ -98,7 +98,7 @@ public:
{
_name = name;
}
void setColumnHeader(const QString& header)
void setDisplayName(const QString& header)
{
_displayName = header;
}
@@ -143,6 +143,8 @@ public:
return !operator==(other);
}
void validate(const ModelProperty& other) const;
private:
QString _name;
QString _displayName;
@@ -180,12 +182,12 @@ public:
{
return _library;
}
const QString getBase() const
QString getBase() const
{
return (_type == ModelType_Physical) ? QStringLiteral("Model")
: QStringLiteral("AppearanceModel");
}
const QString getName() const
QString getName() const
{
return _name;
}
@@ -193,27 +195,22 @@ public:
{
return _type;
}
const QString getDirectory() const
{
return _directory;
}
const QString getDirectoryPath() const
{
return QDir(_directory).absolutePath();
}
const QString getUUID() const
QString getDirectory() const;
QString getFilename() const;
QString getFilePath() const;
QString getUUID() const
{
return _uuid;
}
const QString getDescription() const
QString getDescription() const
{
return _description;
}
const QString getURL() const
QString getURL() const
{
return _url;
}
const QString getDOI() const
QString getDOI() const
{
return _doi;
}
@@ -230,10 +227,8 @@ public:
{
_name = name;
}
void setDirectory(const QString& directory)
{
_directory = directory;
}
void setDirectory(const QString& directory);
void setFilename(const QString& filename);
void setUUID(const QString& uuid)
{
_uuid = uuid;
@@ -306,11 +301,14 @@ public:
return _properties.cend();
}
void validate(const std::shared_ptr<Model>& other) const;
private:
std::shared_ptr<ModelLibrary> _library;
ModelType _type;
QString _name;
QString _directory;
QString _filename;
QString _uuid;
QString _description;
QString _url;

View File

@@ -24,6 +24,8 @@
#include <string>
#endif
#include <QFileInfo>
#include <App/Application.h>
#include "Exceptions.h"
@@ -34,79 +36,13 @@
using namespace Materials;
TYPESYSTEM_SOURCE(Materials::LibraryBase, Base::BaseClass)
TYPESYSTEM_SOURCE(Materials::ModelLibrary, Materials::Library)
LibraryBase::LibraryBase(const QString& libraryName, const QString& dir, const QString& icon)
: _name(libraryName)
, _directory(QDir::cleanPath(dir))
, _iconPath(icon)
{}
bool LibraryBase::operator==(const LibraryBase& library) const
{
return (_name == library._name) && (_directory == library._directory);
}
QString LibraryBase::getLocalPath(const QString& path) const
{
QString filePath = getDirectoryPath();
if (!(filePath.endsWith(QLatin1String("/")) || filePath.endsWith(QLatin1String("\\")))) {
filePath += QLatin1String("/");
}
QString cleanPath = QDir::cleanPath(path);
QString prefix = QStringLiteral("/") + getName();
if (cleanPath.startsWith(prefix)) {
// Remove the library name from the path
filePath += cleanPath.right(cleanPath.length() - prefix.length());
}
else {
filePath += cleanPath;
}
return filePath;
}
bool LibraryBase::isRoot(const QString& path) const
{
QString localPath = getLocalPath(path);
QString cleanPath = getLocalPath(QStringLiteral(""));
std::string pLocal = localPath.toStdString();
std::string pclean = cleanPath.toStdString();
return (cleanPath == localPath);
}
QString LibraryBase::getRelativePath(const QString& path) const
{
QString filePath;
QString cleanPath = QDir::cleanPath(path);
QString prefix = QStringLiteral("/") + 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(QStringLiteral("/"))) {
filePath.remove(0, 1);
}
return filePath;
}
TYPESYSTEM_SOURCE(Materials::ModelLibrary, Materials::LibraryBase)
ModelLibrary::ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon)
: LibraryBase(libraryName, dir, icon)
ModelLibrary::ModelLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly)
: Library(libraryName, dir, icon, readOnly)
{
_modelPathMap = std::make_unique<std::map<QString, std::shared_ptr<Model>>>();
}
@@ -131,9 +67,11 @@ std::shared_ptr<Model> ModelLibrary::getModelByPath(const QString& path) const
std::shared_ptr<Model> ModelLibrary::addModel(const Model& model, const QString& path)
{
QString filePath = getRelativePath(path);
QFileInfo info(filePath);
std::shared_ptr<Model> newModel = std::make_shared<Model>(model);
newModel->setLibrary(getptr());
newModel->setDirectory(filePath);
newModel->setDirectory(getLibraryPath(filePath, info.fileName()));
newModel->setFilename(info.fileName());
(*_modelPathMap)[filePath] = newModel;
@@ -158,6 +96,7 @@ ModelLibrary::getModelTree(ModelFilter filter) const
for (auto& itp : list) {
if (ModelManager::isModel(itp)) {
std::shared_ptr<ModelTreeNode> child = std::make_shared<ModelTreeNode>();
child->setUUID(model->getUUID());
child->setData(model);
(*node)[itp] = child;
}

View File

@@ -32,68 +32,28 @@
#include <Mod/Material/MaterialGlobal.h>
#include "Library.h"
#include "MaterialValue.h"
#include "Model.h"
namespace Materials
{
// class Model;
class MaterialsExport LibraryBase: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
LibraryBase() = default;
LibraryBase(const QString& libraryName, const QString& dir, const QString& icon);
~LibraryBase() override = 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;
bool isRoot(const QString& path) const;
private:
LibraryBase(const LibraryBase&);
QString _name;
QString _directory;
QString _iconPath;
};
class MaterialsExport ModelLibrary: public LibraryBase,
class MaterialsExport ModelLibrary: public Library,
public std::enable_shared_from_this<ModelLibrary>
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
ModelLibrary();
ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon);
ModelLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
~ModelLibrary() override = default;
bool operator==(const ModelLibrary& library) const
{
return LibraryBase::operator==(library);
return Library::operator==(library);
}
bool operator!=(const ModelLibrary& library) const
{
@@ -119,4 +79,6 @@ private:
} // namespace Materials
Q_DECLARE_METATYPE(std::shared_ptr<Materials::ModelLibrary>)
#endif // MATERIAL_MODELLIBRARY_H

View File

@@ -26,118 +26,141 @@
#include <QDirIterator>
#include <QMutexLocker>
#include <App/Application.h>
#include <Base/Console.h>
#include "Model.h"
#include "ModelLoader.h"
#include "ModelManager.h"
#include "ModelManagerLocal.h"
using namespace Materials;
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> ModelManager::_libraryList = nullptr;
std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> ModelManager::_modelMap = nullptr;
QMutex ModelManager::_mutex;
TYPESYSTEM_SOURCE(Materials::ModelManager, Base::BaseClass)
QMutex ModelManager::_mutex;
ModelManager* ModelManager::_manager = nullptr;
std::unique_ptr<ModelManagerLocal> ModelManager::_localManager;
ModelManager::ModelManager()
{}
ModelManager::~ModelManager()
{}
ModelManager& ModelManager::getManager()
{
initLibraries();
if (!_manager) {
initManagers();
}
return *_manager;
}
void ModelManager::initLibraries()
void ModelManager::initManagers()
{
QMutexLocker locker(&_mutex);
if (_modelMap == nullptr) {
_modelMap = std::make_shared<std::map<QString, std::shared_ptr<Model>>>();
if (_libraryList == nullptr) {
_libraryList = std::make_shared<std::list<std::shared_ptr<ModelLibrary>>>();
}
// Load the libraries
ModelLoader loader(_modelMap, _libraryList);
if (!_manager) {
// Can't use smart pointers for this since the constructor is private
_manager = new ModelManager();
}
if (!_localManager) {
_localManager = std::make_unique<ModelManagerLocal>();
}
}
bool ModelManager::isModel(const QString& file)
{
// if (!fs::is_regular_file(p))
// return false;
// check file extension
if (file.endsWith(QStringLiteral(".yml"))) {
return true;
}
return false;
return ModelManagerLocal::isModel(file);
}
void ModelManager::cleanup()
{
if (_libraryList) {
_libraryList->clear();
}
if (_modelMap) {
for (auto& it : *_modelMap) {
// This is needed to resolve cyclic dependencies
it.second->setLibrary(nullptr);
}
_modelMap->clear();
}
return ModelManagerLocal::cleanup();
}
void ModelManager::refresh()
{
_modelMap->clear();
_libraryList->clear();
_localManager->refresh();
}
// Load the libraries
ModelLoader loader(_modelMap, _libraryList);
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> ModelManager::getLibraries()
{
return _localManager->getLibraries();
}
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> ModelManager::getLocalLibraries()
{
return _localManager->getLibraries();
}
void ModelManager::createLibrary(const QString& libraryName, const QString& icon, bool readOnly)
{}
void ModelManager::createLocalLibrary(const QString& libraryName,
const QString& directory,
const QString& icon,
bool readOnly)
{
_localManager->createLibrary(libraryName, directory, icon, readOnly);
}
void ModelManager::renameLibrary(const QString& libraryName, const QString& newName)
{
_localManager->renameLibrary(libraryName, newName);
}
void ModelManager::changeIcon(const QString& libraryName, const QString& icon)
{
_localManager->changeIcon(libraryName, icon);
}
void ModelManager::removeLibrary(const QString& libraryName)
{
_localManager->removeLibrary(libraryName);
}
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
ModelManager::libraryModels(const QString& libraryName)
{
return _localManager->libraryModels(libraryName);
}
bool ModelManager::isLocalLibrary(const QString& libraryName)
{
return true;
}
std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> ModelManager::getModels()
{
return _localManager->getModels();
}
std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> ModelManager::getLocalModels()
{
return _localManager->getModels();
}
std::shared_ptr<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();
}
return _localManager->getModel(uuid);
}
std::shared_ptr<Model> ModelManager::getModelByPath(const QString& path) const
{
QString cleanPath = QDir::cleanPath(path);
for (auto& library : *_libraryList) {
if (cleanPath.startsWith(library->getDirectory())) {
return library->getModelByPath(cleanPath);
}
}
throw MaterialNotFound();
return _localManager->getModelByPath(path);
}
std::shared_ptr<Model> ModelManager::getModelByPath(const QString& path, const QString& lib) const
{
auto library = getLibrary(lib); // May throw LibraryNotFound
return library->getModelByPath(path); // May throw ModelNotFound
return _localManager->getModelByPath(path, lib);
}
std::shared_ptr<ModelLibrary> ModelManager::getLibrary(const QString& name) const
{
for (auto& library : *_libraryList) {
if (library->getName() == name) {
return library;
}
}
throw LibraryNotFound();
return _localManager->getLibrary(name);
}
bool ModelManager::passFilter(ModelFilter filter, Model::ModelType modelType)

View File

@@ -24,6 +24,7 @@
#include <memory>
#include <Base/Parameter.h>
#include <Mod/Material/MaterialGlobal.h>
#include <QMutex>
@@ -35,26 +36,37 @@
namespace Materials
{
class ModelManagerLocal;
class ModelManagerExternal;
class MaterialsExport ModelManager: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
ModelManager();
~ModelManager() override = default;
~ModelManager() override;
static ModelManager& getManager();
static void cleanup();
void refresh();
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> getModelLibraries()
{
return _libraryList;
}
std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> getModels()
{
return _modelMap;
}
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> getLibraries();
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> getLocalLibraries();
void createLibrary(const QString& libraryName, const QString& icon, bool readOnly = true);
void createLocalLibrary(const QString& libraryName,
const QString& directory,
const QString& icon,
bool readOnly = true);
void renameLibrary(const QString& libraryName, const QString& newName);
void changeIcon(const QString& libraryName, const QString& icon);
void removeLibrary(const QString& libraryName);
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
libraryModels(const QString& libraryName);
bool isLocalLibrary(const QString& libraryName);
std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> getModels();
std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> getLocalModels();
std::shared_ptr<std::map<QString, std::shared_ptr<ModelTreeNode>>>
getModelTree(std::shared_ptr<ModelLibrary> library, ModelFilter filter = ModelFilter_None) const
{
@@ -69,13 +81,14 @@ public:
static bool passFilter(ModelFilter filter, Model::ModelType modelType);
private:
static void initLibraries();
ModelManager();
static void initManagers();
static std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> _libraryList;
static std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> _modelMap;
static ModelManager* _manager;
static std::unique_ptr<ModelManagerLocal> _localManager;
static QMutex _mutex;
};
} // namespace Materials
#endif // MATERIAL_MODELMANAGER_H
#endif // MATERIAL_MODELMANAGER_H

View File

@@ -0,0 +1,219 @@
/***************************************************************************
* Copyright (c) 2024 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <QDirIterator>
#include <QMutexLocker>
#include <Base/Console.h>
#include "Model.h"
#include "ModelLoader.h"
#include "ModelManagerLocal.h"
using namespace Materials;
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> ModelManagerLocal::_libraryList = nullptr;
std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> ModelManagerLocal::_modelMap = nullptr;
QMutex ModelManagerLocal::_mutex;
TYPESYSTEM_SOURCE(Materials::ModelManagerLocal, Base::BaseClass)
ModelManagerLocal::ModelManagerLocal()
{
initLibraries();
}
void ModelManagerLocal::initLibraries()
{
QMutexLocker locker(&_mutex);
if (_modelMap == nullptr) {
_modelMap = std::make_shared<std::map<QString, std::shared_ptr<Model>>>();
if (_libraryList == nullptr) {
_libraryList = std::make_shared<std::list<std::shared_ptr<ModelLibrary>>>();
}
// Load the libraries
ModelLoader loader(_modelMap, _libraryList);
}
}
bool ModelManagerLocal::isModel(const QString& file)
{
// if (!fs::is_regular_file(p))
// return false;
// check file extension
if (file.endsWith(QStringLiteral(".yml"))) {
return true;
}
return false;
}
void ModelManagerLocal::cleanup()
{
if (_libraryList) {
_libraryList->clear();
}
if (_modelMap) {
for (auto& it : *_modelMap) {
// This is needed to resolve cyclic dependencies
it.second->setLibrary(nullptr);
}
_modelMap->clear();
}
}
void ModelManagerLocal::refresh()
{
_modelMap->clear();
_libraryList->clear();
// Load the libraries
ModelLoader loader(_modelMap, _libraryList);
}
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> ModelManagerLocal::getLibraries()
{
return _libraryList;
}
void ModelManagerLocal::createLibrary(const QString& libraryName,
const QString& directory,
const QString& icon,
bool readOnly)
{
QDir dir;
if (!dir.exists(directory)) {
if (!dir.mkpath(directory)) {
throw CreationError("Unable to create library path");
}
}
auto modelLibrary = std::make_shared<ModelLibrary>(libraryName, directory, icon, readOnly);
_libraryList->push_back(modelLibrary);
// This needs to be persisted somehow
}
void ModelManagerLocal::renameLibrary(const QString& libraryName, const QString& newName)
{
for (auto& library : *_libraryList) {
if (library->getName() == libraryName) {
library->setName(newName);
return;
}
}
throw LibraryNotFound();
}
void ModelManagerLocal::changeIcon(const QString& libraryName, const QString& icon)
{
for (auto& library : *_libraryList) {
if (library->getName() == libraryName) {
library->setIconPath(icon);
return;
}
}
throw LibraryNotFound();
}
void ModelManagerLocal::removeLibrary(const QString& libraryName)
{
for (auto& library : *_libraryList) {
if (library->getName() == libraryName) {
_libraryList->remove(library);
// At this point we should rebuild the model map
return;
}
}
throw LibraryNotFound();
}
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
ModelManagerLocal::libraryModels(const QString& libraryName)
{
auto models = std::make_shared<std::vector<std::tuple<QString, QString, QString>>>();
for (auto& it : *_modelMap) {
// This is needed to resolve cyclic dependencies
if (it.second->getLibrary()->getName() == libraryName) {
models->push_back(
std::tuple<QString, QString, QString>(it.first, it.second->getDirectory(), it.second->getName()));
}
}
return models;
}
std::shared_ptr<Model> ModelManagerLocal::getModel(const QString& uuid) const
{
try {
if (_modelMap == nullptr) {
throw Uninitialized();
}
return _modelMap->at(uuid);
}
catch (std::out_of_range const&) {
throw ModelNotFound();
}
}
std::shared_ptr<Model> ModelManagerLocal::getModelByPath(const QString& path) const
{
QString cleanPath = QDir::cleanPath(path);
for (auto& library : *_libraryList) {
if (cleanPath.startsWith(library->getDirectory())) {
return library->getModelByPath(cleanPath);
}
}
throw MaterialNotFound();
}
std::shared_ptr<Model> ModelManagerLocal::getModelByPath(const QString& path,
const QString& lib) const
{
auto library = getLibrary(lib); // May throw LibraryNotFound
return library->getModelByPath(path); // May throw ModelNotFound
}
std::shared_ptr<ModelLibrary> ModelManagerLocal::getLibrary(const QString& name) const
{
for (auto& library : *_libraryList) {
if (library->getName() == name) {
return library;
}
}
throw LibraryNotFound();
}

View File

@@ -0,0 +1,87 @@
/***************************************************************************
* Copyright (c) 2024 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef MATERIAL_MODELMANAGERLOCAL_H
#define MATERIAL_MODELMANAGERLOCAL_H
#include <memory>
#include <Mod/Material/MaterialGlobal.h>
#include <QMutex>
#include "Exceptions.h"
#include "FolderTree.h"
#include "Model.h"
#include "ModelLibrary.h"
namespace Materials
{
class MaterialsExport ModelManagerLocal: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
ModelManagerLocal();
~ModelManagerLocal() override = default;
static void cleanup();
void refresh();
std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> getLibraries();
void createLibrary(const QString& libraryName,
const QString& directory,
const QString& icon,
bool readOnly = true);
void renameLibrary(const QString& libraryName, const QString& newName);
void changeIcon(const QString& libraryName, const QString& icon);
void removeLibrary(const QString& libraryName);
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
libraryModels(const QString& libraryName);
std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> getModels()
{
return _modelMap;
}
std::shared_ptr<std::map<QString, std::shared_ptr<ModelTreeNode>>>
getModelTree(std::shared_ptr<ModelLibrary> library, ModelFilter filter = ModelFilter_None) const
{
return library->getModelTree(filter);
}
std::shared_ptr<Model> getModel(const QString& uuid) const;
std::shared_ptr<Model> getModelByPath(const QString& path) const;
std::shared_ptr<Model> getModelByPath(const QString& path, const QString& lib) const;
std::shared_ptr<ModelLibrary> getLibrary(const QString& name) const;
static bool isModel(const QString& file);
private:
static void initLibraries();
static std::shared_ptr<std::list<std::shared_ptr<ModelLibrary>>> _libraryList;
static std::shared_ptr<std::map<QString, std::shared_ptr<Model>>> _modelMap;
static QMutex _mutex;
};
} // namespace Materials
#endif // MATERIAL_MODELMANAGERLOCAL_H

View File

@@ -10,7 +10,7 @@
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
Delete="false">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material model descriptions.</UserDocu>
@@ -31,6 +31,12 @@
</Documentation>
<Parameter Name="ModelLibraries" Type="List"/>
</Attribute>
<Attribute Name="LocalModelLibraries" ReadOnly="true">
<Documentation>
<UserDocu>List of local model libraries.</UserDocu>
</Documentation>
<Parameter Name="LocalModelLibraries" Type="List"/>
</Attribute>
<Attribute Name="Models" ReadOnly="true">
<Documentation>
<UserDocu>List of model libraries.</UserDocu>

View File

@@ -43,7 +43,7 @@ std::string ModelManagerPy::representation() const
PyObject* ModelManagerPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
{
// never create such objects with the constructor
return new ModelManagerPy(new ModelManager());
return new ModelManagerPy(&(ModelManager::getManager()));
}
// constructor method
@@ -116,7 +116,7 @@ PyObject* ModelManagerPy::getModelByPath(PyObject* args)
Py::List ModelManagerPy::getModelLibraries() const
{
auto libraries = getModelManagerPtr()->getModelLibraries();
auto libraries = getModelManagerPtr()->getLibraries();
Py::List list;
for (auto it = libraries->begin(); it != libraries->end(); it++) {
@@ -125,6 +125,26 @@ Py::List ModelManagerPy::getModelLibraries() const
libTuple.setItem(0, Py::String(lib->getName().toStdString()));
libTuple.setItem(1, Py::String(lib->getDirectoryPath().toStdString()));
libTuple.setItem(2, Py::String(lib->getIconPath().toStdString()));
libTuple.setItem(3, Py::Boolean(lib->isReadOnly()));
list.append(libTuple);
}
return list;
}
Py::List ModelManagerPy::getLocalModelLibraries() const
{
auto libraries = getModelManagerPtr()->getLocalLibraries();
Py::List list;
for (auto it = libraries->begin(); it != libraries->end(); it++) {
auto 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()));
libTuple.setItem(3, Py::Boolean(lib->isReadOnly()));
list.append(libTuple);
}

View File

@@ -15,35 +15,64 @@
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material property descriptions.</UserDocu>
</Documentation>
<Attribute Name="Name" ReadOnly="true">
<Attribute Name="Name" ReadOnly="false">
<Documentation>
<UserDocu>Property name.</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Type" ReadOnly="true">
<Attribute Name="DisplayName" ReadOnly="false">
<Documentation>
<UserDocu>Property display friendly name.</UserDocu>
</Documentation>
<Parameter Name="DisplayName" Type="String"/>
</Attribute>
<Attribute Name="Type" ReadOnly="false">
<Documentation>
<UserDocu>Property type.</UserDocu>
</Documentation>
<Parameter Name="Type" Type="String"/>
</Attribute>
<Attribute Name="Units" ReadOnly="true">
<Attribute Name="Units" ReadOnly="false">
<Documentation>
<UserDocu>Property units category.</UserDocu>
</Documentation>
<Parameter Name="Units" Type="String"/>
</Attribute>
<Attribute Name="URL" ReadOnly="true">
<Attribute Name="URL" ReadOnly="false">
<Documentation>
<UserDocu>URL to a detailed description of the property.</UserDocu>
</Documentation>
<Parameter Name="URL" Type="String"/>
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Attribute Name="Description" ReadOnly="false">
<Documentation>
<UserDocu>Property description.</UserDocu>
</Documentation>
<Parameter Name="Description" Type="String"/>
</Attribute>
<Attribute Name="Columns" ReadOnly="true">
<Documentation>
<UserDocu>List of array columns.</UserDocu>
</Documentation>
<Parameter Name="Columns" Type="List"/>
</Attribute>
<Attribute Name="Inheritance" ReadOnly="true">
<Documentation>
<UserDocu>UUID of the model in which the property is defined.</UserDocu>
</Documentation>
<Parameter Name="Inheritance" Type="String"/>
</Attribute>
<Attribute Name="Inherited" ReadOnly="true">
<Documentation>
<UserDocu>True if the property is inherited.</UserDocu>
</Documentation>
<Parameter Name="Inherited" Type="Boolean"/>
</Attribute>
<Methode Name="addColumn" ReadOnly="false">
<Documentation>
<UserDocu>Add a model property column.</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>
</GenerateModel>

View File

@@ -31,19 +31,8 @@ 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 << ")]";
str << "<ModelProperty object at " << getModelPropertyPtr() << ">";
return str.str();
}
@@ -65,26 +54,97 @@ Py::String ModelPropertyPy::getName() const
return Py::String(getModelPropertyPtr()->getName().toStdString());
}
void ModelPropertyPy::setName(Py::String arg)
{
getModelPropertyPtr()->setName(QString::fromStdString(arg));
}
Py::String ModelPropertyPy::getDisplayName() const
{
return Py::String(getModelPropertyPtr()->getDisplayName().toStdString());
}
void ModelPropertyPy::setDisplayName(Py::String arg)
{
getModelPropertyPtr()->setDisplayName(QString::fromStdString(arg));
}
Py::String ModelPropertyPy::getType() const
{
return Py::String(getModelPropertyPtr()->getPropertyType().toStdString());
}
void ModelPropertyPy::setType(Py::String arg)
{
getModelPropertyPtr()->setPropertyType(QString::fromStdString(arg));
}
Py::String ModelPropertyPy::getUnits() const
{
return Py::String(getModelPropertyPtr()->getUnits().toStdString());
}
void ModelPropertyPy::setUnits(Py::String arg)
{
getModelPropertyPtr()->setUnits(QString::fromStdString(arg));
}
Py::String ModelPropertyPy::getURL() const
{
return Py::String(getModelPropertyPtr()->getURL().toStdString());
}
void ModelPropertyPy::setURL(Py::String arg)
{
getModelPropertyPtr()->setURL(QString::fromStdString(arg));
}
Py::String ModelPropertyPy::getDescription() const
{
return Py::String(getModelPropertyPtr()->getDescription().toStdString());
}
void ModelPropertyPy::setDescription(Py::String arg)
{
getModelPropertyPtr()->setDescription(QString::fromStdString(arg));
}
Py::List ModelPropertyPy::getColumns() const
{
Py::List list;
auto columns = getModelPropertyPtr()->getColumns();
for (auto& column : columns) {
PyObject* modelPropertyPy = new ModelPropertyPy(new ModelProperty(column));
list.append(Py::Object(modelPropertyPy, true));
}
return list;
}
Py::String ModelPropertyPy::getInheritance() const
{
return Py::String(getModelPropertyPtr()->getInheritance().toStdString());
}
Py::Boolean ModelPropertyPy::getInherited() const
{
return getModelPropertyPtr()->isInherited();
}
PyObject* ModelPropertyPy::addColumn(PyObject* args)
{
PyObject* object;
if (!PyArg_ParseTuple(args, "O!", &ModelPropertyPy::Type, &object)) {
return nullptr;
}
ModelProperty* property = static_cast<ModelPropertyPy*>(object)->getModelPropertyPtr();
getModelPropertyPtr()->addColumn(*property);
Py_INCREF(Py_None);
return Py_None;
}
PyObject* ModelPropertyPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
@@ -93,4 +153,4 @@ PyObject* ModelPropertyPy::getCustomAttributes(const char* /*attr*/) const
int ModelPropertyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}
}

View File

@@ -33,13 +33,19 @@
</Documentation>
<Parameter Name="LibraryIcon" Type="String"/>
</Attribute>
<Attribute Name="Name" ReadOnly="true">
<Attribute Name="Name" ReadOnly="false">
<Documentation>
<UserDocu>Model name.</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Directory" ReadOnly="true">
<Attribute Name="Type" ReadOnly="false">
<Documentation>
<UserDocu>Model type.</UserDocu>
</Documentation>
<Parameter Name="Type" Type="String"/>
</Attribute>
<Attribute Name="Directory" ReadOnly="false">
<Documentation>
<UserDocu>Model directory.</UserDocu>
</Documentation>
@@ -51,19 +57,19 @@
</Documentation>
<Parameter Name="UUID" Type="String"/>
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Attribute Name="Description" ReadOnly="false">
<Documentation>
<UserDocu>Description of the model.</UserDocu>
</Documentation>
<Parameter Name="Description" Type="String"/>
</Attribute>
<Attribute Name="URL" ReadOnly="true">
<Attribute Name="URL" ReadOnly="false">
<Documentation>
<UserDocu>URL to a detailed description of the model.</UserDocu>
</Documentation>
<Parameter Name="URL" Type="String"/>
</Attribute>
<Attribute Name="DOI" ReadOnly="true">
<Attribute Name="DOI" ReadOnly="false">
<Documentation>
<UserDocu>Digital Object Identifier (see https://doi.org/)</UserDocu>
</Documentation>
@@ -81,5 +87,15 @@
</Documentation>
<Parameter Name="Properties" Type="Dict"/>
</Attribute>
<Methode Name="addInheritance" ReadOnly="false">
<Documentation>
<UserDocu>Add an inherited model.</UserDocu>
</Documentation>
</Methode>
<Methode Name="addProperty" ReadOnly="false">
<Documentation>
<UserDocu>Add a model property.</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>

View File

@@ -34,42 +34,8 @@ 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();
auto library = ptr->getLibrary();
if (library) {
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=[";
auto& 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 << "]]";
str << "<Model object at " << getModelPtr() << ">";
return str.str();
}
@@ -109,9 +75,38 @@ Py::String ModelPy::getName() const
return Py::String(getModelPtr()->getName().toStdString());
}
void ModelPy::setName(Py::String arg)
{
getModelPtr()->setName(QString::fromStdString(arg));
}
Py::String ModelPy::getType() const
{
auto type = (getModelPtr()->getType() == Model::ModelType_Physical)
? "Physical"
: "Appearance";
return Py::String(type);
}
void ModelPy::setType(Py::String arg)
{
if (arg.as_std_string() == "Appearance") {
getModelPtr()->setType(Model::ModelType_Appearance);
}
else {
getModelPtr()->setType(Model::ModelType_Physical);
}
}
Py::String ModelPy::getDirectory() const
{
return Py::String(getModelPtr()->getDirectoryPath().toStdString());
return Py::String(getModelPtr()->getDirectory().toStdString());
}
void ModelPy::setDirectory(Py::String arg)
{
getModelPtr()->setDirectory(QString::fromStdString(arg));
}
Py::String ModelPy::getUUID() const
@@ -124,16 +119,31 @@ Py::String ModelPy::getDescription() const
return Py::String(getModelPtr()->getDescription().toStdString());
}
void ModelPy::setDescription(Py::String arg)
{
getModelPtr()->setDescription(QString::fromStdString(arg));
}
Py::String ModelPy::getURL() const
{
return Py::String(getModelPtr()->getURL().toStdString());
}
void ModelPy::setURL(Py::String arg)
{
getModelPtr()->setURL(QString::fromStdString(arg));
}
Py::String ModelPy::getDOI() const
{
return Py::String(getModelPtr()->getDOI().toStdString());
}
void ModelPy::setDOI(Py::String arg)
{
getModelPtr()->setDOI(QString::fromStdString(arg));
}
Py::List ModelPy::getInherited() const
{
auto& inherited = getModelPtr()->getInheritance();
@@ -148,7 +158,6 @@ Py::List ModelPy::getInherited() const
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++) {
@@ -162,6 +171,31 @@ Py::Dict ModelPy::getProperties() const
return dict;
}
PyObject* ModelPy::addInheritance(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
getModelPtr()->addInheritance(QString::fromStdString(uuid));
Py_INCREF(Py_None);
return Py_None;
}
PyObject* ModelPy::addProperty(PyObject* args)
{
PyObject* object;
if (!PyArg_ParseTuple(args, "O!", &ModelPropertyPy::Type, &object)) {
return nullptr;
}
ModelProperty* property = static_cast<ModelPropertyPy*>(object)->getModelPropertyPtr();
getModelPtr()->addProperty(*property);
Py_INCREF(Py_None);
return Py_None;
}
PyObject* ModelPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;

View File

@@ -88,14 +88,12 @@ void PropertyMaterial::Save(Base::Writer& writer) const
void PropertyMaterial::Restore(Base::XMLReader& reader)
{
MaterialManager manager;
// read my Element
reader.readElement("PropertyMaterial");
// get the value of my Attribute
auto uuid = reader.getAttribute("uuid");
setValue(*manager.getMaterial(QString::fromLatin1(uuid)));
setValue(*MaterialManager::getManager().getMaterial(QString::fromLatin1(uuid)));
}
const char* PropertyMaterial::getEditorName() const

View File

@@ -0,0 +1,75 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#include <QVariant>
#include "PyVariants.h"
#include "Exceptions.h"
using namespace Materials;
PyObject* Materials::_pyObjectFromVariant(const QVariant& value)
{
if (value.isNull()) {
Py_RETURN_NONE;
}
if (value.userType() == qMetaTypeId<Base::Quantity>()) {
return new Base::QuantityPy(new Base::Quantity(value.value<Base::Quantity>()));
}
if (value.userType() == QMetaType::Double) {
return PyFloat_FromDouble(value.toDouble());
}
if (value.userType() == QMetaType::Float) {
return PyFloat_FromDouble(value.toFloat());
}
if (value.userType() == QMetaType::Int) {
return PyLong_FromLong(value.toInt());
}
if (value.userType() == QMetaType::Long) {
return PyLong_FromLong(value.toInt());
}
if (value.userType() == QMetaType::Bool) {
return Py::new_reference_to(Py::Boolean(value.toBool()));
}
if (value.userType() == QMetaType::QString) {
return PyUnicode_FromString(value.toString().toStdString().c_str());
}
if (value.userType() == qMetaTypeId<QList<QVariant>>()) {
return Py::new_reference_to(getList(value));
}
throw UnknownValueType();
}
Py::List Materials::getList(const QVariant& value)
{
auto listValue = value.value<QList<QVariant>>();
Py::List list;
for (auto& it : listValue) {
list.append(Py::Object(_pyObjectFromVariant(it)));
}
return list;
}

View File

@@ -0,0 +1,42 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* 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 Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef MATERIAL_PYVARIANTS_H
#define MATERIAL_PYVARIANTS_H
#include <QMetaType>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
#include <CXX/Objects.hxx>
#include <Gui/MetaTypes.h>
#include <Mod/Material/MaterialGlobal.h>
namespace Materials
{
extern MaterialsExport PyObject* _pyObjectFromVariant(const QVariant& value);
extern MaterialsExport Py::List getList(const QVariant& value);
} // namespace Materials
#endif // MATERIAL_PYVARIANTS_H

View File

@@ -199,7 +199,6 @@ Py::String UUIDsPy::getTextureRendering() const
Py::String UUIDsPy::getAdvancedRendering() const
{
Base::Console().Log(getModelUUIDsPtr()->ModelUUID_Rendering_Advanced.toStdString().c_str());
return Py::String(getModelUUIDsPtr()->ModelUUID_Rendering_Advanced.toStdString());
}

View File

@@ -63,7 +63,7 @@ Array2D::Array2D(const QString& propertyName,
}
if (_property) {
_value =
std::static_pointer_cast<Materials::Material2DArray>(_property->getMaterialValue());
std::static_pointer_cast<Materials::Array2D>(_property->getMaterialValue());
setWindowTitle(_property->getDisplayName());
}
else {

View File

@@ -64,7 +64,7 @@ private:
std::unique_ptr<Ui_Array2D> ui;
std::shared_ptr<Materials::Material> _material;
std::shared_ptr<Materials::MaterialProperty> _property;
std::shared_ptr<Materials::Material2DArray> _value;
std::shared_ptr<Materials::Array2D> _value;
QAction _deleteAction;

View File

@@ -59,7 +59,7 @@ Array3D::Array3D(const QString& propertyName,
}
if (_property) {
_value =
std::static_pointer_cast<Materials::Material3DArray>(_property->getMaterialValue());
std::static_pointer_cast<Materials::Array3D>(_property->getMaterialValue());
}
else {
_value = nullptr;

View File

@@ -67,7 +67,7 @@ private:
std::unique_ptr<Ui_Array3D> ui;
std::shared_ptr<Materials::Material> _material;
std::shared_ptr<Materials::MaterialProperty> _property;
std::shared_ptr<Materials::Material3DArray> _value;
std::shared_ptr<Materials::Array3D> _value;
QAction _deleteDepthAction;
QAction _delete2DAction;

View File

@@ -47,7 +47,7 @@ AbstractArrayModel::AbstractArrayModel(QObject* parent)
Array2DModel::Array2DModel(const std::shared_ptr<Materials::MaterialProperty>& property,
const std::shared_ptr<Materials::Material2DArray>& value,
const std::shared_ptr<Materials::Array2D>& value,
QObject* parent)
: AbstractArrayModel(parent)
, _property(property)
@@ -199,7 +199,7 @@ bool Array2DModel::removeColumns(int column, int count, const QModelIndex& paren
//===
Array3DDepthModel::Array3DDepthModel(const std::shared_ptr<Materials::MaterialProperty>& property,
const std::shared_ptr<Materials::Material3DArray>& value,
const std::shared_ptr<Materials::Array3D>& value,
QObject* parent)
: AbstractArrayModel(parent)
, _property(property)
@@ -337,7 +337,7 @@ bool Array3DDepthModel::removeColumns(int column, int count, const QModelIndex&
//===
Array3DModel::Array3DModel(const std::shared_ptr<Materials::MaterialProperty>& property,
const std::shared_ptr<Materials::Material3DArray>& value,
const std::shared_ptr<Materials::Array3D>& value,
QObject* parent)
: AbstractArrayModel(parent)
, _property(property)

View File

@@ -48,7 +48,7 @@ class Array2DModel: public AbstractArrayModel
{
public:
explicit Array2DModel(const std::shared_ptr<Materials::MaterialProperty>& property = nullptr,
const std::shared_ptr<Materials::Material2DArray>& value = nullptr,
const std::shared_ptr<Materials::Array2D>& value = nullptr,
QObject* parent = nullptr);
~Array2DModel() override = default;
@@ -71,7 +71,7 @@ public:
private:
std::shared_ptr<Materials::MaterialProperty> _property;
std::shared_ptr<Materials::Material2DArray> _value;
std::shared_ptr<Materials::Array2D> _value;
};
class Array3DDepthModel: public AbstractArrayModel
@@ -79,7 +79,7 @@ class Array3DDepthModel: public AbstractArrayModel
public:
explicit Array3DDepthModel(
const std::shared_ptr<Materials::MaterialProperty>& property = nullptr,
const std::shared_ptr<Materials::Material3DArray>& value = nullptr,
const std::shared_ptr<Materials::Array3D>& value = nullptr,
QObject* parent = nullptr);
~Array3DDepthModel() override = default;
@@ -106,14 +106,14 @@ public:
private:
std::shared_ptr<Materials::MaterialProperty> _property;
std::shared_ptr<Materials::Material3DArray> _value;
std::shared_ptr<Materials::Array3D> _value;
};
class Array3DModel: public AbstractArrayModel
{
public:
explicit Array3DModel(const std::shared_ptr<Materials::MaterialProperty>& property = nullptr,
const std::shared_ptr<Materials::Material3DArray>& value = nullptr,
const std::shared_ptr<Materials::Array3D>& value = nullptr,
QObject* parent = nullptr);
~Array3DModel() override = default;
@@ -138,7 +138,7 @@ public:
private:
std::shared_ptr<Materials::MaterialProperty> _property;
std::shared_ptr<Materials::Material3DArray> _value;
std::shared_ptr<Materials::Array3D> _value;
};
} // namespace MatGui

View File

@@ -61,8 +61,6 @@ void CmdMaterialEdit::activated(int iMsg)
{
Q_UNUSED(iMsg);
Base::Console().Log("Material_Edit\n");
static QPointer<QDialog> dlg = nullptr;
if (!dlg) {
dlg = new MatGui::MaterialsEditor(Gui::getMainWindow());

View File

@@ -151,7 +151,7 @@ void DlgInspectAppearance::update(std::vector<Gui::ViewProvider*>& views)
ui->editObjectLabel->setText(QString::fromUtf8(labelProp->getValue()));
}
else {
ui->editObjectLabel->setText(QLatin1String(""));
ui->editObjectLabel->setText(QStringLiteral(""));
}
ui->editObjectName->setText(QLatin1String(obj->getNameInDocument()));
@@ -162,15 +162,15 @@ void DlgInspectAppearance::update(std::vector<Gui::ViewProvider*>& views)
ui->editSubShape->setText(QString::fromStdString(subObject.getSubNames()[0]));
}
else {
ui->editSubShape->setText(QLatin1String(""));
ui->editSubShape->setText(QStringLiteral(""));
}
}
else {
ui->editSubShape->setText(QLatin1String(""));
ui->editSubShape->setText(QStringLiteral(""));
}
auto subShapeType = QString::fromUtf8(obj->getTypeId().getName());
subShapeType.remove(subShapeType.indexOf(QLatin1String("::")), subShapeType.size());
subShapeType.remove(subShapeType.indexOf(QStringLiteral("::")), subShapeType.size());
ui->editSubShapeType->setText(subShapeType);
ui->editShapeType->setText(QString::fromUtf8(obj->getTypeId().getName()));

View File

@@ -120,7 +120,7 @@ void DlgInspectMaterial::appendClip(QString text)
{
// Need to add indent
QString indent(clipboardIndent * 4, QLatin1Char(' '));
clipboardText += indent + text + QLatin1String("\n");
clipboardText += indent + text + QStringLiteral("\n");
}
QStandardItem* DlgInspectMaterial::clipItem(QString text)
@@ -144,7 +144,7 @@ void DlgInspectMaterial::unindent()
void DlgInspectMaterial::update(std::vector<Gui::ViewProvider*>& views)
{
clipboardText = QLatin1String("");
clipboardText = QStringLiteral("");
clipboardIndent = 0;
App::Document* doc = App::GetApplication().getActiveDocument();
if (doc) {
@@ -166,7 +166,7 @@ void DlgInspectMaterial::update(std::vector<Gui::ViewProvider*>& views)
appendClip(tr("Label: ") + QString::fromUtf8(labelProp->getValue()));
}
else {
ui->editObjectLabel->setText(QLatin1String(""));
ui->editObjectLabel->setText(QStringLiteral(""));
}
ui->editObjectName->setText(QLatin1String(obj->getNameInDocument()));
appendClip(tr("Internal Name: ") + QString::fromUtf8(obj->getNameInDocument()));
@@ -178,15 +178,15 @@ void DlgInspectMaterial::update(std::vector<Gui::ViewProvider*>& views)
ui->editSubShape->setText(QString::fromStdString(subObject.getSubNames()[0]));
}
else {
ui->editSubShape->setText(QLatin1String(""));
ui->editSubShape->setText(QStringLiteral(""));
}
}
else {
ui->editSubShape->setText(QLatin1String(""));
ui->editSubShape->setText(QStringLiteral(""));
}
auto subShapeType = QString::fromUtf8(obj->getTypeId().getName());
subShapeType.remove(subShapeType.indexOf(QLatin1String("::")), subShapeType.size());
subShapeType.remove(subShapeType.indexOf(QStringLiteral("::")), subShapeType.size());
appendClip(tr("Type: ") + subShapeType);
ui->editSubShapeType->setText(subShapeType);
appendClip(tr("TypeID: ") + QString::fromUtf8(obj->getTypeId().getName()));
@@ -248,7 +248,7 @@ void DlgInspectMaterial::addModels(QTreeView* tree,
}
else {
for (const QString& uuid : *models) {
auto model = modelManager.getModel(uuid);
auto model = Materials::ModelManager::getManager().getModel(uuid);
auto name = clipItem(tr("Name: ") + model->getName());
addExpanded(tree, parent, name);
@@ -287,7 +287,7 @@ void DlgInspectMaterial::addModelDetails(QTreeView* tree,
}
else {
for (const QString& inherited : inheritedUuids) {
auto inheritedModel = modelManager.getModel(inherited);
auto inheritedModel = Materials::ModelManager::getManager().getModel(inherited);
auto name = clipItem(tr("Name: ") + inheritedModel->getName());
addExpanded(tree, inherits, name);
@@ -340,10 +340,10 @@ void DlgInspectMaterial::addMaterialDetails(QTreeView* tree,
{
auto uuid = clipItem(tr("UUID: ") + material.getUUID());
addExpanded(tree, parent, uuid);
auto library = clipItem(tr("Library: ") + material.getLibrary()->getName());
auto library =
clipItem(tr("Library: ") + material.getLibrary()->getName());
addExpanded(tree, parent, library);
auto libraryPath =
clipItem(tr("Library Directory: ") + material.getLibrary()->getDirectoryPath());
auto libraryPath = clipItem(tr("Library Directory: ") + material.getLibrary()->getDirectoryPath());
addExpanded(tree, parent, libraryPath);
auto directory = clipItem(tr("Sub Directory: ") + material.getDirectory());
addExpanded(tree, parent, directory);
@@ -353,7 +353,7 @@ void DlgInspectMaterial::addMaterialDetails(QTreeView* tree,
indent();
auto parentUUID = material.getParentUUID();
if (!parentUUID.isEmpty()) {
auto parentMaterial = materialManager.getMaterial(material.getParentUUID());
auto parentMaterial = Materials::MaterialManager::getManager().getMaterial(material.getParentUUID());
addMaterial(tree, inherits, *parentMaterial);
}
else {

View File

@@ -60,8 +60,6 @@ public:
private:
std::unique_ptr<Ui_DlgInspectMaterial> ui;
Materials::MaterialManager materialManager;
Materials::ModelManager modelManager;
QString clipboardText;
int clipboardIndent;

View File

@@ -137,22 +137,23 @@ void MaterialSave::onOk(bool checked)
QFileInfo filepath(_selectedPath + QStringLiteral("/") + name
+ QStringLiteral(".FCMat"));
if (library->fileExists(filepath.filePath())) {
/*if (library->fileExists(filepath.filePath()))*/ {
// confirm overwrite
auto res = confirmOverwrite(_filename);
if (res == QMessageBox::Cancel) {
return;
}
_manager.saveMaterial(library, _material, filepath.filePath(), true, false, _saveInherited);
Materials::MaterialManager::getManager()
.saveMaterial(library, _material, filepath.filePath(), true, false, _saveInherited);
accept();
return;
}
bool saveAsCopy = false;
if (_manager.exists(_material->getUUID())) {
if (Materials::MaterialManager::getManager().exists(_material->getUUID())) {
// Does it already exist in this library?
if (_manager.exists(library, _material->getUUID())) {
if (Materials::MaterialManager::getManager().exists(library, _material->getUUID())) {
// Confirm saving a new material
auto res = confirmNewMaterial();
if (res == QMessageBox::Cancel) {
@@ -174,7 +175,7 @@ void MaterialSave::onOk(bool checked)
}
}
_manager
Materials::MaterialManager::getManager()
.saveMaterial(library, _material, filepath.filePath(), false, saveAsCopy, _saveInherited);
accept();
@@ -287,12 +288,16 @@ void MaterialSave::reject()
void MaterialSave::setLibraries()
{
auto libraries = _manager.getMaterialLibraries();
auto libraries = Materials::MaterialManager::getManager().getLibraries();
for (auto& library : *libraries) {
if (!library->isReadOnly()) {
QVariant libraryVariant;
libraryVariant.setValue(library);
ui->comboLibrary->addItem(library->getName(), libraryVariant);
if (library->isLocal()) {
auto materialLibrary =
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
if (!materialLibrary->isReadOnly()) {
QVariant libraryVariant;
libraryVariant.setValue(materialLibrary);
ui->comboLibrary->addItem(materialLibrary->getName(), libraryVariant);
}
}
}
}
@@ -327,7 +332,7 @@ void MaterialSave::addMaterials(
auto tree = ui->treeMaterials;
for (auto& mat : *modelTree) {
std::shared_ptr<Materials::MaterialTreeNode> nodePtr = mat.second;
if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) {
if (nodePtr->getType() == Materials::MaterialTreeNode::NodeType::DataNode) {
std::shared_ptr<Materials::Material> material = nodePtr->getData();
QString uuid = material->getUUID();
@@ -368,7 +373,7 @@ void MaterialSave::showSelectedTree()
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
auto modelTree = _manager.getMaterialTree(library);
auto modelTree = Materials::MaterialManager::getManager().getMaterialTree(library);
addMaterials(*lib, modelTree, folderIcon, icon);
}
else {
@@ -444,14 +449,14 @@ void MaterialSave::createFolder(const QString& path)
{
auto library = currentLibrary();
_manager.createFolder(library, path);
Materials::MaterialManager::getManager().createFolder(library, path);
}
void MaterialSave::renameFolder(const QString& oldPath, const QString& newPath)
{
auto library = currentLibrary();
_manager.renameFolder(library, oldPath, newPath);
Materials::MaterialManager::getManager().renameFolder(library, oldPath, newPath);
}
void MaterialSave::deleteRecursive(const QString& path)
@@ -459,7 +464,7 @@ void MaterialSave::deleteRecursive(const QString& path)
// This will delete files, folders, and any children
auto library = currentLibrary();
_manager.deleteRecursive(library, path);
Materials::MaterialManager::getManager().deleteRecursive(library, path);
}
void MaterialSave::onNewFolder(bool checked)
@@ -552,9 +557,9 @@ int MaterialSave::confirmDelete(QWidget* parent)
{
auto library = currentLibrary();
if (library->isRoot(_selectedFull)) {
return QMessageBox::Cancel;
}
// if (library->isRoot(_selectedFull)) {
// return QMessageBox::Cancel;
// }
QMessageBox box(parent ? parent : this);
box.setIcon(QMessageBox::Question);
@@ -600,10 +605,10 @@ void MaterialSave::deleteSelected()
{
auto library = currentLibrary();
if (!library->isRoot(_selectedFull)) {
_manager.deleteRecursive(library, _selectedFull);
removeSelectedFromTree();
}
// if (!library->isRoot(_selectedFull)) {
// Materials::MaterialManager::getManager().deleteRecursive(library, _selectedFull);
// removeSelectedFromTree();
// }
}
void MaterialSave::removeChildren(QStandardItem* item)

View File

@@ -35,6 +35,8 @@
namespace MatGui
{
class MaterialLibrary;
class Ui_MaterialSave;
class MaterialSave: public QDialog
@@ -76,7 +78,6 @@ public:
private:
std::unique_ptr<Ui_MaterialSave> ui;
Materials::MaterialManager _manager;
std::shared_ptr<Materials::Material> _material;
bool _saveInherited;
QString _selectedPath;

View File

@@ -487,7 +487,7 @@ void MaterialTreeWidget::addRecent(const QString& uuid)
}
// Ensure it is a material. New, unsaved materials will not be
try {
auto material = _materialManager.getMaterial(uuid);
auto material = Materials::MaterialManager::getManager().getMaterial(uuid);
Q_UNUSED(material)
}
catch (const Materials::MaterialNotFound&) {
@@ -555,12 +555,15 @@ void MaterialTreeWidget::fillMaterialTree()
addRecents(lib);
}
auto libraries = _materialManager.getMaterialLibraries();
auto libraries = Materials::MaterialManager::getManager().getLibraries();
for (const auto& library : *libraries) {
auto modelTree = _materialManager.getMaterialTree(library, _filter, _filterOptions);
auto materialTree =
Materials::MaterialManager::getManager().getMaterialTree(library,
_filter,
_filterOptions);
bool showLibraries = _filterOptions.includeEmptyLibraries();
if (!_filterOptions.includeEmptyLibraries() && modelTree->size() > 0) {
if (!_filterOptions.includeEmptyLibraries() && materialTree->size() > 0) {
showLibraries = true;
}
@@ -572,7 +575,7 @@ void MaterialTreeWidget::fillMaterialTree()
QIcon icon(library->getIconPath());
QIcon folderIcon(QStringLiteral(":/icons/folder.svg"));
addMaterials(*lib, modelTree, folderIcon, icon, param);
addMaterials(*lib, materialTree, folderIcon, icon, param);
}
}
}
@@ -616,8 +619,7 @@ void MaterialTreeWidget::addRecents(QStandardItem* parent)
for (auto& uuid : _recents) {
try {
auto material = getMaterialManager().getMaterial(uuid);
QIcon icon = QIcon(material->getLibrary()->getIconPath());
QIcon icon(material->getLibrary()->getIconPath());
auto card = new QStandardItem(icon, material->getName());
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
@@ -634,8 +636,7 @@ void MaterialTreeWidget::addFavorites(QStandardItem* parent)
for (auto& uuid : _favorites) {
try {
auto material = getMaterialManager().getMaterial(uuid);
QIcon icon = QIcon(material->getLibrary()->getIconPath());
QIcon icon(material->getLibrary()->getIconPath());
auto card = new QStandardItem(icon, material->getName());
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
@@ -657,9 +658,8 @@ void MaterialTreeWidget::addMaterials(
auto childParam = param->GetGroup(parent.text().toStdString().c_str());
for (auto& mat : *modelTree) {
auto nodePtr = mat.second;
if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) {
auto material = nodePtr->getData();
QString uuid = material->getUUID();
if (nodePtr->getType() == Materials::MaterialTreeNode::NodeType::DataNode) {
QString uuid = nodePtr->getUUID();
auto card = new QStandardItem(icon, mat.first);
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);

View File

@@ -48,7 +48,6 @@
namespace MatGui
{
class CommandManager;
class WidgetFactoryInst;
class MaterialTreeWidgetPy;
@@ -207,17 +206,13 @@ private:
int _recentMax;
MaterialTreeWidgetPy* pyTreeWidget {nullptr};
Materials::MaterialManager _materialManager;
// friends
friend class Gui::WidgetFactoryInst;
protected:
// bool m_Restored = false;
Materials::MaterialManager& getMaterialManager()
{
return _materialManager;
return Materials::MaterialManager::getManager();
}
void getFavorites();

View File

@@ -46,6 +46,7 @@
#include <Gui/WaitCursor.h>
#include <Mod/Material/App/Exceptions.h>
#include <Mod/Material/App/MaterialLibrary.h>
#include <Mod/Material/App/ModelManager.h>
#include <Mod/Material/App/ModelUuids.h>
@@ -89,7 +90,7 @@ void MaterialsEditor::setup()
Gui::WaitCursor wc;
ui->setupUi(this);
_warningIcon = QIcon(QLatin1String(":/icons/Warning.svg"));
_warningIcon = QIcon(QStringLiteral(":/icons/Warning.svg"));
getFavorites();
getRecents();
@@ -108,7 +109,7 @@ void MaterialsEditor::setup()
resize(width, height);
ui->buttonURL->setIcon(QIcon(QLatin1String(":/icons/internet-web-browser.svg")));
ui->buttonURL->setIcon(QIcon(QStringLiteral(":/icons/internet-web-browser.svg")));
connect(ui->standardButtons->button(QDialogButtonBox::Ok),
&QPushButton::clicked,
@@ -214,7 +215,7 @@ void MaterialsEditor::addFavorite(const QString& uuid)
{
// Ensure it is a material. New, unsaved materials will not be
try {
auto material = _materialManager.getMaterial(uuid);
auto material = Materials::MaterialManager::getManager().getMaterial(uuid);
Q_UNUSED(material)
}
catch (const Materials::MaterialNotFound&) {
@@ -299,7 +300,7 @@ void MaterialsEditor::addRecent(const QString& uuid)
{
// Ensure it is a material. New, unsaved materials will not be
try {
auto material = _materialManager.getMaterial(uuid);
auto material = Materials::MaterialManager::getManager().getMaterial(uuid);
Q_UNUSED(material)
}
catch (const Materials::MaterialNotFound&) {
@@ -429,7 +430,7 @@ void MaterialsEditor::onAppearanceAdd(bool checked)
if (dialog.exec() == QDialog::Accepted) {
QString selected = dialog.selectedModel();
_material->addAppearance(selected);
auto model = getModelManager().getModel(selected);
auto model = Materials::ModelManager::getManager().getModel(selected);
if (selected == Materials::ModelUUIDs::ModelUUID_Rendering_Basic
|| model->inherits(Materials::ModelUUIDs::ModelUUID_Rendering_Basic)) {
// Add default appearance properties
@@ -497,7 +498,7 @@ void MaterialsEditor::setMaterialDefaults()
_material->setLicense(QLatin1String(name));
// Empty materials will have no parent
_materialManager.dereference(_material);
Materials::MaterialManager::getManager().dereference(_material);
updateMaterial();
_material->resetEditState();
@@ -665,18 +666,22 @@ void MaterialsEditor::saveMaterialTree(const Base::Reference<ParameterGrp>& para
void MaterialsEditor::addMaterials(
QStandardItem& parent,
const std::shared_ptr<std::map<QString, std::shared_ptr<Materials::MaterialTreeNode>>>
modelTree,
materialTree,
const QIcon& folderIcon,
const QIcon& icon,
const Base::Reference<ParameterGrp>& param)
{
auto childParam = param->GetGroup(parent.text().toStdString().c_str());
auto tree = ui->treeMaterials;
for (auto& mat : *modelTree) {
for (auto& mat : *materialTree) {
std::shared_ptr<Materials::MaterialTreeNode> nodePtr = mat.second;
if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) {
if (nodePtr->getType() == Materials::MaterialTreeNode::NodeType::DataNode) {
QString uuid = nodePtr->getUUID();
auto material = nodePtr->getData();
QString uuid = material->getUUID();
if (!material) {
material = Materials::MaterialManager::getManager().getMaterial(uuid);
nodePtr->setData(material);
}
QIcon matIcon = icon;
if (material->isOldFormat()) {
@@ -697,7 +702,9 @@ void MaterialsEditor::addMaterials(
addExpanded(tree, &parent, node, childParam);
node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
auto treeMap = nodePtr->getFolder();
addMaterials(*node, treeMap, folderIcon, icon, childParam);
// if (treeMap) {
addMaterials(*node, treeMap, folderIcon, icon, childParam);
// }
}
}
}
@@ -800,14 +807,15 @@ void MaterialsEditor::addRecents(QStandardItem* parent)
for (auto& uuid : _recents) {
try {
auto material = getMaterialManager().getMaterial(uuid);
// if (material->getLibrary()->isLocal()) {
QIcon icon = QIcon(material->getLibrary()->getIconPath());
auto card = new QStandardItem(icon, libraryPath(material));
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
QIcon icon = QIcon(material->getLibrary()->getIconPath());
auto card = new QStandardItem(icon, libraryPath(material));
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, parent, card);
addExpanded(tree, parent, card);
// }
}
catch (const Materials::MaterialNotFound&) {
}
@@ -820,11 +828,10 @@ void MaterialsEditor::addFavorites(QStandardItem* parent)
for (auto& uuid : _favorites) {
try {
auto material = getMaterialManager().getMaterial(uuid);
QIcon icon = QIcon(material->getLibrary()->getIconPath());
auto card = new QStandardItem(icon, libraryPath(material));
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled);
| Qt::ItemIsDropEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
addExpanded(tree, parent, card);
@@ -856,12 +863,12 @@ void MaterialsEditor::fillMaterialTree()
addRecents(lib);
}
auto libraries = getMaterialManager().getMaterialLibraries();
auto libraries = getMaterialManager().getLibraries();
for (const auto& library : *libraries) {
auto modelTree = getMaterialManager().getMaterialTree(library);
auto materialTree = getMaterialManager().getMaterialTree(library);
bool showLibraries = _filterOptions.includeEmptyLibraries();
if (!_filterOptions.includeEmptyLibraries() && modelTree->size() > 0) {
if (!_filterOptions.includeEmptyLibraries() && materialTree->size() > 0) {
showLibraries = true;
}
@@ -873,7 +880,7 @@ void MaterialsEditor::fillMaterialTree()
QIcon icon(library->getIconPath());
QIcon folderIcon(QStringLiteral(":/icons/folder.svg"));
addMaterials(*lib, modelTree, folderIcon, icon, param);
addMaterials(*lib, materialTree, folderIcon, icon, param);
}
}
}
@@ -901,11 +908,11 @@ bool MaterialsEditor::updateTexturePreview() const
{
bool hasImage = false;
QImage image;
//double scaling = 99.0;
// double scaling = 99.0;
if (_material->hasModel(Materials::ModelUUIDs::ModelUUID_Rendering_Texture)) {
// First try loading an embedded image
try {
auto property = _material->getAppearanceProperty(QLatin1String("TextureImage"));
auto property = _material->getAppearanceProperty(QStringLiteral("TextureImage"));
if (!property->isNull()) {
// Base::Console().Log("Has 'TextureImage'\n");
auto propertyValue = property->getString();
@@ -922,7 +929,7 @@ bool MaterialsEditor::updateTexturePreview() const
// If no embedded image, load from a path
if (!hasImage) {
try {
auto property = _material->getAppearanceProperty(QLatin1String("TexturePath"));
auto property = _material->getAppearanceProperty(QStringLiteral("TexturePath"));
if (!property->isNull()) {
// Base::Console().Log("Has 'TexturePath'\n");
auto filePath = property->getString();
@@ -940,10 +947,10 @@ bool MaterialsEditor::updateTexturePreview() const
// Apply any scaling
try {
auto property = _material->getAppearanceProperty(QLatin1String("TextureScaling"));
auto property = _material->getAppearanceProperty(QStringLiteral("TextureScaling"));
if (!property->isNull()) {
//scaling = property->getFloat();
// Base::Console().Log("Has 'TextureScaling' = %g\n", scaling);
// scaling = property->getFloat();
// Base::Console().Log("Has 'TextureScaling' = %g\n", scaling);
}
}
catch (const Materials::PropertyNotFound&) {
@@ -959,43 +966,43 @@ bool MaterialsEditor::updateTexturePreview() const
bool MaterialsEditor::updateMaterialPreview() const
{
if (_material->hasAppearanceProperty(QLatin1String("AmbientColor"))) {
QString color = _material->getAppearanceValueString(QLatin1String("AmbientColor"));
if (_material->hasAppearanceProperty(QStringLiteral("AmbientColor"))) {
QString color = _material->getAppearanceValueString(QStringLiteral("AmbientColor"));
_rendered->setAmbientColor(getColorHash(color, 255));
}
else {
_rendered->resetAmbientColor();
}
if (_material->hasAppearanceProperty(QLatin1String("DiffuseColor"))) {
QString color = _material->getAppearanceValueString(QLatin1String("DiffuseColor"));
if (_material->hasAppearanceProperty(QStringLiteral("DiffuseColor"))) {
QString color = _material->getAppearanceValueString(QStringLiteral("DiffuseColor"));
_rendered->setDiffuseColor(getColorHash(color, 255));
}
else {
_rendered->resetDiffuseColor();
}
if (_material->hasAppearanceProperty(QLatin1String("SpecularColor"))) {
QString color = _material->getAppearanceValueString(QLatin1String("SpecularColor"));
if (_material->hasAppearanceProperty(QStringLiteral("SpecularColor"))) {
QString color = _material->getAppearanceValueString(QStringLiteral("SpecularColor"));
_rendered->setSpecularColor(getColorHash(color, 255));
}
else {
_rendered->resetSpecularColor();
}
if (_material->hasAppearanceProperty(QLatin1String("EmissiveColor"))) {
QString color = _material->getAppearanceValueString(QLatin1String("EmissiveColor"));
if (_material->hasAppearanceProperty(QStringLiteral("EmissiveColor"))) {
QString color = _material->getAppearanceValueString(QStringLiteral("EmissiveColor"));
_rendered->setEmissiveColor(getColorHash(color, 255));
}
else {
_rendered->resetEmissiveColor();
}
if (_material->hasAppearanceProperty(QLatin1String("Shininess"))) {
double value = _material->getAppearanceValue(QLatin1String("Shininess")).toDouble();
if (_material->hasAppearanceProperty(QStringLiteral("Shininess"))) {
double value = _material->getAppearanceValue(QStringLiteral("Shininess")).toDouble();
_rendered->setShininess(value);
}
else {
_rendered->resetShininess();
}
if (_material->hasAppearanceProperty(QLatin1String("Transparency"))) {
double value = _material->getAppearanceValue(QLatin1String("Transparency")).toDouble();
if (_material->hasAppearanceProperty(QStringLiteral("Transparency"))) {
double value = _material->getAppearanceValue(QStringLiteral("Transparency")).toDouble();
_rendered->setTransparency(value);
}
else {
@@ -1065,7 +1072,7 @@ void MaterialsEditor::updateMaterialAppearance()
for (auto it = models->begin(); it != models->end(); it++) {
QString uuid = *it;
try {
auto model = getModelManager().getModel(uuid);
auto model = Materials::ModelManager::getManager().getModel(uuid);
QString name = model->getName();
auto modelRoot = new QStandardItem(name);
@@ -1129,7 +1136,7 @@ void MaterialsEditor::updateMaterialProperties()
for (auto it = models->begin(); it != models->end(); it++) {
QString uuid = *it;
try {
auto model = getModelManager().getModel(uuid);
auto model = Materials::ModelManager::getManager().getModel(uuid);
QString name = model->getName();
auto modelRoot = new QStandardItem(name);
@@ -1177,14 +1184,14 @@ QString MaterialsEditor::libraryPath(const std::shared_ptr<Materials::Material>&
QString path;
auto library = material->getLibrary();
if (library) {
path = QStringLiteral("/%1/%2")
.arg(material->getLibrary()->getName())
.arg(material->getDirectory());
}
else {
path = QStringLiteral("%1").arg(material->getDirectory());
path = QStringLiteral("/%1/%2/%3")
.arg(library->getName())
.arg(material->getDirectory())
.arg(material->getName());
return path;
}
path = QStringLiteral("%1/%2").arg(material->getDirectory()).arg(material->getName());
return path;
}
@@ -1192,7 +1199,7 @@ void MaterialsEditor::updateMaterialGeneral()
{
QString parentString;
try {
auto parent = _materialManager.getParent(_material);
auto parent = Materials::MaterialManager::getManager().getParent(_material);
parentString = libraryPath(parent);
}
catch (const Materials::MaterialNotFound&) {

View File

@@ -82,11 +82,7 @@ public:
Materials::MaterialManager& getMaterialManager()
{
return _materialManager;
}
Materials::ModelManager& getModelManager()
{
return _modelManager;
return Materials::MaterialManager::getManager();
}
static QString libraryPath(const std::shared_ptr<Materials::Material>& material);
@@ -114,8 +110,6 @@ protected:
private:
std::unique_ptr<Ui_MaterialsEditor> ui;
Materials::MaterialManager _materialManager;
Materials::ModelManager _modelManager;
std::shared_ptr<Materials::Material> _material;
AppearancePreview* _rendered;
bool _materialSelected;

View File

@@ -239,7 +239,7 @@ void ModelSelect::addModels(
auto tree = ui->treeModels;
for (auto& mod : *modelTree) {
std::shared_ptr<Materials::ModelTreeNode> nodePtr = mod.second;
if (nodePtr->getType() == Materials::ModelTreeNode::DataNode) {
if (nodePtr->getType() == Materials::ModelTreeNode::NodeType::DataNode) {
auto model = nodePtr->getData();
QString uuid = model->getUUID();
@@ -265,9 +265,9 @@ void ModelSelect::addRecents(QStandardItem* parent)
auto tree = ui->treeModels;
for (auto& uuid : _recents) {
try {
auto model = getModelManager().getModel(uuid);
auto model = Materials::ModelManager::getManager().getModel(uuid);
if (getModelManager().passFilter(_filter, model->getType())) {
if (Materials::ModelManager::getManager().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
@@ -287,9 +287,9 @@ void ModelSelect::addFavorites(QStandardItem* parent)
auto tree = ui->treeModels;
for (auto& uuid : _favorites) {
try {
auto model = getModelManager().getModel(uuid);
auto model = Materials::ModelManager::getManager().getModel(uuid);
if (getModelManager().passFilter(_filter, model->getType())) {
if (Materials::ModelManager::getManager().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
@@ -339,13 +339,13 @@ void ModelSelect::fillTree()
addExpanded(tree, model, lib);
addRecents(lib);
auto libraries = getModelManager().getModelLibraries();
auto libraries = Materials::ModelManager::getManager().getLibraries();
for (auto& library : *libraries) {
lib = new QStandardItem(library->getName());
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
addExpanded(tree, model, lib);
auto modelTree = getModelManager().getModelTree(library, _filter);
auto modelTree = Materials::ModelManager::getManager().getModelTree(library, _filter);
addModels(*lib, modelTree, QIcon(library->getIconPath()));
}
}
@@ -426,7 +426,7 @@ void ModelSelect::updateModelProperties(std::shared_ptr<Materials::Model> model)
void ModelSelect::updateMaterialModel(const QString& uuid)
{
auto model = getModelManager().getModel(uuid);
auto model = Materials::ModelManager::getManager().getModel(uuid);
// Update the general information
ui->editName->setText(model->getName());

View File

@@ -91,14 +91,9 @@ private:
void setColumnWidths(QTableView* table);
void updateModelProperties(std::shared_ptr<Materials::Model> model);
void createModelProperties();
Materials::ModelManager& getModelManager()
{
return _modelManager;
}
Materials::ModelFilter _filter;
std::unique_ptr<Ui_ModelSelect> ui;
Materials::ModelManager _modelManager;
QString _selected;
std::list<QString> _favorites;
std::list<QString> _recents;

View File

@@ -118,3 +118,220 @@ class ModelTestCases(unittest.TestCase):
self.assertIn("URL", dir(prop))
self.assertIn("Units", dir(prop))
self.assertEqual(prop.Name, "Density")
def testTestModelCompleteness(self):
""" Test that the Test model has been loaded correctly """
model = self.ModelManager.getModel(self.uuids.TestModel)
self.assertIsNotNone(model)
self.assertEqual(model.Name, "Test Model")
self.assertEqual(model.UUID, "34d0583d-f999-49ba-99e6-aa40bd5c3a6b")
self.assertIn("TestString", model.Properties)
self.assertEqual(len(model.Properties), 17)
prop = model.Properties["TestString"]
self.assertIn("Description", dir(prop))
self.assertIn("Name", dir(prop))
self.assertIn("Type", dir(prop))
self.assertIn("URL", dir(prop))
self.assertIn("Units", dir(prop))
self.assertEqual(prop.Name, "TestString")
self.assertEqual(prop.Type, "String")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A String")
prop = model.Properties["TestURL"]
self.assertEqual(prop.Name, "TestURL")
self.assertEqual(prop.Type, "URL")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A URL")
prop = model.Properties["TestList"]
self.assertEqual(prop.Name, "TestList")
self.assertEqual(prop.Type, "List")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A List")
prop = model.Properties["TestFileList"]
self.assertEqual(prop.Name, "TestFileList")
self.assertEqual(prop.Type, "FileList")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A List of file paths")
prop = model.Properties["TestImageList"]
self.assertEqual(prop.Name, "TestImageList")
self.assertEqual(prop.Type, "ImageList")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A List of embedded images")
prop = model.Properties["TestInteger"]
self.assertEqual(prop.Name, "TestInteger")
self.assertEqual(prop.Type, "Integer")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A Integer")
prop = model.Properties["TestFloat"]
self.assertEqual(prop.Name, "TestFloat")
self.assertEqual(prop.Type, "Float")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A Float")
prop = model.Properties["TestBoolean"]
self.assertEqual(prop.Name, "TestBoolean")
self.assertEqual(prop.Type, "Boolean")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A Boolean")
prop = model.Properties["TestColor"]
self.assertEqual(prop.Name, "TestColor")
self.assertEqual(prop.Type, "Color")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A Color")
prop = model.Properties["TestFile"]
self.assertEqual(prop.Name, "TestFile")
self.assertEqual(prop.Type, "File")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A File")
prop = model.Properties["TestSVG"]
self.assertEqual(prop.Name, "TestSVG")
self.assertEqual(prop.Type, "SVG")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "An SVG")
prop = model.Properties["TestImage"]
self.assertEqual(prop.Name, "TestImage")
self.assertEqual(prop.Type, "Image")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "An Image")
prop = model.Properties["TestQuantity"]
self.assertEqual(prop.Name, "TestQuantity")
self.assertEqual(prop.Type, "Quantity")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "kg/m^3")
self.assertEqual(prop.Description, "A Quantity")
prop = model.Properties["TestMultiLineString"]
self.assertEqual(prop.Name, "TestMultiLineString")
self.assertEqual(prop.Type, "MultiLineString")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "A string that spans multiple lines")
prop = model.Properties["TestArray2D"]
self.assertEqual(prop.Name, "TestArray2D")
self.assertEqual(prop.Type, "2DArray")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "2 Dimensional array showing density with temperature\n")
self.assertEqual(len(prop.Columns), 2)
col = prop.Columns[0]
self.assertIn("Description", dir(col))
self.assertIn("Name", dir(col))
self.assertIn("Type", dir(col))
self.assertIn("URL", dir(col))
self.assertIn("Units", dir(col))
self.assertEqual(col.Name, "Temperature")
self.assertEqual(col.Type, "Quantity")
self.assertEqual(col.URL, "")
self.assertEqual(col.Units, "C")
self.assertEqual(col.Description, "Temperature")
col = prop.Columns[1]
self.assertEqual(col.Name, "Density")
self.assertEqual(col.Type, "Quantity")
self.assertEqual(col.URL, "https://en.wikipedia.org/wiki/Density")
self.assertEqual(col.Units, "kg/m^3")
self.assertEqual(col.Description, "Density in [FreeCAD Density unit]")
prop = model.Properties["TestArray2D3Column"]
self.assertEqual(prop.Name, "TestArray2D3Column")
self.assertEqual(prop.Type, "2DArray")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "2 Dimensional array showing density and initial yield stress with temperature\n")
self.assertEqual(len(prop.Columns), 3)
col = prop.Columns[0]
self.assertEqual(col.Name, "Temperature")
self.assertEqual(col.Type, "Quantity")
self.assertEqual(col.URL, "")
self.assertEqual(col.Units, "C")
self.assertEqual(col.Description, "Temperature")
col = prop.Columns[1]
self.assertEqual(col.Name, "Density")
self.assertEqual(col.Type, "Quantity")
self.assertEqual(col.URL, "https://en.wikipedia.org/wiki/Density")
self.assertEqual(col.Units, "kg/m^3")
self.assertEqual(col.Description, "Density in [FreeCAD Density unit]")
col = prop.Columns[2]
self.assertEqual(col.Name, "InitialYieldStress")
self.assertEqual(col.Type, "Quantity")
self.assertEqual(col.URL, "")
self.assertEqual(col.Units, "kPa")
self.assertEqual(col.Description, "Saturation stress for Voce isotropic hardening [FreeCAD Pressure unit]\n")
prop = model.Properties["TestArray3D"]
self.assertEqual(prop.Name, "TestArray3D")
self.assertEqual(prop.Type, "3DArray")
self.assertEqual(prop.URL, "")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "3 Dimensional array showing stress and strain as a function of temperature\n")
self.assertEqual(len(prop.Columns), 3)
col = prop.Columns[0]
self.assertEqual(col.Name, "Temperature")
self.assertEqual(col.Type, "Quantity")
self.assertEqual(col.URL, "")
self.assertEqual(col.Units, "C")
self.assertEqual(col.Description, "Temperature")
col = prop.Columns[1]
self.assertEqual(col.Name, "Stress")
self.assertEqual(col.Type, "Quantity")
self.assertEqual(col.URL, "")
self.assertEqual(col.Units, "MPa")
self.assertEqual(col.Description, "Stress")
col = prop.Columns[2]
self.assertEqual(col.Name, "Strain")
self.assertEqual(col.Type, "Quantity")
self.assertEqual(col.URL, "")
self.assertEqual(col.Units, "MPa")
self.assertEqual(col.Description, "Strain")
def testModelInheritance(self):
""" Test that the inherited models have been loaded correctly """
model = self.ModelManager.getModel(self.uuids.LinearElastic)
self.assertIsNotNone(model)
self.assertEqual(model.Name, "Linear Elastic")
self.assertEqual(model.UUID, "7b561d1d-fb9b-44f6-9da9-56a4f74d7536")
self.assertIn("Density", model.Properties)
prop = model.Properties["Density"]
self.assertEqual(prop.Name, "Density")
self.assertEqual(prop.Type, "Quantity")
self.assertEqual(prop.URL, "https://en.wikipedia.org/wiki/Density")
self.assertEqual(prop.Units, "kg/m^3")
self.assertEqual(prop.Description, "Density in [FreeCAD Density unit]")
prop = model.Properties["BulkModulus"]
self.assertEqual(prop.Name, "BulkModulus")
self.assertEqual(prop.DisplayName, "Bulk Modulus")
self.assertEqual(prop.Type, "Quantity")
self.assertEqual(prop.URL, "https://en.wikipedia.org/wiki/Bulk_modulus")
self.assertEqual(prop.Units, "kPa")
self.assertEqual(prop.Description, "Bulk modulus in [FreeCAD Pressure unit]")
prop = model.Properties["PoissonRatio"]
self.assertEqual(prop.Name, "PoissonRatio")
self.assertEqual(prop.DisplayName, "Poisson Ratio")
self.assertEqual(prop.Type, "Float")
self.assertEqual(prop.URL, "https://en.wikipedia.org/wiki/Poisson%27s_ratio")
self.assertEqual(prop.Units, "")
self.assertEqual(prop.Description, "Poisson's ratio [unitless]")
prop = model.Properties["ShearModulus"]
self.assertEqual(prop.Name, "ShearModulus")
self.assertEqual(prop.DisplayName, "Shear Modulus")
self.assertEqual(prop.Type, "Quantity")
self.assertEqual(prop.URL, "https://en.wikipedia.org/wiki/Shear_modulus")
self.assertEqual(prop.Units, "kPa")
self.assertEqual(prop.Description, "Shear modulus in [FreeCAD Pressure unit]")
prop = model.Properties["YoungsModulus"]
self.assertEqual(prop.Name, "YoungsModulus")
self.assertEqual(prop.DisplayName, "Young's Modulus")
self.assertEqual(prop.Type, "Quantity")
self.assertEqual(prop.URL, "https://en.wikipedia.org/wiki/Young%27s_modulus")
self.assertEqual(prop.Units, "kPa")
self.assertEqual(prop.Description, "Young's modulus (or E-Module) in [FreeCAD Pressure unit]")

View File

@@ -57,12 +57,12 @@ protected:
QDir libDir(libPath);
libDir.removeRecursively(); // Clear old run data
libDir.mkdir(libPath);
_library = std::make_shared<Materials::MaterialLibrary>(QStringLiteral("Testing"),
_library = std::make_shared<Materials::MaterialLibraryLocal>(QStringLiteral("Testing"),
libPath,
QStringLiteral(":/icons/preferences-general.svg"),
false);
_modelManager = new Materials::ModelManager();
_materialManager = new Materials::MaterialManager();
_modelManager = &(Materials::ModelManager::getManager());
_materialManager = &(Materials::MaterialManager::getManager());
_testMaterialUUID = QStringLiteral("c6c64159-19c1-40b5-859c-10561f20f979");
}
@@ -70,7 +70,7 @@ protected:
// void TearDown() override {}
Materials::ModelManager* _modelManager;
Materials::MaterialManager* _materialManager;
std::shared_ptr<Materials::MaterialLibrary> _library;
std::shared_ptr<Materials::MaterialLibraryLocal> _library;
QString _testMaterialUUID;
};
@@ -187,17 +187,17 @@ TEST_F(TestMaterialCards, TestColumns)
EXPECT_TRUE(testMaterial->hasPhysicalProperty(QStringLiteral("TestArray2D")));
auto array2d = testMaterial->getPhysicalProperty(QStringLiteral("TestArray2D"))->getMaterialValue();
EXPECT_TRUE(array2d);
EXPECT_EQ(dynamic_cast<Materials::Material2DArray &>(*array2d).columns(), 2);
EXPECT_EQ(dynamic_cast<Materials::Array2D &>(*array2d).columns(), 2);
EXPECT_TRUE(testMaterial->hasPhysicalProperty(QStringLiteral("TestArray2D3Column")));
auto array2d3Column = testMaterial->getPhysicalProperty(QStringLiteral("TestArray2D3Column"))->getMaterialValue();
EXPECT_TRUE(array2d3Column);
EXPECT_EQ(dynamic_cast<Materials::Material2DArray &>(*array2d3Column).columns(), 3);
EXPECT_EQ(dynamic_cast<Materials::Array2D &>(*array2d3Column).columns(), 3);
EXPECT_TRUE(testMaterial->hasPhysicalProperty(QStringLiteral("TestArray3D")));
auto array3d = testMaterial->getPhysicalProperty(QStringLiteral("TestArray3D"))->getMaterialValue();
EXPECT_TRUE(array3d);
EXPECT_EQ(dynamic_cast<Materials::Material3DArray &>(*array3d).columns(), 2);
EXPECT_EQ(dynamic_cast<Materials::Array3D &>(*array3d).columns(), 2);
}
// clang-format on

View File

@@ -52,8 +52,8 @@ protected:
}
void SetUp() override {
_modelManager = new Materials::ModelManager();
_materialManager = new Materials::MaterialManager();
_modelManager = &(Materials::ModelManager::getManager());
_materialManager = &(Materials::MaterialManager::getManager());
// Use our test files as a custom directory
ParameterGrp::handle hGrp =
@@ -74,7 +74,7 @@ protected:
_materialManager->refresh();
_library = _materialManager->getLibrary(QLatin1String("Custom"));
_library = _materialManager->getLibrary(QStringLiteral("Custom"));
}
void TearDown() override {
@@ -153,7 +153,7 @@ TEST_F(TestMaterialFilter, TestFilters)
ASSERT_EQ(tree->size(), 5);
// Create a basic rendering filter
filter->setName(QLatin1String("Basic Appearance"));
filter->setName(QStringLiteral("Basic Appearance"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic);
options.setIncludeLegacy(false);
@@ -166,7 +166,7 @@ TEST_F(TestMaterialFilter, TestFilters)
// Create an advanced rendering filter
filter->clear();
filter->setName(QLatin1String("Advanced Appearance"));
filter->setName(QStringLiteral("Advanced Appearance"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Advanced);
options.setIncludeLegacy(false);
@@ -179,7 +179,7 @@ TEST_F(TestMaterialFilter, TestFilters)
// Create a Density filter
filter->clear();
filter->setName(QLatin1String("Density"));
filter->setName(QStringLiteral("Density"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Mechanical_Density);
options.setIncludeLegacy(false);
@@ -192,7 +192,7 @@ TEST_F(TestMaterialFilter, TestFilters)
// Create a Hardness filter
filter->clear();
filter->setName(QLatin1String("Hardness"));
filter->setName(QStringLiteral("Hardness"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Mechanical_Hardness);
options.setIncludeLegacy(false);
@@ -205,7 +205,7 @@ TEST_F(TestMaterialFilter, TestFilters)
// Create a Density and Basic Rendering filter
filter->clear();
filter->setName(QLatin1String("Density and Basic Rendering"));
filter->setName(QStringLiteral("Density and Basic Rendering"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic);
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Mechanical_Density);
options.setIncludeLegacy(false);
@@ -219,7 +219,7 @@ TEST_F(TestMaterialFilter, TestFilters)
// Create a Linear Elastic filter
filter->clear();
filter->setName(QLatin1String("Linear Elastic"));
filter->setName(QStringLiteral("Linear Elastic"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Mechanical_LinearElastic);
options.setIncludeLegacy(false);
@@ -231,7 +231,7 @@ TEST_F(TestMaterialFilter, TestFilters)
ASSERT_EQ(tree->size(), 0);
filter->clear();
filter->setName(QLatin1String("Linear Elastic"));
filter->setName(QStringLiteral("Linear Elastic"));
filter->addRequired(Materials::ModelUUIDs::ModelUUID_Mechanical_LinearElastic);
options.setIncludeLegacy(false);

View File

@@ -130,9 +130,9 @@ TEST_F(TestMaterialProperties, TestEmpty)
TEST_F(TestMaterialProperties, TestSingle)
{
Materials::MaterialProperty prop(modelProp1, QLatin1String("sampleUUID"));
Materials::MaterialProperty prop(modelProp1, QStringLiteral("sampleUUID"));
EXPECT_EQ(prop.getType(), Materials::MaterialValue::Quantity);
EXPECT_EQ(prop.getModelUUID(), QLatin1String("sampleUUID"));
EXPECT_EQ(prop.getModelUUID(), QStringLiteral("sampleUUID"));
EXPECT_TRUE(prop.isNull());
auto variant = prop.getValue();
EXPECT_TRUE(variant.canConvert<Base::Quantity>());
@@ -146,9 +146,9 @@ TEST_F(TestMaterialProperties, TestSingle)
void check2DArray(Materials::MaterialProperty& prop)
{
EXPECT_EQ(prop.getType(), Materials::MaterialValue::Array2D);
EXPECT_EQ(prop.getModelUUID(), QLatin1String("sampleUUID"));
EXPECT_EQ(prop.getModelUUID(), QStringLiteral("sampleUUID"));
EXPECT_TRUE(prop.isNull());
auto array = std::static_pointer_cast<Materials::Material2DArray>(prop.getMaterialValue());
auto array = std::static_pointer_cast<Materials::Array2D>(prop.getMaterialValue());
EXPECT_EQ(array->rows(), 0);
auto variant = prop.getValue(); // Throw an error?
EXPECT_FALSE(variant.canConvert<QString>());
@@ -162,20 +162,20 @@ void check2DArray(Materials::MaterialProperty& prop)
TEST_F(TestMaterialProperties, Test2DArray)
{
Materials::MaterialProperty prop(modelProp, QLatin1String("sampleUUID"));
Materials::MaterialProperty prop(modelProp, QStringLiteral("sampleUUID"));
check2DArray(prop);
}
TEST_F(TestMaterialProperties, Test2DArrayCopy)
{
Materials::MaterialProperty propBase(modelProp, QLatin1String("sampleUUID"));
Materials::MaterialProperty propBase(modelProp, QStringLiteral("sampleUUID"));
Materials::MaterialProperty prop(propBase);
check2DArray(prop);
}
TEST_F(TestMaterialProperties, Test2DArrayAssignment)
{
Materials::MaterialProperty propBase(modelProp, QLatin1String("sampleUUID"));
Materials::MaterialProperty propBase(modelProp, QStringLiteral("sampleUUID"));
Materials::MaterialProperty prop;
prop = propBase;
@@ -185,9 +185,9 @@ TEST_F(TestMaterialProperties, Test2DArrayAssignment)
void check3DArray(Materials::MaterialProperty& prop)
{
EXPECT_EQ(prop.getType(), Materials::MaterialValue::Array3D);
EXPECT_EQ(prop.getModelUUID(), QLatin1String("sampleUUID"));
EXPECT_EQ(prop.getModelUUID(), QStringLiteral("sampleUUID"));
EXPECT_TRUE(prop.isNull());
auto array = std::static_pointer_cast<Materials::Material3DArray>(prop.getMaterialValue());
auto array = std::static_pointer_cast<Materials::Array3D>(prop.getMaterialValue());
EXPECT_EQ(array->depth(), 0);
auto variant = prop.getValue(); // Throw an error?
EXPECT_FALSE(variant.canConvert<QString>());
@@ -201,20 +201,20 @@ void check3DArray(Materials::MaterialProperty& prop)
TEST_F(TestMaterialProperties, Test3DArray)
{
Materials::MaterialProperty prop(model3DProp, QLatin1String("sampleUUID"));
Materials::MaterialProperty prop(model3DProp, QStringLiteral("sampleUUID"));
check3DArray(prop);
}
TEST_F(TestMaterialProperties, Test3DArrayCopy)
{
Materials::MaterialProperty propBase(model3DProp, QLatin1String("sampleUUID"));
Materials::MaterialProperty propBase(model3DProp, QStringLiteral("sampleUUID"));
Materials::MaterialProperty prop(propBase);
check3DArray(prop);
}
TEST_F(TestMaterialProperties, Test3DArrayAssignment)
{
Materials::MaterialProperty propBase(model3DProp, QLatin1String("sampleUUID"));
Materials::MaterialProperty propBase(model3DProp, QStringLiteral("sampleUUID"));
Materials::MaterialProperty prop;
prop = propBase;

View File

@@ -172,7 +172,7 @@ TEST_F(TestMaterialValue, TestArray2DType)
{
EXPECT_THROW(auto mat1 = Materials::MaterialValue(Materials::MaterialValue::Array2D), Materials::InvalidMaterialType);
auto mat2 = Materials::Material2DArray();
auto mat2 = Materials::Array2D();
EXPECT_EQ(mat2.getType(), Materials::MaterialValue::Array2D);
EXPECT_TRUE(mat2.isNull());
EXPECT_EQ(mat2.rows(), 0);
@@ -182,7 +182,7 @@ TEST_F(TestMaterialValue, TestArray3DType)
{
EXPECT_THROW(auto mat1 = Materials::MaterialValue(Materials::MaterialValue::Array3D), Materials::InvalidMaterialType);
auto mat2 = Materials::Material3DArray();
auto mat2 = Materials::Array3D();
mat2.setColumns(2);
EXPECT_EQ(mat2.getType(), Materials::MaterialValue::Array3D);
EXPECT_TRUE(mat2.isNull());

View File

@@ -31,8 +31,8 @@
#include <QString>
#include <App/Application.h>
#include <Base/Quantity.h>
#include <Base/Interpreter.h>
#include <Base/Quantity.h>
#include <Gui/MetaTypes.h>
#include <src/App/InitApplication.h>
@@ -58,8 +58,8 @@ class TestMaterial : public ::testing::Test {
void SetUp() override {
Base::Interpreter().runString("import Part");
_modelManager = new Materials::ModelManager();
_materialManager = new Materials::MaterialManager();
_modelManager = &(Materials::ModelManager::getManager());
_materialManager = &(Materials::MaterialManager::getManager());
}
// void TearDown() override {}
@@ -72,11 +72,11 @@ TEST_F(TestMaterial, TestInstallation)
ASSERT_NE(_modelManager, nullptr);
// We should have loaded at least the system library
auto libraries = _materialManager->getMaterialLibraries();
auto libraries = _materialManager->getLibraries();
ASSERT_GT(libraries->size(), 0);
// We should have at least one material
auto materials = _materialManager->getMaterials();
auto materials = _materialManager->getLocalMaterials();
ASSERT_GT(materials->size(), 0);
}
@@ -97,7 +97,7 @@ TEST_F(TestMaterial, TestMaterialsWithModel)
// All LinearElastic models should be in IsotropicLinearElastic since it is inherited
EXPECT_LE(materialsLinearElastic->size(), materials->size());
for (auto itp : *materialsLinearElastic) {
for (auto &itp : *materialsLinearElastic) {
auto mat = itp.first;
EXPECT_NO_THROW(materials->at(mat));
}
@@ -365,17 +365,17 @@ TEST_F(TestMaterial, TestColumns)
EXPECT_TRUE(testMaterial.hasPhysicalProperty(QStringLiteral("TestArray2D")));
auto array2d = testMaterial.getPhysicalProperty(QStringLiteral("TestArray2D"))->getMaterialValue();
EXPECT_TRUE(array2d);
EXPECT_EQ(dynamic_cast<Materials::Material2DArray &>(*array2d).columns(), 2);
EXPECT_EQ(dynamic_cast<Materials::Array2D &>(*array2d).columns(), 2);
EXPECT_TRUE(testMaterial.hasPhysicalProperty(QStringLiteral("TestArray2D3Column")));
auto array2d3Column = testMaterial.getPhysicalProperty(QStringLiteral("TestArray2D3Column"))->getMaterialValue();
EXPECT_TRUE(array2d3Column);
EXPECT_EQ(dynamic_cast<Materials::Material2DArray &>(*array2d3Column).columns(), 3);
EXPECT_EQ(dynamic_cast<Materials::Array2D &>(*array2d3Column).columns(), 3);
EXPECT_TRUE(testMaterial.hasPhysicalProperty(QStringLiteral("TestArray3D")));
auto array3d = testMaterial.getPhysicalProperty(QStringLiteral("TestArray3D"))->getMaterialValue();
EXPECT_TRUE(array3d);
EXPECT_EQ(dynamic_cast<Materials::Material3DArray &>(*array3d).columns(), 2);
EXPECT_EQ(dynamic_cast<Materials::Array3D &>(*array3d).columns(), 2);
}
// clang-format on

View File

@@ -46,7 +46,7 @@ class TestModel : public ::testing::Test {
}
void SetUp() override {
_modelManager = new Materials::ModelManager();
_modelManager = &(Materials::ModelManager::getManager());
}
// void TearDown() override {}
@@ -76,7 +76,7 @@ TEST_F(TestModel, TestInstallation)
ASSERT_NE(_modelManager, nullptr);
// We should have loaded at least the system library
auto libraries = _modelManager->getModelLibraries();
auto libraries = _modelManager->getLibraries();
ASSERT_GT(libraries->size(), 0);
// We should have at least one model