/** * @file PaiHeaderView.cpp * @date 2012-11-09 */ #include #include #include #include #include #include #include "PaiHeaderView.h" #include "PaiSettings.h" const int SORT_ARRAW_LEN = 30; // 可以排序时右侧的盘需模式指示标记宽度 const int LAST_SECTION_ADD_SPACE_LEN = 15; //最后一列加点空隙不让pSectionSelectTBtn遮挡 #define LOGICAL_INDEX "logic index" //QCheckBox用于记录自身所属逻辑列数 using namespace pai::gui; PaiHeaderView::PaiHeaderView(Qt::Orientation orientation, QWidget *pParent) : QHeaderView(orientation, pParent), m_SectionSelectableVisible(false) { m_pSectionSelectToolButton = new QToolButton(this); // 该ToolButton底色需与HeaderView底色保持一致 m_pSectionSelectToolButton->setStyleSheet(QString::fromUtf8("background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" "stop:0 #FEFEFF, stop:1 #E9F2F8);\n" "border-left: 1px solid #C9D5DC;\n" "border-right: 0px;\n" "border-top: 1px solid #C9D5DC;\n" "border-bottom: 1px solid #C9D5DC;")); m_pSectionSelectToolButton->setIcon(QIcon(":/add_01.png")); m_pSectionSelectToolButton->setVisible(m_SectionSelectableVisible); // setClickable(true); setStretchLastSection(true); // PAI风格默认 connect(this, SIGNAL(sectionResized(int, int, int)), this, SLOT(AdjustSectionSuitable(int, int, int))); connect(m_pSectionSelectToolButton, SIGNAL(clicked()), this, SLOT(ShowSectionVisibleMenu())); } PaiHeaderView::~PaiHeaderView() { } void PaiHeaderView::SetSectionVisibleSelectable(bool selectable) { m_SectionSelectableVisible = selectable; m_pSectionSelectToolButton->setVisible(m_SectionSelectableVisible); } void PaiHeaderView::paintSection(QPainter *pPainter, const QRect & rect, int logicalIndex) const { // 当显示列选择功能时,需单独绘制最后一列,以使标题信息不被选择按钮挡住 if(m_SectionSelectableVisible && (logicalIndex == LastVisibleSection())) { int adjustSize = m_pSectionSelectToolButton->width()-1; // -1px来保证做测边界只有一个边被显示 // 分两部分绘制,此处为前半部分 QHeaderView::paintSection(pPainter, rect.adjusted(0, 0, -adjustSize, 0), logicalIndex); // 后半部分,其实就是不绘制任何图像 QStyleOptionHeader opt; initStyleOption(&opt); opt.sortIndicator = QStyleOptionHeader::None; opt.rect = rect.adjusted(rect.width() - adjustSize, 0, 0, 0); opt.section = logicalIndex; opt.position = QStyleOptionHeader::End; QApplication::style()->drawControl(QStyle::CE_Header, &opt, pPainter, this); } else // 其它列绘制 { QHeaderView::paintSection(pPainter, rect, logicalIndex); } // 调整CheckBox位置 if(m_ColumnCheckBoxMap.contains(logicalIndex)) { QCheckBox *pCheckBox = m_ColumnCheckBoxMap.value(logicalIndex); int x = rect.x(); //靠左 int y = (rect.height() - pCheckBox->height()) / 2; //垂直居中 pCheckBox->move(x, y); } } void PaiHeaderView::resizeEvent(QResizeEvent *pEvent) { QHeaderView::resizeEvent(pEvent); // 使列选择按钮始终在表格右上角 if(m_SectionSelectableVisible) { m_pSectionSelectToolButton->resize(height(), height()); m_pSectionSelectToolButton->move(width()-height(), 0); } } void PaiHeaderView::mousePressEvent(QMouseEvent *pEvent) { QHeaderView::mousePressEvent(pEvent); if(Qt::RightButton == pEvent->button()) { emit TitleRightClicked(logicalIndexAt(pEvent->pos()), pEvent->globalPos()); } } void PaiHeaderView::ShowSectionVisibleMenu() { QMenu contextMenu; for(int i = 0; i < count(); ++i) { QString colText = model()->headerData(i, Qt::Horizontal).toString(); if(!m_UnselectableSections.contains(colText)) { QAction *pVisibleAct = contextMenu.addAction(colText, this, SLOT(ReverseSectionVisible())); pVisibleAct->setCheckable(true); pVisibleAct->setChecked(!isSectionHidden(i)); pVisibleAct->setData(i); // 以该值来标记action所代表的列 } } contextMenu.exec(mapToGlobal(m_pSectionSelectToolButton->geometry().bottomLeft())); } void PaiHeaderView::CheckBoxStateChanged() { QCheckBox *pCheckBox = dynamic_cast(sender()); if(pCheckBox != NULL) { emit CheckStateChanged(pCheckBox->property(LOGICAL_INDEX).toInt(), pCheckBox->checkState()); } } void PaiHeaderView::ReverseSectionVisible() { QAction *pAct = qobject_cast(sender()); if(pAct) { int index = LastVisibleSection(); // 显示列索引变为逻辑索引 if((index >= 0) && (index < count())) { int size = SectionSuitableWidth(index); if(sectionSize(index) > size) { resizeSection(index, size); } } int sectionIndex = pAct->data().toInt(); if((sectionIndex >= 0) && (sectionIndex < count())) // 判断逻辑索引是否超出范围 { SetSectionHidden(sectionIndex, !isSectionHidden(sectionIndex)); // 交换显示状态 // 隐藏一列后将最后一列重新resize下,不让pSectionSelectTBtn遮挡住 resizeSection (LastVisibleSection(), SectionSuitableWidth(LastVisibleSection())); } } } void PaiHeaderView::RememberCurrentSections() { if(!m_SectionSelectableVisible) { return; } if(parent() == NULL) { return; } // 生成对应的KEY QString objName = parent()->objectName(); if(objName.isEmpty()) { return; } QString key = objName.append("_VISIBLE_SECTIONS"); // 将当前显示的列索引记录到sections中 QStringList sections; int cn = count(); for(int i = 0; i < cn; i++) { if(!isSectionHidden(i)) { sections.append(QString::number(i)); } } PaiSettings settings; settings.setValue(key, sections.join(",")); } void PaiHeaderView::SetColumnCheckable(const int logicalIndex, const bool checkable, QCheckBox *pCheckBox) { if(checkable) { pCheckBox->setParent(this); pCheckBox->setProperty(LOGICAL_INDEX, QString::number(logicalIndex)); pCheckBox->setFixedSize(20, 20); connect(pCheckBox, SIGNAL(stateChanged(int)), this, SLOT(CheckBoxStateChanged())); m_ColumnCheckBoxMap.insert(logicalIndex, pCheckBox); } else { //从Map移除,并返回NULL if(m_ColumnCheckBoxMap.contains(logicalIndex)) { delete m_ColumnCheckBoxMap.value(logicalIndex); m_ColumnCheckBoxMap.remove(logicalIndex); } } update(); } void PaiHeaderView::AdjustCheckBoxMap(bool insert, int column) { QMap newMap; if(insert) { //如果为插入操作,则将插入所在序列后的列序号+1 foreach(int index , m_ColumnCheckBoxMap.keys()) { if(index < column) { newMap.insert(index, m_ColumnCheckBoxMap.value(index)); } else { newMap.insert(index + 1, m_ColumnCheckBoxMap.value(index)); // 调整CheckBox对应的逻辑列 QCheckBox *pCheckBox = newMap.value(index + 1); if(pCheckBox != NULL) { pCheckBox->setProperty(LOGICAL_INDEX, QString::number(index + 1)); } } } } else { // 如果为删除操作,则将删除所在序列后的列序号-1 foreach(int index , m_ColumnCheckBoxMap.keys()) { if(index < column) { newMap.insert(index, m_ColumnCheckBoxMap.value(index)); } else if(index == column) { // 如果此行为删除行,则将CheckBox解析掉 QCheckBox *pCheckBox = m_ColumnCheckBoxMap.value(index); if(pCheckBox != NULL) { delete pCheckBox; pCheckBox = NULL; } } else { newMap.insert(index - 1, m_ColumnCheckBoxMap.value(index)); // 调整CheckBox对应的逻辑列 QCheckBox *pCheckBox = newMap.value(index - 1); if(pCheckBox != NULL) { pCheckBox->setProperty(LOGICAL_INDEX, QString::number(index - 1)); } } } } // 替换为调整后的Map m_ColumnCheckBoxMap = newMap; update(); } void PaiHeaderView::RecallMemberedSections() { if(!m_SectionSelectableVisible) { return; } if(parent() == NULL) { return; } QString objName = parent()->objectName(); if(objName.isEmpty()) { return; } // 生成当前表格显示列记录的KEY QString key = objName.append("_VISIBLE_SECTIONS"); PaiSettings setting; if(setting.contains(key)) { int count = this->count(); // 余下可隐藏的默认显示列也设置其为隐藏 for(int i = 0; i < count; i++) { QString colText = model()->headerData(i, Qt::Horizontal).toString(); if(!m_UnselectableSections.contains(colText)) { SetSectionHidden(i, true); } } QString value = setting.value(key).toString(); if(value.isEmpty()) { return; } QStringList indexs = value.split(","); int size = indexs.size(); bool ok; for(int i = 0; i < size; i++) { int index = indexs.at(i).toInt(&ok, 10); if(ok && (index < count) && (index >= 0)) { SetSectionHidden(index, false); } } } } void PaiHeaderView::SetSectionHidden(int logicalIndex, bool hide) { setSectionHidden(logicalIndex, hide); emit SectionVisibleChanged(logicalIndex, !hide); } void PaiHeaderView::AdjustSectionSuitable(int logicalIndex, int /*oldSize*/, int newSize) { // 为0的时候,认为其将要被隐藏,这时就不能再限制它的长度,注意这里使用isSectionHidden无效 if(newSize != 0) { int sSize = SectionSuitableWidth(logicalIndex); // 获得该列的最适大小 if(newSize < sSize) // 当最新的宽度小于最适大小时,重新调整其大小 { resizeSection(logicalIndex, sSize); } } } int PaiHeaderView::SectionSuitableWidth(int logicalIndex) { // 文本长度 int sw = fontMetrics().width(model()->headerData(logicalIndex, Qt::Horizontal).toString()); if(isSortIndicatorShown()) // 当有排序箭头时,加上该箭头的宽度 { sw += SORT_ARRAW_LEN; } if(m_SectionSelectableVisible && (logicalIndex == LastVisibleSection())) // 当时最后显示列的时候,加上列选择按钮宽度 { sw += m_pSectionSelectToolButton->width(); sw += LAST_SECTION_ADD_SPACE_LEN;//加长点要不最后一列的后两个字母被pSectionSelectTBtn遮挡 } return sw; } int PaiHeaderView::LastVisibleSection() const { for(int i = count() - 1; i >= 0; --i) { int lgIndex = logicalIndex(i); // 显示列索引变为逻辑索引 if(!isSectionHidden(lgIndex)) { return lgIndex; } } return -1; } void PaiHeaderView::SetUnselectableSections(const QStringList & sectionList) { m_UnselectableSections = sectionList; }