|
|
@@ -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);
|
|
|
+}
|