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;
This commit is contained in:
Le Tan 2017-04-06 22:22:14 +08:00
parent 79de92238c
commit 32a7adb8d4
21 changed files with 644 additions and 178 deletions

View File

@ -45,10 +45,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv); QApplication app(argc, argv);
vconfig.initialize(); vconfig.initialize();
QString locale = vconfig.getLanguage(); QString locale = VUtils::getLocale();
if (locale == "System" || !VUtils::isValidLanguage(locale)) {
locale = QLocale::system().name();
}
qDebug() << "use locale" << locale; qDebug() << "use locale" << locale;
// load translation for Qt // load translation for Qt

View File

@ -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.

View File

@ -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会在常用的主要部件上显示至多两个字母此时输入对应的字母即可跳转到该部件中从而实现快速切换焦点并触发功能。

View File

@ -57,7 +57,8 @@ SOURCES += main.cpp\
dialog/vdeletenotebookdialog.cpp \ dialog/vdeletenotebookdialog.cpp \
dialog/vselectdialog.cpp \ dialog/vselectdialog.cpp \
vcaptain.cpp \ vcaptain.cpp \
vopenedlistmenu.cpp vopenedlistmenu.cpp \
vorphanfile.cpp
HEADERS += vmainwindow.h \ HEADERS += vmainwindow.h \
vdirectorytree.h \ vdirectorytree.h \
@ -101,7 +102,8 @@ HEADERS += vmainwindow.h \
dialog/vselectdialog.h \ dialog/vselectdialog.h \
vcaptain.h \ vcaptain.h \
vopenedlistmenu.h \ vopenedlistmenu.h \
vnavigationmode.h vnavigationmode.h \
vorphanfile.h
RESOURCES += \ RESOURCES += \
vnote.qrc \ vnote.qrc \

View File

@ -14,6 +14,11 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QScreen> #include <QScreen>
#include <cmath> #include <cmath>
#include <QLocale>
#include "vconfigmanager.h"
extern VConfigManager vconfig;
const QVector<QPair<QString, QString>> VUtils::c_availableLanguages = {QPair<QString, QString>("en_US", "Englisth(US)"), const QVector<QPair<QString, QString>> VUtils::c_availableLanguages = {QPair<QString, QString>("en_US", "Englisth(US)"),
QPair<QString, QString>("zh_CN", "Chinese")}; QPair<QString, QString>("zh_CN", "Chinese")};
@ -367,3 +372,12 @@ QChar VUtils::keyToChar(int p_key)
} }
return QChar(); return QChar();
} }
QString VUtils::getLocale()
{
QString locale = vconfig.getLanguage();
if (locale == "System" || !isValidLanguage(locale)) {
locale = QLocale::system().name();
}
return locale;
}

View File

@ -49,6 +49,7 @@ public:
static qreal calculateScaleFactor(); static qreal calculateScaleFactor();
static bool realEqual(qreal p_a, qreal p_b); static bool realEqual(qreal p_a, qreal p_b);
static QChar keyToChar(int p_key); static QChar keyToChar(int p_key);
static QString getLocale();
private: private:
// <value, name> // <value, name>

View File

@ -295,6 +295,14 @@ bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
break; break;
} }
case Qt::Key_Question:
{
// Display shortcuts doc.
m_mainWindow->shortcutHelp();
m_widgetBeforeCaptain = NULL;
break;
}
default: default:
// Not implemented yet. Just exit Captain mode. // Not implemented yet. Just exit Captain mode.
break; break;

View File

@ -1,7 +1,12 @@
#ifndef VCONSTANTS_H #ifndef VCONSTANTS_H
#define VCONSTANTS_H #define VCONSTANTS_H
// Html: rich text file;
// Markdown: Markdown text file;
enum class DocType { Html, Markdown }; enum class DocType { Html, Markdown };
enum class FileType { Normal, Orphan };
enum class ClipboardOpType { Invalid, CopyFile, CopyDir }; enum class ClipboardOpType { Invalid, CopyFile, CopyDir };
enum class OpenFileMode {Read = 0, Edit}; enum class OpenFileMode {Read = 0, Edit};

View File

@ -56,6 +56,7 @@ void VEditTab::setupUI()
{ {
switch (m_file->getDocType()) { switch (m_file->getDocType()) {
case DocType::Markdown: case DocType::Markdown:
if (m_file->isModifiable()) {
m_textEditor = new VMdEdit(m_file, this); m_textEditor = new VMdEdit(m_file, this);
connect(dynamic_cast<VMdEdit *>(m_textEditor), &VMdEdit::headersChanged, connect(dynamic_cast<VMdEdit *>(m_textEditor), &VMdEdit::headersChanged,
this, &VEditTab::updateTocFromHeaders); this, &VEditTab::updateTocFromHeaders);
@ -67,7 +68,9 @@ void VEditTab::setupUI()
this, &VEditTab::handleTextChanged); this, &VEditTab::handleTextChanged);
m_textEditor->reloadFile(); m_textEditor->reloadFile();
addWidget(m_textEditor); addWidget(m_textEditor);
} else {
m_textEditor = NULL;
}
setupMarkdownPreview(); setupMarkdownPreview();
break; break;
@ -87,6 +90,7 @@ void VEditTab::setupUI()
void VEditTab::handleTextChanged() void VEditTab::handleTextChanged()
{ {
Q_ASSERT(m_file->isModifiable());
if (m_fileModified) { if (m_fileModified) {
return; return;
} }
@ -148,7 +152,6 @@ void VEditTab::previewByConverter()
processHoedownToc(toc); processHoedownToc(toc);
html.replace(tocExp, toc); html.replace(tocExp, toc);
document.setHtml(html); document.setHtml(html);
// Hoedown will add '\n' while Marked does not
updateTocFromHtml(toc); updateTocFromHtml(toc);
} }
@ -163,6 +166,9 @@ void VEditTab::processHoedownToc(QString &p_toc)
void VEditTab::showFileEditMode() void VEditTab::showFileEditMode()
{ {
if (!m_file->isModifiable()) {
return;
}
isEditMode = true; isEditMode = true;
// beginEdit() may change curHeader. // beginEdit() may change curHeader.
@ -191,7 +197,7 @@ bool VEditTab::closeFile(bool p_forced)
void VEditTab::editFile() void VEditTab::editFile()
{ {
if (isEditMode) { if (isEditMode || !m_file->isModifiable()) {
return; return;
} }
@ -204,7 +210,7 @@ void VEditTab::readFile()
return; return;
} }
if (m_textEditor->isModified()) { if (m_textEditor && m_textEditor->isModified()) {
// Prompt to save the changes // Prompt to save the changes
int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"), int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"),
tr("Note %1 has been modified.").arg(m_file->getName()), tr("Note %1 has been modified.").arg(m_file->getName()),
@ -226,16 +232,21 @@ void VEditTab::readFile()
return; return;
} }
} }
if (m_textEditor) {
m_textEditor->endEdit(); m_textEditor->endEdit();
}
showFileReadMode(); showFileReadMode();
} }
bool VEditTab::saveFile() bool VEditTab::saveFile()
{ {
bool ret;
if (!isEditMode || !m_textEditor->isModified()) { if (!isEditMode || !m_textEditor->isModified()) {
return true; return true;
} }
bool ret;
// Make sure the file already exists. Temporary deal with cases when user delete or move // Make sure the file already exists. Temporary deal with cases when user delete or move
// a file. // a file.
QString filePath = m_file->retrivePath(); QString filePath = m_file->retrivePath();
@ -580,8 +591,10 @@ void VEditTab::clearSearchedWordHighlight()
if (webPreviewer) { if (webPreviewer) {
webPreviewer->findText(""); webPreviewer->findText("");
} }
if (m_textEditor) {
m_textEditor->clearSearchedWordHighlight(); m_textEditor->clearSearchedWordHighlight();
} }
}
bool VEditTab::checkToc() bool VEditTab::checkToc()
{ {

View File

@ -333,7 +333,8 @@ void VEditWindow::updateTabInfo(int p_index)
const VFile *file = editor->getFile(); const VFile *file = editor->getFile();
bool editMode = editor->getIsEditMode(); 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)); setTabToolTip(p_index, generateTooltip(file));
setTabIcon(p_index, editMode ? QIcon(":/resources/icons/editing.svg") : setTabIcon(p_index, editMode ? QIcon(":/resources/icons/editing.svg") :
QIcon(":/resources/icons/reading.svg")); QIcon(":/resources/icons/reading.svg"));
@ -344,7 +345,8 @@ void VEditWindow::updateAllTabsSequence()
for (int i = 0; i < count(); ++i) { for (int i = 0; i < count(); ++i) {
VEditTab *editor = getTab(i); VEditTab *editor = getTab(i);
const VFile *file = editor->getFile(); 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; return;
} }
m_locateAct->setData(tab); m_locateAct->setData(tab);
VEditTab *editor = getTab(tab);
QPointer<VFile> file = editor->getFile();
if (file->getType() == FileType::Normal) {
menu.addAction(m_locateAct); menu.addAction(m_locateAct);
}
int totalWin = m_editArea->windowCount(); int totalWin = m_editArea->windowCount();
if (totalWin > 1) { if (totalWin > 1) {
@ -448,8 +454,10 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos)
menu.addAction(m_moveRightAct); menu.addAction(m_moveRightAct);
} }
if (!menu.actions().isEmpty()) {
menu.exec(bar->mapToGlobal(p_pos)); menu.exec(bar->mapToGlobal(p_pos));
} }
}
void VEditWindow::tabListJump(VFile *p_file) void VEditWindow::tabListJump(VFile *p_file)
{ {
@ -598,8 +606,10 @@ void VEditWindow::handleLocateAct()
int tab = m_locateAct->data().toInt(); int tab = m_locateAct->data().toInt();
VEditTab *editor = getTab(tab); VEditTab *editor = getTab(tab);
QPointer<VFile> file = editor->getFile(); QPointer<VFile> file = editor->getFile();
if (file->getType() == FileType::Normal) {
vnote->getMainWindow()->locateFile(file); vnote->getMainWindow()->locateFile(file);
} }
}
void VEditWindow::handleMoveLeftAct() void VEditWindow::handleMoveLeftAct()
{ {

View File

@ -96,7 +96,7 @@ private:
void noticeStatus(int index); void noticeStatus(int index);
inline QString generateTooltip(const VFile *p_file) const; inline QString generateTooltip(const VFile *p_file) const;
inline QString generateTabText(int p_index, const QString &p_name, inline QString generateTabText(int p_index, const QString &p_name,
bool p_modified) const; bool p_modified, bool p_modifiable) const;
bool canRemoveSplit(); bool canRemoveSplit();
void moveTabOneSplit(int p_tabIdx, bool p_right); void moveTabOneSplit(int p_tabIdx, bool p_right);
void updateTabInfo(int p_idx); 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, 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); 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 #endif // VEDITWINDOW_H

View File

@ -5,9 +5,15 @@
#include <QTextEdit> #include <QTextEdit>
#include "utils/vutils.h" #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), : 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"; 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;
}

View File

@ -3,7 +3,6 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QDir>
#include "vdirectory.h" #include "vdirectory.h"
#include "vconstants.h" #include "vconstants.h"
@ -13,35 +12,37 @@ class VFile : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VFile(const QString &p_name, QObject *p_parent); VFile(const QString &p_name, QObject *p_parent,
bool open(); FileType p_type = FileType::Normal, bool p_modifiable = true);
void close(); virtual ~VFile();
bool save(); virtual bool open();
virtual void close();
virtual bool save();
// Convert current file type. // 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; const QString &getName() const;
void setName(const QString &p_name); virtual void setName(const QString &p_name);
inline VDirectory *getDirectory(); virtual VDirectory *getDirectory();
inline const VDirectory *getDirectory() const; virtual const VDirectory *getDirectory() const;
inline DocType getDocType() const; DocType getDocType() const;
inline const QString &getContent() const; const QString &getContent() const;
inline void setContent(const QString &p_content); virtual void setContent(const QString &p_content);
inline VNotebook *getNotebook(); virtual VNotebook *getNotebook();
inline QString getNotebookName() const; virtual QString getNotebookName() const;
inline QString retrivePath() const; virtual QString retrivePath() const;
inline QString retriveRelativePath() const; virtual QString retriveRelativePath() const;
inline QString retriveBasePath() const; virtual QString retriveBasePath() const;
inline QString retriveImagePath() const; virtual QString retriveImagePath() const;
inline bool isModified() const; bool isModified() const;
inline bool isOpened() const; bool isModifiable() const;
bool isOpened() const;
signals: FileType getType() const;
public slots: public slots:
void setModified(bool p_modified); void setModified(bool p_modified);
private: protected:
// Delete the file and corresponding images // Delete the file and corresponding images
void deleteDiskFile(); void deleteDiskFile();
// Delete local images in ./images of DocType::Markdown // Delete local images in ./images of DocType::Markdown
@ -53,81 +54,10 @@ private:
bool m_modified; bool m_modified;
DocType m_docType; DocType m_docType;
QString m_content; QString m_content;
FileType m_type;
bool m_modifiable;
friend class VDirectory; 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 #endif // VFILE_H

View File

@ -279,16 +279,24 @@ void VMainWindow::initMenuBar()
void VMainWindow::initHelpMenu() void VMainWindow::initHelpMenu()
{ {
QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); 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); 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, connect(aboutAct, &QAction::triggered,
this, &VMainWindow::aboutMessage); this, &VMainWindow::aboutMessage);
QAction *aboutQtAct = new QAction(tr("About &Qt"), this); 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, connect(aboutQtAct, &QAction::triggered,
qApp, &QApplication::aboutQt); qApp, &QApplication::aboutQt);
helpMenu->addAction(shortcutAct);
helpMenu->addAction(aboutQtAct); helpMenu->addAction(aboutQtAct);
helpMenu->addAction(aboutAct); helpMenu->addAction(aboutAct);
} }
@ -786,46 +794,23 @@ void VMainWindow::setRenderBackgroundColor(QAction *action)
void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file, void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
bool p_editMode) bool p_editMode)
{ {
if (p_file) { editNoteAct->setVisible(p_file && p_file->isModifiable() && !p_editMode);
if (p_editMode) { discardExitAct->setVisible(p_file && p_editMode);
editNoteAct->setVisible(false); saveExitAct->setVisible(p_file && p_editMode);
discardExitAct->setVisible(true); saveNoteAct->setVisible(p_file && p_editMode);
saveExitAct->setVisible(true); deleteNoteAct->setEnabled(p_file && p_file->isModifiable());
saveNoteAct->setVisible(true); noteInfoAct->setEnabled(p_file && p_file->getType() == FileType::Normal);
deleteNoteAct->setEnabled(true);
m_insertImageAct->setEnabled(true); m_insertImageAct->setEnabled(p_file && p_editMode);
} else {
editNoteAct->setVisible(true);
discardExitAct->setVisible(false);
saveExitAct->setVisible(false);
saveNoteAct->setVisible(false);
deleteNoteAct->setEnabled(true);
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 // Find/Replace
m_findReplaceAct->setEnabled(false); m_findReplaceAct->setEnabled(p_file);
m_findNextAct->setEnabled(false); m_findNextAct->setEnabled(p_file);
m_findPreviousAct->setEnabled(false); m_findPreviousAct->setEnabled(p_file);
m_replaceAct->setEnabled(false); m_replaceAct->setEnabled(p_file && p_editMode);
m_replaceFindAct->setEnabled(false); m_replaceFindAct->setEnabled(p_file && p_editMode);
m_replaceAllAct->setEnabled(false); m_replaceAllAct->setEnabled(p_file && p_editMode);
if (!p_file) {
m_findReplaceDialog->closeDialog(); m_findReplaceDialog->closeDialog();
} }
} }
@ -840,9 +825,13 @@ void VMainWindow::handleCurTabStatusChanged(const VFile *p_file, const VEditTab
QString title; QString title;
if (p_file) { if (p_file) {
title = QString("[%1] %2").arg(p_file->getNotebookName()).arg(p_file->retrivePath()); title = QString("[%1] %2").arg(p_file->getNotebookName()).arg(p_file->retrivePath());
if (p_file->isModifiable()) {
if (p_file->isModified()) { if (p_file->isModified()) {
title.append('*'); title.append('*');
} }
} else {
title.append('#');
}
} }
updateWindowTitle(title); updateWindowTitle(title);
m_curFile = const_cast<VFile *>(p_file); m_curFile = const_cast<VFile *>(p_file);
@ -924,13 +913,17 @@ void VMainWindow::updateWindowTitle(const QString &str)
void VMainWindow::curEditFileInfo() void VMainWindow::curEditFileInfo()
{ {
Q_ASSERT(m_curFile); if (!m_curFile || m_curFile->getType() != FileType::Normal) {
return;
}
fileList->fileInfo(m_curFile); fileList->fileInfo(m_curFile);
} }
void VMainWindow::deleteCurNote() void VMainWindow::deleteCurNote()
{ {
Q_ASSERT(m_curFile); if (!m_curFile || !m_curFile->isModifiable()) {
return;
}
fileList->deleteFile(m_curFile); fileList->deleteFile(m_curFile);
} }
@ -1028,7 +1021,7 @@ void VMainWindow::insertImage()
void VMainWindow::locateFile(VFile *p_file) void VMainWindow::locateFile(VFile *p_file)
{ {
if (!p_file) { if (!p_file || p_file->getType() != FileType::Normal) {
return; return;
} }
qDebug() << "locate file" << p_file->retrivePath(); 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);
}

View File

@ -47,6 +47,7 @@ private slots:
void viewSettings(); void viewSettings();
void changeMarkdownConverter(QAction *action); void changeMarkdownConverter(QAction *action);
void aboutMessage(); void aboutMessage();
void shortcutHelp();
void changeExpandTab(bool checked); void changeExpandTab(bool checked);
void setTabStopWidth(QAction *action); void setTabStopWidth(QAction *action);
void setEditorBackgroundColor(QAction *action); void setEditorBackgroundColor(QAction *action);

View File

@ -11,6 +11,7 @@
#include "utils/vutils.h" #include "utils/vutils.h"
#include "vconfigmanager.h" #include "vconfigmanager.h"
#include "vmainwindow.h" #include "vmainwindow.h"
#include "vorphanfile.h"
extern VConfigManager vconfig; 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_mermaidDarkCssFile = ":/utils/mermaid/mermaid.dark.css";
const QString VNote::c_mermaidForestCssFile = ":/utils/mermaid/mermaid.forest.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_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) VNote::VNote(QObject *parent)
: QObject(parent), m_mainWindow(dynamic_cast<VMainWindow *>(parent)) : QObject(parent), m_mainWindow(dynamic_cast<VMainWindow *>(parent))
@ -231,3 +234,25 @@ const QString &VNote::getMonospacedFont() const
} }
return font; 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;
}

View File

@ -3,6 +3,7 @@
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#include <QList>
#include <QSettings> #include <QSettings>
#include <QFont> #include <QFont>
#include <QObject> #include <QObject>
@ -13,6 +14,7 @@
#include "vconstants.h" #include "vconstants.h"
class VMainWindow; class VMainWindow;
class VFile;
class VNote : public QObject class VNote : public QObject
{ {
@ -49,6 +51,9 @@ public:
// Mathjax // Mathjax
static const QString c_mathjaxJsFile; static const QString c_mathjaxJsFile;
static const QString c_shortcutsDocFile_en;
static const QString c_shortcutsDocFile_zh;
inline const QVector<QPair<QString, QString> > &getPalette() const; inline const QVector<QPair<QString, QString> > &getPalette() const;
void initPalette(QPalette palette); void initPalette(QPalette palette);
QString getColorFromPalette(const QString &p_name) const; QString getColorFromPalette(const QString &p_name) const;
@ -56,6 +61,9 @@ public:
QString getNavigationLabelStyle(const QString &p_str) const; 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: public slots:
void updateTemplate(); void updateTemplate();
@ -66,6 +74,10 @@ private:
QVector<VNotebook *> m_notebooks; QVector<VNotebook *> m_notebooks;
QVector<QPair<QString, QString> > m_palette; QVector<QPair<QString, QString> > m_palette;
VMainWindow *m_mainWindow; VMainWindow *m_mainWindow;
// Hold all external file: Orphan File.
// Need to clean up periodly.
QList<VFile *> m_externalFiles;
}; };
inline const QVector<QPair<QString, QString> >& VNote::getPalette() const inline const QVector<QPair<QString, QString> >& VNote::getPalette() const

View File

@ -97,5 +97,7 @@
<file>resources/icons/close_red.svg</file> <file>resources/icons/close_red.svg</file>
<file>resources/icons/close_grey.svg</file> <file>resources/icons/close_grey.svg</file>
<file>resources/icons/float.svg</file> <file>resources/icons/float.svg</file>
<file>resources/docs/shortcuts_en.md</file>
<file>resources/docs/shortcuts_zh.md</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -83,7 +83,13 @@ void VOpenedListMenu::updateOpenedList()
if (curNotebook != notebook || file->getDirectory() != directory) { if (curNotebook != notebook || file->getDirectory() != directory) {
notebook = curNotebook; notebook = curNotebook;
directory = file->getDirectory(); 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); QAction *sepAct = addSection(text);
sepAct->setFont(sepFont); sepAct->setFont(sepFont);
} }

89
src/vorphanfile.cpp Normal file
View File

@ -0,0 +1,89 @@
#include "vorphanfile.h"
#include <QDebug>
#include <QTextEdit>
#include <QFileInfo>
#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);
}

33
src/vorphanfile.h Normal file
View File

@ -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