From 6e0f1d38b49ee6a2e3dd1f40080028b390036dfb Mon Sep 17 00:00:00 2001 From: Le Tan Date: Tue, 4 Apr 2017 22:40:44 +0800 Subject: [PATCH] register VDirectoryTree for Navigation Mode --- src/dialog/vsettingsdialog.cpp | 2 +- src/utils/vutils.cpp | 2 +- src/vcaptain.cpp | 32 ++++++++--- src/vcaptain.h | 3 ++ src/vdirectorytree.cpp | 98 ++++++++++++++++++++++++++++++++++ src/vdirectorytree.h | 19 ++++++- src/vmainwindow.cpp | 1 + src/vnote.cpp | 13 +++-- 8 files changed, 155 insertions(+), 15 deletions(-) diff --git a/src/dialog/vsettingsdialog.cpp b/src/dialog/vsettingsdialog.cpp index 7b3ad644..d641757f 100644 --- a/src/dialog/vsettingsdialog.cpp +++ b/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); diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index 7247cc55..b344e35d 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -319,7 +319,7 @@ const QVector>& 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; } diff --git a/src/vcaptain.cpp b/src/vcaptain.cpp index 7baca2fe..d66ecf85 100644 --- a/src/vcaptain.cpp +++ b/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); } diff --git a/src/vcaptain.h b/src/vcaptain.h index d1511292..dabb69f8 100644 --- a/src/vcaptain.h +++ b/src/vcaptain.h @@ -69,6 +69,9 @@ private: }; QList m_targets; QChar m_nextMajorKey; + // Ignore focus change to avoid exiting Captain mode while handling key + // press. + bool m_ignoreFocusChange; }; #endif // VCAPTAIN_H diff --git a/src/vdirectorytree.cpp b/src/vdirectorytree.cpp index 2dd5d31c..00855a6e 100644 --- a/src/vdirectorytree.cpp +++ b/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 VDirectoryTree::getVisibleItems() const +{ + QList 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 VDirectoryTree::getVisibleChildItems(const QTreeWidgetItem *p_item) const +{ + QList 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; +} diff --git a/src/vdirectorytree.h b/src/vdirectorytree.h index d22141a2..2a54130e 100644 --- a/src/vdirectorytree.h +++ b/src/vdirectorytree.h @@ -5,13 +5,17 @@ #include #include #include +#include +#include #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 getVisibleItems() const; + QList getVisibleChildItems(const QTreeWidgetItem *p_item) const; VNote *vnote; QPointer m_notebook; @@ -80,6 +92,11 @@ private: QAction *copyAct; QAction *cutAct; QAction *pasteAct; + + // Navigation Mode. + // Map second key to QTreeWidgetItem. + QMap m_keyMap; + QVector m_naviLabels; }; inline QPointer VDirectoryTree::getVDirectory(QTreeWidgetItem *p_item) diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 493a2a13..fb591165 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -51,6 +51,7 @@ void VMainWindow::initCaptain() this, &VMainWindow::handleCaptainModeChanged); m_captain->registerNavigationTarget(notebookSelector); + m_captain->registerNavigationTarget(directoryTree); } void VMainWindow::setupUI() diff --git a/src/vnote.cpp b/src/vnote.cpp index e535fc07..bd56052c 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -174,9 +174,14 @@ QVector &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; }