aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.cpp4
-rw-r--r--main.qml4
-rw-r--r--monero-wallet-gui.pro6
-rw-r--r--src/qt/MoneroSettings.cpp207
-rw-r--r--src/qt/MoneroSettings.h81
5 files changed, 298 insertions, 4 deletions
diff --git a/main.cpp b/main.cpp
index a51568d2..a41b3c75 100644
--- a/main.cpp
+++ b/main.cpp
@@ -66,6 +66,7 @@
#include "qt/utils.h"
#include "qt/mime.h"
#include "src/qt/KeysFiles.h"
+#include "src/qt/MoneroSettings.h"
#include "qt/prices.h"
// IOS exclusions
@@ -224,6 +225,9 @@ int main(int argc, char *argv[])
// registering types for QML
qmlRegisterType<clipboardAdapter>("moneroComponents.Clipboard", 1, 0, "Clipboard");
+ // Temporary Qt.labs.settings replacement
+ qmlRegisterType<MoneroSettings>("moneroComponents.Settings", 1, 0, "MoneroSettings");
+
qmlRegisterUncreatableType<Wallet>("moneroComponents.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
diff --git a/main.qml b/main.qml
index fb003482..1655456c 100644
--- a/main.qml
+++ b/main.qml
@@ -31,11 +31,11 @@ import QtQuick.Window 2.0
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.2
-import Qt.labs.settings 1.0
import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0
import moneroComponents.NetworkType 1.0
+import moneroComponents.Settings 1.0
import "components"
import "components" as MoneroComponents
@@ -1347,7 +1347,7 @@ ApplicationWindow {
}
}
- Settings {
+ MoneroSettings {
id: persistentSettings
property string language
property string locale
diff --git a/monero-wallet-gui.pro b/monero-wallet-gui.pro
index 745fa1bd..d832ee12 100644
--- a/monero-wallet-gui.pro
+++ b/monero-wallet-gui.pro
@@ -69,7 +69,8 @@ HEADERS += \
src/qt/KeysFiles.h \
src/qt/utils.h \
src/qt/prices.h \
- src/qt/macoshelper.h
+ src/qt/macoshelper.h \
+ src/qt/MoneroSettings.h
SOURCES += main.cpp \
filter.cpp \
@@ -103,7 +104,8 @@ SOURCES += main.cpp \
src/qt/mime.cpp \
src/qt/KeysFiles.cpp \
src/qt/utils.cpp \
- src/qt/prices.cpp
+ src/qt/prices.cpp \
+ src/qt/MoneroSettings.cpp
CONFIG(DISABLE_PASS_STRENGTH_METER) {
HEADERS -= src/zxcvbn-c/zxcvbn.h
diff --git a/src/qt/MoneroSettings.cpp b/src/qt/MoneroSettings.cpp
new file mode 100644
index 00000000..ba3e6876
--- /dev/null
+++ b/src/qt/MoneroSettings.cpp
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+****************************************************************************/
+// Copyright (c) 2014-2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <QtCore>
+#include <QMetaObject>
+#include <QSettings>
+#include <QPointer>
+#include <QJSValue>
+#include <QHash>
+#include <QMetaProperty>
+
+#include "src/qt/MoneroSettings.h"
+
+/*!
+ \qmlmodule moneroSettings 1.0
+ \title Monero Settings QML Component
+ \ingroup qmlmodules
+ \brief Provides persistent platform-independent application settings.
+
+ This component was introduced in order to have control over where the
+ configuration file is written. This is needed for Tails OS and
+ portable installations.
+
+ For more information, see: https://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html and
+ https://github.com/qt/qtdeclarative/blob/v5.12.0/src/imports/settings/qqmlsettings.cpp
+
+ To use this module, import the module with the following line:
+ \code
+ import moneroComponents.Settings 1.0
+ \endcode
+
+ Usage:
+ \code
+ MoneroSettings { id: persistentSettings, property bool foo: true }
+ \endcode
+
+ @TODO: Remove this QML component after migrating to Qt >= 5.12.0, as
+ `Qt.labs.settings` provides the fileName via a Q_PROPERTY
+*/
+
+
+void MoneroSettings::load()
+{
+ const QMetaObject *mo = this->metaObject();
+ const int offset = mo->propertyOffset();
+ const int count = mo->propertyCount();
+
+ for (int i = offset; i < count; ++i) {
+ QMetaProperty property = mo->property(i);
+ const QVariant previousValue = readProperty(property);
+ const QVariant currentValue = this->m_settings->value(property.name(), previousValue);
+
+ if (!currentValue.isNull() && (!previousValue.isValid()
+ || (currentValue.canConvert(previousValue.type()) && previousValue != currentValue))) {
+ property.write(this, currentValue);
+#ifdef QT_DEBUG
+ qDebug() << "QQmlSettings: load" << property.name() << "setting:" << currentValue << "default:" << previousValue;
+#endif
+ }
+
+ // ensure that a non-existent setting gets written
+ // even if the property wouldn't change later
+ if (!this->m_settings->contains(property.name()))
+ this->_q_propertyChanged();
+
+ // setup change notifications on first load
+ if (!this->m_initialized && property.hasNotifySignal()) {
+ static const int propertyChangedIndex = mo->indexOfSlot("_q_propertyChanged()");
+ int signalIndex = property.notifySignalIndex();
+ QMetaObject::connect(this, signalIndex, this, propertyChangedIndex);
+ }
+ }
+}
+
+void MoneroSettings::_q_propertyChanged()
+{
+ // Called on QML property change
+ const QMetaObject *mo = this->metaObject();
+ const int offset = mo->propertyOffset();
+ const int count = mo->propertyCount();
+ for (int i = offset; i < count; ++i) {
+ const QMetaProperty &property = mo->property(i);
+ const QVariant value = readProperty(property);
+ this->m_changedProperties.insert(property.name(), value);
+#ifdef QT_DEBUG
+ //qDebug() << "QQmlSettings: cache" << property.name() << ":" << value;
+#endif
+ }
+
+ if (this->m_timerId != 0)
+ this->killTimer(this->m_timerId);
+ this->m_timerId = this->startTimer(settingsWriteDelay);
+}
+
+QVariant MoneroSettings::readProperty(const QMetaProperty &property) const
+{
+ QVariant var = property.read(this);
+ if (var.userType() == qMetaTypeId<QJSValue>())
+ var = var.value<QJSValue>().toVariant();
+ return var;
+}
+
+void MoneroSettings::init()
+{
+ if (!this->m_initialized) {
+ this->m_settings = this->m_fileName.isEmpty() ? new QSettings() : new QSettings(this->m_fileName, QSettings::IniFormat);
+#ifdef QT_DEBUG
+ qDebug() << "QQmlSettings: stored at" << this->m_settings->fileName();
+#endif
+ this->load();
+ this->m_initialized = true;
+ }
+}
+
+void MoneroSettings::reset()
+{
+ if (this->m_initialized && this->m_settings && !this->m_changedProperties.isEmpty())
+ this->store();
+ delete this->m_settings;
+}
+
+void MoneroSettings::store()
+{
+ QHash<const char *, QVariant>::const_iterator it = this->m_changedProperties.constBegin();
+
+ while (it != this->m_changedProperties.constEnd()) {
+ this->m_settings->setValue(it.key(), it.value());
+
+#ifdef QT_DEBUG
+ //qDebug() << "QQmlSettings: store" << it.key() << ":" << it.value();
+#endif
+
+ ++it;
+ }
+
+ this->m_changedProperties.clear();
+}
+
+void MoneroSettings::setFileName(const QString &fileName)
+{
+ if (fileName != this->m_fileName) {
+ this->reset();
+ this->m_fileName = fileName;
+ if (this->m_initialized)
+ this->load();
+ }
+}
+
+QString MoneroSettings::fileName() const
+{
+ return this->m_fileName;
+}
+
+void MoneroSettings::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == this->m_timerId) {
+ killTimer(this->m_timerId);
+ this->m_timerId = 0;
+ this->store();
+ }
+ QObject::timerEvent(event);
+}
+
+void MoneroSettings::componentComplete()
+{
+ this->init();
+}
+
+void MoneroSettings::classBegin()
+{
+}
+
+MoneroSettings::MoneroSettings(QObject *parent) :
+ QObject(parent)
+{
+}
diff --git a/src/qt/MoneroSettings.h b/src/qt/MoneroSettings.h
new file mode 100644
index 00000000..6de7f641
--- /dev/null
+++ b/src/qt/MoneroSettings.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+****************************************************************************/
+// Copyright (c) 2014-2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#ifndef MONEROSETTINGS_H
+#define MONEROSETTINGS_H
+
+#include <QtQml/qqmlparserstatus.h>
+#include <QGuiApplication>
+#include <QClipboard>
+#include <QObject>
+#include <QDebug>
+#include <qsettings.h>
+
+static const int settingsWriteDelay = 500; // ms
+
+class MoneroSettings : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QString fileName READ fileName WRITE setFileName FINAL)
+public:
+ explicit MoneroSettings(QObject *parent = nullptr);
+
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+public slots:
+ void _q_propertyChanged();
+
+protected:
+ void timerEvent(QTimerEvent *event) override;
+ void classBegin() override;
+ void componentComplete() override;
+
+private:
+ QVariant readProperty(const QMetaProperty &property) const;
+ void init();
+ void reset();
+ void load();
+ void store();
+
+ QHash<const char *, QVariant> m_changedProperties;
+ QSettings *m_settings;
+ QString m_fileName = QString("");
+ bool m_initialized = false;
+ int m_timerId = 0;
+};
+
+#endif // MONEROSETTINGS_H