From 32a7adb8d4eab5c553cfe2f4b5f16fcae5ed8efa Mon Sep 17 00:00:00 2001 From: Le Tan Date: Thu, 6 Apr 2017 22:22:14 +0800 Subject: [PATCH] support viewing external orphan file 1. Add VOrphanFile for external local file; 2. Add doc file for shortcuts; 3. Ctrl+E ? to open the shortcuts doc; --- src/main.cpp | 5 +- src/resources/docs/shortcuts_en.md | 112 +++++++++++++++++++++++++ src/resources/docs/shortcuts_zh.md | 113 ++++++++++++++++++++++++++ src/src.pro | 6 +- src/utils/vutils.cpp | 14 ++++ src/utils/vutils.h | 1 + src/vcaptain.cpp | 8 ++ src/vconstants.h | 5 ++ src/vedittab.cpp | 49 ++++++----- src/veditwindow.cpp | 20 +++-- src/veditwindow.h | 6 +- src/vfile.cpp | 94 ++++++++++++++++++++- src/vfile.h | 126 +++++++---------------------- src/vmainwindow.cpp | 93 ++++++++++----------- src/vmainwindow.h | 1 + src/vnote.cpp | 25 ++++++ src/vnote.h | 12 +++ src/vnote.qrc | 2 + src/vopenedlistmenu.cpp | 8 +- src/vorphanfile.cpp | 89 ++++++++++++++++++++ src/vorphanfile.h | 33 ++++++++ 21 files changed, 644 insertions(+), 178 deletions(-) create mode 100644 src/resources/docs/shortcuts_en.md create mode 100644 src/resources/docs/shortcuts_zh.md create mode 100644 src/vorphanfile.cpp create mode 100644 src/vorphanfile.h diff --git a/src/main.cpp b/src/main.cpp index 6c411490..0fb6b1b8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,10 +45,7 @@ int main(int argc, char *argv[]) QApplication app(argc, argv); vconfig.initialize(); - QString locale = vconfig.getLanguage(); - if (locale == "System" || !VUtils::isValidLanguage(locale)) { - locale = QLocale::system().name(); - } + QString locale = VUtils::getLocale(); qDebug() << "use locale" << locale; // load translation for Qt diff --git a/src/resources/docs/shortcuts_en.md b/src/resources/docs/shortcuts_en.md new file mode 100644 index 00000000..5bc77110 --- /dev/null +++ b/src/resources/docs/shortcuts_en.md @@ -0,0 +1,112 @@ +# VNote Shortcuts +1. All the keys without special notice are **case insensitive**; +2. On macOS, `Ctrl` corresponds to `Command`; + +## Normal Shortcuts +- `Ctrl+T` +Toggle expanding the edit area. +- `Ctrl+N` +Create a note in current directory. +- `Ctrl+F` +Find/Replace in current note. +- `Ctrl+Q` +Quit VNote. +- `Ctrl+J`/`Ctrl+K` +VNote supports `Ctrl+J` and `Ctrl+K` for navigation in the notebooks list, directories list, notes list, opened notes list, and outline list. + +### Read Mode +- `Ctrl+W` +Edit current note. +- `H`/`J`/`K`/`L` +Navigation, corresponding to Left/Down/Up/Right arrow keys. +- `Ctrl+U` +Scroll up half screen. +- `Ctrl+D` +Scroll down half screen. +- `gg`/`G` +Jump to the beginning or end of the note. (Case Sensitive). +- `Ctrl + +/-` +Zoom in/out the page. +- `Ctrl+Wheel` +Zoom in/out the page through the mouse scroll. +- `Ctrl+0` +Recover the page zoom factor to 100%. + +### Edit Mode +- `Ctrl+S` +Save current changes. +- `Ctrl+R` +Save current changes and exit edit mode. + +#### Text Editing +- `Ctrl+B` +Insert bold. Press `Ctrl+B` again to exit. Currently selected text will be changed to bold if exist. +- `Ctrl+I` +Insert italic. Press `Ctrl+I` again to exit. Currently selected text will be changed to italic if exist. +- `Ctrl+O` +Insert inline code. Press `Ctrl+O` again to exit. Currently selected text will be changed to inline code if exist. +- `Ctrl+H` +Backspace. Delete a character backward. +- `Ctrl+W` +Delete all the characters from current cursor to the first space backward. +- `Ctrl+U` +Delete all the characters from current cursor to the beginning of current line. +- `Tab`/`Shift+Tab` +Increase or decrease the indentation. If any text is selected, the indentation will operate on all these selected lines. +- `Shift+Left`, `Shift+Right`, `Shift+Up`, `Shift+Down` +Expand the selection one character left or right, or one line up or down. +- `Ctrl+Shift+Left`, `Ctrl+Shift+Right` +Expand the selection to the beginning or end of current word. +- `Ctrl+Shift+Up`, `Ctrl+Sfhit+Down` +Expand the selection to the beginning or end of current paragraph. +- `Shift+Home`, `Shift+End` +Expand the selection to the beginning or end of current line. +- `Ctrl+Shift+Home`, `Ctrl+Shift+End` +Expand the selection to the beginning or end of current note. + +# Captain Mode +To efficiently utilize the shortcuts, VNote supports the **Captain Mode**. + +Press the leader key `Ctrl+E`, then VNote will enter the Captain Mode, within which VNote supports more efficient shortcuts. + +By the way, in this mode, `Ctrl+W` and `W` is equivalent, thus pressing `Ctrl+E+W` equals to `Ctrl+E W`. + +- `E` +Toggle expanding the edit area. +- `P` +Toggle single panel or two panels mode. +- `T` +Toggle the Tools panel. +- `F` +Popup the opened notes list of current split window. Within this list, pressing the sequence number in front of each note could jump to that note. +- `X` +Close current tab. +- `J` +Jump to next tab. +- `K` +Jump to last tab. +- `1` - `9` +Number key 1 to 9 will jump to the tabs with corresponding sequence number. +- `0` +Jump to previous tab. Alternate between current and previous tab. +- `D` +Locate to the directory of current note. +- `Q` +Discard current changes and exit edit mode. +- `V` +Vertically split current window. +- `R` +Remove current split window. +- `H` +Jump to the first split window on the left. +- `L` +Jump to the first split window on the right. +- `Shift+H` +Move current tab one split window left. +- `Shift+L` +Move current tab one split window right. +- `?` +Display shortcuts documentation. + +## Navigation Mode +Within the Captain MOde, `W` will turn VNote into **Navigation Mode**. In this mode, VNote will display at most two characters on some major widgets, and then pressing corresponding characters will jump to that widget. diff --git a/src/resources/docs/shortcuts_zh.md b/src/resources/docs/shortcuts_zh.md new file mode 100644 index 00000000..98bde214 --- /dev/null +++ b/src/resources/docs/shortcuts_zh.md @@ -0,0 +1,113 @@ +# VNote快捷键说明 +1. 以下按键除特别说明外,都不区分大小写; +2. 在macOS下,`Ctrl`对应于`Command`; + +## 常规快捷键 +- `Ctrl+T` +是否扩展编辑区域。 +- `Ctrl+N` +在当前文件夹下新建笔记。 +- `Ctrl+F` +页内查找和替换。 +- `Ctrl+Q` +退出VNote。 +- `Ctrl+J`/`Ctrl+K` +在笔记本列表、文件夹列表、笔记列表、已打开笔记列表和大纲目录中,均支持`Ctrl+J`和`Ctrl+K`导航。 + +### 阅读模式 +- `Ctrl+W` +编辑当前笔记。 +- `H`/`J`/`K`/`L` +导航,对应于左/下/上/右方向键。 +- `Ctrl+U` +向上滚动半屏。 +- `Ctrl+D` +向下滚动半屏。 +- `gg`/`G` +跳转到笔记的开始或结尾。(区分大小写)。 +- `Ctrl + +/-` +放大/缩小页面。 +- `Ctrl+Wheel` +鼠标滚轮实现放大/缩小页面。 +- `Ctrl+0` +恢复页面大小为100%。 + +### 编辑模式 +- `Ctrl+S` +保存当前更改。 +- `Ctrl+R` +保存当前更改并退出编辑模式。 + +#### 文本编辑 +- `Ctrl+B` +插入粗体;再次按`Ctrl+B`退出。如果已经选择文本,则将当前选择文本加粗。 +- `Ctrl+I` +插入斜体;再次按`Ctrl+I`退出。如果已经选择文本,则将当前选择文本改为斜体。 +- `Ctrl+O` +插入行内代码;再次按`Ctrl+O`退出。如果已经选择文本,则将当前选择文本改为行内代码。 +- `Ctrl+H` +退格键,向前删除一个字符。 +- `Ctrl+W` +删除光标位置向后到第一个空白字符之间的所有字符。 +- `Ctrl+U` +删除光标位置到行首的所有字符。 +- `Tab`/`Shift+Tab` +增加或减小缩进。如果已经选择文本,则对所有选择的行进行缩进操作。 +- `Shift+Left`, `Shift+Right`, `Shift+Up`, `Shift+Down` +扩展选定左右一个字符,或上下一行。 +- `Ctrl+Shift+Left`, `Ctrl+Shift+Right` +扩展选定到单词开始或结尾。 +- `Ctrl+Shift+Up`, `Ctrl+Sfhit+Down` +扩展选定到段尾或段首。 +- `Shift+Home`, `Shift+End` +扩展选定到行首和行尾。 +- `Ctrl+Shift+Home`, `Ctrl+Shift+End` +扩展选定到笔记开始或结尾处。 + +# 舰长模式 +为了更有效地利用快捷键,VNote支持 **舰长模式**。 + +按前导键`Ctrl+E`后,VNote会进入舰长模式。在舰长模式中,VNote会支持更多高效的快捷操作。 + +另外,在该模式中,`Ctrl+W`和`W`是等效的,因此,可以`Ctrl+E+W`来实现`Ctrl+E W`的操作。 + +- `E` +是否扩展编辑区域。 +- `P` +切换单列/双列面板模式。 +- `T` +打开或关闭工具面板。 +- `F` +打开当前分割窗口的笔记列表。在该列表中,可以直接按笔记对应的序号实现跳转。 +- `X` +关闭当前标签页。 +- `J` +跳转到下一个标签页。 +- `K` +跳转到上一个标签页。 +- `1` - `9` +数字1到9会跳转到对应序号的标签页。 +- `0` +跳转到前一个标签页(即前一个当前标签页)。实现当前标签页和前一个标签页之间的轮换。 +- `D` +定位当前笔记所在目录。 +- `Q` +放弃当前更改并退出编辑模式。 +- `V` +竖直分割当前窗口。 +- `R` +移除当前分割窗口。 +- `H` +跳转到左边一个分割窗口。 +- `L` +跳转到右边一个分割窗口。 +- `Shift+H` +将当前标签页左移一个分割窗口。 +- `Shift+L` +将当前标签页右移一个分割窗口。 +- `?` +显示本快捷键说明。 + +## 展览模式 +在舰长模式中,`W`命令会进入 **展览模式**。在展览模式中,VNote会在常用的主要部件上显示至多两个字母,此时输入对应的字母即可跳转到该部件中,从而实现快速切换焦点并触发功能。 + diff --git a/src/src.pro b/src/src.pro index 8f4c7325..4d13fcca 100644 --- a/src/src.pro +++ b/src/src.pro @@ -57,7 +57,8 @@ SOURCES += main.cpp\ dialog/vdeletenotebookdialog.cpp \ dialog/vselectdialog.cpp \ vcaptain.cpp \ - vopenedlistmenu.cpp + vopenedlistmenu.cpp \ + vorphanfile.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -101,7 +102,8 @@ HEADERS += vmainwindow.h \ dialog/vselectdialog.h \ vcaptain.h \ vopenedlistmenu.h \ - vnavigationmode.h + vnavigationmode.h \ + vorphanfile.h RESOURCES += \ vnote.qrc \ diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index b344e35d..5c8100f5 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -14,6 +14,11 @@ #include #include #include +#include + +#include "vconfigmanager.h" + +extern VConfigManager vconfig; const QVector> VUtils::c_availableLanguages = {QPair("en_US", "Englisth(US)"), QPair("zh_CN", "Chinese")}; @@ -367,3 +372,12 @@ QChar VUtils::keyToChar(int p_key) } return QChar(); } + +QString VUtils::getLocale() +{ + QString locale = vconfig.getLanguage(); + if (locale == "System" || !isValidLanguage(locale)) { + locale = QLocale::system().name(); + } + return locale; +} diff --git a/src/utils/vutils.h b/src/utils/vutils.h index 547550dd..0b80f79d 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -49,6 +49,7 @@ public: static qreal calculateScaleFactor(); static bool realEqual(qreal p_a, qreal p_b); static QChar keyToChar(int p_key); + static QString getLocale(); private: // diff --git a/src/vcaptain.cpp b/src/vcaptain.cpp index f0e19496..192ad53e 100644 --- a/src/vcaptain.cpp +++ b/src/vcaptain.cpp @@ -295,6 +295,14 @@ bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers) break; } + case Qt::Key_Question: + { + // Display shortcuts doc. + m_mainWindow->shortcutHelp(); + m_widgetBeforeCaptain = NULL; + break; + } + default: // Not implemented yet. Just exit Captain mode. break; diff --git a/src/vconstants.h b/src/vconstants.h index ad8e710b..0fb94e05 100644 --- a/src/vconstants.h +++ b/src/vconstants.h @@ -1,7 +1,12 @@ #ifndef VCONSTANTS_H #define VCONSTANTS_H +// Html: rich text file; +// Markdown: Markdown text file; enum class DocType { Html, Markdown }; + +enum class FileType { Normal, Orphan }; + enum class ClipboardOpType { Invalid, CopyFile, CopyDir }; enum class OpenFileMode {Read = 0, Edit}; diff --git a/src/vedittab.cpp b/src/vedittab.cpp index 19cbadab..ede39107 100644 --- a/src/vedittab.cpp +++ b/src/vedittab.cpp @@ -56,18 +56,21 @@ void VEditTab::setupUI() { switch (m_file->getDocType()) { case DocType::Markdown: - m_textEditor = new VMdEdit(m_file, this); - connect(dynamic_cast(m_textEditor), &VMdEdit::headersChanged, - this, &VEditTab::updateTocFromHeaders); - connect(dynamic_cast(m_textEditor), &VMdEdit::statusChanged, - this, &VEditTab::noticeStatusChanged); - connect(m_textEditor, SIGNAL(curHeaderChanged(int, int)), - this, SLOT(updateCurHeader(int, int))); - connect(m_textEditor, &VEdit::textChanged, - this, &VEditTab::handleTextChanged); - m_textEditor->reloadFile(); - addWidget(m_textEditor); - + if (m_file->isModifiable()) { + m_textEditor = new VMdEdit(m_file, this); + connect(dynamic_cast(m_textEditor), &VMdEdit::headersChanged, + this, &VEditTab::updateTocFromHeaders); + connect(dynamic_cast(m_textEditor), &VMdEdit::statusChanged, + this, &VEditTab::noticeStatusChanged); + connect(m_textEditor, SIGNAL(curHeaderChanged(int, int)), + this, SLOT(updateCurHeader(int, int))); + connect(m_textEditor, &VEdit::textChanged, + this, &VEditTab::handleTextChanged); + m_textEditor->reloadFile(); + addWidget(m_textEditor); + } else { + m_textEditor = NULL; + } setupMarkdownPreview(); break; @@ -87,6 +90,7 @@ void VEditTab::setupUI() void VEditTab::handleTextChanged() { + Q_ASSERT(m_file->isModifiable()); if (m_fileModified) { return; } @@ -148,7 +152,6 @@ void VEditTab::previewByConverter() processHoedownToc(toc); html.replace(tocExp, toc); document.setHtml(html); - // Hoedown will add '\n' while Marked does not updateTocFromHtml(toc); } @@ -163,6 +166,9 @@ void VEditTab::processHoedownToc(QString &p_toc) void VEditTab::showFileEditMode() { + if (!m_file->isModifiable()) { + return; + } isEditMode = true; // beginEdit() may change curHeader. @@ -191,7 +197,7 @@ bool VEditTab::closeFile(bool p_forced) void VEditTab::editFile() { - if (isEditMode) { + if (isEditMode || !m_file->isModifiable()) { return; } @@ -204,7 +210,7 @@ void VEditTab::readFile() return; } - if (m_textEditor->isModified()) { + if (m_textEditor && m_textEditor->isModified()) { // Prompt to save the changes int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"), tr("Note %1 has been modified.").arg(m_file->getName()), @@ -226,16 +232,21 @@ void VEditTab::readFile() return; } } - m_textEditor->endEdit(); + + if (m_textEditor) { + m_textEditor->endEdit(); + } + showFileReadMode(); } bool VEditTab::saveFile() { - bool ret; if (!isEditMode || !m_textEditor->isModified()) { return true; } + + bool ret; // Make sure the file already exists. Temporary deal with cases when user delete or move // a file. QString filePath = m_file->retrivePath(); @@ -580,7 +591,9 @@ void VEditTab::clearSearchedWordHighlight() if (webPreviewer) { webPreviewer->findText(""); } - m_textEditor->clearSearchedWordHighlight(); + if (m_textEditor) { + m_textEditor->clearSearchedWordHighlight(); + } } bool VEditTab::checkToc() diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index 42b78fe0..b1d118f2 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -333,7 +333,8 @@ void VEditWindow::updateTabInfo(int p_index) const VFile *file = editor->getFile(); bool editMode = editor->getIsEditMode(); - setTabText(p_index, generateTabText(p_index, file->getName(), file->isModified())); + setTabText(p_index, generateTabText(p_index, file->getName(), + file->isModified(), file->isModifiable())); setTabToolTip(p_index, generateTooltip(file)); setTabIcon(p_index, editMode ? QIcon(":/resources/icons/editing.svg") : QIcon(":/resources/icons/reading.svg")); @@ -344,7 +345,8 @@ void VEditWindow::updateAllTabsSequence() for (int i = 0; i < count(); ++i) { VEditTab *editor = getTab(i); const VFile *file = editor->getFile(); - setTabText(i, generateTabText(i, file->getName(), file->isModified())); + setTabText(i, generateTabText(i, file->getName(), + file->isModified(), file->isModifiable())); } } @@ -436,7 +438,11 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) return; } m_locateAct->setData(tab); - menu.addAction(m_locateAct); + VEditTab *editor = getTab(tab); + QPointer file = editor->getFile(); + if (file->getType() == FileType::Normal) { + menu.addAction(m_locateAct); + } int totalWin = m_editArea->windowCount(); if (totalWin > 1) { @@ -448,7 +454,9 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) menu.addAction(m_moveRightAct); } - menu.exec(bar->mapToGlobal(p_pos)); + if (!menu.actions().isEmpty()) { + menu.exec(bar->mapToGlobal(p_pos)); + } } void VEditWindow::tabListJump(VFile *p_file) @@ -598,7 +606,9 @@ void VEditWindow::handleLocateAct() int tab = m_locateAct->data().toInt(); VEditTab *editor = getTab(tab); QPointer file = editor->getFile(); - vnote->getMainWindow()->locateFile(file); + if (file->getType() == FileType::Normal) { + vnote->getMainWindow()->locateFile(file); + } } void VEditWindow::handleMoveLeftAct() diff --git a/src/veditwindow.h b/src/veditwindow.h index 7a265a9c..5a0a1ef3 100644 --- a/src/veditwindow.h +++ b/src/veditwindow.h @@ -96,7 +96,7 @@ private: void noticeStatus(int index); inline QString generateTooltip(const VFile *p_file) const; inline QString generateTabText(int p_index, const QString &p_name, - bool p_modified) const; + bool p_modified, bool p_modifiable) const; bool canRemoveSplit(); void moveTabOneSplit(int p_tabIdx, bool p_right); void updateTabInfo(int p_idx); @@ -134,10 +134,10 @@ inline QString VEditWindow::generateTooltip(const VFile *p_file) const } inline QString VEditWindow::generateTabText(int p_index, const QString &p_name, - bool p_modified) const + bool p_modified, bool p_modifiable) const { QString seq = QString::number(p_index + c_tabSequenceBase, 10); - return seq + ". " + (p_modified ? (p_name + "*") : p_name); + return seq + ". " + p_name + (p_modifiable ? (p_modified ? "*" : "") : "#"); } #endif // VEDITWINDOW_H diff --git a/src/vfile.cpp b/src/vfile.cpp index 27481c36..1e853e61 100644 --- a/src/vfile.cpp +++ b/src/vfile.cpp @@ -5,9 +5,15 @@ #include #include "utils/vutils.h" -VFile::VFile(const QString &p_name, QObject *p_parent) +VFile::VFile(const QString &p_name, QObject *p_parent, + FileType p_type, bool p_modifiable) : QObject(p_parent), m_name(p_name), m_opened(false), m_modified(false), - m_docType(VUtils::isMarkdown(p_name) ? DocType::Markdown : DocType::Html) + m_docType(VUtils::isMarkdown(p_name) ? DocType::Markdown : DocType::Html), + m_type(p_type), m_modifiable(p_modifiable) +{ +} + +VFile::~VFile() { } @@ -112,3 +118,87 @@ void VFile::setName(const QString &p_name) qWarning() << "setName() change the DocType. A convertion should be followed"; } } + +const QString &VFile::getName() const +{ + return m_name; +} + +VDirectory *VFile::getDirectory() +{ + Q_ASSERT(parent()); + return (VDirectory *)parent(); +} + +const VDirectory *VFile::getDirectory() const +{ + Q_ASSERT(parent()); + return (const VDirectory *)parent(); +} + +DocType VFile::getDocType() const +{ + return m_docType; +} + +const QString &VFile::getContent() const +{ + return m_content; +} + +QString VFile::getNotebookName() const +{ + return getDirectory()->getNotebookName(); +} + +VNotebook *VFile::getNotebook() +{ + return getDirectory()->getNotebook(); +} + +QString VFile::retrivePath() const +{ + QString dirPath = getDirectory()->retrivePath(); + return QDir(dirPath).filePath(m_name); +} + +QString VFile::retriveRelativePath() const +{ + QString dirRelativePath = getDirectory()->retriveRelativePath(); + return QDir(dirRelativePath).filePath(m_name); +} + +QString VFile::retriveBasePath() const +{ + return getDirectory()->retrivePath(); +} + +QString VFile::retriveImagePath() const +{ + return QDir(retriveBasePath()).filePath("images"); +} + +void VFile::setContent(const QString &p_content) +{ + m_content = p_content; +} + +bool VFile::isModified() const +{ + return m_modified; +} + +bool VFile::isModifiable() const +{ + return m_modifiable; +} + +bool VFile::isOpened() const +{ + return m_opened; +} + +FileType VFile::getType() const +{ + return m_type; +} diff --git a/src/vfile.h b/src/vfile.h index 3f57febd..58cb93f2 100644 --- a/src/vfile.h +++ b/src/vfile.h @@ -3,7 +3,6 @@ #include #include -#include #include "vdirectory.h" #include "vconstants.h" @@ -13,35 +12,37 @@ class VFile : public QObject { Q_OBJECT public: - explicit VFile(const QString &p_name, QObject *p_parent); - bool open(); - void close(); - bool save(); + VFile(const QString &p_name, QObject *p_parent, + FileType p_type = FileType::Normal, bool p_modifiable = true); + virtual ~VFile(); + virtual bool open(); + virtual void close(); + virtual bool save(); // Convert current file type. - void convert(DocType p_curType, DocType p_targetType); + virtual void convert(DocType p_curType, DocType p_targetType); - inline const QString &getName() const; - void setName(const QString &p_name); - inline VDirectory *getDirectory(); - inline const VDirectory *getDirectory() const; - inline DocType getDocType() const; - inline const QString &getContent() const; - inline void setContent(const QString &p_content); - inline VNotebook *getNotebook(); - inline QString getNotebookName() const; - inline QString retrivePath() const; - inline QString retriveRelativePath() const; - inline QString retriveBasePath() const; - inline QString retriveImagePath() const; - inline bool isModified() const; - inline bool isOpened() const; - -signals: + const QString &getName() const; + virtual void setName(const QString &p_name); + virtual VDirectory *getDirectory(); + virtual const VDirectory *getDirectory() const; + DocType getDocType() const; + const QString &getContent() const; + virtual void setContent(const QString &p_content); + virtual VNotebook *getNotebook(); + virtual QString getNotebookName() const; + virtual QString retrivePath() const; + virtual QString retriveRelativePath() const; + virtual QString retriveBasePath() const; + virtual QString retriveImagePath() const; + bool isModified() const; + bool isModifiable() const; + bool isOpened() const; + FileType getType() const; public slots: void setModified(bool p_modified); -private: +protected: // Delete the file and corresponding images void deleteDiskFile(); // Delete local images in ./images of DocType::Markdown @@ -53,81 +54,10 @@ private: bool m_modified; DocType m_docType; QString m_content; + FileType m_type; + bool m_modifiable; + friend class VDirectory; }; -inline const QString &VFile::getName() const -{ - return m_name; -} - -inline VDirectory *VFile::getDirectory() -{ - Q_ASSERT(parent()); - return (VDirectory *)parent(); -} - -inline const VDirectory *VFile::getDirectory() const -{ - Q_ASSERT(parent()); - return (const VDirectory *)parent(); -} - -inline DocType VFile::getDocType() const -{ - return m_docType; -} - -inline const QString &VFile::getContent() const -{ - return m_content; -} - -inline QString VFile::getNotebookName() const -{ - return getDirectory()->getNotebookName(); -} - -inline VNotebook *VFile::getNotebook() -{ - return getDirectory()->getNotebook(); -} - -inline QString VFile::retrivePath() const -{ - QString dirPath = getDirectory()->retrivePath(); - return QDir(dirPath).filePath(m_name); -} - -inline QString VFile::retriveRelativePath() const -{ - QString dirRelativePath = getDirectory()->retriveRelativePath(); - return QDir(dirRelativePath).filePath(m_name); -} - -inline QString VFile::retriveBasePath() const -{ - return getDirectory()->retrivePath(); -} - -inline QString VFile::retriveImagePath() const -{ - return QDir(retriveBasePath()).filePath("images"); -} - -inline void VFile::setContent(const QString &p_content) -{ - m_content = p_content; -} - -inline bool VFile::isModified() const -{ - return m_modified; -} - -inline bool VFile::isOpened() const -{ - return m_opened; -} - #endif // VFILE_H diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index e5fe4d25..3a864715 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -279,16 +279,24 @@ void VMainWindow::initMenuBar() void VMainWindow::initHelpMenu() { QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); + helpMenu->setToolTipsVisible(true); + + QAction *shortcutAct = new QAction(tr("&Shortcuts Help"), this); + shortcutAct->setToolTip(tr("View information about shortcut keys")); + connect(shortcutAct, &QAction::triggered, + this, &VMainWindow::shortcutHelp); QAction *aboutAct = new QAction(tr("&About VNote"), this); - aboutAct->setStatusTip(tr("View information about VNote")); + aboutAct->setToolTip(tr("View information about VNote")); connect(aboutAct, &QAction::triggered, this, &VMainWindow::aboutMessage); + QAction *aboutQtAct = new QAction(tr("About &Qt"), this); - aboutQtAct->setStatusTip(tr("View information about Qt")); + aboutQtAct->setToolTip(tr("View information about Qt")); connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt); + helpMenu->addAction(shortcutAct); helpMenu->addAction(aboutQtAct); helpMenu->addAction(aboutAct); } @@ -786,46 +794,23 @@ void VMainWindow::setRenderBackgroundColor(QAction *action) void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file, bool p_editMode) { - if (p_file) { - if (p_editMode) { - editNoteAct->setVisible(false); - discardExitAct->setVisible(true); - saveExitAct->setVisible(true); - saveNoteAct->setVisible(true); - deleteNoteAct->setEnabled(true); + editNoteAct->setVisible(p_file && p_file->isModifiable() && !p_editMode); + discardExitAct->setVisible(p_file && p_editMode); + saveExitAct->setVisible(p_file && p_editMode); + saveNoteAct->setVisible(p_file && p_editMode); + deleteNoteAct->setEnabled(p_file && p_file->isModifiable()); + noteInfoAct->setEnabled(p_file && p_file->getType() == FileType::Normal); - m_insertImageAct->setEnabled(true); - } else { - editNoteAct->setVisible(true); - discardExitAct->setVisible(false); - saveExitAct->setVisible(false); - saveNoteAct->setVisible(false); - deleteNoteAct->setEnabled(true); + m_insertImageAct->setEnabled(p_file && p_editMode); + // Find/Replace + m_findReplaceAct->setEnabled(p_file); + m_findNextAct->setEnabled(p_file); + m_findPreviousAct->setEnabled(p_file); + m_replaceAct->setEnabled(p_file && p_editMode); + m_replaceFindAct->setEnabled(p_file && p_editMode); + m_replaceAllAct->setEnabled(p_file && p_editMode); - m_insertImageAct->setEnabled(false); - m_replaceAct->setEnabled(false); - m_replaceFindAct->setEnabled(false); - m_replaceAllAct->setEnabled(false); - } - noteInfoAct->setEnabled(true); - - m_findReplaceAct->setEnabled(true); - } else { - editNoteAct->setVisible(false); - discardExitAct->setVisible(false); - saveExitAct->setVisible(false); - saveNoteAct->setVisible(false); - deleteNoteAct->setEnabled(false); - noteInfoAct->setEnabled(false); - - m_insertImageAct->setEnabled(false); - // Find/Replace - m_findReplaceAct->setEnabled(false); - m_findNextAct->setEnabled(false); - m_findPreviousAct->setEnabled(false); - m_replaceAct->setEnabled(false); - m_replaceFindAct->setEnabled(false); - m_replaceAllAct->setEnabled(false); + if (!p_file) { m_findReplaceDialog->closeDialog(); } } @@ -840,8 +825,12 @@ void VMainWindow::handleCurTabStatusChanged(const VFile *p_file, const VEditTab QString title; if (p_file) { title = QString("[%1] %2").arg(p_file->getNotebookName()).arg(p_file->retrivePath()); - if (p_file->isModified()) { - title.append('*'); + if (p_file->isModifiable()) { + if (p_file->isModified()) { + title.append('*'); + } + } else { + title.append('#'); } } updateWindowTitle(title); @@ -924,13 +913,17 @@ void VMainWindow::updateWindowTitle(const QString &str) void VMainWindow::curEditFileInfo() { - Q_ASSERT(m_curFile); + if (!m_curFile || m_curFile->getType() != FileType::Normal) { + return; + } fileList->fileInfo(m_curFile); } void VMainWindow::deleteCurNote() { - Q_ASSERT(m_curFile); + if (!m_curFile || !m_curFile->isModifiable()) { + return; + } fileList->deleteFile(m_curFile); } @@ -1028,7 +1021,7 @@ void VMainWindow::insertImage() void VMainWindow::locateFile(VFile *p_file) { - if (!p_file) { + if (!p_file || p_file->getType() != FileType::Normal) { return; } qDebug() << "locate file" << p_file->retrivePath(); @@ -1118,3 +1111,13 @@ void VMainWindow::changeAutoList(bool p_checked) } } +void VMainWindow::shortcutHelp() +{ + QString locale = VUtils::getLocale(); + QString docName = VNote::c_shortcutsDocFile_en; + if (locale == "zh_CN") { + docName = VNote::c_shortcutsDocFile_zh; + } + VFile *file = vnote->getOrphanFile(docName); + editArea->openFile(file, OpenFileMode::Read); +} diff --git a/src/vmainwindow.h b/src/vmainwindow.h index 13448f3f..b077a6cd 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -47,6 +47,7 @@ private slots: void viewSettings(); void changeMarkdownConverter(QAction *action); void aboutMessage(); + void shortcutHelp(); void changeExpandTab(bool checked); void setTabStopWidth(QAction *action); void setEditorBackgroundColor(QAction *action); diff --git a/src/vnote.cpp b/src/vnote.cpp index bc012286..828c372b 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -11,6 +11,7 @@ #include "utils/vutils.h" #include "vconfigmanager.h" #include "vmainwindow.h" +#include "vorphanfile.h" extern VConfigManager vconfig; @@ -27,6 +28,8 @@ const QString VNote::c_mermaidCssFile = ":/utils/mermaid/mermaid.css"; const QString VNote::c_mermaidDarkCssFile = ":/utils/mermaid/mermaid.dark.css"; const QString VNote::c_mermaidForestCssFile = ":/utils/mermaid/mermaid.forest.css"; const QString VNote::c_mathjaxJsFile = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML"; +const QString VNote::c_shortcutsDocFile_en = ":/resources/docs/shortcuts_en.md"; +const QString VNote::c_shortcutsDocFile_zh = ":/resources/docs/shortcuts_zh.md"; VNote::VNote(QObject *parent) : QObject(parent), m_mainWindow(dynamic_cast(parent)) @@ -231,3 +234,25 @@ const QString &VNote::getMonospacedFont() const } return font; } + +VFile *VNote::getOrphanFile(const QString &p_path) +{ + if (p_path.isEmpty()) { + return NULL; + } + + // See if the file has already been opened before. + for (auto const &file : m_externalFiles) { + if (file->getType() == FileType::Orphan && file->retrivePath() == p_path) { + qDebug() << "find a VFile for path" << p_path; + return file; + } + } + + // TODO: Clean up unopened file here. + + // Create a VOrphanFile for p_path. + VOrphanFile *file = new VOrphanFile(p_path, this); + m_externalFiles.append(file); + return file; +} diff --git a/src/vnote.h b/src/vnote.h index 4f7bb6ce..a6f04c28 100644 --- a/src/vnote.h +++ b/src/vnote.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include "vconstants.h" class VMainWindow; +class VFile; class VNote : public QObject { @@ -49,6 +51,9 @@ public: // Mathjax static const QString c_mathjaxJsFile; + static const QString c_shortcutsDocFile_en; + static const QString c_shortcutsDocFile_zh; + inline const QVector > &getPalette() const; void initPalette(QPalette palette); QString getColorFromPalette(const QString &p_name) const; @@ -56,6 +61,9 @@ public: QString getNavigationLabelStyle(const QString &p_str) const; + // Given the path of an external file, create a VFile struct. + VFile *getOrphanFile(const QString &p_path); + public slots: void updateTemplate(); @@ -66,6 +74,10 @@ private: QVector m_notebooks; QVector > m_palette; VMainWindow *m_mainWindow; + + // Hold all external file: Orphan File. + // Need to clean up periodly. + QList m_externalFiles; }; inline const QVector >& VNote::getPalette() const diff --git a/src/vnote.qrc b/src/vnote.qrc index 9ef5a181..23af7649 100644 --- a/src/vnote.qrc +++ b/src/vnote.qrc @@ -97,5 +97,7 @@ resources/icons/close_red.svg resources/icons/close_grey.svg resources/icons/float.svg + resources/docs/shortcuts_en.md + resources/docs/shortcuts_zh.md diff --git a/src/vopenedlistmenu.cpp b/src/vopenedlistmenu.cpp index d1c4b75f..a81ee6ac 100644 --- a/src/vopenedlistmenu.cpp +++ b/src/vopenedlistmenu.cpp @@ -83,7 +83,13 @@ void VOpenedListMenu::updateOpenedList() if (curNotebook != notebook || file->getDirectory() != directory) { notebook = curNotebook; directory = file->getDirectory(); - QString text = QString("[%1] %2").arg(notebook).arg(directory->getName()); + QString dirName; + if (!directory) { + dirName = file->retriveBasePath(); + } else { + dirName = directory->getName(); + } + QString text = QString("[%1] %2").arg(notebook).arg(dirName); QAction *sepAct = addSection(text); sepAct->setFont(sepFont); } diff --git a/src/vorphanfile.cpp b/src/vorphanfile.cpp new file mode 100644 index 00000000..bdc3b67d --- /dev/null +++ b/src/vorphanfile.cpp @@ -0,0 +1,89 @@ +#include "vorphanfile.h" +#include +#include +#include +#include "utils/vutils.h" + +VOrphanFile::VOrphanFile(const QString &p_path, QObject *p_parent) + : VFile(VUtils::fileNameFromPath(p_path), p_parent, FileType::Orphan, false), + m_path(p_path) +{ + qDebug() << "VOrphanFile" << p_path << m_name; +} + +bool VOrphanFile::open() +{ + Q_ASSERT(!m_name.isEmpty()); + if (m_opened) { + return true; + } + Q_ASSERT(m_content.isEmpty()); + Q_ASSERT(m_docType == (VUtils::isMarkdown(m_name) ? DocType::Markdown : DocType::Html)); + Q_ASSERT(QFileInfo::exists(m_path)); + m_content = VUtils::readFileFromDisk(m_path); + m_modified = false; + m_opened = true; + return true; +} + +QString VOrphanFile::retrivePath() const +{ + return m_path; +} + +QString VOrphanFile::retriveRelativePath() const +{ + return m_path; +} + +QString VOrphanFile::retriveBasePath() const +{ + return VUtils::basePathFromPath(m_path); +} + +QString VOrphanFile::retriveImagePath() const +{ + V_ASSERT(false); + return ""; +} + +bool VOrphanFile::save() +{ + V_ASSERT(false); + return false; +} + +void VOrphanFile::convert(DocType /* p_curType */, DocType /* p_targetType */) +{ + V_ASSERT(false); +} + +void VOrphanFile::setName(const QString & /* p_name */) +{ + V_ASSERT(false); +} + +VDirectory *VOrphanFile::getDirectory() +{ + return NULL; +} + +const VDirectory *VOrphanFile::getDirectory() const +{ + return NULL; +} + +QString VOrphanFile::getNotebookName() const +{ + return "[EMPTY]"; +} + +VNotebook *VOrphanFile::getNotebook() +{ + return NULL; +} + +void VOrphanFile::setContent(const QString & /* p_content */) +{ + V_ASSERT(false); +} diff --git a/src/vorphanfile.h b/src/vorphanfile.h new file mode 100644 index 00000000..87218ccb --- /dev/null +++ b/src/vorphanfile.h @@ -0,0 +1,33 @@ +#ifndef VORPHANFILE_H +#define VORPHANFILE_H + +#include "vfile.h" + +// VOrphanFile is file not belong to any notebooks or directories. +// Given the path of the file, VNote could load its content as read-only. +class VOrphanFile : public VFile +{ + Q_OBJECT +public: + VOrphanFile(const QString &p_path, QObject *p_parent); + bool open(); + QString retrivePath() const; + QString retriveRelativePath() const; + QString retriveBasePath() const; + VDirectory *getDirectory(); + const VDirectory *getDirectory() const; + QString getNotebookName() const; + VNotebook *getNotebook(); + +private: + bool save(); + void convert(DocType p_curType, DocType p_targetType); + void setName(const QString &p_name); + QString retriveImagePath() const; + void setContent(const QString &p_content); + + QString m_path; + friend class VDirectory; +}; + +#endif // VORPHANFILE_H