File indexing completed on 2024-05-12 15:54:28

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