#include "treewidget.h" #include #include #include #include #include #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::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 TreeWidget::getVisibleItems(const QTreeWidget *p_widget) { QVector 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 &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 &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; }