aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorConfuSomu2023-08-15 19:42:18 -0400
committerConfuSomu2023-08-15 19:42:18 -0400
commitade98b4cf6630635e2fdbf84ac29fe83a79cc371 (patch)
tree1297fa1f808baa949e14276c80b536f61fcd76cb /src
parent82dc68463c625fcf36155dbccfb264ac2171a386 (diff)
downloadActorViewer-ade98b4cf6630635e2fdbf84ac29fe83a79cc371.tar
ActorViewer-ade98b4cf6630635e2fdbf84ac29fe83a79cc371.tar.gz
ActorViewer-ade98b4cf6630635e2fdbf84ac29fe83a79cc371.zip
Implement settings dialog
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp4
-rw-r--r--src/mainwindow.cpp16
-rw-r--r--src/mainwindow.h4
-rw-r--r--src/mainwindow.ui12
-rw-r--r--src/settings_interface.cpp120
-rw-r--r--src/settings_interface.h46
-rw-r--r--src/settingsdialog.cpp106
-rw-r--r--src/settingsdialog.h43
-rw-r--r--src/settingsdialog.ui221
9 files changed, 572 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 81f3024..02d36c1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,6 +7,10 @@ int main(int argc, char *argv[])
{
QApplication app(argc, argv);
+ QCoreApplication::setOrganizationName("ConfuSomu");
+ QCoreApplication::setOrganizationDomain("twilightsparkle.space");
+ QCoreApplication::setApplicationName("ActorViewer");
+
QCommandLineParser parser;
CommandLineParsedOptions result = parse_command_line(parser, app);
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 4fc3970..4943775 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -4,6 +4,7 @@
#include "src/finddialog.h"
#include "src/list_item.h"
#include "src/command_line.h"
+#include "src/settingsdialog.h"
#include <QFileDialog>
#include <QMessageBox>
@@ -56,6 +57,21 @@ void MainWindow::on_actionOpen_triggered(bool checked) {
}
}
+void MainWindow::on_actionSettings_triggered(bool checked) {
+ if (!settings_dialog) {
+ settings_dialog = new SettingsDialog(this);
+ connect(settings_dialog, &QDialog::finished, this, &MainWindow::settingsDialog_done);
+ }
+ settings_dialog->open();
+}
+
+void MainWindow::settingsDialog_done(int result) {
+ if (result == QDialog::Accepted) {
+ // TODO: reload settings
+ }
+ delete settings_dialog; settings_dialog = nullptr;
+}
+
void MainWindow::on_actionQuit_triggered(bool checked) {
QCoreApplication::quit();
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index fced119..4c7e034 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -7,6 +7,7 @@
#include <variant>
#include "archive/base_archive.h"
+#include "src/settingsdialog.h"
#include "types.h"
#include "command_line.h"
#include "finddialog.h"
@@ -34,6 +35,7 @@ signals:
private slots:
void on_actionOpen_triggered(bool checked);
+ void on_actionSettings_triggered(bool checked);
void on_actionQuit_triggered(bool checked);
void on_actionAbout_triggered(bool checked);
@@ -62,8 +64,10 @@ private:
void finish_listWidget_itemActivated(const QString& status_info);
void finish_open_file(const Archive::InitError& parse_error);
+ void settingsDialog_done(int result);
FindDialog* find_dialog = nullptr;
+ SettingsDialog* settings_dialog = nullptr;
QString open_file_filename;
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index cd351d4..292930d 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -96,6 +96,7 @@ p, li { white-space: pre-wrap; }
<string>File</string>
</property>
<addaction name="actionOpen"/>
+ <addaction name="actionSettings"/>
<addaction name="actionQuit"/>
</widget>
<widget class="QMenu" name="menuHelp">
@@ -259,6 +260,17 @@ p, li { white-space: pre-wrap; }
<string>Ctrl+F</string>
</property>
</action>
+ <action name="actionSettings">
+ <property name="text">
+ <string>Preferences…</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Shift+,</string>
+ </property>
+ <property name="menuRole">
+ <enum>QAction::PreferencesRole</enum>
+ </property>
+ </action>
</widget>
<tabstops>
<tabstop>listWidget</tabstop>
diff --git a/src/settings_interface.cpp b/src/settings_interface.cpp
new file mode 100644
index 0000000..e14da92
--- /dev/null
+++ b/src/settings_interface.cpp
@@ -0,0 +1,120 @@
+#include "settings_interface.h"
+#include <QDebug>
+#include <qvariant.h>
+
+const QVariant default_setting(const QString &key);
+
+SettingsInterface::~SettingsInterface() {
+ delete modified; modified = nullptr;
+}
+
+// Read a setting key and return the value associated with it.
+// See SettingsInterface::write_setting() for updating a key's value.
+const QVariant SettingsInterface::read_setting(const QString &key) {
+ qDebug() << "Read value of" << key;
+ if (must_clear.contains(key))
+ return default_setting(key);
+ if (modified and modified->contains(key))
+ return modified->value(key);
+ return qt_settings.value(key, default_setting(key));
+}
+
+// Write a new value for key. Isn't written to disk until you use SettingsInterface::commit().
+void SettingsInterface::write_setting(const QString &key, const QVariant &value) {
+ if (not modified) modified = new QHash<QString, QVariant>;
+ modified->insert(key, value);
+ qDebug() << "New modified key value:" << key << value;
+
+ // As the key has a new value it doesn't have to be cleared and thus if all keys were to be cleared it isn't true anymore
+ must_clear.removeOne(key);
+ must_clear_all = false;
+}
+
+// Clear a setting and use the default value instead
+void SettingsInterface::clear_setting(const QString &key) {
+ must_clear.append(key);
+}
+
+// Clear all settings and only use the default values
+void SettingsInterface::clear_all() {
+ // Optimization to be able to clear all settings faster
+ must_clear_all = true;
+
+ // Construct a list of all settings in case one gets (written) a new value and thus must not be removed afterwards
+ must_clear.append(qt_settings.allKeys());
+ if (modified)
+ must_clear.append(modified->keys());
+ must_clear.removeDuplicates();
+}
+
+// Write the changed settings into the internal QSetting memeber. They are then written to disk.
+// A return value of false indicates that an error occured while writing the config to disk.
+bool SettingsInterface::commit() {
+ /* If everything has to be cleared, it is cleared and synced.
+ * If nothing has been modified or has to removed, then quits.
+ * If a few key(s) have to be removed they are removed, after that
+ * if key(s) have been modified/added they are added, then synced.
+ */
+
+ if (must_clear_all) {
+ qt_settings.clear();
+ must_clear_all = false;
+ goto sync;
+ } else if ((not modified or (modified and modified->isEmpty()))
+ and must_clear.isEmpty())
+ return true;
+
+ if (not must_clear.isEmpty()) {
+ for (int i = 0; i < must_clear.size(); ++i)
+ qt_settings.remove(must_clear.at(i));
+ must_clear.clear();
+ }
+ if (not modified) goto sync;
+
+ {
+ QHash<QString, QVariant>::const_iterator i = modified->constBegin();
+ while (i != modified->constEnd()) {
+ qt_settings.setValue(i.key(), i.value());
+ qDebug() << "Wrote to disk" << i.key() << i.value();
+ ++i;
+ }
+ modified->clear();
+ }
+
+sync:
+ qt_settings.sync();
+ qDebug() << "Sync done";
+ return qt_settings.status() == QSettings::NoError;
+}
+
+// whether the key been changed from its default value.
+bool SettingsInterface::is_default(const QString &key) {
+ return ((modified and modified->contains(key))
+ or qt_settings.contains(key));
+}
+
+// Whether the key been modified and not yet been commited to disk.
+bool SettingsInterface::is_uncommited(const QString &key) {
+ if (not modified) return false;
+ return modified->contains(key);
+}
+
+// Return the default setting value for key.
+const QVariant default_setting(const QString &key) {
+ // This is not ideal as a compile time created key-value store would be better. Though won't it end up with making the same code?
+ if (key == "ui/timezone")
+ return AppSettingsTypes::Timezone::LOCALTIME;
+ else if (key == "net/access_internet")
+ return true;
+ else if (key == "net/download_emoji")
+ return true;
+ else if (key == "net/download_attachments")
+ return true;
+ else if (key == "net/instance/type")
+ return AppSettingsTypes::InstanceType::MASTODON;
+ else if (key == "net/instance/address"
+ or key == "net/instance/token")
+ return "";
+ else
+ return -1;
+}
diff --git a/src/settings_interface.h b/src/settings_interface.h
new file mode 100644
index 0000000..e3935d0
--- /dev/null
+++ b/src/settings_interface.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <QString>
+#include <QVariant>
+#include <QSettings>
+
+/* struct AppSettings {
+ enum {LOCALTIME, UTC} ui_timezone = LOCALTIME;
+ bool can_access_internet = true;
+ bool can_download_emoji = true;
+ bool can_download_attachments = true;
+ struct {
+ enum {MASTODON} type = MASTODON;
+ QString address;
+ QString token;
+ } instance;
+}; */
+
+namespace AppSettingsTypes {
+ enum Timezone {LOCALTIME = 0, UTC};
+ enum InstanceType {MASTODON = 0};
+}
+// Declare metatypes for use with QVariant
+Q_DECLARE_METATYPE(AppSettingsTypes::Timezone);
+Q_DECLARE_METATYPE(AppSettingsTypes::InstanceType);
+
+class SettingsInterface {
+public:
+ ~SettingsInterface();
+ const QVariant read_setting(const QString &key);
+ void write_setting(const QString &key, const QVariant &value);
+ void clear_setting(const QString &key);
+ void clear_all();
+ bool commit();
+ bool is_default(const QString &key);
+ bool is_uncommited(const QString &key);
+
+private:
+ QSettings qt_settings;
+ QHash<QString, QVariant>* modified = nullptr;
+
+ // Optimization to commit a clear_all() faster
+ bool must_clear_all = false;
+ // List of keys to remove from the QSettings
+ QStringList must_clear;
+};
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
new file mode 100644
index 0000000..0c64641
--- /dev/null
+++ b/src/settingsdialog.cpp
@@ -0,0 +1,106 @@
+#include "settingsdialog.h"
+#include "settings_interface.h"
+#include <QPushButton>
+#include <QDialogButtonBox>
+
+SettingsDialog::SettingsDialog(QWidget* parent)
+ : QDialog(parent, Qt::Dialog), ui(new Ui::SettingsDialog)
+{
+ ui->setupUi(this);
+
+ // Create connections for each dialog button box button, as this is the best way to do it
+ connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &SettingsDialog::defaults_button_clicked);
+ connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &SettingsDialog::apply_button_clicked);
+ connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &SettingsDialog::cancel_button_clicked);
+
+ update_ui();
+}
+
+SettingsDialog::~SettingsDialog() {
+ delete ui;
+}
+
+/* ----- General tab ----- */
+
+void SettingsDialog::on_timezoneCombo_activated(int index) {
+ if (update_ui_in_progress) return;
+ settings_interface.write_setting("ui/timezone", index);
+}
+
+/* ----- Network tab ----- */
+
+void SettingsDialog::on_connectToTheInternetCheckBox_clicked(bool checked) {
+ if (update_ui_in_progress) return;
+ settings_interface.write_setting("net/access_internet", checked);
+}
+
+void SettingsDialog::on_DownloadCustomEmojiCheckBox_clicked(bool checked) {
+ if (update_ui_in_progress) return;
+ settings_interface.write_setting("net/download_emoji", checked);
+}
+
+void SettingsDialog::on_downloadAttachmentsCheckBox_clicked(bool checked) {
+ if (update_ui_in_progress) return;
+ settings_interface.write_setting("net/download_attachments", checked);
+}
+
+void SettingsDialog::on_instanceTypeComboBox_activated(int index) {
+ if (update_ui_in_progress) return;
+ settings_interface.write_setting("net/instance/type", index);
+}
+
+void SettingsDialog::on_instanceAddressLineEdit_editingFinished() {
+ if (update_ui_in_progress) return;
+ settings_interface.write_setting("net/instance/address", ui->instanceAddressLineEdit->text());
+}
+
+void SettingsDialog::on_tokenLineEdit_editingFinished() {
+ if (update_ui_in_progress) return;
+ settings_interface.write_setting("net/instance/token", ui->tokenLineEdit->text());
+}
+
+void SettingsDialog::on_instanceActionsLabel_linkActivated(const QString& link) {
+ if (link == "action:fill-address") {
+ update_ui_in_progress = true;
+ // TODO
+ update_ui_in_progress = false;
+ } else if (link == "action:request-token") {
+ // TODO
+ }
+}
+
+/* ----- Dialog & setting saving/restoring ----- */
+
+// OK button pressed, save and apply new settings
+void SettingsDialog::apply_button_clicked() {
+ settings_interface.commit();
+ emit QDialog::accept(); // Closes the dialog with return code
+}
+
+// Cancel button pressed, discard new settings
+void SettingsDialog::cancel_button_clicked() {
+ emit QDialog::reject(); // Closes the dialog with return code
+}
+
+// Restore defaults button pressed, reset settings
+void SettingsDialog::defaults_button_clicked() {
+ settings_interface.clear_all();
+ update_ui();
+}
+
+// Update the UI's setting values with the values in settings_interface.
+void SettingsDialog::update_ui() {
+ update_ui_in_progress = true;
+ // General tab
+ ui->timezoneCombo->setCurrentIndex(settings_interface.read_setting("ui/timezone").value<AppSettingsTypes::Timezone>());
+
+ // Network tab
+ ui->connectToTheInternetCheckBox->setChecked(settings_interface.read_setting("net/access_internet").value<bool>());
+ ui->DownloadCustomEmojiCheckBox->setChecked(settings_interface.read_setting("net/download_emoji").value<bool>());
+ ui->downloadAttachmentsCheckBox->setChecked(settings_interface.read_setting("net/download_attachments").value<bool>());
+ // Instance frame
+ ui->instanceTypeComboBox->setCurrentIndex(settings_interface.read_setting("net/instance/type").value<AppSettingsTypes::InstanceType>());
+ ui->instanceAddressLineEdit->setText(settings_interface.read_setting("net/instance/address").value<QString>());
+ ui->tokenLineEdit->setText(settings_interface.read_setting("net/instance/token").value<QString>());
+ update_ui_in_progress = false;
+}
diff --git a/src/settingsdialog.h b/src/settingsdialog.h
new file mode 100644
index 0000000..e320a08
--- /dev/null
+++ b/src/settingsdialog.h
@@ -0,0 +1,43 @@
+#pragma once
+#include <QDialog>
+#include "./ui_settingsdialog.h"
+#include "settings_interface.h"
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class SettingsDialog; }
+QT_END_NAMESPACE
+
+class SettingsDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ SettingsDialog(QWidget *parent = nullptr);
+ ~SettingsDialog();
+
+ static void initialize_default_settings();
+
+public slots:
+ void defaults_button_clicked();
+ void apply_button_clicked();
+ void cancel_button_clicked();
+
+private slots:
+ // General tab:
+ void on_timezoneCombo_activated(int index);
+ // Network tab:
+ void on_connectToTheInternetCheckBox_clicked(bool checked);
+ void on_DownloadCustomEmojiCheckBox_clicked(bool checked);
+ void on_downloadAttachmentsCheckBox_clicked(bool checked);
+ void on_instanceTypeComboBox_activated(int index);
+ void on_instanceAddressLineEdit_editingFinished();
+ void on_tokenLineEdit_editingFinished();
+ void on_instanceActionsLabel_linkActivated(const QString& link);
+
+private:
+ Ui::SettingsDialog* ui;
+
+ SettingsInterface settings_interface;
+ bool update_ui_in_progress = false;
+
+ void update_ui();
+};
diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui
new file mode 100644
index 0000000..b2c1c69
--- /dev/null
+++ b/src/settingsdialog.ui
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>364</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Preferences</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="general">
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <layout class="QFormLayout" name="formLayoutWidget">
+ <item row="0" column="0">
+ <widget class="QLabel" name="timezoneLabel">
+ <property name="text">
+ <string>Time zone to use when formatting dates</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="timezoneCombo">
+ <item>
+ <property name="text">
+ <string>Local Time</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>UTC</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="network">
+ <attribute name="title">
+ <string>Network</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="formLayoutWidget2">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="1" column="0">
+ <widget class="QLabel" name="DownloadCustomEmojiLabel">
+ <property name="text">
+ <string>Download custom emoji</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="DownloadCustomEmojiCheckBox">
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="downloadAttachmentsLabel">
+ <property name="text">
+ <string>Download remote attachments</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="downloadAttachmentsCheckBox">
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="connectToTheInternetLabel">
+ <property name="text">
+ <string>Connect to the internet</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="connectToTheInternetCheckBox">
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Instance with whom to fetch posts with</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="1">
+ <widget class="QComboBox" name="instanceTypeComboBox">
+ <item>
+ <property name="text">
+ <string>Mastodon</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="instanceTypeLabel">
+ <property name="text">
+ <string>Instance type</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="instanceAddressLabel">
+ <property name="text">
+ <string>Instance Address</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="instanceAddressLineEdit"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="tokenLabel">
+ <property name="text">
+ <string>Token</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="tokenLineEdit"/>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QLabel" name="instanceActionsLabel">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Actions: &lt;a href=&quot;action:fill-address&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#d2737f;&quot;&gt;auto-fill address&lt;/span&gt;&lt;/a&gt; and &lt;a href=&quot;action:request-token&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#d2737f;&quot;&gt;request token&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>tabWidget</tabstop>
+ <tabstop>timezoneCombo</tabstop>
+ <tabstop>connectToTheInternetCheckBox</tabstop>
+ <tabstop>DownloadCustomEmojiCheckBox</tabstop>
+ <tabstop>downloadAttachmentsCheckBox</tabstop>
+ <tabstop>instanceTypeComboBox</tabstop>
+ <tabstop>instanceAddressLineEdit</tabstop>
+ <tabstop>tokenLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>255</x>
+ <y>304</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>323</x>
+ <y>304</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>