diff options
Diffstat (limited to 'src/mainwindow.cpp')
| -rw-r--r-- | src/mainwindow.cpp | 122 |
1 files changed, 115 insertions, 7 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 48b475c..2a79988 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -19,9 +19,12 @@ #include "mainwindow.h" #include <QAction> +#include <QCloseEvent> #include <QComboBox> #include <QDialog> #include <QDialogButtonBox> +#include <QDir> +#include <QFileInfo> #include <QHBoxLayout> #include <QHeaderView> #include <QLabel> @@ -33,6 +36,7 @@ #include <QPushButton> #include <QSettings> #include <QSplitter> +#include <QStandardPaths> #include <QStatusBar> #include <QTableView> #include <QToolBar> @@ -61,6 +65,73 @@ QString MainWindow::cidPrefixForIndex(int index) return QStringLiteral("m%1").arg(index); } +QString MainWindow::uiStatePath() +{ + // GenericStateLocation, not StateLocation: the latter appends both the + // organization and the application name, and both are "qtmaildir" here, + // so it yields ~/.local/state/qtmaildir/qtmaildir. Built the same way + // Config::defaultPath() builds its own. + const QString base = + QStandardPaths::writableLocation(QStandardPaths::GenericStateLocation); + return base + QStringLiteral("/qtmaildir/uistate.conf"); +} + +void MainWindow::restoreUiState() +{ + QSettings state(uiStatePath(), QSettings::IniFormat); + + // Every restore is conditional: an absent or rejected blob must leave the + // buildUi() defaults alone rather than produce a zero-size window. + const QByteArray geometry = state.value(QStringLiteral("window/geometry")) + .toByteArray(); + if (!geometry.isEmpty()) { + restoreGeometry(geometry); + } + + const QByteArray windowState = state.value(QStringLiteral("window/state")) + .toByteArray(); + if (!windowState.isEmpty()) { + restoreState(windowState); + } + + const QByteArray splitter = state.value(QStringLiteral("window/splitter")) + .toByteArray(); + if (!splitter.isEmpty()) { + m_splitter->restoreState(splitter); + } + + const QByteArray header = state.value(QStringLiteral("threadlist/header")) + .toByteArray(); + if (!header.isEmpty()) { + m_threadView->horizontalHeader()->restoreState(header); + } + + // The config value is the starting point for a profile that has never + // zoomed; once the user does, the state file is what they last had. + // clampZoom() rejects the garbage a hand-edited file can hold. + m_messageView->setZoomFactor( + state.value(QStringLiteral("message/zoom"), m_config.messageZoom()) + .toDouble()); +} + +void MainWindow::saveUiState() const +{ + QDir().mkpath(QFileInfo(uiStatePath()).absolutePath()); + QSettings state(uiStatePath(), QSettings::IniFormat); + state.setValue(QStringLiteral("window/geometry"), saveGeometry()); + state.setValue(QStringLiteral("window/state"), saveState()); + state.setValue(QStringLiteral("window/splitter"), m_splitter->saveState()); + state.setValue(QStringLiteral("threadlist/header"), + m_threadView->horizontalHeader()->saveState()); + state.setValue(QStringLiteral("message/zoom"), m_messageView->zoomFactor()); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + saveUiState(); + QMainWindow::closeEvent(event); +} + MainWindow::MainWindow(const Config &config, QWidget *parent) : QMainWindow(parent), m_config(config) { @@ -87,6 +158,9 @@ MainWindow::MainWindow(const Config &config, QWidget *parent) buildUi(); registerActions(); buildMenus(); + // After buildMenus(): QMainWindow::restoreState() matches toolbars by + // object name, so they must already exist or their position is dropped. + restoreUiState(); wireWorker(); showWarnings(); @@ -97,8 +171,12 @@ MainWindow::MainWindow(const Config &config, QWidget *parent) // modifier shortcuts such as Ctrl+Q still work there, which the old // filter blocked. - if (!m_config.savedQueries().isEmpty()) { - m_queryEdit->setText(m_config.savedQueries().first().query); + // Not savedQueries().first(): [queries] is read through childKeys(), which + // sorts alphabetically, so "first" means whatever happens to sort first + // rather than anything the user chose. Config resolves the name. + const SavedQuery startup = m_config.startupSavedQuery(); + if (!startup.query.isEmpty()) { + m_queryEdit->setText(startup.query); runCurrentQuery(); } } @@ -210,11 +288,11 @@ void MainWindow::buildUi() connect(m_messageView, &MessageView::statusMessage, this, [this](const QString &text) { m_statusLabel->setText(text); }); - auto *splitter = new QSplitter(Qt::Horizontal, central); - splitter->addWidget(m_threadView); - splitter->addWidget(m_messageView); - splitter->setStretchFactor(1, 2); - layout->addWidget(splitter, 1); + m_splitter = new QSplitter(Qt::Horizontal, central); + m_splitter->addWidget(m_threadView); + m_splitter->addWidget(m_messageView); + m_splitter->setStretchFactor(1, 2); + layout->addWidget(m_splitter, 1); layout->addWidget(m_syncLog); @@ -315,6 +393,32 @@ void MainWindow::registerActions() tr("Load remote images for the current thread"), [this]() { m_messageView->loadRemoteContent(); }); + addAction(QStringLiteral("zoom_in"), tr("Zoom &in"), + tr("Enlarge the message text"), [this]() { + m_messageView->zoomIn(); + }); + addAction(QStringLiteral("zoom_out"), tr("Zoom &out"), + tr("Shrink the message text"), [this]() { + m_messageView->zoomOut(); + }); + auto *zoomReset = + addAction(QStringLiteral("zoom_reset"), tr("&Actual size"), + tr("Return the message text to its default size"), [this]() { + m_messageView->zoomReset(); + }); + + // Ctrl+= alongside the configured binding: '=' reads as "back to normal", + // and on a layout where '+' is Shift+'=' it is the unshifted key next to + // zoom in. Appended rather than assigned, so a [keys] override of + // zoom_reset keeps working and simply gains this as a second way in. + // A user who bound Ctrl+= to something else in [keys] keeps their binding. + const QKeySequence altReset(QStringLiteral("Ctrl+=")); + if (m_keyMap.actionFor(altReset).isEmpty()) { + QList<QKeySequence> shortcuts = zoomReset->shortcuts(); + shortcuts.append(altReset); + zoomReset->setShortcuts(shortcuts); + } + addAction(QStringLiteral("undo"), tr("&Undo"), tr("Undo the last tag change"), [this]() { if (m_undoStack.canUndo()) @@ -362,6 +466,10 @@ void MainWindow::buildMenus() viewMenu->addSeparator(); viewMenu->addAction(m_actions.value(QStringLiteral("toggle_html"))); viewMenu->addAction(m_actions.value(QStringLiteral("load_remote"))); + viewMenu->addSeparator(); + viewMenu->addAction(m_actions.value(QStringLiteral("zoom_in"))); + viewMenu->addAction(m_actions.value(QStringLiteral("zoom_out"))); + viewMenu->addAction(m_actions.value(QStringLiteral("zoom_reset"))); auto *helpMenu = menuBar()->addMenu(tr("&Help")); auto *shortcuts = helpMenu->addAction(tr("&Keyboard shortcuts")); |
