Browse Source

refactor VCaptain to enable Captain mode with Input Method

Le Tan 8 years ago
parent
commit
6c83f9bd04
9 changed files with 288 additions and 126 deletions
  1. 8 0
      src/utils/vutils.cpp
  2. 3 0
      src/utils/vutils.h
  3. 102 51
      src/vcaptain.cpp
  4. 35 19
      src/vcaptain.h
  5. 70 22
      src/veditarea.cpp
  6. 13 13
      src/veditarea.h
  7. 38 11
      src/vmainwindow.cpp
  8. 9 9
      src/vmainwindow.h
  9. 10 1
      src/vnavigationmode.cpp

+ 8 - 0
src/utils/vutils.cpp

@@ -1066,3 +1066,11 @@ void VUtils::touchFile(const QString &p_file)
 
     file.close();
 }
+
+bool VUtils::isMetaKey(int p_key)
+{
+    return p_key == Qt::Key_Control
+           || p_key == Qt::Key_Shift
+           || p_key == Qt::Key_Meta
+           || p_key == Qt::Key_Alt;
+}

+ 3 - 0
src/utils/vutils.h

@@ -258,6 +258,9 @@ public:
     // If @p_file does not exists, create an empty file.
     static void touchFile(const QString &p_file);
 
+    // Ctrl, Meta, Shift, Alt.
+    static bool isMetaKey(int p_key);
+
     // Regular expression for image link.
     // ![image title]( http://github.com/tamlok/vnote.jpg "alt \" text" )
     // Captured texts (need to be trimmed):

+ 102 - 51
src/vcaptain.cpp

@@ -14,13 +14,10 @@ extern VConfigManager *g_config;
 VCaptain::VCaptain(QWidget *p_parent)
     : QWidget(p_parent),
       m_mode(CaptainMode::Normal),
-      m_widgetBeforeNavigation(NULL),
+      m_widgetBeforeCaptain(NULL),
       m_nextMajorKey('a'),
-      m_ignoreFocusChange(false),
-      m_leaderKey(g_config->getShortcutKeySequence("CaptainMode"))
+      m_ignoreFocusChange(false)
 {
-    Q_ASSERT(!m_leaderKey.isEmpty());
-
     connect(qApp, &QApplication::focusChanged,
             this, &VCaptain::handleFocusChanged);
 
@@ -30,6 +27,14 @@ VCaptain::VCaptain(QWidget *p_parent)
     // of VMainWindow.
     resize(1, 1);
 
+    // Register Captain mode leader key.
+    // This can fix the Input Method blocking issue.
+    QShortcut *shortcut = new QShortcut(QKeySequence(g_config->getShortcutKeySequence("CaptainMode")),
+                                        this);
+    shortcut->setContext(Qt::ApplicationShortcut);
+    connect(shortcut, &QShortcut::activated,
+            this, &VCaptain::trigger);
+
     // Register Navigation mode as Captain mode target.
     registerCaptainTarget(tr("NavigationMode"),
                           g_config->getCaptainShortcutKeySequence("NavigationMode"),
@@ -61,11 +66,21 @@ void VCaptain::handleFocusChanged(QWidget *p_old, QWidget * p_now)
 {
     Q_UNUSED(p_now);
 
-    if (!m_ignoreFocusChange
-        && !checkMode(CaptainMode::Normal)
-        && p_old == this) {
-        exitNavigationMode();
+    if (p_old == this
+        && !m_ignoreFocusChange
+        && !checkMode(CaptainMode::Normal)) {
+        exitCaptainMode();
+    }
+}
+
+void VCaptain::trigger()
+{
+    if (!checkMode(CaptainMode::Normal)) {
+        exitCaptainMode();
+        return;
     }
+
+    triggerCaptainMode();
 }
 
 void VCaptain::keyPressEvent(QKeyEvent *p_event)
@@ -73,7 +88,9 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
     int key = p_event->key();
     Qt::KeyboardModifiers modifiers = p_event->modifiers();
 
-    if (key == Qt::Key_Control || key == Qt::Key_Shift) {
+    Q_ASSERT(!checkMode(CaptainMode::Normal));
+
+    if (VUtils::isMetaKey(key)) {
         QWidget::keyPressEvent(p_event);
         return;
     }
@@ -87,18 +104,19 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
 
 bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
 {
-    if (!checkMode(CaptainMode::Navigation)) {
-        return false;
-    }
+    bool ret = true;
 
-    if (p_key == Qt::Key_Escape
-        || (p_key == Qt::Key_BracketLeft
-            && p_modifiers == Qt::ControlModifier)) {
-        exitNavigationMode();
-        return true;
+    m_ignoreFocusChange = true;
+
+    if (checkMode(CaptainMode::Navigation)) {
+        ret = handleKeyPressNavigationMode(p_key, p_modifiers);
+        m_ignoreFocusChange = false;
+        return ret;
     }
 
-    return handleKeyPressNavigationMode(p_key, p_modifiers);
+    ret = handleKeyPressCaptainMode(p_key, p_modifiers);
+    m_ignoreFocusChange = false;
+    return ret;
 }
 
 bool VCaptain::handleKeyPressNavigationMode(int p_key,
@@ -107,7 +125,6 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
     Q_ASSERT(m_mode == CaptainMode::Navigation);
     bool hasConsumed = false;
     bool pending = false;
-    m_ignoreFocusChange = true;
     for (auto &target : m_naviTargets) {
         if (hasConsumed) {
             target.m_available = false;
@@ -122,7 +139,7 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
                 hasConsumed = true;
                 if (succeed) {
                     // Exit.
-                    m_widgetBeforeNavigation = NULL;
+                    m_widgetBeforeCaptain = NULL;
                 } else {
                     // Consumed but not succeed. Need more keys.
                     pending = true;
@@ -135,21 +152,18 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
         }
     }
 
-    m_ignoreFocusChange = false;
     if (pending) {
         return true;
     }
 
-    exitNavigationMode();
+    exitCaptainMode();
     return true;
 }
 
 void VCaptain::triggerNavigationMode()
 {
     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();
@@ -164,17 +178,30 @@ void VCaptain::exitNavigationMode()
         target.m_available = true;
         target.m_target->hideNavigation();
     }
-
-    restoreFocus();
 }
 
 void VCaptain::restoreFocus()
 {
-    if (m_widgetBeforeNavigation) {
-        m_widgetBeforeNavigation->setFocus();
+    if (m_widgetBeforeCaptain) {
+        m_widgetBeforeCaptain->setFocus();
+        m_widgetBeforeCaptain = NULL;
     }
 }
 
+void VCaptain::exitCaptainMode()
+{
+    if (checkMode(CaptainMode::Navigation)) {
+        exitNavigationMode();
+    }
+
+    setMode(CaptainMode::Normal);
+    m_ignoreFocusChange = false;
+
+    restoreFocus();
+
+    qDebug() << "exit Captain mode";
+}
+
 bool VCaptain::registerCaptainTarget(const QString &p_name,
                                      const QString &p_key,
                                      void *p_target,
@@ -184,48 +211,72 @@ bool VCaptain::registerCaptainTarget(const QString &p_name,
         return false;
     }
 
-    QString lowerKey = p_key.toLower();
+    QString normKey = QKeySequence(p_key).toString();
 
-    if (m_captainTargets.contains(lowerKey)) {
+    if (m_captainTargets.contains(normKey)) {
         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,
+                             normKey,
                              p_target,
-                             p_func,
-                             shortcut);
-    m_captainTargets.insert(lowerKey, target);
+                             p_func);
+    m_captainTargets.insert(normKey, target);
 
-    qDebug() << "registered:" << target.toString() << sequence;
+    qDebug() << "registered:" << target.toString() << normKey;
 
     return true;
 }
 
 void VCaptain::triggerCaptainTarget(const QString &p_key)
 {
-    auto it = m_captainTargets.find(p_key.toLower());
-    Q_ASSERT(it != m_captainTargets.end());
+    auto it = m_captainTargets.find(p_key);
+    if (it == m_captainTargets.end()) {
+        return;
+    }
+
     const CaptainModeTarget &target = it.value();
 
     qDebug() << "triggered:" << target.toString();
 
-    target.m_function(target.m_target, nullptr);
+    CaptainData data(m_widgetBeforeCaptain);
+    if (!target.m_function(target.m_target, (void *)&data)) {
+        m_widgetBeforeCaptain = NULL;
+    }
 }
 
-void VCaptain::navigationModeByCaptain(void *p_target, void *p_data)
+bool VCaptain::navigationModeByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VCaptain *obj = static_cast<VCaptain *>(p_target);
     obj->triggerNavigationMode();
+    return true;
+}
+
+void VCaptain::triggerCaptainMode()
+{
+    qDebug() << "trigger Captain mode";
+
+    m_widgetBeforeCaptain = QApplication::focusWidget();
+
+    m_ignoreFocusChange = false;
+
+    setMode(CaptainMode::Pending);
+
+    // Focus to listen pending key press.
+    setFocus();
+}
+
+bool VCaptain::handleKeyPressCaptainMode(int p_key,
+                                         Qt::KeyboardModifiers p_modifiers)
+{
+    Q_ASSERT(checkMode(CaptainMode::Pending));
+    QString normKey = QKeySequence(p_key | p_modifiers).toString();
+    triggerCaptainTarget(normKey);
+
+    if (!checkMode(CaptainMode::Navigation)) {
+        exitCaptainMode();
+    }
+
+    return true;
 }

+ 35 - 19
src/vcaptain.h

@@ -11,8 +11,22 @@ class QKeyEvent;
 class VNavigationMode;
 class QShortcut;
 
-// void func(void *p_target, void *p_data);
-typedef std::function<void(void *, void *)> CaptainFunc;
+// bool func(void *p_target, void *p_data);
+// Return true if the target needs to restore focus by the Captain.
+typedef std::function<bool(void *, void *)> CaptainFunc;
+
+
+// Will be passed to CaptainFunc as the data.
+struct CaptainData
+{
+    CaptainData(QWidget *p_focusWidgetBeforeCaptain)
+        : m_focusWidgetBeforeCaptain(p_focusWidgetBeforeCaptain)
+    {
+    }
+
+    QWidget *m_focusWidgetBeforeCaptain;
+};
+
 
 class VCaptain : public QWidget
 {
@@ -62,20 +76,18 @@ private:
 
     struct CaptainModeTarget {
         CaptainModeTarget()
-            : m_target(nullptr), m_function(nullptr), m_shortcut(nullptr)
+            : m_target(nullptr), m_function(nullptr)
         {
         }
 
         CaptainModeTarget(const QString &p_name,
                           const QString &p_key,
                           void *p_target,
-                          CaptainFunc p_func,
-                          QShortcut *p_shortcut)
+                          CaptainFunc p_func)
             : m_name(p_name),
               m_key(p_key),
               m_target(p_target),
-              m_function(p_func),
-              m_shortcut(p_shortcut)
+              m_function(p_func)
         {
         }
 
@@ -96,12 +108,9 @@ private:
 
         // Function to call when this target is trigger.
         CaptainFunc m_function;
-
-        // Shortcut for this target.
-        QShortcut *m_shortcut;
     };
 
-    // Restore the focus to m_widgetBeforeNavigation.
+    // Restore the focus to m_widgetBeforeCaptain.
     void restoreFocus();
 
     // Return true if finish handling the event; otherwise, let the base widget
@@ -112,6 +121,10 @@ private:
     bool handleKeyPressNavigationMode(int p_key,
                                       Qt::KeyboardModifiers p_modifiers);
 
+    // Handle key press event in Captain mode.
+    bool handleKeyPressCaptainMode(int p_key,
+                                   Qt::KeyboardModifiers p_modifiers);
+
     // Get next major key to use for Navigation mode.
     QChar getNextMajorKey();
 
@@ -121,6 +134,8 @@ private:
     // Exit navigation mode to ask all targets hide themselves.
     void exitNavigationMode();
 
+    void exitCaptainMode();
+
     // Called to trigger the action of a Captain target which has
     // registered @p_key.
     void triggerCaptainTarget(const QString &p_key);
@@ -129,13 +144,17 @@ private:
 
     bool checkMode(CaptainMode p_mode) const;
 
-    static void navigationModeByCaptain(void *p_target, void *p_data);
+    void trigger();
 
-    // Used to indicate whether we are in Navigation mode.
+    void triggerCaptainMode();
+
+    static bool navigationModeByCaptain(void *p_target, void *p_data);
+
+    // Used to indicate current mode.
     CaptainMode m_mode;
 
-    // The widget which has the focus before entering Navigation mode.
-    QWidget* m_widgetBeforeNavigation;
+    // The widget which has the focus before entering Captain mode.
+    QWidget *m_widgetBeforeCaptain;
 
     // Targets for Navigation mode.
     QVector<NaviModeTarget> m_naviTargets;
@@ -146,11 +165,8 @@ private:
     // Key(lower) -> CaptainModeTarget.
     QHash<QString, CaptainModeTarget> m_captainTargets;
 
-    // Ignore focus change during handling Navigation target actions.
+    // Ignore focus change during handling Captain and Navigation target actions.
     bool m_ignoreFocusChange;
-
-    // Leader key sequence for Captain mode.
-    QString m_leaderKey;
 };
 
 inline void VCaptain::setMode(CaptainMode p_mode)

+ 70 - 22
src/veditarea.cpp

@@ -10,6 +10,7 @@
 #include "vfilesessioninfo.h"
 #include "vmainwindow.h"
 #include "vcaptain.h"
+#include "vfilelist.h"
 
 extern VConfigManager *g_config;
 
@@ -899,65 +900,87 @@ void VEditArea::registerCaptainTargets()
                                    applySnippetByCaptain);
 }
 
-void VEditArea::activateTabByCaptain(void *p_target, void *p_data, int p_idx)
+bool 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);
+        if (win->activateTab(p_idx)) {
+            return false;
+        }
     }
+
+    return true;
 }
 
-void VEditArea::alternateTabByCaptain(void *p_target, void *p_data)
+bool 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();
+        if (win->alternateTab()) {
+            return false;
+        }
     }
+
+    return true;
 }
 
-void VEditArea::showOpenedFileListByCaptain(void *p_target, void *p_data)
+bool 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();
+        if (win->showOpenedFileList()) {
+            return false;
+        }
     }
+
+    return true;
 }
 
-void VEditArea::activateSplitLeftByCaptain(void *p_target, void *p_data)
+bool VEditArea::activateSplitLeftByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
-    obj->focusNextWindow(-1);
+    if (obj->focusNextWindow(-1) > -1) {
+        return false;
+    }
+
+    return true;
 }
 
-void VEditArea::activateSplitRightByCaptain(void *p_target, void *p_data)
+bool VEditArea::activateSplitRightByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
-    obj->focusNextWindow(1);
+    if (obj->focusNextWindow(1) > -1) {
+        return false;
+    }
+
+    return true;
 }
 
-void VEditArea::moveTabSplitLeftByCaptain(void *p_target, void *p_data)
+bool VEditArea::moveTabSplitLeftByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
     obj->moveCurrentTabOneSplit(false);
+    return true;
 }
 
-void VEditArea::moveTabSplitRightByCaptain(void *p_target, void *p_data)
+bool VEditArea::moveTabSplitRightByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
     obj->moveCurrentTabOneSplit(true);
+    return true;
 }
 
-void VEditArea::activateNextTabByCaptain(void *p_target, void *p_data)
+bool VEditArea::activateNextTabByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
@@ -965,50 +988,75 @@ void VEditArea::activateNextTabByCaptain(void *p_target, void *p_data)
     if (win) {
         win->focusNextTab(true);
     }
+
+    return true;
 }
 
-void VEditArea::activatePreviousTabByCaptain(void *p_target, void *p_data)
+bool 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);
+        return false;
     }
+
+    return true;
 }
 
-void VEditArea::verticalSplitByCaptain(void *p_target, void *p_data)
+bool VEditArea::verticalSplitByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
     obj->splitCurrentWindow();
+    return false;
 }
 
-void VEditArea::removeSplitByCaptain(void *p_target, void *p_data)
+bool VEditArea::removeSplitByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
     obj->removeCurrentWindow();
+
+    QWidget *nextFocus = obj->getCurrentTab();
+    if (nextFocus) {
+        nextFocus->setFocus();
+    } else {
+        g_mainWin->getFileList()->setFocus();
+    }
+
+    return false;
 }
 
-void VEditArea::evaluateMagicWordsByCaptain(void *p_target, void *p_data)
+bool VEditArea::evaluateMagicWordsByCaptain(void *p_target, void *p_data)
 {
-    Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
+    CaptainData *data = static_cast<CaptainData *>(p_data);
+
     VEditTab *tab = obj->getCurrentTab();
-    if (tab && tab->tabHasFocus()) {
+    if (tab
+        && (data->m_focusWidgetBeforeCaptain == tab
+            || tab->isAncestorOf(data->m_focusWidgetBeforeCaptain))) {
         tab->evaluateMagicWords();
     }
+
+    return true;
 }
 
-void VEditArea::applySnippetByCaptain(void *p_target, void *p_data)
+bool VEditArea::applySnippetByCaptain(void *p_target, void *p_data)
 {
-    Q_UNUSED(p_data);
     VEditArea *obj = static_cast<VEditArea *>(p_target);
+    CaptainData *data = static_cast<CaptainData *>(p_data);
+
     VEditTab *tab = obj->getCurrentTab();
-    if (tab && tab->tabHasFocus()) {
+    if (tab
+        && (data->m_focusWidgetBeforeCaptain == tab
+            || tab->isAncestorOf(data->m_focusWidgetBeforeCaptain))) {
         tab->applySnippet();
     }
+
+    return true;
 }
 
 void VEditArea::recordClosedFile(const VFileSessionInfo &p_file)

+ 13 - 13
src/veditarea.h

@@ -176,33 +176,33 @@ private:
     // Captain mode functions.
 
     // Activate tab @p_idx.
-    static void activateTabByCaptain(void *p_target, void *p_data, int p_idx);
+    static bool activateTabByCaptain(void *p_target, void *p_data, int p_idx);
 
-    static void alternateTabByCaptain(void *p_target, void *p_data);
+    static bool alternateTabByCaptain(void *p_target, void *p_data);
 
-    static void showOpenedFileListByCaptain(void *p_target, void *p_data);
+    static bool showOpenedFileListByCaptain(void *p_target, void *p_data);
 
-    static void activateSplitLeftByCaptain(void *p_target, void *p_data);
+    static bool activateSplitLeftByCaptain(void *p_target, void *p_data);
 
-    static void activateSplitRightByCaptain(void *p_target, void *p_data);
+    static bool activateSplitRightByCaptain(void *p_target, void *p_data);
 
-    static void moveTabSplitLeftByCaptain(void *p_target, void *p_data);
+    static bool moveTabSplitLeftByCaptain(void *p_target, void *p_data);
 
-    static void moveTabSplitRightByCaptain(void *p_target, void *p_data);
+    static bool moveTabSplitRightByCaptain(void *p_target, void *p_data);
 
-    static void activateNextTabByCaptain(void *p_target, void *p_data);
+    static bool activateNextTabByCaptain(void *p_target, void *p_data);
 
-    static void activatePreviousTabByCaptain(void *p_target, void *p_data);
+    static bool activatePreviousTabByCaptain(void *p_target, void *p_data);
 
-    static void verticalSplitByCaptain(void *p_target, void *p_data);
+    static bool verticalSplitByCaptain(void *p_target, void *p_data);
 
-    static void removeSplitByCaptain(void *p_target, void *p_data);
+    static bool removeSplitByCaptain(void *p_target, void *p_data);
 
     // Evaluate selected text or the word on cursor as magic words.
-    static void evaluateMagicWordsByCaptain(void *p_target, void *p_data);
+    static bool evaluateMagicWordsByCaptain(void *p_target, void *p_data);
 
     // Prompt for user to apply a snippet.
-    static void applySnippetByCaptain(void *p_target, void *p_data);
+    static bool applySnippetByCaptain(void *p_target, void *p_data);
 
     // End Captain mode functions.
 

+ 38 - 11
src/vmainwindow.cpp

@@ -2582,32 +2582,39 @@ bool VMainWindow::isHeadingSequenceApplicable() const
 }
 
 // Popup the attachment list if it is enabled.
-void VMainWindow::showAttachmentListByCaptain(void *p_target, void *p_data)
+bool 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();
     }
+
+    return true;
 }
 
-void VMainWindow::locateCurrentFileByCaptain(void *p_target, void *p_data)
+bool 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);
+        if (obj->locateFile(obj->m_curFile)) {
+            return false;
+        }
     }
+
+    return true;
 }
 
-void VMainWindow::toggleExpandModeByCaptain(void *p_target, void *p_data)
+bool VMainWindow::toggleExpandModeByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VMainWindow *obj = static_cast<VMainWindow *>(p_target);
     obj->expandViewAct->trigger();
+    return true;
 }
 
-void VMainWindow::toggleOnePanelViewByCaptain(void *p_target, void *p_data)
+bool VMainWindow::toggleOnePanelViewByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VMainWindow *obj = static_cast<VMainWindow *>(p_target);
@@ -2616,39 +2623,57 @@ void VMainWindow::toggleOnePanelViewByCaptain(void *p_target, void *p_data)
     } else {
         obj->twoPanelView();
     }
+
+    return true;
 }
 
-void VMainWindow::discardAndReadByCaptain(void *p_target, void *p_data)
+bool VMainWindow::discardAndReadByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VMainWindow *obj = static_cast<VMainWindow *>(p_target);
-    if (obj->m_curFile) {
+    if (obj->m_curTab) {
         obj->discardExitAct->trigger();
+        obj->m_curTab->setFocus();
+
+        return false;
     }
+
+    return true;
 }
 
-void VMainWindow::toggleToolsDockByCaptain(void *p_target, void *p_data)
+bool 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());
+    return true;
 }
 
-void VMainWindow::closeFileByCaptain(void *p_target, void *p_data)
+bool VMainWindow::closeFileByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VMainWindow *obj = static_cast<VMainWindow *>(p_target);
     obj->closeCurrentFile();
+
+    QWidget *nextFocus = obj->editArea->getCurrentTab();
+    if (nextFocus) {
+        nextFocus->setFocus();
+    } else {
+        obj->m_fileList->setFocus();
+    }
+
+    return false;
 }
 
-void VMainWindow::shortcutsHelpByCaptain(void *p_target, void *p_data)
+bool VMainWindow::shortcutsHelpByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_data);
     VMainWindow *obj = static_cast<VMainWindow *>(p_target);
     obj->shortcutsHelp();
+    return false;
 }
 
-void VMainWindow::flushLogFileByCaptain(void *p_target, void *p_data)
+bool VMainWindow::flushLogFileByCaptain(void *p_target, void *p_data)
 {
     Q_UNUSED(p_target);
     Q_UNUSED(p_data);
@@ -2657,6 +2682,8 @@ void VMainWindow::flushLogFileByCaptain(void *p_target, void *p_data)
     // Flush g_logFile.
     g_logFile.flush();
 #endif
+
+    return true;
 }
 
 void VMainWindow::promptNewNotebookIfEmpty()

+ 9 - 9
src/vmainwindow.h

@@ -264,23 +264,23 @@ private:
     // Captain mode functions.
 
     // Popup the attachment list if it is enabled.
-    static void showAttachmentListByCaptain(void *p_target, void *p_data);
+    static bool showAttachmentListByCaptain(void *p_target, void *p_data);
 
-    static void locateCurrentFileByCaptain(void *p_target, void *p_data);
+    static bool locateCurrentFileByCaptain(void *p_target, void *p_data);
 
-    static void toggleExpandModeByCaptain(void *p_target, void *p_data);
+    static bool toggleExpandModeByCaptain(void *p_target, void *p_data);
 
-    static void toggleOnePanelViewByCaptain(void *p_target, void *p_data);
+    static bool toggleOnePanelViewByCaptain(void *p_target, void *p_data);
 
-    static void discardAndReadByCaptain(void *p_target, void *p_data);
+    static bool discardAndReadByCaptain(void *p_target, void *p_data);
 
-    static void toggleToolsDockByCaptain(void *p_target, void *p_data);
+    static bool toggleToolsDockByCaptain(void *p_target, void *p_data);
 
-    static void closeFileByCaptain(void *p_target, void *p_data);
+    static bool closeFileByCaptain(void *p_target, void *p_data);
 
-    static void shortcutsHelpByCaptain(void *p_target, void *p_data);
+    static bool shortcutsHelpByCaptain(void *p_target, void *p_data);
 
-    static void flushLogFileByCaptain(void *p_target, void *p_data);
+    static bool flushLogFileByCaptain(void *p_target, void *p_data);
 
     // End Captain mode functions.
 

+ 10 - 1
src/vnavigationmode.cpp

@@ -4,6 +4,7 @@
 #include <QLabel>
 #include <QListWidget>
 #include <QTreeWidget>
+#include <QScrollBar>
 
 #include "vnote.h"
 #include "utils/vutils.h"
@@ -50,8 +51,16 @@ void VNavigationMode::showNavigation(QListWidget *p_widget)
         label->show();
         QRect rect = p_widget->visualItemRect(items[i]);
         // Display the label at the end to show the file name.
-        label->move(rect.x() + p_widget->rect().width() - label->width() - 2,
+        // Fix: take the vertical scrollbar into account.
+        int extraWidth = label->width() + 2;
+        QScrollBar *vbar = p_widget->verticalScrollBar();
+        if (vbar && vbar->minimum() != vbar->maximum()) {
+            extraWidth += vbar->width();
+        }
+
+        label->move(rect.x() + p_widget->rect().width() - extraWidth,
                     rect.y());
+
         m_naviLabels.append(label);
     }
 }