Browse Source

register VDirectoryTree for Navigation Mode

Le Tan 8 years ago
parent
commit
6e0f1d38b4
8 changed files with 155 additions and 15 deletions
  1. 1 1
      src/dialog/vsettingsdialog.cpp
  2. 1 1
      src/utils/vutils.cpp
  3. 24 8
      src/vcaptain.cpp
  4. 3 0
      src/vcaptain.h
  5. 98 0
      src/vdirectorytree.cpp
  6. 18 1
      src/vdirectorytree.h
  7. 1 0
      src/vmainwindow.cpp
  8. 9 4
      src/vnote.cpp

+ 1 - 1
src/dialog/vsettingsdialog.cpp

@@ -92,7 +92,7 @@ VGeneralTab::VGeneralTab(QWidget *p_parent)
     m_langCombo = new QComboBox(this);
     m_langCombo->addItem(tr("System"), "System");
     auto langs = VUtils::getAvailableLanguages();
-    for (auto lang : langs) {
+    for (auto const &lang : langs) {
         m_langCombo->addItem(lang.second, lang.first);
     }
     langLabel->setBuddy(m_langCombo);

+ 1 - 1
src/utils/vutils.cpp

@@ -319,7 +319,7 @@ const QVector<QPair<QString, QString>>& VUtils::getAvailableLanguages()
 
 bool VUtils::isValidLanguage(const QString &p_lang)
 {
-    for (auto lang : c_availableLanguages) {
+    for (auto const &lang : c_availableLanguages) {
         if (lang.first == p_lang) {
             return true;
         }

+ 24 - 8
src/vcaptain.cpp

@@ -15,7 +15,7 @@ const int c_pendingTime = 3 * 1000;
 
 VCaptain::VCaptain(VMainWindow *p_parent)
     : QWidget(p_parent), m_mainWindow(p_parent), m_mode(VCaptain::Normal),
-      m_widgetBeforeCaptain(NULL), m_nextMajorKey('a')
+      m_widgetBeforeCaptain(NULL), m_nextMajorKey('a'), m_ignoreFocusChange(false)
 {
     m_pendingTimer = new QTimer(this);
     m_pendingTimer->setSingleShot(true);
@@ -62,7 +62,7 @@ void VCaptain::registerNavigationTarget(VNavigationMode *p_target)
 // In pending mode, if user click other widgets, we need to exit Captain mode.
 void VCaptain::handleFocusChanged(QWidget *p_old, QWidget * /* p_now */)
 {
-    if (p_old == this) {
+    if (!m_ignoreFocusChange && p_old == this) {
         exitCaptainMode();
     }
 }
@@ -124,8 +124,12 @@ bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
         goto exit;
     }
 
+    m_ignoreFocusChange = true;
+
     if (m_mode == VCaptainMode::Navigation) {
-        return handleKeyPressNavigationMode(p_key, p_modifiers);
+        ret = handleKeyPressNavigationMode(p_key, p_modifiers);
+        m_ignoreFocusChange = false;
+        return ret;
     }
 
     // In Captain mode, Ctrl key won't make a difference.
@@ -303,25 +307,36 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
                                             Qt::KeyboardModifiers /* p_modifiers */)
 {
     Q_ASSERT(m_mode == VCaptainMode::Navigation);
-    for (auto target : m_targets) {
+    bool hasConsumed = false;
+    bool pending = false;
+    for (auto &target : m_targets) {
+        if (hasConsumed) {
+            target.m_available = false;
+            target.m_target->hideNavigation();
+            continue;
+        }
         if (target.m_available) {
             bool succeed = false;
             bool consumed = target.m_target->handleKeyNavigation(p_key, succeed);
             if (consumed) {
+                hasConsumed = true;
                 if (succeed) {
                     // Exit.
                     m_widgetBeforeCaptain = NULL;
-                    break;
                 } else {
                     // Consumed but not succeed. Need more keys.
-                    return true;
+                    pending = true;
                 }
             } else {
                 // Do not ask this target any more.
                 target.m_available = false;
+                target.m_target->hideNavigation();
             }
         }
     }
+    if (pending) {
+        return true;
+    }
     exitCaptainMode();
     restoreFocus();
     return true;
@@ -332,7 +347,7 @@ void VCaptain::triggerNavigationMode()
     m_pendingTimer->stop();
     m_mode = VCaptainMode::Navigation;
 
-    for (auto target : m_targets) {
+    for (auto &target : m_targets) {
         target.m_available = true;
         target.m_target->showNavigation();
     }
@@ -342,7 +357,7 @@ void VCaptain::exitNavigationMode()
 {
     m_mode = VCaptainMode::Normal;
 
-    for (auto target : m_targets) {
+    for (auto &target : m_targets) {
         target.m_available = true;
         target.m_target->hideNavigation();
     }
@@ -383,6 +398,7 @@ void VCaptain::exitCaptainMode()
     }
     m_mode = VCaptain::Normal;
     m_pendingTimer->stop();
+    m_ignoreFocusChange = false;
 
     emit captainModeChanged(false);
 }

+ 3 - 0
src/vcaptain.h

@@ -69,6 +69,9 @@ private:
     };
     QList<NaviModeTarget> m_targets;
     QChar m_nextMajorKey;
+    // Ignore focus change to avoid exiting Captain mode while handling key
+    // press.
+    bool m_ignoreFocusChange;
 };
 
 #endif // VCAPTAIN_H

+ 98 - 0
src/vdirectorytree.cpp

@@ -8,6 +8,8 @@
 #include "utils/vutils.h"
 #include "veditarea.h"
 
+extern VNote *g_vnote;
+
 VDirectoryTree::VDirectoryTree(VNote *vnote, QWidget *parent)
     : QTreeWidget(parent), vnote(vnote), m_editArea(NULL)
 {
@@ -665,3 +667,99 @@ void VDirectoryTree::expandItemTree(QTreeWidgetItem *p_item)
         expandItem(p_item);
     }
 }
+
+void VDirectoryTree::registerNavigation(QChar p_majorKey)
+{
+    m_majorKey = p_majorKey;
+    V_ASSERT(m_keyMap.empty());
+    V_ASSERT(m_naviLabels.empty());
+}
+
+void VDirectoryTree::showNavigation()
+{
+    // Clean up.
+    m_keyMap.clear();
+    for (auto label : m_naviLabels) {
+        delete label;
+    }
+    m_naviLabels.clear();
+
+    // Generate labels for visible items.
+    auto items = getVisibleItems();
+    for (int i = 0; i < 26 && i < items.size(); ++i) {
+        QChar key('a' + i);
+        m_keyMap[key] = items[i];
+
+        qDebug() << key << items[i];
+        QLabel *label = new QLabel(QString(m_majorKey) + key, this);
+        label->setStyleSheet(g_vnote->getNavigationLabelStyle());
+        label->move(visualItemRect(items[i]).topLeft());
+        label->show();
+        m_naviLabels.append(label);
+    }
+}
+
+void VDirectoryTree::hideNavigation()
+{
+    m_keyMap.clear();
+    for (auto label : m_naviLabels) {
+        delete label;
+    }
+    m_naviLabels.clear();
+}
+
+bool VDirectoryTree::handleKeyNavigation(int p_key, bool &p_succeed)
+{
+    static bool secondKey = false;
+    bool ret = false;
+    p_succeed = false;
+    QChar keyChar = VUtils::keyToChar(p_key);
+    if (secondKey && !keyChar.isNull()) {
+        secondKey = false;
+        auto it = m_keyMap.find(keyChar);
+        if (it != m_keyMap.end()) {
+            setCurrentItem(it.value());
+            setFocus();
+            p_succeed = true;
+            ret = true;
+        }
+    } else if (keyChar == m_majorKey) {
+        // Major key pressed.
+        // Need second key.
+        secondKey = true;
+        ret = true;
+    }
+    return ret;
+}
+
+QList<QTreeWidgetItem *> VDirectoryTree::getVisibleItems() const
+{
+    QList<QTreeWidgetItem *> items;
+    for (int i = 0; i < topLevelItemCount(); ++i) {
+        QTreeWidgetItem *item = topLevelItem(i);
+        if (!item->isHidden()) {
+            items.append(item);
+            if (item->isExpanded()) {
+                items.append(getVisibleChildItems(item));
+            }
+        }
+    }
+    return items;
+}
+
+QList<QTreeWidgetItem *> VDirectoryTree::getVisibleChildItems(const QTreeWidgetItem *p_item) const
+{
+    QList<QTreeWidgetItem *> items;
+    if (p_item && !p_item->isHidden() && p_item->isExpanded()) {
+        for (int i = 0; i < p_item->childCount(); ++i) {
+            QTreeWidgetItem *child = p_item->child(i);
+            if (!child->isHidden()) {
+                items.append(child);
+                if (child->isExpanded()) {
+                    items.append(getVisibleChildItems(child));
+                }
+            }
+        }
+    }
+    return items;
+}

+ 18 - 1
src/vdirectorytree.h

@@ -5,13 +5,17 @@
 #include <QJsonObject>
 #include <QPointer>
 #include <QVector>
+#include <QMap>
+#include <QList>
 #include "vdirectory.h"
 #include "vnotebook.h"
+#include "vnavigationmode.h"
 
 class VNote;
 class VEditArea;
+class QLabel;
 
-class VDirectoryTree : public QTreeWidget
+class VDirectoryTree : public QTreeWidget, public VNavigationMode
 {
     Q_OBJECT
 public:
@@ -20,6 +24,12 @@ public:
     bool locateDirectory(const VDirectory *p_directory);
     inline const VNotebook *currentNotebook() const;
 
+    // Implementations for VNavigationMode.
+    void registerNavigation(QChar p_majorKey);
+    void showNavigation();
+    void hideNavigation();
+    bool handleKeyNavigation(int p_key, bool &p_succeed);
+
 signals:
     void currentDirectoryChanged(VDirectory *p_directory);
     void directoryUpdated(const VDirectory *p_directory);
@@ -65,6 +75,8 @@ private:
     QTreeWidgetItem *expandToVDirectory(const VDirectory *p_directory);
     // Expand the tree under @p_item according to VDirectory.isOpened().
     void expandItemTree(QTreeWidgetItem *p_item);
+    QList<QTreeWidgetItem *> getVisibleItems() const;
+    QList<QTreeWidgetItem *> getVisibleChildItems(const QTreeWidgetItem *p_item) const;
 
     VNote *vnote;
     QPointer<VNotebook> m_notebook;
@@ -80,6 +92,11 @@ private:
     QAction *copyAct;
     QAction *cutAct;
     QAction *pasteAct;
+
+    // Navigation Mode.
+    // Map second key to QTreeWidgetItem.
+    QMap<QChar, QTreeWidgetItem *> m_keyMap;
+    QVector<QLabel *> m_naviLabels;
 };
 
 inline QPointer<VDirectory> VDirectoryTree::getVDirectory(QTreeWidgetItem *p_item)

+ 1 - 0
src/vmainwindow.cpp

@@ -51,6 +51,7 @@ void VMainWindow::initCaptain()
             this, &VMainWindow::handleCaptainModeChanged);
 
     m_captain->registerNavigationTarget(notebookSelector);
+    m_captain->registerNavigationTarget(directoryTree);
 }
 
 void VMainWindow::setupUI()

+ 9 - 4
src/vnote.cpp

@@ -174,9 +174,14 @@ QVector<VNotebook *> &VNote::getNotebooks()
 
 const QString &VNote::getNavigationLabelStyle() const
 {
-    static const QString stylesheet = QString("color: %1;"
-                                              "font-size: %2;"
-                                              "font: bold;").arg(getColorFromPalette("Red5"))
-                                                            .arg("18pt");
+    static const QString stylesheet = QString("background-color: %1;"
+                                              "color: %2;"
+                                              "font-size: %3;"
+                                              "font: bold;"
+                                              "font-family: Monospace;"
+                                              "border-radius: 3px;")
+                                              .arg(getColorFromPalette("logo-base"))
+                                              .arg(getColorFromPalette("logo-max"))
+                                              .arg("18pt");
     return stylesheet;
 }