apply parametrization through AssignableProxy

Doesn't work as intended yet, see DynamicReadableConnection.cpp:44
This commit is contained in:
Jussi Kuokkanen 2023-08-28 18:35:44 +03:00
parent 9b22f14898
commit 407974c0b9
8 changed files with 85 additions and 20 deletions

View File

@ -0,0 +1,11 @@
#pragma once
class DeviceModel;
// Data that (needs) to be accessed globally, eg. main stacked widget
namespace Globals {
// This is used to search nodes by their DBus path to avoid passing pointers through many levels
extern DeviceModel *g_deviceModel;
} // namespace Globals

View File

@ -15,6 +15,7 @@
#include <QString>
#include <QTreeView>
#include <QVector>
#include <Globals.hpp>
#include <Tree.hpp>
#include <Utils.hpp>
@ -25,6 +26,8 @@ using namespace TuxClocker;
Q_DECLARE_METATYPE(TCDBus::DeviceNode)
Q_DECLARE_METATYPE(TCDBus::FlatTreeNode<TCDBus::DeviceNode>)
DeviceModel *Globals::g_deviceModel;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
qDBusRegisterMetaType<TCDBus::DeviceNode>();
qDBusRegisterMetaType<TCDBus::FlatTreeNode<TCDBus::DeviceNode>>();
@ -61,6 +64,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
auto browser = new DeviceBrowser(*model);
setCentralWidget(browser);
// TODO: make sure this is the only assignment
Globals::g_deviceModel = model;
Utils::writeAssignableDefaults(*model);
}

View File

@ -22,8 +22,7 @@ QVariant fromAssignmentArgument(TuxClocker::Device::AssignmentArgument arg) {
using ModelTraverseCallback = std::function<QModelIndex(QAbstractItemModel *, QModelIndex &, int)>;
void traverseModel(const ModelTraverseCallback &cb, QAbstractItemModel *model,
QModelIndex parent = QModelIndex()) {
void traverseModel(const ModelTraverseCallback &cb, QAbstractItemModel *model, QModelIndex parent) {
for (int i = 0; i < model->rowCount(parent); i++) {
// We get the next index we should traverse, and the funtion does
// its thing with the model and index

View File

@ -4,6 +4,10 @@
namespace Utils {
using ModelTraverseCallback = std::function<QModelIndex(QAbstractItemModel *, QModelIndex &, int)>;
void traverseModel(
const ModelTraverseCallback &, QAbstractItemModel *, QModelIndex parent = QModelIndex());
void writeAssignableDefaults(DeviceModel &model);
}
} // namespace Utils

View File

@ -1,6 +1,9 @@
#include "AssignableProxy.hpp"
#include <DBusTypes.hpp>
#include <DynamicReadableConnection.hpp>
#include <Globals.hpp>
#include <Utils.hpp>
#include <QDBusReply>
#include <QDBusMessage>
@ -19,6 +22,8 @@ AssignableProxy::AssignableProxy(QString path, QDBusConnection conn, QObject *pa
qDBusRegisterMetaType<TCD::Result<QDBusVariant>>();
m_iface =
new QDBusInterface("org.tuxclocker", path, "org.tuxclocker.Assignable", conn, this);
m_connection = nullptr;
}
std::optional<AssignmentError> AssignableProxy::doApply(const QVariant &v) {
@ -34,11 +39,57 @@ std::optional<AssignmentError> AssignableProxy::doApply(const QVariant &v) {
return AssignmentError::UnknownError;
}
std::optional<DynamicReadableProxy *> fromPath(QString path) {
DynamicReadableProxy *retval = nullptr;
auto cb = [&](auto model, auto index, int row) {
auto ifaceIndex = model->index(row, DeviceModel::InterfaceColumn, index);
auto dynProxyV = ifaceIndex.data(DeviceModel::DynamicReadableProxyRole);
if (dynProxyV.isValid()) {
auto dynProxy = qvariant_cast<DynamicReadableProxy *>(dynProxyV);
if (dynProxy->dbusPath() == path) {
// TODO: stop recursing here
retval = dynProxy;
}
}
return model->index(row, DeviceModel::NameColumn, index);
};
Utils::traverseModel(cb, Globals::g_deviceModel);
if (retval)
return retval;
return std::nullopt;
}
void AssignableProxy::apply() {
// A value hasn't been set yet
if (m_value.isNull())
return;
// Stop existing parametrization
if (m_connection) {
disconnect(m_connection, nullptr, nullptr, nullptr);
m_connection->stop();
delete m_connection;
m_connection = nullptr;
}
// Parametrization
if (m_value.canConvert<DynamicReadableConnectionData>()) {
auto data = m_value.value<DynamicReadableConnectionData>();
auto opt = fromPath(data.dynamicReadablePath);
if (opt.has_value()) {
auto proxy = opt.value();
m_connection = new DynamicReadableConnection<uint>{*proxy, data.points};
startConnection();
m_value = QVariant();
return;
}
}
// Use QDBusVariant since otherwise tries to call with the wrong signature
QDBusVariant dv(m_value);
QVariant v;
@ -48,9 +99,8 @@ void AssignableProxy::apply() {
m_value = QVariant();
}
void AssignableProxy::startConnection(std::shared_ptr<AssignableConnection> conn) {
m_assignableConnection = conn;
connect(conn.get(), &AssignableConnection::targetValueChanged,
void AssignableProxy::startConnection() {
QObject::connect(m_connection, &AssignableConnection::targetValueChanged,
[this](auto targetValue, auto text) {
auto err = doApply(targetValue);
if (err.has_value())
@ -60,7 +110,7 @@ void AssignableProxy::startConnection(std::shared_ptr<AssignableConnection> conn
});
// Emit started signal in case a connection emits a new value right away
emit connectionStarted();
m_assignableConnection->start();
m_connection->start();
}
// DBus type to the more precise C++ type

View File

@ -4,6 +4,7 @@
#include <AssignableConnection.hpp>
#include <Device.hpp>
#include <DynamicReadableConnection.hpp>
#include <memory>
#include <QDebug>
#include <QDBusConnection>
@ -17,7 +18,6 @@ class AssignableProxy : public QObject {
public:
AssignableProxy(QString path, QDBusConnection conn, QObject *parent = nullptr);
void apply();
void startConnection(std::shared_ptr<AssignableConnection> conn);
// Stop connection and clear current connection
void stopConnection();
void setValue(QVariant v) { m_value = v; }
@ -34,8 +34,11 @@ private:
QVariant m_value;
QDBusInterface *m_iface;
DynamicReadableConnection<uint> *m_connection;
// This is a bit of a peril but not sure if we can store interfaces any better...
std::shared_ptr<AssignableConnection> m_assignableConnection;
std::optional<TC::Device::AssignmentError> doApply(const QVariant &v);
void startConnection();
};

View File

@ -25,6 +25,8 @@ public:
QString dynamicReadablePath;
};
Q_DECLARE_METATYPE(DynamicReadableConnectionData)
// TODO: make DynamicReadableProxy type parametrized so we can be sure to only get numeric values
// from it Connection of an Assignable with a DynamicReadable
template <typename OutType> // Result of linear interpolation
@ -39,16 +41,7 @@ public:
}
virtual QVariant connectionData() override { return QVariant(); }
virtual void start() override {
/*QObject::connect(&m_timer, &QTimer::timeout, [this] {
int rand = QRandomGenerator::global()->bounded(0, 10);
QDBusVariant arg{QVariant{rand}};
QVariant v;
v.setValue(arg);
emit targetValueChanged(v, QString::number(rand));
});
m_timer.start(1000);*/
// TODO: Something goes wrong here (not always!!)
connect(&m_proxy, &DynamicReadableProxy::valueChanged, [this](auto val) {
match(val)(pattern(as<ReadableValue>(arg)) = [this](auto rv) {
match(rv)(pattern(as<uint>(arg)) = [this](auto u) {
@ -62,7 +55,7 @@ public:
v.setValue(arg);
emit targetValueChanged(v, "1");*/
}
virtual void stop() override {}
virtual void stop() override { disconnect(&m_proxy, nullptr, nullptr, nullptr); }
private:
DynamicReadableProxy &m_proxy;
QTimer m_timer;

View File

@ -32,7 +32,6 @@
// Delet this
namespace p = mpark::patterns;
Q_DECLARE_METATYPE(DynamicReadableConnectionData)
Q_DECLARE_METATYPE(DynamicReadableProxy *)
// TODO: make constructor of the type data Editor a = Maybe (Range a)