summaryrefslogtreecommitdiffhomepage
path: root/facetracknoir/options.h
diff options
context:
space:
mode:
Diffstat (limited to 'facetracknoir/options.h')
-rw-r--r--facetracknoir/options.h144
1 files changed, 95 insertions, 49 deletions
diff --git a/facetracknoir/options.h b/facetracknoir/options.h
index 37377b55..b4b1f0f7 100644
--- a/facetracknoir/options.h
+++ b/facetracknoir/options.h
@@ -8,9 +8,11 @@
#pragma once
#include <memory>
+#include <tuple>
+#include <map>
+
#include <QObject>
#include <QSettings>
-#include <QMap>
#include <QString>
#include <QVariant>
#include <QMutex>
@@ -25,9 +27,14 @@
#include <QLabel>
#include <QCoreApplication>
+#include <cinttypes>
+
#include <QDebug>
namespace options {
+ template<typename k, typename v>
+ using map = std::map<k, v>;
+
template<typename t>
// don't elide usages of the function, qvariant default implicit
// conversion results in nonsensical runtime behavior -sh
@@ -66,7 +73,7 @@ namespace options {
// snapshot of qsettings group at given time
class group {
private:
- QMap<QString, QVariant> map;
+ map<QString, QVariant> map;
QString name;
static const QString ini_pathname()
{
@@ -85,39 +92,42 @@ namespace options {
}
static constexpr const char* org = "opentrack";
- void save() {
+ void save()
+ {
QSettings s(ini_pathname(), QSettings::IniFormat);
s.beginGroup(name);
- for (auto& k : map.keys())
- s.setValue(k, map[k]);
+ for (auto& i : map)
+ s.setValue(i.first, map[i.first]);
s.endGroup();
}
+
template<typename t>
- t get(const QString& k) {
- return qcruft_to_t<t>(map.value(k));
+ t get(const QString& k)
+ {
+ return qcruft_to_t<t>(map[k]);
}
+
void put(const QString& s, const QVariant& d)
{
map[s] = d;
}
+
bool contains(const QString& s)
{
- return map.contains(s);
+ return map.count(s) != 0;
}
};
class impl_bundle : public QObject {
Q_OBJECT
- private:
+ protected:
QMutex mtx;
const QString group_name;
group saved;
group transient;
+ bool modified;
impl_bundle(const impl_bundle&) = delete;
impl_bundle& operator=(const impl_bundle&) = delete;
- bool modified;
- signals:
- void changed();
public:
impl_bundle(const QString& group_name) :
mtx(QMutex::Recursive),
@@ -127,25 +137,32 @@ namespace options {
modified(false)
{
}
+
+ QString name() { return group_name; }
+
void reload() {
QMutexLocker l(&mtx);
saved = group(group_name);
transient = saved;
+ modified = false;
}
- void store_kv(const QString& name, const QVariant& datum)
+
+ bool store_kv(const QString& name, const QVariant& datum)
{
QMutexLocker l(&mtx);
+
auto old = transient.get<QVariant>(name);
if (!transient.contains(name) || datum != old)
{
if (!modified)
- qDebug() << "bundle" << group_name <<
- "modified due to" << name <<
- transient.get<QVariant>(name) <<
- old << "->" << datum;
+ qDebug() << "bundle" << (intptr_t)static_cast<void*>(this) <<
+ "modified as per" << name << old << "->" << datum;
+
modified = true;
transient.put(name, datum);
+ return true;
}
+ return false;
}
bool contains(const QString& name)
{
@@ -153,7 +170,8 @@ namespace options {
return transient.contains(name);
}
template<typename t>
- t get(const QString& name) {
+ t get(const QString& name)
+ {
QMutexLocker l(&mtx);
return transient.get<t>(name);
}
@@ -163,14 +181,6 @@ namespace options {
modified = false;
saved = transient;
transient.save();
- emit changed();
- }
- void revert()
- {
- QMutexLocker l(&mtx);
- modified = false;
- transient = saved;
- emit changed();
}
bool modifiedp() {
@@ -178,15 +188,64 @@ namespace options {
return modified;
}
};
-
- using pbundle = std::shared_ptr<impl_bundle>;
+
+ class opt_bundle;
+ using pbundle = std::shared_ptr<opt_bundle>;
+
+ namespace {
+ using tt = std::tuple<int, pbundle>;
+
+ QMutex implsgl_mtx(QMutex::Recursive);
+ map<QString, tt> implsgl_bundles;
+ }
+
+ class opt_bundle : public impl_bundle
+ {
+ public:
+ opt_bundle() : impl_bundle("i-have-no-name") {}
+ opt_bundle(const QString& group_name) : impl_bundle(group_name) {}
+
+ ~opt_bundle()
+ {
+ QMutexLocker l(&implsgl_mtx);
+
+ if (--std::get<0>(implsgl_bundles[this->group_name]) == 0)
+ implsgl_bundles.erase(this->group_name);
+ }
+ };
+
+ inline pbundle bundle(const QString& group) {
+ QMutexLocker l(&implsgl_mtx);
+
+ if (implsgl_bundles.count(group) != 0)
+ return std::get<1>(implsgl_bundles[group]);
+
+ auto shr = std::make_shared<opt_bundle>(group);
+ implsgl_bundles[group] = tt(1,shr);
+ return shr;
+ }
class base_value : public QObject {
Q_OBJECT
#define DEFINE_SLOT(t) void setValue(t datum) { store(datum); }
-#define DEFINE_SIGNAL(t) void valueChanged(t);
+#define DEFINE_SIGNAL(t) void valueChanged(const t&)
public:
- base_value(pbundle b, const QString& name) : b(b), self_name(name) {}
+ base_value(pbundle b, const QString& name) : b(b), self_name(name), reentrancy_count(0) {}
+ protected:
+ pbundle b;
+ QString self_name;
+
+ template<typename t>
+ void store(const t& datum)
+ {
+ reentrancy_count++;
+ if (b->store_kv(self_name, datum))
+ if (reentrancy_count == 0)
+ emit valueChanged(datum);
+ reentrancy_count--;
+ }
+ private:
+ volatile char reentrancy_count;
public slots:
DEFINE_SLOT(double)
DEFINE_SLOT(int)
@@ -197,34 +256,25 @@ namespace options {
DEFINE_SIGNAL(int);
DEFINE_SIGNAL(bool);
DEFINE_SIGNAL(QString);
- // Qt5 moc really insists on that one -sh 20141012
- DEFINE_SIGNAL(QVariant);
- protected:
- pbundle b;
- QString self_name;
-
- template<typename t>
- void store(const t& datum)
- {
- b->store_kv(self_name, datum);
- emit valueChanged(static_cast<t>(datum));
- }
};
template<typename t>
class value : public base_value {
public:
- t operator=(const t& datum)
+ t operator=(const t datum)
{
- store(qVariantFromValue<t>(datum));
+ store(datum);
return datum;
}
static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection;
- static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::AutoConnection;
+ static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::BlockingQueuedConnection;
value(pbundle b, const QString& name, t def) : base_value(b, name)
{
if (!b->contains(name) || b->get<QVariant>(name).type() == QVariant::Invalid)
+ {
+ qDebug() << "new option" << *(t*)this;
*this = def;
+ }
}
operator t()
{
@@ -300,8 +350,4 @@ namespace options {
lb->setText(v);
base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.SAFE_CONNTYPE);
}
-
- inline pbundle bundle(const QString& group) {
- return std::make_shared<impl_bundle>(group);
- }
}