summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabien Proriol <fabien.proriol@kazoe.org>2025-05-22 17:10:35 +0200
committerFabien Proriol <fabien.proriol@kazoe.org>2025-05-26 10:48:46 +0200
commit2feba4447a482840e21fa2d3b33f1a5da12d09b7 (patch)
tree83a790b1ae5b5f32f5964350856a160dbed52e05
parentc842548fef050ac5f8b56a5fcb4f579820247434 (diff)
qt: Add Qt Wrapper library and QML module
-rw-r--r--.gitignore3
-rw-r--r--CMakeLists.txt115
-rw-r--r--cmake/CPack.cmake4
-rw-r--r--cmake/Config.cmake.in6
-rw-r--r--cmd/kzsettings.cpp (renamed from cmd/ksettings.cpp)6
-rw-r--r--python/bindings.cpp38
-rw-r--r--qt/cmake/Config.cmake.in9
-rw-r--r--qt/kzqproperty.cpp64
-rw-r--r--qt/kzqproperty.h38
-rw-r--r--qt/kzqsettings.cpp246
-rw-r--r--qt/kzqsettings.h34
-rw-r--r--qt/kzqsettings_plugin.cpp12
-rw-r--r--qt/kzqsettings_plugin.h15
-rw-r--r--qt/qml/qmldir2
-rw-r--r--src/changewatcher.cpp1
-rw-r--r--src/kzsettings.cpp (renamed from src/settings.cpp)66
-rw-r--r--src/kzsettings.h (renamed from src/settings.h)32
17 files changed, 589 insertions, 102 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c3897b5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+build*
+CMakeLists.txt.user*
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index acb7c5d..9d06877 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,34 +1,38 @@
cmake_minimum_required(VERSION 3.14)
-project(KaZoe-Settings VERSION 1.0.0 LANGUAGES CXX)
+project(KzSettings VERSION 1.0.0 LANGUAGES CXX)
-option(WITH_PYTHON "Create python binding" ON)
+option(WITH_PYTHON "Create python binding" ON)
+option(WITH_QT "Create Qt6 library and QML Module" ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
+include(GNUInstallDirs)
find_package (Threads REQUIRED)
-add_library(KaZoeSettings SHARED
- src/settings.h src/settings.cpp
+add_library(KzSettings SHARED
+ src/kzsettings.h src/kzsettings.cpp
src/changewatcher.h src/changewatcher.cpp
+ cmake/Config.cmake.in
+ cmake/CPack.cmake
)
-set_target_properties(KaZoeSettings PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION 1)
-set_target_properties(KaZoeSettings PROPERTIES PUBLIC_HEADER "src/settings.h")
-target_link_libraries(KaZoeSettings PRIVATE Threads::Threads)
+set_target_properties(KzSettings PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION 1)
+set_target_properties(KzSettings PROPERTIES PUBLIC_HEADER "src/kzsettings.h")
+target_link_libraries(KzSettings PRIVATE Threads::Threads)
-add_executable(ksettings cmd/ksettings.cpp)
-target_include_directories(ksettings PRIVATE src)
-target_link_libraries(ksettings KaZoeSettings)
+add_executable(kzsettings cmd/kzsettings.cpp)
+target_include_directories(kzsettings PRIVATE src)
+target_link_libraries(kzsettings KzSettings)
-install(TARGETS KaZoeSettings
- EXPORT "KaZoeSettingsTargets"
+install(TARGETS KzSettings
+ EXPORT "KzSettingsTargets"
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_PREFIX}/include/KaZoe/"
)
-install(TARGETS ksettings
+install(TARGETS kzsettings
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
@@ -39,33 +43,94 @@ if(WITH_PYTHON)
set(PYTHON_MODULE_EXTENSION ".so" CACHE INTERNAL "Cross python lib extension")
find_package(pybind11 REQUIRED)
include_directories(${Python3_INCLUDE_DIRS})
- pybind11_add_module(PyKaZoeSettings python/bindings.cpp)
- set_target_properties(PyKaZoeSettings PROPERTIES OUTPUT_NAME "KaZoeSettings")
- target_link_libraries(PyKaZoeSettings PUBLIC KaZoeSettings ${PYTHON_LIBRARY})
- install(TARGETS PyKaZoeSettings LIBRARY DESTINATION ${Python3_SITEARCH})
+ pybind11_add_module(PyKzSettings python/bindings.cpp)
+ set_target_properties(PyKzSettings PROPERTIES OUTPUT_NAME "KzSettings")
+ target_link_libraries(PyKzSettings PUBLIC KzSettings ${PYTHON_LIBRARY})
+ if(NOT PYTHONPATH)
+ set(PYTHONPATH ${Python3_SITEARCH})
+ endif(NOT PYTHONPATH)
+ install(TARGETS PyKzSettings LIBRARY DESTINATION ${PYTHONPATH})
endif(WITH_PYTHON)
-# CMake Module
include(CMakePackageConfigHelpers)
+
+if(WITH_QT)
+ if(NOT DEFINED QML_MODULE_INSTALL_PATH)
+ if(DEFINED OE_QMAKE_PATH_QML)
+ set(QML_MODULE_INSTALL_PATH ${OE_QMAKE_PATH_QML} )
+ else()
+ set(QML_MODULE_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/qml )
+ endif()
+ endif()
+ message(STATUS "Build with Qt module in ${QML_MODULE_INSTALL_PATH}")
+
+ find_package(Qt6 COMPONENTS Core Qml REQUIRED)
+ add_library(KzQSettings SHARED
+ qt/kzqsettings.h qt/kzqsettings.cpp
+ qt/kzqproperty.h qt/kzqproperty.cpp
+ qt/cmake/Config.cmake.in
+ )
+ target_link_libraries(KzQSettings PUBLIC Qt6::Core KzSettings)
+ set_target_properties(KzQSettings PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION 1)
+ set(KzQSettingsPublicHeader qt/kzqsettings.h qt/kzqproperty.h)
+ set_target_properties(KzQSettings PROPERTIES PUBLIC_HEADER "${KzQSettingsPublicHeader}")
+ install(TARGETS KzQSettings
+ EXPORT "KzQSettingsTargets"
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_PREFIX}/include/KaZoe/"
+ )
+ write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/generated/KzQSettingsConfigVersion.cmake" COMPATIBILITY SameMajorVersion
+ )
+
+ configure_package_config_file(
+ "qt/cmake/Config.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/generated/KzQSettingsConfig.cmake"
+ INSTALL_DESTINATION "lib/cmake/KzQSettings"
+ )
+
+ install(
+ FILES "${CMAKE_CURRENT_BINARY_DIR}/generated/KzQSettingsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/generated/KzQSettingsConfigVersion.cmake"
+ DESTINATION "lib/cmake/KzQSettings"
+ )
+
+ install(
+ EXPORT "KzQSettingsTargets"
+ DESTINATION "lib/cmake/KzQSettings"
+ )
+
+ set(PLUGIN_SOURCES
+ qt/kzqsettings_plugin.h qt/kzqsettings_plugin.cpp
+ qt/qml/qmldir
+ )
+
+ add_library(KzQSettingsPlugin SHARED ${PLUGIN_SOURCES})
+ target_link_libraries(KzQSettingsPlugin PRIVATE Qt6::Qml KzQSettings)
+ install(TARGETS KzQSettingsPlugin DESTINATION ${QML_MODULE_INSTALL_PATH}/org/kazoe/settings)
+ install(FILES qt/qml/qmldir DESTINATION ${QML_MODULE_INSTALL_PATH}/org/kazoe/settings)
+endif(WITH_QT)
+
+
write_basic_package_version_file(
- "${CMAKE_CURRENT_BINARY_DIR}/generated/KaZoeSettingsConfigVersion.cmake" COMPATIBILITY SameMajorVersion
+ "${CMAKE_CURRENT_BINARY_DIR}/generated/KzSettingsConfigVersion.cmake" COMPATIBILITY SameMajorVersion
)
configure_package_config_file(
"cmake/Config.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/generated/KaZoeSettingsConfig.cmake"
- INSTALL_DESTINATION "lib/cmake/${PROJECT_NAME}"
+ "${CMAKE_CURRENT_BINARY_DIR}/generated/KzSettingsConfig.cmake"
+ INSTALL_DESTINATION "lib/cmake/KzSettings"
)
install(
- FILES "${CMAKE_CURRENT_BINARY_DIR}/generated/KaZoeSettingsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/generated/KaZoeSettingsConfigVersion.cmake"
- DESTINATION "lib/cmake/${PROJECT_NAME}"
+ FILES "${CMAKE_CURRENT_BINARY_DIR}/generated/KzSettingsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/generated/KzSettingsConfigVersion.cmake"
+ DESTINATION "lib/cmake/KzSettings"
)
install(
- EXPORT "KaZoeSettingsTargets"
- DESTINATION "lib/cmake/${PROJECT_NAME}"
+ EXPORT "KzSettingsTargets"
+ DESTINATION "lib/cmake/KzSettings"
)
include(cmake/CPack.cmake)
diff --git a/cmake/CPack.cmake b/cmake/CPack.cmake
index 33169b1..b8b9f75 100644
--- a/cmake/CPack.cmake
+++ b/cmake/CPack.cmake
@@ -1,8 +1,8 @@
set(CPACK_GENERATOR "DEB")
-set(CPACK_PACKAGE_NAME "KaZoe-Settings")
+set(CPACK_PACKAGE_NAME "KzSettings")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "python3")
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
set(CPACK_PACKAGE_VERSION_PATCH "${CMAKE_PROJECT_VERSION_PATCH}")
-set(CPACK_PACKAGE_DESCRIPTION "KaZoe library")
+set(CPACK_PACKAGE_DESCRIPTION "KaZoe Settings library")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Fabien Proriol <fabien.proriol@kazoe.org>")
include(CPack)
diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in
index efbb7cc..cc295f1 100644
--- a/cmake/Config.cmake.in
+++ b/cmake/Config.cmake.in
@@ -1,7 +1,7 @@
@PACKAGE_INIT@
-include("${CMAKE_CURRENT_LIST_DIR}/KaZoeSettingsTargets.cmake")
-set(LIBKAZOESETTINGS_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include/@PROJECT_NAME@")
-set(LIBKAZOESETTINGS_LIBRARIES "KaZoeSettings" )
+include("${CMAKE_CURRENT_LIST_DIR}/KzSettingsTargets.cmake")
+set(LIBKZSETTINGS_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include/KaZoe")
+set(LIBKZSETTINGS_LIBRARIES "KzSettings" )
check_required_components("@PROJECT_NAME@")
diff --git a/cmd/ksettings.cpp b/cmd/kzsettings.cpp
index 0d29dab..2484e1d 100644
--- a/cmd/ksettings.cpp
+++ b/cmd/kzsettings.cpp
@@ -1,17 +1,17 @@
#include <iostream>
-#include <settings.h>
+#include <kzsettings.h>
using namespace std;
int main(int argc, char *argv[])
{
- KaZoe::Settings settings;
+ KaZoe::KzSettings settings;
if(argc < 2)
{
std::cout << "Current settings:" << std::endl;
- settings.forEach([](const SettingKey& key, const SettingValue& value) {
+ settings.forEach([](const KzSettingKey& key, const KzSettingValue& value) {
std::string head;
if(!key.first.empty())
{
diff --git a/python/bindings.cpp b/python/bindings.cpp
index 5c816f6..acce65b 100644
--- a/python/bindings.cpp
+++ b/python/bindings.cpp
@@ -1,65 +1,65 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
-#include "../src/settings.h"
+#include "../src/kzsettings.h"
namespace py = pybind11;
using namespace pybind11::literals;
-class PyKaZoeSettings {
- KaZoe::Settings m_settings;
+class KzPySettings {
+ KaZoe::KzSettings m_settings;
public:
- PyKaZoeSettings();
+ KzPySettings();
std::string __repr__();
static void add_python_binding(pybind11::module &m);
- SettingValue get(std::string key, std::string category, SettingValue def);
- SettingValue set(std::string key, SettingValue value, std::string category);
+ KzSettingValue get(std::string key, std::string category, KzSettingValue def);
+ KzSettingValue set(std::string key, KzSettingValue value, std::string category);
};
-PyKaZoeSettings::PyKaZoeSettings() {
+KzPySettings::KzPySettings() {
py::module sys = py::module::import("sys");
py::list argv = sys.attr("argv");
m_settings.setId(argv[0].cast<std::string>());
}
-SettingValue PyKaZoeSettings::get(std::string key, std::string category, SettingValue def) {
+KzSettingValue KzPySettings::get(std::string key, std::string category, KzSettingValue def) {
return m_settings.get(key, category, def);
}
-SettingValue PyKaZoeSettings::set(std::string key, SettingValue value, std::string category) {
+KzSettingValue KzPySettings::set(std::string key, KzSettingValue value, std::string category) {
return m_settings.set(key, value, category);
}
-std::string PyKaZoeSettings::__repr__() {
+std::string KzPySettings::__repr__() {
std::string result = "KaZoeSettings";
return result;
}
-void PyKaZoeSettings::add_python_binding(pybind11::module &m)
+void KzPySettings::add_python_binding(pybind11::module &m)
{
- py::class_<PyKaZoeSettings>(m, "KaZoeSettings")
+ py::class_<KzPySettings>(m, "KzSettings")
.def(py::init<>())
- .def("get", [] (PyKaZoeSettings &m, std::string key, std::string category = "", SettingValue def = SettingValue()) {
+ .def("get", [] (KzPySettings &m, std::string key, std::string category = "", KzSettingValue def = KzSettingValue()) {
return m.get(key, category, def);
},
py::arg("key"),
py::arg("category") = "",
- py::arg("default") = SettingValue())
- .def("set", [] (PyKaZoeSettings &m, std::string key, SettingValue value, std::string category = "") {
+ py::arg("default") = KzSettingValue())
+ .def("set", [] (KzPySettings &m, std::string key, KzSettingValue value, std::string category = "") {
return m.set(key, value, category);
},
py::arg("key"),
py::arg("value"),
py::arg("category") = "")
- .def("__repr__", &PyKaZoeSettings::__repr__);
+ .def("__repr__", &KzPySettings::__repr__);
}
-PYBIND11_MODULE(KaZoeSettings, m) {
+PYBIND11_MODULE(KzSettings, m) {
m.doc() = R"pbdoc(
- Python bindings for KaZoeSettings
+ Python bindings for KzSettings
)pbdoc";
- PyKaZoeSettings::add_python_binding(m);
+ KzPySettings::add_python_binding(m);
}
diff --git a/qt/cmake/Config.cmake.in b/qt/cmake/Config.cmake.in
new file mode 100644
index 0000000..a0d89fc
--- /dev/null
+++ b/qt/cmake/Config.cmake.in
@@ -0,0 +1,9 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake")
+set(LIBKZQSETTINGS_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/KaZoe")
+find_package(Qt6 COMPONENTS Core REQUIRED)
+find_package(KzSettings REQUIRED)
+set(LIBKZQSETTINGS_LIBRARIES "KzQSettings" "Qt6::Core" "${LIBKZSETTINGS_LIBRARIES}")
+
+check_required_components("@PROJECT_NAME@")
diff --git a/qt/kzqproperty.cpp b/qt/kzqproperty.cpp
new file mode 100644
index 0000000..4290e8c
--- /dev/null
+++ b/qt/kzqproperty.cpp
@@ -0,0 +1,64 @@
+#include "kzqproperty.h"
+#include "kzqsettings.h"
+
+namespace KaZoe {
+class KzQPropertyPrivate
+{
+ Q_DISABLE_COPY(KzQPropertyPrivate)
+ Q_DECLARE_PUBLIC(KaZoe::KzQProperty)
+
+ KaZoe::KzQProperty * const q_ptr;
+ QString m_key;
+ QVariant m_value;
+ KaZoe::KzQSettings m_settings;
+
+ KzQPropertyPrivate(KaZoe::KzQProperty* systemprop): q_ptr(systemprop){}
+};
+};
+
+KaZoe::KzQProperty::KzQProperty(QObject *parent)
+ : QObject{parent}
+ , d_ptr(new KaZoe::KzQPropertyPrivate(this))
+{
+ Q_D(KzQProperty);
+ QObject::connect(&d->m_settings, &KaZoe::KzQSettings::valueChanged, [this](QString id, QVariant value){
+ Q_D(KzQProperty);
+ if(id == d->m_key)
+ {
+ setValue(value);
+ }
+ });
+}
+
+KaZoe::KzQProperty::~KzQProperty() = default;
+
+QString KaZoe::KzQProperty::key() const
+{
+ Q_D(const KzQProperty);
+ return d->m_key;
+}
+
+void KaZoe::KzQProperty::setKey(const QString &newKey)
+{
+ Q_D(KzQProperty);
+ if (d->m_key == newKey)
+ return;
+ d->m_key = newKey;
+ setValue(d->m_settings.get(d->m_key));
+ emit keyChanged();
+}
+
+QVariant KaZoe::KzQProperty::value() const
+{
+ Q_D(const KzQProperty);
+ return d->m_value;
+}
+
+void KaZoe::KzQProperty::setValue(const QVariant &newValue)
+{
+ Q_D(KzQProperty);
+ if (d->m_value == newValue)
+ return;
+ d->m_value = newValue;
+ emit valueChanged();
+}
diff --git a/qt/kzqproperty.h b/qt/kzqproperty.h
new file mode 100644
index 0000000..8bd1b08
--- /dev/null
+++ b/qt/kzqproperty.h
@@ -0,0 +1,38 @@
+#ifndef KZQPROPERTY_H
+#define KZQPROPERTY_H
+
+#include <QObject>
+#include <QVariant>
+#include <QScopedPointer>
+
+namespace KaZoe {
+
+class KzQPropertyPrivate;
+class KzQProperty : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString key READ key WRITE setKey NOTIFY keyChanged)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ explicit KzQProperty(QObject *parent = nullptr);
+ ~KzQProperty();
+
+ QString key() const;
+ void setKey(const QString &newKey);
+
+ QVariant value() const;
+ void setValue(const QVariant &newValue);
+
+signals:
+ void keyChanged();
+ void valueChanged();
+
+private:
+ Q_DISABLE_COPY(KzQProperty)
+ Q_DECLARE_PRIVATE(KzQProperty)
+ QScopedPointer<KzQPropertyPrivate> d_ptr;
+};
+};
+
+#endif // KZQPROPERTY_H
diff --git a/qt/kzqsettings.cpp b/qt/kzqsettings.cpp
new file mode 100644
index 0000000..9ad4674
--- /dev/null
+++ b/qt/kzqsettings.cpp
@@ -0,0 +1,246 @@
+#include "kzqsettings.h"
+#include "../src/kzsettings.h"
+#include <qdebug.h>
+
+class QFileSystemWatcher;
+
+
+QVariant toQVariant(const KzSettingValue &value, QVariant defvalue = QVariant())
+{
+ if(std::holds_alternative<std::string>(value))
+ {
+ return QString::fromStdString(std::get<std::string>(value));
+ }
+ if(std::holds_alternative<int>(value))
+ {
+ return std::get<int>(value);
+ }
+ if(std::holds_alternative<bool>(value))
+ {
+ return std::get<bool>(value);
+ }
+ if(std::holds_alternative<double>(value))
+ {
+ return std::get<double>(value);
+ }
+ return QVariant(defvalue);
+}
+
+KzSettingValue fromQVariant(const QVariant &value)
+{
+ if(value.isNull())
+ return KzSettingValue();
+
+ switch (value.userType())
+ {
+ case QMetaType::Int:
+ return value.value<int>();
+
+ case QMetaType::QString:
+ return value.toString().toStdString();
+
+ case QMetaType::Bool:
+ return value.value<bool>();
+
+ case QMetaType::Double:
+ return value.value<double>();
+
+ default:
+ return false;
+ }
+}
+
+QString toKeyCombined(const std::string& category, const std::string& key)
+{
+ QString keysig;
+ if(category.size())
+ {
+ keysig.append("[");
+ keysig.append(QString::fromStdString(category));
+ keysig.append("]");
+ }
+ keysig.append(QString::fromStdString(key));
+ return keysig;
+}
+
+KaZoe::KzQSettings::KzQSettings(QObject *parent)
+ : QObject(parent)
+ , m_settings(new KaZoe::KzSettings())
+{
+ m_settings->setNotifier([this](const std::string& category, const std::string& key, KzSettingValue value) {
+ emit valueChanged(toKeyCombined(category, key), toQVariant(value));
+ });
+}
+
+KaZoe::KzQSettings::~KzQSettings()
+{
+}
+
+QVariant KaZoe::KzQSettings::getValue(const QString &id, QVariant defvalue)
+{
+ KaZoe::KzSettings settings;
+
+ QString category;
+ QString key = id;
+ if(id.contains("/"))
+ {
+ qWarning() << "OLD Syntax used for " << id;
+ QStringList tab = id.split("/");
+ category = tab[0];
+ tab.removeFirst();
+ key = tab.join("/");
+ }
+
+ KzSettingValue value = settings.get(key.toStdString(), category.toStdString(), fromQVariant(defvalue));
+ return toQVariant(value);
+}
+
+bool KaZoe::KzQSettings::setValue(const QString &id, const QVariant &value)
+{
+ KaZoe::KzSettings settings;
+ bool ret;
+ QString key = id;
+ QString category;
+
+ if(id.contains("/"))
+ {
+ qWarning() << "OLD Syntax used for " << id;
+ QStringList tab = id.split("/");
+ category = tab[0];
+ tab.removeFirst();
+ key = tab.join("/");
+ }
+
+ switch (value.userType())
+ {
+ case QMetaType::Int:
+ ret = settings.set(key.toStdString(), value.value<int>(), category.toStdString());
+ break;
+
+ case QMetaType::QString:
+ ret = settings.set(key.toStdString(), value.toString().toStdString(), category.toStdString());
+ break;
+
+ case QMetaType::Bool:
+ ret = settings.set(key.toStdString(), value.value<bool>(), category.toStdString());
+ break;
+
+ case QMetaType::Double:
+ ret = settings.set(key.toStdString(), value.value<double>(), category.toStdString());
+ break;
+ default:
+ ret = false;
+ break;
+ }
+
+ if(!ret)
+ {
+ qWarning() << "Settings ERROR: Write access not permitted for" << id << " with " << QString::fromStdString(settings.id());
+ return false;
+ }
+ return true;
+}
+
+
+int KaZoe::KzQSettings::count() const
+{
+ if(m_settings) return m_settings->size();
+ qWarning() << "Invalid object state for count";
+ return -1;
+}
+
+QVariant KaZoe::KzQSettings::get(const QString &id, const QVariant defvalue) const
+{
+ if(!m_settings)
+ {
+ qWarning() << "Invalid object state for get";
+ return QVariant();
+ }
+
+ QString category;
+ QString key = id;
+ if(id.contains("/"))
+ {
+ qWarning() << "OLD Syntax used for " << id;
+ QStringList tab = id.split("/");
+ category = tab[0];
+ tab.removeFirst();
+ key = tab.join("/");
+ }
+
+ KzSettingValue value = m_settings->get(key.toStdString(), category.toStdString(), fromQVariant(defvalue));
+ return toQVariant(value);
+}
+
+bool KaZoe::KzQSettings::set(const QString &id, const QVariant &value)
+{
+ if(!m_settings)
+ {
+ qWarning() << "Invalid object state for set";
+ return false;
+ }
+ bool ret;
+ QString key = id;
+ QString category;
+
+ if(id.contains("/"))
+ {
+ qWarning() << "OLD Syntax used for " << id;
+ QStringList tab = id.split("/");
+ category = tab[0];
+ tab.removeFirst();
+ key = tab.join("/");
+ }
+
+ switch (value.userType())
+ {
+ case QMetaType::Int:
+ ret = m_settings->set(key.toStdString(), value.value<int>(), category.toStdString());
+ break;
+
+ case QMetaType::QString:
+ ret = m_settings->set(key.toStdString(), value.toString().toStdString(), category.toStdString());
+ break;
+
+ case QMetaType::Bool:
+ ret = m_settings->set(key.toStdString(), value.value<bool>(), category.toStdString());
+ break;
+
+ case QMetaType::Double:
+ ret = m_settings->set(key.toStdString(), value.value<double>(), category.toStdString());
+ break;
+ default:
+ ret = false;
+ break;
+ }
+
+ if(!ret)
+ {
+ qWarning() << "Settings ERROR: Write access not permitted for" << id << " with " << QString::fromStdString(m_settings->id());
+ return false;
+ }
+
+ emit valueChanged(toKeyCombined(category.toStdString(), key.toStdString()), value);
+ return true;
+}
+
+QStringList KaZoe::KzQSettings::keys() const
+{
+ if(!m_settings)
+ {
+ qWarning() << "Invalid object state for keys";
+ return QStringList();
+ }
+
+ QStringList keys;
+ m_settings->forEach([&keys](const KzSettingKey& key, const KzSettingValue& value) {
+ std::string combined;
+ if(!key.first.empty())
+ {
+ combined = "[" + key.first + "]";
+ }
+ combined.append(key.second);
+ keys.append(QString::fromStdString(combined));
+ });
+ return keys;
+}
diff --git a/qt/kzqsettings.h b/qt/kzqsettings.h
new file mode 100644
index 0000000..6ab48a0
--- /dev/null
+++ b/qt/kzqsettings.h
@@ -0,0 +1,34 @@
+#ifndef KZQSETTINGS_H
+#define KZQSETTINGS_H
+
+#include <QObject>
+#include <QVariant>
+
+namespace KaZoe {
+
+class KzSettings;
+
+class KzQSettings : public QObject
+{
+ Q_OBJECT
+ QScopedPointer<KaZoe::KzSettings> m_settings;
+
+public:
+ explicit KzQSettings(QObject *parent = nullptr);
+ virtual ~KzQSettings();
+
+ static QVariant getValue(const QString &id, QVariant defvalue = QVariant());
+ static bool setValue(const QString &id, const QVariant &value);
+
+public slots:
+ int count() const;
+ QVariant get(const QString &id, const QVariant defvalue = QVariant()) const;
+ bool set(const QString &id, const QVariant &value);
+ QStringList keys() const;
+
+signals:
+ void valueChanged(QString id, QVariant value);
+};
+};
+
+#endif // KZQSETTINGS_H
diff --git a/qt/kzqsettings_plugin.cpp b/qt/kzqsettings_plugin.cpp
new file mode 100644
index 0000000..170324e
--- /dev/null
+++ b/qt/kzqsettings_plugin.cpp
@@ -0,0 +1,12 @@
+#include "kzqsettings_plugin.h"
+#include "kzqsettings.h"
+#include "kzqproperty.h"
+
+#include <qqml.h>
+
+void KzSettingsPlugin::registerTypes(const char *uri)
+{
+ // @uri kazoe
+ qmlRegisterType<KaZoe::KzQSettings>(uri, 1, 0, "KzSettings");
+ qmlRegisterType<KaZoe::KzQProperty>(uri, 1, 0, "KzProperty");
+}
diff --git a/qt/kzqsettings_plugin.h b/qt/kzqsettings_plugin.h
new file mode 100644
index 0000000..dcaf808
--- /dev/null
+++ b/qt/kzqsettings_plugin.h
@@ -0,0 +1,15 @@
+#ifndef KZSETTINGS_PLUGIN_H
+#define KZSETTINGS_PLUGIN_H
+
+#include <QQmlExtensionPlugin>
+
+class KzSettingsPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ void registerTypes(const char *uri) override;
+};
+
+#endif // SYSTEMSETTINGS_PLUGIN_H
diff --git a/qt/qml/qmldir b/qt/qml/qmldir
new file mode 100644
index 0000000..d15e7a3
--- /dev/null
+++ b/qt/qml/qmldir
@@ -0,0 +1,2 @@
+module org.kazoe.settings
+plugin KzQSettingsPlugin
diff --git a/src/changewatcher.cpp b/src/changewatcher.cpp
index 4762ebb..ef54019 100644
--- a/src/changewatcher.cpp
+++ b/src/changewatcher.cpp
@@ -1,5 +1,4 @@
#include "changewatcher.h"
-#include <iostream>
#include <filesystem>
#include <sys/inotify.h>
#include <sys/eventfd.h>
diff --git a/src/settings.cpp b/src/kzsettings.cpp
index addaa32..5580a80 100644
--- a/src/settings.cpp
+++ b/src/kzsettings.cpp
@@ -1,4 +1,4 @@
-#include "settings.h"
+#include "kzsettings.h"
#include <iostream>
#include <fstream>
#include <map>
@@ -23,29 +23,29 @@ static inline bool list_contains(std::vector<std::string> list, const std::strin
}
namespace KaZoe {
-class SettingsPrivate {
- friend class Settings;
- Settings *m_parent;
- std::map<SettingKey, SettingValue> m_data;
+class KzSettingsPrivate {
+ friend class KzSettings;
+ KzSettings *m_parent;
+ std::map<KzSettingKey, KzSettingValue> m_data;
ChangeWatcher m_watcher;
- std::map<SettingKey, std::string> m_owner;
+ std::map<KzSettingKey, std::string> m_owner;
std::string m_id;
std::mutex m_mutex_data;
std::mutex m_mutex_notifier;
bool m_bypass {false};
- std::vector<std::function<void(const std::string&, const std::string&, SettingValue)>> m_notifier;
+ std::vector<std::function<void(const std::string&, const std::string&, KzSettingValue)>> m_notifier;
public:
- SettingsPrivate(Settings *parent)
+ KzSettingsPrivate(KzSettings *parent)
: m_parent(parent) {
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
std::string binary = std::string(result, (count > 0) ? count : 0);
std::filesystem::path bin = binary;
m_id = bin.filename();
- if(m_id == "settings")
+ if(m_id == "kzsettings")
{
- // Only "settings cli tools can bypass the owner protection"
+ // Only "kzsettings cli tools can bypass the owner protection"
m_bypass = true;
}
@@ -54,7 +54,7 @@ public:
m_watcher.setFileWrited([this](const std::string path){ refreshFile(path); });
}
- void parseFile(const std::string &filename, std::map<SettingKey, SettingValue> &data, bool watch = false)
+ void parseFile(const std::string &filename, std::map<KzSettingKey, KzSettingValue> &data, bool watch = false)
{
if(!std::filesystem::exists(filename))
{
@@ -92,21 +92,21 @@ public:
if(key.starts_with("@"))
{
- m_owner[SettingKey(category, key.substr(1))] = value;
+ m_owner[KzSettingKey(category, key.substr(1))] = value;
continue;
}
if(key.ends_with("/owner"))
{
std::cerr << "WARNING: Legacy usage for owner: " << key << " should be @" << key.substr(0, key.size() - 6) << std::endl;
- m_owner[SettingKey(category, key.substr(0, key.size() - 6))] = value;
+ m_owner[KzSettingKey(category, key.substr(0, key.size() - 6))] = value;
continue;
}
- data[SettingKey(category, key)] = makeValue(value);
+ data[KzSettingKey(category, key)] = makeValue(value);
}
}
- void parseDir(const std::string &dconf, std::map<SettingKey, SettingValue> &data, bool watch)
+ void parseDir(const std::string &dconf, std::map<KzSettingKey, KzSettingValue> &data, bool watch)
{
if(std::filesystem::exists(dconf) && std::filesystem::is_directory(dconf))
{
@@ -118,7 +118,7 @@ public:
}
}
- void parseConf(const std::string &fconf, std::map<SettingKey, SettingValue> &data, bool watch)
+ void parseConf(const std::string &fconf, std::map<KzSettingKey, KzSettingValue> &data, bool watch)
{
if(std::filesystem::exists(fconf))
{
@@ -132,7 +132,7 @@ public:
}
}
- void refreshData(const std::map<SettingKey, SettingValue> &cust_data)
+ void refreshData(const std::map<KzSettingKey, KzSettingValue> &cust_data)
{
std::lock_guard<std::mutex> lock(m_mutex_data);
std::lock_guard<std::mutex> lock_notifier(m_mutex_notifier);
@@ -152,21 +152,21 @@ public:
void refreshFile(const std::string &file)
{
- std::map<SettingKey, SettingValue> cust_data;
+ std::map<KzSettingKey, KzSettingValue> cust_data;
parseFile(file, cust_data);
refreshData(cust_data);
}
void refreshDirectory(const std::string &dirname)
{
- std::map<SettingKey, SettingValue> cust_data;
+ std::map<KzSettingKey, KzSettingValue> cust_data;
parseDir(dirname, cust_data, true);
refreshData(cust_data);
}
void refreshAll()
{
- std::map<SettingKey, SettingValue> cust_data;
+ std::map<KzSettingKey, KzSettingValue> cust_data;
parseConf("/etc/kazoe.conf", cust_data, false);
parseConf("/var/kazoe.conf", cust_data, true);
refreshData(cust_data);
@@ -174,14 +174,14 @@ public:
};
};
-Settings::Settings()
- : m_ptr(std::make_unique<SettingsPrivate>(this))
+KzSettings::KzSettings()
+ : m_ptr(std::make_unique<KzSettingsPrivate>(this))
{
m_ptr->parseConf("/etc/kazoe.conf", m_ptr->m_data, false);
m_ptr->parseConf("/var/kazoe.conf", m_ptr->m_data, true);
}
-SettingValue Settings::get(const std::string &key, const std::string &category, SettingValue def) const
+KzSettingValue KzSettings::get(const std::string &key, const std::string &category, KzSettingValue def) const
{
std::lock_guard<std::mutex> lock(m_ptr->m_mutex_data);
std::string gkey = key;
@@ -192,7 +192,7 @@ SettingValue Settings::get(const std::string &key, const std::string &category,
gkey = gkey.substr(gkey.find(']') + 1);
}
- SettingKey pkey(gcategory, gkey);
+ KzSettingKey pkey(gcategory, gkey);
if(m_ptr->m_data.count(pkey))
{
@@ -201,11 +201,11 @@ SettingValue Settings::get(const std::string &key, const std::string &category,
return def;
}
-bool Settings::set(const std::string &key, SettingValue value, const std::string &category)
+bool KzSettings::set(const std::string &key, KzSettingValue value, const std::string &category)
{
// Check if variable is writable
std::lock_guard<std::mutex> lock(m_ptr->m_mutex_data);
- SettingKey pkey(category, key);
+ KzSettingKey pkey(category, key);
std::string id;
if(!m_ptr->m_owner.count(pkey))
@@ -229,7 +229,7 @@ bool Settings::set(const std::string &key, SettingValue value, const std::string
}
// Permission is OK, get old custom variable
- std::map<SettingKey, SettingValue> cust_data;
+ std::map<KzSettingKey, KzSettingValue> cust_data;
m_ptr->parseFile("/var/kazoe.conf.d/"+id+".conf", cust_data);
cust_data[pkey] = value;
std::string last_category = "";
@@ -248,30 +248,30 @@ bool Settings::set(const std::string &key, SettingValue value, const std::string
return true;
}
-std::string Settings::id() const
+std::string KzSettings::id() const
{
return m_ptr->m_id;
}
-void Settings::setId(const std::string &newid)
+void KzSettings::setId(const std::string &newid)
{
m_ptr->m_id = newid;
}
-void Settings::setNotifier(const std::function<void (const std::string &, const std::string &, SettingValue)> &callback)
+void KzSettings::setNotifier(const std::function<void (const std::string &, const std::string &, KzSettingValue)> &callback)
{
std::lock_guard<std::mutex> lock(m_ptr->m_mutex_notifier);
m_ptr->m_notifier.push_back(callback);
m_ptr->m_watcher.setEnable(true);
}
-std::size_t Settings::size() const
+std::size_t KzSettings::size() const
{
std::lock_guard<std::mutex> lock(m_ptr->m_mutex_data);
return m_ptr->m_data.size();
}
-void Settings::forEach(const std::function<void (const SettingKey &, const SettingValue &)> &callback) const
+void KzSettings::forEach(const std::function<void (const KzSettingKey &, const KzSettingValue &)> &callback) const
{
std::lock_guard<std::mutex> lock(m_ptr->m_mutex_data);
for (const auto& [key, value] : m_ptr->m_data) {
@@ -279,7 +279,7 @@ void Settings::forEach(const std::function<void (const SettingKey &, const Setti
}
}
-Settings::~Settings()
+KzSettings::~KzSettings()
{
m_ptr->m_watcher.setEnable(false);
}
diff --git a/src/settings.h b/src/kzsettings.h
index 5dfe90b..9f8d35b 100644
--- a/src/settings.h
+++ b/src/kzsettings.h
@@ -1,5 +1,5 @@
-#ifndef KAZOESETTINGS_H
-#define KAZOESETTINGS_H
+#ifndef KZSETTINGS_H
+#define KZSETTINGS_H
#include <functional>
#include <memory>
@@ -8,15 +8,15 @@
#include <algorithm>
/** @brief Key type for settings, composed of category and name */
-using SettingKey = std::pair<std::string, std::string>;
+using KzSettingKey = std::pair<std::string, std::string>;
/** @brief Value type that can hold string, int, double or boolean */
-using SettingValue = std::variant<std::string, int, double, bool>;
+using KzSettingValue = std::variant<std::string, int, double, bool>;
namespace KaZoe {
-class SettingsPrivate;
+class KzSettingsPrivate;
/**
* @brief Main class for managing KaZoe settings
@@ -24,14 +24,14 @@ class SettingsPrivate;
* This class provides a thread-safe interface for storing and retrieving
* configuration settings with support for different value types.
*/
-class Settings
+class KzSettings
{
public:
/** @brief Constructs a new Settings instance */
- explicit Settings();
+ explicit KzSettings();
/** @brief Virtual destructor */
- virtual ~Settings();
+ virtual ~KzSettings();
/**
* @brief Retrieves a setting value
@@ -40,7 +40,7 @@ public:
* @param def Default value if setting not found (optional)
* @return The setting value or default if not found
*/
- SettingValue get(const std::string &key, const std::string &category = "", SettingValue def = SettingValue()) const;
+ KzSettingValue get(const std::string &key, const std::string &category = "", KzSettingValue def = KzSettingValue()) const;
/**
* @brief Sets a setting value
@@ -49,7 +49,7 @@ public:
* @param category The setting category (optional)
* @return true if successful, false otherwise
*/
- bool set(const std::string &key, SettingValue value, const std::string &category = "");
+ bool set(const std::string &key, KzSettingValue value, const std::string &category = "");
/**
* @brief Gets the current instance identifier
@@ -67,7 +67,7 @@ public:
* @brief Sets a callback for setting changes notification
* @param callback Function to call when settings change
*/
- void setNotifier(const std::function<void(const std::string&, const std::string&, SettingValue)>& callback);
+ void setNotifier(const std::function<void(const std::string&, const std::string&, KzSettingValue)>& callback);
/**
* @brief Gets the number of settings
@@ -79,10 +79,10 @@ public:
* @brief Iterates over all settings in a thread-safe manner
* @param callback Function called for each key-value pair
*/
- void forEach(const std::function<void(const SettingKey&, const SettingValue&)>& callback) const;
+ void forEach(const std::function<void(const KzSettingKey&, const KzSettingValue&)>& callback) const;
private:
- std::unique_ptr<SettingsPrivate> m_ptr; ///< Private implementation pointer
+ std::unique_ptr<KzSettingsPrivate> m_ptr; ///< Private implementation pointer
};
@@ -103,7 +103,7 @@ struct settingValueFunctor {
* @param value Input SettingValue to convert
* @return std::string containing the converted value
*/
-static inline std::string valueToStr(const SettingValue &value)
+static inline std::string valueToStr(const KzSettingValue &value)
{
return std::visit(settingValueFunctor(), value);
}
@@ -133,7 +133,7 @@ static inline bool is_numeric(const std::string& str) {
* - "false"/"off" -> boolean false
* - Other -> string
*/
-static inline SettingValue makeValue(const std::string &value)
+static inline KzSettingValue makeValue(const std::string &value)
{
if(value.starts_with('"') || value.starts_with('\''))
{
@@ -177,4 +177,4 @@ static inline SettingValue makeValue(const std::string &value)
};
-#endif // KAZOESETTINGS_H
+#endif // KZSETTINGS_H