From 611a695cb1bfc2a41439053762c531d27031ae5e Mon Sep 17 00:00:00 2001 From: Le Tan Date: Wed, 5 Apr 2017 23:31:03 +0800 Subject: [PATCH] register VFileList for Navigation Mode Support Ctrl+J and Ctrl+K navigation in VFileList. --- src/vcaptain.cpp | 4 +- src/vdirectorytree.cpp | 6 +- src/vfilelist.cpp | 115 +++++++++++++++++++++++++++++++++++++- src/vfilelist.h | 17 +++++- src/vmainwindow.cpp | 5 ++ src/vnote.cpp | 33 +++++++---- src/vnote.h | 2 +- src/vnotebookselector.cpp | 2 +- 8 files changed, 166 insertions(+), 18 deletions(-) diff --git a/src/vcaptain.cpp b/src/vcaptain.cpp index d66ecf85..b01b4d0f 100644 --- a/src/vcaptain.cpp +++ b/src/vcaptain.cpp @@ -251,7 +251,9 @@ bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers) case Qt::Key_Q: // Discard changes and exit edit mode. - m_mainWindow->discardExitAct->trigger(); + if (m_mainWindow->m_curFile) { + m_mainWindow->discardExitAct->trigger(); + } break; case Qt::Key_R: diff --git a/src/vdirectorytree.cpp b/src/vdirectorytree.cpp index 6514ffce..e64a87b0 100644 --- a/src/vdirectorytree.cpp +++ b/src/vdirectorytree.cpp @@ -726,9 +726,9 @@ void VDirectoryTree::showNavigation() 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()); + QString str = QString(m_majorKey) + key; + QLabel *label = new QLabel(str, this); + label->setStyleSheet(g_vnote->getNavigationLabelStyle(str)); label->move(visualItemRect(items[i]).topLeft()); label->show(); m_naviLabels.append(label); diff --git a/src/vfilelist.cpp b/src/vfilelist.cpp index 4a66dc29..b7bb2c2b 100644 --- a/src/vfilelist.cpp +++ b/src/vfilelist.cpp @@ -9,6 +9,8 @@ #include "utils/vutils.h" #include "vfile.h" +extern VNote *g_vnote; + VFileList::VFileList(QWidget *parent) : QWidget(parent) { @@ -461,11 +463,45 @@ bool VFileList::copyFile(VDirectory *p_destDir, const QString &p_destName, VFile void VFileList::keyPressEvent(QKeyEvent *event) { - if (event->key() == Qt::Key_Return) { + int key = event->key(); + int modifiers = event->modifiers(); + switch (key) { + case Qt::Key_Return: + { QListWidgetItem *item = fileList->currentItem(); if (item) { handleItemClicked(item); } + break; + } + + + case Qt::Key_J: + { + if (modifiers == Qt::ControlModifier) { + event->accept(); + QKeyEvent *downEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, + Qt::NoModifier); + QCoreApplication::postEvent(fileList, downEvent); + return; + } + break; + } + + case Qt::Key_K: + { + if (modifiers == Qt::ControlModifier) { + event->accept(); + QKeyEvent *upEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, + Qt::NoModifier); + QCoreApplication::postEvent(fileList, upEvent); + return; + } + break; + } + + default: + break; } QWidget::keyPressEvent(event); } @@ -512,3 +548,80 @@ bool VFileList::identicalListWithDirectory() const } return true; } + +void VFileList::registerNavigation(QChar p_majorKey) +{ + m_majorKey = p_majorKey; + V_ASSERT(m_keyMap.empty()); + V_ASSERT(m_naviLabels.empty()); +} + +void VFileList::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]; + + QString str = QString(m_majorKey) + key; + QLabel *label = new QLabel(str, this); + label->setStyleSheet(g_vnote->getNavigationLabelStyle(str)); + label->move(fileList->visualItemRect(items[i]).topLeft()); + label->show(); + m_naviLabels.append(label); + } +} + +void VFileList::hideNavigation() +{ + m_keyMap.clear(); + for (auto label : m_naviLabels) { + delete label; + } + m_naviLabels.clear(); +} + +bool VFileList::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()) { + fileList->setCurrentItem(it.value()); + fileList->setFocus(); + p_succeed = true; + ret = true; + } + } else if (keyChar == m_majorKey) { + // Major key pressed. + // Need second key. + secondKey = true; + ret = true; + } + return ret; +} + +QList VFileList::getVisibleItems() const +{ + QList items; + for (int i = 0; i < fileList->count(); ++i) { + QListWidgetItem *item = fileList->item(i); + if (!item->isHidden()) { + items.append(item); + } + } + return items; +} + diff --git a/src/vfilelist.h b/src/vfilelist.h index 82eb217f..1fd57cdf 100644 --- a/src/vfilelist.h +++ b/src/vfilelist.h @@ -7,10 +7,12 @@ #include #include #include +#include #include "vnotebook.h" #include "vconstants.h" #include "vdirectory.h" #include "vfile.h" +#include "vnavigationmode.h" class QAction; class VNote; @@ -18,8 +20,9 @@ class QListWidget; class QPushButton; class VEditArea; class QFocusEvent; +class QLabel; -class VFileList : public QWidget +class VFileList : public QWidget, public VNavigationMode { Q_OBJECT public: @@ -31,6 +34,12 @@ public: bool locateFile(const VFile *p_file); inline const VDirectory *currentDirectory() const; + // Implementations for VNavigationMode. + void registerNavigation(QChar p_majorKey); + void showNavigation(); + void hideNavigation(); + bool handleKeyNavigation(int p_key, bool &p_succeed); + signals: void fileClicked(VFile *p_file, OpenFileMode mode = OpenFileMode::Read); void fileCreated(VFile *p_file, OpenFileMode mode = OpenFileMode::Read); @@ -70,6 +79,7 @@ private: inline QPointer getVFile(QListWidgetItem *p_item) const; // Check if the list items match exactly the contents of the directory. bool identicalListWithDirectory() const; + QList getVisibleItems() const; VEditArea *editArea; QListWidget *fileList; @@ -83,6 +93,11 @@ private: QAction *copyAct; QAction *cutAct; QAction *pasteAct; + + // Navigation Mode. + // Map second key to QListWidgetItem. + QMap m_keyMap; + QVector m_naviLabels; }; inline void VFileList::setEditArea(VEditArea *editArea) diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index fb591165..44ade597 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -52,6 +52,7 @@ void VMainWindow::initCaptain() m_captain->registerNavigationTarget(notebookSelector); m_captain->registerNavigationTarget(directoryTree); + m_captain->registerNavigationTarget(fileList); } void VMainWindow::setupUI() @@ -250,6 +251,7 @@ void VMainWindow::initFileToolBar() deleteNoteAct->setEnabled(false); editNoteAct->setVisible(false); saveExitAct->setVisible(false); + discardExitAct->setVisible(false); saveNoteAct->setVisible(false); fileToolBar->addAction(newRootDirAct); @@ -785,6 +787,7 @@ void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file, if (p_file) { if (p_editMode) { editNoteAct->setVisible(false); + discardExitAct->setVisible(true); saveExitAct->setVisible(true); saveNoteAct->setVisible(true); deleteNoteAct->setEnabled(true); @@ -792,6 +795,7 @@ void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file, m_insertImageAct->setEnabled(true); } else { editNoteAct->setVisible(true); + discardExitAct->setVisible(false); saveExitAct->setVisible(false); saveNoteAct->setVisible(false); deleteNoteAct->setEnabled(true); @@ -806,6 +810,7 @@ void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file, m_findReplaceAct->setEnabled(true); } else { editNoteAct->setVisible(false); + discardExitAct->setVisible(false); saveExitAct->setVisible(false); saveNoteAct->setVisible(false); deleteNoteAct->setEnabled(false); diff --git a/src/vnote.cpp b/src/vnote.cpp index bd56052c..61462746 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "vnote.h" #include "utils/vutils.h" #include "vconfigmanager.h" @@ -172,16 +174,27 @@ QVector &VNote::getNotebooks() return m_notebooks; } -const QString &VNote::getNavigationLabelStyle() const +QString VNote::getNavigationLabelStyle(const QString &p_str) const { - 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"); + int fontPt = 15; + QString fontFamily("Monospace"); + QFont font(fontFamily, fontPt); + font.setBold(true); + QFontMetrics fm(font); + int pxWidth = fm.width(p_str); + + QString stylesheet = QString("background-color: %1;" + "color: %2;" + "font-size: %3pt;" + "font: bold;" + "font-family: %4;" + "border-radius: 3px;" + "min-width: %5px;" + "max-width: %5px;") + .arg(getColorFromPalette("logo-base")) + .arg(getColorFromPalette("logo-max")) + .arg(fontPt) + .arg(fontFamily) + .arg(pxWidth); return stylesheet; } diff --git a/src/vnote.h b/src/vnote.h index 19ccafa0..ce9f53dc 100644 --- a/src/vnote.h +++ b/src/vnote.h @@ -54,7 +54,7 @@ public: QString getColorFromPalette(const QString &p_name) const; inline VMainWindow *getMainWindow() const; - const QString &getNavigationLabelStyle() const; + QString getNavigationLabelStyle(const QString &p_str) const; public slots: void updateTemplate(); diff --git a/src/vnotebookselector.cpp b/src/vnotebookselector.cpp index 3ef2b52f..36c07665 100644 --- a/src/vnotebookselector.cpp +++ b/src/vnotebookselector.cpp @@ -403,7 +403,7 @@ void VNotebookSelector::registerNavigation(QChar p_majorKey) m_majorKey = p_majorKey; m_naviLabel = new QLabel(m_majorKey, this); - m_naviLabel->setStyleSheet(g_vnote->getNavigationLabelStyle()); + m_naviLabel->setStyleSheet(g_vnote->getNavigationLabelStyle(m_majorKey)); m_naviLabel->hide(); }