Browse Source

UniversalEntry: add m for ListFolderUE

- Ctrl+M: to list current item folder or the folder containing current
item using ListFolderUE.
Le Tan 7 years ago
parent
commit
af3d380683

+ 8 - 0
src/iuniversalentry.h

@@ -90,6 +90,14 @@ public:
         Q_UNUSED(p_id);
     }
 
+    // Ask the UE to return current item folder path or the folder containing current
+    // item note.
+    virtual QString currentItemFolder(int p_id)
+    {
+        Q_UNUSED(p_id);
+        return QString();
+    }
+
     void setWidgetParent(QWidget *p_parent)
     {
         m_widgetParent = p_parent;

+ 4 - 2
src/src.pro

@@ -123,7 +123,8 @@ SOURCES += main.cpp\
     vdoublerowitemwidget.cpp \
     vsearchue.cpp \
     voutlineue.cpp \
-    vhelpue.cpp
+    vhelpue.cpp \
+    vlistfolderue.cpp
 
 HEADERS  += vmainwindow.h \
     vdirectorytree.h \
@@ -237,7 +238,8 @@ HEADERS  += vmainwindow.h \
     vdoublerowitemwidget.h \
     vsearchue.h \
     voutlineue.h \
-    vhelpue.h
+    vhelpue.h \
+    vlistfolderue.h
 
 RESOURCES += \
     vnote.qrc \

+ 6 - 5
src/vhelpue.cpp

@@ -63,12 +63,13 @@ bool VHelpUE::initListWidget()
         m_listWidget->addItem(tr("Esc/Ctrl+[: Hide Universal Entry"));
         m_listWidget->addItem(tr("Ctrl+U: Clear the command input"));
         m_listWidget->addItem(tr("Ctrl+E: Clear the command input except the entry key"));
-        m_listWidget->addItem(tr("Ctrl+J: Select next item"));
-        m_listWidget->addItem(tr("Ctrl+K: Select previous item"));
-        m_listWidget->addItem(tr("Enter: Activate current item"));
-        m_listWidget->addItem(tr("Ctrl+R: Select current item's parent item"));
+        m_listWidget->addItem(tr("Ctrl+J: Go to next item"));
+        m_listWidget->addItem(tr("Ctrl+K: Go to previous item"));
+        m_listWidget->addItem(tr("Ctrl+R: Go to current item's parent item"));
         m_listWidget->addItem(tr("Ctrl+T: Expand/Collapse current item"));
-        m_listWidget->addItem(tr("Ctrl+S: Sort the items"));
+        m_listWidget->addItem(tr("Ctrl+S: Sort items"));
+        m_listWidget->addItem(tr("Enter: Activate current item"));
+        m_listWidget->addItem(tr("Ctrl+M: Browse current item folder or the folder containing current item"));
 
         return true;
     }

+ 346 - 0
src/vlistfolderue.cpp

@@ -0,0 +1,346 @@
+#include "vlistfolderue.h"
+
+#include <QListWidgetItem>
+#include <QLabel>
+#include <QVBoxLayout>
+
+#include "vlistwidgetdoublerows.h"
+#include "vdirectory.h"
+#include "vdirectorytree.h"
+#include "vmainwindow.h"
+#include "vnote.h"
+#include "utils/viconutils.h"
+#include "vnotefile.h"
+#include "vsearchue.h"
+#include "utils/vutils.h"
+#include "vnotebook.h"
+
+extern VMainWindow *g_mainWin;
+
+extern VNote *g_vnote;
+
+VListFolderPanel::VListFolderPanel(QWidget *p_contentWidget,
+                                QWidget *p_parent)
+    : QWidget(p_parent)
+{
+    m_titleLabel = new QLabel(this);
+    m_titleLabel->setProperty("TitleLabel", true);
+
+    p_contentWidget->setParent(this);
+
+    QVBoxLayout *layout = new QVBoxLayout();
+    layout->addWidget(m_titleLabel);
+    layout->addWidget(p_contentWidget);
+
+    layout->setContentsMargins(0, 0, 0, 0);
+
+    setLayout(layout);
+}
+
+void VListFolderPanel::setTitleLabel(const QString &p_title)
+{
+    m_titleLabel->setText(p_title);
+}
+
+void VListFolderPanel::clearTitle()
+{
+    m_titleLabel->clear();
+}
+
+
+VListFolderUE::VListFolderUE(QObject *p_parent)
+    : IUniversalEntry(p_parent),
+      m_listWidget(NULL)
+{
+}
+
+QString VListFolderUE::description(int p_id) const
+{
+    Q_UNUSED(p_id);
+
+    return tr("List and search the folders and notes of current folder");
+}
+
+void VListFolderUE::init()
+{
+    if (m_initialized) {
+        return;
+    }
+
+    m_initialized = true;
+
+    m_noteIcon = VIconUtils::treeViewIcon(":/resources/icons/note_item.svg");
+    m_folderIcon = VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg");
+
+    m_listWidget = new VListWidgetDoubleRows(m_widgetParent);
+    m_listWidget->setFitContent(true);
+    connect(m_listWidget, SIGNAL(itemActivated(QListWidgetItem *)),
+            this, SLOT(activateItem(QListWidgetItem *)));
+
+    m_panel = new VListFolderPanel(m_listWidget, m_widgetParent);
+    m_panel->hide();
+}
+
+QWidget *VListFolderUE::widget(int p_id)
+{
+    Q_UNUSED(p_id);
+
+    init();
+
+    return m_panel;
+}
+
+void VListFolderUE::processCommand(int p_id, const QString &p_cmd)
+{
+    Q_UNUSED(p_id);
+
+    init();
+
+    QString folderPath = m_folderPath;
+    if (folderPath.isEmpty()) {
+        VDirectory *dir = g_mainWin->getDirectoryTree()->currentDirectory();
+        folderPath = dir->fetchPath();
+    }
+
+    listFolder(folderPath, p_cmd);
+
+    m_listWidget->updateGeometry();
+    emit widgetUpdated();
+    emit stateUpdated(State::Success);
+}
+
+void VListFolderUE::clear(int p_id)
+{
+    Q_UNUSED(p_id);
+
+    m_panel->clearTitle();
+    m_listWidget->clearAll();
+    m_data.clear();
+
+    m_folderPath.clear();
+    m_currentFolderPath.clear();
+}
+
+void VListFolderUE::selectNextItem(int p_id, bool p_forward)
+{
+    Q_UNUSED(p_id);
+
+    m_listWidget->selectNextItem(p_forward);
+}
+
+void VListFolderUE::selectParentItem(int p_id)
+{
+    Q_UNUSED(p_id);
+
+    if (m_currentFolderPath.isEmpty()) {
+        return;
+    }
+
+    if (listFolder(VUtils::basePathFromPath(m_currentFolderPath), QString())) {
+        m_folderPath = m_currentFolderPath;
+    }
+
+    m_listWidget->updateGeometry();
+    emit widgetUpdated();
+}
+
+void VListFolderUE::activate(int p_id)
+{
+    Q_UNUSED(p_id);
+    activateItem(m_listWidget->currentItem());
+}
+
+const QSharedPointer<VSearchResultItem> &VListFolderUE::itemResultData(const QListWidgetItem *p_item) const
+{
+    Q_ASSERT(p_item);
+    int idx = p_item->data(Qt::UserRole).toInt();
+    Q_ASSERT(idx >= 0 && idx < m_data.size());
+    return m_data[idx];
+}
+
+void VListFolderUE::activateItem(QListWidgetItem *p_item)
+{
+    if (!p_item) {
+        return;
+    }
+
+    emit requestHideUniversalEntry();
+
+    VSearchUE::activateItem(itemResultData(p_item));
+}
+
+void VListFolderUE::sort(int p_id)
+{
+    Q_UNUSED(p_id);
+    static bool noteFirst = false;
+
+    int cnt = m_listWidget->count();
+    if (noteFirst) {
+        int idx = cnt - 1;
+        while (true) {
+            if (itemResultData(m_listWidget->item(idx))->m_type != VSearchResultItem::Note) {
+                // Move it to the first row.
+                m_listWidget->moveItem(idx, 0);
+            } else {
+                break;
+            }
+        }
+    } else {
+        int idx = 0;
+        while (true) {
+            if (itemResultData(m_listWidget->item(idx))->m_type != VSearchResultItem::Note) {
+                // Move it to the last row.
+                m_listWidget->moveItem(idx, cnt - 1);
+            } else {
+                break;
+            }
+        }
+    }
+
+    if (cnt) {
+        m_listWidget->setCurrentRow(0);
+    }
+
+    noteFirst = !noteFirst;
+}
+
+void VListFolderUE::addResultItem(const QSharedPointer<VSearchResultItem> &p_item)
+{
+    m_data.append(p_item);
+
+    QString first, second;
+    if (p_item->m_text.isEmpty()) {
+        first = p_item->m_path;
+    } else {
+        first = p_item->m_text;
+        second = p_item->m_path;
+    }
+
+    QIcon *icon = NULL;
+    switch (p_item->m_type) {
+    case VSearchResultItem::Note:
+        icon = &m_noteIcon;
+        break;
+
+    case VSearchResultItem::Folder:
+        icon = &m_folderIcon;
+        break;
+
+    default:
+        break;
+    }
+
+    QListWidgetItem *item = m_listWidget->addDoubleRowsItem(*icon, first, second);
+    item->setData(Qt::UserRole, m_data.size() - 1);
+    item->setToolTip(p_item->m_path);
+
+    if (m_listWidget->count() == 1) {
+        m_listWidget->setCurrentRow(0);
+    }
+}
+
+void VListFolderUE::entryShown(int p_id, const QString &p_cmd)
+{
+    processCommand(p_id, p_cmd);
+}
+
+void VListFolderUE::setFolderPath(const QString &p_path)
+{
+    m_folderPath = p_path;
+}
+
+QString VListFolderUE::currentItemFolder(int p_id)
+{
+    Q_UNUSED(p_id);
+    QString folder;
+    QListWidgetItem *item = m_listWidget->currentItem();
+    if (item) {
+        const QSharedPointer<VSearchResultItem> &resItem = itemResultData(item);
+        if (resItem->m_type == VSearchResultItem::Folder) {
+            folder = resItem->m_path;
+        }
+    }
+
+    return folder;
+}
+
+bool VListFolderUE::listFolder(const QString &p_path, const QString &p_cmd)
+{
+    VDirectory *dir = g_vnote->getInternalDirectory(p_path);
+    if (!dir) {
+        // See if it is a notebook.
+        VNotebook *nb = g_vnote->getNotebook(p_path);
+        if (!nb) {
+            return false;
+        }
+
+        dir = nb->getRootDir();
+    }
+
+    m_panel->clearTitle();
+    m_listWidget->clearAll();
+    m_data.clear();
+
+    m_currentFolderPath = dir->fetchPath();
+    m_panel->setTitleLabel(m_currentFolderPath);
+
+    if (!dir->open()) {
+        return true;
+    }
+
+    if (p_cmd.isEmpty()) {
+        // List the content.
+        for (auto const & it : dir->getSubDirs()) {
+            QSharedPointer<VSearchResultItem> item(new VSearchResultItem(VSearchResultItem::Folder,
+                                                                         VSearchResultItem::LineNumber,
+                                                                         it->getName(),
+                                                                         it->fetchPath()));
+            addResultItem(item);
+        }
+
+        for (auto const & file : dir->getFiles()) {
+            QSharedPointer<VSearchResultItem> item(new VSearchResultItem(VSearchResultItem::Note,
+                                                                         VSearchResultItem::LineNumber,
+                                                                         file->getName(),
+                                                                         file->fetchPath()));
+            addResultItem(item);
+        }
+    } else {
+        // Search the content.
+        VSearchConfig config(VSearchConfig::CurrentFolder,
+                             VSearchConfig::Name,
+                             VSearchConfig::Note | VSearchConfig::Folder,
+                             VSearchConfig::Internal,
+                             VSearchConfig::NoneOption,
+                             p_cmd,
+                             QString());
+
+        for (auto const & it : dir->getSubDirs()) {
+            QString name = it->getName();
+            if (!config.m_token.matched(name)) {
+                continue;
+            }
+
+            QSharedPointer<VSearchResultItem> item(new VSearchResultItem(VSearchResultItem::Folder,
+                                                                         VSearchResultItem::LineNumber,
+                                                                         name,
+                                                                         it->fetchPath()));
+            addResultItem(item);
+        }
+
+        for (auto const & file : dir->getFiles()) {
+            QString name = file->getName();
+            if (!config.m_token.matched(name)) {
+                continue;
+            }
+
+            QSharedPointer<VSearchResultItem> item(new VSearchResultItem(VSearchResultItem::Note,
+                                                                         VSearchResultItem::LineNumber,
+                                                                         name,
+                                                                         file->fetchPath()));
+            addResultItem(item);
+        }
+    }
+
+    return true;
+}

+ 89 - 0
src/vlistfolderue.h

@@ -0,0 +1,89 @@
+#ifndef VLISTFOLDERUE_H
+#define VLISTFOLDERUE_H
+
+#include "iuniversalentry.h"
+#include <QWidget>
+#include <QIcon>
+
+#include "vsearchconfig.h"
+
+class VListWidgetDoubleRows;
+class QListWidgetItem;
+class QLabel;
+
+class VListFolderPanel : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit VListFolderPanel(QWidget *p_contentWidget,
+                              QWidget *p_parent = nullptr);
+
+    void setTitleLabel(const QString &p_title);
+
+    void clearTitle();
+
+private:
+    QLabel *m_titleLabel;
+};
+
+
+// Universal Entry to list contents of folder.
+class VListFolderUE : public IUniversalEntry
+{
+    Q_OBJECT
+public:
+    explicit VListFolderUE(QObject *p_parent = nullptr);
+
+    QString description(int p_id) const Q_DECL_OVERRIDE;
+
+    QWidget *widget(int p_id) Q_DECL_OVERRIDE;
+
+    void processCommand(int p_id, const QString &p_cmd) Q_DECL_OVERRIDE;
+
+    void clear(int p_id) Q_DECL_OVERRIDE;
+
+    void selectNextItem(int p_id, bool p_forward) Q_DECL_OVERRIDE;
+
+    void selectParentItem(int p_id) Q_DECL_OVERRIDE;
+
+    void activate(int p_id) Q_DECL_OVERRIDE;
+
+    void sort(int p_id) Q_DECL_OVERRIDE;
+
+    void entryShown(int p_id, const QString &p_cmd) Q_DECL_OVERRIDE;
+
+    QString currentItemFolder(int p_id) Q_DECL_OVERRIDE;
+
+    void setFolderPath(const QString &p_path);
+
+protected:
+    void init() Q_DECL_OVERRIDE;
+
+private slots:
+    void activateItem(QListWidgetItem *p_item);
+
+private:
+    void addResultItem(const QSharedPointer<VSearchResultItem> &p_item);
+
+    const QSharedPointer<VSearchResultItem> &itemResultData(const QListWidgetItem *p_item) const;
+
+    bool listFolder(const QString &p_path, const QString &p_cmd);
+
+    QVector<QSharedPointer<VSearchResultItem> > m_data;
+
+    QIcon m_noteIcon;
+    QIcon m_folderIcon;
+
+    // Folder path to list.
+    // If empty, use current folder.
+    QString m_folderPath;
+
+    // Current folder path.
+    QString m_currentFolderPath;
+
+    VListWidgetDoubleRows *m_listWidget;
+
+    VListFolderPanel *m_panel;
+};
+
+#endif // VLISTFOLDERUE_H

+ 10 - 0
src/vlistwidgetdoublerows.cpp

@@ -11,6 +11,16 @@ VListWidgetDoubleRows::VListWidgetDoubleRows(QWidget *p_parent)
 {
 }
 
+QListWidgetItem *VListWidgetDoubleRows::addDoubleRowsItem(const QIcon &p_icon,
+                                                          const QString &p_firstRow,
+                                                          const QString &p_secondRow)
+{
+    return insertDoubleRowsItem(count(),
+                                p_icon,
+                                p_firstRow,
+                                p_secondRow);
+}
+
 QListWidgetItem *VListWidgetDoubleRows::insertDoubleRowsItem(int p_row,
                                                              const QIcon &p_icon,
                                                              const QString &p_firstRow,

+ 4 - 0
src/vlistwidgetdoublerows.h

@@ -14,6 +14,10 @@ class VListWidgetDoubleRows : public VListWidget
 public:
     explicit VListWidgetDoubleRows(QWidget *p_parent = nullptr);
 
+    QListWidgetItem *addDoubleRowsItem(const QIcon &p_icon,
+                                       const QString &p_firstRow,
+                                       const QString &p_secondRow);
+
     QListWidgetItem *insertDoubleRowsItem(int p_row,
                                           const QIcon &p_icon,
                                           const QString &p_firstRow,

+ 2 - 0
src/vmainwindow.cpp

@@ -43,6 +43,7 @@
 #include "vsearchue.h"
 #include "voutlineue.h"
 #include "vhelpue.h"
+#include "vlistfolderue.h"
 
 extern VConfigManager *g_config;
 
@@ -3214,5 +3215,6 @@ void VMainWindow::initUniversalEntry()
     m_ue->registerEntry('y', new VOutlineUE(this), 0);
     m_ue->registerEntry('h', searchUE, VSearchUE::Path_FolderNote_AllNotebook);
     m_ue->registerEntry('n', searchUE, VSearchUE::Path_FolderNote_CurrentNotebook);
+    m_ue->registerEntry('m', new VListFolderUE(this), 0);
     m_ue->registerEntry('?', new VHelpUE(this), 0);
 }

+ 8 - 8
src/voutlineue.cpp

@@ -106,15 +106,15 @@ void VOutlineUE::processCommand(int p_id, const QString &p_cmd)
         // Search the outline.
         m_listOutline = false;
 
-        VSearchConfig config(VSearchConfig::CurrentNote,
-                             VSearchConfig::Content,
-                             VSearchConfig::Note,
-                             VSearchConfig::Internal,
-                             VSearchConfig::NoneOption,
-                             p_cmd,
-                             QString());
-
         if (tab) {
+            VSearchConfig config(VSearchConfig::CurrentNote,
+                                 VSearchConfig::Content,
+                                 VSearchConfig::Note,
+                                 VSearchConfig::Internal,
+                                 VSearchConfig::NoneOption,
+                                 p_cmd,
+                                 QString());
+
             const VTableOfContent &outline = tab->getOutline();
             const QVector<VTableOfContentItem> &table = outline.getTable();
             for (auto const & it : table) {

+ 59 - 0
src/vsearchue.cpp

@@ -981,3 +981,62 @@ void VSearchUE::sort(int p_id)
         break;
     }
 }
+
+QString VSearchUE::currentItemFolder(int p_id)
+{
+    QString folder;
+    QSharedPointer<VSearchResultItem> resItem;
+
+    switch (p_id) {
+    case ID::Name_Notebook_AllNotebook:
+    case ID::Name_FolderNote_AllNotebook:
+    case ID::Name_FolderNote_CurrentNotebook:
+    case ID::Name_FolderNote_CurrentFolder:
+    case ID::Name_Note_Buffer:
+    case ID::Path_FolderNote_AllNotebook:
+    case ID::Path_FolderNote_CurrentNotebook:
+    {
+        QListWidgetItem *item = m_listWidget->currentItem();
+        if (item) {
+            resItem = itemResultData(item);
+        }
+
+        break;
+    }
+
+    case ID::Content_Note_AllNotebook:
+    case ID::Content_Note_CurrentNotebook:
+    case ID::Content_Note_CurrentFolder:
+    case ID::Content_Note_Buffer:
+    case ID::Outline_Note_Buffer:
+    {
+        QTreeWidgetItem *item = m_treeWidget->currentItem();
+        if (item) {
+            resItem = itemResultData(item);
+        }
+
+        break;
+    }
+
+    default:
+        Q_ASSERT(false);
+    }
+
+    if (!resItem.isNull()) {
+        switch (resItem->m_type) {
+        case VSearchResultItem::Note:
+            folder = VUtils::basePathFromPath(resItem->m_path);
+            break;
+
+        case VSearchResultItem::Folder:
+        case VSearchResultItem::Notebook:
+            folder = resItem->m_path;
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    return folder;
+}

+ 4 - 2
src/vsearchue.h

@@ -79,6 +79,10 @@ public:
 
     void sort(int p_id) Q_DECL_OVERRIDE;
 
+    QString currentItemFolder(int p_id) Q_DECL_OVERRIDE;
+
+    static void activateItem(const QSharedPointer<VSearchResultItem> &p_item);
+
 protected:
     void init() Q_DECL_OVERRIDE;
 
@@ -125,8 +129,6 @@ private:
 
     void appendItemToTree(const QSharedPointer<VSearchResultItem> &p_item);
 
-    void activateItem(const QSharedPointer<VSearchResultItem> &p_item);
-
     const QSharedPointer<VSearchResultItem> &itemResultData(const QListWidgetItem *p_item) const;
 
     const QSharedPointer<VSearchResultItem> &itemResultData(const QTreeWidgetItem *p_item) const;

+ 30 - 2
src/vuniversalentry.cpp

@@ -17,11 +17,12 @@
 #include "utils/vutils.h"
 #include "vlistwidget.h"
 #include "vpalette.h"
+#include "vlistfolderue.h"
 
 #define MINIMUM_WIDTH 200
 
 #define CMD_EDIT_INTERVAL 500
-#define CMD_EDIT_IDLE_INTERVAL 200
+#define CMD_EDIT_IDLE_INTERVAL 100
 
 extern VPalette *g_palette;
 
@@ -108,7 +109,7 @@ void VUniversalEntry::setupUI()
     connect(m_cmdEdit, &VMetaWordLineEdit::textEdited,
             this, [this](const QString &p_text) {
                 m_cmdTimer->stop();
-                if (p_text.isEmpty() || p_text.size() == 1) {
+                if (p_text.size() <= 1) {
                     m_cmdTimer->start(CMD_EDIT_IDLE_INTERVAL);
                 } else {
                     m_cmdTimer->start(CMD_EDIT_INTERVAL);
@@ -190,6 +191,12 @@ void VUniversalEntry::registerEntry(QChar p_key, IUniversalEntry *p_entry, int p
     m_infoWidget->addItem(QString("%1: %2").arg(p_key)
                                            .arg(p_entry->description(p_id)));
     m_infoWidget->updateGeometry();
+
+    if (m_listEntryKey.isNull()) {
+        if (dynamic_cast<VListFolderUE *>(p_entry)) {
+            m_listEntryKey = p_key;
+        }
+    }
 }
 
 void VUniversalEntry::processCommand()
@@ -368,6 +375,27 @@ void VUniversalEntry::keyPressEvent(QKeyEvent *p_event)
 
         break;
 
+    case Qt::Key_M:
+        if (VUtils::isControlModifierForVim(modifiers)) {
+            // Ctrl+M to browse current item folder or the folder containing current
+            // item.
+            if (m_lastEntry && !m_listEntryKey.isNull()) {
+                QString folderPath = m_lastEntry->m_entry->currentItemFolder(m_lastEntry->m_id);
+                if (!folderPath.isEmpty()) {
+                    m_cmdTimer->stop();
+                    Q_ASSERT(m_entries.contains(m_listEntryKey));
+                    const Entry &entry = m_entries[m_listEntryKey];
+                    static_cast<VListFolderUE *>(entry.m_entry)->setFolderPath(folderPath);
+                    m_cmdEdit->setText(m_listEntryKey);
+                    processCommand();
+                }
+            }
+
+            return;
+        }
+
+        break;
+
     default:
         break;
     }

+ 3 - 0
src/vuniversalentry.h

@@ -114,6 +114,9 @@ private:
     // Last used Entry.
     const Entry *m_lastEntry;
 
+    // Entry to list folder content.
+    QChar m_listEntryKey;
+
     // The CMD edit's original style sheet.
     QString m_cmdStyleSheet;