/** * @file PaiTableWidget.cpp * @date 2012-03-27 */ #include #include #include #include #include #include #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()); } }