support custom shortcuts

This commit is contained in:
Le Tan 2017-07-10 21:15:04 +08:00
parent 301879c50c
commit ba84489c68
10 changed files with 281 additions and 15 deletions

View File

@ -72,6 +72,36 @@ 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.
## Custom Shortcuts
VNote supports customing some standard shortcuts, though it is not recommended. VNote stores shortcuts' configuration information in the `[shortcuts]` section of user configuration file `vnote.ini`.
For example, the default configruation may look like this:
```ini
[shortcuts]
1\operation=NewNote
1\keysequence=Ctrl+N
2\operation=SaveNote
2\keysequence=Ctrl+S
3\operation=SaveAndRead
3\keysequence=Ctrl+T
4\operation=EditNote
4\keysequence=Ctrl+W
5\operation=CloseNote
5\keysequence=
6\operation=Find
6\keysequence=Ctrl+F
7\operation=FindNext
7\keysequence=F3
8\operation=FindPrevious
8\keysequence=Shift+F3
size=8
```
`size=8` tells VNote that there are 8 shotcuts defined here, with each beginning with the number sequence. You could change the `keysequence` value to change the default key sequence of a specified operation. Leave the `keysequence` empty (`keysequence=`) to disable shortcut for that operation.
Pay attention that `Ctrl+E` is reserved for *Captain Mode* and `Ctrl+Q` is reserved for quitting VNote.
# Captain Mode
To efficiently utilize the shortcuts, VNote supports the **Captain Mode**.
@ -117,7 +147,7 @@ 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.
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.
# Vim Mode
VNote supports a simple but useful Vim mode, including **Normal**, **Insert**, **Visual**, and **VisualLine** modes.

View File

@ -72,6 +72,37 @@
- `Ctrl+Shift+Home`, `Ctrl+Shift+End`
扩展选定到笔记开始或结尾处。
## 自定义快捷键
VNote支持自定义部分标准快捷键但并不建议这么做。VNote将快捷键信息保存在用户配置文件`vnote.ini`中的`[shortcuts]`小节。
例如,默认的配置可能是这样子的:
```ini
[shortcuts]
1\operation=NewNote
1\keysequence=Ctrl+N
2\operation=SaveNote
2\keysequence=Ctrl+S
3\operation=SaveAndRead
3\keysequence=Ctrl+T
4\operation=EditNote
4\keysequence=Ctrl+W
5\operation=CloseNote
5\keysequence=
6\operation=Find
6\keysequence=Ctrl+F
7\operation=FindNext
7\keysequence=F3
8\operation=FindPrevious
8\keysequence=Shift+F3
size=8
```
`size=8` 告诉VNote这里定义了8组快捷键每组快捷键都以一个数字序号开始。通过改变每组快捷键中`keysequence`的值来改变某个操作的默认快捷键。将`keysequence`设置为空(`keysequence=`)则会禁用该操作的任何快捷键。
注意,`Ctrl+E`保留作为*舰长模式*的前导键,`Ctrl+Q`保留为退出VNote。
# 舰长模式
为了更有效地利用快捷键VNote支持 **舰长模式**

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M443.6,387.1L312.4,255.4l131.5-130c5.4-5.4,5.4-14.2,0-19.6l-37.4-37.6c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4
L256,197.8L124.9,68.3c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4L68,105.9c-5.4,5.4-5.4,14.2,0,19.6l131.5,130L68.4,387.1
c-2.6,2.6-4.1,6.1-4.1,9.8c0,3.7,1.4,7.2,4.1,9.8l37.4,37.6c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1L256,313.1l130.7,131.1
c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1l37.4-37.6c2.6-2.6,4.1-6.1,4.1-9.8C447.7,393.2,446.2,389.7,443.6,387.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 984 B

View File

@ -13,7 +13,7 @@ editor
# Do not use "" to quote the name
font-family: Hiragino Sans GB, 冬青黑体, Microsoft YaHei, 微软雅黑, Microsoft YaHei UI, WenQuanYi Micro Hei, 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, Liberation Sans, Droid Sans, NSimSun, 新宋体, SimSun, 宋体, Helvetica, sans-serif, Tahoma, Arial, Verdana, Geneva, Georgia, Times New Roman
# [VNote] Style for trailing space
trailing-space: ffebee
trailing-space: a8a8a8
font-size: 12
line-number-background: bdbdbd
line-number-foreground: 424242

View File

@ -70,3 +70,27 @@ tools_dock_checked=true
4\name=LightGrey
4\rgb=D3D3D3
size=4
[shortcuts]
; Define shortcuts here, with each item in the form "operation->keysequence".
; Leave keysequence empty to disable the shortcut of an operation.
; Custom shortcuts may conflict with some key bindings in edit mode or Vim mode.
; Ctrl+E is reserved for Captain Mode.
; Ctrl+Q is reserved for quitting VNote.
1\operation=NewNote
1\keysequence=Ctrl+N
2\operation=SaveNote
2\keysequence=Ctrl+S
3\operation=SaveAndRead
3\keysequence=Ctrl+T
4\operation=EditNote
4\keysequence=Ctrl+W
5\operation=CloseNote
5\keysequence=
6\operation=Find
6\keysequence=Ctrl+F
7\operation=FindNext
7\keysequence=F3
8\operation=FindPrevious
8\keysequence=Shift+F3
size=8

View File

@ -153,6 +153,8 @@ void VConfigManager::initialize()
m_editorLineNumber = getConfigFromSettings("global",
"editor_line_number").toInt();
readShortcutsFromSettings();
}
void VConfigManager::readPredefinedColorsFromSettings()
@ -338,7 +340,7 @@ void VConfigManager::updateMarkdownEditStyle()
static const QString defaultVimInsertBg = "#CDC0B0";
static const QString defaultVimVisualBg = "#90CAF9";
static const QString defaultVimReplaceBg = "#F8BBD0";
static const QString defaultTrailingSpaceBackground = "#FFEBEE";
static const QString defaultTrailingSpaceBackground = "#A8A8A8";
static const QString defaultLineNumberBg = "#BDBDBD";
static const QString defaultLineNumberFg = "#424242";
@ -483,6 +485,13 @@ QString VConfigManager::getConfigFolder() const
return VUtils::basePathFromPath(iniPath);
}
QString VConfigManager::getConfigFilePath() const
{
V_ASSERT(userSettings);
return userSettings->fileName();
}
QString VConfigManager::getStyleConfigFolder() const
{
return getConfigFolder() + QDir::separator() + c_styleConfigFolder;
@ -690,3 +699,85 @@ QString VConfigManager::getVnoteNotebookFolderPath()
{
return QDir::home().filePath(c_vnoteNotebookFolderName);
}
bool VConfigManager::isValidKeySequence(const QString &p_seq)
{
QString lower = p_seq.toLower();
return lower != "ctrl+q" && lower != "ctrl+e";
}
void VConfigManager::readShortcutsFromSettings()
{
m_shortcuts.clear();
int size = defaultSettings->beginReadArray("shortcuts");
for (int i = 0; i < size; ++i) {
defaultSettings->setArrayIndex(i);
QString op = defaultSettings->value("operation").toString();
QString seq = defaultSettings->value("keysequence").toString().trimmed();
if (isValidKeySequence(seq)) {
qDebug() << "read shortcut config" << op << seq;
m_shortcuts[op] = seq;
}
}
defaultSettings->endArray();
// Whether we need to update user settings.
bool needUpdate = false;
size = userSettings->beginReadArray("shortcuts");
QSet<QString> matched;
matched.reserve(m_shortcuts.size());
for (int i = 0; i < size; ++i) {
userSettings->setArrayIndex(i);
QString op = userSettings->value("operation").toString();
QString seq = userSettings->value("keysequence").toString().trimmed();
if (isValidKeySequence(seq)) {
qDebug() << "read user shortcut config" << op << seq;
auto it = m_shortcuts.find(op);
if (it == m_shortcuts.end()) {
// Could not find this in default settings.
needUpdate = true;
} else {
matched.insert(op);
*it = seq;
}
}
}
userSettings->endArray();
if (needUpdate || matched.size() < m_shortcuts.size()) {
// Write the combined config to user settings.
writeShortcutsToSettings();
}
}
void VConfigManager::writeShortcutsToSettings()
{
// Clear it first
userSettings->beginGroup("shortcuts");
userSettings->remove("");
userSettings->endGroup();
userSettings->beginWriteArray("shortcuts");
int idx = 0;
for (auto it = m_shortcuts.begin(); it != m_shortcuts.end(); ++it, ++idx) {
userSettings->setArrayIndex(idx);
userSettings->setValue("operation", it.key());
userSettings->setValue("keysequence", it.value());
}
userSettings->endArray();
}
QString VConfigManager::getShortcutKeySequence(const QString &p_operation) const
{
auto it = m_shortcuts.find(p_operation);
if (it == m_shortcuts.end()) {
return QString();
}
return *it;
}

View File

@ -205,9 +205,16 @@ public:
const QString &getEditorLineNumberBg() const;
const QString &getEditorLineNumberFg() const;
// Return the configured key sequence of @p_operation.
// Return empty if there is no corresponding config.
QString getShortcutKeySequence(const QString &p_operation) const;
// Get the folder the ini file exists.
QString getConfigFolder() const;
// Get the ini config file path.
QString getConfigFilePath() const;
// Get the folder c_styleConfigFolder in the config folder.
QString getStyleConfigFolder() const;
@ -248,6 +255,20 @@ private:
// the new one; if not, use the c_dirConfigFile.
static QString fetchDirConfigFilePath(const QString &p_path);
// Read the [shortcuts] section in settings to init m_shortcuts.
// Will remove invalid config items.
// First read the config in default settings;
// Second read the config in user settings and overwrite the default ones;
// If there is any config in deafult settings that is absent in user settings,
// write the combined configs to user settings.
void readShortcutsFromSettings();
// Write m_shortcuts to the [shortcuts] section in the user settings.
void writeShortcutsToSettings();
// Whether @p_seq is a valid key sequence for shortcuts.
bool isValidKeySequence(const QString &p_seq);
// Default font and palette.
QFont m_defaultEditFont;
QPalette m_defaultEditPalette;
@ -379,6 +400,10 @@ private:
// The foreground color of the line number area.
QString m_editorLineNumberFg;
// Shortcuts config.
// Operation -> KeySequence.
QHash<QString, QString> m_shortcuts;
// The name of the config file in each directory, obsolete.
// Use c_dirConfigFile instead.
static const QString c_obsoleteDirConfigFile;

View File

@ -301,7 +301,9 @@ void VMainWindow::initFileToolBar()
newNoteAct = new QAction(QIcon(":/resources/icons/create_note_tb.svg"),
tr("New &Note"), this);
newNoteAct->setStatusTip(tr("Create a note in current folder"));
newNoteAct->setShortcut(QKeySequence::New);
QString keySeq = vconfig.getShortcutKeySequence("NewNote");
qDebug() << "set NewNote shortcut to" << keySeq;
newNoteAct->setShortcut(QKeySequence(keySeq));
connect(newNoteAct, &QAction::triggered,
fileList, &VFileList::newFile);
@ -317,10 +319,25 @@ void VMainWindow::initFileToolBar()
connect(deleteNoteAct, &QAction::triggered,
this, &VMainWindow::deleteCurNote);
m_closeNoteAct = new QAction(QIcon(":/resources/icons/close_note_tb.svg"),
tr("&Close Note"), this);
m_closeNoteAct->setStatusTip(tr("Close current note"));
keySeq = vconfig.getShortcutKeySequence("CloseNote");
qDebug() << "set CloseNote shortcut to" << keySeq;
m_closeNoteAct->setShortcut(QKeySequence(keySeq));
connect(m_closeNoteAct, &QAction::triggered,
this, [this](){
if (m_curFile) {
editArea->closeFile(m_curFile, false);
}
});
editNoteAct = new QAction(QIcon(":/resources/icons/edit_note.svg"),
tr("&Edit"), this);
editNoteAct->setStatusTip(tr("Edit current note"));
editNoteAct->setShortcut(QKeySequence("Ctrl+W"));
keySeq = vconfig.getShortcutKeySequence("EditNote");
qDebug() << "set EditNote shortcut to" << keySeq;
editNoteAct->setShortcut(QKeySequence(keySeq));
connect(editNoteAct, &QAction::triggered,
editArea, &VEditArea::editFile);
@ -339,21 +356,26 @@ void VMainWindow::initFileToolBar()
tr("Save Changes And Read (Ctrl+T)"), this);
saveExitAct->setStatusTip(tr("Save changes and exit edit mode"));
saveExitAct->setMenu(exitEditMenu);
saveExitAct->setShortcut(QKeySequence("Ctrl+T"));
keySeq = vconfig.getShortcutKeySequence("SaveAndRead");
qDebug() << "set SaveAndRead shortcut to" << keySeq;
saveExitAct->setShortcut(QKeySequence(keySeq));
connect(saveExitAct, &QAction::triggered,
editArea, &VEditArea::saveAndReadFile);
saveNoteAct = new QAction(QIcon(":/resources/icons/save_note.svg"),
tr("Save"), this);
saveNoteAct->setStatusTip(tr("Save changes to current note"));
saveNoteAct->setShortcut(QKeySequence::Save);
keySeq = vconfig.getShortcutKeySequence("SaveNote");
qDebug() << "set SaveNote shortcut to" << keySeq;
saveNoteAct->setShortcut(QKeySequence(keySeq));
connect(saveNoteAct, &QAction::triggered,
editArea, &VEditArea::saveFile);
newRootDirAct->setEnabled(false);
newNoteAct->setEnabled(false);
noteInfoAct->setEnabled(false);
deleteNoteAct->setEnabled(false);
noteInfoAct->setVisible(false);
deleteNoteAct->setVisible(false);
m_closeNoteAct->setVisible(false);
editNoteAct->setVisible(false);
saveExitAct->setVisible(false);
discardExitAct->setVisible(false);
@ -361,9 +383,10 @@ void VMainWindow::initFileToolBar()
fileToolBar->addAction(newRootDirAct);
fileToolBar->addAction(newNoteAct);
fileToolBar->addSeparator();
fileToolBar->addAction(noteInfoAct);
fileToolBar->addAction(deleteNoteAct);
fileToolBar->addSeparator();
fileToolBar->addAction(m_closeNoteAct);
fileToolBar->addAction(editNoteAct);
fileToolBar->addAction(saveExitAct);
fileToolBar->addAction(saveNoteAct);
@ -634,6 +657,29 @@ void VMainWindow::initFileMenu()
fileMenu->addAction(settingsAct);
QAction *customShortcutAct = new QAction(tr("Custom Shortcuts"), this);
customShortcutAct->setToolTip(tr("Custom some standard shortcuts"));
connect(customShortcutAct, &QAction::triggered,
this, [this](){
int ret = VUtils::showMessage(QMessageBox::Information,
tr("Custom Shortcuts"),
tr("VNote supports customing some standard shorcuts by "
"editing user's configuration file (vnote.ini). Please "
"reference the shortcuts help documentation for more "
"information."),
tr("Click \"OK\" to custom shortcuts."),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok,
this);
if (ret == QMessageBox::Ok) {
QUrl url = QUrl::fromLocalFile(vconfig.getConfigFilePath());
QDesktopServices::openUrl(url);
}
});
fileMenu->addAction(customShortcutAct);
fileMenu->addSeparator();
// Exit.
@ -663,19 +709,25 @@ void VMainWindow::initEditMenu()
m_findReplaceAct = newAction(QIcon(":/resources/icons/find_replace.svg"),
tr("Find/Replace"), this);
m_findReplaceAct->setToolTip(tr("Open Find/Replace dialog to search in current note"));
m_findReplaceAct->setShortcut(QKeySequence::Find);
QString keySeq = vconfig.getShortcutKeySequence("Find");
qDebug() << "set Find shortcut to" << keySeq;
m_findReplaceAct->setShortcut(QKeySequence(keySeq));
connect(m_findReplaceAct, &QAction::triggered,
this, &VMainWindow::openFindDialog);
m_findNextAct = new QAction(tr("Find Next"), this);
m_findNextAct->setToolTip(tr("Find next occurence"));
m_findNextAct->setShortcut(QKeySequence::FindNext);
keySeq = vconfig.getShortcutKeySequence("FindNext");
qDebug() << "set FindNext shortcut to" << keySeq;
m_findNextAct->setShortcut(QKeySequence(keySeq));
connect(m_findNextAct, SIGNAL(triggered(bool)),
m_findReplaceDialog, SLOT(findNext()));
m_findPreviousAct = new QAction(tr("Find Previous"), this);
m_findPreviousAct->setToolTip(tr("Find previous occurence"));
m_findPreviousAct->setShortcut(QKeySequence::FindPrevious);
keySeq = vconfig.getShortcutKeySequence("FindPrevious");
qDebug() << "set FindPrevious shortcut to" << keySeq;
m_findPreviousAct->setShortcut(QKeySequence(keySeq));
connect(m_findPreviousAct, SIGNAL(triggered(bool)),
m_findReplaceDialog, SLOT(findPrevious()));
@ -1279,8 +1331,9 @@ void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
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);
deleteNoteAct->setVisible(p_file && p_file->isModifiable());
noteInfoAct->setVisible(p_file && p_file->getType() == FileType::Normal);
m_closeNoteAct->setVisible(p_file);
m_insertImageAct->setEnabled(p_file && p_editMode);

View File

@ -178,6 +178,7 @@ private:
QAction *newNoteAct;
QAction *noteInfoAct;
QAction *deleteNoteAct;
QAction *m_closeNoteAct;
QAction *editNoteAct;
QAction *saveNoteAct;
QAction *saveExitAct;

View File

@ -115,5 +115,6 @@
<file>resources/icons/italic.svg</file>
<file>resources/icons/strikethrough.svg</file>
<file>resources/icons/inline_code.svg</file>
<file>resources/icons/close_note_tb.svg</file>
</qresource>
</RCC>