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"
VConfigManager *g_config;
VMainWindow *g_mainWin;
#if defined(QT_NO_DEBUG)
QFile g_logFile;
@ -157,7 +156,6 @@ int main(int argc, char *argv[])
}
VMainWindow w(&guard);
g_mainWin = &w;
QString style = VUtils::readFileFromDisk(":/resources/vnote.qss");
if (!style.isEmpty()) {
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.
## 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:
```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
; 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+Q is reserved for quitting VNote.
; Leader key of Captain mode
CaptainMode=Ctrl+E
; Create a note in current folder
NewNote=Ctrl+Alt+N
; Save current note
SaveNote=Ctrl+S
; Save changes and enter read mode
SaveAndRead=Ctrl+T
; Edit current note
EditNote=Ctrl+W
; Close current note
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
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`

View File

@ -80,43 +80,103 @@
扩展选定到笔记开始或结尾处。
## 自定义快捷键
VNote支持自定义部分标准快捷键但并不建议这么做。VNote将快捷键信息保存在用户配置文件`vnote.ini`中的`[shortcuts]`小节。
VNote支持自定义部分标准快捷键但并不建议这么做。VNote将快捷键信息保存在用户配置文件`vnote.ini`中的`[shortcuts]``[captain_mode_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
; 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+Q is reserved for quitting VNote.
; Leader key of Captain mode
CaptainMode=Ctrl+E
; Create a note in current folder
NewNote=Ctrl+Alt+N
; Save current note
SaveNote=Ctrl+S
; Save changes and enter read mode
SaveAndRead=Ctrl+T
; Edit current note
EditNote=Ctrl+W
; Close current note
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支持 **舰长模式**
按前导键`Ctrl+E`VNote会进入舰长模式。在舰长模式中VNote会支持更多高效的快捷操作。
另外,在该模式中,`Ctrl+W``W`是等效的,因此,可以`Ctrl+E+W`来实现`Ctrl+E W`的操作。
- `E`
是否扩展编辑区域。
- `P`

View File

@ -168,25 +168,82 @@ mathjax_javascript=https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.
size=4
[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.
; 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+Alt+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
; Leader key of Captain mode
CaptainMode=Ctrl+E
; Create a note in current folder
NewNote=Ctrl+Alt+N
; Save current note
SaveNote=Ctrl+S
; Save changes and enter read mode
SaveAndRead=Ctrl+T
; Edit current note
EditNote=Ctrl+W
; Close current note
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

View File

@ -1,6 +1,5 @@
#include <QtWidgets>
#include <QString>
#include <QTimer>
#include <QDebug>
#include <QShortcut>
#include "vcaptain.h"
@ -9,38 +8,39 @@
#include "vedittab.h"
#include "vfilelist.h"
#include "vnavigationmode.h"
#include "vconfigmanager.h"
extern VMainWindow *g_mainWin;
extern VConfigManager *g_config;
// 3s pending time after the leader keys.
const int c_pendingTime = 3 * 1000;
#if defined(QT_NO_DEBUG)
extern QFile g_logFile;
#endif
VCaptain::VCaptain(VMainWindow *p_parent)
: QWidget(p_parent), m_mainWindow(p_parent), m_mode(VCaptain::Normal),
m_widgetBeforeCaptain(NULL), m_nextMajorKey('a'), m_ignoreFocusChange(false)
VCaptain::VCaptain(QWidget *p_parent)
: QWidget(p_parent),
m_mode(CaptainMode::Normal),
m_widgetBeforeNavigation(NULL),
m_nextMajorKey('a'),
m_ignoreFocusChange(false),
m_leaderKey(g_config->getShortcutKeySequence("CaptainMode"))
{
m_pendingTimer = new QTimer(this);
m_pendingTimer->setSingleShot(true);
m_pendingTimer->setInterval(c_pendingTime);
connect(m_pendingTimer, &QTimer::timeout,
this, &VCaptain::pendingTimerTimeout);
Q_ASSERT(!m_leaderKey.isEmpty());
connect(qApp, &QApplication::focusChanged,
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);
// Make it as small as possible. This widget will stay at the top-left corner
// of VMainWindow.
resize(1, 1);
// Register Navigation mode as Captain mode target.
registerCaptainTarget(tr("NavigationMode"),
g_config->getCaptainShortcutKeySequence("NavigationMode"),
this,
navigationModeByCaptain);
}
QChar VCaptain::getNextMajorKey()
@ -59,39 +59,19 @@ void VCaptain::registerNavigationTarget(VNavigationMode *p_target)
QChar key = getNextMajorKey();
if (!key.isNull()) {
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) {
exitCaptainMode();
}
}
Q_UNUSED(p_now);
void VCaptain::pendingTimerTimeout()
{
qDebug() << "Captain mode timeout";
exitCaptainMode();
restoreFocus();
if (!m_ignoreFocusChange
&& !checkMode(CaptainMode::Normal)
&& p_old == this) {
exitNavigationMode();
}
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)
@ -99,13 +79,6 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
int key = p_event->key();
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) {
QWidget::keyPressEvent(p_event);
return;
@ -120,230 +93,28 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
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
|| (p_key == Qt::Key_BracketLeft
&& p_modifiers == Qt::ControlModifier)) {
goto exit;
exitNavigationMode();
return true;
}
m_ignoreFocusChange = true;
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;
return handleKeyPressNavigationMode(p_key, p_modifiers);
}
bool VCaptain::handleKeyPressNavigationMode(int p_key,
Qt::KeyboardModifiers /* p_modifiers */)
{
Q_ASSERT(m_mode == VCaptainMode::Navigation);
Q_ASSERT(m_mode == CaptainMode::Navigation);
bool hasConsumed = false;
bool pending = false;
for (auto &target : m_targets) {
m_ignoreFocusChange = true;
for (auto &target : m_naviTargets) {
if (hasConsumed) {
target.m_available = false;
target.m_target->hideNavigation();
@ -351,12 +122,13 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
}
if (target.m_available) {
bool succeed = false;
// May change focus, so we need to ignore focus change here.
bool consumed = target.m_target->handleKeyNavigation(p_key, succeed);
if (consumed) {
hasConsumed = true;
if (succeed) {
// Exit.
m_widgetBeforeCaptain = NULL;
m_widgetBeforeNavigation = NULL;
} else {
// Consumed but not succeed. Need more keys.
pending = true;
@ -368,20 +140,23 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
}
}
}
m_ignoreFocusChange = false;
if (pending) {
return true;
}
exitCaptainMode();
restoreFocus();
exitNavigationMode();
return true;
}
void VCaptain::triggerNavigationMode()
{
m_pendingTimer->stop();
m_mode = VCaptainMode::Navigation;
for (auto &target : m_targets) {
setMode(CaptainMode::Navigation);
m_widgetBeforeNavigation = QApplication::focusWidget();
// Focus to listen pending key press.
setFocus();
for (auto &target : m_naviTargets) {
target.m_available = true;
target.m_target->showNavigation();
}
@ -389,51 +164,74 @@ void VCaptain::triggerNavigationMode()
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_target->hideNavigation();
}
}
bool VCaptain::eventFilter(QObject *p_obj, QEvent *p_event)
{
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()
{
if (m_widgetBeforeCaptain) {
m_widgetBeforeCaptain->setFocus();
if (m_widgetBeforeNavigation) {
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) {
exitNavigationMode();
}
m_mode = VCaptain::Normal;
m_pendingTimer->stop();
m_ignoreFocusChange = false;
emit captainModeChanged(false);
if (p_key.isEmpty()) {
return 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
#define VCAPTAIN_H
#include <QWidget>
#include <QList>
#include <functional>
#include <QWidget>
#include <QVector>
#include <QHash>
class QTimer;
class QKeyEvent;
class VMainWindow;
class QEvent;
class VNavigationMode;
// void func(void *p_target, void *p_data);
typedef std::function<void(void *, void *)> CaptainFunc;
class VCaptain : public QWidget
{
Q_OBJECT
public:
explicit VCaptain(VMainWindow *p_parent);
explicit VCaptain(QWidget *p_parent);
// Trigger Captain mode.
void trigger();
// Register a target for Navigation Mode.
// Register a target for Navigation mode.
void registerNavigationTarget(VNavigationMode *p_target);
signals:
void captainModeChanged(bool p_enabled);
// Register a target for Captain mode.
bool registerCaptainTarget(const QString &p_name,
const QString &p_key,
void *p_target,
CaptainFunc p_func);
protected:
void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
bool eventFilter(QObject *p_obj, QEvent *p_event) Q_DECL_OVERRIDE;
public slots:
private slots:
void pendingTimerTimeout();
// Exit Navigation mode if focus lost.
void handleFocusChanged(QWidget *p_old, QWidget *p_new);
private:
// Restore the focus to m_widgetBeforeCaptain.
void restoreFocus();
void exitCaptainMode();
// Return true if finish handling the event; otherwise, let the base widget
// 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();
// A widget target for Navigation mode.
struct NaviModeTarget {
NaviModeTarget()
: m_target(nullptr), m_available(false)
{
}
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,
Pending,
Navigation
};
VMainWindow *m_mainWindow;
QTimer *m_pendingTimer;
int m_mode;
// The widget which has the focus before entering Captain mode.
QWidget* m_widgetBeforeCaptain;
struct CaptainModeTarget {
CaptainModeTarget()
: m_target(nullptr), m_function(nullptr), m_shortcut(nullptr)
{
}
struct NaviModeTarget {
VNavigationMode *m_target;
bool m_available;
CaptainModeTarget(const QString &p_name,
const QString &p_key,
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)
: m_target(p_target), m_available(p_available) {}
QString toString() const
{
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;
// 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;
// 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

View File

@ -172,6 +172,8 @@ void VConfigManager::initialize()
readShortcutsFromSettings();
readCaptainShortcutsFromSettings();
initDocSuffixes();
m_markdownHighlightInterval = getConfigFromSettings("global",
@ -1002,76 +1004,120 @@ QString VConfigManager::getVnoteNotebookFolderPath()
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)
{
QString lower = p_seq.toLower();
return lower != "ctrl+q" && lower != "ctrl+e";
return p_seq.toLower() != "ctrl+q"
&& !QKeySequence(p_seq).isEmpty();
}
void VConfigManager::readShortcutsFromSettings()
{
const QString group("shortcuts");
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();
m_shortcuts = readShortcutsFromSettings(defaultSettings, group);
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");
// Update default settings according to user settings.
QHash<QString, QString> userShortcuts = readShortcutsFromSettings(userSettings,
group);
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;
for (auto it = userShortcuts.begin(); it != userShortcuts.end(); ++it) {
auto defaultIt = m_shortcuts.find(it.key());
if (defaultIt != m_shortcuts.end()) {
QString sequence = it.value().trimmed();
if (sequence != defaultIt.value()) {
if (isValidKeySequence(sequence)) {
matched.insert(it.key());
*defaultIt = sequence;
}
} else {
matched.insert(op);
*it = seq;
matched.insert(it.key());
}
}
}
userSettings->endArray();
if (needUpdate || matched.size() < m_shortcuts.size()) {
// Write the combined config to user settings.
writeShortcutsToSettings();
}
if (matched.size() < m_shortcuts.size()) {
writeShortcutsToSettings(userSettings, group, m_shortcuts);
}
void VConfigManager::writeShortcutsToSettings()
qDebug() << "shortcuts:" << m_shortcuts;
}
void VConfigManager::readCaptainShortcutsFromSettings()
{
// Clear it first
userSettings->beginGroup("shortcuts");
userSettings->remove("");
userSettings->endGroup();
const QString group("captain_mode_shortcuts");
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());
m_captainShortcuts.clear();
m_captainShortcuts = readShortcutsFromSettings(defaultSettings, group);
// Update default settings according to user settings.
QHash<QString, QString> userShortcuts = readShortcutsFromSettings(userSettings,
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
@ -1084,6 +1130,16 @@ QString VConfigManager::getShortcutKeySequence(const QString &p_operation) const
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()
{
m_docSuffixes.clear();

View File

@ -334,6 +334,10 @@ public:
// Return empty if there is no corresponding config.
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.
QString getConfigFolder() const;
@ -418,8 +422,16 @@ private:
// write the combined configs to user settings.
void readShortcutsFromSettings();
// Write m_shortcuts to the [shortcuts] section in the user settings.
void writeShortcutsToSettings();
// Read the [captain_mode_shortcuts] section in the settings to init
// 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.
bool isValidKeySequence(const QString &p_seq);
@ -592,6 +604,10 @@ private:
// Operation -> KeySequence.
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.
// -1: uninitialized;
// 0: do not minimize to the tay;

View File

@ -8,10 +8,15 @@
#include "dialog/vfindreplacedialog.h"
#include "utils/vutils.h"
#include "vfilesessioninfo.h"
#include "vmainwindow.h"
#include "vcaptain.h"
extern VConfigManager *g_config;
extern VNote *g_vnote;
extern VMainWindow *g_mainWin;
VEditArea::VEditArea(QWidget *parent)
: QWidget(parent),
VNavigationMode(),
@ -21,6 +26,8 @@ VEditArea::VEditArea(QWidget *parent)
insertSplitWindow(0);
setCurrentWindow(0, false);
registerCaptainTargets();
}
void VEditArea::setupUI()
@ -749,3 +756,180 @@ int VEditArea::openFiles(const QVector<VFileSessionInfo> &p_files)
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.
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;
// 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 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));
return idx;
}
@ -484,8 +486,7 @@ void VEditWindow::updateTabInfo(int p_index)
const VFile *file = editor->getFile();
bool editMode = editor->isEditMode();
setTabText(p_index, generateTabText(p_index, file->getName(),
file->isModified(), file->isModifiable()));
setTabText(p_index, generateTabText(p_index, file));
setTabToolTip(p_index, generateTooltip(file));
QString iconUrl(":/resources/icons/reading.svg");
@ -502,8 +503,7 @@ void VEditWindow::updateAllTabsSequence()
for (int i = 0; i < count(); ++i) {
VEditTab *editor = getTab(i);
const VFile *file = editor->getFile();
setTabText(i, generateTabText(i, file->getName(),
file->isModified(), file->isModifiable()));
setTabText(i, generateTabText(i, file));
}
}

View File

@ -140,9 +140,11 @@ private:
int insertEditTab(int p_index, VFile *p_file, QWidget *p_page);
int appendEditTab(VFile *p_file, QWidget *p_page);
int openFileInTab(VFile *p_file, OpenFileMode p_mode);
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();
// 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,
bool p_modified, bool p_modifiable) const
inline QString VEditWindow::generateTabText(int p_index, const VFile *p_file) const
{
QString seq = QString::number(p_index + c_tabSequenceBase, 10);
return seq + ". " + p_name + (p_modifiable ? (p_modified ? "*" : "") : "#");
if (!p_file) {
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

View File

@ -31,6 +31,8 @@
#include "vattachmentlist.h"
#include "vfilesessioninfo.h"
VMainWindow *g_mainWin;
extern VConfigManager *g_config;
VNote *g_vnote;
@ -41,12 +43,15 @@ const int VMainWindow::c_sharedMemTimerInterval = 1000;
extern QFile g_logFile;
#endif
VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
: QMainWindow(p_parent), m_guard(p_guard),
m_windowOldState(Qt::WindowNoState), m_requestQuit(false)
{
qsrand(QDateTime::currentDateTime().toTime_t());
g_mainWin = this;
setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
vnote = new VNote(this);
g_vnote = vnote;
@ -59,6 +64,8 @@ VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
m_panelViewState = PanelViewState::TwoPanels;
}
initCaptain();
setupUI();
initMenuBar();
@ -74,9 +81,9 @@ VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
notebookSelector->update();
initCaptain();
initSharedMemoryWatcher();
registerCaptainAndNavigationTargets();
}
void VMainWindow::initSharedMemoryWatcher()
@ -95,14 +102,53 @@ void VMainWindow::initCaptain()
// VCaptain should be visible to accpet key focus. But VCaptain
// may hide other widgets.
m_captain = new VCaptain(this);
connect(m_captain, &VCaptain::captainModeChanged,
this, &VMainWindow::handleCaptainModeChanged);
}
void VMainWindow::registerCaptainAndNavigationTargets()
{
m_captain->registerNavigationTarget(notebookSelector);
m_captain->registerNavigationTarget(directoryTree);
m_captain->registerNavigationTarget(m_fileList);
m_captain->registerNavigationTarget(editArea);
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()
@ -488,11 +534,7 @@ void VMainWindow::initFileToolBar(QSize p_iconSize)
m_closeNoteShortcut = new QShortcut(QKeySequence(keySeq), this);
m_closeNoteShortcut->setContext(Qt::WidgetWithChildrenShortcut);
connect(m_closeNoteShortcut, &QShortcut::activated,
this, [this](){
if (m_curFile) {
editArea->closeFile(m_curFile, false);
}
});
this, &VMainWindow::closeCurrentFile);
editNoteAct = new QAction(QIcon(":/resources/icons/edit_note.svg"),
tr("&Edit"), this);
@ -580,7 +622,7 @@ void VMainWindow::initHelpMenu()
QAction *shortcutAct = new QAction(tr("&Shortcuts Help"), this);
shortcutAct->setToolTip(tr("View information about shortcut keys"));
connect(shortcutAct, &QAction::triggered,
this, &VMainWindow::shortcutHelp);
this, &VMainWindow::shortcutsHelp);
QAction *mdGuideAct = new QAction(tr("&Markdown Guide"), this);
mdGuideAct->setToolTip(tr("A quick guide of Markdown syntax"));
@ -1812,15 +1854,6 @@ void VMainWindow::compactModeView()
changePanelView(m_panelViewState);
}
void VMainWindow::toggleOnePanelView()
{
if (m_panelViewState == PanelViewState::TwoPanels) {
onePanelView();
} else {
twoPanelView();
}
}
void VMainWindow::enableCompactMode(bool p_enabled)
{
const int fileListIdx = 1;
@ -2153,15 +2186,6 @@ bool VMainWindow::locateFile(VFile *p_file)
return ret;
}
bool VMainWindow::locateCurrentFile()
{
if (m_curFile) {
return locateFile(m_curFile);
}
return false;
}
void VMainWindow::handleFindDialogTextChanged(const QString &p_text, uint /* p_options */)
{
bool enabled = true;
@ -2186,18 +2210,6 @@ void VMainWindow::viewSettings()
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()
{
if (m_curFile) {
@ -2255,7 +2267,7 @@ void VMainWindow::enableImageCaption(bool p_checked)
g_config->setEnableImageCaption(p_checked);
}
void VMainWindow::shortcutHelp()
void VMainWindow::shortcutsHelp()
{
QString locale = VUtils::getLocale();
QString docName = VNote::c_shortcutsDocFile_en;
@ -2466,13 +2478,6 @@ void VMainWindow::showMainWindow()
this->activateWindow();
}
void VMainWindow::showAttachmentList()
{
if (m_attachmentBtn->isEnabled()) {
m_attachmentBtn->showPopupWidget();
}
}
void VMainWindow::openStartupPages()
{
StartupPageType type = g_config->getStartupPageType();
@ -2513,3 +2518,81 @@ bool VMainWindow::isHeadingSequenceApplicable() const
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.
bool locateFile(VFile *p_file);
// Returns true if the location succeeds.
bool locateCurrentFile();
VFileList *getFileList() const;
VEditArea *getEditArea() const;
@ -81,18 +78,20 @@ public:
// Show a temporary message in status bar.
void showStatusMessage(const QString &p_msg);
// Popup the attachment list if it is enabled.
void showAttachmentList();
// Open startup pages according to configuration.
void openStartupPages();
VCaptain *getCaptain() const;
private slots:
void importNoteFromFile();
void viewSettings();
void changeMarkdownConverter(QAction *action);
void aboutMessage();
void shortcutHelp();
// Display shortcuts help.
void shortcutsHelp();
void changeExpandTab(bool checked);
void setTabStopWidth(QAction *action);
void setEditorBackgroundColor(QAction *action);
@ -129,7 +128,6 @@ private slots:
void openFindDialog();
void enableMermaid(bool p_checked);
void enableMathjax(bool p_checked);
void handleCaptainModeChanged(bool p_enabled);
void changeAutoIndent(bool p_checked);
void changeAutoList(bool p_checked);
void changeVimMode(bool p_checked);
@ -160,6 +158,9 @@ private slots:
// Restore main window.
void showMainWindow();
// Close current note.
void closeCurrentFile();
protected:
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
@ -213,9 +214,10 @@ private:
void restoreStateAndGeometry();
void repositionAvatar();
// Should init VCaptain before setupUI().
void initCaptain();
void toggleOnePanelView();
void closeCurrentFile();
void registerCaptainAndNavigationTargets();
// Update status bar information.
void updateStatusInfo(const VEditTabInfo &p_info);
@ -240,6 +242,29 @@ private:
// Only available for writable Markdown file.
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;
QPointer<VFile> m_curFile;
QPointer<VEditTab> m_curTab;
@ -355,4 +380,9 @@ inline VEditArea *VMainWindow::getEditArea() const
return editArea;
}
inline VCaptain *VMainWindow::getCaptain() const
{
return m_captain;
}
#endif // VMAINWINDOW_H