Materials: External Module Support
The final PR for the external module feature that allows materials to be stored in an external datastore, webservice, etc. This includes the final material manager classes, and the UI support in the form of commands and preference pages.
This commit is contained in:
committed by
Chris Hennes
parent
1bf21f85bd
commit
ffb7ab779b
@@ -33,6 +33,10 @@
|
||||
#include "MaterialManagerLocal.h"
|
||||
#include "ModelManagerLocal.h"
|
||||
#include "PropertyMaterial.h"
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
#include "ModelManagerExternal.h"
|
||||
#include "MaterialManagerExternal.h"
|
||||
#endif
|
||||
|
||||
#include "Array2DPy.h"
|
||||
#include "Array3DPy.h"
|
||||
@@ -107,6 +111,10 @@ PyMOD_INIT_FUNC(Materials)
|
||||
Materials::MaterialManagerLocal ::init();
|
||||
Materials::Model ::init();
|
||||
Materials::ModelManager ::init();
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
Materials::MaterialManagerExternal ::init();
|
||||
Materials::ModelManagerExternal ::init();
|
||||
#endif
|
||||
Materials::ModelManagerLocal ::init();
|
||||
Materials::ModelUUIDs ::init();
|
||||
|
||||
|
||||
@@ -22,6 +22,13 @@ include_directories(
|
||||
SYSTEM
|
||||
${YAML_CPP_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if (BUILD_MATERIAL_EXTERNAL)
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/src/3rdParty/lru-cache/include
|
||||
)
|
||||
endif(BUILD_MATERIAL_EXTERNAL)
|
||||
|
||||
link_directories(${YAML_CPP_LIBRARY_DIR})
|
||||
|
||||
if(BUILD_MATERIAL_EXTERNAL)
|
||||
@@ -70,6 +77,11 @@ SET(MaterialsAPI_Files
|
||||
MaterialAPI/MaterialManagerExternal.py
|
||||
)
|
||||
|
||||
SET(MaterialsAPI_Files
|
||||
MaterialAPI/__init__.py
|
||||
MaterialAPI/MaterialManagerExternal.py
|
||||
)
|
||||
|
||||
SET(Python_SRCS
|
||||
Exceptions.h
|
||||
Array2D.pyi
|
||||
@@ -145,6 +157,8 @@ if(BUILD_MATERIAL_EXTERNAL)
|
||||
list(APPEND Materials_SRCS
|
||||
ExternalManager.cpp
|
||||
ExternalManager.h
|
||||
MaterialManagerExternal.cpp
|
||||
MaterialManagerExternal.h
|
||||
ModelManagerExternal.cpp
|
||||
ModelManagerExternal.h
|
||||
)
|
||||
|
||||
@@ -188,7 +188,6 @@ ExternalManager::libraryFromObject(const Py::Object& entry)
|
||||
if (!pyName.isNone()) {
|
||||
libraryName = QString::fromStdString(pyName.as_string());
|
||||
}
|
||||
|
||||
QString icon;
|
||||
if (!pyIcon.isNone()) {
|
||||
icon = QString::fromStdString(pyIcon.as_string());
|
||||
|
||||
@@ -56,6 +56,11 @@ MaterialLibrary::MaterialLibrary(const QString& libraryName,
|
||||
, _local(false)
|
||||
{}
|
||||
|
||||
MaterialLibrary::MaterialLibrary(const Library& library)
|
||||
: Library(library)
|
||||
, _local(false)
|
||||
{}
|
||||
|
||||
bool MaterialLibrary::isLocal() const
|
||||
{
|
||||
return _local;
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
const QString& dir,
|
||||
const QString& icon,
|
||||
bool readOnly = true);
|
||||
MaterialLibrary(const Library& library);
|
||||
MaterialLibrary(const MaterialLibrary&) = delete;
|
||||
~MaterialLibrary() override = default;
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#include "MaterialConfigLoader.h"
|
||||
#include "MaterialLoader.h"
|
||||
#include "MaterialManager.h"
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
#include "MaterialManagerExternal.h"
|
||||
#endif
|
||||
#include "MaterialManagerLocal.h"
|
||||
#include "ModelManager.h"
|
||||
#include "ModelUuids.h"
|
||||
@@ -49,14 +52,25 @@ using namespace Materials;
|
||||
TYPESYSTEM_SOURCE(Materials::MaterialManager, Base::BaseClass)
|
||||
|
||||
QMutex MaterialManager::_mutex;
|
||||
bool MaterialManager::_useExternal = false;
|
||||
MaterialManager* MaterialManager::_manager = nullptr;
|
||||
std::unique_ptr<MaterialManagerLocal> MaterialManager::_localManager;
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
std::unique_ptr<MaterialManagerExternal> MaterialManager::_externalManager;
|
||||
#endif
|
||||
|
||||
MaterialManager::MaterialManager()
|
||||
{}
|
||||
{
|
||||
_hGrp = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface");
|
||||
_useExternal = _hGrp->GetBool("UseExternal", false);
|
||||
_hGrp->Attach(this);
|
||||
}
|
||||
|
||||
MaterialManager::~MaterialManager()
|
||||
{}
|
||||
{
|
||||
_hGrp->Detach(this);
|
||||
}
|
||||
|
||||
MaterialManager& MaterialManager::getManager()
|
||||
{
|
||||
@@ -77,6 +91,22 @@ void MaterialManager::initManagers()
|
||||
if (!_localManager) {
|
||||
_localManager = std::make_unique<MaterialManagerLocal>();
|
||||
}
|
||||
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
if (!_externalManager) {
|
||||
_externalManager = std::make_unique<MaterialManagerExternal>();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MaterialManager::OnChange(ParameterGrp::SubjectType& rCaller, ParameterGrp::MessageType Reason)
|
||||
{
|
||||
const ParameterGrp& rGrp = static_cast<ParameterGrp&>(rCaller);
|
||||
if (strcmp(Reason, "UseExternal") == 0) {
|
||||
Base::Console().Log("Use external changed\n");
|
||||
_useExternal = rGrp.GetBool("UseExternal", false);
|
||||
// _dbManager->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialManager::cleanup()
|
||||
@@ -84,6 +114,11 @@ void MaterialManager::cleanup()
|
||||
if (_localManager) {
|
||||
_localManager->cleanup();
|
||||
}
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
if (_externalManager) {
|
||||
_externalManager->cleanup();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MaterialManager::refresh()
|
||||
@@ -183,22 +218,52 @@ QString MaterialManager::defaultMaterialUUID()
|
||||
|
||||
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> MaterialManager::getLibraries()
|
||||
{
|
||||
auto libraries = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>();
|
||||
// External libraries take precedence over local libraries
|
||||
auto libMap = std::map<QString, std::shared_ptr<MaterialLibrary>>();
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
if (_useExternal) {
|
||||
auto remoteLibraries = _externalManager->getLibraries();
|
||||
for (auto& remote : *remoteLibraries) {
|
||||
libMap.try_emplace(remote->getName(), remote);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
auto localLibraries = _localManager->getLibraries();
|
||||
for (auto& local : *localLibraries) {
|
||||
libraries->push_back(local);
|
||||
libMap.try_emplace(local->getName(), local);
|
||||
}
|
||||
|
||||
// Consolidate into a single list
|
||||
auto libraries = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>();
|
||||
for (auto libEntry : libMap) {
|
||||
libraries->push_back(libEntry.second);
|
||||
}
|
||||
|
||||
return libraries;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> MaterialManager::getLocalLibraries()
|
||||
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>
|
||||
MaterialManager::getLocalLibraries()
|
||||
{
|
||||
return _localManager->getLibraries();
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialLibrary> MaterialManager::getLibrary(const QString& name) const
|
||||
{
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
if (_useExternal) {
|
||||
try
|
||||
{
|
||||
auto lib = _externalManager->getLibrary(name);
|
||||
if (lib) {
|
||||
return lib;
|
||||
}
|
||||
}
|
||||
catch (const LibraryNotFound& e) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// We really want to return the local library if not found, such as for User folder models
|
||||
return _localManager->getLibrary(name);
|
||||
}
|
||||
|
||||
@@ -233,6 +298,18 @@ void MaterialManager::removeLibrary(const QString& libraryName)
|
||||
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
|
||||
MaterialManager::libraryMaterials(const QString& libraryName)
|
||||
{
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
if (_useExternal) {
|
||||
try {
|
||||
auto materials = _externalManager->libraryMaterials(libraryName);
|
||||
if (materials) {
|
||||
return materials;
|
||||
}
|
||||
}
|
||||
catch (const LibraryNotFound& e) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return _localManager->libraryMaterials(libraryName);
|
||||
}
|
||||
|
||||
@@ -241,13 +318,42 @@ MaterialManager::libraryMaterials(const QString& libraryName,
|
||||
const std::shared_ptr<MaterialFilter>& filter,
|
||||
const MaterialFilterOptions& options)
|
||||
{
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
if (_useExternal) {
|
||||
try {
|
||||
auto materials = _externalManager->libraryMaterials(libraryName, filter, options);
|
||||
if (materials) {
|
||||
return materials;
|
||||
}
|
||||
}
|
||||
catch (const LibraryNotFound& e) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return _localManager->libraryMaterials(libraryName, filter, options);
|
||||
}
|
||||
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
bool MaterialManager::isLocalLibrary(const QString& libraryName)
|
||||
{
|
||||
if (_useExternal) {
|
||||
try {
|
||||
auto lib = _externalManager->getLibrary(libraryName);
|
||||
if (lib) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const LibraryNotFound& e) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
bool MaterialManager::isLocalLibrary(const QString& /*libraryName*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
//=====
|
||||
//
|
||||
@@ -346,6 +452,15 @@ MaterialManager::getLocalMaterials() const
|
||||
|
||||
std::shared_ptr<Material> MaterialManager::getMaterial(const QString& uuid) const
|
||||
{
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
if (_useExternal) {
|
||||
auto material = _externalManager->getMaterial(uuid);
|
||||
if (material) {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// We really want to return the local material if not found, such as for User folder models
|
||||
return _localManager->getMaterial(uuid);
|
||||
}
|
||||
|
||||
@@ -443,3 +558,55 @@ void MaterialManager::dereference(std::shared_ptr<Material> material) const
|
||||
{
|
||||
_localManager->dereference(material);
|
||||
}
|
||||
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
void MaterialManager::migrateToExternal(const std::shared_ptr<Materials::MaterialLibrary>& library)
|
||||
{
|
||||
_externalManager->createLibrary(library->getName(),
|
||||
library->getIconPath(),
|
||||
library->isReadOnly());
|
||||
|
||||
auto materials = _localManager->libraryMaterials(library->getName());
|
||||
for (auto& tuple : *materials) {
|
||||
auto uuid = std::get<0>(tuple);
|
||||
auto path = std::get<1>(tuple);
|
||||
auto name = std::get<2>(tuple);
|
||||
Base::Console().Log("\t('%s', '%s', '%s')\n",
|
||||
uuid.toStdString().c_str(),
|
||||
path.toStdString().c_str(),
|
||||
name.toStdString().c_str());
|
||||
|
||||
auto material = _localManager->getMaterial(uuid);
|
||||
if (!material->isOldFormat()) {
|
||||
_externalManager->migrateMaterial(library->getName(), path, material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialManager::validateMigration(const std::shared_ptr<Materials::MaterialLibrary>& library)
|
||||
{
|
||||
auto materials = _localManager->libraryMaterials(library->getName());
|
||||
for (auto& tuple : *materials) {
|
||||
auto uuid = std::get<0>(tuple);
|
||||
auto path = std::get<1>(tuple);
|
||||
auto name = std::get<2>(tuple);
|
||||
Base::Console().Log("\t('%s', '%s', '%s')\n",
|
||||
uuid.toStdString().c_str(),
|
||||
path.toStdString().c_str(),
|
||||
name.toStdString().c_str());
|
||||
|
||||
auto material = _localManager->getMaterial(uuid);
|
||||
if (!material->isOldFormat()) {
|
||||
auto externalMaterial = _externalManager->getMaterial(uuid);
|
||||
material->validate(externalMaterial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache stats
|
||||
double MaterialManager::materialHitRate()
|
||||
{
|
||||
initManagers();
|
||||
return _externalManager->materialHitRate();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -51,7 +51,7 @@ class MaterialManagerLocal;
|
||||
class MaterialFilter;
|
||||
class MaterialFilterOptions;
|
||||
|
||||
class MaterialsExport MaterialManager: public Base::BaseClass
|
||||
class MaterialsExport MaterialManager: public Base::BaseClass, ParameterGrp::ObserverType
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
|
||||
@@ -136,14 +136,31 @@ public:
|
||||
void dereference(std::shared_ptr<Material> material) const;
|
||||
void dereference() const;
|
||||
|
||||
/// Observer message from the ParameterGrp
|
||||
void OnChange(ParameterGrp::SubjectType& rCaller, ParameterGrp::MessageType Reason) override;
|
||||
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
void migrateToExternal(const std::shared_ptr<Materials::MaterialLibrary>& library);
|
||||
void validateMigration(const std::shared_ptr<Materials::MaterialLibrary>& library);
|
||||
|
||||
// Cache functions
|
||||
static double materialHitRate();
|
||||
#endif
|
||||
|
||||
private:
|
||||
MaterialManager();
|
||||
static void initManagers();
|
||||
|
||||
static MaterialManager* _manager;
|
||||
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
static std::unique_ptr<MaterialManagerExternal> _externalManager;
|
||||
#endif
|
||||
static std::unique_ptr<MaterialManagerLocal> _localManager;
|
||||
static QMutex _mutex;
|
||||
static bool _useExternal;
|
||||
|
||||
ParameterGrp::handle _hGrp;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
210
src/Mod/Material/App/MaterialManagerExternal.cpp
Normal file
210
src/Mod/Material/App/MaterialManagerExternal.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
/***************************************************************************
|
||||
* 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_
|
||||
#endif
|
||||
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "ExternalManager.h"
|
||||
#include "MaterialLibrary.h"
|
||||
#include "MaterialManagerExternal.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
/* TRANSLATOR Material::Materials */
|
||||
|
||||
QMutex MaterialManagerExternal::_mutex;
|
||||
LRU::Cache<std::string, std::shared_ptr<Material>>
|
||||
MaterialManagerExternal::_cache(DEFAULT_CACHE_SIZE);
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::MaterialManagerExternal, Base::BaseClass)
|
||||
|
||||
MaterialManagerExternal::MaterialManagerExternal()
|
||||
{
|
||||
initCache();
|
||||
}
|
||||
|
||||
void MaterialManagerExternal::initCache()
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface");
|
||||
auto cacheSize = hGrp->GetInt("MaterialCacheSize", DEFAULT_CACHE_SIZE);
|
||||
_cache.capacity(cacheSize);
|
||||
|
||||
_cache.monitor();
|
||||
}
|
||||
|
||||
void MaterialManagerExternal::cleanup()
|
||||
{}
|
||||
|
||||
void MaterialManagerExternal::refresh()
|
||||
{
|
||||
resetCache();
|
||||
}
|
||||
|
||||
//=====
|
||||
//
|
||||
// Library management
|
||||
//
|
||||
//=====
|
||||
|
||||
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> MaterialManagerExternal::getLibraries()
|
||||
{
|
||||
auto libraryList = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>();
|
||||
try {
|
||||
auto externalLibraries = ExternalManager::getManager()->libraries();
|
||||
for (auto& entry : *externalLibraries) {
|
||||
auto library = std::make_shared<MaterialLibrary>(*entry);
|
||||
libraryList->push_back(library);
|
||||
}
|
||||
}
|
||||
catch (const LibraryNotFound& e) {
|
||||
}
|
||||
catch (const ConnectionError& e) {
|
||||
}
|
||||
|
||||
return libraryList;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>>
|
||||
MaterialManagerExternal::getMaterialLibraries()
|
||||
{
|
||||
auto libraryList = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>();
|
||||
try {
|
||||
auto externalLibraries = ExternalManager::getManager()->materialLibraries();
|
||||
for (auto& entry : *externalLibraries) {
|
||||
auto library = std::make_shared<MaterialLibrary>(*entry);
|
||||
libraryList->push_back(library);
|
||||
}
|
||||
}
|
||||
catch (const LibraryNotFound& e) {
|
||||
}
|
||||
catch (const ConnectionError& e) {
|
||||
}
|
||||
|
||||
return libraryList;
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialLibrary> MaterialManagerExternal::getLibrary(const QString& name) const
|
||||
{
|
||||
try {
|
||||
auto lib = ExternalManager::getManager()->getLibrary(name);
|
||||
auto library = std::make_shared<MaterialLibrary>(*lib);
|
||||
return library;
|
||||
}
|
||||
catch (const LibraryNotFound& e) {
|
||||
throw LibraryNotFound(e);
|
||||
}
|
||||
catch (const ConnectionError& e) {
|
||||
throw LibraryNotFound(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialManagerExternal::createLibrary(const QString& libraryName,
|
||||
const QString& icon,
|
||||
bool readOnly)
|
||||
{
|
||||
ExternalManager::getManager()->createLibrary(libraryName, icon, readOnly);
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
|
||||
MaterialManagerExternal::libraryMaterials(const QString& libraryName)
|
||||
{
|
||||
return ExternalManager::getManager()->libraryMaterials(libraryName);
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<std::tuple<QString, QString, QString>>>
|
||||
MaterialManagerExternal::libraryMaterials(const QString& libraryName,
|
||||
const std::shared_ptr<MaterialFilter>& filter,
|
||||
const MaterialFilterOptions& options)
|
||||
{
|
||||
return ExternalManager::getManager()->libraryMaterials(libraryName, filter, options);
|
||||
}
|
||||
|
||||
//=====
|
||||
//
|
||||
// Material management
|
||||
//
|
||||
//=====
|
||||
|
||||
std::shared_ptr<Material> MaterialManagerExternal::getMaterial(const QString& uuid) const
|
||||
{
|
||||
if (_cache.contains(uuid.toStdString())) {
|
||||
return _cache.lookup(uuid.toStdString());
|
||||
}
|
||||
try {
|
||||
auto material = ExternalManager::getManager()->getMaterial(uuid);
|
||||
_cache.emplace(uuid.toStdString(), material);
|
||||
return material;
|
||||
}
|
||||
catch (const MaterialNotFound& e) {
|
||||
_cache.emplace(uuid.toStdString(), nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
catch (const ConnectionError& e) {
|
||||
_cache.emplace(uuid.toStdString(), nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialManagerExternal::addMaterial(const QString& libraryName,
|
||||
const QString& path,
|
||||
const std::shared_ptr<Material>& material)
|
||||
{
|
||||
_cache.erase(material->getUUID().toStdString());
|
||||
ExternalManager::getManager()->addMaterial(libraryName, path, material);
|
||||
}
|
||||
|
||||
void MaterialManagerExternal::migrateMaterial(const QString& libraryName,
|
||||
const QString& path,
|
||||
const std::shared_ptr<Material>& material)
|
||||
{
|
||||
_cache.erase(material->getUUID().toStdString());
|
||||
ExternalManager::getManager()->migrateMaterial(libraryName, path, material);
|
||||
}
|
||||
|
||||
//=====
|
||||
//
|
||||
// Cache management
|
||||
//
|
||||
//=====
|
||||
|
||||
void MaterialManagerExternal::resetCache()
|
||||
{
|
||||
_cache.clear();
|
||||
}
|
||||
|
||||
double MaterialManagerExternal::materialHitRate()
|
||||
{
|
||||
auto hitRate = _cache.stats().hit_rate();
|
||||
if (std::isnan(hitRate)) {
|
||||
return 0;
|
||||
}
|
||||
return hitRate;
|
||||
}
|
||||
102
src/Mod/Material/App/MaterialManagerExternal.h
Normal file
102
src/Mod/Material/App/MaterialManagerExternal.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/***************************************************************************
|
||||
* 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_MATERIALMANAGEREXTERNAl_H
|
||||
#define MATERIAL_MATERIALMANAGEREXTERNAl_H
|
||||
|
||||
#include <memory>
|
||||
#include <lru/lru.hpp>
|
||||
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
#include "FolderTree.h"
|
||||
#include "Materials.h"
|
||||
|
||||
class QMutex;
|
||||
|
||||
namespace App
|
||||
{
|
||||
class Material;
|
||||
}
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class MaterialLibrary;
|
||||
class MaterialLibraryExternal;
|
||||
class MaterialFilter;
|
||||
class MaterialFilterOptions;
|
||||
|
||||
class MaterialsExport MaterialManagerExternal: public Base::BaseClass
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
|
||||
public:
|
||||
MaterialManagerExternal();
|
||||
~MaterialManagerExternal() override = default;
|
||||
|
||||
static void cleanup();
|
||||
void refresh();
|
||||
|
||||
static const int DEFAULT_CACHE_SIZE = 100;
|
||||
|
||||
// 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& icon, bool readOnly = true);
|
||||
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
|
||||
|
||||
// Material management
|
||||
std::shared_ptr<Material> getMaterial(const QString& uuid) const;
|
||||
void addMaterial(const QString& libraryName,
|
||||
const QString& path,
|
||||
const std::shared_ptr<Material>& material);
|
||||
void migrateMaterial(const QString& libraryName,
|
||||
const QString& path,
|
||||
const std::shared_ptr<Material>& material);
|
||||
|
||||
// Cache functions
|
||||
void resetCache();
|
||||
double materialHitRate();
|
||||
|
||||
private:
|
||||
static void initCache();
|
||||
|
||||
static QMutex _mutex;
|
||||
|
||||
// Older platforms (Ubuntu 20.04) can't use QString as the index
|
||||
// due to a lack of a move constructor
|
||||
static LRU::Cache<std::string, std::shared_ptr<Material>> _cache;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MATERIALMANAGEREXTERNAl_H
|
||||
@@ -551,6 +551,7 @@ PyObject* MaterialPy::setAppearanceValue(PyObject* args)
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::setValue(PyObject* args)
|
||||
{
|
||||
char* name;
|
||||
@@ -595,7 +596,8 @@ PyObject* MaterialPy::setValue(PyObject* args)
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Either a string, a list, or an array are expected");
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Either a string, a list, or an array are expected");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -669,4 +671,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)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ 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:
|
||||
|
||||
@@ -46,7 +46,7 @@ class MaterialsExport ModelLibrary: public Library,
|
||||
|
||||
public:
|
||||
ModelLibrary();
|
||||
ModelLibrary(const Library& other);
|
||||
ModelLibrary(const Library& library);
|
||||
ModelLibrary(const QString& libraryName,
|
||||
const QString& dir,
|
||||
const QString& icon,
|
||||
|
||||
@@ -121,7 +121,7 @@ void ModelManagerLocal::createLibrary(const QString& libraryName,
|
||||
void ModelManagerLocal::renameLibrary(const QString& libraryName, const QString& newName)
|
||||
{
|
||||
for (auto& library : *_libraryList) {
|
||||
if (library->getName() == libraryName) {
|
||||
if (library->isName(libraryName)) {
|
||||
library->setName(newName);
|
||||
return;
|
||||
}
|
||||
@@ -133,7 +133,7 @@ void ModelManagerLocal::renameLibrary(const QString& libraryName, const QString&
|
||||
void ModelManagerLocal::changeIcon(const QString& libraryName, const QString& icon)
|
||||
{
|
||||
for (auto& library : *_libraryList) {
|
||||
if (library->getName() == libraryName) {
|
||||
if (library->isName(libraryName)) {
|
||||
library->setIconPath(icon);
|
||||
return;
|
||||
}
|
||||
@@ -145,7 +145,7 @@ void ModelManagerLocal::changeIcon(const QString& libraryName, const QString& ic
|
||||
void ModelManagerLocal::removeLibrary(const QString& libraryName)
|
||||
{
|
||||
for (auto& library : *_libraryList) {
|
||||
if (library->getName() == libraryName) {
|
||||
if (library->isName(libraryName)) {
|
||||
_libraryList->remove(library);
|
||||
|
||||
// At this point we should rebuild the model map
|
||||
@@ -163,7 +163,7 @@ ModelManagerLocal::libraryModels(const QString& libraryName)
|
||||
|
||||
for (auto& it : *_modelMap) {
|
||||
// This is needed to resolve cyclic dependencies
|
||||
if (it.second->getLibrary()->getName() == libraryName) {
|
||||
if (it.second->getLibrary()->isName(libraryName)) {
|
||||
models->push_back(
|
||||
std::tuple<QString, QString, QString>(it.first, it.second->getDirectory(), it.second->getName()));
|
||||
}
|
||||
@@ -217,7 +217,7 @@ std::shared_ptr<Model> ModelManagerLocal::getModelByPath(const QString& path,
|
||||
std::shared_ptr<ModelLibrary> ModelManagerLocal::getLibrary(const QString& name) const
|
||||
{
|
||||
for (auto& library : *_libraryList) {
|
||||
if (library->getName() == name) {
|
||||
if (library->isName(name)) {
|
||||
return library;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
#include "MaterialTreeWidget.h"
|
||||
#include "MaterialTreeWidgetPy.h"
|
||||
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
#include "DlgSettingsExternal.h"
|
||||
#endif
|
||||
|
||||
// use a different name to CreateCommand()
|
||||
void CreateMaterialCommands();
|
||||
|
||||
@@ -108,6 +112,10 @@ PyMOD_INIT_FUNC(MatGui)
|
||||
QT_TRANSLATE_NOOP("QObject", "Material"));
|
||||
new Gui::PrefPageProducer<MatGui::DlgSettingsDefaultMaterial>(
|
||||
QT_TRANSLATE_NOOP("QObject", "Material"));
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
new Gui::PrefPageProducer<MatGui::DlgSettingsExternal>(
|
||||
QT_TRANSLATE_NOOP("QObject", "Material"));
|
||||
#endif
|
||||
|
||||
// add resources and reloads the translators
|
||||
loadMaterialResource();
|
||||
|
||||
@@ -4,6 +4,10 @@ else(MSVC)
|
||||
add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
|
||||
endif(MSVC)
|
||||
|
||||
if(BUILD_MATERIAL_EXTERNAL)
|
||||
add_definitions(-DBUILD_MATERIAL_EXTERNAL)
|
||||
endif(BUILD_MATERIAL_EXTERNAL)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
@@ -54,6 +58,12 @@ set(MatGui_UIC_SRCS
|
||||
ModelSelect.ui
|
||||
TextEdit.ui
|
||||
)
|
||||
if(BUILD_MATERIAL_EXTERNAL)
|
||||
list(APPEND MatGui_UIC_SRCS
|
||||
DlgSettingsExternal.ui
|
||||
TaskMigrateExternal.ui
|
||||
)
|
||||
endif(BUILD_MATERIAL_EXTERNAL)
|
||||
|
||||
SET(MatGui_SRCS
|
||||
${Python_SRCS}
|
||||
@@ -126,6 +136,16 @@ SET(MatGui_SRCS
|
||||
WorkbenchManipulator.cpp
|
||||
WorkbenchManipulator.h
|
||||
)
|
||||
if(BUILD_MATERIAL_EXTERNAL)
|
||||
list(APPEND MatGui_SRCS
|
||||
DlgSettingsExternal.cpp
|
||||
DlgSettingsExternal.h
|
||||
DlgSettingsExternal.ui
|
||||
TaskMigrateExternal.cpp
|
||||
TaskMigrateExternal.h
|
||||
TaskMigrateExternal.ui
|
||||
)
|
||||
endif(BUILD_MATERIAL_EXTERNAL)
|
||||
|
||||
if(FREECAD_USE_PCH)
|
||||
add_definitions(-D_PreComp_)
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "MaterialSave.h"
|
||||
#include "MaterialsEditor.h"
|
||||
#include "ModelSelect.h"
|
||||
#include "TaskMigrateExternal.h"
|
||||
|
||||
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@@ -187,6 +188,37 @@ bool CmdInspectMaterial::isActive()
|
||||
return (Gui::Control().activeDialog() == nullptr);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Materials_MigrateToDatabase
|
||||
//===========================================================================
|
||||
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
DEF_STD_CMD_A(CmdMigrateToExternal)
|
||||
|
||||
CmdMigrateToExternal::CmdMigrateToExternal()
|
||||
: Command("Materials_MigrateToExternal")
|
||||
{
|
||||
sGroup = "Standard-View";
|
||||
sMenuText = QT_TR_NOOP("Migrate...");
|
||||
sToolTipText = QT_TR_NOOP("Migrate the materials to the external materials manager");
|
||||
sWhatsThis = "Materials_MigrateToDatabase";
|
||||
sStatusTip = QT_TR_NOOP("Migrate existing materials to the external materials manager");
|
||||
// sPixmap = "Materials_Edit";
|
||||
}
|
||||
|
||||
void CmdMigrateToExternal::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
MatGui::TaskMigrateExternal* dlg = new MatGui::TaskMigrateExternal();
|
||||
Gui::Control().showDialog(dlg);
|
||||
}
|
||||
|
||||
bool CmdMigrateToExternal::isActive()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------
|
||||
|
||||
void CreateMaterialCommands()
|
||||
@@ -198,4 +230,7 @@ void CreateMaterialCommands()
|
||||
rcCmdMgr.addCommand(new StdCmdSetMaterial());
|
||||
rcCmdMgr.addCommand(new CmdInspectAppearance());
|
||||
rcCmdMgr.addCommand(new CmdInspectMaterial());
|
||||
#if defined(BUILD_MATERIAL_EXTERNAL)
|
||||
rcCmdMgr.addCommand(new CmdMigrateToExternal());
|
||||
#endif
|
||||
}
|
||||
|
||||
133
src/Mod/Material/Gui/DlgSettingsExternal.cpp
Normal file
133
src/Mod/Material/Gui/DlgSettingsExternal.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/***************************************************************************
|
||||
* 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_
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
#include <Mod/Material/App/MaterialManager.h>
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
|
||||
#include "DlgSettingsExternal.h"
|
||||
#include "ui_DlgSettingsExternal.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
DlgSettingsExternal::DlgSettingsExternal(QWidget* parent)
|
||||
: PreferencePage(parent)
|
||||
, ui(new Ui_DlgSettingsExternal)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
DlgSettingsExternal::~DlgSettingsExternal()
|
||||
{}
|
||||
|
||||
void DlgSettingsExternal::saveSettings()
|
||||
{
|
||||
ParameterGrp::handle hGrp =
|
||||
App::GetApplication().GetParameterGroupByPath(getPreferences().c_str());
|
||||
|
||||
ui->spinModelCacheSize->onSave();
|
||||
ui->spinMaterialCacheSize->onSave();
|
||||
|
||||
bool useExternal = ui->groupExternal->isChecked();
|
||||
hGrp->SetBool("UseExternal", useExternal);
|
||||
hGrp->SetASCII("Current", ui->comboInterface->currentText().toStdString());
|
||||
}
|
||||
|
||||
QString DlgSettingsExternal::toPerCent(double value) const
|
||||
{
|
||||
QString pcString;
|
||||
pcString.setNum(int(value * 100.0));
|
||||
pcString += QLatin1String("%");
|
||||
|
||||
return pcString;
|
||||
}
|
||||
|
||||
void DlgSettingsExternal::loadSettings()
|
||||
{
|
||||
ParameterGrp::handle hGrp =
|
||||
App::GetApplication().GetParameterGroupByPath(getPreferences().c_str());
|
||||
|
||||
loadInterfaces();
|
||||
|
||||
bool useExternal = hGrp->GetBool("UseExternal", false);
|
||||
ui->groupExternal->setChecked(useExternal);
|
||||
|
||||
auto cacheSize = hGrp->GetInt("ModelCacheSize", 100);
|
||||
ui->spinModelCacheSize->setValue(cacheSize);
|
||||
cacheSize = hGrp->GetInt("MaterialCacheSize", 100);
|
||||
ui->spinMaterialCacheSize->setValue(cacheSize);
|
||||
|
||||
// Cache stats
|
||||
auto hitRate = Materials::ModelManager::modelHitRate();
|
||||
ui->inputModelCacheHitRate->setText(toPerCent(hitRate));
|
||||
hitRate = Materials::MaterialManager::materialHitRate();
|
||||
ui->inputMaterialCacheHitRate->setText(toPerCent(hitRate));
|
||||
}
|
||||
|
||||
void DlgSettingsExternal::loadInterfaces()
|
||||
{
|
||||
ParameterGrp::handle hGrp =
|
||||
App::GetApplication().GetParameterGroupByPath(getPreferencesInterfaces().c_str());
|
||||
|
||||
ui->comboInterface->clear();
|
||||
ui->comboInterface->addItem(tr("None"));
|
||||
|
||||
for (auto& group : hGrp->GetGroups()) {
|
||||
auto moduleName = QString::fromStdString(group->GetGroupName());
|
||||
|
||||
ui->comboInterface->addItem(moduleName);
|
||||
}
|
||||
|
||||
hGrp = App::GetApplication().GetParameterGroupByPath(getPreferences().c_str());
|
||||
auto current = hGrp->GetASCII("Current", "None");
|
||||
ui->comboInterface->setCurrentText(QString::fromStdString(current));
|
||||
}
|
||||
|
||||
std::string DlgSettingsExternal::getPreferences() const
|
||||
{
|
||||
return "User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface";
|
||||
}
|
||||
|
||||
std::string DlgSettingsExternal::getPreferencesInterfaces() const
|
||||
{
|
||||
return "User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface/Interfaces";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strings of the subwidgets using the current language.
|
||||
*/
|
||||
void DlgSettingsExternal::changeEvent(QEvent* e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
else {
|
||||
QWidget::changeEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_DlgSettingsExternal.cpp"
|
||||
58
src/Mod/Material/Gui/DlgSettingsExternal.h
Normal file
58
src/Mod/Material/Gui/DlgSettingsExternal.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/***************************************************************************
|
||||
* 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 MATGUI_DLGSETTINGSEXTERNAL_H
|
||||
#define MATGUI_DLGSETTINGSEXTERNAL_H
|
||||
|
||||
#include <Gui/PropertyPage.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
class Ui_DlgSettingsExternal;
|
||||
|
||||
class DlgSettingsExternal: public Gui::Dialog::PreferencePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DlgSettingsExternal(QWidget* parent = nullptr);
|
||||
~DlgSettingsExternal() override;
|
||||
|
||||
protected:
|
||||
void saveSettings() override;
|
||||
void loadSettings() override;
|
||||
void loadInterfaces();
|
||||
void changeEvent(QEvent* e) override;
|
||||
|
||||
std::string getPreferences() const;
|
||||
std::string getPreferencesInterfaces() const;
|
||||
|
||||
private:
|
||||
QString toPerCent(double value) const;
|
||||
|
||||
std::unique_ptr<Ui_DlgSettingsExternal> ui;
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_DLGSETTINGSDATABASE_H
|
||||
183
src/Mod/Material/Gui/DlgSettingsExternal.ui
Normal file
183
src/Mod/Material/Gui/DlgSettingsExternal.ui
Normal file
@@ -0,0 +1,183 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MatGui::DlgSettingsExternal</class>
|
||||
<widget class="QWidget" name="MatGui::DlgSettingsExternal">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>291</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>External Interface</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupExternal">
|
||||
<property name="title">
|
||||
<string>Use External Interface</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>External Interface</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="Gui::PrefComboBox" name="comboInterface">
|
||||
<property name="currentText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>Current</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Material/ExternalInterface</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Cache</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="inputModelCacheHitRate">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::PrefSpinBox" name="spinMaterialCacheSize">
|
||||
<property name="maximum">
|
||||
<number>4096</number>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>MaterialCacheSize</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Material/ExternalInterface</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Model Cache Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Hit Rate</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefSpinBox" name="spinModelCacheSize">
|
||||
<property name="maximum">
|
||||
<number>4096</number>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>ModelCacheSize</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Material/ExternalInterface</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="inputMaterialCacheHitRate"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Hit Rate</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Material Cache Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::PrefSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
209
src/Mod/Material/Gui/TaskMigrateExternal.cpp
Normal file
209
src/Mod/Material/Gui/TaskMigrateExternal.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <QFlags>
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Gui/WaitCursor.h>
|
||||
|
||||
#include "TaskMigrateExternal.h"
|
||||
#include "ui_TaskMigrateExternal.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
/* TRANSLATOR MatGui::DlgMigrateExternal */
|
||||
|
||||
DlgMigrateExternal::DlgMigrateExternal(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui_TaskMigrateExternal)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
showLibraries();
|
||||
}
|
||||
|
||||
void DlgMigrateExternal::showLibraries()
|
||||
{
|
||||
auto materialLibraries = Materials::MaterialManager::getManager().getLocalLibraries();
|
||||
for (auto library : *materialLibraries) {
|
||||
if (library->getName() != QLatin1String("User")) {
|
||||
auto item = new QListWidgetItem(library->getName());
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(Qt::Checked);
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(library));
|
||||
ui->listMaterialLibraries->addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
auto modelLibraries = Materials::ModelManager::getManager().getLocalLibraries();
|
||||
for (auto library : *modelLibraries) {
|
||||
if (library->getName() != QLatin1String("User")) {
|
||||
auto item = new QListWidgetItem(library->getName());
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(Qt::Checked);
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(library));
|
||||
ui->listModelLibraries->addItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DlgMigrateExternal::migrate()
|
||||
{
|
||||
try {
|
||||
statusUpdate(tr("Migrating Models..."));
|
||||
for (int row = 0; row < ui->listModelLibraries->count(); row++) {
|
||||
auto item = ui->listModelLibraries->item(row);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
auto library =
|
||||
item->data(Qt::UserRole).value<std::shared_ptr<Materials::ModelLibrary>>();
|
||||
statusUpdate(tr(" Library: ") + library->getName());
|
||||
Materials::ModelManager::getManager().migrateToExternal(library);
|
||||
}
|
||||
}
|
||||
statusUpdate(tr("done"));
|
||||
|
||||
statusUpdate(tr("Validating Models..."));
|
||||
for (int row = 0; row < ui->listModelLibraries->count(); row++) {
|
||||
auto item = ui->listModelLibraries->item(row);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
auto library =
|
||||
item->data(Qt::UserRole).value<std::shared_ptr<Materials::ModelLibrary>>();
|
||||
statusUpdate(tr(" Library: ") + library->getName());
|
||||
Materials::ModelManager::getManager().validateMigration(library);
|
||||
}
|
||||
}
|
||||
statusUpdate(tr("done"));
|
||||
|
||||
statusUpdate(tr("Migrating Materials..."));
|
||||
for (int row = 0; row < ui->listMaterialLibraries->count(); row++) {
|
||||
auto item = ui->listMaterialLibraries->item(row);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
auto library =
|
||||
item->data(Qt::UserRole).value<std::shared_ptr<Materials::MaterialLibrary>>();
|
||||
statusUpdate(tr(" Library: ") + library->getName());
|
||||
Materials::MaterialManager::getManager().migrateToExternal(library);
|
||||
}
|
||||
}
|
||||
statusUpdate(tr("done"));
|
||||
|
||||
statusUpdate(tr("Validating Materials..."));
|
||||
for (int row = 0; row < ui->listMaterialLibraries->count(); row++) {
|
||||
auto item = ui->listMaterialLibraries->item(row);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
auto library =
|
||||
item->data(Qt::UserRole).value<std::shared_ptr<Materials::MaterialLibrary>>();
|
||||
statusUpdate(tr(" Library: ") + library->getName());
|
||||
Materials::MaterialManager::getManager().validateMigration(library);
|
||||
}
|
||||
}
|
||||
statusUpdate(tr("done"));
|
||||
}
|
||||
catch (const Materials::ConnectionError& e) {
|
||||
statusUpdate(QString::fromStdString(e.what()));
|
||||
statusUpdate(tr("Aborted"));
|
||||
}
|
||||
catch (const Materials::CreationError& e) {
|
||||
statusUpdate(QString::fromStdString(e.what()));
|
||||
statusUpdate(tr("Aborted"));
|
||||
}
|
||||
catch (const Materials::InvalidModel& e) {
|
||||
statusUpdate(QString::fromStdString(e.what()));
|
||||
statusUpdate(tr("Aborted"));
|
||||
}
|
||||
catch (const Materials::InvalidMaterial& e) {
|
||||
statusUpdate(QString::fromStdString(e.what()));
|
||||
statusUpdate(tr("Aborted"));
|
||||
}
|
||||
catch (const Materials::InvalidProperty& e) {
|
||||
statusUpdate(QString::fromStdString(e.what()));
|
||||
statusUpdate(tr("Aborted"));
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
statusUpdate(QString::fromStdString(e.what()));
|
||||
statusUpdate(tr("Unknown exception - Aborted"));
|
||||
}
|
||||
}
|
||||
|
||||
void DlgMigrateExternal::statusUpdate(const QString& status)
|
||||
{
|
||||
Base::Console().Log("%s\n", status.toStdString().c_str());
|
||||
ui->textStatus->append(status);
|
||||
|
||||
// This is required to update in real time
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
/* TRANSLATOR MatGui::TaskMigrateExternal */
|
||||
|
||||
TaskMigrateExternal::TaskMigrateExternal()
|
||||
{
|
||||
_widget = new DlgMigrateExternal();
|
||||
addTaskBox(_widget);
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButtons TaskMigrateExternal::getStandardButtons() const
|
||||
{
|
||||
return QDialogButtonBox::Close | QDialogButtonBox::Ok;
|
||||
}
|
||||
|
||||
void TaskMigrateExternal::modifyStandardButtons(QDialogButtonBox* box)
|
||||
{
|
||||
_migrateButton = box->button(QDialogButtonBox::Ok);
|
||||
_closeButton = box->button(QDialogButtonBox::Close);
|
||||
_migrateButton->setText(QApplication::translate("MatGui::TaskMigrateExternal", "&Migrate"));
|
||||
// connect(btn, &QPushButton::clicked, this, &TaskMigrateExternal::onMigrate);
|
||||
}
|
||||
|
||||
void TaskMigrateExternal::onMigrate(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
Gui::WaitCursor wc;
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
// Disable the buttons during migration
|
||||
_migrateButton->setEnabled(false);
|
||||
_closeButton->setEnabled(false);
|
||||
|
||||
_widget->migrate();
|
||||
|
||||
_migrateButton->setEnabled(true);
|
||||
_closeButton->setEnabled(true);
|
||||
}
|
||||
|
||||
bool TaskMigrateExternal::accept()
|
||||
{
|
||||
_widget->migrate();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TaskMigrateExternal::reject()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#include "moc_TaskMigrateExternal.cpp"
|
||||
78
src/Mod/Material/Gui/TaskMigrateExternal.h
Normal file
78
src/Mod/Material/Gui/TaskMigrateExternal.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef MATGUI_TASKMIGRATEEXTERNAL_H
|
||||
#define MATGUI_TASKMIGRATEEXTERNAL_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#include <Gui/TaskView/TaskDialog.h>
|
||||
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
#include <Mod/Material/App/MaterialManager.h>
|
||||
|
||||
namespace MatGui {
|
||||
|
||||
class Ui_TaskMigrateExternal;
|
||||
|
||||
class DlgMigrateExternal: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DlgMigrateExternal(QWidget* parent = nullptr);
|
||||
~DlgMigrateExternal() override = default;
|
||||
void migrate();
|
||||
void statusUpdate(const QString& status);
|
||||
|
||||
private:
|
||||
void showLibraries();
|
||||
|
||||
std::shared_ptr<Ui_TaskMigrateExternal> ui;
|
||||
};
|
||||
|
||||
class TaskMigrateExternal: public Gui::TaskView::TaskDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskMigrateExternal();
|
||||
|
||||
public:
|
||||
bool accept() override;
|
||||
bool reject() override;
|
||||
QDialogButtonBox::StandardButtons getStandardButtons() const override;
|
||||
void modifyStandardButtons(QDialogButtonBox*) override;
|
||||
void onMigrate(bool checked);
|
||||
|
||||
private:
|
||||
DlgMigrateExternal* _widget;
|
||||
QPushButton* _migrateButton;
|
||||
QPushButton* _closeButton;
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_TASKMIGRATEEXTERNAL_H
|
||||
63
src/Mod/Material/Gui/TaskMigrateExternal.ui
Normal file
63
src/Mod/Material/Gui/TaskMigrateExternal.ui
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MatGui::TaskMigrateExternal</class>
|
||||
<widget class="QWidget" name="MatGui::TaskMigrateExternal">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Materials Migration</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Select Material Libraries</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listMaterialLibraries">
|
||||
<property name="toolTip">
|
||||
<string>Select material libraries to migrate. Existing materials will not be overwritten.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Select Model Libraries</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listModelLibraries">
|
||||
<property name="toolTip">
|
||||
<string>Select model libraries to migrate. Existing models will not be overwritten.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Status</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="textStatus">
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -57,6 +57,9 @@ class MaterialFilterTestCases(unittest.TestCase):
|
||||
self.useUserDir = param.GetBool("UseMaterialsFromConfigDir", True)
|
||||
self.useCustomDir = param.GetBool("UseMaterialsFromCustomDir", False)
|
||||
|
||||
paramExternal = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface")
|
||||
self.useExternal = paramExternal.GetBool("UseExternal", False)
|
||||
|
||||
filePath = os.path.dirname(__file__) + os.sep
|
||||
testPath = filePath + "Materials"
|
||||
param.SetString("CustomMaterialsDir", testPath)
|
||||
@@ -65,6 +68,8 @@ class MaterialFilterTestCases(unittest.TestCase):
|
||||
param.SetBool("UseMaterialsFromConfigDir", False)
|
||||
param.SetBool("UseMaterialsFromCustomDir", True)
|
||||
|
||||
paramExternal.SetBool("UseExternal", False)
|
||||
|
||||
self.MaterialManager.refresh()
|
||||
|
||||
def tearDown(self):
|
||||
@@ -77,6 +82,9 @@ class MaterialFilterTestCases(unittest.TestCase):
|
||||
param.SetBool("UseMaterialsFromConfigDir", self.useUserDir)
|
||||
param.SetBool("UseMaterialsFromCustomDir", self.useCustomDir)
|
||||
|
||||
paramExternal = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface")
|
||||
paramExternal.SetBool("UseExternal", self.useExternal)
|
||||
|
||||
self.MaterialManager.refresh()
|
||||
|
||||
def testFilter(self):
|
||||
|
||||
Reference in New Issue
Block a user