/* Copyright 2006-2025 The QElectroTech Team This file is part of QElectroTech. QElectroTech is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. QElectroTech is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with QElectroTech. If not, see . */ #include "qetgraphicsheaderitem.h" #include "../../createdxf.h" #include "../../qetxml.h" #include "../../utils/qetutils.h" #include "qabstractitemmodel.h" #include #include static int no_model_height = 20; static int no_model_width = 40; /** @brief QetGraphicsHeaderItem::QetGraphicsHeaderItem @param parent */ QetGraphicsHeaderItem::QetGraphicsHeaderItem(QGraphicsItem *parent) : QGraphicsObject(parent) {} /** @brief QetGraphicsHeaderItem::setModel Set the model presented by this item Since QetGraphicsHeaderItem don't take ownership of model, if item already have a model, it's your responsibility to delete it. @param model */ void QetGraphicsHeaderItem::setModel(QAbstractItemModel *model) { if (m_model) { disconnect(m_model, &QAbstractItemModel::headerDataChanged, this, &QetGraphicsHeaderItem::headerDataChanged); disconnect(m_model, &QAbstractItemModel::modelReset, this, &QetGraphicsHeaderItem::modelReseted); disconnect(m_model, &QAbstractItemModel::columnsInserted, this, &QetGraphicsHeaderItem::modelReseted); } m_model = model; if (m_model) { connect(m_model, &QAbstractItemModel::headerDataChanged, this, &QetGraphicsHeaderItem::headerDataChanged); connect(m_model, &QAbstractItemModel::modelReset, this, &QetGraphicsHeaderItem::modelReseted); connect(m_model, &QAbstractItemModel::columnsInserted, this, &QetGraphicsHeaderItem::modelReseted); setUpMinimumSectionsSize(); m_current_sections_width.clear(); m_current_sections_width.resize(m_sections_minimum_width.size()); } else { setUpMinimumSectionsSize(); } adjustSize(); } /** @brief QetGraphicsHeaderItem::model @return the model that this item is presenting */ QAbstractItemModel *QetGraphicsHeaderItem::model() const { return m_model; } /** @brief QetGraphicsHeaderItem::boundingRect Reimplemented from QGraphicsObject::boundingRect() const; @return */ QRectF QetGraphicsHeaderItem::boundingRect() const { return m_bounding_rect; } /** @brief QetGraphicsHeaderItem::paint Reimplemented from QGraphicsObject::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) const; @param painter @param option @param widget */ void QetGraphicsHeaderItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) painter->save(); QPen pen; pen.setWidthF(0.7); pen.setColor(Qt::black); QBrush brush = painter->brush(); brush.setColor(Qt::lightGray); brush.setStyle(Qt::SolidPattern); painter->setBrush(brush); painter->setPen(pen); painter->drawRect(m_current_rect); if (!m_model) { painter->restore(); return; } painter->setFont( m_model->headerData( 0, Qt::Horizontal, Qt::FontRole).value()); //Draw vertical lines auto offset= 0; for(auto size : m_current_sections_width) { QPointF p1(offset+size, m_current_rect.top()); QPointF p2(offset+size, m_current_rect.bottom()); painter->drawLine(p1, p2); offset += size; } //Write text of each cell auto margins_ = QETUtils::marginsFromString( m_model->headerData( 0, Qt::Horizontal, Qt::UserRole+1).toString()); QPointF top_left(margins_.left(), margins_.top()); for (auto i= 0 ; icolumnCount() ; ++i) { QSize size( m_current_sections_width.at(i) - margins_.left() - margins_.right(), m_section_height - margins_.top() - margins_.bottom()); painter->drawText( QRectF(top_left, size), m_model->headerData( 0, Qt::Horizontal, Qt::TextAlignmentRole).toInt(), m_model->headerData( i, Qt::Horizontal, Qt::DisplayRole).toString()); top_left.setX(top_left.x() + m_current_sections_width.at(i)); } painter->restore(); } /** @brief QetGraphicsHeaderItem::toDXF Draw this table to the dxf document @param filepath file path of the the dxf document @return true if draw success */ bool QetGraphicsHeaderItem::toDXF(const QString &filepath) { QRectF rect = m_current_rect; QPolygonF poly(rect); Createdxf::drawPolygon(filepath,mapToScene(poly),0); //Draw vertical lines auto offset= 0; for(auto size : m_current_sections_width) { QPointF p1(offset+size, m_current_rect.top()); QPointF p2(offset+size, m_current_rect.bottom()); Createdxf::drawLine( filepath, QLineF( mapToScene(p1), mapToScene(p2)), 0); offset += size; } //Write text of each cell auto margins_ = QETUtils::marginsFromString( m_model->headerData( 0, Qt::Horizontal, Qt::UserRole+1).toString()); QPointF top_left(margins_.left(), margins_.top()); for (auto i= 0 ; icolumnCount() ; ++i) { QSize size(m_current_sections_width.at(i) - margins_.left() - margins_.right(), m_section_height - margins_.top() - margins_.bottom()); QPointF qm = mapToScene(top_left); qreal h = size.height();// * Createdxf::yScale; qreal x = qm.x() * Createdxf::xScale; qreal y = Createdxf::sheetHeight - ((qm.y() + h/2) * Createdxf::yScale); qreal h1 = h * 0.5 * Createdxf::yScale; int valign = 2; Createdxf::drawTextAligned( filepath, m_model->headerData( i, Qt::Horizontal, Qt::DisplayRole).toString(), x,y,h1,0,0,0,valign,x,0,0); top_left.setX(top_left.x() + m_current_sections_width.at(i)); } return true; } /** @brief QetGraphicsHeaderItem::rect @return the current rect of the item aka the size of rectangle painted. */ QRect QetGraphicsHeaderItem::rect() const { return m_current_rect; } /** @brief QetGraphicsHeaderItem::resizeSection @param logicalIndex @param size */ void QetGraphicsHeaderItem::resizeSection(int logicalIndex, int size) { if (!m_model) { m_current_sections_width.clear(); m_current_sections_width.append(no_model_width); m_sections_minimum_width.clear(); m_sections_minimum_width.append(no_model_width); m_current_rect.setWidth(no_model_width); setUpBoundingRect(); update(); emit sectionResized(0, no_model_width); return; } if (logicalIndex >= m_current_sections_width.size() || m_current_sections_width.at(logicalIndex) == size) { return; } if (m_model && logicalIndexcolumnCount() && size >= m_sections_minimum_width.at(logicalIndex)) { prepareGeometryChange(); m_current_sections_width.replace(logicalIndex, size); m_current_rect.setWidth( std::accumulate( m_current_sections_width.begin(), m_current_sections_width.end(), 0)); setUpBoundingRect(); update(); emit sectionResized(logicalIndex, size); } } /** @brief QetGraphicsHeaderItem::sectionSize @param logical_index @return the width (or height for vertical headers) of the given logicalIndex. */ int QetGraphicsHeaderItem::sectionSize(int logical_index) const { if (logical_index>=0 && logical_indexheaderData( 0, Qt::Horizontal, Qt::UserRole+1).toString()))); } return dom_element; } /** @brief QetGraphicsHeaderItem::fromXml Restore the header from xml @param element */ void QetGraphicsHeaderItem::fromXml(const QDomElement &element) { if ((element.tagName() != xmlTagName()) || !m_model) { return; } auto margins_ = QETUtils::marginsToString( QETXML::marginsFromXml( element.firstChildElement("margins"))); m_model->setHeaderData( 0, Qt::Horizontal, QETUtils::marginsToString( QETXML::marginsFromXml( element.firstChildElement("margins"))), Qt::UserRole+1); } /** @brief QetGraphicsHeaderItem::setUpMinimumSectionsSize Setup the minimum section size and height of the item. Not that this function doesn't change the current size of this item. */ void QetGraphicsHeaderItem::setUpMinimumSectionsSize() { if (!m_model) { m_minimum_section_height = no_model_height; m_sections_minimum_width.clear(); m_sections_minimum_width.append(no_model_width); m_minimum_width = no_model_width; return; } QFontMetrics metrics( m_model->headerData( 0, Qt::Horizontal, Qt::FontRole).value()); auto margins_ = QETUtils::marginsFromString( m_model->headerData( 0, Qt::Horizontal, Qt::UserRole+1).toString()); //Set the height of row; m_minimum_section_height = metrics.boundingRect("HEIGHT TEST").height() + margins_.top() + margins_.bottom(); m_sections_minimum_width.clear(); m_sections_minimum_width.resize(m_model->columnCount()); for (auto i= 0 ; icolumnCount() ; ++i) { auto str = m_model->headerData(i, Qt::Horizontal).toString(); m_sections_minimum_width.replace( i, metrics.boundingRect(str).width() + margins_.left() + margins_.right()); } m_minimum_width = std::accumulate( m_sections_minimum_width.begin(), m_sections_minimum_width.end(), 0); } /** @brief QetGraphicsHeaderItem::setUpBoundingRect Setup the bounding rect of the item */ void QetGraphicsHeaderItem::setUpBoundingRect() { m_bounding_rect = m_current_rect.adjusted(-10, -10, 10, 10); } /** @brief QetGraphicsHeaderItem::headerDataChanged Update the header when data of displayed model change @param orientation @param first @param last */ void QetGraphicsHeaderItem::headerDataChanged( Qt::Orientations orientation, int first, int last) { Q_UNUSED(orientation) Q_UNUSED(first) Q_UNUSED(last) setUpMinimumSectionsSize(); adjustSize(); update(); } /** @brief QetGraphicsHeaderItem::adjustSize If needed, this function resize the current height and section according to there minimum */ void QetGraphicsHeaderItem::adjustSize() { if (m_section_height != m_minimum_section_height) { m_section_height = m_minimum_section_height; m_current_rect.setHeight(m_section_height); emit heightResized(); } update(); } void QetGraphicsHeaderItem::modelReseted() { setUpMinimumSectionsSize(); m_current_sections_width.clear(); m_current_sections_width.resize(m_sections_minimum_width.size()); adjustSize(); }