ViewArea session (#1762)

This commit is contained in:
Le Tan 2021-05-15 05:49:29 -07:00 committed by GitHub
parent 6cd666552d
commit 1843ca5bfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 626 additions and 36 deletions

View File

@ -25,7 +25,7 @@ Buffer::Buffer(const BufferParameters &p_parameters,
QObject *p_parent)
: QObject(p_parent),
m_provider(p_parameters.m_provider),
c_id(generateBufferID()),
m_id(generateBufferID()),
m_readOnly(m_provider->isReadOnly())
{
m_autoSaveTimer = new QTimer(this);
@ -110,9 +110,9 @@ QString Buffer::getResourcePath() const
return m_provider->getResourcePath();
}
ID Buffer::getID() const
ID Buffer::getId() const
{
return c_id;
return m_id;
}
const QString &Buffer::getContent() const

View File

@ -87,7 +87,7 @@ namespace vnotex
// Return nullptr if not available.
QSharedPointer<File> getFile() const;
ID getID() const;
ID getId() const;
// Get buffer content.
// It may differ from the content on disk.
@ -212,7 +212,7 @@ namespace vnotex
bool isBackupFileOfBuffer(const QString &p_file) const;
// Will be assigned uniquely once created.
const ID c_id = 0;
const ID m_id = 0;
// Revision of contents.
int m_revision = 0;

View File

@ -49,6 +49,8 @@ void CoreConfig::init(const QJsonObject &p_app,
}
loadNoteManagement(appObj, userObj);
m_recoverLastSessionOnStartEnabled = READBOOL(QStringLiteral("recover_last_session_on_start"));
}
QJsonObject CoreConfig::toJson() const
@ -58,6 +60,7 @@ QJsonObject CoreConfig::toJson() const
obj[QStringLiteral("locale")] = m_locale;
obj[QStringLiteral("shortcuts")] = saveShortcuts();
obj[QStringLiteral("toolbar_icon_size")] = m_toolBarIconSize;
obj[QStringLiteral("recover_last_session_on_start")] = m_recoverLastSessionOnStartEnabled;
return obj;
}
@ -149,3 +152,13 @@ const QStringList &CoreConfig::getExternalNodeExcludePatterns() const
{
return m_externalNodeExcludePatterns;
}
bool CoreConfig::isRecoverLastSessionOnStartEnabled() const
{
return m_recoverLastSessionOnStartEnabled;
}
void CoreConfig::setRecoverLastSessionOnStartEnabled(bool p_enabled)
{
updateConfig(m_recoverLastSessionOnStartEnabled, p_enabled, this);
}

View File

@ -63,6 +63,9 @@ namespace vnotex
static const QStringList &getAvailableLocales();
bool isRecoverLastSessionOnStartEnabled() const;
void setRecoverLastSessionOnStartEnabled(bool p_enabled);
private:
void loadShortcuts(const QJsonObject &p_app, const QJsonObject &p_user);
@ -84,6 +87,9 @@ namespace vnotex
QStringList m_externalNodeExcludePatterns;
// Whether recover last session on start.
bool m_recoverLastSessionOnStartEnabled = true;
static QStringList s_availableLocales;
};
} // ns vnotex

View File

@ -26,6 +26,9 @@ namespace vnotex
// If m_lineNumber > -1, it indicates the line to scroll to after opening the file.
// 0-based.
int m_lineNumber = -1;
// Whether always open a new window for file.
bool m_alwaysNewWindow = false;
};
}

View File

@ -98,6 +98,9 @@ namespace vnotex
FocusPreview,
Invalid
};
enum { InvalidViewSplitId = 0 };
} // ns vnotex
Q_DECLARE_OPERATORS_FOR_FLAGS(vnotex::FindOptions);

View File

@ -154,9 +154,7 @@ namespace vnotex
}
template <typename T>
static void updateConfig(T &p_cur,
const T &p_new,
IConfig *p_config)
static void updateConfig(T &p_cur, const T &p_new, IConfig *p_config)
{
if (p_cur == p_new) {
return;
@ -167,6 +165,14 @@ namespace vnotex
p_config->writeToSettings();
}
template <typename T>
static void updateConfigWithoutCheck(T &p_cur, const T &p_new, IConfig *p_config)
{
++p_config->m_revision;
p_cur = p_new;
p_config->writeToSettings();
}
IConfig *m_topConfig = nullptr;
QString m_sessionName;

View File

@ -64,6 +64,8 @@ void SessionConfig::init()
m_exportOption.fromJson(sessionJobj[QStringLiteral("export_option")].toObject());
m_searchOption.fromJson(sessionJobj[QStringLiteral("search_option")].toObject());
m_viewAreaSession = readByteArray(sessionJobj, QStringLiteral("viewarea_session"));
}
void SessionConfig::loadCore(const QJsonObject &p_session)
@ -180,6 +182,7 @@ QJsonObject SessionConfig::toJson() const
obj[QStringLiteral("state_geometry")] = saveStateAndGeometry();
obj[QStringLiteral("export_option")] = m_exportOption.toJson();
obj[QStringLiteral("search_option")] = m_searchOption.toJson();
writeByteArray(obj, QStringLiteral("viewarea_session"), m_viewAreaSession);
return obj;
}
@ -308,3 +311,15 @@ void SessionConfig::loadStateAndGeometry(const QJsonObject &p_session)
m_mainWindowStateGeometry.m_mainState = readByteArray(obj, QStringLiteral("main_window_state"));
m_mainWindowStateGeometry.m_mainGeometry = readByteArray(obj, QStringLiteral("main_window_geometry"));
}
QByteArray SessionConfig::getViewAreaSessionAndClear()
{
QByteArray bytes;
m_viewAreaSession.swap(bytes);
return bytes;
}
void SessionConfig::setViewAreaSession(const QByteArray &p_bytes)
{
updateConfigWithoutCheck(m_viewAreaSession, p_bytes, this);
}

View File

@ -91,6 +91,9 @@ namespace vnotex
const SearchOption &getSearchOption() const;
void setSearchOption(const SearchOption &p_option);
QByteArray getViewAreaSessionAndClear();
void setViewAreaSession(const QByteArray &p_obj);
private:
void loadCore(const QJsonObject &p_session);
@ -129,6 +132,8 @@ namespace vnotex
ExportOption m_exportOption;
SearchOption m_searchOption;
QByteArray m_viewAreaSession;
};
} // ns vnotex

View File

@ -39,7 +39,8 @@
".git"
]
}
}
},
"recover_last_session_on_start" : true
},
"editor" : {
"core": {

View File

@ -69,6 +69,16 @@ void GeneralPage::setupUI()
this, &GeneralPage::pageIsChanged);
}
#endif
{
const QString label(tr("Recover last session on start"));
m_recoverLastSessionCheckBox = WidgetsFactory::createCheckBox(label, this);
m_recoverLastSessionCheckBox->setToolTip(tr("Recover last session (like buffers) on start of VNote"));
mainLayout->addRow(m_recoverLastSessionCheckBox);
addSearchItem(label, m_recoverLastSessionCheckBox->toolTip(), m_recoverLastSessionCheckBox);
connect(m_recoverLastSessionCheckBox, &QCheckBox::stateChanged,
this, &GeneralPage::pageIsChanged);
}
}
void GeneralPage::loadInternal()
@ -92,6 +102,8 @@ void GeneralPage::loadInternal()
int toTray = sessionConfig.getMinimizeToSystemTray();
m_systemTrayCheckBox->setChecked(toTray > 0);
}
m_recoverLastSessionCheckBox->setChecked(coreConfig.isRecoverLastSessionOnStartEnabled());
}
void GeneralPage::saveInternal()
@ -113,6 +125,8 @@ void GeneralPage::saveInternal()
// This will override the -1 state. That is fine.
sessionConfig.setMinimizeToSystemTray(m_systemTrayCheckBox->isChecked());
}
coreConfig.setRecoverLastSessionOnStartEnabled(m_recoverLastSessionCheckBox->isChecked());
}
QString GeneralPage::title() const

View File

@ -29,6 +29,8 @@ namespace vnotex
QComboBox *m_openGLComboBox = nullptr;
QCheckBox *m_systemTrayCheckBox = nullptr;
QCheckBox *m_recoverLastSessionCheckBox = nullptr;
};
}

View File

@ -145,8 +145,8 @@ QGroupBox *MarkdownEditorPage::setupReadGroup()
m_zoomFactorSpinBox = WidgetsFactory::createDoubleSpinBox(box);
m_zoomFactorSpinBox->setToolTip(tr("Zoom factor in read mode"));
m_zoomFactorSpinBox->setRange(0.25, 10);
m_zoomFactorSpinBox->setSingleStep(0.25);
m_zoomFactorSpinBox->setRange(0.1, 10);
m_zoomFactorSpinBox->setSingleStep(0.1);
const QString label(tr("Zoom factor:"));
layout->addRow(label, m_zoomFactorSpinBox);

View File

@ -360,8 +360,8 @@ void MarkdownViewer::handleWebKeyPress(int p_key, bool p_ctrl, bool p_shift, boo
void MarkdownViewer::zoomOut()
{
qreal factor = zoomFactor();
if (factor > 0.25) {
factor -= 0.25;
if (factor > 0.1) {
factor -= 0.1;
setZoomFactor(factor);
emit zoomFactorChanged(factor);
}
@ -370,7 +370,7 @@ void MarkdownViewer::zoomOut()
void MarkdownViewer::zoomIn()
{
qreal factor = zoomFactor();
factor += 0.25;
factor += 0.1;
setZoomFactor(factor);
emit zoomFactorChanged(factor);
}

View File

@ -935,3 +935,13 @@ void MarkdownViewWindow::openTwice(const QSharedPointer<FileOpenParameters> &p_p
Q_ASSERT(!p_paras || !p_paras->m_newFile);
handleFileOpenParameters(p_paras);
}
ViewWindowSession MarkdownViewWindow::saveSession() const
{
auto session = ViewWindow::saveSession();
if (getBuffer()) {
session.m_lineNumber = isReadMode() ? adapter()->getTopLineNumber()
: m_editor->getCursorPosition().first;
}
return session;
}

View File

@ -42,6 +42,8 @@ namespace vnotex
void openTwice(const QSharedPointer<FileOpenParameters> &p_paras) Q_DECL_OVERRIDE;
ViewWindowSession saveSession() const Q_DECL_OVERRIDE;
public slots:
void handleEditorConfigChange() Q_DECL_OVERRIDE;

View File

@ -244,3 +244,12 @@ void TextViewWindow::handleFileOpenParameters(const QSharedPointer<FileOpenParam
m_editor->scrollToLine(p_paras->m_lineNumber, true);
}
}
ViewWindowSession TextViewWindow::saveSession() const
{
auto session = ViewWindow::saveSession();
if (getBuffer()) {
session.m_lineNumber = m_editor->getCursorPosition().first;
}
return session;
}

View File

@ -29,6 +29,8 @@ namespace vnotex
void openTwice(const QSharedPointer<FileOpenParameters> &p_paras) Q_DECL_OVERRIDE;
ViewWindowSession saveSession() const Q_DECL_OVERRIDE;
public slots:
void handleEditorConfigChange() Q_DECL_OVERRIDE;

View File

@ -11,6 +11,7 @@
#include <QTimer>
#include <QApplication>
#include <QSet>
#include <QHash>
#include "viewwindow.h"
#include "mainwindow.h"
@ -21,6 +22,7 @@
#include <core/vnotex.h>
#include <core/configmgr.h>
#include <core/coreconfig.h>
#include <core/sessionconfig.h>
#include <core/fileopenparameters.h>
#include <notebook/node.h>
#include <notebook/notebook.h>
@ -47,7 +49,9 @@ ViewArea::ViewArea(QWidget *p_parent)
return;
}
// TODO: save last opened files.
if (ConfigMgr::getInst().getCoreConfig().isRecoverLastSessionOnStartEnabled()) {
saveSession();
}
bool ret = close(false);
if (!ret) {
@ -61,6 +65,11 @@ ViewArea::ViewArea(QWidget *p_parent)
close(true);
});
if (ConfigMgr::getInst().getCoreConfig().isRecoverLastSessionOnStartEnabled()) {
connect(mainWindow, &MainWindow::mainWindowStarted,
this, &ViewArea::loadSession);
}
connect(&VNoteX::getInst(), &VNoteX::nodeAboutToMove,
this, &ViewArea::handleNodeChange);
@ -127,8 +136,6 @@ void ViewArea::setupUI()
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setContentsMargins(0, 0, 0, 0);
showSceneWidget();
}
QSize ViewArea::sizeHint() const
@ -145,7 +152,10 @@ QSize ViewArea::sizeHint() const
void ViewArea::openBuffer(Buffer *p_buffer, const QSharedPointer<FileOpenParameters> &p_paras)
{
// We allow multiple ViewWindows of the same buffer in different workspaces by default.
auto wins = findBufferInViewSplits(p_buffer);
QVector<ViewWindow *> wins;
if (!p_paras->m_alwaysNewWindow) {
wins = findBufferInViewSplits(p_buffer);
}
if (wins.isEmpty()) {
if (!m_currentSplit) {
addFirstViewSplit();
@ -193,12 +203,20 @@ QVector<ViewWindow *> ViewArea::findBufferInViewSplits(const Buffer *p_buffer) c
return wins;
}
ViewSplit *ViewArea::createViewSplit(QWidget *p_parent)
ViewSplit *ViewArea::createViewSplit(QWidget *p_parent, ID p_viewSplitId)
{
auto workspace = createWorkspace();
m_workspaces.push_back(workspace);
auto split = new ViewSplit(m_workspaces, workspace, p_parent);
ID id = p_viewSplitId;
if (id == InvalidViewSplitId) {
id = m_nextViewSplitId++;
} else {
Q_ASSERT(p_viewSplitId >= m_nextViewSplitId);
m_nextViewSplitId = id + 1;
}
auto split = new ViewSplit(m_workspaces, workspace, id, p_parent);
connect(split, &ViewSplit::viewWindowCloseRequested,
this, [this](ViewWindow *p_win) {
closeViewWindow(p_win, false, true);
@ -282,7 +300,13 @@ void ViewArea::addFirstViewSplit()
hideSceneWidget();
m_mainLayout->addWidget(split);
setCurrentViewSplit(split, false);
postFirstViewSplit();
}
void ViewArea::postFirstViewSplit()
{
Q_ASSERT(!m_splits.isEmpty());
setCurrentViewSplit(m_splits.first(), false);
emit viewSplitsCountChanged();
checkCurrentViewWindowChange();
@ -446,7 +470,7 @@ QSharedPointer<ViewWorkspace> ViewArea::createWorkspace()
ID id = 1;
QSet<ID> usedIds;
for (auto ws : m_workspaces) {
usedIds.insert(ws->c_id);
usedIds.insert(ws->m_id);
}
while (true) {
@ -996,3 +1020,185 @@ QList<Buffer *> ViewArea::getAllBuffersInViewSplits() const
return bufferSet.values();
}
void ViewArea::loadSession()
{
auto &sessionConfig = ConfigMgr::getInst().getSessionConfig();
auto sessionData = sessionConfig.getViewAreaSessionAndClear();
auto session = ViewAreaSession::deserialize(sessionData);
// Load widgets layout.
if (session.m_root.isEmpty()) {
showSceneWidget();
} else {
Q_ASSERT(m_splits.isEmpty());
if (session.m_root.m_type == ViewAreaSession::Node::Type::Splitter) {
// Splitter.
auto splitter = createSplitter(session.m_root.m_orientation, this);
m_mainLayout->addWidget(splitter);
loadSplitterFromSession(session.m_root, splitter);
} else {
// Just only one ViewSplit.
Q_ASSERT(session.m_root.m_type == ViewAreaSession::Node::Type::ViewSplit);
auto split = createViewSplit(this, session.m_root.m_viewSplitId);
m_splits.push_back(split);
m_mainLayout->addWidget(split);
}
QHash<ID, int> viewSplitToWorkspace;
setCurrentViewSplit(m_splits.first(), false);
// Load invisible workspace.
for (int i = 0; i < session.m_workspaces.size(); ++i) {
const auto &ws = session.m_workspaces[i];
if (ws.m_viewSplitId != InvalidViewSplitId) {
viewSplitToWorkspace.insert(ws.m_viewSplitId, i);
continue;
}
for (const auto &winSession : ws.m_viewWindows) {
openViewWindowFromSession(winSession);
}
// Check if there is any window.
if (m_currentSplit->getViewWindowCount() > 0) {
m_currentSplit->setCurrentViewWindow(ws.m_currentViewWindowIndex);
// New another workspace.
auto newWs = createWorkspace();
m_workspaces.push_back(newWs);
m_currentSplit->setWorkspace(newWs);
}
}
// Load visible workspace.
for (auto split : m_splits) {
setCurrentViewSplit(split, false);
auto it = viewSplitToWorkspace.find(split->getId());
Q_ASSERT(it != viewSplitToWorkspace.end());
const auto &ws = session.m_workspaces[it.value()];
for (const auto &winSession : ws.m_viewWindows) {
openViewWindowFromSession(winSession);
}
if (m_currentSplit->getViewWindowCount() > 0) {
m_currentSplit->setCurrentViewWindow(ws.m_currentViewWindowIndex);
}
}
postFirstViewSplit();
distributeViewSplits();
}
}
void ViewArea::saveSession() const
{
ViewAreaSession session;
takeSnapshot(session);
auto &sessionConfig = ConfigMgr::getInst().getSessionConfig();
sessionConfig.setViewAreaSession(session.serialize());
}
static void takeSnapshotOfWidgetNodes(ViewAreaSession::Node &p_node, const QWidget *p_widget, QHash<ID, ID> &p_workspaceToViewSplit)
{
p_node.clear();
// Splitter.
auto splitter = dynamic_cast<const QSplitter *>(p_widget);
if (splitter) {
p_node.m_type = ViewAreaSession::Node::Type::Splitter;
p_node.m_orientation = splitter->orientation();
p_node.m_children.resize(splitter->count());
for (int i = 0; i < p_node.m_children.size(); ++i) {
takeSnapshotOfWidgetNodes(p_node.m_children[i], splitter->widget(i), p_workspaceToViewSplit);
}
return;
}
// ViewSplit.
auto viewSplit = dynamic_cast<const ViewSplit *>(p_widget);
Q_ASSERT(viewSplit);
p_node.m_type = ViewAreaSession::Node::Type::ViewSplit;
p_node.m_viewSplitId = viewSplit->getId();
auto ws = viewSplit->getWorkspace();
if (ws) {
viewSplit->updateStateToWorkspace();
p_workspaceToViewSplit.insert(ws->m_id, viewSplit->getId());
}
}
void ViewArea::takeSnapshot(ViewAreaSession &p_session) const
{
QHash<ID, ID> workspaceToViewSplit;
// Widget hirarchy.
p_session.m_root.clear();
if (!m_splits.isEmpty()) {
auto topWidget = m_mainLayout->itemAt(0)->widget();
takeSnapshotOfWidgetNodes(p_session.m_root, topWidget, workspaceToViewSplit);
}
// Workspaces.
p_session.m_workspaces.clear();
p_session.m_workspaces.reserve(m_workspaces.size());
for (const auto &ws : m_workspaces) {
p_session.m_workspaces.push_back(ViewAreaSession::Workspace());
auto &wsSnap = p_session.m_workspaces.last();
if (ws->m_visible) {
auto it = workspaceToViewSplit.find(ws->m_id);
Q_ASSERT(it != workspaceToViewSplit.end());
wsSnap.m_viewSplitId = it.value();
}
wsSnap.m_currentViewWindowIndex = ws->m_currentViewWindowIndex;
for (auto win : ws->m_viewWindows) {
wsSnap.m_viewWindows.push_back(win->saveSession());
}
}
}
void ViewArea::loadSplitterFromSession(const ViewAreaSession::Node &p_node, QSplitter *p_splitter)
{
// @p_splitter is the splitter corresponding to @p_node.
Q_ASSERT(p_node.m_type == ViewAreaSession::Node::Type::Splitter);
for (const auto &child : p_node.m_children) {
if (child.m_type == ViewAreaSession::Node::Type::Splitter) {
auto childSplitter = createSplitter(child.m_orientation, p_splitter);
p_splitter->addWidget(childSplitter);
loadSplitterFromSession(child, childSplitter);
} else {
Q_ASSERT(child.m_type == ViewAreaSession::Node::Type::ViewSplit);
auto childSplit = createViewSplit(this, child.m_viewSplitId);
m_splits.push_back(childSplit);
p_splitter->addWidget(childSplit);
}
}
}
void ViewArea::openViewWindowFromSession(const ViewWindowSession &p_session)
{
if (p_session.m_bufferPath.isEmpty()) {
return;
}
auto paras = QSharedPointer<FileOpenParameters>::create();
paras->m_mode = p_session.m_viewWindowMode;
paras->m_readOnly = p_session.m_readOnly;
paras->m_lineNumber = p_session.m_lineNumber;
paras->m_alwaysNewWindow = true;
emit VNoteX::getInst().openFileRequested(p_session.m_bufferPath, paras);
}

View File

@ -10,6 +10,7 @@
#include "global.h"
#include "navigationmode.h"
#include "viewsplit.h"
#include "viewareasession.h"
class QLayout;
class QSplitter;
@ -29,7 +30,7 @@ namespace vnotex
struct ViewWorkspace
{
explicit ViewWorkspace(ID p_id)
: c_id(p_id)
: m_id(p_id)
{
}
@ -45,7 +46,7 @@ namespace vnotex
m_currentViewWindowIndex = 0;
}
const ID c_id = 0;
const ID m_id = 0;
// Whether it is displayed by a ViewSplit now.
bool m_visible = false;
@ -132,6 +133,10 @@ namespace vnotex
void handleNodeChange(Node *p_node, const QSharedPointer<Event> &p_event);
void loadSession();
void saveSession() const;
private:
enum class SplitType
{
@ -145,7 +150,7 @@ namespace vnotex
// Does not search invisible work spaces.
QVector<ViewWindow *> findBufferInViewSplits(const Buffer *p_buffer) const;
ViewSplit *createViewSplit(QWidget *p_parent);
ViewSplit *createViewSplit(QWidget *p_parent, ID p_viewSplitId = InvalidViewSplitId);
// A Scene widget will be used when there is no split.
// Usually it is used to show some help message.
@ -205,6 +210,14 @@ namespace vnotex
QVector<ViewWindow *> getAllViewWindows(ViewSplit *p_split) const;
void takeSnapshot(ViewAreaSession &p_session) const;
void postFirstViewSplit();
void loadSplitterFromSession(const ViewAreaSession::Node &p_node, QSplitter *p_splitter);
void openViewWindowFromSession(const ViewWindowSession &p_session);
QLayout *m_mainLayout = nullptr;
QWidget *m_sceneWidget = nullptr;
@ -226,6 +239,8 @@ namespace vnotex
// Timer to check file change outside periodically.
QTimer *m_fileCheckTimer = nullptr;
ID m_nextViewSplitId = InvalidViewSplitId + 1;
};
} // ns vnotex

View File

@ -0,0 +1,101 @@
#include "viewareasession.h"
#include <QIODevice>
#include <QDebug>
#include <QSplitter>
#include <QLayout>
using namespace vnotex;
QDataStream &::vnotex::operator<<(QDataStream &p_ds, const ViewAreaSession::Node &p_node)
{
p_ds << static_cast<qint8>(p_node.m_type);
p_ds << static_cast<qint8>(p_node.m_orientation);
p_ds << p_node.m_viewSplitId;
p_ds << p_node.m_children;
return p_ds;
}
QDataStream &::vnotex::operator>>(QDataStream &p_ds, ViewAreaSession::Node &p_node)
{
qint8 tmp = 0;
p_ds >> tmp;
p_node.m_type = static_cast<ViewAreaSession::Node::Type>(tmp);
p_ds >> tmp;
p_node.m_orientation = static_cast<Qt::Orientation>(tmp);
p_ds >> p_node.m_viewSplitId;
p_ds >> p_node.m_children;
return p_ds;
}
QDataStream &::vnotex::operator<<(QDataStream &p_ds, const ViewAreaSession::Workspace &p_workspace)
{
p_ds << p_workspace.m_viewSplitId;
p_ds << p_workspace.m_viewWindows;
p_ds << static_cast<qint32>(p_workspace.m_currentViewWindowIndex);
return p_ds;
}
QDataStream &::vnotex::operator>>(QDataStream &p_ds, ViewAreaSession::Workspace &p_workspace)
{
p_ds >> p_workspace.m_viewSplitId;
p_ds >> p_workspace.m_viewWindows;
{
qint32 tmp = 0;
p_ds >> tmp;
p_workspace.m_currentViewWindowIndex = tmp;
}
return p_ds;
}
void ViewAreaSession::Node::clear()
{
m_type = Type::Empty;
m_orientation = Qt::Horizontal;
m_viewSplitId = InvalidViewSplitId;
m_children.clear();
}
bool ViewAreaSession::Node::isEmpty() const
{
return m_type == Type::Empty;
}
QByteArray ViewAreaSession::serialize() const
{
QByteArray data;
QDataStream outs(&data, QIODevice::WriteOnly);
outs.setVersion(QDataStream::Qt_5_12);
outs << m_root;
outs << m_workspaces;
return data;
}
ViewAreaSession ViewAreaSession::deserialize(const QByteArray &p_data)
{
ViewAreaSession session;
if (p_data.isEmpty()) {
return session;
}
QDataStream ins(p_data);
ins.setVersion(QDataStream::Qt_5_12);
ins >> session.m_root;
ins >> session.m_workspaces;
return session;
}

View File

@ -0,0 +1,66 @@
#ifndef VIEWAREASESSION_H
#define VIEWAREASESSION_H
#include <QVector>
#include <QDataStream>
#include <QHash>
#include <core/global.h>
#include "viewwindowsession.h"
namespace vnotex
{
struct ViewAreaSession
{
// A node for splitter and ViewSplit hirarchy.
struct Node
{
enum Type
{
Splitter,
ViewSplit,
Empty
};
void clear();
bool isEmpty() const;
Type m_type = Type::Empty;
Qt::Orientation m_orientation = Qt::Horizontal;
ID m_viewSplitId = InvalidViewSplitId;
QVector<Node> m_children;
};
struct Workspace
{
ID m_viewSplitId = InvalidViewSplitId;
QVector<ViewWindowSession> m_viewWindows;
int m_currentViewWindowIndex = 0;
};
QByteArray serialize() const;
static ViewAreaSession deserialize(const QByteArray &p_data);
Node m_root;
QVector<Workspace> m_workspaces;
};
extern QDataStream &operator<<(QDataStream &p_ds, const ViewAreaSession::Node &p_node);
extern QDataStream &operator>>(QDataStream &p_ds, ViewAreaSession::Node &p_node);
extern QDataStream &operator<<(QDataStream &p_ds, const ViewAreaSession::Workspace &p_workspace);
extern QDataStream &operator>>(QDataStream &p_ds, ViewAreaSession::Workspace &p_workspace);
}
#endif // VIEWAREASESSION_H

View File

@ -42,8 +42,10 @@ const QString ViewSplit::c_actionButtonForegroundName = "widgets#viewsplit#actio
ViewSplit::ViewSplit(const QVector<QSharedPointer<ViewWorkspace>> &p_allWorkspaces,
const QSharedPointer<ViewWorkspace> &p_workspace,
ID p_id,
QWidget *p_parent)
: QTabWidget(p_parent),
m_id(p_id),
m_allWorkspaces(p_allWorkspaces)
{
setAcceptDrops(true);
@ -258,17 +260,12 @@ void ViewSplit::setWorkspace(const QSharedPointer<ViewWorkspace> &p_workspace)
void ViewSplit::updateAndTakeCurrentWorkspace()
{
if (m_workspace) {
// Store current workspace.
m_workspace->m_currentViewWindowIndex = currentIndex();
updateStateToWorkspace();
// Take all the view windows out.
int cnt = getViewWindowCount();
m_workspace->m_viewWindows.resize(cnt);
for (int i = cnt - 1; i >= 0; --i) {
auto window = getViewWindow(i);
takeViewWindow(window);
m_workspace->m_viewWindows[i] = window;
takeViewWindow(getViewWindow(i));
}
m_workspace->m_visible = false;
@ -279,6 +276,23 @@ void ViewSplit::updateAndTakeCurrentWorkspace()
}
}
void ViewSplit::updateStateToWorkspace() const
{
if (!m_workspace) {
return;
}
Q_ASSERT(m_workspace->m_visible);
m_workspace->m_currentViewWindowIndex = currentIndex();
int cnt = getViewWindowCount();
m_workspace->m_viewWindows.resize(cnt);
for (int i = cnt - 1; i >= 0; --i) {
m_workspace->m_viewWindows[i] = getViewWindow(i);
}
}
QVector<ViewWindow *> ViewSplit::findBuffer(const Buffer *p_buffer) const
{
QVector<ViewWindow *> wins;
@ -441,7 +455,7 @@ void ViewSplit::updateMenu(QMenu *p_menu)
}
for (int i = 0; i < m_allWorkspaces.size(); ++i) {
auto act = new QAction(tr("Workspace %1").arg(m_allWorkspaces[i]->c_id),
auto act = new QAction(tr("Workspace %1").arg(m_allWorkspaces[i]->m_id),
m_workspaceActionGroup);
act->setData(i);
act->setCheckable(true);
@ -735,3 +749,14 @@ void ViewSplit::focus()
{
focusCurrentViewWindow();
}
ID ViewSplit::getId() const
{
return m_id;
}
void ViewSplit::setCurrentViewWindow(int p_idx)
{
auto win = getViewWindow(p_idx);
setCurrentViewWindow(win);
}

View File

@ -30,9 +30,10 @@ namespace vnotex
ViewWindow *m_viewWindow = nullptr;
};
explicit ViewSplit(const QVector<QSharedPointer<ViewWorkspace>> &p_allWorkspaces,
const QSharedPointer<ViewWorkspace> &p_workspace,
QWidget *p_parent = nullptr);
ViewSplit(const QVector<QSharedPointer<ViewWorkspace>> &p_allWorkspaces,
const QSharedPointer<ViewWorkspace> &p_workspace,
ID p_id,
QWidget *p_parent = nullptr);
~ViewSplit();
@ -45,6 +46,8 @@ namespace vnotex
ViewWindow *getCurrentViewWindow() const;
void setCurrentViewWindow(ViewWindow *p_win);
void setCurrentViewWindow(int p_idx);
// @p_win is not deleted.
void takeViewWindow(ViewWindow *p_win);
@ -62,6 +65,10 @@ namespace vnotex
void focus();
ID getId() const;
void updateStateToWorkspace() const;
signals:
void viewWindowCloseRequested(ViewWindow *p_win);
@ -122,6 +129,8 @@ namespace vnotex
void focusCurrentViewWindow();
ID m_id = 0;
const QVector<QSharedPointer<ViewWorkspace>> &m_allWorkspaces;
QSharedPointer<ViewWorkspace> m_workspace;

View File

@ -1079,3 +1079,14 @@ QToolBar *ViewWindow::createToolBar(QWidget *p_parent)
toolBar->setProperty(PropertyDefs::c_viewWindowToolBar, true);
return toolBar;
}
ViewWindowSession ViewWindow::saveSession() const
{
ViewWindowSession session;
if (m_buffer) {
session.m_bufferPath = m_buffer->getPath();
session.m_readOnly = m_buffer->isReadOnly();
}
session.m_viewWindowMode = getMode();
return session;
}

View File

@ -9,6 +9,7 @@
#include <core/global.h>
#include "viewwindowtoolbarhelper.h"
#include "viewwindowsession.h"
class QVBoxLayout;
class QTimer;
@ -71,6 +72,8 @@ namespace vnotex
// Called by upside.
void checkFileMissingOrChangedOutsidePeriodically();
virtual ViewWindowSession saveSession() const;
public slots:
virtual void handleEditorConfigChange() = 0;

View File

@ -0,0 +1,33 @@
#include "viewwindowsession.h"
using namespace vnotex;
QDataStream &::vnotex::operator<<(QDataStream &p_ds, const ViewWindowSession &p_session)
{
p_ds << p_session.m_bufferPath;
p_ds << static_cast<qint8>(p_session.m_readOnly);
p_ds << static_cast<qint8>(p_session.m_viewWindowMode);
p_ds << static_cast<qint32>(p_session.m_lineNumber);
return p_ds;
}
QDataStream &::vnotex::operator>>(QDataStream &p_ds, ViewWindowSession &p_session)
{
p_ds >> p_session.m_bufferPath;
qint8 tmp8 = 0;
p_ds >> tmp8;
p_session.m_readOnly = tmp8 > 0;
p_ds >> tmp8;
p_session.m_viewWindowMode = static_cast<ViewWindowMode>(tmp8);
{
qint32 tmp = 0;
p_ds >> tmp;
p_session.m_lineNumber = static_cast<int>(tmp);
}
return p_ds;
}

View File

@ -0,0 +1,26 @@
#ifndef VIEWWINDOWSESSION_H
#define VIEWWINDOWSESSION_H
#include <QDataStream>
#include <core/global.h>
namespace vnotex
{
struct ViewWindowSession
{
QString m_bufferPath;
bool m_readOnly = false;
ViewWindowMode m_viewWindowMode = ViewWindowMode::Read;
// 0-based.
int m_lineNumber = -1;
};
extern QDataStream &operator<<(QDataStream &p_ds, const ViewWindowSession &p_session);
extern QDataStream &operator>>(QDataStream &p_ds, ViewWindowSession &p_session);
}
#endif // VIEWWINDOWSESSION_H

View File

@ -57,8 +57,10 @@ SOURCES += \
$$PWD/textviewwindow.cpp \
$$PWD/toolbarhelper.cpp \
$$PWD/treeview.cpp \
$$PWD/viewareasession.cpp \
$$PWD/viewsplit.cpp \
$$PWD/viewwindow.cpp \
$$PWD/viewwindowsession.cpp \
$$PWD/viewwindowtoolbarhelper.cpp \
$$PWD/webpage.cpp \
$$PWD/webviewer.cpp \
@ -149,8 +151,10 @@ HEADERS += \
$$PWD/textviewwindowhelper.h \
$$PWD/toolbarhelper.h \
$$PWD/treeview.h \
$$PWD/viewareasession.h \
$$PWD/viewsplit.h \
$$PWD/viewwindow.h \
$$PWD/viewwindowsession.h \
$$PWD/viewwindowtoolbarhelper.h \
$$PWD/webpage.h \
$$PWD/webviewer.h \