register VDirectoryTree for Navigation Mode

This commit is contained in:
Le Tan 2017-04-04 22:40:44 +08:00
parent 4bd05739c0
commit 6e0f1d38b4
8 changed files with 155 additions and 15 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -8,6 +8,8 @@
#include "utils/vutils.h" #include "utils/vutils.h"
#include "veditarea.h" #include "veditarea.h"
extern VNote *g_vnote;
VDirectoryTree::VDirectoryTree(VNote *vnote, QWidget *parent) VDirectoryTree::VDirectoryTree(VNote *vnote, QWidget *parent)
: QTreeWidget(parent), vnote(vnote), m_editArea(NULL) : QTreeWidget(parent), vnote(vnote), m_editArea(NULL)
{ {
@ -665,3 +667,99 @@ void VDirectoryTree::expandItemTree(QTreeWidgetItem *p_item)
expandItem(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;
}

View File

@ -5,13 +5,17 @@
#include <QJsonObject> #include <QJsonObject>
#include <QPointer> #include <QPointer>
#include <QVector> #include <QVector>
#include <QMap>
#include <QList>
#include "vdirectory.h" #include "vdirectory.h"
#include "vnotebook.h" #include "vnotebook.h"
#include "vnavigationmode.h"
class VNote; class VNote;
class VEditArea; class VEditArea;
class QLabel;
class VDirectoryTree : public QTreeWidget class VDirectoryTree : public QTreeWidget, public VNavigationMode
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -20,6 +24,12 @@ public:
bool locateDirectory(const VDirectory *p_directory); bool locateDirectory(const VDirectory *p_directory);
inline const VNotebook *currentNotebook() const; 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: signals:
void currentDirectoryChanged(VDirectory *p_directory); void currentDirectoryChanged(VDirectory *p_directory);
void directoryUpdated(const VDirectory *p_directory); void directoryUpdated(const VDirectory *p_directory);
@ -65,6 +75,8 @@ private:
QTreeWidgetItem *expandToVDirectory(const VDirectory *p_directory); QTreeWidgetItem *expandToVDirectory(const VDirectory *p_directory);
// Expand the tree under @p_item according to VDirectory.isOpened(). // Expand the tree under @p_item according to VDirectory.isOpened().
void expandItemTree(QTreeWidgetItem *p_item); void expandItemTree(QTreeWidgetItem *p_item);
QList<QTreeWidgetItem *> getVisibleItems() const;
QList<QTreeWidgetItem *> getVisibleChildItems(const QTreeWidgetItem *p_item) const;
VNote *vnote; VNote *vnote;
QPointer<VNotebook> m_notebook; QPointer<VNotebook> m_notebook;
@ -80,6 +92,11 @@ private:
QAction *copyAct; QAction *copyAct;
QAction *cutAct; QAction *cutAct;
QAction *pasteAct; 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) inline QPointer<VDirectory> VDirectoryTree::getVDirectory(QTreeWidgetItem *p_item)

View File

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

View File

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