193 lines
6.1 KiB
C++
193 lines
6.1 KiB
C++
/**
|
||
* @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); // 暂不支持的排序类型使用基类排序
|
||
}
|