refactor Captain mode

- Configuration [shortcuts] and [captain_mode_shortcuts] for shortcuts
and shortcuts in Captain mode.
This commit is contained in:
Le Tan 2017-10-18 19:53:46 +08:00
parent 34aa9e0083
commit 00feaa13e2
14 changed files with 996 additions and 529 deletions

View File

@ -13,7 +13,6 @@
#include "vconfigmanager.h" #include "vconfigmanager.h"
VConfigManager *g_config; VConfigManager *g_config;
VMainWindow *g_mainWin;
#if defined(QT_NO_DEBUG) #if defined(QT_NO_DEBUG)
QFile g_logFile; QFile g_logFile;
@ -157,7 +156,6 @@ int main(int argc, char *argv[])
} }
VMainWindow w(&guard); VMainWindow w(&guard);
g_mainWin = &w;
QString style = VUtils::readFileFromDisk(":/resources/vnote.qss"); QString style = VUtils::readFileFromDisk(":/resources/vnote.qss");
if (!style.isEmpty()) { if (!style.isEmpty()) {
VUtils::processStyle(style, w.getPalette()); VUtils::processStyle(style, w.getPalette());

View File

@ -80,42 +80,102 @@ Expand the selection to the beginning or end of current line.
Expand the selection to the beginning or end of current note. Expand the selection to the beginning or end of current note.
## Custom Shortcuts ## 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`. VNote supports customing some standard shortcuts, though it is not recommended. VNote stores shortcuts' configuration information in the `[shortcuts]` and `[captain_mode_shortcuts]` sections of user configuration file `vnote.ini`.
For example, the default configruation may look like this: For example, the default configruation may look like this:
```ini ```ini
[shortcuts] [shortcuts]
1\operation=NewNote ; Define shortcuts here, with each item in the form "operation=keysequence".
1\keysequence=Ctrl+N ; Leave keysequence empty to disable the shortcut of an operation.
2\operation=SaveNote ; Custom shortcuts may conflict with some key bindings in edit mode or Vim mode.
2\keysequence=Ctrl+S ; Ctrl+Q is reserved for quitting VNote.
3\operation=SaveAndRead
3\keysequence=Ctrl+T ; Leader key of Captain mode
4\operation=EditNote CaptainMode=Ctrl+E
4\keysequence=Ctrl+W ; Create a note in current folder
5\operation=CloseNote NewNote=Ctrl+Alt+N
5\keysequence= ; Save current note
6\operation=Find SaveNote=Ctrl+S
6\keysequence=Ctrl+F ; Save changes and enter read mode
7\operation=FindNext SaveAndRead=Ctrl+T
7\keysequence=F3 ; Edit current note
8\operation=FindPrevious EditNote=Ctrl+W
8\keysequence=Shift+F3 ; Close current note
size=8 CloseNote=
; Open file/replace dialog
Find=Ctrl+F
; Find next occurence
FindNext=F3
; Find previous occurence
FindPrevious=Shift+F3
[captain_mode_shortcuts]
; Define shortcuts in Captain mode here.
; There shortcuts are the sub-sequence after the CaptainMode key sequence
; in [shortcuts].
; Enter Navigation mode
NavigationMode=W
; Show attachment list of current note
AttachmentList=A
; Locate to the folder of current note
LocateCurrentFile=D
; Toggle Expand mode
ExpandMode=E
; Alternate one/two panels view
OnePanelView=P
; Discard changes and enter read mode
DiscardAndRead=Q
; Toggle Tools dock widget
ToolsDock=T
; Close current note
CloseNote=X
; Show shortcuts help document
ShortcutsHelp=?
; Flush the log file
FlushLogFile=";"
; Show opened files list
OpenedFileList=F
; Activate the ith tab
ActivateTab1=1
ActivateTab2=2
ActivateTab3=3
ActivateTab4=4
ActivateTab5=5
ActivateTab6=6
ActivateTab7=7
ActivateTab8=8
ActivateTab9=9
; Alternate between current and last tab
AlternateTab=0
; Activate next tab
ActivateNextTab=J
; Activate previous tab
ActivatePreviousTab=K
; Activate the window split on the left
ActivateSplitLeft=H
; Activate the window split on the right
ActivateSplitRight=L
; Move current tab one split left
MoveTabSplitLeft=Shift+H
; Move current tab one split right
MoveTabSplitRight=Shift+L
; Create a vertical split
VerticalSplit=V
; Remove current split
RemoveSplit=R
``` ```
`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. Each item is in the form `operation=keysequence`, with `keysequence` empty to disable shortcuts for that operation.
Pay attention that `Ctrl+E` is reserved for *Captain Mode* and `Ctrl+Q` is reserved for quitting VNote. Pay attention that `Ctrl+Q` is reserved for quitting VNote.
# Captain Mode # Captain Mode
To efficiently utilize the shortcuts, VNote supports the **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. 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` - `E`
Toggle expanding the edit area. Toggle expanding the edit area.
- `P` - `P`

View File

@ -80,43 +80,103 @@
扩展选定到笔记开始或结尾处。 扩展选定到笔记开始或结尾处。
## 自定义快捷键 ## 自定义快捷键
VNote支持自定义部分标准快捷键但并不建议这么做。VNote将快捷键信息保存在用户配置文件`vnote.ini`中的`[shortcuts]`小节。 VNote支持自定义部分标准快捷键但并不建议这么做。VNote将快捷键信息保存在用户配置文件`vnote.ini`中的`[shortcuts]``[captain_mode_shortcuts]`两个小节。
例如,默认的配置可能是这样子的: 例如,默认的配置可能是这样子的:
```ini ```ini
[shortcuts] [shortcuts]
1\operation=NewNote ; Define shortcuts here, with each item in the form "operation=keysequence".
1\keysequence=Ctrl+N ; Leave keysequence empty to disable the shortcut of an operation.
2\operation=SaveNote ; Custom shortcuts may conflict with some key bindings in edit mode or Vim mode.
2\keysequence=Ctrl+S ; Ctrl+Q is reserved for quitting VNote.
3\operation=SaveAndRead
3\keysequence=Ctrl+T ; Leader key of Captain mode
4\operation=EditNote CaptainMode=Ctrl+E
4\keysequence=Ctrl+W ; Create a note in current folder
5\operation=CloseNote NewNote=Ctrl+Alt+N
5\keysequence= ; Save current note
6\operation=Find SaveNote=Ctrl+S
6\keysequence=Ctrl+F ; Save changes and enter read mode
7\operation=FindNext SaveAndRead=Ctrl+T
7\keysequence=F3 ; Edit current note
8\operation=FindPrevious EditNote=Ctrl+W
8\keysequence=Shift+F3 ; Close current note
size=8 CloseNote=
; Open file/replace dialog
Find=Ctrl+F
; Find next occurence
FindNext=F3
; Find previous occurence
FindPrevious=Shift+F3
[captain_mode_shortcuts]
; Define shortcuts in Captain mode here.
; There shortcuts are the sub-sequence after the CaptainMode key sequence
; in [shortcuts].
; Enter Navigation mode
NavigationMode=W
; Show attachment list of current note
AttachmentList=A
; Locate to the folder of current note
LocateCurrentFile=D
; Toggle Expand mode
ExpandMode=E
; Alternate one/two panels view
OnePanelView=P
; Discard changes and enter read mode
DiscardAndRead=Q
; Toggle Tools dock widget
ToolsDock=T
; Close current note
CloseNote=X
; Show shortcuts help document
ShortcutsHelp=?
; Flush the log file
FlushLogFile=";"
; Show opened files list
OpenedFileList=F
; Activate the ith tab
ActivateTab1=1
ActivateTab2=2
ActivateTab3=3
ActivateTab4=4
ActivateTab5=5
ActivateTab6=6
ActivateTab7=7
ActivateTab8=8
ActivateTab9=9
; Alternate between current and last tab
AlternateTab=0
; Activate next tab
ActivateNextTab=J
; Activate previous tab
ActivatePreviousTab=K
; Activate the window split on the left
ActivateSplitLeft=H
; Activate the window split on the right
ActivateSplitRight=L
; Move current tab one split left
MoveTabSplitLeft=Shift+H
; Move current tab one split right
MoveTabSplitRight=Shift+L
; Create a vertical split
VerticalSplit=V
; Remove current split
RemoveSplit=R
``` ```
`size=8` 告诉VNote这里定义了8组快捷键每组快捷键都以一个数字序号开始。通过改变每组快捷键中`keysequence`的值来改变某个操作的默认快捷键。将`keysequence`设置为空(`keysequence=`)则会禁用该操作的任何快捷键。 每一项配置的形式为`操作=按键序列`。如果`按键序列`为空,则表示禁用该操作的快捷键。
注意,`Ctrl+E`保留作为*舰长模式*的前导键,`Ctrl+Q`保留为退出VNote。 注意,`Ctrl+Q`保留为退出VNote。
# 舰长模式 # 舰长模式
为了更有效地利用快捷键VNote支持 **舰长模式** 为了更有效地利用快捷键VNote支持 **舰长模式**
按前导键`Ctrl+E`VNote会进入舰长模式。在舰长模式中VNote会支持更多高效的快捷操作。 按前导键`Ctrl+E`VNote会进入舰长模式。在舰长模式中VNote会支持更多高效的快捷操作。
另外,在该模式中,`Ctrl+W``W`是等效的,因此,可以`Ctrl+E+W`来实现`Ctrl+E W`的操作。
- `E` - `E`
是否扩展编辑区域。 是否扩展编辑区域。
- `P` - `P`

View File

@ -168,25 +168,82 @@ mathjax_javascript=https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.
size=4 size=4
[shortcuts] [shortcuts]
; Define shortcuts here, with each item in the form "operation->keysequence". ; Define shortcuts here, with each item in the form "operation=keysequence".
; Leave keysequence empty to disable the shortcut of an operation. ; Leave keysequence empty to disable the shortcut of an operation.
; Custom shortcuts may conflict with some key bindings in edit mode or Vim mode. ; 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. ; Ctrl+Q is reserved for quitting VNote.
1\operation=NewNote
1\keysequence=Ctrl+Alt+N ; Leader key of Captain mode
2\operation=SaveNote CaptainMode=Ctrl+E
2\keysequence=Ctrl+S ; Create a note in current folder
3\operation=SaveAndRead NewNote=Ctrl+Alt+N
3\keysequence=Ctrl+T ; Save current note
4\operation=EditNote SaveNote=Ctrl+S
4\keysequence=Ctrl+W ; Save changes and enter read mode
5\operation=CloseNote SaveAndRead=Ctrl+T
5\keysequence= ; Edit current note
6\operation=Find EditNote=Ctrl+W
6\keysequence=Ctrl+F ; Close current note
7\operation=FindNext CloseNote=
7\keysequence=F3 ; Open file/replace dialog
8\operation=FindPrevious Find=Ctrl+F
8\keysequence=Shift+F3 ; Find next occurence
size=8 FindNext=F3
; Find previous occurence
FindPrevious=Shift+F3
[captain_mode_shortcuts]
; Define shortcuts in Captain mode here.
; There shortcuts are the sub-sequence after the CaptainMode key sequence
; in [shortcuts].
; Enter Navigation mode
NavigationMode=W
; Show attachment list of current note
AttachmentList=A
; Locate to the folder of current note
LocateCurrentFile=D
; Toggle Expand mode
ExpandMode=E
; Alternate one/two panels view
OnePanelView=P
; Discard changes and enter read mode
DiscardAndRead=Q
; Toggle Tools dock widget
ToolsDock=T
; Close current note
CloseNote=X
; Show shortcuts help document
ShortcutsHelp=?
; Flush the log file
FlushLogFile=";"
; Show opened files list
OpenedFileList=F
; Activate the ith tab
ActivateTab1=1
ActivateTab2=2
ActivateTab3=3
ActivateTab4=4
ActivateTab5=5
ActivateTab6=6
ActivateTab7=7
ActivateTab8=8
ActivateTab9=9
; Alternate between current and last tab
AlternateTab=0
; Activate next tab
ActivateNextTab=J
; Activate previous tab
ActivatePreviousTab=K
; Activate the window split on the left
ActivateSplitLeft=H
; Activate the window split on the right
ActivateSplitRight=L
; Move current tab one split left
MoveTabSplitLeft=Shift+H
; Move current tab one split right
MoveTabSplitRight=Shift+L
; Create a vertical split
VerticalSplit=V
; Remove current split
RemoveSplit=R

View File

@ -1,6 +1,5 @@
#include <QtWidgets> #include <QtWidgets>
#include <QString> #include <QString>
#include <QTimer>
#include <QDebug> #include <QDebug>
#include <QShortcut> #include <QShortcut>
#include "vcaptain.h" #include "vcaptain.h"
@ -9,38 +8,39 @@
#include "vedittab.h" #include "vedittab.h"
#include "vfilelist.h" #include "vfilelist.h"
#include "vnavigationmode.h" #include "vnavigationmode.h"
#include "vconfigmanager.h"
extern VMainWindow *g_mainWin;
extern VConfigManager *g_config;
// 3s pending time after the leader keys. // 3s pending time after the leader keys.
const int c_pendingTime = 3 * 1000; const int c_pendingTime = 3 * 1000;
#if defined(QT_NO_DEBUG) VCaptain::VCaptain(QWidget *p_parent)
extern QFile g_logFile; : QWidget(p_parent),
#endif m_mode(CaptainMode::Normal),
m_widgetBeforeNavigation(NULL),
VCaptain::VCaptain(VMainWindow *p_parent) m_nextMajorKey('a'),
: QWidget(p_parent), m_mainWindow(p_parent), m_mode(VCaptain::Normal), m_ignoreFocusChange(false),
m_widgetBeforeCaptain(NULL), m_nextMajorKey('a'), m_ignoreFocusChange(false) m_leaderKey(g_config->getShortcutKeySequence("CaptainMode"))
{ {
m_pendingTimer = new QTimer(this); Q_ASSERT(!m_leaderKey.isEmpty());
m_pendingTimer->setSingleShot(true);
m_pendingTimer->setInterval(c_pendingTime);
connect(m_pendingTimer, &QTimer::timeout,
this, &VCaptain::pendingTimerTimeout);
connect(qApp, &QApplication::focusChanged, connect(qApp, &QApplication::focusChanged,
this, &VCaptain::handleFocusChanged); this, &VCaptain::handleFocusChanged);
QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+E"), this,
Q_NULLPTR, Q_NULLPTR);
connect(shortcut, &QShortcut::activated,
this, &VCaptain::trigger);
qApp->installEventFilter(this);
setWindowFlags(Qt::FramelessWindowHint); setWindowFlags(Qt::FramelessWindowHint);
// Make it as small as possible. This widget will stay at the top-left corner // Make it as small as possible. This widget will stay at the top-left corner
// of VMainWindow. // of VMainWindow.
resize(1, 1); resize(1, 1);
// Register Navigation mode as Captain mode target.
registerCaptainTarget(tr("NavigationMode"),
g_config->getCaptainShortcutKeySequence("NavigationMode"),
this,
navigationModeByCaptain);
} }
QChar VCaptain::getNextMajorKey() QChar VCaptain::getNextMajorKey()
@ -59,53 +59,26 @@ void VCaptain::registerNavigationTarget(VNavigationMode *p_target)
QChar key = getNextMajorKey(); QChar key = getNextMajorKey();
if (!key.isNull()) { if (!key.isNull()) {
p_target->registerNavigation(key); p_target->registerNavigation(key);
m_targets.append(NaviModeTarget(p_target, true)); m_naviTargets.push_back(NaviModeTarget(p_target, true));
} }
} }
// In pending mode, if user click other widgets, we need to exit Captain mode. void VCaptain::handleFocusChanged(QWidget *p_old, QWidget * p_now)
void VCaptain::handleFocusChanged(QWidget *p_old, QWidget * /* p_now */)
{ {
if (!m_ignoreFocusChange && p_old == this) { Q_UNUSED(p_now);
exitCaptainMode();
if (!m_ignoreFocusChange
&& !checkMode(CaptainMode::Normal)
&& p_old == this) {
exitNavigationMode();
} }
} }
void VCaptain::pendingTimerTimeout()
{
qDebug() << "Captain mode timeout";
exitCaptainMode();
restoreFocus();
}
void VCaptain::trigger()
{
if (m_mode != VCaptain::Normal) {
return;
}
qDebug() << "trigger Captain mode";
// Focus to listen pending key press.
m_widgetBeforeCaptain = QApplication::focusWidget();
setFocus();
m_mode = VCaptain::Pending;
m_pendingTimer->stop();
m_pendingTimer->start();
emit captainModeChanged(true);
}
void VCaptain::keyPressEvent(QKeyEvent *p_event) void VCaptain::keyPressEvent(QKeyEvent *p_event)
{ {
int key = p_event->key(); int key = p_event->key();
Qt::KeyboardModifiers modifiers = p_event->modifiers(); Qt::KeyboardModifiers modifiers = p_event->modifiers();
if (m_mode == VCaptain::Normal) {
// Should not in focus while in Normal mode.
QWidget::keyPressEvent(p_event);
m_mainWindow->focusNextChild();
return;
}
if (key == Qt::Key_Control || key == Qt::Key_Shift) { if (key == Qt::Key_Control || key == Qt::Key_Shift) {
QWidget::keyPressEvent(p_event); QWidget::keyPressEvent(p_event);
return; return;
@ -120,230 +93,28 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers) bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
{ {
bool ret = true; if (!checkMode(CaptainMode::Navigation)) {
return false;
}
if (p_key == Qt::Key_Escape if (p_key == Qt::Key_Escape
|| (p_key == Qt::Key_BracketLeft || (p_key == Qt::Key_BracketLeft
&& p_modifiers == Qt::ControlModifier)) { && p_modifiers == Qt::ControlModifier)) {
goto exit; exitNavigationMode();
return true;
} }
m_ignoreFocusChange = true; return handleKeyPressNavigationMode(p_key, p_modifiers);
if (m_mode == VCaptainMode::Navigation) {
ret = handleKeyPressNavigationMode(p_key, p_modifiers);
m_ignoreFocusChange = false;
return ret;
}
// In Captain mode, Ctrl key won't make a difference.
switch (p_key) {
case Qt::Key_1:
case Qt::Key_2:
case Qt::Key_3:
case Qt::Key_4:
case Qt::Key_5:
case Qt::Key_6:
case Qt::Key_7:
case Qt::Key_8:
case Qt::Key_9:
{
// Switch to tab <i>.
VEditWindow *win = m_mainWindow->editArea->getCurrentWindow();
if (win) {
int sequence = p_key - Qt::Key_0;
if (win->activateTab(sequence)) {
m_widgetBeforeCaptain = NULL;
}
}
break;
}
case Qt::Key_0:
{
// Alternate the tab.
VEditWindow *win = m_mainWindow->editArea->getCurrentWindow();
if (win) {
if (win->alternateTab()) {
m_widgetBeforeCaptain = NULL;
}
}
break;
}
case Qt::Key_A:
{
// Show attachment list of current note.
m_mainWindow->showAttachmentList();
break;
}
case Qt::Key_D:
// Locate current tab.
if (m_mainWindow->locateCurrentFile()) {
m_widgetBeforeCaptain = NULL;
}
break;
case Qt::Key_E:
// Toggle expand view.
m_mainWindow->expandViewAct->trigger();
break;
case Qt::Key_F:
{
// Show current window's opened file list.
VEditWindow *win = m_mainWindow->editArea->getCurrentWindow();
if (win) {
if (win->showOpenedFileList()) {
// showOpenedFileList() already focus the right widget.
m_widgetBeforeCaptain = NULL;
}
}
break;
}
case Qt::Key_H:
{
if (p_modifiers & Qt::ShiftModifier) {
// Move current tab one split left.
m_mainWindow->editArea->moveCurrentTabOneSplit(false);
} else {
// Focus previous window split.
int idx = m_mainWindow->editArea->focusNextWindow(-1);
if (idx > -1) {
m_widgetBeforeCaptain = NULL;
}
}
break;
}
case Qt::Key_J:
{
// Focus next tab.
VEditWindow *win = m_mainWindow->editArea->getCurrentWindow();
if (win) {
win->focusNextTab(true);
// focusNextTab() will focus the right widget.
m_widgetBeforeCaptain = NULL;
}
break;
}
case Qt::Key_K:
{
// Focus previous tab.
VEditWindow *win = m_mainWindow->editArea->getCurrentWindow();
if (win) {
win->focusNextTab(false);
// focusNextTab() will focus the right widget.
m_widgetBeforeCaptain = NULL;
}
break;
}
case Qt::Key_L:
{
if (p_modifiers & Qt::ShiftModifier) {
// Move current tab one split right.
m_mainWindow->editArea->moveCurrentTabOneSplit(true);
} else {
// Focus next window split.
int idx = m_mainWindow->editArea->focusNextWindow(1);
if (idx > -1) {
m_widgetBeforeCaptain = NULL;
}
}
break;
}
case Qt::Key_P:
// Toggle one/two panel view.
m_mainWindow->toggleOnePanelView();
break;
case Qt::Key_Q:
// Discard changes and exit edit mode.
if (m_mainWindow->m_curFile) {
m_mainWindow->discardExitAct->trigger();
}
break;
case Qt::Key_R:
{
// Remove current window split.
m_mainWindow->editArea->removeCurrentWindow();
QWidget *nextFocus = m_mainWindow->editArea->getCurrentTab();
m_widgetBeforeCaptain = nextFocus ? nextFocus : m_mainWindow->getFileList();
break;
}
case Qt::Key_T:
// Toggle the Tools dock.
m_mainWindow->toolDock->setVisible(!m_mainWindow->toolDock->isVisible());
break;
case Qt::Key_V:
// Vertical split current window.
m_mainWindow->editArea->splitCurrentWindow();
// Do not restore focus.
m_widgetBeforeCaptain = NULL;
break;
case Qt::Key_W:
// Enter navigation mode.
triggerNavigationMode();
m_ignoreFocusChange = false;
return ret;
case Qt::Key_X:
{
// Close current tab.
m_mainWindow->closeCurrentFile();
// m_widgetBeforeCaptain may be the closed tab which will cause crash.
QWidget *nextFocus = m_mainWindow->editArea->getCurrentTab();
m_widgetBeforeCaptain = nextFocus ? nextFocus : m_mainWindow->getFileList();
break;
}
case Qt::Key_Question:
{
// Display shortcuts doc.
m_mainWindow->shortcutHelp();
m_widgetBeforeCaptain = NULL;
break;
}
#if defined(QT_NO_DEBUG)
case Qt::Key_Comma:
{
// Flush g_logFile.
g_logFile.flush();
break;
}
#endif
default:
// Not implemented yet. Just exit Captain mode.
break;
}
exit:
exitCaptainMode();
restoreFocus();
return ret;
} }
bool VCaptain::handleKeyPressNavigationMode(int p_key, bool VCaptain::handleKeyPressNavigationMode(int p_key,
Qt::KeyboardModifiers /* p_modifiers */) Qt::KeyboardModifiers /* p_modifiers */)
{ {
Q_ASSERT(m_mode == VCaptainMode::Navigation); Q_ASSERT(m_mode == CaptainMode::Navigation);
bool hasConsumed = false; bool hasConsumed = false;
bool pending = false; bool pending = false;
for (auto &target : m_targets) { m_ignoreFocusChange = true;
for (auto &target : m_naviTargets) {
if (hasConsumed) { if (hasConsumed) {
target.m_available = false; target.m_available = false;
target.m_target->hideNavigation(); target.m_target->hideNavigation();
@ -351,12 +122,13 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
} }
if (target.m_available) { if (target.m_available) {
bool succeed = false; bool succeed = false;
// May change focus, so we need to ignore focus change here.
bool consumed = target.m_target->handleKeyNavigation(p_key, succeed); bool consumed = target.m_target->handleKeyNavigation(p_key, succeed);
if (consumed) { if (consumed) {
hasConsumed = true; hasConsumed = true;
if (succeed) { if (succeed) {
// Exit. // Exit.
m_widgetBeforeCaptain = NULL; m_widgetBeforeNavigation = NULL;
} else { } else {
// Consumed but not succeed. Need more keys. // Consumed but not succeed. Need more keys.
pending = true; pending = true;
@ -368,20 +140,23 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
} }
} }
} }
m_ignoreFocusChange = false;
if (pending) { if (pending) {
return true; return true;
} }
exitCaptainMode();
restoreFocus(); exitNavigationMode();
return true; return true;
} }
void VCaptain::triggerNavigationMode() void VCaptain::triggerNavigationMode()
{ {
m_pendingTimer->stop(); setMode(CaptainMode::Navigation);
m_mode = VCaptainMode::Navigation; m_widgetBeforeNavigation = QApplication::focusWidget();
// Focus to listen pending key press.
for (auto &target : m_targets) { setFocus();
for (auto &target : m_naviTargets) {
target.m_available = true; target.m_available = true;
target.m_target->showNavigation(); target.m_target->showNavigation();
} }
@ -389,51 +164,74 @@ void VCaptain::triggerNavigationMode()
void VCaptain::exitNavigationMode() void VCaptain::exitNavigationMode()
{ {
m_mode = VCaptainMode::Normal; setMode(CaptainMode::Normal);
for (auto &target : m_targets) { for (auto &target : m_naviTargets) {
target.m_available = true; target.m_available = true;
target.m_target->hideNavigation(); target.m_target->hideNavigation();
} }
}
bool VCaptain::eventFilter(QObject *p_obj, QEvent *p_event) restoreFocus();
{
if (m_mode != VCaptain::Normal && p_event->type() == QEvent::Shortcut) {
qDebug() << "filter" << p_event;
QShortcutEvent *keyEve = dynamic_cast<QShortcutEvent *>(p_event);
Q_ASSERT(keyEve);
const QKeySequence &keys = keyEve->key();
if (keys.count() == 1) {
int key = keys[0];
Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(key & (~0x01FFFFFFU));
key &= 0x01FFFFFFUL;
if (handleKeyPress(key, modifiers)) {
return true;
}
}
exitCaptainMode();
restoreFocus();
}
return QWidget::eventFilter(p_obj, p_event);
} }
void VCaptain::restoreFocus() void VCaptain::restoreFocus()
{ {
if (m_widgetBeforeCaptain) { if (m_widgetBeforeNavigation) {
m_widgetBeforeCaptain->setFocus(); m_widgetBeforeNavigation->setFocus();
} }
} }
void VCaptain::exitCaptainMode() bool VCaptain::registerCaptainTarget(const QString &p_name,
const QString &p_key,
void *p_target,
CaptainFunc p_func)
{ {
if (m_mode == VCaptainMode::Navigation) { if (p_key.isEmpty()) {
exitNavigationMode(); return false;
} }
m_mode = VCaptain::Normal;
m_pendingTimer->stop();
m_ignoreFocusChange = false;
emit captainModeChanged(false); QString lowerKey = p_key.toLower();
if (m_captainTargets.contains(lowerKey)) {
return false;
}
// Register shortcuts.
QString sequence = QString("%1,%2").arg(m_leaderKey).arg(p_key);
QShortcut *shortcut = new QShortcut(QKeySequence(sequence),
this);
shortcut->setContext(Qt::ApplicationShortcut);
connect(shortcut, &QShortcut::activated,
this, std::bind(&VCaptain::triggerCaptainTarget, this, p_key));
CaptainModeTarget target(p_name,
p_key,
p_target,
p_func,
shortcut);
m_captainTargets.insert(lowerKey, target);
qDebug() << "registered:" << target.toString() << sequence;
return true;
} }
void VCaptain::triggerCaptainTarget(const QString &p_key)
{
auto it = m_captainTargets.find(p_key.toLower());
Q_ASSERT(it != m_captainTargets.end());
const CaptainModeTarget &target = it.value();
qDebug() << "triggered:" << target.toString();
target.m_function(target.m_target, nullptr);
}
void VCaptain::navigationModeByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VCaptain *obj = static_cast<VCaptain *>(p_target);
obj->triggerNavigationMode();
}

View File

@ -1,77 +1,165 @@
#ifndef VCAPTAIN_H #ifndef VCAPTAIN_H
#define VCAPTAIN_H #define VCAPTAIN_H
#include <QWidget> #include <functional>
#include <QList>
#include <QWidget>
#include <QVector>
#include <QHash>
class QTimer;
class QKeyEvent; class QKeyEvent;
class VMainWindow;
class QEvent;
class VNavigationMode; class VNavigationMode;
// void func(void *p_target, void *p_data);
typedef std::function<void(void *, void *)> CaptainFunc;
class VCaptain : public QWidget class VCaptain : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VCaptain(VMainWindow *p_parent); explicit VCaptain(QWidget *p_parent);
// Trigger Captain mode. // Register a target for Navigation mode.
void trigger();
// Register a target for Navigation Mode.
void registerNavigationTarget(VNavigationMode *p_target); void registerNavigationTarget(VNavigationMode *p_target);
signals: // Register a target for Captain mode.
void captainModeChanged(bool p_enabled); bool registerCaptainTarget(const QString &p_name,
const QString &p_key,
void *p_target,
CaptainFunc p_func);
protected: protected:
void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
bool eventFilter(QObject *p_obj, QEvent *p_event) Q_DECL_OVERRIDE;
public slots:
private slots: private slots:
void pendingTimerTimeout(); // Exit Navigation mode if focus lost.
void handleFocusChanged(QWidget *p_old, QWidget *p_new); void handleFocusChanged(QWidget *p_old, QWidget *p_new);
private: private:
// Restore the focus to m_widgetBeforeCaptain. // A widget target for Navigation mode.
void restoreFocus(); struct NaviModeTarget {
void exitCaptainMode(); NaviModeTarget()
// Return true if finish handling the event; otherwise, let the base widget : m_target(nullptr), m_available(false)
// to handle it. {
bool handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers); }
bool handleKeyPressNavigationMode(int p_key,
Qt::KeyboardModifiers p_modifiers);
QChar getNextMajorKey();
void triggerNavigationMode();
void exitNavigationMode();
enum VCaptainMode { NaviModeTarget(VNavigationMode *p_target, bool p_available)
: m_target(p_target), m_available(p_available)
{
}
VNavigationMode *m_target;
bool m_available;
};
// Modes.
enum class CaptainMode {
Normal = 0, Normal = 0,
Pending, Pending,
Navigation Navigation
}; };
VMainWindow *m_mainWindow; struct CaptainModeTarget {
QTimer *m_pendingTimer; CaptainModeTarget()
int m_mode; : m_target(nullptr), m_function(nullptr), m_shortcut(nullptr)
// The widget which has the focus before entering Captain mode. {
QWidget* m_widgetBeforeCaptain; }
struct NaviModeTarget { CaptainModeTarget(const QString &p_name,
VNavigationMode *m_target; const QString &p_key,
bool m_available; void *p_target,
CaptainFunc p_func,
QShortcut *p_shortcut)
: m_name(p_name),
m_key(p_key),
m_target(p_target),
m_function(p_func),
m_shortcut(p_shortcut)
{
}
NaviModeTarget(VNavigationMode *p_target, bool p_available) QString toString() const
: m_target(p_target), m_available(p_available) {} {
return QString("Captain mode target %1 key[%2]").arg(m_name).arg(m_key);
}
// Name to display.
QString m_name;
// Key sequence to trigger this target.
// This is the sub-sequence after leader key.
QString m_key;
// Target.
void *m_target;
// Function to call when this target is trigger.
CaptainFunc m_function;
// Shortcut for this target.
QShortcut *m_shortcut;
}; };
QList<NaviModeTarget> m_targets;
// Restore the focus to m_widgetBeforeNavigation.
void restoreFocus();
// Return true if finish handling the event; otherwise, let the base widget
// to handle it.
bool handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers);
// Handle key press event in Navigation mode.
bool handleKeyPressNavigationMode(int p_key,
Qt::KeyboardModifiers p_modifiers);
// Get next major key to use for Navigation mode.
QChar getNextMajorKey();
// Trigger navigation mode to ask all targets show themselves.
void triggerNavigationMode();
// Exit navigation mode to ask all targets hide themselves.
void exitNavigationMode();
// Called to trigger the action of a Captain target which has
// registered @p_key.
void triggerCaptainTarget(const QString &p_key);
void setMode(CaptainMode p_mode);
bool checkMode(CaptainMode p_mode) const;
static void navigationModeByCaptain(void *p_target, void *p_data);
// Used to indicate whether we are in Navigation mode.
CaptainMode m_mode;
// The widget which has the focus before entering Navigation mode.
QWidget* m_widgetBeforeNavigation;
// Targets for Navigation mode.
QVector<NaviModeTarget> m_naviTargets;
QChar m_nextMajorKey; QChar m_nextMajorKey;
// Ignore focus change to avoid exiting Captain mode while handling key
// press. // Targets for Captain mode.
// Key(lower) -> CaptainModeTarget.
QHash<QString, CaptainModeTarget> m_captainTargets;
// Ignore focus change during handling Navigation target actions.
bool m_ignoreFocusChange; bool m_ignoreFocusChange;
// Leader key sequence for Captain mode.
QString m_leaderKey;
}; };
inline void VCaptain::setMode(CaptainMode p_mode)
{
m_mode = p_mode;
}
inline bool VCaptain::checkMode(CaptainMode p_mode) const
{
return m_mode == p_mode;
}
#endif // VCAPTAIN_H #endif // VCAPTAIN_H

View File

@ -172,6 +172,8 @@ void VConfigManager::initialize()
readShortcutsFromSettings(); readShortcutsFromSettings();
readCaptainShortcutsFromSettings();
initDocSuffixes(); initDocSuffixes();
m_markdownHighlightInterval = getConfigFromSettings("global", m_markdownHighlightInterval = getConfigFromSettings("global",
@ -1002,76 +1004,120 @@ QString VConfigManager::getVnoteNotebookFolderPath()
return QDir::home().filePath(c_vnoteNotebookFolderName); return QDir::home().filePath(c_vnoteNotebookFolderName);
} }
QHash<QString, QString> VConfigManager::readShortcutsFromSettings(QSettings *p_settings,
const QString &p_group)
{
QHash<QString, QString> ret;
p_settings->beginGroup(p_group);
QStringList keys = p_settings->childKeys();
for (auto const & key : keys) {
if (key.isEmpty()) {
continue;
}
QVariant varVal = p_settings->value(key);
QString sequence = varVal.toString();
if (varVal.type() == QVariant::StringList) {
sequence = varVal.toStringList().join(",");
}
sequence = sequence.trimmed();
if (isValidKeySequence(sequence)) {
ret.insert(key, sequence);
}
}
p_settings->endGroup();
return ret;
}
bool VConfigManager::isValidKeySequence(const QString &p_seq) bool VConfigManager::isValidKeySequence(const QString &p_seq)
{ {
QString lower = p_seq.toLower(); return p_seq.toLower() != "ctrl+q"
return lower != "ctrl+q" && lower != "ctrl+e"; && !QKeySequence(p_seq).isEmpty();
} }
void VConfigManager::readShortcutsFromSettings() void VConfigManager::readShortcutsFromSettings()
{ {
const QString group("shortcuts");
m_shortcuts.clear(); m_shortcuts.clear();
int size = defaultSettings->beginReadArray("shortcuts"); m_shortcuts = readShortcutsFromSettings(defaultSettings, group);
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)) { // Update default settings according to user settings.
qDebug() << "read shortcut config" << op << seq; QHash<QString, QString> userShortcuts = readShortcutsFromSettings(userSettings,
m_shortcuts[op] = seq; group);
}
}
defaultSettings->endArray();
// Whether we need to update user settings.
bool needUpdate = false;
size = userSettings->beginReadArray("shortcuts");
QSet<QString> matched; QSet<QString> matched;
matched.reserve(m_shortcuts.size()); matched.reserve(m_shortcuts.size());
for (int i = 0; i < size; ++i) { for (auto it = userShortcuts.begin(); it != userShortcuts.end(); ++it) {
userSettings->setArrayIndex(i); auto defaultIt = m_shortcuts.find(it.key());
QString op = userSettings->value("operation").toString(); if (defaultIt != m_shortcuts.end()) {
QString seq = userSettings->value("keysequence").toString().trimmed(); QString sequence = it.value().trimmed();
if (sequence != defaultIt.value()) {
if (isValidKeySequence(seq)) { if (isValidKeySequence(sequence)) {
qDebug() << "read user shortcut config" << op << seq; matched.insert(it.key());
auto it = m_shortcuts.find(op); *defaultIt = sequence;
if (it == m_shortcuts.end()) { }
// Could not find this in default settings.
needUpdate = true;
} else { } else {
matched.insert(op); matched.insert(it.key());
*it = seq;
} }
} }
} }
userSettings->endArray(); if (matched.size() < m_shortcuts.size()) {
writeShortcutsToSettings(userSettings, group, m_shortcuts);
if (needUpdate || matched.size() < m_shortcuts.size()) {
// Write the combined config to user settings.
writeShortcutsToSettings();
} }
qDebug() << "shortcuts:" << m_shortcuts;
} }
void VConfigManager::writeShortcutsToSettings() void VConfigManager::readCaptainShortcutsFromSettings()
{ {
// Clear it first const QString group("captain_mode_shortcuts");
userSettings->beginGroup("shortcuts");
userSettings->remove("");
userSettings->endGroup();
userSettings->beginWriteArray("shortcuts"); m_captainShortcuts.clear();
int idx = 0; m_captainShortcuts = readShortcutsFromSettings(defaultSettings, group);
for (auto it = m_shortcuts.begin(); it != m_shortcuts.end(); ++it, ++idx) {
userSettings->setArrayIndex(idx); // Update default settings according to user settings.
userSettings->setValue("operation", it.key()); QHash<QString, QString> userShortcuts = readShortcutsFromSettings(userSettings,
userSettings->setValue("keysequence", it.value()); group);
QSet<QString> matched;
matched.reserve(m_captainShortcuts.size());
for (auto it = userShortcuts.begin(); it != userShortcuts.end(); ++it) {
auto defaultIt = m_captainShortcuts.find(it.key());
if (defaultIt != m_captainShortcuts.end()) {
QString sequence = it.value().trimmed();
if (sequence != defaultIt.value()) {
if (isValidKeySequence(sequence)) {
matched.insert(it.key());
*defaultIt = sequence;
}
} else {
matched.insert(it.key());
}
}
} }
userSettings->endArray(); if (matched.size() < m_captainShortcuts.size()) {
writeShortcutsToSettings(userSettings, group, m_captainShortcuts);
}
qDebug() << "captain mode shortcuts:" << m_captainShortcuts;
}
void VConfigManager::writeShortcutsToSettings(QSettings *p_settings,
const QString &p_group,
const QHash<QString, QString> &p_shortcuts)
{
p_settings->beginGroup(p_group);
p_settings->remove("");
for (auto it = p_shortcuts.begin(); it != p_shortcuts.end(); ++it) {
p_settings->setValue(it.key(), it.value());
}
p_settings->endGroup();
} }
QString VConfigManager::getShortcutKeySequence(const QString &p_operation) const QString VConfigManager::getShortcutKeySequence(const QString &p_operation) const
@ -1084,6 +1130,16 @@ QString VConfigManager::getShortcutKeySequence(const QString &p_operation) const
return *it; return *it;
} }
QString VConfigManager::getCaptainShortcutKeySequence(const QString &p_operation) const
{
auto it = m_captainShortcuts.find(p_operation);
if (it == m_captainShortcuts.end()) {
return QString();
}
return *it;
}
void VConfigManager::initDocSuffixes() void VConfigManager::initDocSuffixes()
{ {
m_docSuffixes.clear(); m_docSuffixes.clear();

View File

@ -334,6 +334,10 @@ public:
// Return empty if there is no corresponding config. // Return empty if there is no corresponding config.
QString getShortcutKeySequence(const QString &p_operation) const; QString getShortcutKeySequence(const QString &p_operation) const;
// Return the configured key sequence in Captain mode.
// Return empty if there is no corresponding config.
QString getCaptainShortcutKeySequence(const QString &p_operation) const;
// Get the folder the ini file exists. // Get the folder the ini file exists.
QString getConfigFolder() const; QString getConfigFolder() const;
@ -418,8 +422,16 @@ private:
// write the combined configs to user settings. // write the combined configs to user settings.
void readShortcutsFromSettings(); void readShortcutsFromSettings();
// Write m_shortcuts to the [shortcuts] section in the user settings. // Read the [captain_mode_shortcuts] section in the settings to init
void writeShortcutsToSettings(); // m_captainShortcuts.
void readCaptainShortcutsFromSettings();
QHash<QString, QString> readShortcutsFromSettings(QSettings *p_settings,
const QString &p_group);
void writeShortcutsToSettings(QSettings *p_settings,
const QString &p_group,
const QHash<QString, QString> &p_shortcuts);
// Whether @p_seq is a valid key sequence for shortcuts. // Whether @p_seq is a valid key sequence for shortcuts.
bool isValidKeySequence(const QString &p_seq); bool isValidKeySequence(const QString &p_seq);
@ -592,6 +604,10 @@ private:
// Operation -> KeySequence. // Operation -> KeySequence.
QHash<QString, QString> m_shortcuts; QHash<QString, QString> m_shortcuts;
// Shortcuts config in Captain mode.
// Operation -> KeySequence.
QHash<QString, QString> m_captainShortcuts;
// Whether minimize to system tray icon when closing the app. // Whether minimize to system tray icon when closing the app.
// -1: uninitialized; // -1: uninitialized;
// 0: do not minimize to the tay; // 0: do not minimize to the tay;

View File

@ -8,10 +8,15 @@
#include "dialog/vfindreplacedialog.h" #include "dialog/vfindreplacedialog.h"
#include "utils/vutils.h" #include "utils/vutils.h"
#include "vfilesessioninfo.h" #include "vfilesessioninfo.h"
#include "vmainwindow.h"
#include "vcaptain.h"
extern VConfigManager *g_config; extern VConfigManager *g_config;
extern VNote *g_vnote; extern VNote *g_vnote;
extern VMainWindow *g_mainWin;
VEditArea::VEditArea(QWidget *parent) VEditArea::VEditArea(QWidget *parent)
: QWidget(parent), : QWidget(parent),
VNavigationMode(), VNavigationMode(),
@ -21,6 +26,8 @@ VEditArea::VEditArea(QWidget *parent)
insertSplitWindow(0); insertSplitWindow(0);
setCurrentWindow(0, false); setCurrentWindow(0, false);
registerCaptainTargets();
} }
void VEditArea::setupUI() void VEditArea::setupUI()
@ -749,3 +756,180 @@ int VEditArea::openFiles(const QVector<VFileSessionInfo> &p_files)
return nrOpened; return nrOpened;
} }
void VEditArea::registerCaptainTargets()
{
using namespace std::placeholders;
VCaptain *captain = g_mainWin->getCaptain();
captain->registerCaptainTarget(tr("ActivateTab1"),
g_config->getCaptainShortcutKeySequence("ActivateTab1"),
this,
std::bind(activateTabByCaptain, _1, _2, 1));
captain->registerCaptainTarget(tr("ActivateTab2"),
g_config->getCaptainShortcutKeySequence("ActivateTab2"),
this,
std::bind(activateTabByCaptain, _1, _2, 2));
captain->registerCaptainTarget(tr("ActivateTab3"),
g_config->getCaptainShortcutKeySequence("ActivateTab3"),
this,
std::bind(activateTabByCaptain, _1, _2, 3));
captain->registerCaptainTarget(tr("ActivateTab4"),
g_config->getCaptainShortcutKeySequence("ActivateTab4"),
this,
std::bind(activateTabByCaptain, _1, _2, 4));
captain->registerCaptainTarget(tr("ActivateTab5"),
g_config->getCaptainShortcutKeySequence("ActivateTab5"),
this,
std::bind(activateTabByCaptain, _1, _2, 5));
captain->registerCaptainTarget(tr("ActivateTab6"),
g_config->getCaptainShortcutKeySequence("ActivateTab6"),
this,
std::bind(activateTabByCaptain, _1, _2, 6));
captain->registerCaptainTarget(tr("ActivateTab7"),
g_config->getCaptainShortcutKeySequence("ActivateTab7"),
this,
std::bind(activateTabByCaptain, _1, _2, 7));
captain->registerCaptainTarget(tr("ActivateTab8"),
g_config->getCaptainShortcutKeySequence("ActivateTab8"),
this,
std::bind(activateTabByCaptain, _1, _2, 8));
captain->registerCaptainTarget(tr("ActivateTab9"),
g_config->getCaptainShortcutKeySequence("ActivateTab9"),
this,
std::bind(activateTabByCaptain, _1, _2, 9));
captain->registerCaptainTarget(tr("AlternateTab"),
g_config->getCaptainShortcutKeySequence("AlternateTab"),
this,
alternateTabByCaptain);
captain->registerCaptainTarget(tr("OpenedFileList"),
g_config->getCaptainShortcutKeySequence("OpenedFileList"),
this,
showOpenedFileListByCaptain);
captain->registerCaptainTarget(tr("ActivateSplitLeft"),
g_config->getCaptainShortcutKeySequence("ActivateSplitLeft"),
this,
activateSplitLeftByCaptain);
captain->registerCaptainTarget(tr("ActivateSplitRight"),
g_config->getCaptainShortcutKeySequence("ActivateSplitRight"),
this,
activateSplitRightByCaptain);
captain->registerCaptainTarget(tr("MoveTabSplitLeft"),
g_config->getCaptainShortcutKeySequence("MoveTabSplitLeft"),
this,
moveTabSplitLeftByCaptain);
captain->registerCaptainTarget(tr("MoveTabSplitRight"),
g_config->getCaptainShortcutKeySequence("MoveTabSplitRight"),
this,
moveTabSplitRightByCaptain);
captain->registerCaptainTarget(tr("ActivateNextTab"),
g_config->getCaptainShortcutKeySequence("ActivateNextTab"),
this,
activateNextTabByCaptain);
captain->registerCaptainTarget(tr("ActivatePreviousTab"),
g_config->getCaptainShortcutKeySequence("ActivatePreviousTab"),
this,
activatePreviousTabByCaptain);
captain->registerCaptainTarget(tr("VerticalSplit"),
g_config->getCaptainShortcutKeySequence("VerticalSplit"),
this,
verticalSplitByCaptain);
captain->registerCaptainTarget(tr("RemoveSplit"),
g_config->getCaptainShortcutKeySequence("RemoveSplit"),
this,
removeSplitByCaptain);
}
void VEditArea::activateTabByCaptain(void *p_target, void *p_data, int p_idx)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
VEditWindow *win = obj->getCurrentWindow();
if (win) {
win->activateTab(p_idx);
}
}
void VEditArea::alternateTabByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
VEditWindow *win = obj->getCurrentWindow();
if (win) {
win->alternateTab();
}
}
void VEditArea::showOpenedFileListByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
VEditWindow *win = obj->getCurrentWindow();
if (win) {
win->showOpenedFileList();
}
}
void VEditArea::activateSplitLeftByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
obj->focusNextWindow(-1);
}
void VEditArea::activateSplitRightByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
obj->focusNextWindow(1);
}
void VEditArea::moveTabSplitLeftByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
obj->moveCurrentTabOneSplit(false);
}
void VEditArea::moveTabSplitRightByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
obj->moveCurrentTabOneSplit(true);
}
void VEditArea::activateNextTabByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
VEditWindow *win = obj->getCurrentWindow();
if (win) {
win->focusNextTab(true);
}
}
void VEditArea::activatePreviousTabByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
VEditWindow *win = obj->getCurrentWindow();
if (win) {
win->focusNextTab(false);
}
}
void VEditArea::verticalSplitByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
obj->splitCurrentWindow();
}
void VEditArea::removeSplitByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
obj->removeCurrentWindow();
}

View File

@ -160,6 +160,36 @@ private:
// Update status of current window. // Update status of current window.
void updateWindowStatus(); void updateWindowStatus();
// Init targets for Captain mode.
void registerCaptainTargets();
// Captain mode functions.
// Activate tab @p_idx.
static void activateTabByCaptain(void *p_target, void *p_data, int p_idx);
static void alternateTabByCaptain(void *p_target, void *p_data);
static void showOpenedFileListByCaptain(void *p_target, void *p_data);
static void activateSplitLeftByCaptain(void *p_target, void *p_data);
static void activateSplitRightByCaptain(void *p_target, void *p_data);
static void moveTabSplitLeftByCaptain(void *p_target, void *p_data);
static void moveTabSplitRightByCaptain(void *p_target, void *p_data);
static void activateNextTabByCaptain(void *p_target, void *p_data);
static void activatePreviousTabByCaptain(void *p_target, void *p_data);
static void verticalSplitByCaptain(void *p_target, void *p_data);
static void removeSplitByCaptain(void *p_target, void *p_data);
// End Captain mode functions.
int curWindowIndex; int curWindowIndex;
// Splitter holding multiple split windows // Splitter holding multiple split windows

View File

@ -263,7 +263,9 @@ void VEditWindow::removeEditTab(int p_index)
int VEditWindow::insertEditTab(int p_index, VFile *p_file, QWidget *p_page) int VEditWindow::insertEditTab(int p_index, VFile *p_file, QWidget *p_page)
{ {
int idx = insertTab(p_index, p_page, p_file->getName()); int idx = insertTab(p_index,
p_page,
generateTabText(p_index, p_file));
setTabToolTip(idx, generateTooltip(p_file)); setTabToolTip(idx, generateTooltip(p_file));
return idx; return idx;
} }
@ -484,8 +486,7 @@ void VEditWindow::updateTabInfo(int p_index)
const VFile *file = editor->getFile(); const VFile *file = editor->getFile();
bool editMode = editor->isEditMode(); bool editMode = editor->isEditMode();
setTabText(p_index, generateTabText(p_index, file->getName(), setTabText(p_index, generateTabText(p_index, file));
file->isModified(), file->isModifiable()));
setTabToolTip(p_index, generateTooltip(file)); setTabToolTip(p_index, generateTooltip(file));
QString iconUrl(":/resources/icons/reading.svg"); QString iconUrl(":/resources/icons/reading.svg");
@ -502,8 +503,7 @@ 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(), setTabText(i, generateTabText(i, file));
file->isModified(), file->isModifiable()));
} }
} }

View File

@ -140,9 +140,11 @@ private:
int insertEditTab(int p_index, VFile *p_file, QWidget *p_page); int insertEditTab(int p_index, VFile *p_file, QWidget *p_page);
int appendEditTab(VFile *p_file, QWidget *p_page); int appendEditTab(VFile *p_file, QWidget *p_page);
int openFileInTab(VFile *p_file, OpenFileMode p_mode); int openFileInTab(VFile *p_file, OpenFileMode p_mode);
QString generateTooltip(const VFile *p_file) const; QString generateTooltip(const VFile *p_file) const;
QString generateTabText(int p_index, const QString &p_name,
bool p_modified, bool p_modifiable) const; QString generateTabText(int p_index, const VFile *p_file) const;
bool canRemoveSplit(); bool canRemoveSplit();
// Move tab at @p_tabIdx one split window. // Move tab at @p_tabIdx one split window.
@ -212,11 +214,16 @@ 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 VFile *p_file) const
bool p_modified, bool p_modifiable) const
{ {
QString seq = QString::number(p_index + c_tabSequenceBase, 10); if (!p_file) {
return seq + ". " + p_name + (p_modifiable ? (p_modified ? "*" : "") : "#"); return "";
}
return QString("%1.%2%3").arg(QString::number(p_index + c_tabSequenceBase, 10))
.arg(p_file->getName())
.arg(p_file->isModifiable()
? (p_file->isModified() ? "*" : "") : "#");
} }
#endif // VEDITWINDOW_H #endif // VEDITWINDOW_H

View File

@ -31,6 +31,8 @@
#include "vattachmentlist.h" #include "vattachmentlist.h"
#include "vfilesessioninfo.h" #include "vfilesessioninfo.h"
VMainWindow *g_mainWin;
extern VConfigManager *g_config; extern VConfigManager *g_config;
VNote *g_vnote; VNote *g_vnote;
@ -41,12 +43,15 @@ const int VMainWindow::c_sharedMemTimerInterval = 1000;
extern QFile g_logFile; extern QFile g_logFile;
#endif #endif
VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent) VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
: QMainWindow(p_parent), m_guard(p_guard), : QMainWindow(p_parent), m_guard(p_guard),
m_windowOldState(Qt::WindowNoState), m_requestQuit(false) m_windowOldState(Qt::WindowNoState), m_requestQuit(false)
{ {
qsrand(QDateTime::currentDateTime().toTime_t()); qsrand(QDateTime::currentDateTime().toTime_t());
g_mainWin = this;
setWindowIcon(QIcon(":/resources/icons/vnote.ico")); setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
vnote = new VNote(this); vnote = new VNote(this);
g_vnote = vnote; g_vnote = vnote;
@ -59,6 +64,8 @@ VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
m_panelViewState = PanelViewState::TwoPanels; m_panelViewState = PanelViewState::TwoPanels;
} }
initCaptain();
setupUI(); setupUI();
initMenuBar(); initMenuBar();
@ -74,9 +81,9 @@ VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
notebookSelector->update(); notebookSelector->update();
initCaptain();
initSharedMemoryWatcher(); initSharedMemoryWatcher();
registerCaptainAndNavigationTargets();
} }
void VMainWindow::initSharedMemoryWatcher() void VMainWindow::initSharedMemoryWatcher()
@ -95,14 +102,53 @@ void VMainWindow::initCaptain()
// VCaptain should be visible to accpet key focus. But VCaptain // VCaptain should be visible to accpet key focus. But VCaptain
// may hide other widgets. // may hide other widgets.
m_captain = new VCaptain(this); m_captain = new VCaptain(this);
connect(m_captain, &VCaptain::captainModeChanged, }
this, &VMainWindow::handleCaptainModeChanged);
void VMainWindow::registerCaptainAndNavigationTargets()
{
m_captain->registerNavigationTarget(notebookSelector); m_captain->registerNavigationTarget(notebookSelector);
m_captain->registerNavigationTarget(directoryTree); m_captain->registerNavigationTarget(directoryTree);
m_captain->registerNavigationTarget(m_fileList); m_captain->registerNavigationTarget(m_fileList);
m_captain->registerNavigationTarget(editArea); m_captain->registerNavigationTarget(editArea);
m_captain->registerNavigationTarget(outline); m_captain->registerNavigationTarget(outline);
// Register Captain mode targets.
m_captain->registerCaptainTarget(tr("AttachmentList"),
g_config->getCaptainShortcutKeySequence("AttachmentList"),
this,
showAttachmentListByCaptain);
m_captain->registerCaptainTarget(tr("LocateCurrentFile"),
g_config->getCaptainShortcutKeySequence("LocateCurrentFile"),
this,
locateCurrentFileByCaptain);
m_captain->registerCaptainTarget(tr("ExpandMode"),
g_config->getCaptainShortcutKeySequence("ExpandMode"),
this,
toggleExpandModeByCaptain);
m_captain->registerCaptainTarget(tr("OnePanelView"),
g_config->getCaptainShortcutKeySequence("OnePanelView"),
this,
toggleOnePanelViewByCaptain);
m_captain->registerCaptainTarget(tr("DiscardAndRead"),
g_config->getCaptainShortcutKeySequence("DiscardAndRead"),
this,
discardAndReadByCaptain);
m_captain->registerCaptainTarget(tr("ToolsDock"),
g_config->getCaptainShortcutKeySequence("ToolsDock"),
this,
toggleToolsDockByCaptain);
m_captain->registerCaptainTarget(tr("CloseNote"),
g_config->getCaptainShortcutKeySequence("CloseNote"),
this,
closeFileByCaptain);
m_captain->registerCaptainTarget(tr("ShortcutsHelp"),
g_config->getCaptainShortcutKeySequence("ShortcutsHelp"),
this,
shortcutsHelpByCaptain);
m_captain->registerCaptainTarget(tr("FlushLogFile"),
g_config->getCaptainShortcutKeySequence("FlushLogFile"),
this,
flushLogFileByCaptain);
} }
void VMainWindow::setupUI() void VMainWindow::setupUI()
@ -488,11 +534,7 @@ void VMainWindow::initFileToolBar(QSize p_iconSize)
m_closeNoteShortcut = new QShortcut(QKeySequence(keySeq), this); m_closeNoteShortcut = new QShortcut(QKeySequence(keySeq), this);
m_closeNoteShortcut->setContext(Qt::WidgetWithChildrenShortcut); m_closeNoteShortcut->setContext(Qt::WidgetWithChildrenShortcut);
connect(m_closeNoteShortcut, &QShortcut::activated, connect(m_closeNoteShortcut, &QShortcut::activated,
this, [this](){ this, &VMainWindow::closeCurrentFile);
if (m_curFile) {
editArea->closeFile(m_curFile, false);
}
});
editNoteAct = new QAction(QIcon(":/resources/icons/edit_note.svg"), editNoteAct = new QAction(QIcon(":/resources/icons/edit_note.svg"),
tr("&Edit"), this); tr("&Edit"), this);
@ -580,7 +622,7 @@ void VMainWindow::initHelpMenu()
QAction *shortcutAct = new QAction(tr("&Shortcuts Help"), this); QAction *shortcutAct = new QAction(tr("&Shortcuts Help"), this);
shortcutAct->setToolTip(tr("View information about shortcut keys")); shortcutAct->setToolTip(tr("View information about shortcut keys"));
connect(shortcutAct, &QAction::triggered, connect(shortcutAct, &QAction::triggered,
this, &VMainWindow::shortcutHelp); this, &VMainWindow::shortcutsHelp);
QAction *mdGuideAct = new QAction(tr("&Markdown Guide"), this); QAction *mdGuideAct = new QAction(tr("&Markdown Guide"), this);
mdGuideAct->setToolTip(tr("A quick guide of Markdown syntax")); mdGuideAct->setToolTip(tr("A quick guide of Markdown syntax"));
@ -1812,15 +1854,6 @@ void VMainWindow::compactModeView()
changePanelView(m_panelViewState); changePanelView(m_panelViewState);
} }
void VMainWindow::toggleOnePanelView()
{
if (m_panelViewState == PanelViewState::TwoPanels) {
onePanelView();
} else {
twoPanelView();
}
}
void VMainWindow::enableCompactMode(bool p_enabled) void VMainWindow::enableCompactMode(bool p_enabled)
{ {
const int fileListIdx = 1; const int fileListIdx = 1;
@ -2153,15 +2186,6 @@ bool VMainWindow::locateFile(VFile *p_file)
return ret; return ret;
} }
bool VMainWindow::locateCurrentFile()
{
if (m_curFile) {
return locateFile(m_curFile);
}
return false;
}
void VMainWindow::handleFindDialogTextChanged(const QString &p_text, uint /* p_options */) void VMainWindow::handleFindDialogTextChanged(const QString &p_text, uint /* p_options */)
{ {
bool enabled = true; bool enabled = true;
@ -2186,18 +2210,6 @@ void VMainWindow::viewSettings()
settingsDialog.exec(); settingsDialog.exec();
} }
void VMainWindow::handleCaptainModeChanged(bool p_enabled)
{
static QString normalBaseColor = m_avatar->getBaseColor();
static QString captainModeColor = vnote->getColorFromPalette("Purple5");
if (p_enabled) {
m_avatar->updateBaseColor(captainModeColor);
} else {
m_avatar->updateBaseColor(normalBaseColor);
}
}
void VMainWindow::closeCurrentFile() void VMainWindow::closeCurrentFile()
{ {
if (m_curFile) { if (m_curFile) {
@ -2255,7 +2267,7 @@ void VMainWindow::enableImageCaption(bool p_checked)
g_config->setEnableImageCaption(p_checked); g_config->setEnableImageCaption(p_checked);
} }
void VMainWindow::shortcutHelp() void VMainWindow::shortcutsHelp()
{ {
QString locale = VUtils::getLocale(); QString locale = VUtils::getLocale();
QString docName = VNote::c_shortcutsDocFile_en; QString docName = VNote::c_shortcutsDocFile_en;
@ -2466,13 +2478,6 @@ void VMainWindow::showMainWindow()
this->activateWindow(); this->activateWindow();
} }
void VMainWindow::showAttachmentList()
{
if (m_attachmentBtn->isEnabled()) {
m_attachmentBtn->showPopupWidget();
}
}
void VMainWindow::openStartupPages() void VMainWindow::openStartupPages()
{ {
StartupPageType type = g_config->getStartupPageType(); StartupPageType type = g_config->getStartupPageType();
@ -2513,3 +2518,81 @@ bool VMainWindow::isHeadingSequenceApplicable() const
return true; return true;
} }
// Popup the attachment list if it is enabled.
void VMainWindow::showAttachmentListByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
if (obj->m_attachmentBtn->isEnabled()) {
obj->m_attachmentBtn->showPopupWidget();
}
}
void VMainWindow::locateCurrentFileByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
if (obj->m_curFile) {
obj->locateFile(obj->m_curFile);
}
}
void VMainWindow::toggleExpandModeByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
obj->expandViewAct->trigger();
}
void VMainWindow::toggleOnePanelViewByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
if (obj->m_panelViewState == PanelViewState::TwoPanels) {
obj->onePanelView();
} else {
obj->twoPanelView();
}
}
void VMainWindow::discardAndReadByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
if (obj->m_curFile) {
obj->discardExitAct->trigger();
}
}
void VMainWindow::toggleToolsDockByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
obj->toolDock->setVisible(!obj->toolDock->isVisible());
}
void VMainWindow::closeFileByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
obj->closeCurrentFile();
}
void VMainWindow::shortcutsHelpByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
obj->shortcutsHelp();
}
void VMainWindow::flushLogFileByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_target);
Q_UNUSED(p_data);
#if defined(QT_NO_DEBUG)
// Flush g_logFile.
g_logFile.flush();
#endif
}

View File

@ -60,9 +60,6 @@ public:
// Returns true if the location succeeds. // Returns true if the location succeeds.
bool locateFile(VFile *p_file); bool locateFile(VFile *p_file);
// Returns true if the location succeeds.
bool locateCurrentFile();
VFileList *getFileList() const; VFileList *getFileList() const;
VEditArea *getEditArea() const; VEditArea *getEditArea() const;
@ -81,18 +78,20 @@ public:
// Show a temporary message in status bar. // Show a temporary message in status bar.
void showStatusMessage(const QString &p_msg); void showStatusMessage(const QString &p_msg);
// Popup the attachment list if it is enabled.
void showAttachmentList();
// Open startup pages according to configuration. // Open startup pages according to configuration.
void openStartupPages(); void openStartupPages();
VCaptain *getCaptain() const;
private slots: private slots:
void importNoteFromFile(); void importNoteFromFile();
void viewSettings(); void viewSettings();
void changeMarkdownConverter(QAction *action); void changeMarkdownConverter(QAction *action);
void aboutMessage(); void aboutMessage();
void shortcutHelp();
// Display shortcuts help.
void shortcutsHelp();
void changeExpandTab(bool checked); void changeExpandTab(bool checked);
void setTabStopWidth(QAction *action); void setTabStopWidth(QAction *action);
void setEditorBackgroundColor(QAction *action); void setEditorBackgroundColor(QAction *action);
@ -129,7 +128,6 @@ private slots:
void openFindDialog(); void openFindDialog();
void enableMermaid(bool p_checked); void enableMermaid(bool p_checked);
void enableMathjax(bool p_checked); void enableMathjax(bool p_checked);
void handleCaptainModeChanged(bool p_enabled);
void changeAutoIndent(bool p_checked); void changeAutoIndent(bool p_checked);
void changeAutoList(bool p_checked); void changeAutoList(bool p_checked);
void changeVimMode(bool p_checked); void changeVimMode(bool p_checked);
@ -160,6 +158,9 @@ private slots:
// Restore main window. // Restore main window.
void showMainWindow(); void showMainWindow();
// Close current note.
void closeCurrentFile();
protected: protected:
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
@ -213,9 +214,10 @@ private:
void restoreStateAndGeometry(); void restoreStateAndGeometry();
void repositionAvatar(); void repositionAvatar();
// Should init VCaptain before setupUI().
void initCaptain(); void initCaptain();
void toggleOnePanelView();
void closeCurrentFile(); void registerCaptainAndNavigationTargets();
// Update status bar information. // Update status bar information.
void updateStatusInfo(const VEditTabInfo &p_info); void updateStatusInfo(const VEditTabInfo &p_info);
@ -240,6 +242,29 @@ private:
// Only available for writable Markdown file. // Only available for writable Markdown file.
bool isHeadingSequenceApplicable() const; bool isHeadingSequenceApplicable() const;
// Captain mode functions.
// Popup the attachment list if it is enabled.
static void showAttachmentListByCaptain(void *p_target, void *p_data);
static void locateCurrentFileByCaptain(void *p_target, void *p_data);
static void toggleExpandModeByCaptain(void *p_target, void *p_data);
static void toggleOnePanelViewByCaptain(void *p_target, void *p_data);
static void discardAndReadByCaptain(void *p_target, void *p_data);
static void toggleToolsDockByCaptain(void *p_target, void *p_data);
static void closeFileByCaptain(void *p_target, void *p_data);
static void shortcutsHelpByCaptain(void *p_target, void *p_data);
static void flushLogFileByCaptain(void *p_target, void *p_data);
// End Captain mode functions.
VNote *vnote; VNote *vnote;
QPointer<VFile> m_curFile; QPointer<VFile> m_curFile;
QPointer<VEditTab> m_curTab; QPointer<VEditTab> m_curTab;
@ -355,4 +380,9 @@ inline VEditArea *VMainWindow::getEditArea() const
return editArea; return editArea;
} }
inline VCaptain *VMainWindow::getCaptain() const
{
return m_captain;
}
#endif // VMAINWINDOW_H #endif // VMAINWINDOW_H