mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
ViewArea session (#1762)
This commit is contained in:
parent
6cd666552d
commit
1843ca5bfd
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,9 @@ namespace vnotex
|
||||
FocusPreview,
|
||||
Invalid
|
||||
};
|
||||
|
||||
enum { InvalidViewSplitId = 0 };
|
||||
|
||||
} // ns vnotex
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(vnotex::FindOptions);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -39,7 +39,8 @@
|
||||
".git"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"recover_last_session_on_start" : true
|
||||
},
|
||||
"editor" : {
|
||||
"core": {
|
||||
|
@ -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
|
||||
|
@ -29,6 +29,8 @@ namespace vnotex
|
||||
QComboBox *m_openGLComboBox = nullptr;
|
||||
|
||||
QCheckBox *m_systemTrayCheckBox = nullptr;
|
||||
|
||||
QCheckBox *m_recoverLastSessionCheckBox = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
101
src/widgets/viewareasession.cpp
Normal file
101
src/widgets/viewareasession.cpp
Normal 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;
|
||||
}
|
66
src/widgets/viewareasession.h
Normal file
66
src/widgets/viewareasession.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
33
src/widgets/viewwindowsession.cpp
Normal file
33
src/widgets/viewwindowsession.cpp
Normal 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;
|
||||
}
|
26
src/widgets/viewwindowsession.h
Normal file
26
src/widgets/viewwindowsession.h
Normal 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
|
@ -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 \
|
||||
|
Loading…
x
Reference in New Issue
Block a user