logplus/Workflow/WFWidget/src/PaiTreeWidget.cpp

193 lines
6.1 KiB
C++
Raw Normal View History

2026-01-16 17:18:41 +08:00
/**
* @file PaiTreeWidget.cpp
* @brief P.A.I系统定制发布的树控件
* @date 2012-10-18
*/
#include <QLabel>
#include <QHeaderView>
#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<int>() << column);
}
void PaiTreeWidget::Filter(const QString & keyword, QList<int> 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<QTreeWidgetItem*> searchResult;
for(int col=0; col<columns.size(); ++col)
{
searchResult <<
findItems(keyword, bWildcard ? (Qt::MatchRecursive
| Qt::MatchContains
| Qt::MatchWildcard) : Qt::MatchRecursive | Qt::MatchContains, col);
}
clearSelection();
if(!searchResult.empty())
{
// 首先显示全体
for(QTreeWidgetItemIterator it(this); *it; ++it)
{
(*it)->setHidden(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); // 暂不支持的排序类型使用基类排序
}