feat: move window state to a separate file (#1828)

Fixes #1084.
This commit is contained in:
Oleg Shparber
2026-05-03 22:20:39 +03:00
committed by GitHub
parent 7a1a9420ab
commit 9d2ec8f6de
14 changed files with 18415 additions and 37 deletions
File diff suppressed because it is too large Load Diff
+15
View File
@@ -6,6 +6,7 @@ add_library(Core STATIC
httpserver.cpp httpserver.cpp
networkaccessmanager.cpp networkaccessmanager.cpp
settings.cpp settings.cpp
session.cpp
) )
target_link_libraries(Core PRIVATE Registry) target_link_libraries(Core PRIVATE Registry)
@@ -38,6 +39,15 @@ else()
target_link_libraries(Core PRIVATE ${LibArchive_LIBRARIES}) target_link_libraries(Core PRIVATE ${LibArchive_LIBRARIES})
endif() endif()
# Configure toml++ (header-only).
find_package(tomlplusplus CONFIG QUIET)
if(tomlplusplus_FOUND)
target_link_libraries(Core PRIVATE tomlplusplus::tomlplusplus)
else()
# Use bundled version of toml++ if not found.
target_include_directories(Core PRIVATE "${CMAKE_SOURCE_DIR}/src/contrib/tomlplusplus")
endif()
# Configure cpp-httplib. # Configure cpp-httplib.
add_definitions(-DCPPHTTPLIB_USE_POLL) add_definitions(-DCPPHTTPLIB_USE_POLL)
@@ -55,3 +65,8 @@ if(NOT WIN32)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(Core PRIVATE Threads::Threads) target_link_libraries(Core PRIVATE Threads::Threads)
endif() endif()
# Tests
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
+12
View File
@@ -7,6 +7,7 @@
#include "filemanager.h" #include "filemanager.h"
#include "httpserver.h" #include "httpserver.h"
#include "networkaccessmanager.h" #include "networkaccessmanager.h"
#include "session.h"
#include "settings.h" #include "settings.h"
#include <registry/docsetregistry.h> #include <registry/docsetregistry.h>
@@ -39,6 +40,9 @@ Application::Application(QObject *parent)
m_instance = this; m_instance = this;
m_settings = new Settings(this); m_settings = new Settings(this);
m_session = new Session();
m_session->load();
m_networkManager = new NetworkAccessManager(this); m_networkManager = new NetworkAccessManager(this);
m_fileManager = new FileManager(this); m_fileManager = new FileManager(this);
@@ -75,6 +79,9 @@ Application::~Application()
m_extractorThread->wait(); m_extractorThread->wait();
delete m_extractor; delete m_extractor;
delete m_docsetRegistry; delete m_docsetRegistry;
m_session->save();
delete m_session;
} }
/*! /*!
@@ -92,6 +99,11 @@ QNetworkAccessManager *Application::networkManager() const
return m_networkManager; return m_networkManager;
} }
Session *Application::session() const
{
return m_session;
}
Settings *Application::settings() const Settings *Application::settings() const
{ {
return m_settings; return m_settings;
+3
View File
@@ -23,6 +23,7 @@ class Extractor;
class FileManager; class FileManager;
class HttpServer; class HttpServer;
class Settings; class Settings;
struct Session;
class Application final : public QObject class Application final : public QObject
{ {
@@ -35,6 +36,7 @@ public:
static Application *instance(); static Application *instance();
QNetworkAccessManager *networkManager() const; QNetworkAccessManager *networkManager() const;
Session *session() const;
Settings *settings() const; Settings *settings() const;
Registry::DocsetRegistry *docsetRegistry() const; Registry::DocsetRegistry *docsetRegistry() const;
@@ -65,6 +67,7 @@ private:
static Application *m_instance; static Application *m_instance;
Session *m_session = nullptr;
Settings *m_settings = nullptr; Settings *m_settings = nullptr;
QNetworkAccessManager *m_networkManager = nullptr; QNetworkAccessManager *m_networkManager = nullptr;
+224
View File
@@ -0,0 +1,224 @@
// Copyright (C) Oleg Shparber, et al. <https://zealdocs.org>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "session.h"
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QLoggingCategory>
#include <QSettings>
#include <QStandardPaths>
#include <sstream>
#include <string_view>
#include <toml++/toml.hpp>
namespace Zeal::Core {
namespace {
Q_LOGGING_CATEGORY(log, "zeal.core.session")
constexpr std::string_view ArrayWindows = "windows";
constexpr std::string_view KeyGeometry = "geometry";
constexpr std::string_view KeySplitter = "splitter";
constexpr std::string_view KeyTocSplitter = "toc_splitter";
QByteArray readBlob(const toml::table &tbl, std::string_view key)
{
const auto *node = tbl.get(key);
if (node == nullptr || !node->is_string()) {
return {};
}
const std::string &encoded = node->as_string()->get();
return QByteArray::fromBase64(QByteArray::fromStdString(encoded));
}
void writeBlob(toml::table &tbl, std::string_view key, const QByteArray &blob)
{
tbl.insert_or_assign(key, blob.toBase64().toStdString());
}
} // namespace
WindowState &Session::primaryWindow()
{
if (windows.isEmpty()) {
windows.append(WindowState());
}
return windows.first();
}
QString Session::defaultFilePath()
{
#ifdef PORTABLE_BUILD
return QCoreApplication::applicationDirPath() + QLatin1String("/session.toml");
#else
// Test mode: isolate test runs under ~/.qttest/zeal/, mirroring how
// QStandardPaths handles its own path categories in test mode.
if (QStandardPaths::isTestModeEnabled()) {
return QDir::homePath() + QLatin1String("/.qttest/zeal/session.toml");
}
// Compute the canonical platform path directly rather than via
// QStandardPaths::StateLocation, which (a) is Qt 6.7+ only and (b) appends
// "<organizationName>/<applicationName>" yielding the doubled "Zeal/Zeal"
// path tracked in #1104. The path must not depend on Qt version — distro
// Qt upgrades shouldn't relocate the state file.
#if defined(Q_OS_WIN)
QString base = QString::fromLocal8Bit(qgetenv("LOCALAPPDATA"));
if (base.isEmpty()) {
base = QDir::homePath() + QLatin1String("/AppData/Local");
}
return base + QLatin1String("/Zeal/session.toml");
#elif defined(Q_OS_MACOS)
return QDir::homePath() + QLatin1String("/Library/Application Support/Zeal/session.toml");
#else
const QByteArray xdgState = qgetenv("XDG_STATE_HOME");
const QString base = xdgState.isEmpty() ? QDir::homePath() + QLatin1String("/.local/state")
: QString::fromLocal8Bit(xdgState);
return base + QLatin1String("/zeal/session.toml");
#endif
#endif
}
void Session::load()
{
const QString path = defaultFilePath();
if (QFile::exists(path)) {
loadFromFile(path);
return;
}
// First launch with the new state system: migrate the three blobs from the
// legacy QSettings 'state' group. Persist session.toml before removing the
// legacy keys so a crash between the two steps doesn't lose user data —
// migration retries on the next launch.
#ifndef PORTABLE_BUILD
QSettings legacy;
#else
QSettings legacy(QCoreApplication::applicationDirPath() + QLatin1String("/zeal.ini"), QSettings::IniFormat);
#endif
legacy.beginGroup(QStringLiteral("state"));
const QByteArray geometry = legacy.value(QStringLiteral("window_geometry")).toByteArray();
const QByteArray splitter = legacy.value(QStringLiteral("splitter_geometry")).toByteArray();
const QByteArray tocSplitter = legacy.value(QStringLiteral("toc_splitter_state")).toByteArray();
legacy.endGroup();
if (geometry.isEmpty() && splitter.isEmpty() && tocSplitter.isEmpty()) {
return; // Nothing to migrate.
}
WindowState ws;
ws.geometry = geometry;
ws.splitterState = splitter;
ws.tocSplitterState = tocSplitter;
windows.append(ws);
if (!saveToFile(path)) {
return; // Leave legacy keys intact so migration retries next launch.
}
legacy.beginGroup(QStringLiteral("state"));
legacy.remove(QStringLiteral("window_geometry"));
legacy.remove(QStringLiteral("splitter_geometry"));
legacy.remove(QStringLiteral("toc_splitter_state"));
legacy.endGroup();
legacy.sync();
}
bool Session::save() const
{
return saveToFile(defaultFilePath());
}
void Session::loadFromFile(const QString &path)
{
windows.clear();
QFile file(path);
if (!file.exists()) {
return; // Defaults.
}
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(log, "Failed to open state file '%s': %s", qPrintable(path), qPrintable(file.errorString()));
return;
}
const QByteArray contents = file.readAll();
file.close();
toml::table root;
try {
root = toml::parse(std::string_view(contents.constData(), static_cast<size_t>(contents.size())));
} catch (const toml::parse_error &err) {
qCWarning(log,
"Failed to parse state file '%s': %s",
qPrintable(path),
qPrintable(QString::fromUtf8(err.description())));
return;
}
const auto *windowsNode = root.get(ArrayWindows);
if (windowsNode == nullptr || !windowsNode->is_array()) {
return;
}
for (const auto &node : *windowsNode->as_array()) {
const auto *tbl = node.as_table();
if (tbl == nullptr) {
continue;
}
WindowState ws;
ws.geometry = readBlob(*tbl, KeyGeometry);
ws.splitterState = readBlob(*tbl, KeySplitter);
ws.tocSplitterState = readBlob(*tbl, KeyTocSplitter);
windows.append(ws);
}
}
bool Session::saveToFile(const QString &path) const
{
QDir().mkpath(QFileInfo(path).absolutePath());
toml::array windowsArray;
for (const WindowState &ws : windows) {
toml::table tbl;
writeBlob(tbl, KeyGeometry, ws.geometry);
writeBlob(tbl, KeySplitter, ws.splitterState);
writeBlob(tbl, KeyTocSplitter, ws.tocSplitterState);
windowsArray.push_back(std::move(tbl));
}
toml::table root;
root.insert_or_assign(ArrayWindows, std::move(windowsArray));
std::ostringstream oss;
oss << "# Managed by Zeal. Do not edit manually.\n\n";
oss << root;
const std::string text = oss.str();
QFile file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
qCWarning(log, "Failed to write state file '%s': %s", qPrintable(path), qPrintable(file.errorString()));
return false;
}
const auto expected = static_cast<qint64>(text.size());
const qint64 written = file.write(text.c_str(), expected);
file.close();
if (written != expected) {
qCWarning(log, "Partial write to state file '%s': %s", qPrintable(path), qPrintable(file.errorString()));
// Don't leave a truncated/corrupt file behind — next launch should retry from scratch.
QFile::remove(path);
return false;
}
return true;
}
} // namespace Zeal::Core
+40
View File
@@ -0,0 +1,40 @@
// Copyright (C) Oleg Shparber, et al. <https://zealdocs.org>
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef ZEAL_CORE_SESSION_H
#define ZEAL_CORE_SESSION_H
#include <QByteArray>
#include <QList>
#include <QString>
namespace Zeal::Core {
struct WindowState final
{
QByteArray geometry;
QByteArray splitterState;
QByteArray tocSplitterState;
};
struct Session final
{
QList<WindowState> windows;
// Returns a reference to the first window's state, creating an empty entry
// if the list is empty. Until multi-window support lands, all callers go
// through this accessor.
WindowState &primaryWindow();
void load();
bool save() const;
void loadFromFile(const QString &path);
bool saveToFile(const QString &path) const;
static QString defaultFilePath();
};
} // namespace Zeal::Core
#endif // ZEAL_CORE_SESSION_H
-24
View File
@@ -38,7 +38,6 @@ constexpr char GroupGlobalShortcuts[] = "global_shortcuts";
constexpr char GroupSearch[] = "search"; constexpr char GroupSearch[] = "search";
constexpr char GroupTabs[] = "tabs"; constexpr char GroupTabs[] = "tabs";
constexpr char GroupInternal[] = "internal"; constexpr char GroupInternal[] = "internal";
constexpr char GroupState[] = "state";
constexpr char GroupProxy[] = "proxy"; constexpr char GroupProxy[] = "proxy";
} // namespace } // namespace
@@ -277,12 +276,6 @@ void Settings::load()
} }
} }
settings->beginGroup(GroupState);
windowGeometry = settings->value(QStringLiteral("window_geometry")).toByteArray();
verticalSplitterGeometry = settings->value(QStringLiteral("splitter_geometry")).toByteArray();
tocSplitterState = settings->value(QStringLiteral("toc_splitter_state")).toByteArray();
settings->endGroup();
settings->beginGroup(GroupInternal); settings->beginGroup(GroupInternal);
installId = settings installId = settings
->value(QStringLiteral("install_id"), ->value(QStringLiteral("install_id"),
@@ -352,12 +345,6 @@ void Settings::save()
settings->setValue(QStringLiteral("path"), docsetPath); settings->setValue(QStringLiteral("path"), docsetPath);
settings->endGroup(); settings->endGroup();
settings->beginGroup(GroupState);
settings->setValue(QStringLiteral("window_geometry"), windowGeometry);
settings->setValue(QStringLiteral("splitter_geometry"), verticalSplitterGeometry);
settings->setValue(QStringLiteral("toc_splitter_state"), tocSplitterState);
settings->endGroup();
settings->beginGroup(GroupInternal); settings->beginGroup(GroupInternal);
settings->setValue(QStringLiteral("install_id"), installId); settings->setValue(QStringLiteral("install_id"), installId);
// Version of configuration file format, should match Zeal version. Used for migration rules. // Version of configuration file format, should match Zeal version. Used for migration rules.
@@ -416,17 +403,6 @@ void Settings::migrate(QSettings *settings) const
settings->endGroup(); settings->endGroup();
} }
} }
//
// Pre 0.3
//
// Unset 'state/splitter_geometry', because custom styles were removed.
if (version < QVersionNumber(0, 3, 0)) {
settings->beginGroup(GroupState);
settings->remove(QStringLiteral("splitter_geometry"));
settings->endGroup();
}
} }
/*! /*!
-5
View File
@@ -100,11 +100,6 @@ public:
// Other // Other
QString docsetPath; QString docsetPath;
// State
QByteArray windowGeometry;
QByteArray verticalSplitterGeometry;
QByteArray tocSplitterState;
explicit Settings(QObject *parent = nullptr); explicit Settings(QObject *parent = nullptr);
~Settings() override; ~Settings() override;
+6
View File
@@ -0,0 +1,6 @@
find_package(Qt6 REQUIRED COMPONENTS Test)
add_executable(session_test session_test.cpp)
target_link_libraries(session_test PRIVATE Core Qt6::Test)
zeal_add_test(session_test)
+212
View File
@@ -0,0 +1,212 @@
// Copyright (C) Oleg Shparber, et al. <https://zealdocs.org>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "../session.h"
#include <QSettings>
#include <QStandardPaths>
#include <QTemporaryDir>
#include <QtTest>
using Zeal::Core::Session;
using Zeal::Core::WindowState;
class SessionTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void loadMissingFile_usesDefaults();
void saveThenLoad_roundTrip();
void loadCorruptFile_usesDefaults();
void loadEmptyFile_usesDefaults();
void loadPartialFile_missingKeysUseDefaults();
void load_migratesFromLegacyQSettings();
void load_skipsMigrationWhenStateFileExists();
};
void SessionTest::initTestCase()
{
QStandardPaths::setTestModeEnabled(true);
QCoreApplication::setOrganizationName(QStringLiteral("ZealTest"));
QCoreApplication::setApplicationName(QStringLiteral("ZealTest"));
}
void SessionTest::loadMissingFile_usesDefaults()
{
QTemporaryDir dir;
QVERIFY(dir.isValid());
Session session;
session.loadFromFile(dir.filePath("missing.toml"));
QVERIFY(session.windows.isEmpty());
}
void SessionTest::saveThenLoad_roundTrip()
{
QTemporaryDir dir;
QVERIFY(dir.isValid());
const QString path = dir.filePath("session.toml");
const QByteArray geom = QByteArray::fromHex("0102030405deadbeef");
const QByteArray splitter = QByteArray::fromHex("aabbccdd");
const QByteArray tocSplitter = QByteArray::fromHex("cafebabe");
{
Session out;
WindowState ws;
ws.geometry = geom;
ws.splitterState = splitter;
ws.tocSplitterState = tocSplitter;
out.windows.append(ws);
out.saveToFile(path);
}
Session in;
in.loadFromFile(path);
QCOMPARE(in.windows.size(), 1);
QCOMPARE(in.windows.first().geometry, geom);
QCOMPARE(in.windows.first().splitterState, splitter);
QCOMPARE(in.windows.first().tocSplitterState, tocSplitter);
}
void SessionTest::loadCorruptFile_usesDefaults()
{
QTemporaryDir dir;
QVERIFY(dir.isValid());
const QString path = dir.filePath("session.toml");
QFile file(path);
QVERIFY(file.open(QIODevice::WriteOnly));
file.write("this is not [valid toml");
file.close();
Session session;
session.loadFromFile(path);
QVERIFY(session.windows.isEmpty());
}
void SessionTest::loadEmptyFile_usesDefaults()
{
QTemporaryDir dir;
QVERIFY(dir.isValid());
const QString path = dir.filePath("session.toml");
QFile file(path);
QVERIFY(file.open(QIODevice::WriteOnly));
file.close();
Session session;
session.loadFromFile(path);
QVERIFY(session.windows.isEmpty());
}
void SessionTest::loadPartialFile_missingKeysUseDefaults()
{
QTemporaryDir dir;
QVERIFY(dir.isValid());
const QString path = dir.filePath("session.toml");
QFile file(path);
QVERIFY(file.open(QIODevice::WriteOnly));
file.write("[[windows]]\ngeometry = \"AQIDBA==\"\n");
file.close();
Session session;
session.loadFromFile(path);
QCOMPARE(session.windows.size(), 1);
QCOMPARE(session.windows.first().geometry, QByteArray::fromHex("01020304"));
QCOMPARE(session.windows.first().splitterState, QByteArray());
QCOMPARE(session.windows.first().tocSplitterState, QByteArray());
}
void SessionTest::load_migratesFromLegacyQSettings()
{
const QByteArray geom = QByteArray::fromHex("deadbeef0102");
const QByteArray splitter = QByteArray::fromHex("aabbccdd");
const QByteArray tocSplitter = QByteArray::fromHex("11223344");
// Populate legacy QSettings and make sure session.toml does not exist yet.
{
QSettings legacy;
legacy.beginGroup(QStringLiteral("state"));
legacy.setValue(QStringLiteral("window_geometry"), geom);
legacy.setValue(QStringLiteral("splitter_geometry"), splitter);
legacy.setValue(QStringLiteral("toc_splitter_state"), tocSplitter);
legacy.endGroup();
legacy.sync();
}
QFile::remove(Session::defaultFilePath());
Session session;
session.load();
QCOMPARE(session.windows.size(), 1);
QCOMPARE(session.windows.first().geometry, geom);
QCOMPARE(session.windows.first().splitterState, splitter);
QCOMPARE(session.windows.first().tocSplitterState, tocSplitter);
// Legacy keys should be gone after migration.
QSettings legacy;
legacy.beginGroup(QStringLiteral("state"));
QVERIFY(!legacy.contains(QStringLiteral("window_geometry")));
QVERIFY(!legacy.contains(QStringLiteral("splitter_geometry")));
QVERIFY(!legacy.contains(QStringLiteral("toc_splitter_state")));
// Migration must persist the state so future runs load from TOML, not QSettings.
QVERIFY(QFile::exists(Session::defaultFilePath()));
// Cleanup so other tests start from a known state.
QFile::remove(Session::defaultFilePath());
}
void SessionTest::load_skipsMigrationWhenStateFileExists()
{
const QByteArray legacyGeom = QByteArray::fromHex("deadbeef");
const QByteArray tomlGeom = QByteArray::fromHex("aabbccdd");
// Populate legacy QSettings with values that should NOT be loaded.
{
QSettings legacy;
legacy.beginGroup(QStringLiteral("state"));
legacy.setValue(QStringLiteral("window_geometry"), legacyGeom);
legacy.endGroup();
legacy.sync();
}
// Create session.toml with different values that SHOULD be loaded.
{
Session out;
WindowState ws;
ws.geometry = tomlGeom;
out.windows.append(ws);
QVERIFY(out.saveToFile(Session::defaultFilePath()));
}
Session session;
session.load();
// Loaded from TOML, not legacy.
QCOMPARE(session.windows.size(), 1);
QCOMPARE(session.windows.first().geometry, tomlGeom);
// Legacy keys must be untouched (migration was skipped).
QSettings legacy;
legacy.beginGroup(QStringLiteral("state"));
QCOMPARE(legacy.value(QStringLiteral("window_geometry")).toByteArray(), legacyGeom);
legacy.endGroup();
// Cleanup so other tests start from a known state.
{
QSettings cleanup;
cleanup.beginGroup(QStringLiteral("state"));
cleanup.remove(QStringLiteral("window_geometry"));
cleanup.endGroup();
}
QFile::remove(Session::defaultFilePath());
}
QTEST_GUILESS_MAIN(SessionTest)
#include "session_test.moc"
+2 -2
View File
@@ -6,7 +6,7 @@
#include "view.h" #include "view.h"
#include <core/application.h> #include <core/application.h>
#include <core/settings.h> #include <core/session.h>
#include <ui/widgets/layouthelper.h> #include <ui/widgets/layouthelper.h>
#include <QSplitter> #include <QSplitter>
@@ -23,7 +23,7 @@ Container::Container(QWidget *parent)
m_splitter = new QSplitter(); m_splitter = new QSplitter();
m_splitter->setOrientation(Qt::Vertical); m_splitter->setOrientation(Qt::Vertical);
connect(m_splitter, &QSplitter::splitterMoved, this, [this]() { connect(m_splitter, &QSplitter::splitterMoved, this, [this]() {
Core::Application::instance()->settings()->tocSplitterState = m_splitter->saveState(); Core::Application::instance()->session()->primaryWindow().tocSplitterState = m_splitter->saveState();
}); });
// Setup main layout. // Setup main layout.
+7 -4
View File
@@ -15,6 +15,7 @@
#include <browser/webbridge.h> #include <browser/webbridge.h>
#include <browser/webcontrol.h> #include <browser/webcontrol.h>
#include <core/application.h> #include <core/application.h>
#include <core/session.h>
#include <core/settings.h> #include <core/settings.h>
#include <qxtglobalshortcut/qxtglobalshortcut.h> #include <qxtglobalshortcut/qxtglobalshortcut.h>
#include <sidebar/container.h> #include <sidebar/container.h>
@@ -73,7 +74,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent)
setCentralWidget(centralWidget); setCentralWidget(centralWidget);
restoreGeometry(m_settings->windowGeometry); Core::WindowState &windowState = m_application->session()->primaryWindow();
restoreGeometry(windowState.geometry);
// Setup sidebar. // Setup sidebar.
auto *sbViewProvider = new SidebarViewProvider(this); auto *sbViewProvider = new SidebarViewProvider(this);
@@ -84,7 +86,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent)
// Setup splitter. // Setup splitter.
m_splitter->insertWidget(0, sb); m_splitter->insertWidget(0, sb);
m_splitter->restoreState(m_settings->verticalSplitterGeometry); m_splitter->restoreState(windowState.splitterState);
// Setup web settings. // Setup web settings.
new Browser::Settings(m_settings, this); new Browser::Settings(m_settings, this);
@@ -108,8 +110,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent)
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
m_settings->verticalSplitterGeometry = m_splitter->saveState(); Core::WindowState &windowState = m_application->session()->primaryWindow();
m_settings->windowGeometry = saveGeometry(); windowState.splitterState = m_splitter->saveState();
windowState.geometry = saveGeometry();
} }
void MainWindow::search(const Registry::SearchQuery &query) void MainWindow::search(const Registry::SearchQuery &query)
+3 -2
View File
@@ -9,6 +9,7 @@
#include "widgets/toolbarframe.h" #include "widgets/toolbarframe.h"
#include <core/application.h> #include <core/application.h>
#include <core/session.h>
#include <core/settings.h> #include <core/settings.h>
#include <registry/docset.h> #include <registry/docset.h>
#include <registry/docsetregistry.h> #include <registry/docsetregistry.h>
@@ -104,7 +105,7 @@ SearchSidebar::SearchSidebar(const SearchSidebar *other, QWidget *parent)
m_pageTocView->hide(); m_pageTocView->hide();
} else { } else {
m_pageTocView->show(); m_pageTocView->show();
m_splitter->restoreState(Core::Application::instance()->settings()->tocSplitterState); m_splitter->restoreState(Core::Application::instance()->session()->primaryWindow().tocSplitterState);
} }
}); });
m_pageTocView->setModel(m_pageTocModel); m_pageTocView->setModel(m_pageTocModel);
@@ -192,7 +193,7 @@ SearchSidebar::SearchSidebar(const SearchSidebar *other, QWidget *parent)
m_splitter->addWidget(m_treeView); m_splitter->addWidget(m_treeView);
m_splitter->addWidget(m_pageTocView); m_splitter->addWidget(m_pageTocView);
connect(m_splitter, &QSplitter::splitterMoved, this, [this]() { connect(m_splitter, &QSplitter::splitterMoved, this, [this]() {
Core::Application::instance()->settings()->tocSplitterState = m_splitter->saveState(); Core::Application::instance()->session()->primaryWindow().tocSplitterState = m_splitter->saveState();
}); });
// Setup main layout. // Setup main layout.
+1
View File
@@ -11,6 +11,7 @@
"default-features": false "default-features": false
}, },
"sqlite3", "sqlite3",
"tomlplusplus",
"vulkan-headers" "vulkan-headers"
] ]
} }