git repos / SagoImageBrowser

blame: src/mainwindow.cpp

normal view · raw

032aa1e1 Poul Sander 2026-02-19 18:55 1
#include "mainwindow.h"
032aa1e1 Poul Sander 2026-02-19 18:55 2
#include "imagemodel.h"
61136b77 Poul Sander 2026-02-20 22:45 3
#include "imageviewwidget.h"
f61bf886 Poul Sander 2026-02-23 19:27 4
#include "preferencesdialog.h"
ac476ca8 Poul Sander 2026-05-18 16:47 5
#include "thumbnailcache.h"
53fdab93 Poul Sander 2026-05-18 18:45 6
#include "exifreader.h"
032aa1e1 Poul Sander 2026-02-19 18:55 7
032aa1e1 Poul Sander 2026-02-19 18:55 8
#include <QFileSystemModel>
032aa1e1 Poul Sander 2026-02-19 18:55 9
#include <QTreeView>
032aa1e1 Poul Sander 2026-02-19 18:55 10
#include <QListView>
032aa1e1 Poul Sander 2026-02-19 18:55 11
#include <QLabel>
61136b77 Poul Sander 2026-02-20 22:45 12
#include <QStackedWidget>
032aa1e1 Poul Sander 2026-02-19 18:55 13
#include <QDir>
3bee3e3e Poul Sander 2026-03-05 17:07 14
#include <QListWidget>
fc5f2e27 Poul Sander 2026-02-22 22:06 15
#include <QStandardPaths>
032aa1e1 Poul Sander 2026-02-19 18:55 16
#include <QImageReader>
032aa1e1 Poul Sander 2026-02-19 18:55 17
#include <QHeaderView>
6fcd6c90 Poul Sander 2026-02-19 21:12 18
#include <QScrollBar>
6fcd6c90 Poul Sander 2026-02-19 21:12 19
#include <QTimer>
6fcd6c90 Poul Sander 2026-02-19 21:12 20
#include <QEvent>
61136b77 Poul Sander 2026-02-20 22:45 21
#include <QKeyEvent>
c9e5684a Poul Sander 2026-02-23 19:18 22
#include <QCloseEvent>
cfe4a67b Poul Sander 2026-02-19 23:06 23
#include <QItemSelectionModel>
cbc7d22b Poul Sander 2026-02-24 19:23 24
#include <QDockWidget>
f61bf886 Poul Sander 2026-02-23 19:27 25
#include <QMenuBar>
f61bf886 Poul Sander 2026-02-23 19:27 26
#include <QMenu>
f61bf886 Poul Sander 2026-02-23 19:27 27
#include <QAction>
f61bf886 Poul Sander 2026-02-23 19:27 28
#include <QSettings>
53fdab93 Poul Sander 2026-05-18 18:45 29
#include <QTableWidget>
6fcd6c90 Poul Sander 2026-02-19 21:12 30
#include <iostream>
032aa1e1 Poul Sander 2026-02-19 18:55 31
ac476ca8 Poul Sander 2026-05-18 16:47 32
namespace
ac476ca8 Poul Sander 2026-05-18 16:47 33
{
ac476ca8 Poul Sander 2026-05-18 16:47 34
ThumbnailCache::Size thumbnailSizeFromString(const QString &s)
ac476ca8 Poul Sander 2026-05-18 16:47 35
{
ac476ca8 Poul Sander 2026-05-18 16:47 36
    return (s == "large") ? ThumbnailCache::Size::Large
ac476ca8 Poul Sander 2026-05-18 16:47 37
                          : ThumbnailCache::Size::Normal;
ac476ca8 Poul Sander 2026-05-18 16:47 38
}
ac476ca8 Poul Sander 2026-05-18 16:47 39
} // namespace
ac476ca8 Poul Sander 2026-05-18 16:47 40
032aa1e1 Poul Sander 2026-02-19 18:55 41
MainWindow::MainWindow(QWidget *parent)
032aa1e1 Poul Sander 2026-02-19 18:55 42
    : QMainWindow(parent)
032aa1e1 Poul Sander 2026-02-19 18:55 43
{
032aa1e1 Poul Sander 2026-02-19 18:55 44
    setupUi();
f61bf886 Poul Sander 2026-02-23 19:27 45
    setupMenuBar();
032aa1e1 Poul Sander 2026-02-19 18:55 46
    setupConnections();
f61bf886 Poul Sander 2026-02-23 19:27 47
    loadPreferences();
032aa1e1 Poul Sander 2026-02-19 18:55 48
}
032aa1e1 Poul Sander 2026-02-19 18:55 49
032aa1e1 Poul Sander 2026-02-19 18:55 50
void MainWindow::setupUi()
032aa1e1 Poul Sander 2026-02-19 18:55 51
{
032aa1e1 Poul Sander 2026-02-19 18:55 52
    // Folder model (left pane)
032aa1e1 Poul Sander 2026-02-19 18:55 53
    m_dirModel = new QFileSystemModel(this);
032aa1e1 Poul Sander 2026-02-19 18:55 54
    m_dirModel->setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
032aa1e1 Poul Sander 2026-02-19 18:55 55
    m_dirModel->setRootPath(QDir::homePath());
032aa1e1 Poul Sander 2026-02-19 18:55 56
3bee3e3e Poul Sander 2026-03-05 17:07 57
    // Root chooser list
3bee3e3e Poul Sander 2026-03-05 17:07 58
    m_rootList = new QListWidget;
3bee3e3e Poul Sander 2026-03-05 17:07 59
    m_rootList->setSelectionMode(QAbstractItemView::SingleSelection);
3bee3e3e Poul Sander 2026-03-05 17:07 60
3bee3e3e Poul Sander 2026-03-05 17:07 61
    auto addRootItem = [this](const QString &label, const QString &path) {
3bee3e3e Poul Sander 2026-03-05 17:07 62
        QListWidgetItem *item = new QListWidgetItem(label, m_rootList);
3bee3e3e Poul Sander 2026-03-05 17:07 63
        item->setData(Qt::UserRole, path);
3bee3e3e Poul Sander 2026-03-05 17:07 64
    };
3bee3e3e Poul Sander 2026-03-05 17:07 65
    addRootItem("Home", QDir::homePath());
3bee3e3e Poul Sander 2026-03-05 17:07 66
    addRootItem("Pictures", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
3bee3e3e Poul Sander 2026-03-05 17:07 67
    addRootItem("File System", QDir::rootPath());
3bee3e3e Poul Sander 2026-03-05 17:07 68
    m_rootList->setCurrentRow(0);
fc5f2e27 Poul Sander 2026-02-22 22:06 69
032aa1e1 Poul Sander 2026-02-19 18:55 70
    m_treeView = new QTreeView;
032aa1e1 Poul Sander 2026-02-19 18:55 71
    m_treeView->setModel(m_dirModel);
032aa1e1 Poul Sander 2026-02-19 18:55 72
    m_treeView->setRootIndex(m_dirModel->index(QDir::homePath()));
032aa1e1 Poul Sander 2026-02-19 18:55 73
    m_treeView->header()->hide();
032aa1e1 Poul Sander 2026-02-19 18:55 74
    m_treeView->setColumnHidden(1, true);
032aa1e1 Poul Sander 2026-02-19 18:55 75
    m_treeView->setColumnHidden(2, true);
032aa1e1 Poul Sander 2026-02-19 18:55 76
    m_treeView->setColumnHidden(3, true);
032aa1e1 Poul Sander 2026-02-19 18:55 77
032aa1e1 Poul Sander 2026-02-19 18:55 78
    // Thumbnail model (center pane)
032aa1e1 Poul Sander 2026-02-19 18:55 79
    m_imageModel = new ImageModel(this);
032aa1e1 Poul Sander 2026-02-19 18:55 80
032aa1e1 Poul Sander 2026-02-19 18:55 81
    m_listView = new QListView;
032aa1e1 Poul Sander 2026-02-19 18:55 82
    m_listView->setModel(m_imageModel);
032aa1e1 Poul Sander 2026-02-19 18:55 83
    m_listView->setViewMode(QListView::IconMode);
032aa1e1 Poul Sander 2026-02-19 18:55 84
    m_listView->setIconSize(QSize(128, 128));
b614a581 Poul Sander 2026-02-19 21:18 85
    m_listView->setGridSize(QSize(148, 168));
032aa1e1 Poul Sander 2026-02-19 18:55 86
    m_listView->setResizeMode(QListView::Adjust);
032aa1e1 Poul Sander 2026-02-19 18:55 87
    m_listView->setSelectionMode(QAbstractItemView::SingleSelection);
b614a581 Poul Sander 2026-02-19 21:18 88
    m_listView->setSpacing(4);
b614a581 Poul Sander 2026-02-19 21:18 89
    m_listView->setWordWrap(true);
b614a581 Poul Sander 2026-02-19 21:18 90
    m_listView->setTextElideMode(Qt::ElideRight);
032aa1e1 Poul Sander 2026-02-19 18:55 91
032aa1e1 Poul Sander 2026-02-19 18:55 92
    // Preview pane (right)
032aa1e1 Poul Sander 2026-02-19 18:55 93
    m_previewLabel = new QLabel;
032aa1e1 Poul Sander 2026-02-19 18:55 94
    m_previewLabel->setAlignment(Qt::AlignCenter);
cbc7d22b Poul Sander 2026-02-24 19:23 95
    m_previewLabel->setMinimumWidth(200);
61136b77 Poul Sander 2026-02-20 22:45 96
61136b77 Poul Sander 2026-02-20 22:45 97
    // Single image view
61136b77 Poul Sander 2026-02-20 22:45 98
    m_imageView = new ImageViewWidget;
61136b77 Poul Sander 2026-02-20 22:45 99
61136b77 Poul Sander 2026-02-20 22:45 100
    // Stack to switch between browser and single image
61136b77 Poul Sander 2026-02-20 22:45 101
    m_stack = new QStackedWidget;
cbc7d22b Poul Sander 2026-02-24 19:23 102
    m_stack->addWidget(m_listView);
61136b77 Poul Sander 2026-02-20 22:45 103
    m_stack->addWidget(m_imageView);
cbc7d22b Poul Sander 2026-02-24 19:23 104
    m_browserPage = m_listView;
61136b77 Poul Sander 2026-02-20 22:45 105
61136b77 Poul Sander 2026-02-20 22:45 106
    setCentralWidget(m_stack);
cbc7d22b Poul Sander 2026-02-24 19:23 107
cbc7d22b Poul Sander 2026-02-24 19:23 108
    // Dock widgets — can be dragged, floated and stacked by the user
3bee3e3e Poul Sander 2026-03-05 17:07 109
    m_rootDock = new QDockWidget(tr("Roots"), this);
3bee3e3e Poul Sander 2026-03-05 17:07 110
    m_rootDock->setObjectName("RootDock");
3bee3e3e Poul Sander 2026-03-05 17:07 111
    m_rootDock->setWidget(m_rootList);
3bee3e3e Poul Sander 2026-03-05 17:07 112
    addDockWidget(Qt::LeftDockWidgetArea, m_rootDock);
3bee3e3e Poul Sander 2026-03-05 17:07 113
cbc7d22b Poul Sander 2026-02-24 19:23 114
    m_folderDock = new QDockWidget(tr("Folders"), this);
cbc7d22b Poul Sander 2026-02-24 19:23 115
    m_folderDock->setObjectName("FolderDock");
3bee3e3e Poul Sander 2026-03-05 17:07 116
    m_folderDock->setWidget(m_treeView);
cbc7d22b Poul Sander 2026-02-24 19:23 117
    addDockWidget(Qt::LeftDockWidgetArea, m_folderDock);
3bee3e3e Poul Sander 2026-03-05 17:07 118
    splitDockWidget(m_rootDock, m_folderDock, Qt::Vertical);
cbc7d22b Poul Sander 2026-02-24 19:23 119
cbc7d22b Poul Sander 2026-02-24 19:23 120
    m_previewDock = new QDockWidget(tr("Preview"), this);
cbc7d22b Poul Sander 2026-02-24 19:23 121
    m_previewDock->setObjectName("PreviewDock");
cbc7d22b Poul Sander 2026-02-24 19:23 122
    m_previewDock->setWidget(m_previewLabel);
cbc7d22b Poul Sander 2026-02-24 19:23 123
    addDockWidget(Qt::RightDockWidgetArea, m_previewDock);
53fdab93 Poul Sander 2026-05-18 18:45 124
53fdab93 Poul Sander 2026-05-18 18:45 125
    // EXIF info dock — placed below the preview dock by default
53fdab93 Poul Sander 2026-05-18 18:45 126
    m_exifTable = new QTableWidget(0, 2);
53fdab93 Poul Sander 2026-05-18 18:45 127
    m_exifTable->setHorizontalHeaderLabels({tr("Field"), tr("Value")});
53fdab93 Poul Sander 2026-05-18 18:45 128
    m_exifTable->horizontalHeader()->setStretchLastSection(true);
53fdab93 Poul Sander 2026-05-18 18:45 129
    m_exifTable->verticalHeader()->hide();
53fdab93 Poul Sander 2026-05-18 18:45 130
    m_exifTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
53fdab93 Poul Sander 2026-05-18 18:45 131
    m_exifTable->setSelectionMode(QAbstractItemView::NoSelection);
53fdab93 Poul Sander 2026-05-18 18:45 132
    m_exifTable->setShowGrid(false);
53fdab93 Poul Sander 2026-05-18 18:45 133
    m_exifTable->setAlternatingRowColors(true);
53fdab93 Poul Sander 2026-05-18 18:45 134
    m_exifTable->setMinimumWidth(200);
53fdab93 Poul Sander 2026-05-18 18:45 135
53fdab93 Poul Sander 2026-05-18 18:45 136
    m_exifDock = new QDockWidget(tr("EXIF Info"), this);
53fdab93 Poul Sander 2026-05-18 18:45 137
    m_exifDock->setObjectName("ExifDock");
53fdab93 Poul Sander 2026-05-18 18:45 138
    m_exifDock->setWidget(m_exifTable);
53fdab93 Poul Sander 2026-05-18 18:45 139
    addDockWidget(Qt::RightDockWidgetArea, m_exifDock);
53fdab93 Poul Sander 2026-05-18 18:45 140
    splitDockWidget(m_previewDock, m_exifDock, Qt::Vertical);
032aa1e1 Poul Sander 2026-02-19 18:55 141
}
032aa1e1 Poul Sander 2026-02-19 18:55 142
f61bf886 Poul Sander 2026-02-23 19:27 143
void MainWindow::setupMenuBar()
f61bf886 Poul Sander 2026-02-23 19:27 144
{
ccb726b8 Poul Sander 2026-02-23 22:43 145
    m_menuBar = menuBar();
0df01dc1 Poul Sander 2026-02-24 18:51 146
    m_menuBar->setStyleSheet(
0df01dc1 Poul Sander 2026-02-24 18:51 147
        "QMenuBar { padding: 1px 2px; }"
0df01dc1 Poul Sander 2026-02-24 18:51 148
        "QMenuBar::item { padding: 2px 6px; }"
0df01dc1 Poul Sander 2026-02-24 18:51 149
    );
cbc7d22b Poul Sander 2026-02-24 19:23 150
    QMenu *viewMenu = m_menuBar->addMenu("&View");
3bee3e3e Poul Sander 2026-03-05 17:07 151
    viewMenu->addAction(m_rootDock->toggleViewAction());
cbc7d22b Poul Sander 2026-02-24 19:23 152
    viewMenu->addAction(m_folderDock->toggleViewAction());
cbc7d22b Poul Sander 2026-02-24 19:23 153
    viewMenu->addAction(m_previewDock->toggleViewAction());
53fdab93 Poul Sander 2026-05-18 18:45 154
    viewMenu->addAction(m_exifDock->toggleViewAction());
cbc7d22b Poul Sander 2026-02-24 19:23 155
ccb726b8 Poul Sander 2026-02-23 22:43 156
    QMenu *editMenu = m_menuBar->addMenu("&Edit");
f61bf886 Poul Sander 2026-02-23 19:27 157
    QAction *preferencesAction = editMenu->addAction("&Preferences");
f61bf886 Poul Sander 2026-02-23 19:27 158
    connect(preferencesAction, &QAction::triggered, this, &MainWindow::onPreferencesTriggered);
f61bf886 Poul Sander 2026-02-23 19:27 159
}
f61bf886 Poul Sander 2026-02-23 19:27 160
665ac308 Poul Sander 2026-02-23 19:34 161
void MainWindow::navigateToFolder(const QString &path)
665ac308 Poul Sander 2026-02-23 19:34 162
{
665ac308 Poul Sander 2026-02-23 19:34 163
    m_previousFolderPath = m_imageModel->currentDirectory();
665ac308 Poul Sander 2026-02-23 19:34 164
    m_imageModel->setDirectory(path);
665ac308 Poul Sander 2026-02-23 19:34 165
    QModelIndex dirIdx = m_dirModel->index(path);
665ac308 Poul Sander 2026-02-23 19:34 166
    if (dirIdx.isValid())
665ac308 Poul Sander 2026-02-23 19:34 167
        m_treeView->setCurrentIndex(dirIdx);
665ac308 Poul Sander 2026-02-23 19:34 168
    QTimer::singleShot(0, this, [this]() {
665ac308 Poul Sander 2026-02-23 19:34 169
        selectPreviousFolderIfExists();
665ac308 Poul Sander 2026-02-23 19:34 170
        loadVisibleThumbnails();
665ac308 Poul Sander 2026-02-23 19:34 171
    });
665ac308 Poul Sander 2026-02-23 19:34 172
}
665ac308 Poul Sander 2026-02-23 19:34 173
48607848 Poul Sander 2026-05-19 19:20 174
void MainWindow::openPath(const QString &path)
48607848 Poul Sander 2026-05-19 19:20 175
{
48607848 Poul Sander 2026-05-19 19:20 176
    QFileInfo info(path);
48607848 Poul Sander 2026-05-19 19:20 177
    if (!info.exists())
48607848 Poul Sander 2026-05-19 19:20 178
        return;
48607848 Poul Sander 2026-05-19 19:20 179
48607848 Poul Sander 2026-05-19 19:20 180
    if (info.isDir()) {
48607848 Poul Sander 2026-05-19 19:20 181
        navigateToFolder(info.absoluteFilePath());
48607848 Poul Sander 2026-05-19 19:20 182
    } else if (info.isFile()) {
48607848 Poul Sander 2026-05-19 19:20 183
        navigateToFolder(info.absolutePath());
48607848 Poul Sander 2026-05-19 19:20 184
48607848 Poul Sander 2026-05-19 19:20 185
        // ImageModel::setDirectory is synchronous, so items are ready now.
48607848 Poul Sander 2026-05-19 19:20 186
        // Find the file in the model and open it.
48607848 Poul Sander 2026-05-19 19:20 187
        for (int i = 0; i < m_imageModel->rowCount(); ++i) {
48607848 Poul Sander 2026-05-19 19:20 188
            QModelIndex idx = m_imageModel->index(i);
48607848 Poul Sander 2026-05-19 19:20 189
            if (m_imageModel->filePath(idx) == info.absoluteFilePath()) {
48607848 Poul Sander 2026-05-19 19:20 190
                m_listView->setCurrentIndex(idx);
48607848 Poul Sander 2026-05-19 19:20 191
                m_listView->scrollTo(idx);
48607848 Poul Sander 2026-05-19 19:20 192
                showPreview(idx);
48607848 Poul Sander 2026-05-19 19:20 193
                // ImageModel only lists image files and folders; non-folder = image.
48607848 Poul Sander 2026-05-19 19:20 194
                if (!m_imageModel->isFolder(idx))
48607848 Poul Sander 2026-05-19 19:20 195
                    enterSingleImageMode(idx);
48607848 Poul Sander 2026-05-19 19:20 196
                break;
48607848 Poul Sander 2026-05-19 19:20 197
            }
48607848 Poul Sander 2026-05-19 19:20 198
        }
48607848 Poul Sander 2026-05-19 19:20 199
    }
48607848 Poul Sander 2026-05-19 19:20 200
}
48607848 Poul Sander 2026-05-19 19:20 201
665ac308 Poul Sander 2026-02-23 19:34 202
void MainWindow::selectPreviousFolderIfExists()
665ac308 Poul Sander 2026-02-23 19:34 203
{
665ac308 Poul Sander 2026-02-23 19:34 204
    if (m_previousFolderPath.isEmpty())
665ac308 Poul Sander 2026-02-23 19:34 205
        return;
665ac308 Poul Sander 2026-02-23 19:34 206
665ac308 Poul Sander 2026-02-23 19:34 207
    // Find the previous folder in the current directory's contents
665ac308 Poul Sander 2026-02-23 19:34 208
    for (int i = 0; i < m_imageModel->rowCount(); ++i) {
665ac308 Poul Sander 2026-02-23 19:34 209
        QModelIndex idx = m_imageModel->index(i);
665ac308 Poul Sander 2026-02-23 19:34 210
        if (m_imageModel->isFolder(idx)) {
665ac308 Poul Sander 2026-02-23 19:34 211
            QString folderPath = m_imageModel->filePath(idx);
665ac308 Poul Sander 2026-02-23 19:34 212
            if (folderPath == m_previousFolderPath) {
665ac308 Poul Sander 2026-02-23 19:34 213
                m_listView->setCurrentIndex(idx);
665ac308 Poul Sander 2026-02-23 19:34 214
                m_listView->scrollTo(idx);
665ac308 Poul Sander 2026-02-23 19:34 215
                return;
665ac308 Poul Sander 2026-02-23 19:34 216
            }
665ac308 Poul Sander 2026-02-23 19:34 217
        }
665ac308 Poul Sander 2026-02-23 19:34 218
    }
665ac308 Poul Sander 2026-02-23 19:34 219
}
665ac308 Poul Sander 2026-02-23 19:34 220
032aa1e1 Poul Sander 2026-02-19 18:55 221
void MainWindow::setupConnections()
032aa1e1 Poul Sander 2026-02-19 18:55 222
{
3bee3e3e Poul Sander 2026-03-05 17:07 223
    connect(m_rootList, &QListWidget::currentItemChanged, this,
3bee3e3e Poul Sander 2026-03-05 17:07 224
            [this](QListWidgetItem *current, QListWidgetItem *) {
3bee3e3e Poul Sander 2026-03-05 17:07 225
                if (current == nullptr)
3bee3e3e Poul Sander 2026-03-05 17:07 226
                    return;
3bee3e3e Poul Sander 2026-03-05 17:07 227
3bee3e3e Poul Sander 2026-03-05 17:07 228
                QString rootPath = current->data(Qt::UserRole).toString();
fc5f2e27 Poul Sander 2026-02-22 22:06 229
                m_dirModel->setRootPath(rootPath);
fc5f2e27 Poul Sander 2026-02-22 22:06 230
                m_treeView->setRootIndex(m_dirModel->index(rootPath));
fc5f2e27 Poul Sander 2026-02-22 22:06 231
            });
fc5f2e27 Poul Sander 2026-02-22 22:06 232
032aa1e1 Poul Sander 2026-02-19 18:55 233
    connect(m_treeView, &QTreeView::clicked, this,
032aa1e1 Poul Sander 2026-02-19 18:55 234
            [this](const QModelIndex &index)
6fcd6c90 Poul Sander 2026-02-19 21:12 235
            {
6fcd6c90 Poul Sander 2026-02-19 21:12 236
                QString path = m_dirModel->filePath(index);
665ac308 Poul Sander 2026-02-23 19:34 237
                navigateToFolder(path);
6fcd6c90 Poul Sander 2026-02-19 21:12 238
            });
032aa1e1 Poul Sander 2026-02-19 18:55 239
032aa1e1 Poul Sander 2026-02-19 18:55 240
    connect(m_listView, &QListView::clicked, this,
cfe4a67b Poul Sander 2026-02-19 23:06 241
            [this](const QModelIndex &index) { showPreview(index); });
6fcd6c90 Poul Sander 2026-02-19 21:12 242
cfe4a67b Poul Sander 2026-02-19 23:06 243
    connect(m_listView->selectionModel(), &QItemSelectionModel::currentChanged,
cfe4a67b Poul Sander 2026-02-19 23:06 244
            this, [this](const QModelIndex &current) { showPreview(current); });
6fcd6c90 Poul Sander 2026-02-19 21:12 245
61136b77 Poul Sander 2026-02-20 22:45 246
    connect(m_listView, &QListView::doubleClicked, this,
09130ab9 Poul Sander 2026-02-22 22:19 247
            [this](const QModelIndex &index) {
09130ab9 Poul Sander 2026-02-22 22:19 248
                if (m_imageModel->isFolder(index)) {
09130ab9 Poul Sander 2026-02-22 22:19 249
                    QString path = m_imageModel->filePath(index);
665ac308 Poul Sander 2026-02-23 19:34 250
                    navigateToFolder(path);
09130ab9 Poul Sander 2026-02-22 22:19 251
                } else {
09130ab9 Poul Sander 2026-02-22 22:19 252
                    enterSingleImageMode(index);
09130ab9 Poul Sander 2026-02-22 22:19 253
                }
09130ab9 Poul Sander 2026-02-22 22:19 254
            });
61136b77 Poul Sander 2026-02-20 22:45 255
61136b77 Poul Sander 2026-02-20 22:45 256
    connect(m_imageView, &ImageViewWidget::closeRequested,
61136b77 Poul Sander 2026-02-20 22:45 257
            this, &MainWindow::leaveSingleImageMode);
61136b77 Poul Sander 2026-02-20 22:45 258
1ffc1962 Poul Sander 2026-02-20 23:41 259
    connect(m_imageView, &ImageViewWidget::nextRequested, this, [this]() {
1ffc1962 Poul Sander 2026-02-20 23:41 260
        QModelIndex cur = m_listView->currentIndex();
1ffc1962 Poul Sander 2026-02-20 23:41 261
        int next = cur.isValid() ? cur.row() + 1 : 0;
09130ab9 Poul Sander 2026-02-22 22:19 262
        while (next < m_imageModel->rowCount() && m_imageModel->isFolder(m_imageModel->index(next)))
09130ab9 Poul Sander 2026-02-22 22:19 263
            ++next;
1ffc1962 Poul Sander 2026-02-20 23:41 264
        if (next < m_imageModel->rowCount())
1ffc1962 Poul Sander 2026-02-20 23:41 265
        {
1ffc1962 Poul Sander 2026-02-20 23:41 266
            QModelIndex idx = m_imageModel->index(next);
1ffc1962 Poul Sander 2026-02-20 23:41 267
            m_listView->setCurrentIndex(idx);
1ffc1962 Poul Sander 2026-02-20 23:41 268
            enterSingleImageMode(idx);
1ffc1962 Poul Sander 2026-02-20 23:41 269
        }
1ffc1962 Poul Sander 2026-02-20 23:41 270
    });
1ffc1962 Poul Sander 2026-02-20 23:41 271
1ffc1962 Poul Sander 2026-02-20 23:41 272
    connect(m_imageView, &ImageViewWidget::previousRequested, this, [this]() {
1ffc1962 Poul Sander 2026-02-20 23:41 273
        QModelIndex cur = m_listView->currentIndex();
1ffc1962 Poul Sander 2026-02-20 23:41 274
        int prev = cur.isValid() ? cur.row() - 1 : 0;
09130ab9 Poul Sander 2026-02-22 22:19 275
        while (prev >= 0 && m_imageModel->isFolder(m_imageModel->index(prev)))
09130ab9 Poul Sander 2026-02-22 22:19 276
            --prev;
1ffc1962 Poul Sander 2026-02-20 23:41 277
        if (prev >= 0)
1ffc1962 Poul Sander 2026-02-20 23:41 278
        {
1ffc1962 Poul Sander 2026-02-20 23:41 279
            QModelIndex idx = m_imageModel->index(prev);
1ffc1962 Poul Sander 2026-02-20 23:41 280
            m_listView->setCurrentIndex(idx);
1ffc1962 Poul Sander 2026-02-20 23:41 281
            enterSingleImageMode(idx);
1ffc1962 Poul Sander 2026-02-20 23:41 282
        }
1ffc1962 Poul Sander 2026-02-20 23:41 283
    });
1ffc1962 Poul Sander 2026-02-20 23:41 284
6fcd6c90 Poul Sander 2026-02-19 21:12 285
    connect(m_listView->verticalScrollBar(), &QScrollBar::valueChanged,
6fcd6c90 Poul Sander 2026-02-19 21:12 286
            this, [this]()
6fcd6c90 Poul Sander 2026-02-19 21:12 287
            { loadVisibleThumbnails(); });
6fcd6c90 Poul Sander 2026-02-19 21:12 288
6fcd6c90 Poul Sander 2026-02-19 21:12 289
    // Also catch resize — visible range changes when the viewport is resized
6fcd6c90 Poul Sander 2026-02-19 21:12 290
    m_listView->viewport()->installEventFilter(this);
6fcd6c90 Poul Sander 2026-02-19 21:12 291
}
6fcd6c90 Poul Sander 2026-02-19 21:12 292
6fcd6c90 Poul Sander 2026-02-19 21:12 293
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
6fcd6c90 Poul Sander 2026-02-19 21:12 294
{
6fcd6c90 Poul Sander 2026-02-19 21:12 295
    if (obj == m_listView->viewport() && event->type() == QEvent::Resize)
6fcd6c90 Poul Sander 2026-02-19 21:12 296
        QTimer::singleShot(0, this, &MainWindow::loadVisibleThumbnails);
6fcd6c90 Poul Sander 2026-02-19 21:12 297
6fcd6c90 Poul Sander 2026-02-19 21:12 298
    return QMainWindow::eventFilter(obj, event);
6fcd6c90 Poul Sander 2026-02-19 21:12 299
}
6fcd6c90 Poul Sander 2026-02-19 21:12 300
6fcd6c90 Poul Sander 2026-02-19 21:12 301
void MainWindow::loadVisibleThumbnails()
6fcd6c90 Poul Sander 2026-02-19 21:12 302
{
6fcd6c90 Poul Sander 2026-02-19 21:12 303
    QModelIndex topLeft = m_listView->indexAt(QPoint(0, 0));
6fcd6c90 Poul Sander 2026-02-19 21:12 304
    QModelIndex bottomRight = m_listView->indexAt(
6fcd6c90 Poul Sander 2026-02-19 21:12 305
        QPoint(m_listView->viewport()->width() - 1,
6fcd6c90 Poul Sander 2026-02-19 21:12 306
               m_listView->viewport()->height() - 1));
6fcd6c90 Poul Sander 2026-02-19 21:12 307
6fcd6c90 Poul Sander 2026-02-19 21:12 308
    int first = topLeft.isValid() ? topLeft.row() : 0;
6fcd6c90 Poul Sander 2026-02-19 21:12 309
    int last = bottomRight.isValid() ? bottomRight.row()
6fcd6c90 Poul Sander 2026-02-19 21:12 310
                                     : m_imageModel->rowCount() - 1;
6fcd6c90 Poul Sander 2026-02-19 21:12 311
6fcd6c90 Poul Sander 2026-02-19 21:12 312
    if (last < 0)
6fcd6c90 Poul Sander 2026-02-19 21:12 313
        return;
6fcd6c90 Poul Sander 2026-02-19 21:12 314
6fcd6c90 Poul Sander 2026-02-19 21:12 315
    std::cout << "loadVisibleThumbnails: " << first << " - " << last << "\n";
6fcd6c90 Poul Sander 2026-02-19 21:12 316
    m_imageModel->requestThumbnails(first, last);
032aa1e1 Poul Sander 2026-02-19 18:55 317
}
cfe4a67b Poul Sander 2026-02-19 23:06 318
cfe4a67b Poul Sander 2026-02-19 23:06 319
void MainWindow::showPreview(const QModelIndex &index)
cfe4a67b Poul Sander 2026-02-19 23:06 320
{
cfe4a67b Poul Sander 2026-02-19 23:06 321
    if (!index.isValid())
cfe4a67b Poul Sander 2026-02-19 23:06 322
        return;
cfe4a67b Poul Sander 2026-02-19 23:06 323
cfe4a67b Poul Sander 2026-02-19 23:06 324
    QString path = m_imageModel->filePath(index);
cfe4a67b Poul Sander 2026-02-19 23:06 325
cfe4a67b Poul Sander 2026-02-19 23:06 326
    QImageReader reader(path);
cfe4a67b Poul Sander 2026-02-19 23:06 327
    reader.setAutoTransform(true);
7889168c Poul Sander 2026-02-26 18:27 328
    // Scale during decoding for the preview to avoid the 128 MB allocation limit
7889168c Poul Sander 2026-02-26 18:27 329
    QSize fullSize = reader.size();
7889168c Poul Sander 2026-02-26 18:27 330
    if (fullSize.isValid()) {
7889168c Poul Sander 2026-02-26 18:27 331
        QSize target = fullSize.scaled(m_previewLabel->size(), Qt::KeepAspectRatio);
7889168c Poul Sander 2026-02-26 18:27 332
        reader.setScaledSize(target);
7889168c Poul Sander 2026-02-26 18:27 333
    }
cfe4a67b Poul Sander 2026-02-19 23:06 334
    QImage image = reader.read();
cfe4a67b Poul Sander 2026-02-19 23:06 335
cfe4a67b Poul Sander 2026-02-19 23:06 336
    m_previewLabel->setPixmap(
cfe4a67b Poul Sander 2026-02-19 23:06 337
        QPixmap::fromImage(image).scaled(
cfe4a67b Poul Sander 2026-02-19 23:06 338
            m_previewLabel->size(),
cfe4a67b Poul Sander 2026-02-19 23:06 339
            Qt::KeepAspectRatio,
cfe4a67b Poul Sander 2026-02-19 23:06 340
            Qt::SmoothTransformation));
53fdab93 Poul Sander 2026-05-18 18:45 341
53fdab93 Poul Sander 2026-05-18 18:45 342
    updateExifInfo(path);
53fdab93 Poul Sander 2026-05-18 18:45 343
}
53fdab93 Poul Sander 2026-05-18 18:45 344
53fdab93 Poul Sander 2026-05-18 18:45 345
void MainWindow::updateExifInfo(const QString &path)
53fdab93 Poul Sander 2026-05-18 18:45 346
{
53fdab93 Poul Sander 2026-05-18 18:45 347
    QFileInfo fi(path);
53fdab93 Poul Sander 2026-05-18 18:45 348
    if (fi.isDir()) {
53fdab93 Poul Sander 2026-05-18 18:45 349
        m_exifTable->setRowCount(0);
53fdab93 Poul Sander 2026-05-18 18:45 350
        return;
53fdab93 Poul Sander 2026-05-18 18:45 351
    }
53fdab93 Poul Sander 2026-05-18 18:45 352
    const ExifData data = ExifReader::read(path);
53fdab93 Poul Sander 2026-05-18 18:45 353
    const auto fields = data.toList();
53fdab93 Poul Sander 2026-05-18 18:45 354
    m_exifTable->setRowCount(fields.size());
53fdab93 Poul Sander 2026-05-18 18:45 355
    for (int i = 0; i < fields.size(); ++i) {
53fdab93 Poul Sander 2026-05-18 18:45 356
        m_exifTable->setItem(i, 0, new QTableWidgetItem(fields[i].first));
53fdab93 Poul Sander 2026-05-18 18:45 357
        m_exifTable->setItem(i, 1, new QTableWidgetItem(fields[i].second));
53fdab93 Poul Sander 2026-05-18 18:45 358
    }
53fdab93 Poul Sander 2026-05-18 18:45 359
    m_exifTable->resizeColumnToContents(0);
cfe4a67b Poul Sander 2026-02-19 23:06 360
}
61136b77 Poul Sander 2026-02-20 22:45 361
61136b77 Poul Sander 2026-02-20 22:45 362
void MainWindow::enterSingleImageMode(const QModelIndex &index)
61136b77 Poul Sander 2026-02-20 22:45 363
{
61136b77 Poul Sander 2026-02-20 22:45 364
    if (!index.isValid())
61136b77 Poul Sander 2026-02-20 22:45 365
        return;
61136b77 Poul Sander 2026-02-20 22:45 366
cbc7d22b Poul Sander 2026-02-24 19:23 367
    // Only save state and hide chrome when transitioning from browse mode
cbc7d22b Poul Sander 2026-02-24 19:23 368
    if (m_stack->currentWidget() != m_imageView) {
3bee3e3e Poul Sander 2026-03-05 17:07 369
        m_rootDockWasVisible = m_rootDock->isVisible();
cbc7d22b Poul Sander 2026-02-24 19:23 370
        m_folderDockWasVisible = m_folderDock->isVisible();
cbc7d22b Poul Sander 2026-02-24 19:23 371
        m_previewDockWasVisible = m_previewDock->isVisible();
53fdab93 Poul Sander 2026-05-18 18:45 372
        m_exifDockWasVisible = m_exifDock->isVisible();
3bee3e3e Poul Sander 2026-03-05 17:07 373
        m_rootDock->hide();
cbc7d22b Poul Sander 2026-02-24 19:23 374
        m_folderDock->hide();
cbc7d22b Poul Sander 2026-02-24 19:23 375
        m_previewDock->hide();
53fdab93 Poul Sander 2026-05-18 18:45 376
        m_exifDock->hide();
cbc7d22b Poul Sander 2026-02-24 19:23 377
        m_menuBar->hide();
cbc7d22b Poul Sander 2026-02-24 19:23 378
    }
cbc7d22b Poul Sander 2026-02-24 19:23 379
f61bf886 Poul Sander 2026-02-23 19:27 380
    m_imageView->setBackgroundColor(m_backgroundColorPreference);
61136b77 Poul Sander 2026-02-20 22:45 381
    QString path = m_imageModel->filePath(index);
58103277 Poul Sander 2026-03-01 22:53 382
    m_imageView->setNeighborPaths(computeNeighborPaths(index));
61136b77 Poul Sander 2026-02-20 22:45 383
    m_imageView->setImage(path);
53fdab93 Poul Sander 2026-05-18 18:45 384
    m_imageView->setExifData(ExifReader::read(path));
53fdab93 Poul Sander 2026-05-18 18:45 385
    updateExifInfo(path);
61136b77 Poul Sander 2026-02-20 22:45 386
    m_stack->setCurrentWidget(m_imageView);
61136b77 Poul Sander 2026-02-20 22:45 387
    m_imageView->setFocus();
ccb726b8 Poul Sander 2026-02-23 22:43 388
ccb726b8 Poul Sander 2026-02-23 22:43 389
    if (m_imageViewWasFullScreen) {
ccb726b8 Poul Sander 2026-02-23 22:43 390
        setFullScreenMode(true);
ccb726b8 Poul Sander 2026-02-23 22:43 391
        m_imageViewWasFullScreen = false;
ccb726b8 Poul Sander 2026-02-23 22:43 392
    }
61136b77 Poul Sander 2026-02-20 22:45 393
}
61136b77 Poul Sander 2026-02-20 22:45 394
61136b77 Poul Sander 2026-02-20 22:45 395
void MainWindow::leaveSingleImageMode()
61136b77 Poul Sander 2026-02-20 22:45 396
{
3968465e Poul Sander 2026-02-23 19:13 397
    if (isFullScreen()) {
ccb726b8 Poul Sander 2026-02-23 22:43 398
        m_imageViewWasFullScreen = true;
ccb726b8 Poul Sander 2026-02-23 22:43 399
        setFullScreenMode(false);
61136b77 Poul Sander 2026-02-20 22:45 400
    }
58103277 Poul Sander 2026-03-01 22:53 401
    m_imageView->clearCache();
61136b77 Poul Sander 2026-02-20 22:45 402
    m_stack->setCurrentWidget(m_browserPage);
cbc7d22b Poul Sander 2026-02-24 19:23 403
    m_menuBar->show();
3bee3e3e Poul Sander 2026-03-05 17:07 404
    if (m_rootDockWasVisible)
3bee3e3e Poul Sander 2026-03-05 17:07 405
        m_rootDock->show();
cbc7d22b Poul Sander 2026-02-24 19:23 406
    if (m_folderDockWasVisible)
cbc7d22b Poul Sander 2026-02-24 19:23 407
        m_folderDock->show();
cbc7d22b Poul Sander 2026-02-24 19:23 408
    if (m_previewDockWasVisible)
cbc7d22b Poul Sander 2026-02-24 19:23 409
        m_previewDock->show();
53fdab93 Poul Sander 2026-05-18 18:45 410
    if (m_exifDockWasVisible)
53fdab93 Poul Sander 2026-05-18 18:45 411
        m_exifDock->show();
61136b77 Poul Sander 2026-02-20 22:45 412
    m_listView->setFocus();
61136b77 Poul Sander 2026-02-20 22:45 413
}
61136b77 Poul Sander 2026-02-20 22:45 414
58103277 Poul Sander 2026-03-01 22:53 415
QStringList MainWindow::computeNeighborPaths(const QModelIndex &index) const
58103277 Poul Sander 2026-03-01 22:53 416
{
58103277 Poul Sander 2026-03-01 22:53 417
    QStringList paths;
58103277 Poul Sander 2026-03-01 22:53 418
    int row = index.row();
58103277 Poul Sander 2026-03-01 22:53 419
58103277 Poul Sander 2026-03-01 22:53 420
    // Collect up to CacheKeepBehind non-folder images before current
58103277 Poul Sander 2026-03-01 22:53 421
    int count = 0;
58103277 Poul Sander 2026-03-01 22:53 422
    for (int i = row - 1; i >= 0 && count < ImageViewWidget::CacheKeepBehind; --i) {
58103277 Poul Sander 2026-03-01 22:53 423
        QModelIndex idx = m_imageModel->index(i);
58103277 Poul Sander 2026-03-01 22:53 424
        if (!m_imageModel->isFolder(idx)) {
58103277 Poul Sander 2026-03-01 22:53 425
            paths.prepend(m_imageModel->filePath(idx));
58103277 Poul Sander 2026-03-01 22:53 426
            ++count;
58103277 Poul Sander 2026-03-01 22:53 427
        }
58103277 Poul Sander 2026-03-01 22:53 428
    }
58103277 Poul Sander 2026-03-01 22:53 429
58103277 Poul Sander 2026-03-01 22:53 430
    // Collect up to CacheReadAhead non-folder images after current
58103277 Poul Sander 2026-03-01 22:53 431
    count = 0;
58103277 Poul Sander 2026-03-01 22:53 432
    for (int i = row + 1; i < m_imageModel->rowCount() && count < ImageViewWidget::CacheReadAhead; ++i) {
58103277 Poul Sander 2026-03-01 22:53 433
        QModelIndex idx = m_imageModel->index(i);
58103277 Poul Sander 2026-03-01 22:53 434
        if (!m_imageModel->isFolder(idx)) {
58103277 Poul Sander 2026-03-01 22:53 435
            paths.append(m_imageModel->filePath(idx));
58103277 Poul Sander 2026-03-01 22:53 436
            ++count;
58103277 Poul Sander 2026-03-01 22:53 437
        }
58103277 Poul Sander 2026-03-01 22:53 438
    }
58103277 Poul Sander 2026-03-01 22:53 439
58103277 Poul Sander 2026-03-01 22:53 440
    return paths;
58103277 Poul Sander 2026-03-01 22:53 441
}
58103277 Poul Sander 2026-03-01 22:53 442
ccb726b8 Poul Sander 2026-02-23 22:43 443
void MainWindow::setFullScreenMode(bool fullScreen)
ccb726b8 Poul Sander 2026-02-23 22:43 444
{
ccb726b8 Poul Sander 2026-02-23 22:43 445
    if (fullScreen == isFullScreen())
ccb726b8 Poul Sander 2026-02-23 22:43 446
        return;
ccb726b8 Poul Sander 2026-02-23 22:43 447
ccb726b8 Poul Sander 2026-02-23 22:43 448
    if (fullScreen) {
ccb726b8 Poul Sander 2026-02-23 22:43 449
        m_wasMaximized = isMaximized();
ccb726b8 Poul Sander 2026-02-23 22:43 450
        m_menuBar->hide();
ccb726b8 Poul Sander 2026-02-23 22:43 451
        showFullScreen();
ccb726b8 Poul Sander 2026-02-23 22:43 452
    } else {
cbc7d22b Poul Sander 2026-02-24 19:23 453
        // Only restore menu bar when returning to browse mode
cbc7d22b Poul Sander 2026-02-24 19:23 454
        if (m_stack->currentWidget() != m_imageView)
cbc7d22b Poul Sander 2026-02-24 19:23 455
            m_menuBar->show();
ccb726b8 Poul Sander 2026-02-23 22:43 456
        if (m_wasMaximized)
ccb726b8 Poul Sander 2026-02-23 22:43 457
            showMaximized();
ccb726b8 Poul Sander 2026-02-23 22:43 458
        else
ccb726b8 Poul Sander 2026-02-23 22:43 459
            showNormal();
ccb726b8 Poul Sander 2026-02-23 22:43 460
    }
ccb726b8 Poul Sander 2026-02-23 22:43 461
}
ccb726b8 Poul Sander 2026-02-23 22:43 462
61136b77 Poul Sander 2026-02-20 22:45 463
void MainWindow::keyPressEvent(QKeyEvent *event)
61136b77 Poul Sander 2026-02-20 22:45 464
{
61136b77 Poul Sander 2026-02-20 22:45 465
    if (event->key() == Qt::Key_F11 && m_stack->currentWidget() == m_imageView)
61136b77 Poul Sander 2026-02-20 22:45 466
    {
ccb726b8 Poul Sander 2026-02-23 22:43 467
        setFullScreenMode(!isFullScreen());
61136b77 Poul Sander 2026-02-20 22:45 468
        event->accept();
61136b77 Poul Sander 2026-02-20 22:45 469
        return;
61136b77 Poul Sander 2026-02-20 22:45 470
    }
61136b77 Poul Sander 2026-02-20 22:45 471
61136b77 Poul Sander 2026-02-20 22:45 472
    if (event->key() == Qt::Key_Return && m_stack->currentWidget() == m_browserPage)
61136b77 Poul Sander 2026-02-20 22:45 473
    {
61136b77 Poul Sander 2026-02-20 22:45 474
        QModelIndex current = m_listView->currentIndex();
61136b77 Poul Sander 2026-02-20 22:45 475
        if (current.isValid())
61136b77 Poul Sander 2026-02-20 22:45 476
        {
09130ab9 Poul Sander 2026-02-22 22:19 477
            if (m_imageModel->isFolder(current)) {
09130ab9 Poul Sander 2026-02-22 22:19 478
                QString path = m_imageModel->filePath(current);
665ac308 Poul Sander 2026-02-23 19:34 479
                navigateToFolder(path);
09130ab9 Poul Sander 2026-02-22 22:19 480
            } else {
09130ab9 Poul Sander 2026-02-22 22:19 481
                enterSingleImageMode(current);
09130ab9 Poul Sander 2026-02-22 22:19 482
            }
61136b77 Poul Sander 2026-02-20 22:45 483
            event->accept();
61136b77 Poul Sander 2026-02-20 22:45 484
            return;
61136b77 Poul Sander 2026-02-20 22:45 485
        }
61136b77 Poul Sander 2026-02-20 22:45 486
    }
61136b77 Poul Sander 2026-02-20 22:45 487
61136b77 Poul Sander 2026-02-20 22:45 488
    QMainWindow::keyPressEvent(event);
61136b77 Poul Sander 2026-02-20 22:45 489
}
c9e5684a Poul Sander 2026-02-23 19:18 490
c9e5684a Poul Sander 2026-02-23 19:18 491
void MainWindow::closeEvent(QCloseEvent *event)
c9e5684a Poul Sander 2026-02-23 19:18 492
{
c9e5684a Poul Sander 2026-02-23 19:18 493
    if (m_stack->currentWidget() == m_imageView)
c9e5684a Poul Sander 2026-02-23 19:18 494
    {
c9e5684a Poul Sander 2026-02-23 19:18 495
        leaveSingleImageMode();
c9e5684a Poul Sander 2026-02-23 19:18 496
        event->ignore();
c9e5684a Poul Sander 2026-02-23 19:18 497
        return;
c9e5684a Poul Sander 2026-02-23 19:18 498
    }
c9e5684a Poul Sander 2026-02-23 19:18 499
f61bf886 Poul Sander 2026-02-23 19:27 500
    savePreferences();
c9e5684a Poul Sander 2026-02-23 19:18 501
    QMainWindow::closeEvent(event);
c9e5684a Poul Sander 2026-02-23 19:18 502
}
f61bf886 Poul Sander 2026-02-23 19:27 503
4ae57f60 Poul Sander 2026-02-25 21:35 504
void MainWindow::applyDockLocking(bool lock)
4ae57f60 Poul Sander 2026-02-25 21:35 505
{
4ae57f60 Poul Sander 2026-02-25 21:35 506
    const QDockWidget::DockWidgetFeatures movableFeatures =
4ae57f60 Poul Sander 2026-02-25 21:35 507
        QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable;
4ae57f60 Poul Sander 2026-02-25 21:35 508
    const QDockWidget::DockWidgetFeatures baseFeatures =
4ae57f60 Poul Sander 2026-02-25 21:35 509
        QDockWidget::DockWidgetClosable;
4ae57f60 Poul Sander 2026-02-25 21:35 510
4ae57f60 Poul Sander 2026-02-25 21:35 511
    QDockWidget::DockWidgetFeatures features = lock ? baseFeatures
4ae57f60 Poul Sander 2026-02-25 21:35 512
                                                    : (baseFeatures | movableFeatures);
3bee3e3e Poul Sander 2026-03-05 17:07 513
    m_rootDock->setFeatures(features);
4ae57f60 Poul Sander 2026-02-25 21:35 514
    m_folderDock->setFeatures(features);
4ae57f60 Poul Sander 2026-02-25 21:35 515
    m_previewDock->setFeatures(features);
53fdab93 Poul Sander 2026-05-18 18:45 516
    m_exifDock->setFeatures(features);
4ae57f60 Poul Sander 2026-02-25 21:35 517
}
4ae57f60 Poul Sander 2026-02-25 21:35 518
f61bf886 Poul Sander 2026-02-23 19:27 519
void MainWindow::loadPreferences()
f61bf886 Poul Sander 2026-02-23 19:27 520
{
f61bf886 Poul Sander 2026-02-23 19:27 521
    QSettings settings("SagoImageBrowser", "SagoImageBrowser");
f61bf886 Poul Sander 2026-02-23 19:27 522
    m_backgroundColorPreference = settings.value("backgroundColor", "black").toString();
f61bf886 Poul Sander 2026-02-23 19:27 523
    m_imageView->setBackgroundColor(m_backgroundColorPreference);
4ae57f60 Poul Sander 2026-02-25 21:35 524
    m_lockDockingPreference = settings.value("lockDocking", false).toBool();
4ae57f60 Poul Sander 2026-02-25 21:35 525
    applyDockLocking(m_lockDockingPreference);
459bad0f Poul Sander 2026-05-17 14:11 526
    m_folderCacheSizePreference = settings.value("folderCacheSize", 4).toInt();
459bad0f Poul Sander 2026-05-17 14:11 527
    m_imageModel->setCacheMaxSize(m_folderCacheSizePreference);
ac476ca8 Poul Sander 2026-05-18 16:47 528
    m_thumbnailCacheSizePreference = settings.value("thumbnailCacheSize", "normal").toString();
ac476ca8 Poul Sander 2026-05-18 16:47 529
    m_imageModel->setThumbnailSize(thumbnailSizeFromString(m_thumbnailCacheSizePreference));
cbc7d22b Poul Sander 2026-02-24 19:23 530
    if (settings.contains("windowGeometry"))
cbc7d22b Poul Sander 2026-02-24 19:23 531
        restoreGeometry(settings.value("windowGeometry").toByteArray());
cbc7d22b Poul Sander 2026-02-24 19:23 532
    if (settings.contains("windowState"))
cbc7d22b Poul Sander 2026-02-24 19:23 533
        restoreState(settings.value("windowState").toByteArray());
f61bf886 Poul Sander 2026-02-23 19:27 534
}
f61bf886 Poul Sander 2026-02-23 19:27 535
f61bf886 Poul Sander 2026-02-23 19:27 536
void MainWindow::savePreferences()
f61bf886 Poul Sander 2026-02-23 19:27 537
{
f61bf886 Poul Sander 2026-02-23 19:27 538
    QSettings settings("SagoImageBrowser", "SagoImageBrowser");
f61bf886 Poul Sander 2026-02-23 19:27 539
    settings.setValue("backgroundColor", m_backgroundColorPreference);
4ae57f60 Poul Sander 2026-02-25 21:35 540
    settings.setValue("lockDocking", m_lockDockingPreference);
459bad0f Poul Sander 2026-05-17 14:11 541
    settings.setValue("folderCacheSize", m_folderCacheSizePreference);
ac476ca8 Poul Sander 2026-05-18 16:47 542
    settings.setValue("thumbnailCacheSize", m_thumbnailCacheSizePreference);
cbc7d22b Poul Sander 2026-02-24 19:23 543
    settings.setValue("windowGeometry", saveGeometry());
cbc7d22b Poul Sander 2026-02-24 19:23 544
    settings.setValue("windowState", saveState());
f61bf886 Poul Sander 2026-02-23 19:27 545
}
f61bf886 Poul Sander 2026-02-23 19:27 546
f61bf886 Poul Sander 2026-02-23 19:27 547
void MainWindow::onPreferencesTriggered()
f61bf886 Poul Sander 2026-02-23 19:27 548
{
f61bf886 Poul Sander 2026-02-23 19:27 549
    PreferencesDialog dialog(this);
f61bf886 Poul Sander 2026-02-23 19:27 550
    dialog.setBackgroundColor(m_backgroundColorPreference);
4ae57f60 Poul Sander 2026-02-25 21:35 551
    dialog.setLockDocking(m_lockDockingPreference);
459bad0f Poul Sander 2026-05-17 14:11 552
    dialog.setCacheSize(m_folderCacheSizePreference);
ac476ca8 Poul Sander 2026-05-18 16:47 553
    dialog.setThumbnailCacheSize(m_thumbnailCacheSizePreference);
f61bf886 Poul Sander 2026-02-23 19:27 554
7370f1c0 Poul Sander 2026-03-01 15:15 555
    bool shouldResetLayout = false;
7370f1c0 Poul Sander 2026-03-01 15:15 556
    connect(&dialog, &PreferencesDialog::resetLayoutRequested, this, [&shouldResetLayout]() {
7370f1c0 Poul Sander 2026-03-01 15:15 557
        shouldResetLayout = true;
7370f1c0 Poul Sander 2026-03-01 15:15 558
    });
7370f1c0 Poul Sander 2026-03-01 15:15 559
f61bf886 Poul Sander 2026-02-23 19:27 560
    if (dialog.exec() == QDialog::Accepted)
f61bf886 Poul Sander 2026-02-23 19:27 561
    {
f61bf886 Poul Sander 2026-02-23 19:27 562
        m_backgroundColorPreference = dialog.getBackgroundColor();
f61bf886 Poul Sander 2026-02-23 19:27 563
        m_imageView->setBackgroundColor(m_backgroundColorPreference);
4ae57f60 Poul Sander 2026-02-25 21:35 564
        m_lockDockingPreference = dialog.getLockDocking();
4ae57f60 Poul Sander 2026-02-25 21:35 565
        applyDockLocking(m_lockDockingPreference);
459bad0f Poul Sander 2026-05-17 14:11 566
        m_folderCacheSizePreference = dialog.getCacheSize();
459bad0f Poul Sander 2026-05-17 14:11 567
        m_imageModel->setCacheMaxSize(m_folderCacheSizePreference);
ac476ca8 Poul Sander 2026-05-18 16:47 568
        QString newThumbSize = dialog.getThumbnailCacheSize();
ac476ca8 Poul Sander 2026-05-18 16:47 569
        if (newThumbSize != m_thumbnailCacheSizePreference)
ac476ca8 Poul Sander 2026-05-18 16:47 570
        {
ac476ca8 Poul Sander 2026-05-18 16:47 571
            m_thumbnailCacheSizePreference = newThumbSize;
ac476ca8 Poul Sander 2026-05-18 16:47 572
            m_imageModel->setThumbnailSize(thumbnailSizeFromString(m_thumbnailCacheSizePreference));
ac476ca8 Poul Sander 2026-05-18 16:47 573
            loadVisibleThumbnails();
ac476ca8 Poul Sander 2026-05-18 16:47 574
        }
f61bf886 Poul Sander 2026-02-23 19:27 575
        savePreferences();
f61bf886 Poul Sander 2026-02-23 19:27 576
    }
7370f1c0 Poul Sander 2026-03-01 15:15 577
    
7370f1c0 Poul Sander 2026-03-01 15:15 578
    // Apply layout reset immediately after dialog closes if requested
7370f1c0 Poul Sander 2026-03-01 15:15 579
    if (shouldResetLayout) {
7370f1c0 Poul Sander 2026-03-01 15:15 580
        resetLayoutToDefault();
7370f1c0 Poul Sander 2026-03-01 15:15 581
    }
7370f1c0 Poul Sander 2026-03-01 15:15 582
}
7370f1c0 Poul Sander 2026-03-01 15:15 583
7370f1c0 Poul Sander 2026-03-01 15:15 584
void MainWindow::resetLayoutToDefault()
7370f1c0 Poul Sander 2026-03-01 15:15 585
{
7370f1c0 Poul Sander 2026-03-01 15:15 586
    QSettings settings("SagoImageBrowser", "SagoImageBrowser");
7370f1c0 Poul Sander 2026-03-01 15:15 587
    settings.remove("windowGeometry");
7370f1c0 Poul Sander 2026-03-01 15:15 588
    settings.remove("windowState");
7370f1c0 Poul Sander 2026-03-01 15:15 589
    
7370f1c0 Poul Sander 2026-03-01 15:15 590
    // Hide and detach docks completely
3bee3e3e Poul Sander 2026-03-05 17:07 591
    m_rootDock->hide();
7370f1c0 Poul Sander 2026-03-01 15:15 592
    m_folderDock->hide();
7370f1c0 Poul Sander 2026-03-01 15:15 593
    m_previewDock->hide();
7370f1c0 Poul Sander 2026-03-01 15:15 594
    
3bee3e3e Poul Sander 2026-03-05 17:07 595
    m_rootDock->setFloating(false);
7370f1c0 Poul Sander 2026-03-01 15:15 596
    m_folderDock->setFloating(false);
7370f1c0 Poul Sander 2026-03-01 15:15 597
    m_previewDock->setFloating(false);
7370f1c0 Poul Sander 2026-03-01 15:15 598
    
3bee3e3e Poul Sander 2026-03-05 17:07 599
    removeDockWidget(m_rootDock);
7370f1c0 Poul Sander 2026-03-01 15:15 600
    removeDockWidget(m_folderDock);
7370f1c0 Poul Sander 2026-03-01 15:15 601
    removeDockWidget(m_previewDock);
7370f1c0 Poul Sander 2026-03-01 15:15 602
    
7370f1c0 Poul Sander 2026-03-01 15:15 603
    // Re-add in default positions
3bee3e3e Poul Sander 2026-03-05 17:07 604
    addDockWidget(Qt::LeftDockWidgetArea, m_rootDock);
7370f1c0 Poul Sander 2026-03-01 15:15 605
    addDockWidget(Qt::LeftDockWidgetArea, m_folderDock);
7370f1c0 Poul Sander 2026-03-01 15:15 606
    addDockWidget(Qt::RightDockWidgetArea, m_previewDock);
3bee3e3e Poul Sander 2026-03-05 17:07 607
    splitDockWidget(m_rootDock, m_folderDock, Qt::Vertical);
7370f1c0 Poul Sander 2026-03-01 15:15 608
    
3bee3e3e Poul Sander 2026-03-05 17:07 609
    // Show all docks
3bee3e3e Poul Sander 2026-03-05 17:07 610
    m_rootDock->show();
7370f1c0 Poul Sander 2026-03-01 15:15 611
    m_folderDock->show();
7370f1c0 Poul Sander 2026-03-01 15:15 612
    m_previewDock->show();
f61bf886 Poul Sander 2026-02-23 19:27 613
}
1970-01-01 00:00 614