mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
328 lines
7.9 KiB
C++
328 lines
7.9 KiB
C++
#include "treewidget.h"
|
|
|
|
#include <QMouseEvent>
|
|
#include <QHeaderView>
|
|
#include <QKeyEvent>
|
|
#include <QDropEvent>
|
|
|
|
#include <utils/widgetutils.h>
|
|
#include "styleditemdelegate.h"
|
|
|
|
using namespace vnotex;
|
|
|
|
TreeWidget::TreeWidget(QWidget *p_parent)
|
|
: QTreeWidget(p_parent)
|
|
{
|
|
}
|
|
|
|
TreeWidget::TreeWidget(TreeWidget::Flags p_flags, QWidget *p_parent)
|
|
: QTreeWidget(p_parent),
|
|
m_flags(p_flags)
|
|
{
|
|
if (m_flags & Flag::EnhancedStyle) {
|
|
auto interface = QSharedPointer<StyledItemDelegateTreeWidget>::create(this);
|
|
auto delegate = new StyledItemDelegate(interface, StyledItemDelegate::Highlights, this);
|
|
setItemDelegate(delegate);
|
|
}
|
|
}
|
|
|
|
void TreeWidget::mousePressEvent(QMouseEvent *p_event)
|
|
{
|
|
QTreeWidget::mousePressEvent(p_event);
|
|
|
|
if (m_flags & Flag::ClickSpaceToClearSelection) {
|
|
auto idx = indexAt(p_event->pos());
|
|
if (!idx.isValid()) {
|
|
clearSelection();
|
|
setCurrentItem(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TreeWidget::setupSingleColumnHeaderlessTree(QTreeWidget *p_widget, bool p_contextMenu, bool p_extendedSelection)
|
|
{
|
|
p_widget->setColumnCount(1);
|
|
p_widget->setHeaderHidden(true);
|
|
if (p_contextMenu) {
|
|
p_widget->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
}
|
|
if (p_extendedSelection) {
|
|
p_widget->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
}
|
|
}
|
|
|
|
void TreeWidget::showHorizontalScrollbar(QTreeWidget *p_tree)
|
|
{
|
|
p_tree->header()->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
p_tree->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
p_tree->header()->setStretchLastSection(false);
|
|
}
|
|
|
|
QTreeWidgetItem *TreeWidget::findItem(const QTreeWidget *p_widget, const QVariant &p_data, int p_column)
|
|
{
|
|
int nrTop = p_widget->topLevelItemCount();
|
|
for (int i = 0; i < nrTop; ++i) {
|
|
auto item = findItemHelper(p_widget->topLevelItem(i), p_data, p_column);
|
|
if (item) {
|
|
return item;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QTreeWidgetItem *TreeWidget::findItemHelper(QTreeWidgetItem *p_item, const QVariant &p_data, int p_column)
|
|
{
|
|
if (!p_item) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (p_item->data(0, Qt::UserRole) == p_data) {
|
|
return p_item;
|
|
}
|
|
|
|
int nrChild = p_item->childCount();
|
|
for (int i = 0; i < nrChild; ++i) {
|
|
auto item = findItemHelper(p_item->child(i), p_data, p_column);
|
|
if (item) {
|
|
return item;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void TreeWidget::keyPressEvent(QKeyEvent *p_event)
|
|
{
|
|
if (WidgetUtils::processKeyEventLikeVi(this, p_event)) {
|
|
return;
|
|
}
|
|
|
|
// On Mac OS X, it is `Command+O` to activate an item, instead of Return.
|
|
#if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
|
|
if (p_event->key() == Qt::Key_Return) {
|
|
if (auto item = currentItem()) {
|
|
emit itemActivated(item, currentColumn());
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
QTreeWidget::keyPressEvent(p_event);
|
|
}
|
|
|
|
QTreeWidgetItem *TreeWidget::nextItem(const QTreeWidget *p_tree,
|
|
QTreeWidgetItem *p_item,
|
|
bool p_forward)
|
|
{
|
|
QTreeWidgetItem *nItem = NULL;
|
|
if (p_forward) {
|
|
if (p_item->isExpanded() && p_item->childCount() > 0) {
|
|
nItem = p_item->child(0);
|
|
} else {
|
|
while (!nItem && p_item) {
|
|
nItem = nextSibling(p_tree, p_item, true);
|
|
p_item = p_item->parent();
|
|
}
|
|
}
|
|
} else {
|
|
nItem = nextSibling(p_tree, p_item, false);
|
|
if (!nItem) {
|
|
nItem = p_item->parent();
|
|
} else {
|
|
nItem = lastItemOfTree(nItem);
|
|
}
|
|
}
|
|
|
|
return nItem;
|
|
}
|
|
|
|
QTreeWidgetItem *TreeWidget::lastItemOfTree(QTreeWidgetItem *p_item)
|
|
{
|
|
if (p_item->isExpanded() && p_item->childCount() > 0) {
|
|
return p_item->child(p_item->childCount() - 1);
|
|
} else {
|
|
return p_item;
|
|
}
|
|
}
|
|
|
|
QTreeWidgetItem *TreeWidget::nextSibling(const QTreeWidget *p_tree,
|
|
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 = p_tree->indexOfTopLevelItem(p_item);
|
|
if (p_forward) {
|
|
++idx;
|
|
if (idx >= p_tree->topLevelItemCount()) {
|
|
return NULL;
|
|
}
|
|
} else {
|
|
--idx;
|
|
if (idx < 0) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return p_tree->topLevelItem(idx);
|
|
}
|
|
}
|
|
|
|
QVector<QTreeWidgetItem *> TreeWidget::getVisibleItems(const QTreeWidget *p_widget)
|
|
{
|
|
QVector<QTreeWidgetItem *> items;
|
|
|
|
auto firstItem = p_widget->itemAt(0, 0);
|
|
if (!firstItem) {
|
|
return items;
|
|
}
|
|
|
|
auto lastItem = p_widget->itemAt(p_widget->viewport()->rect().bottomLeft());
|
|
|
|
auto item = firstItem;
|
|
while (item) {
|
|
items.append(item);
|
|
if (item == lastItem) {
|
|
break;
|
|
}
|
|
|
|
item = nextItem(p_widget, item, true);
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
void TreeWidget::dropEvent(QDropEvent *p_event)
|
|
{
|
|
auto dragItems = selectedItems();
|
|
|
|
QTreeWidget::dropEvent(p_event);
|
|
|
|
if (dragItems.size() == 1) {
|
|
emit itemMoved(dragItems[0]);
|
|
}
|
|
}
|
|
|
|
void TreeWidget::forEachItem(const QTreeWidget *p_widget, const std::function<bool(QTreeWidgetItem *p_item)> &p_func)
|
|
{
|
|
const int cnt = p_widget->topLevelItemCount();
|
|
for (int i = 0; i < cnt; ++i) {
|
|
if (!forEachItem(p_widget->topLevelItem(i), p_func)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool TreeWidget::forEachItem(QTreeWidgetItem *p_item, const std::function<bool(QTreeWidgetItem *p_item)> &p_func)
|
|
{
|
|
if (!p_item) {
|
|
return true;
|
|
}
|
|
|
|
if (!p_func(p_item)) {
|
|
return false;
|
|
}
|
|
|
|
const int cnt = p_item->childCount();
|
|
for (int i = 0; i < cnt; ++i) {
|
|
if (!forEachItem(p_item->child(i), p_func)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void TreeWidget::mark(QTreeWidgetItem *p_item, int p_column)
|
|
{
|
|
p_item->setData(p_column, Qt::ForegroundRole, StyledItemDelegate::s_highlightForeground);
|
|
p_item->setData(p_column, Qt::BackgroundRole, StyledItemDelegate::s_highlightBackground);
|
|
}
|
|
|
|
void TreeWidget::unmark(QTreeWidgetItem *p_item, int p_column)
|
|
{
|
|
p_item->setData(p_column, Qt::ForegroundRole, QVariant());
|
|
p_item->setData(p_column, Qt::BackgroundRole, QVariant());
|
|
}
|
|
|
|
void TreeWidget::expandRecursively(QTreeWidgetItem *p_item)
|
|
{
|
|
if (!p_item) {
|
|
return;
|
|
}
|
|
|
|
p_item->setExpanded(true);
|
|
const int cnt = p_item->childCount();
|
|
if (cnt == 0) {
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < cnt; ++i) {
|
|
expandRecursively(p_item->child(i));
|
|
}
|
|
}
|
|
|
|
void TreeWidget::selectParentItem(QTreeWidget *p_widget)
|
|
{
|
|
auto item = p_widget->currentItem();
|
|
if (item) {
|
|
auto pitem = item->parent();
|
|
if (pitem) {
|
|
p_widget->setCurrentItem(pitem, 0, QItemSelectionModel::ClearAndSelect);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool isItemTreeExpanded(const QTreeWidgetItem *p_item)
|
|
{
|
|
if (!p_item) {
|
|
return true;
|
|
}
|
|
|
|
if (p_item->isHidden() || !p_item->isExpanded()) {
|
|
return false;
|
|
}
|
|
|
|
int cnt = p_item->childCount();
|
|
for (int i = 0; i < cnt; ++i) {
|
|
if (!isItemTreeExpanded(p_item->child(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TreeWidget::isExpanded(const QTreeWidget *p_widget)
|
|
{
|
|
int cnt = p_widget->topLevelItemCount();
|
|
for (int i = 0; i < cnt; ++i) {
|
|
if (!isItemTreeExpanded(p_widget->topLevelItem(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|