File indexing completed on 2024-05-12 04:20:44

0001 /*
0002  * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
0003  *
0004  * This file is part of the KGantt library.
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "kganttlegend.h"
0010 #include "kganttlegend_p.h"
0011 
0012 #include "kganttitemdelegate.h"
0013 
0014 #include <QApplication>
0015 #include <QPainter>
0016 
0017 #include <cassert>
0018 
0019 using namespace KGantt;
0020 
0021 
0022 Legend::Legend( QWidget* parent )
0023     : QAbstractItemView( parent ),
0024       _d( new Private )
0025 {
0026     setItemDelegate( new ItemDelegate( this ) );
0027     setFrameStyle( QFrame::NoFrame );
0028 }
0029 
0030 
0031 Legend::~Legend()
0032 {
0033     delete _d;
0034 }
0035 
0036 #define d d_func()
0037 
0038 QModelIndex Legend::indexAt( const QPoint& point ) const
0039 {
0040     Q_UNUSED( point );
0041     return QModelIndex();
0042 }
0043 
0044 QRect Legend::visualRect( const QModelIndex& index ) const
0045 {
0046     Q_UNUSED( index );
0047     return QRect();
0048 }
0049 
0050 QSize Legend::sizeHint() const
0051 {
0052     return measureItem( rootIndex() );
0053 }
0054 
0055 QSize Legend::minimumSizeHint() const
0056 {
0057     return measureItem( rootIndex() );
0058 }
0059 
0060 void Legend::setModel( QAbstractItemModel* model )
0061 {
0062     if ( this->model() != nullptr )
0063     {
0064         disconnect( this->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelDataChanged()) );
0065         disconnect( this->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(modelDataChanged()) );
0066         disconnect( this->model(), SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(modelDataChanged()) );
0067     }
0068 
0069     QAbstractItemView::setModel( model );
0070     d->proxyModel.setSourceModel( model );
0071 
0072     if ( this->model() != nullptr )
0073     {
0074         connect( this->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelDataChanged()) );
0075         connect( this->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(modelDataChanged()) );
0076         connect( this->model(), SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(modelDataChanged()) );
0077     }
0078 
0079 }
0080 
0081 
0082 void Legend::modelDataChanged()
0083 {
0084     updateGeometry();
0085     viewport()->update();
0086 }
0087 
0088 void Legend::paintEvent( QPaintEvent* event )
0089 {
0090     Q_UNUSED( event );
0091     // no model, no legend...
0092     if ( model() == nullptr )
0093         return;
0094 
0095     QPainter p( viewport() );
0096     p.fillRect( viewport()->rect(), palette().color( QPalette::Window ) );
0097     drawItem( &p, rootIndex() );
0098 }
0099 
0100 
0101 StyleOptionGanttItem Legend::getStyleOption( const QModelIndex& index ) const
0102 {
0103     StyleOptionGanttItem opt;
0104     opt.displayPosition = StyleOptionGanttItem::Right;
0105     opt.displayAlignment = Qt::Alignment( d->proxyModel.data( index, Qt::TextAlignmentRole ).toInt() );
0106     opt.text = index.model()->data( index, LegendRole ).toString();
0107     opt.font = ( index.model()->data( index, Qt::FontRole ) ).value< QFont >();
0108     return opt;
0109 }
0110 
0111 
0112 QRect Legend::drawItem( QPainter* painter, const QModelIndex& index, const QPoint& pos ) const
0113 {
0114     int xPos = pos.x();
0115     int yPos = pos.y();
0116 
0117     if ( index.isValid() && index.model() == &d->proxyModel )
0118     {
0119         ItemDelegate* const delegate = qobject_cast< ItemDelegate* >( itemDelegate( index ) );
0120         assert( delegate != nullptr );
0121         const QRect r( pos, measureItem( index, false ) );
0122         StyleOptionGanttItem opt = getStyleOption( index );
0123         opt.rect = r;
0124         opt.rect.setWidth( r.height() );
0125 
0126         const ItemType typ = static_cast<ItemType>( index.model()->data( index, ItemTypeRole ).toInt() );
0127         const int dx = (typ == TypeEvent) ? (r.height() / 2) : 0;
0128 
0129         opt.itemRect = opt.rect.adjusted(dx,0,dx,0);
0130         opt.boundingRect = r;
0131         opt.boundingRect.setWidth( r.width() + r.height() );
0132         if ( !opt.text.isNull() )
0133             delegate->paintGanttItem( painter, opt, index );
0134 
0135         xPos = r.right();
0136         yPos = r.bottom();
0137     }
0138 
0139     
0140     const int rowCount = d->proxyModel.rowCount( index );
0141     for ( int row = 0; row < rowCount; ++row )
0142     {
0143         const QRect r = drawItem( painter, d->proxyModel.index( row, 0, index ), QPoint( pos.x(), yPos ) );
0144         xPos = qMax( xPos, r.right() );
0145         yPos = qMax( yPos, r.bottom() );
0146     }
0147 
0148     return QRect( pos, QPoint( xPos, yPos ) );
0149 }
0150 
0151 
0152 QSize Legend::measureItem( const QModelIndex& index, bool recursive ) const
0153 {
0154     if ( model() == nullptr )
0155         return QSize();
0156 
0157     QSize baseSize;
0158     if ( index.model() != nullptr )
0159     {
0160         QFontMetrics fm( ( index.model()->data( index, Qt::FontRole ) ).value< QFont >() );
0161         const QString text = index.model()->data( index, LegendRole ).toString();
0162         if ( !text.isEmpty() )
0163             baseSize += QSize( fm.boundingRect( text ).width() + fm.height() + 2, fm.height() + 2 );
0164     }
0165 
0166     if ( !recursive )
0167         return baseSize;
0168 
0169     QSize childrenSize;
0170 
0171     const int rowCount = d->proxyModel.rowCount( index );
0172     for ( int row = 0; row < rowCount; ++row )
0173     {
0174         const QSize childSize = measureItem( d->proxyModel.index( row, 0, index ) );
0175         childrenSize.setWidth( qMax( childrenSize.width(), childSize.width() ) );
0176         childrenSize.rheight() += childSize.height();
0177     }
0178     return baseSize + childrenSize;
0179 }