From 0b9cf8c968a89784b5c2b8afe1a819b33749165e Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Wed, 28 Nov 2018 12:39:14 +0100 Subject: Rewrite Session saving and loading --- doc/Development/Configuring.asciidoc | 34 ------------- doc/Development/Session.asciidoc | 19 ++++++++ doc/Development/meson.asciidoc | 30 ++++++++++++ src/browser.cpp | 2 +- src/browser.h | 4 ++ src/mainwindow/mainwindow.cpp | 32 +++--------- src/mainwindow/mainwindow.h | 2 +- src/session/session.cpp | 95 ++++++++++++++++++++++++++++++++---- src/session/session.h | 12 ++++- src/session/sessiondialog.cpp | 2 +- src/subwindow/subwindow.cpp | 2 +- src/subwindow/subwindow.h | 2 +- 12 files changed, 163 insertions(+), 73 deletions(-) delete mode 100644 doc/Development/Configuring.asciidoc create mode 100644 doc/Development/Session.asciidoc create mode 100644 doc/Development/meson.asciidoc diff --git a/doc/Development/Configuring.asciidoc b/doc/Development/Configuring.asciidoc deleted file mode 100644 index f436da5..0000000 --- a/doc/Development/Configuring.asciidoc +++ /dev/null @@ -1,34 +0,0 @@ -=== CMake - -==== Compiler flags --pipe -fstack-protector-strong -fno-plt -fPIE --march=native -mtune=native - -==== Install paths -CMAKE_INSTALL_PREFIX is prepended onto all install paths. This variable defaults -to /usr/local on *nix and c:/Program Files/${PROJECT_NAME} on Windows. - -On *nix you can use DESTDIR to relocate the entire installation. DESTDIR is -prepended to CMAKE_INSTALL_PREFIX. - -This will install the project to /ports/pkg/install/usr: - -[source, sh] ----- -cmake -DCMAKE_INSTALL_PREFIX=/usr ... -... -make DESTDIR=/ports/pkg/install install ----- - -==== clang-tidy -CMAKE_CXX_CLANG_TIDY="clang-tidy;-checks=*" - -==== cppcheck -CMAKE_CXX_CPPCHECK="cppcheck" - -==== ccache --DCMAKE_CXX_COMPILER_LAUNCHER=ccache - -==== llvm libcpp -CMAKE_CXX_FLAGS: -stdlib=libc++" -CMAKE_EXE_LINKER_FLAGS -stdlib=libc++ diff --git a/doc/Development/Session.asciidoc b/doc/Development/Session.asciidoc new file mode 100644 index 0000000..846d6a3 --- /dev/null +++ b/doc/Development/Session.asciidoc @@ -0,0 +1,19 @@ +== Session + +== Session JSON structure +- windows: list of windows + +=== Window +- subwindows: list of subwindows + +=== Subwindow +- profile: profile ID +- tabs: list of views +- current: current tab index + +=== View +- profile: profile ID +- history: view history + +Storing history: compress, toBase64 (to make printable), toQString (to store in json) +Restoring history: toLatin1 (turn into bytearray), fromBase64, uncompress diff --git a/doc/Development/meson.asciidoc b/doc/Development/meson.asciidoc new file mode 100644 index 0000000..1eb08c6 --- /dev/null +++ b/doc/Development/meson.asciidoc @@ -0,0 +1,30 @@ +==== Setting compiler +Compiler can only be set when initially configuring the build, and cannot be +changed with --reconfigure: + +[source, sh] +---- +export CXX="ccache clang++" +meson build-path +---- + +==== Setting linker +[source, sh] +---- +build% meson configure -Dcpp_link_args='-fuse_ld=gold' +---- + +==== Listing build options +[source, sh] +---- +build% meson configure +---- + +==== Changing build options +[source, sh] +---- +build% meson configure -D= +# for example: +build% meson configure -DPlasma=enabled +---- + diff --git a/src/browser.cpp b/src/browser.cpp index 7130096..0a0bd91 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -221,7 +221,7 @@ void Browser::createSession(const QJsonObject &object) } } if(window == nullptr) - window = mainwindow->createSubWindow(m_config, profile); + window = mainwindow->createSubWindow(m_config.get(), profile); const QJsonArray tabs = subwindow.value("tabs").toArray(); if(tabs.isEmpty()) diff --git a/src/browser.h b/src/browser.h index 1989631..5a6404b 100644 --- a/src/browser.h +++ b/src/browser.h @@ -53,6 +53,10 @@ public: void setup(QVector plugins); + const QVector windows() const + { + return qAsConst(m_windows); + } QJsonObject session() const { return Session::session(m_windows); diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp index a01cb94..9e6f187 100644 --- a/src/mainwindow/mainwindow.cpp +++ b/src/mainwindow/mainwindow.cpp @@ -95,7 +95,7 @@ MainWindow::MainWindow(const std::unique_ptr &config, QWidget *pa { connect(ui->actionNewSubwindow, &QAction::triggered, this, [this, &config]() { auto *profile = WebProfile::defaultProfile(); - auto *window = createSubWindow(config, profile); + auto *window = createSubWindow(config.get(), profile); window->addTab(profile->newtab(), profile); }); config->setShortcut(ui->actionNewSubwindow, "mainwindow.shortcuts.newGroup"); @@ -118,34 +118,18 @@ MainWindow::MainWindow(const std::unique_ptr &config, QWidget *pa // connect session menu { - connect(ui->actionSaveSession, &QAction::triggered, this, [this]() { -#ifndef QT_DEBUG - const QString filename = QFileDialog::getSaveFileName(this, tr("Save Session"), QDir::homePath(), tr("JSON (*.json)")); + const QString sessionPath = config->value("browser.session.path").value(); + connect(ui->actionSaveSession, &QAction::triggered, this, [this, sessionPath]() { + const QString filename = QFileDialog::getSaveFileName(this, tr("Save Session"), sessionPath, tr("JSON (*.json)")); QFile output(filename); if(output.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { - output.write(QJsonDocument(Session::window(this)).toJson()); + auto *browser = qobject_cast(qApp); + auto data = Session::_session(browser->windows()); + output.write(QJsonDocument(data).toJson()); output.close(); } -#else - auto data = Session::view(currentView); - QJsonDocument doc(data); - qDebug(qUtf8Printable(doc.toJson())); -#endif }); -#ifdef QT_DEBUG - auto *openViewAction = ui->menuSession->addAction("Open View"); - connect(openViewAction, &QAction::triggered, this, [this]() { - const QString filename = QFileDialog::getOpenFileName(this, tr("Open View"), QDir::homePath(), tr("JSON (*json)")); - QFile output(filename); - if(output.open(QIODevice::ReadOnly | QIODevice::Text)) { - QJsonDocument doc = QJsonDocument::fromJson(output.readAll()); - Session::restoreView(currentView, doc.object()); - output.close(); - } - }); -#endif - connect(ui->actionLoadSession, &QAction::triggered, this, [this]() { auto *sessionDialog = new SessionDialog(this); sessionDialog->exec(); @@ -356,7 +340,7 @@ SubWindow *MainWindow::currentSubWindow() const return qobject_cast(mdiArea->currentSubWindow()); } -SubWindow *MainWindow::createSubWindow(const std::unique_ptr &config, WebProfile *profile) +SubWindow *MainWindow::createSubWindow(const Configuration *config, WebProfile *profile) { bool shouldMaximize = true; // if there is a current window, use its maximize state diff --git a/src/mainwindow/mainwindow.h b/src/mainwindow/mainwindow.h index 296a73e..de77540 100644 --- a/src/mainwindow/mainwindow.h +++ b/src/mainwindow/mainwindow.h @@ -54,7 +54,7 @@ signals: public slots: void createTab(const QUrl &url); - SubWindow *createSubWindow(const std::unique_ptr &config, WebProfile *profile); + SubWindow *createSubWindow(const Configuration *config, WebProfile *profile); private slots: void setView(WebView *view); diff --git a/src/session/session.cpp b/src/session/session.cpp index d728d55..0853c70 100644 --- a/src/session/session.cpp +++ b/src/session/session.cpp @@ -7,15 +7,17 @@ */ #include "session.h" +#include "../webengine/webview.h" +#include "browser.h" #include "mainwindow/mainwindow.h" +#include "profilemanager.h" #include "subwindow/subwindow.h" -#include -#include #include "webengine/webview.h" -#include "profilemanager.h" -#include "browser.h" -#include "../webengine/webview.h" +#include +#include #include +#include +#include "configuration.h" QJsonObject Session::session(QVector windows) { @@ -81,6 +83,58 @@ QJsonObject Session::window(const QString &profile, const QStringList &urls) return session; } +////// + +QJsonObject Session::_session(const QVector windows) +{ + QJsonObject sessionData; + + { + QJsonArray windowList; + for(const auto *window : windows) { + windowList.append(Session::_window(window)); + } + sessionData.insert("windows", windowList); + } + + return sessionData; +} + +QJsonObject Session::_window(const MainWindow *window) +{ + QJsonObject windowData; + + { + QJsonArray subwindows; + for(const auto *subwindow : window->subWindows()) { + subwindows.append(Session::_subwindow(subwindow)); + } + windowData.insert("subwindows", subwindows); + } + + return windowData; +} + +QJsonObject Session::_subwindow(const SubWindow *subwindow) +{ + auto *profileManager = dynamic_cast(qApp)->getProfileManager(); + Q_CHECK_PTR(profileManager); + + QJsonObject subwindowData; + + subwindowData.insert("profile", profileManager->id(subwindow->profile())); + + { + QJsonArray tabs; + for(int i = 0; i < subwindow->tabCount(); ++i) { + tabs.append(Session::view(subwindow->view(i))); + } + subwindowData.insert("tabs", tabs); + } + + return subwindowData; +} + QJsonObject Session::view(const WebView *view) { auto *profileManager = dynamic_cast(qApp)->getProfileManager(); @@ -91,10 +145,10 @@ QJsonObject Session::view(const WebView *view) historyStream << *view->history(); QJsonObject viewData; - viewData.insert("url", view->url().toString()); viewData.insert("profile", profileManager->id(view->profile())); - //viewData.insert("history", QString(qCompress(historyData).toBase64())); - viewData.insert("history", QString(historyData.toBase64())); + + // store history: compress, toBase64 (to make printable), toQString (to store in json) + viewData.insert("history", QString(qCompress(historyData).toBase64())); return viewData; } @@ -108,7 +162,30 @@ void Session::restoreView(WebView *view, const QJsonObject &data) if(profile) view->setProfile(profile); - QByteArray historyData = QByteArray::fromBase64(data["history"].toString().toLatin1()); + // restore history: toLatin1 (turn into bytearray), fromBase64, uncompress + QByteArray historyData = qUncompress(QByteArray::fromBase64(data["history"].toString().toLatin1())); QDataStream historyStream(&historyData, QIODevice::ReadOnly); historyStream >> *view->history(); } + +void Session::restoreSession(const QJsonObject &sessionData) +{ + auto *browser = dynamic_cast(qApp); + Q_CHECK_PTR(browser); + auto *profileManager = browser->getProfileManager(); + Q_CHECK_PTR(profileManager); + + for(const auto windowData : sessionData["windows"].toArray()) { + auto *window = browser->createWindow(); + + for(const auto subwindowData : windowData.toObject()["subwindows"].toArray()) { + auto *subwindow = window->createSubWindow(browser->getConfiguration(), WebProfile::defaultProfile()); + subwindow->setProfile(profileManager->profile(subwindowData.toObject()["profile"].toString())); + + for(const auto tabData : subwindowData.toObject()["tabs"].toArray()) { + auto *view = subwindow->view(subwindow->addTab()); + Session::restoreView(view, tabData.toObject()); + } + } + } +} diff --git a/src/session/session.h b/src/session/session.h index 222c7ef..720b711 100644 --- a/src/session/session.h +++ b/src/session/session.h @@ -12,6 +12,7 @@ #include class MainWindow; +class SubWindow; class WebView; namespace Session { @@ -19,8 +20,17 @@ QJsonObject session(QVector windows); QJsonObject window(const MainWindow *window); QJsonObject window(const QString &profile, const QStringList &urls); +// TODO: +QJsonObject _session(const QVector windows); +QJsonObject _window(const MainWindow *window); +QJsonObject _subwindow(const SubWindow *subwindow); + + QJsonObject view(const WebView *view); void restoreView(WebView *view, const QJsonObject &data); -} + +void restoreSession(const QJsonObject &sessionData); + +} // namespace Session #endif // SMOLBOTE_SESSION_H diff --git a/src/session/sessiondialog.cpp b/src/session/sessiondialog.cpp index e31a42f..5fd65c3 100644 --- a/src/session/sessiondialog.cpp +++ b/src/session/sessiondialog.cpp @@ -81,7 +81,7 @@ void SessionDialog::openSession(const QString &filename) if(json.open(QIODevice::ReadOnly | QIODevice::Text)) { auto *browser = qobject_cast(qApp); auto doc = QJsonDocument::fromJson(json.readAll()); - browser->createSession(doc.object()); + Session::restoreSession(doc.object()); json.close(); } } diff --git a/src/subwindow/subwindow.cpp b/src/subwindow/subwindow.cpp index f718368..1006200 100644 --- a/src/subwindow/subwindow.cpp +++ b/src/subwindow/subwindow.cpp @@ -23,7 +23,7 @@ #include "profilemanager.h" #include "webprofile.h" -SubWindow::SubWindow(const std::unique_ptr &config, QWidget *parent, Qt::WindowFlags flags) +SubWindow::SubWindow(const Configuration *config, QWidget *parent, Qt::WindowFlags flags) : QMdiSubWindow(parent, flags) , tabWidget(new TabWidget(this)) { diff --git a/src/subwindow/subwindow.h b/src/subwindow/subwindow.h index 5dd17f2..3d70c98 100644 --- a/src/subwindow/subwindow.h +++ b/src/subwindow/subwindow.h @@ -22,7 +22,7 @@ class SubWindow : public QMdiSubWindow Q_OBJECT public: - explicit SubWindow(const std::unique_ptr &config, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); + explicit SubWindow(const Configuration *config, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); ~SubWindow() override; WebView *currentView(); -- cgit v1.2.1