logplus/Workflow/WFWidget/src/PaiTableWidget.cpp
2026-01-16 17:18:41 +08:00

396 lines
9.7 KiB
C++

/**
* @file PaiTableWidget.cpp
* @date 2012-03-27
*/
#include <QPainter>
#include <QTableWidgetItem>
#include <QMenu>
#include <QClipboard>
#include <QApplication>
#include <QKeyEvent>
#include "PaiTableWidget.h"
#include "PaiTableItemDelegate.h"
#include "PaiHeaderView.h"
using namespace pai::gui;
PaiTableWidget::PaiTableWidget(QWidget* pParent) :
QTableWidget(pParent),
m_AutoHeight(false),
m_ShowFilterEmptyMessage(false),
m_AutoHeightMaxRowCount(10),
m_MessageWhileFilterEmpty("found nothing!")
{
setSortingEnabled(true);
QTableWidget::setShowGrid(false);
setItemDelegate(new PaiTableItemDelegate(this));
setHorizontalHeader(new PaiHeaderView(Qt::Horizontal, this));
this->horizontalHeader()->setHighlightSections(false);
this->horizontalHeader()->setMinimumHeight(27);
connect(model(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(RowCountChanged()));
connect(model(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(RowCountChanged()));
connect(this, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(TableItemChanged(QTableWidgetItem*)));
setContextMenuPolicy(Qt::DefaultContextMenu);
}
PaiTableWidget::~PaiTableWidget()
{
//记录当前显示的表头
RememberCurrentSections();
}
void PaiTableWidget::RowCountChanged()
{
if(m_AutoHeight && (rowCount() <= m_AutoHeightMaxRowCount))
{
ResetTableHeight();
}
emit RowCountChanged( rowCount());
}
void PaiTableWidget::Filter(const QString & keyword, int column)
{
Filter(keyword, QList< int > () << column);
}
void PaiTableWidget::Filter(const QString & keyword, QList< int > columns, QList< int > ignoreLines)
{
m_IgnoreLines = ignoreLines;
m_IgnoreHeight = 0;
for(int i = 0; i < ignoreLines.count(); i++)
{
m_IgnoreHeight += rowHeight(ignoreLines.at(i));
}
// 清空提示信息
m_ShowFilterEmptyMessage = false;
m_FilterKeyword = keyword;
m_FilterColumns = columns;
QList< int > searchResult;
for(int rowIndex = 0; rowIndex < rowCount(); ++rowIndex)
{
// 忽略行不进行过滤
if(m_IgnoreLines.contains(rowIndex))
{
setRowHidden(rowIndex, false);
continue;
}
bool pass = Filter(rowIndex);
// 只显示过滤的结果
setRowHidden(rowIndex, !pass);
if(pass)
{
searchResult.append(rowIndex);
}
}
// 如果没搜到任何东西,则显示未找到提示
if(searchResult.empty())
{
if(!m_FilterKeyword.isEmpty()) // 停止搜索但表格原本就是空的情况下不应显示该提示
{
m_ShowFilterEmptyMessage = true;
}
}
else // 如果搜索到结果,就将搜索到的第一个节点滚动到顶端显示
{
scrollToItem(item(searchResult.first(), 0), QAbstractItemView::PositionAtTop);
}
}
bool PaiTableWidget::Filter(int rowIndex)
{
bool pass = false;
if(m_FilterKeyword.isEmpty())
{
pass = true;
}
else if(m_FilterKeyword.contains('*') || m_FilterKeyword.contains('?'))
{
QRegExp rx(m_FilterKeyword, Qt::CaseInsensitive, QRegExp::Wildcard);
foreach(int colIndex, m_FilterColumns)
{
QTableWidgetItem *pItem = item(rowIndex, colIndex);
if(pItem && rx.exactMatch(pItem->text()))
{
pass = true;
break;
}
}
}
else
{
foreach(int colIndex, m_FilterColumns)
{
QTableWidgetItem *pItem = item(rowIndex, colIndex);
if(pItem && pItem->text().contains(m_FilterKeyword, Qt::CaseInsensitive))
{
pass = true;
break;
}
}
}
return pass;
}
void PaiTableWidget::insertColumn(int column)
{
QTableWidget::insertColumn(column);
// 如果使用的时PaiHeaderView(表头可显CheckBox),则调整CheckBox
PaiHeaderView *pHeadView = dynamic_cast< PaiHeaderView* > (horizontalHeader());
if(pHeadView != NULL)
{
pHeadView->AdjustCheckBoxMap(true, column);
}
}
void PaiTableWidget::removeColumn(int column)
{
QTableWidget::removeColumn(column);
// 如果使用的时PaiHeaderView(表头可显CheckBox),则调整CheckBox
PaiHeaderView *pHeadView = dynamic_cast< PaiHeaderView* > (horizontalHeader());
if(pHeadView != NULL)
{
pHeadView->AdjustCheckBoxMap(false, column);
}
}
void PaiTableWidget::ResetTableHeight()
{
const int rcount = rowCount();
int theight = horizontalHeader()->height() + 2; // +2 is ok, I don't know why.
if(rcount)
{
theight += (rowViewportPosition(rcount - 1) + rowHeight(rcount - 1));
}
setMinimumHeight(theight);
setMaximumHeight(theight);
}
void PaiTableWidget::SetAutoHeight(const bool ok, const int maxRowCount)
{
m_AutoHeight = ok;
m_AutoHeightMaxRowCount = maxRowCount;
if(ok)
{
ResetTableHeight();
}
else
{
setMinimumHeight(0);
setMaximumHeight(16777215); // a enough large number
}
}
void PaiTableWidget::RemoveRows(const int rowIndex, const int count)
{
if(rowIndex >= rowCount())
{
return;
}
const int rCount = (rowIndex + count > rowCount()) ? (rowCount() - rowIndex) : count;
for(int i = rCount - 1; i >= rowIndex; --i)
{
removeRow(i);
}
}
void PaiTableWidget::SetFilterEmptyMessage(const QString & message)
{
m_MessageWhileFilterEmpty = message;
}
void PaiTableWidget::paintEvent(QPaintEvent *pEvent)
{
QTableWidget::paintEvent(pEvent);
QPainter painter(viewport());
painter.save();
const int BASE_HEIGHT = horizontalHeader()->sectionViewportPosition(0) + 20 + m_IgnoreHeight;
if(m_ShowFilterEmptyMessage)
{
int x = (width() - painter.fontMetrics().width(m_MessageWhileFilterEmpty)) / 2;
int y = BASE_HEIGHT;
painter.drawText(x, y, m_MessageWhileFilterEmpty);
}
if(!m_PromptMessage.isEmpty())
{
int x = (width() - painter.fontMetrics().width(m_PromptMessage)) / 2;
int y = BASE_HEIGHT;
painter.drawText(x, y, m_PromptMessage);
}
painter.restore();
}
void PaiTableWidget::RemoveRows()
{
setRowCount(0);
}
void PaiTableWidget::setShowGrid(bool horizontalLine, bool verticalLine)
{
PaiTableItemDelegate *pDelegate = dynamic_cast< PaiTableItemDelegate* > (itemDelegate());
if(pDelegate)
{
pDelegate->setShowGrid(horizontalLine, verticalLine);
}
}
void PaiTableWidget::ShowPromptMessage(const QString & message)
{
m_PromptMessage = message;
}
void PaiTableWidget::SetColumnVisibleSelectable(bool selectable)
{
PaiHeaderView *pHeader = qobject_cast< PaiHeaderView* > (horizontalHeader());
if(pHeader)
{
pHeader->SetSectionVisibleSelectable(selectable);
}
}
void PaiTableWidget::SetUnselectableColumns(const QStringList & columnList)
{
PaiHeaderView *pHeader = qobject_cast< PaiHeaderView* > (horizontalHeader());
if(pHeader)
{
pHeader->SetUnselectableSections(columnList);
}
}
void PaiTableWidget::RecallMemberedSections()
{
PaiHeaderView *paiHeader = (PaiHeaderView*) horizontalHeader();
paiHeader->RecallMemberedSections();
}
void PaiTableWidget::SetColumnCheckable(const int logicalIndex, const bool checkable, QCheckBox *pCheckBox)
{
PaiHeaderView *pHeadView = dynamic_cast< PaiHeaderView* > (horizontalHeader());
if(pHeadView)
{
pHeadView->SetColumnCheckable(logicalIndex, checkable, pCheckBox);
}
}
void PaiTableWidget::RememberCurrentSections()
{
PaiHeaderView *paiHeader = (PaiHeaderView*) horizontalHeader();
paiHeader->RememberCurrentSections();
}
void PaiTableWidget::SetClipboard()
{
QList< QTableWidgetItem * > itemList = selectedItems();
if(itemList.size() == 0)
{
return;
}
QString dataString;
int maxColumn = 0;
int minColumn = itemList[0]->column();
int maxRow = 0;
int minRow = itemList[0]->row();
foreach (QTableWidgetItem *pItem, itemList)
{
if(pItem->row() > maxRow)
{
maxRow = pItem->row();
}
if(pItem->row() < minRow)
{
minRow = pItem->row();
}
if(pItem->column() > maxColumn)
{
maxColumn = pItem->column();
}
if(pItem->column() < minColumn)
{
minColumn = pItem->column();
}
}
for(int row = minRow; row <= maxRow; row++)
{
for(int col = minColumn; col <= maxColumn; col++)
{
QTableWidgetItem *pItem = this->item(row, col);
if(pItem && pItem->isSelected())
{
dataString += pItem->data(Qt::DisplayRole).toString();
}
if(col != maxColumn)
{
dataString += "\t";
}
}
if(row != maxRow)
{
dataString += "\n";
}
}
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(dataString);
}
void PaiTableWidget::contextMenuEvent(QContextMenuEvent *pEvent)
{
QMenu menu(NULL);
QAction action(tr("Copy"), this);
action.setShortcut(tr("Ctrl+C"));
menu.addAction(&action);
connect(&action, SIGNAL(triggered()), this, SLOT(SetClipboard()));
menu.exec(pEvent->globalPos());
}
void PaiTableWidget::keyPressEvent(QKeyEvent *pEvent)
{
QTableWidget::keyPressEvent(pEvent);
if((pEvent->key() == Qt::Key_C) && (pEvent->modifiers() & Qt::ControlModifier))
{
SetClipboard();
}
}
void PaiTableWidget::TableItemChanged(QTableWidgetItem *pItem)
{
// 当单元格数据发生变化后,如果有过滤条件则实时过滤
if(!m_FilterKeyword.isEmpty())
{
Filter(pItem->row());
}
}