/** * @file PaiTreeWidget.cpp * @brief P.A.I系统定制发布的树控件 * @date 2012-10-18 */ #include #include #include "PaiTreeWidget.h" #include "GlobalUtility.h" // 设置树标题栏的最小高度 const int HEADER_MINHEIGHT = 27; using namespace pai::gui; PaiTreeWidget::PaiTreeWidget(QWidget *pParent) : QTreeWidget(pParent), m_InSearching(false), m_pTipLabel(NULL) { this->header()->setMinimumHeight(HEADER_MINHEIGHT); } PaiTreeWidget::~PaiTreeWidget() { } void PaiTreeWidget::Filter(const QString & keyword, int column) { Filter(keyword, QList() << column); } void PaiTreeWidget::Filter(const QString & keyword, QList columns) { // 去掉搜索结果为空的提示 if(m_pTipLabel) { m_pTipLabel->hide(); } // 记住搜索前树的状态,以便搜索之后重新显示 if(!m_InSearching) { for(QTreeWidgetItemIterator it(this); *it; ++it) { (*it)->setData(1, pai::gui::SearchRole, (*it)->isExpanded()); (*it)->setData(2, pai::gui::SearchRole, (*it)->isSelected()); } m_InSearching = true; } // 如果搜索字符为空,认为搜索结束,恢复搜索前树的状态 if(keyword.isEmpty()) { // 此处必须用两次循环来实现,第一次来表示选中与否,第二次来表示展开与否 // 之所以这样做,是因为在选中某节点的时候其相应的父节点也会自动展开, // 造成还原效果与之前记录的效果不一致的问题(defect:17515) clearSelection(); for(QTreeWidgetItemIterator it(this); *it; ++it) { (*it)->setHidden(false); (*it)->setSelected((*it)->data(2, pai::gui::SearchRole).toBool()); } for(QTreeWidgetItemIterator it(this); *it; ++it) { (*it)->setExpanded((*it)->data(1, pai::gui::SearchRole).toBool()); } m_InSearching = false; emit SearchFinished(invisibleRootItem()); return; } // 遍历树,来搜索符合条件的节点, 建于绝大多数用户对正则表达式的了解,目前只支持到‘*’ ‘?’ bool bWildcard = keyword.contains('*') || keyword.contains('?'); QList searchResult; for(int col=0; colsetHidden(false); } } foreach(QTreeWidgetItem *pItem, searchResult) { pItem->setHidden(true); // 隐藏搜索结果集本身 pItem->setSelected(true); pItem->setExpanded(false); } if(!searchResult.empty()) { for(QTreeWidgetItemIterator it(this); *it; ++it) { bool bGenerationOfResult = IsGenerationOfFoundItem(*it); (*it)->setHidden(bGenerationOfResult); // 隐藏搜索结果集的子代,显示结果集的父母和兄弟 } foreach(QTreeWidgetItem *pItem, searchResult) { QTreeWidgetItem *pParentItem = pItem->parent(); while(pParentItem) { pParentItem->setHidden(true); // 隐藏搜索结果集的直系父代 pParentItem->setExpanded(true); // 顺便置展开状态 pParentItem = pParentItem->parent(); } } for(QTreeWidgetItemIterator it(this); *it; ++it) { (*it)->setHidden((!(*it)->isHidden()));//取反来显示所有搜索结果 } } // 如果没搜到任何东西,则显示未找到提示 if(searchResult.empty()) { for(int i = 0; i < topLevelItemCount(); ++i) { topLevelItem(i)->setHidden(true); } if(!m_pTipLabel) { m_pTipLabel = new QLabel(tr("found nothing!"), this); } m_pTipLabel->move((width() - m_pTipLabel->width()) / 2, HEADER_MINHEIGHT); m_pTipLabel->show(); // 必须调用此函数,否则显示不出来 } else // 如果搜索到结果,就将搜索到的第一个节点滚动到顶端显示 { scrollToItem(searchResult.first(), QAbstractItemView::PositionAtTop); } emit SearchFinished(invisibleRootItem()); } bool PaiTreeWidget::IsGenerationOfFoundItem(QTreeWidgetItem *pItem) { // 本函数的逻辑依赖于Filter函数的实现,请不要在其他函数中调用!!! // 调本函数之前,已经将搜索结果集及其父代全部隐藏,根据setHidden的传递性,此时搜索结果集的子代也是处于hidden状态 if(pItem->isHidden()) { return true; } QTreeWidgetItem *pParentItem = pItem->parent(); while((pParentItem != NULL) && (pParentItem != invisibleRootItem())) { if(pParentItem->isHidden()) { return true; } pParentItem = pParentItem->parent(); } return false; } /////////////////////////////// PaiTreeWidgetItem /////////////////////////////////// PaiTreeWidgetItem::PaiTreeWidgetItem() : QTreeWidgetItem() { } PaiTreeWidgetItem::PaiTreeWidgetItem(QTreeWidgetItem *pParent) : QTreeWidgetItem(pParent) { } PaiTreeWidgetItem::~PaiTreeWidgetItem() { } bool PaiTreeWidgetItem::operator < (const QTreeWidgetItem & otherItem) const { if(data(0, pai::gui::DataSortRole).isValid() && otherItem.data(0, pai::gui::DataSortRole).isValid()) { if((data(0, pai::gui::DataSortRole).type() == QVariant::Int) && (otherItem.data(0, pai::gui::DataSortRole).type() == QVariant::Int)) // 整形比较 { return data(0, pai::gui::DataSortRole).toInt() < otherItem.data(0, pai::gui::DataSortRole).toInt(); } } return QTreeWidgetItem::operator < (otherItem); // 暂不支持的排序类型使用基类排序 }