Browse Source

UniversalEntry: add z to search content of note in all notebooks

Le Tan 7 years ago
parent
commit
a2c2d57570

+ 14 - 0
src/utils/vutils.cpp

@@ -25,6 +25,7 @@
 #include <QStyledItemDelegate>
 #include <QWebEngineView>
 #include <QAction>
+#include <QTreeWidgetItem>
 
 #include "vorphanfile.h"
 #include "vnote.h"
@@ -1390,3 +1391,16 @@ QStringList VUtils::parseCombinedArgString(const QString &p_program)
 
     return args;
 }
+
+const QTreeWidgetItem *VUtils::topLevelTreeItem(const QTreeWidgetItem *p_item)
+{
+    if (!p_item) {
+        return NULL;
+    }
+
+    if (p_item->parent()) {
+        return p_item->parent();
+    } else {
+        return p_item;
+    }
+}

+ 3 - 0
src/utils/vutils.h

@@ -19,6 +19,7 @@ class QWidget;
 class QComboBox;
 class QWebEngineView;
 class QAction;
+class QTreeWidgetItem;
 
 #if !defined(V_ASSERT)
     #define V_ASSERT(cond) ((!(cond)) ? qt_assert(#cond, __FILE__, __LINE__) : qt_noop())
@@ -314,6 +315,8 @@ public:
     // From QProcess code.
     static QStringList parseCombinedArgString(const QString &p_program);
 
+    static const QTreeWidgetItem *topLevelTreeItem(const QTreeWidgetItem *p_item);
+
     // Regular expression for image link.
     // ![image title]( http://github.com/tamlok/vnote.jpg "alt \" text" )
     // Captured texts (need to be trimmed):

+ 2 - 2
src/vlistwidget.cpp

@@ -176,11 +176,11 @@ void VListWidget::sortListWidget(QListWidget *p_list, const QVector<int> &p_sort
 
 QSize VListWidget::sizeHint() const
 {
-    if (count() == 0 || !m_fitContent) {
+    int cnt = count();
+    if (cnt == 0 || !m_fitContent) {
         return QListWidget::sizeHint();
     } else {
         // Adjust size to content.
-        int cnt = count();
         int hei = 0;
         int wid = sizeHintForColumn(0) + 10;
         for (int i = 0; i < cnt; ++i) {

+ 1 - 1
src/vlistwidget.h

@@ -32,7 +32,7 @@ public:
 
     virtual void selectNextItem(bool p_forward) Q_DECL_OVERRIDE;
 
-    QSize sizeHint() const Q_DECL_OVERRIDE;
+    virtual QSize sizeHint() const Q_DECL_OVERRIDE;
 
     // Sort @p_list according to @p_sortedIdx.
     static void sortListWidget(QListWidget *p_list, const QVector<int> &p_sortedIdx);

+ 1 - 0
src/vmainwindow.cpp

@@ -3201,4 +3201,5 @@ void VMainWindow::initUniversalEntry()
     VSearchUE *searchUE = new VSearchUE(this);
     m_ue->registerEntry('q', searchUE, VSearchUE::Name_Notebook_AllNotebook);
     m_ue->registerEntry('a', searchUE, VSearchUE::Name_FolderNote_AllNotebook);
+    m_ue->registerEntry('z', searchUE, VSearchUE::Content_Note_AllNotebook);
 }

+ 46 - 4
src/vsearchconfig.h

@@ -259,6 +259,16 @@ struct VSearchConfig
         compileToken(p_keyword);
     }
 
+    // We support some magic switch in the keyword which will suppress the specified
+    // options:
+    // \c: Case insensitive;
+    // \C: Case sensitive;
+    // \r: Turn off regular expression;
+    // \R: Turn on regular expression;
+    // \f: Turn off fuzzy search;
+    // \F: Turn on fuzzy search (invalid when searching content);
+    // \w: Turn off whole word only;
+    // \W: Turn on whole word only;
     void compileToken(const QString &p_keyword)
     {
         m_token.clear();
@@ -267,12 +277,48 @@ struct VSearchConfig
             return;
         }
 
+        // """ to input a ";
+        // && for AND, || for OR;
+        QStringList args = VUtils::parseCombinedArgString(p_keyword);
+
         Qt::CaseSensitivity cs = m_option & VSearchConfig::CaseSensitive
                                  ? Qt::CaseSensitive : Qt::CaseInsensitive;
         bool useReg = m_option & VSearchConfig::RegularExpression;
         bool wwo = m_option & VSearchConfig::WholeWordOnly;
         bool fuzzy = m_option & VSearchConfig::Fuzzy;
 
+        // Read magic switch from keyword.
+        for (int i = 0; i < args.size();) {
+            const QString &arg = args[i];
+            if (arg.size() != 2 || arg[0] != '\\') {
+                ++i;
+                continue;
+            }
+
+            if (arg == "\\c") {
+                cs = Qt::CaseInsensitive;
+            } else if (arg == "\\C") {
+                cs = Qt::CaseSensitive;
+            } else if (arg == "\\r") {
+                useReg = false;
+            } else if (arg == "\\R") {
+                useReg = true;
+            } else if (arg == "\\f") {
+                fuzzy = false;
+            } else if (arg == "\\F") {
+                fuzzy = true;
+            } else if (arg == "\\w") {
+                wwo = false;
+            } else if (arg == "\\W") {
+                wwo = true;
+            } else {
+                ++i;
+                continue;
+            }
+
+            args.removeAt(i);
+        }
+
         m_token.m_caseSensitivity = cs;
         m_contentToken.m_caseSensitivity = cs;
 
@@ -293,10 +339,6 @@ struct VSearchConfig
         }
 
         VSearchToken::Operator op = VSearchToken::And;
-
-        // """ to input a ";
-        // && for AND, || for OR;
-        QStringList args = VUtils::parseCombinedArgString(p_keyword);
         for (auto const & arg : args) {
             if (arg == QStringLiteral("&&")) {
                 op = VSearchToken::And;

+ 3 - 2
src/vsearchresulttree.cpp

@@ -3,6 +3,7 @@
 #include <QAction>
 #include <QMenu>
 
+#include "utils/vutils.h"
 #include "utils/viconutils.h"
 #include "vnote.h"
 #include "vmainwindow.h"
@@ -43,7 +44,7 @@ void VSearchResultTree::initActions()
     m_openAct->setToolTip(tr("Open selected notes"));
     connect(m_openAct, &QAction::triggered,
             this, [this]() {
-                activateItem(topLevelItem(currentItem()));
+                activateItem(currentItem());
             });
 
     m_locateAct = new QAction(VIconUtils::menuIcon(":/resources/icons/locate_note.svg"),
@@ -207,7 +208,7 @@ VSearchResultItem::ItemType VSearchResultTree::itemResultType(const QTreeWidgetI
 const QSharedPointer<VSearchResultItem> &VSearchResultTree::itemResultData(const QTreeWidgetItem *p_item) const
 {
     Q_ASSERT(p_item);
-    const QTreeWidgetItem *topItem = topLevelItem(p_item);
+    const QTreeWidgetItem *topItem = VUtils::topLevelTreeItem(p_item);
     int idx = topItem->data(0, Qt::UserRole).toInt();
     Q_ASSERT(idx >= 0 && idx < m_data.size());
     return m_data[idx];

+ 0 - 14
src/vsearchresulttree.h

@@ -39,8 +39,6 @@ private:
 
     VSearchResultItem::ItemType itemResultType(const QTreeWidgetItem *p_item) const;
 
-    const QTreeWidgetItem *topLevelItem(const QTreeWidgetItem *p_item) const;
-
     void activateItem(const QTreeWidgetItem *p_item) const;
 
     const QSharedPointer<VSearchResultItem> &itemResultData(const QTreeWidgetItem *p_item) const;
@@ -58,16 +56,4 @@ private:
     QAction *m_addToCartAct;
 };
 
-inline const QTreeWidgetItem *VSearchResultTree::topLevelItem(const QTreeWidgetItem *p_item) const
-{
-    if (!p_item) {
-        return NULL;
-    }
-
-    if (p_item->parent()) {
-        return p_item->parent();
-    } else {
-        return p_item;
-    }
-}
 #endif // VSEARCHRESULTTREE_H

+ 169 - 24
src/vsearchue.cpp

@@ -4,10 +4,12 @@
 #include <QVector>
 
 #include "vlistwidgetdoublerows.h"
+#include "vtreewidget.h"
 #include "vnotebook.h"
 #include "vnote.h"
 #include "vsearch.h"
 #include "utils/viconutils.h"
+#include "utils/vutils.h"
 #include "vmainwindow.h"
 #include "vnotebookselector.h"
 #include "vnotefile.h"
@@ -20,8 +22,9 @@ VSearchUE::VSearchUE(QObject *p_parent)
     : IUniversalEntry(p_parent),
       m_search(NULL),
       m_inSearch(false),
+      m_id(ID::Name_Notebook_AllNotebook),
       m_listWidget(NULL),
-      m_id(ID::Name_Notebook_AllNotebook)
+      m_treeWidget(NULL)
 {
 }
 
@@ -34,6 +37,9 @@ QString VSearchUE::description(int p_id) const
     case ID::Name_FolderNote_AllNotebook:
         return tr("Search the name of folders/notes in all notebooks");
 
+    case ID::Content_Note_AllNotebook:
+        return tr("Search the content of notes in all notebooks");
+
     default:
         Q_ASSERT(false);
         return tr("Invalid ID %1").arg(p_id);
@@ -63,8 +69,20 @@ void VSearchUE::init()
     m_listWidget = new VListWidgetDoubleRows(m_widgetParent);
     m_listWidget->setFitContent(true);
     m_listWidget->hide();
-    connect(m_listWidget, &VListWidgetDoubleRows::itemActivated,
-            this, &VSearchUE::activateItem);
+    connect(m_listWidget, SIGNAL(itemActivated(QListWidgetItem *)),
+            this, SLOT(activateItem(QListWidgetItem *)));
+
+    m_treeWidget = new VTreeWidget(m_widgetParent);
+    m_treeWidget->setColumnCount(1);
+    m_treeWidget->setHeaderHidden(true);
+    m_treeWidget->setExpandsOnDoubleClick(false);
+    m_treeWidget->setSimpleSearchMatchFlags(m_treeWidget->getSimpleSearchMatchFlags() & ~Qt::MatchRecursive);
+    m_treeWidget->setFitContent(true);
+    m_treeWidget->hide();
+    connect(m_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
+            this, SLOT(activateItem(QTreeWidgetItem *, int)));
+    connect(m_treeWidget, &VTreeWidget::itemExpanded,
+            this, &VSearchUE::widgetUpdated);
 }
 
 QWidget *VSearchUE::widget(int p_id)
@@ -73,10 +91,12 @@ QWidget *VSearchUE::widget(int p_id)
 
     switch (p_id) {
     case ID::Name_Notebook_AllNotebook:
-        V_FALLTHROUGH;
     case ID::Name_FolderNote_AllNotebook:
         return m_listWidget;
 
+    case ID::Content_Note_AllNotebook:
+        return m_treeWidget;
+
     default:
         Q_ASSERT(false);
         return NULL;
@@ -103,6 +123,10 @@ void VSearchUE::processCommand(int p_id, const QString &p_cmd)
         searchNameOfFolderNoteInAllNotebooks(p_cmd);
         break;
 
+    case ID::Content_Note_AllNotebook:
+        searchContentOfNoteInAllNotebooks(p_cmd);
+        break;
+
     default:
         Q_ASSERT(false);
         break;
@@ -165,6 +189,27 @@ void VSearchUE::searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd)
     }
 }
 
+void VSearchUE::searchContentOfNoteInAllNotebooks(const QString &p_cmd)
+{
+    const QVector<VNotebook *> &notebooks = g_vnote->getNotebooks();
+    if (p_cmd.isEmpty()) {
+        m_inSearch = false;
+        emit stateUpdated(State::Success);
+    } else {
+        VSearchConfig::Option opt = VSearchConfig::NoneOption;
+        QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::AllNotebooks,
+                                                               VSearchConfig::Content,
+                                                               VSearchConfig::Note,
+                                                               VSearchConfig::Internal,
+                                                               opt,
+                                                               p_cmd,
+                                                               QString()));
+        m_search->setConfig(config);
+        QSharedPointer<VSearchResult> result = m_search->search(notebooks);
+        handleSearchFinished(result);
+    }
+}
+
 void VSearchUE::clear(int p_id)
 {
     Q_UNUSED(p_id);
@@ -172,6 +217,7 @@ void VSearchUE::clear(int p_id)
 
     m_data.clear();
     m_listWidget->clearAll();
+    m_treeWidget->clearAll();
 }
 
 void VSearchUE::entryHidden(int p_id)
@@ -183,11 +229,14 @@ void VSearchUE::handleSearchItemAdded(const QSharedPointer<VSearchResultItem> &p
 {
     switch (m_id) {
     case ID::Name_Notebook_AllNotebook:
-        V_FALLTHROUGH;
     case ID::Name_FolderNote_AllNotebook:
         appendItemToList(p_item);
         break;
 
+    case ID::Content_Note_AllNotebook:
+        appendItemToTree(p_item);
+        break;
+
     default:
         break;
     }
@@ -228,13 +277,67 @@ void VSearchUE::appendItemToList(const QSharedPointer<VSearchResultItem> &p_item
     item->setData(Qt::UserRole, m_data.size() - 1);
     item->setToolTip(p_item->m_path);
 
+    ++itemAdded;
     if (m_listWidget->currentRow() == -1) {
         m_listWidget->setCurrentRow(0);
+        m_listWidget->updateGeometry();
+        emit widgetUpdated();
+    } else if (itemAdded >= 20) {
+        itemAdded = 0;
+        m_listWidget->updateGeometry();
+        emit widgetUpdated();
+    }
+}
+
+void VSearchUE::appendItemToTree(const QSharedPointer<VSearchResultItem> &p_item)
+{
+    static int itemAdded = 0;
+    m_data.append(p_item);
+
+    QTreeWidgetItem *item = new QTreeWidgetItem(m_treeWidget);
+    item->setData(0, Qt::UserRole, m_data.size() - 1);
+    item->setText(0, p_item->m_text.isEmpty() ? p_item->m_path : p_item->m_text);
+    item->setToolTip(0, p_item->m_path);
+
+    switch (p_item->m_type) {
+    case VSearchResultItem::Note:
+        item->setIcon(0, m_noteIcon);
+        break;
+
+    case VSearchResultItem::Folder:
+        item->setIcon(0, m_folderIcon);
+        break;
+
+    case VSearchResultItem::Notebook:
+        item->setIcon(0, m_notebookIcon);
+        break;
+
+    default:
+        break;
+    }
+
+    for (auto const & it: p_item->m_matches) {
+        QTreeWidgetItem *subItem = new QTreeWidgetItem(item);
+        QString text;
+        if (it.m_lineNumber > -1) {
+            text = QString("[%1] %2").arg(it.m_lineNumber).arg(it.m_text);
+        } else {
+            text = it.m_text;
+        }
+
+        subItem->setText(0, text);
+        subItem->setToolTip(0, it.m_text);
     }
 
-    if (++itemAdded >= 10) {
+    ++itemAdded;
+    if (!m_treeWidget->currentItem()) {
+        m_treeWidget->setCurrentItem(item);
+        m_treeWidget->resizeColumnToContents(0);
+        m_treeWidget->updateGeometry();
+        emit widgetUpdated();
+    } else if (itemAdded >= 20) {
         itemAdded = 0;
-        m_listWidget->updateGeometry();
+        m_treeWidget->updateGeometry();
         emit widgetUpdated();
     }
 }
@@ -248,11 +351,13 @@ void VSearchUE::handleSearchFinished(const QSharedPointer<VSearchResult> &p_resu
 
     IUniversalEntry::State state = State::Idle;
 
+    bool finished = true;
     switch (p_result->m_state) {
     case VSearchState::Busy:
         qDebug() << "search is ongoing";
         state = State::Busy;
-        return;
+        finished = false;
+        break;
 
     case VSearchState::Success:
         qDebug() << "search succeeded";
@@ -273,10 +378,17 @@ void VSearchUE::handleSearchFinished(const QSharedPointer<VSearchResult> &p_resu
         break;
     }
 
-    m_search->clear();
-    m_inSearch = false;
+    if (finished) {
+        m_search->clear();
+        m_inSearch = false;
+    }
+
+    QWidget *wid = widget(m_id);
+    if (wid == m_treeWidget) {
+        m_treeWidget->resizeColumnToContents(0);
+    }
 
-    widget(m_id)->updateGeometry();
+    wid->updateGeometry();
     emit widgetUpdated();
 
     emit stateUpdated(state);
@@ -302,26 +414,28 @@ const QSharedPointer<VSearchResultItem> &VSearchUE::itemResultData(const QListWi
     return m_data[idx];
 }
 
-void VSearchUE::activateItem(const QListWidgetItem *p_item)
+const QSharedPointer<VSearchResultItem> &VSearchUE::itemResultData(const QTreeWidgetItem *p_item) const
 {
-    if (!p_item) {
-        return;
-    }
-
-    emit requestHideUniversalEntry();
+    Q_ASSERT(p_item);
+    const QTreeWidgetItem *topItem = VUtils::topLevelTreeItem(p_item);
+    int idx = topItem->data(0, Qt::UserRole).toInt();
+    Q_ASSERT(idx >= 0 && idx < m_data.size());
+    return m_data[idx];
+}
 
-    const QSharedPointer<VSearchResultItem> &resItem = itemResultData(p_item);
-    switch (resItem->m_type) {
+void VSearchUE::activateItem(const QSharedPointer<VSearchResultItem> &p_item)
+{
+    switch (p_item->m_type) {
     case VSearchResultItem::Note:
     {
-        QStringList files(resItem->m_path);
+        QStringList files(p_item->m_path);
         g_mainWin->openFiles(files);
         break;
     }
 
     case VSearchResultItem::Folder:
     {
-        VDirectory *dir = g_vnote->getInternalDirectory(resItem->m_path);
+        VDirectory *dir = g_vnote->getInternalDirectory(p_item->m_path);
         if (dir) {
             g_mainWin->locateDirectory(dir);
         }
@@ -331,7 +445,7 @@ void VSearchUE::activateItem(const QListWidgetItem *p_item)
 
     case VSearchResultItem::Notebook:
     {
-        VNotebook *nb = g_vnote->getNotebook(resItem->m_path);
+        VNotebook *nb = g_vnote->getNotebook(p_item->m_path);
         if (nb) {
             g_mainWin->getNotebookSelector()->locateNotebook(nb);
         }
@@ -344,11 +458,31 @@ void VSearchUE::activateItem(const QListWidgetItem *p_item)
     }
 }
 
+void VSearchUE::activateItem(QListWidgetItem *p_item)
+{
+    if (!p_item) {
+        return;
+    }
+
+    emit requestHideUniversalEntry();
+    activateItem(itemResultData(p_item));
+}
+
+void VSearchUE::activateItem(QTreeWidgetItem *p_item, int p_col)
+{
+    Q_UNUSED(p_col);
+    if (!p_item) {
+        return;
+    }
+
+    emit requestHideUniversalEntry();
+    activateItem(itemResultData(p_item));
+}
+
 void VSearchUE::selectNextItem(int p_id, bool p_forward)
 {
     switch (p_id) {
     case ID::Name_Notebook_AllNotebook:
-        V_FALLTHROUGH;
     case ID::Name_FolderNote_AllNotebook:
     {
         // Could not use postEvent method here which will induce infinite recursion.
@@ -356,6 +490,12 @@ void VSearchUE::selectNextItem(int p_id, bool p_forward)
         break;
     }
 
+    case ID::Content_Note_AllNotebook:
+    {
+        m_treeWidget->selectNextItem(p_forward);
+        break;
+    }
+
     default:
         Q_ASSERT(false);
     }
@@ -365,13 +505,18 @@ void VSearchUE::activate(int p_id)
 {
     switch (p_id) {
     case ID::Name_Notebook_AllNotebook:
-        V_FALLTHROUGH;
     case ID::Name_FolderNote_AllNotebook:
     {
         activateItem(m_listWidget->currentItem());
         break;
     }
 
+    case ID::Content_Note_AllNotebook:
+    {
+        activateItem(m_treeWidget->currentItem(), 0);
+        break;
+    }
+
     default:
         Q_ASSERT(false);
     }

+ 19 - 2
src/vsearchue.h

@@ -10,6 +10,8 @@
 
 class VListWidgetDoubleRows;
 class QListWidgetItem;
+class VTreeWidget;
+class QTreeWidgetItem;
 
 
 // Universal Entry to list and search all the notebooks.
@@ -23,7 +25,10 @@ public:
         Name_Notebook_AllNotebook = 0,
 
         // Search the name of the folder/note in all the notebooks.
-        Name_FolderNote_AllNotebook
+        Name_FolderNote_AllNotebook,
+
+        // Search content of the note in all the notebooks.
+        Content_Note_AllNotebook,
     };
 
     explicit VSearchUE(QObject *p_parent = nullptr);
@@ -52,20 +57,30 @@ private slots:
 
     void handleSearchFinished(const QSharedPointer<VSearchResult> &p_result);
 
+    void activateItem(QListWidgetItem *p_item);
+
+    void activateItem(QTreeWidgetItem *p_item, int p_col);
+
 private:
     void searchNameOfAllNotebooks(const QString &p_cmd);
 
     void searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd);
 
+    void searchContentOfNoteInAllNotebooks(const QString &p_cmd);
+
     // Stop the search synchronously.
     void stopSearch();
 
     void appendItemToList(const QSharedPointer<VSearchResultItem> &p_item);
 
-    void activateItem(const QListWidgetItem *p_item);
+    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;
+
     VSearch *m_search;
 
     bool m_inSearch;
@@ -80,6 +95,8 @@ private:
     QIcon m_notebookIcon;
 
     VListWidgetDoubleRows *m_listWidget;
+
+    VTreeWidget *m_treeWidget;
 };
 
 #endif // VSEARCHUE_H

+ 28 - 14
src/vtreewidget.cpp

@@ -18,7 +18,8 @@
 
 VTreeWidget::VTreeWidget(QWidget *p_parent)
     : QTreeWidget(p_parent),
-      ISimpleSearch()
+      ISimpleSearch(),
+      m_fitContent(false)
 {
     setAttribute(Qt::WA_MacShowFocusRect, false);
 
@@ -45,6 +46,13 @@ VTreeWidget::VTreeWidget(QWidget *p_parent)
 
     m_delegate = new VStyledItemDelegate(this);
     setItemDelegate(m_delegate);
+
+    connect(this, &VTreeWidget::itemExpanded,
+            this, [this]() {
+                if (m_fitContent) {
+                    resizeColumnToContents(0);
+                }
+            });
 }
 
 void VTreeWidget::keyPressEvent(QKeyEvent *p_event)
@@ -288,26 +296,32 @@ void VTreeWidget::selectNextItem(bool p_forward)
         return;
     }
 
-    QTreeWidgetItem *nextItem = NULL;
+    QTreeWidgetItem *nItem = nextItem(item, p_forward);
+    if (nItem) {
+        setCurrentItem(nItem);
+    }
+}
+
+QTreeWidgetItem *VTreeWidget::nextItem(QTreeWidgetItem *p_item, bool p_forward)
+{
+    QTreeWidgetItem *nItem = NULL;
     if (p_forward) {
-        if (item->isExpanded()) {
-            nextItem = item->child(0);
+        if (p_item->isExpanded()) {
+            nItem = p_item->child(0);
         } else {
-            while (!nextItem && item) {
-                nextItem = nextSibling(item, true);
-                item = item->parent();
+            while (!nItem && p_item) {
+                nItem = nextSibling(p_item, true);
+                p_item = p_item->parent();
             }
         }
     } else {
-        nextItem = nextSibling(item, false);
-        if (!nextItem) {
-            nextItem = item->parent();
+        nItem = nextSibling(p_item, false);
+        if (!nItem) {
+            nItem = p_item->parent();
         } else {
-            nextItem = lastItemOfTree(nextItem);
+            nItem = lastItemOfTree(nItem);
         }
     }
 
-    if (nextItem) {
-        setCurrentItem(nextItem);
-    }
+    return nItem;
 }

+ 14 - 0
src/vtreewidget.h

@@ -39,6 +39,8 @@ public:
 
     virtual void selectNextItem(bool p_forward) Q_DECL_OVERRIDE;
 
+    void setFitContent(bool p_enabled);
+
 protected:
     void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
 
@@ -63,11 +65,16 @@ private:
 
     QTreeWidgetItem *nextSibling(QTreeWidgetItem *p_item, bool p_forward);
 
+    // Next visible item.
+    QTreeWidgetItem *nextItem(QTreeWidgetItem *p_item, bool p_forward);
+
     VSimpleSearchInput *m_searchInput;
 
     VStyledItemDelegate *m_delegate;
 
     QTimer *m_searchColdTimer;
+
+    bool m_fitContent;
 };
 
 inline void VTreeWidget::setSimpleSearchMatchFlags(Qt::MatchFlags p_flags)
@@ -79,4 +86,11 @@ inline Qt::MatchFlags VTreeWidget::getSimpleSearchMatchFlags() const
 {
     return m_searchInput->getMatchFlags();
 }
+
+inline void VTreeWidget::setFitContent(bool p_enabled)
+{
+    m_fitContent = p_enabled;
+    setSizeAdjustPolicy(m_fitContent ? QAbstractScrollArea::AdjustToContents
+                                     : QAbstractScrollArea::AdjustIgnored);
+}
 #endif // VTREEWIDGET_H