Skip to content

Commit

Permalink
feat: [session] add session manager to save/restore workspace state
Browse files Browse the repository at this point in the history
Implement session management functionality to persist and restore workspace
state across IDE sessions. This includes:

- Add SessionManager class to handle session operations
- Save/restore opened files and current file in editor
- Save/restore breakpoints with conditions in debugger
- Save/restore project list and active project
- Add session events for coordination between components
- Integrate session loading/saving with core components

The session manager provides a centralized way to persist workspace state
and restore it when reopening projects.

Log: add session manager to save and restore workspace state
  • Loading branch information
Kakueeen committed Nov 25, 2024
1 parent 0fc225d commit d18fba9
Show file tree
Hide file tree
Showing 59 changed files with 2,494 additions and 333 deletions.
4 changes: 2 additions & 2 deletions src/common/settings/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ bool Settings::contains(const QString &group, const QString &key) const
return d->defaultData.values.value(group).contains(key);
}

QVariant Settings::value(const QString &group, const QString &key, const QVariant &defaultValue)
QVariant Settings::value(const QString &group, const QString &key, const QVariant &defaultValue) const
{
auto value = d->settingData.value(group, key, QVariant::Invalid);
if (value.isValid())
Expand All @@ -199,7 +199,7 @@ QVariant Settings::value(const QString &group, const QString &key, const QVarian
return d->defaultData.value(group, key, defaultValue);
}

QVariant Settings::defaultValue(const QString &group, const QString &key, const QVariant &defaultValue)
QVariant Settings::defaultValue(const QString &group, const QString &key, const QVariant &defaultValue) const
{
return d->defaultData.value(group, key, defaultValue);
}
Expand Down
4 changes: 2 additions & 2 deletions src/common/settings/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class Settings : public QObject
QStringList groupList() const;
QStringList keyList(const QString &group) const;
bool contains(const QString &group, const QString &key) const;
QVariant value(const QString &group, const QString &key, const QVariant &defaultValue = QVariant());
QVariant defaultValue(const QString &group, const QString &key, const QVariant &defaultValue = QVariant());
QVariant value(const QString &group, const QString &key, const QVariant &defaultValue = QVariant()) const;
QVariant defaultValue(const QString &group, const QString &key, const QVariant &defaultValue = QVariant()) const;
void setValue(const QString &group, const QString &key, const QVariant &value, bool notify = false);
void removeGroup(const QString &group);
void remove(const QString &group, const QString &key);
Expand Down
7 changes: 7 additions & 0 deletions src/common/util/eventdefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ OPI_OBJECT(workspace,
OPI_INTERFACE(expandAll)
OPI_INTERFACE(foldAll)
)
OPI_OBJECT(session,
OPI_INTERFACE(readyToSaveSession)
OPI_INTERFACE(sessionLoaded, "session")
OPI_INTERFACE(sessionCreated, "session")
OPI_INTERFACE(sessionRenamed, "oldName", "newName")
OPI_INTERFACE(sessionRemoved, "session")
)

struct AnalysedData
{
Expand Down
1 change: 0 additions & 1 deletion src/plugins/codeeditor/gui/private/tabbar_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class TabBarPrivate : public QObject
void updateBackgroundColor();
bool isModified(int index) const;
int showConfirmDialog(const QString &filePath);
void closeAllTab(const QStringList &exceptList);

public slots:
void onCurrentTabChanged(int index);
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/codeeditor/gui/private/workspacewidget_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "base/abstracteditwidget.h"
#include "common/util/eventdefinitions.h"
#include "services/window/windowservice.h"
#include "services/session/sessionservice.h"
#include "Qsci/qscicommand.h"

#include <QStackedWidget>
Expand Down Expand Up @@ -64,6 +65,8 @@ public slots:
void handleSetModifiedAutoReload(const QString &fileName, bool flag);
void handleSetComment();
void handleShowOpenedFiles();
void handleSaveSession();
void handleSessionLoaded();

public:
WorkspaceWidget *q;
Expand All @@ -78,6 +81,8 @@ public slots:
QStringList modifiedFileList;
QStringList removedFileList;
QTimer fileCheckTimer;

dpfservice::SessionService *sessionSrv { nullptr };
};

#endif // WORKSPACEWIDGET_P_H
45 changes: 18 additions & 27 deletions src/plugins/codeeditor/gui/tabbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,29 +81,6 @@ int TabBarPrivate::showConfirmDialog(const QString &filePath)
return dialog.exec();
}

void TabBarPrivate::closeAllTab(const QStringList &exceptList)
{
QStringList tabList;
for (int i = 0; i < tabBar->count(); ++i) {
auto file = tabBar->tabToolTip(i);
if (exceptList.contains(file))
continue;

if (isModified(i)) {
int ret = showConfirmDialog(file);
if (ret == 0) // save
emit q->saveFileRequested(file);
else if (ret == 2 || ret == -1) // cancel or close
return;
}

tabList << file;
}

for (const auto &tab : tabList)
q->removeTab(tab, true);
}

void TabBarPrivate::initConnection()
{
connect(tabBar, &DTabBar::currentChanged, this, &TabBarPrivate::onCurrentTabChanged);
Expand Down Expand Up @@ -149,12 +126,12 @@ void TabBarPrivate::showMenu(QPoint pos)
q->removeTab(file);
});
menu.addAction(tr("Close All Files"), [=]() {
closeAllTab({});
q->closeAllTab({});
});
menu.addAction(tr("Close All Files Except This"), [=]() {
auto curFile = tabBar->tabToolTip(curIndex);
QStringList exceptList { curFile };
closeAllTab(exceptList);
q->closeAllTab(exceptList);
});

menu.addSeparator();
Expand Down Expand Up @@ -248,8 +225,7 @@ void TabBar::removeTab(const QString &fileName, bool silent)
if (-1 == index)
return;

QFileInfo info(fileName);
if (!silent && info.exists() && d->isModified(index)) {
if (!silent && QFile::exists(fileName) && d->isModified(index)) {
int ret = d->showConfirmDialog(fileName);
if (ret == 0) // save
emit saveFileRequested(fileName);
Expand All @@ -263,6 +239,21 @@ void TabBar::removeTab(const QString &fileName, bool silent)
editor.switchedFile(this->currentFileName());
}

void TabBar::closeAllTab(const QStringList &exceptList, bool silent)
{
QStringList tabList;
for (int i = 0; i < d->tabBar->count(); ++i) {
auto file = d->tabBar->tabToolTip(i);
if (exceptList.contains(file))
continue;

tabList << file;
}

for (const auto &tab : tabList)
removeTab(tab, silent);
}

void TabBar::setCloseButtonVisible(bool visible)
{
d->closeBtn->setVisible(visible);
Expand Down
1 change: 1 addition & 0 deletions src/plugins/codeeditor/gui/tabbar.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class TabBar : public QWidget

void switchTab(const QString &fileName);
void removeTab(const QString &fileName, bool silent = false);
void closeAllTab(const QStringList &exceptList, bool silent = false);

void setCloseButtonVisible(bool visible);
void setSplitButtonVisible(bool visible);
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/codeeditor/gui/tabwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,11 @@ void TabWidget::closeFileEditor()
closeFileEditor(editor->getFile());
}

void TabWidget::closeAllEditor()
{
d->tabBar->closeAllTab({}, true);
}

void TabWidget::switchHeaderSource()
{
auto editor = d->currentTextEditor();
Expand Down
1 change: 1 addition & 0 deletions src/plugins/codeeditor/gui/tabwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class TabWidget : public QWidget
void setFileModified(const QString &fileName, bool isModified);
void closeFileEditor(const QString &fileName);
void closeFileEditor();
void closeAllEditor();
void switchHeaderSource();
void followSymbolUnderCursor();
void findUsage();
Expand Down
45 changes: 38 additions & 7 deletions src/plugins/codeeditor/gui/workspacewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
#include <QApplication>
#include <QFileDialog>

constexpr char TextEditorContext[] { "Text Editor" };
constexpr char kTextEditorContext[] { "Text Editor" };
constexpr char kOpenedFileList[] { "OpenFileList" };
constexpr char kCurrentFile[] { "CurrentFile" };

using namespace dpfservice;
DWIDGET_USE_NAMESPACE
Expand All @@ -27,6 +29,7 @@ WorkspaceWidgetPrivate::WorkspaceWidgetPrivate(WorkspaceWidget *qq)
: QObject(qq),
q(qq)
{
sessionSrv = dpfGetService(SessionService);
fileCheckTimer.setInterval(500);
fileCheckTimer.setSingleShot(true);
}
Expand Down Expand Up @@ -69,13 +72,13 @@ void WorkspaceWidgetPrivate::initActions()

// add/del comment
QAction *commentAction = new QAction(tr("Add/Delete Comment"), q);
auto cmd = ActionManager::instance()->registerAction(commentAction, "TextEditor.AddAndRemoveComment", { TextEditorContext });
auto cmd = ActionManager::instance()->registerAction(commentAction, "TextEditor.AddAndRemoveComment", { kTextEditorContext });
cmd->setDefaultKeySequence(Qt::CTRL | Qt::Key_Slash);
connect(commentAction, &QAction::triggered, this, &WorkspaceWidgetPrivate::handleSetComment);

// show opened files
QAction *showOpenedAction = new QAction(tr("Show opened files"), q);
cmd = ActionManager::instance()->registerAction(showOpenedAction, "TextEditor.ShowOpenedFiles", { TextEditorContext });
cmd = ActionManager::instance()->registerAction(showOpenedAction, "TextEditor.ShowOpenedFiles", { kTextEditorContext });
cmd->setDefaultKeySequence(Qt::CTRL | Qt::Key_Tab);
connect(showOpenedAction, &QAction::triggered, this, &WorkspaceWidgetPrivate::handleShowOpenedFiles);

Expand Down Expand Up @@ -438,7 +441,7 @@ void WorkspaceWidgetPrivate::initActions()
if (!actionText.isEmpty()) {
auto id = QString("TextEditor.%1").arg(me.valueToKey(val));
auto act = new QAction(actionText, q);
auto cmd = ActionManager::instance()->registerAction(act, id, { TextEditorContext });
auto cmd = ActionManager::instance()->registerAction(act, id, { kTextEditorContext });
if (!ksList.isEmpty())
cmd->setDefaultKeySequences(ksList);
connect(act, &QAction::triggered, this, [val, this] {
Expand Down Expand Up @@ -469,6 +472,32 @@ void WorkspaceWidgetPrivate::handleShowOpenedFiles()
currentTabWidget()->handleShowOpenedFiles(q->pos().x() - q->mapFromGlobal(q->pos()).x(), q->pos().y() + q->mapToGlobal(q->pos()).y() - 100, q->size());
}

void WorkspaceWidgetPrivate::handleSaveSession()
{
sessionSrv->setValue(kOpenedFileList, q->openedFiles());
sessionSrv->setValue(kCurrentFile, q->currentFile());
}

void WorkspaceWidgetPrivate::handleSessionLoaded()
{
while (tabWidgetList.size() > 1) {
auto tabWidget = tabWidgetList.takeLast();
tabWidget->deleteLater();
}

tabWidgetList.first()->closeAllEditor();
focusTabWidget = tabWidgetList.first();
auto symbolWidget = SymbolWidgetGenerator::instance()->symbolWidget();
symbolWidget->setEditor(nullptr);

const auto &openedFiles = sessionSrv->value(kOpenedFileList).toStringList();
const auto &currentFile = sessionSrv->value(kCurrentFile).toString();
for (const auto &file : openedFiles)
handleOpenFile("", file);
if (!currentFile.isEmpty())
handleOpenFile("", currentFile);
}

void WorkspaceWidgetPrivate::initConnection()
{
connect(&fileCheckTimer, &QTimer::timeout, this, &WorkspaceWidgetPrivate::checkFileState);
Expand All @@ -495,6 +524,8 @@ void WorkspaceWidgetPrivate::initConnection()
connect(EditorCallProxy::instance(), &EditorCallProxy::reqRenameSymbol, this, &WorkspaceWidgetPrivate::handleRenameSymbol);
connect(EditorCallProxy::instance(), &EditorCallProxy::reqToggleBreakpoint, this, &WorkspaceWidgetPrivate::handleToggleBreakpoint);
connect(EditorCallProxy::instance(), &EditorCallProxy::reqSetModifiedAutoReload, this, &WorkspaceWidgetPrivate::handleSetModifiedAutoReload);
connect(EditorCallProxy::instance(), &EditorCallProxy::reqSaveSession, this, &WorkspaceWidgetPrivate::handleSaveSession);
connect(EditorCallProxy::instance(), &EditorCallProxy::reqSessionLoaded, this, &WorkspaceWidgetPrivate::handleSessionLoaded);
}

void WorkspaceWidgetPrivate::connectTabWidgetSignals(TabWidget *tabWidget)
Expand Down Expand Up @@ -904,18 +935,18 @@ void WorkspaceWidgetPrivate::onFocusChanged(QWidget *old, QWidget *now)
Q_UNUSED(old)

if (!now) {
ActionManager::instance()->removeContext({ TextEditorContext });
ActionManager::instance()->removeContext({ kTextEditorContext });
return;
}

// the `now` is TextEditor
auto tabWidget = qobject_cast<TabWidget *>(now->parentWidget());
if (!tabWidget) {
ActionManager::instance()->removeContext({ TextEditorContext });
ActionManager::instance()->removeContext({ kTextEditorContext });
return;
}

ActionManager::instance()->addContext({ TextEditorContext });
ActionManager::instance()->addContext({ kTextEditorContext });
focusTabWidget = tabWidget;
editor.switchedFile(focusTabWidget->currentFile());
auto symbolWidget = SymbolWidgetGenerator::instance()->symbolWidget();
Expand Down
18 changes: 16 additions & 2 deletions src/plugins/codeeditor/transceiver/codeeditorreceiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ CodeEditorReceiver::CodeEditorReceiver(QObject *parent)
eventHandleMap.insert(editor.setBreakpointEnabled.name, std::bind(&CodeEditorReceiver::processSetBreakpointEnabledEvent, this, _1));
eventHandleMap.insert(editor.clearAllBreakpoint.name, std::bind(&CodeEditorReceiver::processClearAllBreakpointsEvent, this, _1));
eventHandleMap.insert(editor.setModifiedAutoReload.name, std::bind(&CodeEditorReceiver::processSetModifiedAutoReloadEvent, this, _1));
eventHandleMap.insert(session.readyToSaveSession.name, std::bind(&CodeEditorReceiver::processReadyToSaveSessionEvent, this, _1));
eventHandleMap.insert(session.sessionLoaded.name, std::bind(&CodeEditorReceiver::processSessionLoadedEvent, this, _1));
}

dpf::EventHandler::Type CodeEditorReceiver::type()
{
return dpf::EventHandler::Type::Async;
return dpf::EventHandler::Type::Sync;
}

QStringList CodeEditorReceiver::topics()
{
return { editor.topic };
return { editor.topic, session.topic };
}

void CodeEditorReceiver::eventProcess(const dpf::Event &event)
Expand Down Expand Up @@ -140,6 +142,18 @@ void CodeEditorReceiver::processRemoveDebugLineEvent(const dpf::Event &event)
Q_EMIT EditorCallProxy::instance()->reqRemoveDebugLine();
}

void CodeEditorReceiver::processSessionLoadedEvent(const dpf::Event &event)
{
Q_UNUSED(event)
Q_EMIT EditorCallProxy::instance()->reqSessionLoaded();
}

void CodeEditorReceiver::processReadyToSaveSessionEvent(const dpf::Event &event)
{
Q_UNUSED(event)
Q_EMIT EditorCallProxy::instance()->reqSaveSession();
}

EditorCallProxy::EditorCallProxy()
{
}
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/codeeditor/transceiver/codeeditorreceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class CodeEditorReceiver : public dpf::EventHandler, dpf::AutoEventHandlerRegist
void processSetDebugLineEvent(const dpf::Event &event);
void processRemoveDebugLineEvent(const dpf::Event &event);

// session
void processSessionLoadedEvent(const dpf::Event &event);
void processReadyToSaveSessionEvent(const dpf::Event &event);

private:
QHash<QString, std::function<void(const dpf::Event &)>> eventHandleMap;
};
Expand Down Expand Up @@ -71,6 +75,10 @@ class EditorCallProxy : public QObject
void reqClearAllBreakpoints();
void reqSetDebugLine(const QString &fileName, int line);
void reqRemoveDebugLine();

// session
void reqSaveSession();
void reqSessionLoaded();
};

#endif // CODEEDITORRECEIVER_H
9 changes: 9 additions & 0 deletions src/plugins/core/builtin/texts/uc_add_16px.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions src/plugins/core/builtin/texts/uc_clone_16px.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/plugins/core/builtin/texts/uc_delete_16px.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions src/plugins/core/builtin/texts/uc_edit_16px.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit d18fba9

Please sign in to comment.