mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
add VTreeWidget with simple search and convert VDirectoryTree to it
This commit is contained in:
parent
0125251716
commit
878a272777
@ -2,33 +2,6 @@
|
|||||||
|
|
||||||
#include <QtWidgets>
|
#include <QtWidgets>
|
||||||
|
|
||||||
void VTreeWidget::dropEvent(QDropEvent *p_event)
|
|
||||||
{
|
|
||||||
QList<QTreeWidgetItem *> dragItems = selectedItems();
|
|
||||||
|
|
||||||
int first = -1, last = -1;
|
|
||||||
QTreeWidgetItem *firstItem = NULL;
|
|
||||||
for (int i = 0; i < dragItems.size(); ++i) {
|
|
||||||
int row = indexFromItem(dragItems[i]).row();
|
|
||||||
if (row > last) {
|
|
||||||
last = row;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first == -1 || row < first) {
|
|
||||||
first = row;
|
|
||||||
firstItem = dragItems[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_ASSERT(firstItem);
|
|
||||||
|
|
||||||
QTreeWidget::dropEvent(p_event);
|
|
||||||
|
|
||||||
int target = indexFromItem(firstItem).row();
|
|
||||||
emit rowsMoved(first, last, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VSortDialog::VSortDialog(const QString &p_title,
|
VSortDialog::VSortDialog(const QString &p_title,
|
||||||
const QString &p_info,
|
const QString &p_info,
|
||||||
QWidget *p_parent)
|
QWidget *p_parent)
|
||||||
|
@ -3,33 +3,11 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QTreeWidget>
|
|
||||||
|
#include "vtreewidget.h"
|
||||||
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QDialogButtonBox;
|
class QDialogButtonBox;
|
||||||
class QTreeWidget;
|
|
||||||
class QDropEvent;
|
|
||||||
|
|
||||||
// QTreeWidget won't emit the rowsMoved() signal after drag-and-drop.
|
|
||||||
// VTreeWidget will emit rowsMoved() signal.
|
|
||||||
class VTreeWidget : public QTreeWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit VTreeWidget(QWidget *p_parent = 0)
|
|
||||||
: QTreeWidget(p_parent)
|
|
||||||
{
|
|
||||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void dropEvent(QDropEvent *p_event) Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
// Rows [@p_first, @p_last] were moved to @p_row.
|
|
||||||
void rowsMoved(int p_first, int p_last, int p_row);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class VSortDialog : public QDialog
|
class VSortDialog : public QDialog
|
||||||
{
|
{
|
||||||
|
@ -111,7 +111,8 @@ SOURCES += main.cpp\
|
|||||||
vvimcmdlineedit.cpp \
|
vvimcmdlineedit.cpp \
|
||||||
vlistwidget.cpp \
|
vlistwidget.cpp \
|
||||||
vsimplesearchinput.cpp \
|
vsimplesearchinput.cpp \
|
||||||
vstyleditemdelegate.cpp
|
vstyleditemdelegate.cpp \
|
||||||
|
vtreewidget.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -209,7 +210,8 @@ HEADERS += vmainwindow.h \
|
|||||||
vvimcmdlineedit.h \
|
vvimcmdlineedit.h \
|
||||||
vlistwidget.h \
|
vlistwidget.h \
|
||||||
vsimplesearchinput.h \
|
vsimplesearchinput.h \
|
||||||
vstyleditemdelegate.h
|
vstyleditemdelegate.h \
|
||||||
|
vtreewidget.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc \
|
vnote.qrc \
|
||||||
|
@ -149,15 +149,6 @@ QString VUtils::generateImageFileName(const QString &path,
|
|||||||
return imageName;
|
return imageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VUtils::processStyle(QString &style, const QVector<QPair<QString, QString> > &varMap)
|
|
||||||
{
|
|
||||||
// Process style
|
|
||||||
for (int i = 0; i < varMap.size(); ++i) {
|
|
||||||
const QPair<QString, QString> &map = varMap[i];
|
|
||||||
style.replace("@" + map.first, map.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString VUtils::fileNameFromPath(const QString &p_path)
|
QString VUtils::fileNameFromPath(const QString &p_path)
|
||||||
{
|
{
|
||||||
if (p_path.isEmpty()) {
|
if (p_path.isEmpty()) {
|
||||||
|
@ -104,8 +104,6 @@ public:
|
|||||||
static QString generateCopiedDirName(const QString &p_parentDirPath,
|
static QString generateCopiedDirName(const QString &p_parentDirPath,
|
||||||
const QString &p_dirName);
|
const QString &p_dirName);
|
||||||
|
|
||||||
static void processStyle(QString &style, const QVector<QPair<QString, QString> > &varMap);
|
|
||||||
|
|
||||||
// Return the last directory name of @p_path.
|
// Return the last directory name of @p_path.
|
||||||
static QString directoryNameFromPath(const QString& p_path);
|
static QString directoryNameFromPath(const QString& p_path);
|
||||||
|
|
||||||
|
@ -25,13 +25,13 @@ const QString VDirectoryTree::c_cutShortcutSequence = "Ctrl+X";
|
|||||||
const QString VDirectoryTree::c_pasteShortcutSequence = "Ctrl+V";
|
const QString VDirectoryTree::c_pasteShortcutSequence = "Ctrl+V";
|
||||||
|
|
||||||
VDirectoryTree::VDirectoryTree(QWidget *parent)
|
VDirectoryTree::VDirectoryTree(QWidget *parent)
|
||||||
: QTreeWidget(parent), VNavigationMode(),
|
: VTreeWidget(parent),
|
||||||
|
VNavigationMode(),
|
||||||
m_editArea(NULL)
|
m_editArea(NULL)
|
||||||
{
|
{
|
||||||
setColumnCount(1);
|
setColumnCount(1);
|
||||||
setHeaderHidden(true);
|
setHeaderHidden(true);
|
||||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
|
||||||
|
|
||||||
initShortcuts();
|
initShortcuts();
|
||||||
initActions();
|
initActions();
|
||||||
@ -939,15 +939,11 @@ void VDirectoryTree::mousePressEvent(QMouseEvent *event)
|
|||||||
setCurrentItem(NULL);
|
setCurrentItem(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTreeWidget::mousePressEvent(event);
|
VTreeWidget::mousePressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDirectoryTree::keyPressEvent(QKeyEvent *event)
|
void VDirectoryTree::keyPressEvent(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
if (VimNavigationForWidget::injectKeyPressEventForVim(this, event)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int key = event->key();
|
int key = event->key();
|
||||||
int modifiers = event->modifiers();
|
int modifiers = event->modifiers();
|
||||||
|
|
||||||
@ -980,7 +976,7 @@ void VDirectoryTree::keyPressEvent(QKeyEvent *event)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTreeWidget::keyPressEvent(event);
|
VTreeWidget::keyPressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTreeWidgetItem *VDirectoryTree::findVDirectory(const VDirectory *p_dir, bool *p_widget)
|
QTreeWidgetItem *VDirectoryTree::findVDirectory(const VDirectory *p_dir, bool *p_widget)
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
#ifndef VDIRECTORYTREE_H
|
#ifndef VDIRECTORYTREE_H
|
||||||
#define VDIRECTORYTREE_H
|
#define VDIRECTORYTREE_H
|
||||||
|
|
||||||
#include <QTreeWidget>
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
|
||||||
|
#include "vtreewidget.h"
|
||||||
#include "vdirectory.h"
|
#include "vdirectory.h"
|
||||||
#include "vnotebook.h"
|
#include "vnotebook.h"
|
||||||
#include "vnavigationmode.h"
|
#include "vnavigationmode.h"
|
||||||
@ -16,7 +17,7 @@
|
|||||||
class VEditArea;
|
class VEditArea;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
|
||||||
class VDirectoryTree : public QTreeWidget, public VNavigationMode
|
class VDirectoryTree : public VTreeWidget, public VNavigationMode
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "vlistwidget.h"
|
#include "vlistwidget.h"
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
@ -49,12 +48,12 @@ void VListWidget::setSearchInputVisible(bool p_visible)
|
|||||||
{
|
{
|
||||||
m_searchInput->setVisible(p_visible);
|
m_searchInput->setVisible(p_visible);
|
||||||
|
|
||||||
int topMargin = 0;
|
int bottomMargin = 0;
|
||||||
if (p_visible) {
|
if (p_visible) {
|
||||||
topMargin = m_searchInput->height();
|
bottomMargin = m_searchInput->height();
|
||||||
}
|
}
|
||||||
|
|
||||||
setViewportMargins(0, topMargin, 0, 0);
|
setViewportMargins(0, 0, 0, bottomMargin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VListWidget::resizeEvent(QResizeEvent *p_event)
|
void VListWidget::resizeEvent(QResizeEvent *p_event)
|
||||||
@ -68,8 +67,14 @@ void VListWidget::resizeEvent(QResizeEvent *p_event)
|
|||||||
width -= vbar->width();
|
width -= vbar->width();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int y = rect.bottom() - m_searchInput->height();
|
||||||
|
QScrollBar *hbar = horizontalScrollBar();
|
||||||
|
if (hbar && (hbar->minimum() != hbar->maximum())) {
|
||||||
|
y -= hbar->height();
|
||||||
|
}
|
||||||
|
|
||||||
m_searchInput->setGeometry(QRect(rect.left(),
|
m_searchInput->setGeometry(QRect(rect.left(),
|
||||||
rect.top(),
|
y,
|
||||||
width,
|
width,
|
||||||
m_searchInput->height()));
|
m_searchInput->height()));
|
||||||
}
|
}
|
||||||
@ -131,3 +136,9 @@ int VListWidget::totalNumberOfItems()
|
|||||||
{
|
{
|
||||||
return count();
|
return count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VListWidget::selectNextItem(bool p_forward)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_forward);
|
||||||
|
Q_ASSERT(false);
|
||||||
|
}
|
||||||
|
@ -29,6 +29,8 @@ public:
|
|||||||
|
|
||||||
virtual int totalNumberOfItems() Q_DECL_OVERRIDE;
|
virtual int totalNumberOfItems() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void selectNextItem(bool p_forward) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleSearchModeTriggered(bool p_inSearchMode);
|
void handleSearchModeTriggered(bool p_inSearchMode);
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ VSimpleSearchInput::VSimpleSearchInput(ISimpleSearch *p_obj, QWidget *p_parent)
|
|||||||
m_obj(p_obj),
|
m_obj(p_obj),
|
||||||
m_inSearchMode(false),
|
m_inSearchMode(false),
|
||||||
m_currentIdx(-1),
|
m_currentIdx(-1),
|
||||||
m_wildCardEnabled(g_config->getEnableWildCardInSimpleSearch())
|
m_wildCardEnabled(g_config->getEnableWildCardInSimpleSearch()),
|
||||||
|
m_navigationKeyEnabled(false)
|
||||||
{
|
{
|
||||||
if (m_wildCardEnabled) {
|
if (m_wildCardEnabled) {
|
||||||
m_matchFlags = Qt::MatchWildcard | Qt::MatchWrap | Qt::MatchRecursive;
|
m_matchFlags = Qt::MatchWildcard | Qt::MatchWrap | Qt::MatchRecursive;
|
||||||
@ -151,6 +152,23 @@ bool VSimpleSearchInput::tryHandleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Up/Down Ctrl+K/J to navigate to next item.
|
||||||
|
// QTreeWidget may not response to the key event if it does not have the focus.
|
||||||
|
if (m_inSearchMode && m_navigationKeyEnabled) {
|
||||||
|
if (key == Qt::Key_Down
|
||||||
|
|| key == Qt::Key_Up
|
||||||
|
|| (VUtils::isControlModifierForVim(modifiers)
|
||||||
|
&& (key == Qt::Key_J || key == Qt::Key_K))) {
|
||||||
|
bool forward = true;
|
||||||
|
if (key == Qt::Key_Up || key == Qt::Key_K) {
|
||||||
|
forward = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_obj->selectNextItem(forward);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,13 +199,13 @@ bool VSimpleSearchInput::eventFilter(QObject *p_watched, QEvent *p_event)
|
|||||||
void VSimpleSearchInput::handleEditTextChanged(const QString &p_text)
|
void VSimpleSearchInput::handleEditTextChanged(const QString &p_text)
|
||||||
{
|
{
|
||||||
if (!m_inSearchMode) {
|
if (!m_inSearchMode) {
|
||||||
return;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_text.isEmpty()) {
|
if (p_text.isEmpty()) {
|
||||||
clearSearch();
|
clearSearch();
|
||||||
m_obj->selectHitItem(NULL);
|
m_obj->selectHitItem(NULL);
|
||||||
return;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_wildCardEnabled) {
|
if (m_wildCardEnabled) {
|
||||||
@ -208,6 +226,9 @@ void VSimpleSearchInput::handleEditTextChanged(const QString &p_text)
|
|||||||
m_currentIdx = m_hitItems.isEmpty() ? -1 : 0;
|
m_currentIdx = m_hitItems.isEmpty() ? -1 : 0;
|
||||||
|
|
||||||
m_obj->selectHitItem(currentItem());
|
m_obj->selectHitItem(currentItem());
|
||||||
|
|
||||||
|
exit:
|
||||||
|
emit inputTextChanged(p_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VSimpleSearchInput::updateInfoLabel(int p_nrHit, int p_total)
|
void VSimpleSearchInput::updateInfoLabel(int p_nrHit, int p_total)
|
||||||
|
@ -26,6 +26,9 @@ public:
|
|||||||
|
|
||||||
// Get the total number of all the items.
|
// Get the total number of all the items.
|
||||||
virtual int totalNumberOfItems() = 0;
|
virtual int totalNumberOfItems() = 0;
|
||||||
|
|
||||||
|
// Select next item.
|
||||||
|
virtual void selectNextItem(bool p_forward) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -42,10 +45,14 @@ public:
|
|||||||
// Return true if @p_event is consumed and do not need further process.
|
// Return true if @p_event is consumed and do not need further process.
|
||||||
bool tryHandleKeyPressEvent(QKeyEvent *p_event);
|
bool tryHandleKeyPressEvent(QKeyEvent *p_event);
|
||||||
|
|
||||||
|
void setNavigationKeyEnabled(bool p_enabled);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// Search mode is triggered.
|
// Search mode is triggered.
|
||||||
void triggered(bool p_inSearchMode);
|
void triggered(bool p_inSearchMode);
|
||||||
|
|
||||||
|
void inputTextChanged(const QString &p_text);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject *p_watched, QEvent *p_event) Q_DECL_OVERRIDE;
|
bool eventFilter(QObject *p_watched, QEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
@ -76,6 +83,9 @@ private:
|
|||||||
Qt::MatchFlags m_matchFlags;
|
Qt::MatchFlags m_matchFlags;
|
||||||
|
|
||||||
bool m_wildCardEnabled;
|
bool m_wildCardEnabled;
|
||||||
|
|
||||||
|
// Down/Up/Ctrl+J/Ctrl+K to navigate.
|
||||||
|
bool m_navigationKeyEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void *VSimpleSearchInput::currentItem() const
|
inline void *VSimpleSearchInput::currentItem() const
|
||||||
@ -86,4 +96,9 @@ inline void *VSimpleSearchInput::currentItem() const
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void VSimpleSearchInput::setNavigationKeyEnabled(bool p_enabled)
|
||||||
|
{
|
||||||
|
m_navigationKeyEnabled = p_enabled;
|
||||||
|
}
|
||||||
#endif // VSIMPLESEARCHINPUT_H
|
#endif // VSIMPLESEARCHINPUT_H
|
||||||
|
321
src/vtreewidget.cpp
Normal file
321
src/vtreewidget.cpp
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
#include "vtreewidget.h"
|
||||||
|
|
||||||
|
#include <QDropEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QGraphicsOpacityEffect>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
#include "utils/vimnavigationforwidget.h"
|
||||||
|
#include "vstyleditemdelegate.h"
|
||||||
|
|
||||||
|
#define SEARCH_INPUT_NORMAL_OPACITY 0.8
|
||||||
|
|
||||||
|
#define SEARCH_INPUT_IDLE_OPACITY 0.2
|
||||||
|
|
||||||
|
VTreeWidget::VTreeWidget(QWidget *p_parent)
|
||||||
|
: QTreeWidget(p_parent),
|
||||||
|
ISimpleSearch()
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||||
|
|
||||||
|
m_searchInput = new VSimpleSearchInput(this, this);
|
||||||
|
m_searchInput->setNavigationKeyEnabled(true);
|
||||||
|
connect(m_searchInput, &VSimpleSearchInput::triggered,
|
||||||
|
this, &VTreeWidget::handleSearchModeTriggered);
|
||||||
|
connect(m_searchInput, &VSimpleSearchInput::inputTextChanged,
|
||||||
|
this, &VTreeWidget::handleSearchInputTextChanged);
|
||||||
|
|
||||||
|
QGraphicsOpacityEffect * effect = new QGraphicsOpacityEffect(m_searchInput);
|
||||||
|
effect->setOpacity(SEARCH_INPUT_NORMAL_OPACITY);
|
||||||
|
m_searchInput->setGraphicsEffect(effect);
|
||||||
|
m_searchInput->hide();
|
||||||
|
|
||||||
|
m_searchColdTimer = new QTimer(this);
|
||||||
|
m_searchColdTimer->setSingleShot(true);
|
||||||
|
m_searchColdTimer->setInterval(1000);
|
||||||
|
connect(m_searchColdTimer, &QTimer::timeout,
|
||||||
|
this, [this]() {
|
||||||
|
QGraphicsOpacityEffect *effect = getSearchInputEffect();
|
||||||
|
Q_ASSERT(effect);
|
||||||
|
effect->setOpacity(SEARCH_INPUT_IDLE_OPACITY);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_delegate = new VStyledItemDelegate(this);
|
||||||
|
setItemDelegate(m_delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::keyPressEvent(QKeyEvent *p_event)
|
||||||
|
{
|
||||||
|
if (m_searchInput->tryHandleKeyPressEvent(p_event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VimNavigationForWidget::injectKeyPressEventForVim(this, p_event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidget::keyPressEvent(p_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::clearAll()
|
||||||
|
{
|
||||||
|
m_searchInput->clear();
|
||||||
|
setSearchInputVisible(false);
|
||||||
|
|
||||||
|
VTreeWidget::clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::setSearchInputVisible(bool p_visible)
|
||||||
|
{
|
||||||
|
m_searchInput->setVisible(p_visible);
|
||||||
|
// setViewportMargins() and setContentsMargins() do not work for QTreeWidget.
|
||||||
|
// setStyleSheet(QString("padding-bottom: %1px").arg(bottomMargin));
|
||||||
|
QGraphicsOpacityEffect *effect = getSearchInputEffect();
|
||||||
|
Q_ASSERT(effect);
|
||||||
|
effect->setOpacity(SEARCH_INPUT_NORMAL_OPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::resizeEvent(QResizeEvent *p_event)
|
||||||
|
{
|
||||||
|
QTreeWidget::resizeEvent(p_event);
|
||||||
|
|
||||||
|
QRect contentRect = contentsRect();
|
||||||
|
int width = contentRect.width();
|
||||||
|
QScrollBar *vbar = verticalScrollBar();
|
||||||
|
if (vbar && (vbar->minimum() != vbar->maximum())) {
|
||||||
|
width -= vbar->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
int y = height() - m_searchInput->height();
|
||||||
|
QScrollBar *hbar = horizontalScrollBar();
|
||||||
|
if (hbar && (hbar->minimum() != hbar->maximum())) {
|
||||||
|
y -= hbar->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_searchInput->setGeometry(QRect(contentRect.left(),
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
m_searchInput->height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::handleSearchModeTriggered(bool p_inSearchMode)
|
||||||
|
{
|
||||||
|
setSearchInputVisible(p_inSearchMode);
|
||||||
|
if (!p_inSearchMode) {
|
||||||
|
clearItemsHighlight();
|
||||||
|
|
||||||
|
setFocus();
|
||||||
|
|
||||||
|
QTreeWidgetItem *item = currentItem();
|
||||||
|
if (item) {
|
||||||
|
setCurrentItem(item);
|
||||||
|
} else if (topLevelItemCount() > 0) {
|
||||||
|
setCurrentItem(topLevelItem(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::dropEvent(QDropEvent *p_event)
|
||||||
|
{
|
||||||
|
QList<QTreeWidgetItem *> dragItems = selectedItems();
|
||||||
|
|
||||||
|
int first = -1, last = -1;
|
||||||
|
QTreeWidgetItem *firstItem = NULL;
|
||||||
|
for (int i = 0; i < dragItems.size(); ++i) {
|
||||||
|
int row = indexFromItem(dragItems[i]).row();
|
||||||
|
if (row > last) {
|
||||||
|
last = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first == -1 || row < first) {
|
||||||
|
first = row;
|
||||||
|
firstItem = dragItems[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(firstItem);
|
||||||
|
|
||||||
|
QTreeWidget::dropEvent(p_event);
|
||||||
|
|
||||||
|
int target = indexFromItem(firstItem).row();
|
||||||
|
emit rowsMoved(first, last, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<void *> VTreeWidget::searchItems(const QString &p_text,
|
||||||
|
Qt::MatchFlags p_flags) const
|
||||||
|
{
|
||||||
|
QList<QTreeWidgetItem *> items = findItems(p_text, p_flags);
|
||||||
|
|
||||||
|
QList<void *> res;
|
||||||
|
res.reserve(items.size());
|
||||||
|
for (int i = 0; i < items.size(); ++i) {
|
||||||
|
res.append(items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::highlightHitItems(const QList<void *> &p_items)
|
||||||
|
{
|
||||||
|
clearItemsHighlight();
|
||||||
|
|
||||||
|
QSet<QModelIndex> hitIndexes;
|
||||||
|
for (auto it : p_items) {
|
||||||
|
QModelIndex index = indexFromItem(static_cast<QTreeWidgetItem *>(it));
|
||||||
|
if (index.isValid()) {
|
||||||
|
hitIndexes.insert(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hitIndexes.isEmpty()) {
|
||||||
|
m_delegate->setHitItems(hitIndexes);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::clearItemsHighlight()
|
||||||
|
{
|
||||||
|
m_delegate->clearHitItems();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::selectHitItem(void *p_item)
|
||||||
|
{
|
||||||
|
setCurrentItem(static_cast<QTreeWidgetItem *>(p_item),
|
||||||
|
QItemSelectionModel::ClearAndSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the total number of tree @p_item.
|
||||||
|
static int treeItemCount(QTreeWidgetItem *p_item)
|
||||||
|
{
|
||||||
|
if (!p_item) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int child = p_item->childCount();
|
||||||
|
int total = 1;
|
||||||
|
for (int i = 0; i < child; ++i) {
|
||||||
|
total += treeItemCount(p_item->child(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VTreeWidget::totalNumberOfItems()
|
||||||
|
{
|
||||||
|
int total = 0;
|
||||||
|
int cn = topLevelItemCount();
|
||||||
|
for (int i = 0; i < cn; ++i) {
|
||||||
|
total += treeItemCount(topLevelItem(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::handleSearchInputTextChanged(const QString &p_text)
|
||||||
|
{
|
||||||
|
m_searchColdTimer->stop();
|
||||||
|
m_searchColdTimer->start();
|
||||||
|
|
||||||
|
Q_UNUSED(p_text);
|
||||||
|
QGraphicsOpacityEffect *effect = getSearchInputEffect();
|
||||||
|
Q_ASSERT(effect);
|
||||||
|
effect->setOpacity(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
QGraphicsOpacityEffect *VTreeWidget::getSearchInputEffect() const
|
||||||
|
{
|
||||||
|
return static_cast<QGraphicsOpacityEffect *>(m_searchInput->graphicsEffect());
|
||||||
|
}
|
||||||
|
|
||||||
|
static QTreeWidgetItem *lastItemOfTree(QTreeWidgetItem *p_item)
|
||||||
|
{
|
||||||
|
if (p_item->isExpanded()) {
|
||||||
|
Q_ASSERT(p_item->childCount() > 0);
|
||||||
|
return p_item->child(p_item->childCount() - 1);
|
||||||
|
} else {
|
||||||
|
return p_item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *VTreeWidget::nextSibling(QTreeWidgetItem *p_item, bool p_forward)
|
||||||
|
{
|
||||||
|
if (!p_item) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *pa = p_item->parent();
|
||||||
|
if (pa) {
|
||||||
|
int idx = pa->indexOfChild(p_item);
|
||||||
|
if (p_forward) {
|
||||||
|
++idx;
|
||||||
|
if (idx >= pa->childCount()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
--idx;
|
||||||
|
if (idx < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pa->child(idx);
|
||||||
|
} else {
|
||||||
|
// Top level item.
|
||||||
|
int idx = indexOfTopLevelItem(p_item);
|
||||||
|
if (p_forward) {
|
||||||
|
++idx;
|
||||||
|
if (idx >= topLevelItemCount()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
--idx;
|
||||||
|
if (idx < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return topLevelItem(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTreeWidget::selectNextItem(bool p_forward)
|
||||||
|
{
|
||||||
|
if (topLevelItemCount() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *item = currentItem();
|
||||||
|
if (!item) {
|
||||||
|
setCurrentItem(topLevelItem(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *nextItem = NULL;
|
||||||
|
if (p_forward) {
|
||||||
|
if (item->isExpanded()) {
|
||||||
|
nextItem = item->child(0);
|
||||||
|
} else {
|
||||||
|
while (!nextItem && item) {
|
||||||
|
nextItem = nextSibling(item, true);
|
||||||
|
item = item->parent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nextItem = nextSibling(item, false);
|
||||||
|
if (!nextItem) {
|
||||||
|
nextItem = item->parent();
|
||||||
|
} else {
|
||||||
|
nextItem = lastItemOfTree(nextItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextItem) {
|
||||||
|
setCurrentItem(nextItem);
|
||||||
|
}
|
||||||
|
}
|
68
src/vtreewidget.h
Normal file
68
src/vtreewidget.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#ifndef VTREEWIDGET_H
|
||||||
|
#define VTREEWIDGET_H
|
||||||
|
|
||||||
|
#include <QTreeWidget>
|
||||||
|
|
||||||
|
#include "vsimplesearchinput.h"
|
||||||
|
|
||||||
|
class QDropEvent;
|
||||||
|
class VStyledItemDelegate;
|
||||||
|
class QTimer;
|
||||||
|
class QGraphicsOpacityEffect;
|
||||||
|
|
||||||
|
// QTreeWidget won't emit the rowsMoved() signal after drag-and-drop.
|
||||||
|
// VTreeWidget will emit rowsMoved() signal.
|
||||||
|
class VTreeWidget : public QTreeWidget, public ISimpleSearch
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VTreeWidget(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
// Clear tree widget as well as other data.
|
||||||
|
void clearAll();
|
||||||
|
|
||||||
|
// Implement ISimpleSearch.
|
||||||
|
virtual QList<void *> searchItems(const QString &p_text,
|
||||||
|
Qt::MatchFlags p_flags) const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void highlightHitItems(const QList<void *> &p_items) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void clearItemsHighlight() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void selectHitItem(void *p_item) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
virtual int totalNumberOfItems() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void selectNextItem(bool p_forward) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void dropEvent(QDropEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// Rows [@p_first, @p_last] were moved to @p_row.
|
||||||
|
void rowsMoved(int p_first, int p_last, int p_row);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleSearchModeTriggered(bool p_inSearchMode);
|
||||||
|
|
||||||
|
void handleSearchInputTextChanged(const QString &p_text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Show or hide search input.
|
||||||
|
void setSearchInputVisible(bool p_visible);
|
||||||
|
|
||||||
|
QGraphicsOpacityEffect *getSearchInputEffect() const;
|
||||||
|
|
||||||
|
QTreeWidgetItem *nextSibling(QTreeWidgetItem *p_item, bool p_forward);
|
||||||
|
|
||||||
|
VSimpleSearchInput *m_searchInput;
|
||||||
|
|
||||||
|
VStyledItemDelegate *m_delegate;
|
||||||
|
|
||||||
|
QTimer *m_searchColdTimer;
|
||||||
|
};
|
||||||
|
#endif // VTREEWIDGET_H
|
Loading…
x
Reference in New Issue
Block a user