Merge pull request #23140 from kadet1090/yaml-source-style-parameters
Gui: Add YamlParameterSource for StyleParameters
This commit is contained in:
@@ -141,6 +141,7 @@
|
||||
#include "QtWidgets.h"
|
||||
|
||||
#include <OverlayManager.h>
|
||||
#include <ParamHandler.h>
|
||||
#include <Base/ServiceProvider.h>
|
||||
|
||||
#ifdef BUILD_TRACY_FRAME_PROFILER
|
||||
@@ -381,20 +382,48 @@ struct PyMethodDef FreeCADGui_methods[] = {
|
||||
|
||||
void Application::initStyleParameterManager()
|
||||
{
|
||||
static ParamHandlers handlers;
|
||||
|
||||
const auto deduceParametersFilePath = []() -> std::string {
|
||||
const auto hMainWindowGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow");
|
||||
|
||||
if (const std::string& path = hMainWindowGrp->GetASCII("ThemeStyleParametersFile");
|
||||
!path.empty()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
return fmt::format("qss:parameters/{}.yaml", hMainWindowGrp->GetASCII("Theme", "Classic"));
|
||||
};
|
||||
|
||||
auto themeParametersSource = new StyleParameters::YamlParameterSource(
|
||||
deduceParametersFilePath(),
|
||||
{.name = QT_TR_NOOP("Theme Parameters"),
|
||||
.options = StyleParameters::ParameterSourceOption::UserEditable});
|
||||
|
||||
handlers.addDelayedHandler(
|
||||
"BaseApp/Preferences/MainWindow",
|
||||
{"ThemeStyleParametersFiles", "Theme"},
|
||||
[themeParametersSource, deduceParametersFilePath](ParameterGrp::handle) {
|
||||
themeParametersSource->changeFilePath(deduceParametersFilePath());
|
||||
});
|
||||
|
||||
Base::registerServiceImplementation<StyleParameters::ParameterSource>(
|
||||
new StyleParameters::BuiltInParameterSource({.name = QT_TR_NOOP("Built-in Parameters")}));
|
||||
|
||||
Base::registerServiceImplementation<StyleParameters::ParameterSource>(
|
||||
new StyleParameters::UserParameterSource(
|
||||
App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Themes/Tokens"),
|
||||
{.name = QT_TR_NOOP("Theme Parameters"),
|
||||
.options = StyleParameters::ParameterSourceOption::UserEditable}));
|
||||
|
||||
// todo: left for compatibility with older theme versions, to be removed before release
|
||||
Base::registerServiceImplementation<StyleParameters::ParameterSource>(
|
||||
new StyleParameters::UserParameterSource(
|
||||
App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Themes/UserTokens"),
|
||||
{.name = QT_TR_NOOP("Theme Parameters - Fallback"),
|
||||
.options = StyleParameters::ParameterSourceOption::ReadOnly}));
|
||||
|
||||
Base::registerServiceImplementation<StyleParameters::ParameterSource>(themeParametersSource);
|
||||
|
||||
Base::registerServiceImplementation<StyleParameters::ParameterSource>(
|
||||
new StyleParameters::UserParameterSource(
|
||||
App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Themes/UserParameters"),
|
||||
{.name = QT_TR_NOOP("User Parameters"),
|
||||
.options = StyleParameters::ParameterSource::UserEditable}));
|
||||
|
||||
|
||||
@@ -146,7 +146,9 @@ target_include_directories(
|
||||
${QtNetwork_INCLUDE_DIRS}
|
||||
${QtUiTools_INCLUDE_DIRS}
|
||||
${QtXml_INCLUDE_DIRS}
|
||||
${YAML_CPP_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
list(APPEND FreeCADGui_LIBS
|
||||
${QtCore_LIBRARIES}
|
||||
${QtWidgets_LIBRARIES}
|
||||
@@ -159,6 +161,18 @@ list(APPEND FreeCADGui_LIBS
|
||||
${QtUiTools_LIBRARIES}
|
||||
)
|
||||
|
||||
link_directories(${YAML_CPP_LIBRARY_DIR})
|
||||
|
||||
if(yaml-cpp_VERSION VERSION_LESS 0.8.0)
|
||||
list(APPEND FreeCADGui_LIBS
|
||||
${YAML_CPP_LIBRARIES}
|
||||
)
|
||||
else()
|
||||
list(APPEND FreeCADGui_LIBS
|
||||
yaml-cpp::yaml-cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${Qt5WinExtras_FOUND})
|
||||
target_include_directories(
|
||||
FreeCADGui
|
||||
|
||||
@@ -465,6 +465,10 @@ void StyleParametersModel::flush()
|
||||
}
|
||||
});
|
||||
|
||||
for (auto* source : sources) {
|
||||
source->flush();
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
#include "ParameterManager.h"
|
||||
#include "Parser.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <fstream>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <QColor>
|
||||
#include <QRegularExpression>
|
||||
@@ -35,6 +39,8 @@
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
FC_LOG_LEVEL_INIT("Gui", true, true)
|
||||
|
||||
namespace Gui::StyleParameters
|
||||
{
|
||||
|
||||
@@ -215,6 +221,92 @@ void UserParameterSource::remove(const std::string& name)
|
||||
hGrp->RemoveASCII(name.c_str());
|
||||
}
|
||||
|
||||
YamlParameterSource::YamlParameterSource(const std::string& filePath, const Metadata& metadata)
|
||||
: ParameterSource(metadata)
|
||||
{
|
||||
changeFilePath(filePath);
|
||||
}
|
||||
|
||||
void YamlParameterSource::changeFilePath(const std::string& path)
|
||||
{
|
||||
this->filePath = path;
|
||||
reload();
|
||||
}
|
||||
|
||||
void YamlParameterSource::reload()
|
||||
{
|
||||
QFile file(QString::fromStdString(filePath));
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
FC_TRACE("StyleParameters: Unable to open file " << filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (filePath.starts_with(":/")) {
|
||||
this->metadata.options |= ReadOnly;
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
std::string content = in.readAll().toStdString();
|
||||
|
||||
YAML::Node root = YAML::Load(content);
|
||||
parameters.clear();
|
||||
for (auto it = root.begin(); it != root.end(); ++it) {
|
||||
auto key = it->first.as<std::string>();
|
||||
auto value = it->second.as<std::string>();
|
||||
|
||||
parameters[key] = Parameter {
|
||||
.name = key,
|
||||
.value = value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
std::list<Parameter> YamlParameterSource::all() const
|
||||
{
|
||||
std::list<Parameter> result;
|
||||
for (const auto& param : parameters | std::views::values) {
|
||||
result.push_back(param);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<Parameter> YamlParameterSource::get(const std::string& name) const
|
||||
{
|
||||
if (auto it = parameters.find(name); it != parameters.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void YamlParameterSource::define(const Parameter& param)
|
||||
{
|
||||
parameters[param.name] = param;
|
||||
}
|
||||
|
||||
void YamlParameterSource::remove(const std::string& name)
|
||||
{
|
||||
parameters.erase(name);
|
||||
}
|
||||
|
||||
void YamlParameterSource::flush()
|
||||
{
|
||||
YAML::Node root;
|
||||
for (const auto& [name, param] : parameters) {
|
||||
root[name] = param.value;
|
||||
}
|
||||
|
||||
QFile file(QString::fromStdString(filePath));
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
|
||||
FC_WARN("StyleParameters: Unable to open file " << filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream out(&file);
|
||||
out << QString::fromStdString(YAML::Dump(root));
|
||||
}
|
||||
|
||||
ParameterManager::ParameterManager() = default;
|
||||
|
||||
void ParameterManager::reload()
|
||||
|
||||
@@ -306,6 +306,11 @@ public:
|
||||
* @param[in] name The name of the parameter to remove.
|
||||
*/
|
||||
virtual void remove([[maybe_unused]] const std::string& name) {}
|
||||
|
||||
/**
|
||||
* @brief Flushes buffered changes into more persistent storage.
|
||||
*/
|
||||
virtual void flush() {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -376,6 +381,43 @@ public:
|
||||
void remove(const std::string& name) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class YamlParameterSource
|
||||
* @brief A ParameterSource implementation that loads and saves parameters
|
||||
* from a YAML file using yaml-cpp.
|
||||
*
|
||||
* This class maintains an in-memory map of parameters loaded from a YAML file.
|
||||
* Any changes through define() or remove() will also update the file.
|
||||
*/
|
||||
class GuiExport YamlParameterSource : public ParameterSource
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a YamlParameterSource that reads parameters from the given YAML file.
|
||||
*
|
||||
* If the file exists, all key-value pairs are loaded into memory.
|
||||
* If the file does not exist, an empty parameter set is initialized.
|
||||
*
|
||||
* @param filePath Path to the YAML file used for persistence.
|
||||
* @param metadata Optional metadata describing this source.
|
||||
*/
|
||||
explicit YamlParameterSource(const std::string& filePath, const Metadata& metadata = {});
|
||||
|
||||
void changeFilePath(const std::string& path);
|
||||
void reload();
|
||||
|
||||
std::list<Parameter> all() const override;
|
||||
std::optional<Parameter> get(const std::string& name) const override;
|
||||
void define(const Parameter& param) override;
|
||||
void remove(const std::string& name) override;
|
||||
|
||||
void flush() override;
|
||||
|
||||
private:
|
||||
std::string filePath;
|
||||
std::map<std::string, Parameter> parameters;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Central manager for style parameters that aggregates multiple sources.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user