diff --git a/src/resources/docs/shortcuts_en.md b/src/resources/docs/shortcuts_en.md index 5a0c2948..2cfe0db3 100644 --- a/src/resources/docs/shortcuts_en.md +++ b/src/resources/docs/shortcuts_en.md @@ -15,6 +15,8 @@ Quit VNote. VNote supports `Ctrl+J` and `Ctrl+K` for navigation in the notebooks list, directories list, notes list, opened notes list, and outline list. - `Ctrl+Left Mouse` Scroll in all directions. +- `Ctrl+Shift+T` +Recover last closed file. ### Read Mode - `Ctrl+W` diff --git a/src/resources/docs/shortcuts_zh.md b/src/resources/docs/shortcuts_zh.md index 06862f02..60146c69 100644 --- a/src/resources/docs/shortcuts_zh.md +++ b/src/resources/docs/shortcuts_zh.md @@ -15,6 +15,8 @@ 在笔记本列表、文件夹列表、笔记列表、已打开笔记列表和大纲目录中,均支持`Ctrl+J`和`Ctrl+K`导航。 - `Ctrl+Left Mouse` 任意滚动。 +- `Ctrl+Shift+T` +恢复上一个关闭的文件。 ### 阅读模式 - `Ctrl+W` diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index d6e42680..002dba68 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -191,6 +191,8 @@ Find=Ctrl+F FindNext=F3 ; Find previous occurence FindPrevious=Shift+F3 +; Recover last closed file +LastClosedFile=Ctrl+Shift+T [captain_mode_shortcuts] ; Define shortcuts in Captain mode here. diff --git a/src/veditarea.cpp b/src/veditarea.cpp index 2ebe8125..3a4a8dee 100644 --- a/src/veditarea.cpp +++ b/src/veditarea.cpp @@ -70,6 +70,22 @@ void VEditArea::setupUI() connect(m_findReplace, &VFindReplaceDialog::dialogClosed, this, &VEditArea::handleFindDialogClosed); m_findReplace->hide(); + + // Shortcut Ctrl+Shift+T to open last closed file. + QString keySeq = g_config->getShortcutKeySequence("LastClosedFile"); + qDebug() << "set LastClosedFile shortcut to" << keySeq; + QShortcut *lastClosedFileShortcut = new QShortcut(QKeySequence(keySeq), this); + lastClosedFileShortcut->setContext(Qt::ApplicationShortcut); + connect(lastClosedFileShortcut, &QShortcut::activated, + this, [this]() { + if (!m_lastClosedFiles.isEmpty()) { + const VFileSessionInfo &file = m_lastClosedFiles.top(); + QVector files(1, file); + m_lastClosedFiles.pop(); + + openFiles(files); + } + }); } void VEditArea::insertSplitWindow(int idx) @@ -947,3 +963,16 @@ void VEditArea::evaluateMagicWordsByCaptain(void *p_target, void *p_data) } } +void VEditArea::recordClosedFile(const VFileSessionInfo &p_file) +{ + for (auto it = m_lastClosedFiles.begin(); it != m_lastClosedFiles.end(); ++it) { + if (it->m_file == p_file.m_file) { + // Remove it. + m_lastClosedFiles.erase(it); + break; + } + } + + m_lastClosedFiles.push(p_file); + qDebug() << "pushed closed file" << p_file.m_file; +} diff --git a/src/veditarea.h b/src/veditarea.h index 0172f8a0..e434dca9 100644 --- a/src/veditarea.h +++ b/src/veditarea.h @@ -8,11 +8,12 @@ #include #include #include -#include #include +#include #include "vnotebook.h" #include "veditwindow.h" #include "vnavigationmode.h" +#include "vfilesessioninfo.h" class VFile; class VDirectory; @@ -76,6 +77,9 @@ public: // Open files @p_files. int openFiles(const QVector &p_files); + // Record a closed file in the stack. + void recordClosedFile(const VFileSessionInfo &p_file); + signals: // Emit when current window's tab status updated. void tabStatusUpdated(const VEditTabInfo &p_info); @@ -199,6 +203,9 @@ private: QSplitter *splitter; VFindReplaceDialog *m_findReplace; + // Last closed files stack. + QStack m_lastClosedFiles; + // Navigation Mode. // Map second key to VEditWindow. QMap m_keyMap; diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index bc4a9e3a..7955d350 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -302,18 +302,25 @@ bool VEditWindow::closeFile(const VFile *p_file, bool p_forced) VEditTab *editor = getTab(idx); Q_ASSERT(editor); + VEditTabInfo tabInfo = editor->fetchTabInfo(); + VFileSessionInfo info = VFileSessionInfo::fromEditTabInfo(&tabInfo); if (!p_forced) { setCurrentIndex(idx); updateTabStatus(idx); } + // Even p_forced is true we need to delete unused images. bool ok = editor->closeFile(p_forced); if (ok) { removeEditTab(idx); + + m_editArea->recordClosedFile(info); } + if (count() == 0) { emit requestRemoveSplit(this); } + return ok; } @@ -362,22 +369,30 @@ bool VEditWindow::closeAllFiles(bool p_forced) for (int i = 0; i < nrTab; ++i) { VEditTab *editor = getTab(0); + VEditTabInfo tabInfo = editor->fetchTabInfo(); + VFileSessionInfo info = VFileSessionInfo::fromEditTabInfo(&tabInfo); + if (!p_forced) { setCurrentIndex(0); updateTabStatus(0); } + // Even p_forced is true we need to delete unused images. bool ok = editor->closeFile(p_forced); if (ok) { removeEditTab(0); + + m_editArea->recordClosedFile(info); } else { ret = false; break; } } + if (count() == 0) { emit requestRemoveSplit(this); } + return ret; } @@ -420,9 +435,13 @@ bool VEditWindow::closeTab(int p_index) { VEditTab *editor = getTab(p_index); Q_ASSERT(editor); + VEditTabInfo tabInfo = editor->fetchTabInfo(); + VFileSessionInfo info = VFileSessionInfo::fromEditTabInfo(&tabInfo); bool ok = editor->closeFile(false); if (ok) { removeEditTab(p_index); + + m_editArea->recordClosedFile(info); } // User clicks the close button. We should make this window @@ -431,6 +450,7 @@ bool VEditWindow::closeTab(int p_index) if (count() == 0) { emit requestRemoveSplit(this); } + return ok; } diff --git a/src/vnote.cpp b/src/vnote.cpp index 48d2e6d9..a2f4614a 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -343,7 +343,13 @@ VFile *VNote::getFile(const QString &p_path) { VFile *file = getInternalFile(p_path); if (!file) { - file = getOrphanFile(p_path, true, false); + QFileInfo fi(p_path); + if (fi.isNativePath()) { + file = getOrphanFile(p_path, true, false); + } else { + // File in Qt resource system. + file = getOrphanFile(p_path, false, true); + } } return file;