mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
792 lines
25 KiB
C++
792 lines
25 KiB
C++
/****************************************************************************
|
|
** Copyright (C) 2001-2006 Klarälvdalens Datakonsult AB. All rights reserved.
|
|
**
|
|
** This file is part of the KD Gantt library.
|
|
**
|
|
** This file may be distributed and/or modified under the terms of the
|
|
** GNU General Public License version 2 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
** packaging of this file.
|
|
**
|
|
** Licensees holding valid commercial KD Gantt licenses may use this file in
|
|
** accordance with the KD Gantt Commercial License Agreement provided with
|
|
** the Software.
|
|
**
|
|
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
**
|
|
** See http://www.kdab.net/kdgantt for
|
|
** information about KD Gantt Commercial License Agreements.
|
|
**
|
|
** Contact info@kdab.net if any conditions of this
|
|
** licensing are not clear to you.
|
|
**
|
|
**********************************************************************/
|
|
#include "kdganttgraphicsscene.h"
|
|
#include "kdganttgraphicsscene_p.h"
|
|
#include "kdganttgraphicsitem.h"
|
|
#include "kdganttconstraint.h"
|
|
#include "kdganttconstraintgraphicsitem.h"
|
|
#include "kdganttitemdelegate.h"
|
|
#include "kdganttabstractrowcontroller.h"
|
|
#include "kdganttdatetimegrid.h"
|
|
#include "kdganttsummaryhandlingproxymodel.h"
|
|
|
|
#include <QApplication>
|
|
#include <QGraphicsSceneHelpEvent>
|
|
#include <QPainter>
|
|
#include <QPrinter>
|
|
#include <QTextDocument>
|
|
#include <QToolTip>
|
|
#include <QSet>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <functional>
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
|
|
/* Older Qt dont have this macro, so define it... */
|
|
#ifndef QT_VERSION_CHECK
|
|
# define QT_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
|
|
#endif
|
|
|
|
/*!\class KDGantt::GraphicsScene
|
|
* \internal
|
|
*/
|
|
|
|
using namespace KDGantt;
|
|
|
|
GraphicsScene::Private::Private( GraphicsScene* _q )
|
|
: q( _q ),
|
|
dragSource( 0 ),
|
|
itemDelegate( new ItemDelegate( _q ) ),
|
|
rowController( 0 ),
|
|
grid( &default_grid ),
|
|
readOnly( false ),
|
|
isPrinting( false ),
|
|
summaryHandlingModel( new SummaryHandlingProxyModel( _q ) ),
|
|
selectionModel( 0 )
|
|
{
|
|
default_grid.setStartDateTime( QDateTime::currentDateTime().addDays( -1 ) );
|
|
}
|
|
|
|
void GraphicsScene::Private::resetConstraintItems()
|
|
{
|
|
q->clearConstraintItems();
|
|
if ( constraintModel.isNull() ) return;
|
|
QList<Constraint> clst = constraintModel->constraints();
|
|
Q_FOREACH( Constraint c, clst ) {
|
|
createConstraintItem( c );
|
|
}
|
|
q->updateItems();
|
|
}
|
|
|
|
void GraphicsScene::Private::createConstraintItem( const Constraint& c )
|
|
{
|
|
GraphicsItem* sitem = q->findItem( summaryHandlingModel->mapFromSource( c.startIndex() ) );
|
|
GraphicsItem* eitem = q->findItem( summaryHandlingModel->mapFromSource( c.endIndex() ) );
|
|
|
|
if ( sitem && eitem ) {
|
|
ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
|
|
sitem->addStartConstraint( citem );
|
|
eitem->addEndConstraint( citem );
|
|
q->addItem( citem );
|
|
}
|
|
|
|
|
|
|
|
//q->insertConstraintItem( c, citem );
|
|
}
|
|
|
|
// Delete the constraint item, and clean up pointers in the start- and end item
|
|
void GraphicsScene::Private::deleteConstraintItem( ConstraintGraphicsItem *citem )
|
|
{
|
|
//qDebug()<<"GraphicsScene::Private::deleteConstraintItem citem="<<(void*)citem;
|
|
if ( citem == 0 ) {
|
|
return;
|
|
}
|
|
Constraint c = citem->constraint();
|
|
GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), 0 );
|
|
if ( item ) {
|
|
//qDebug()<<"GraphicsScene::Private::deleteConstraintItem startConstraints"<<item<<(void*)citem;
|
|
item->removeStartConstraint( citem );
|
|
} //else qDebug()<<"GraphicsScene::Private::deleteConstraintItem"<<c.startIndex()<<"start item not found";
|
|
item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), 0 );
|
|
if ( item ) {
|
|
//qDebug()<<"GraphicsScene::Private::deleteConstraintItem endConstraints"<<item<<(void*)citem;
|
|
item->removeEndConstraint( citem );
|
|
} //else qDebug()<<"GraphicsScene::Private::deleteConstraintItem"<<c.endIndex()<<"end item not found";
|
|
//qDebug()<<"GraphicsScene::Private::deleteConstraintItem"<<citem<<"deleted";
|
|
delete citem;
|
|
}
|
|
|
|
void GraphicsScene::Private::deleteConstraintItem( const Constraint& c )
|
|
{
|
|
//qDebug()<<"GraphicsScene::Private::deleteConstraintItem c="<<c;
|
|
deleteConstraintItem( findConstraintItem( c ) );
|
|
}
|
|
|
|
ConstraintGraphicsItem* GraphicsScene::Private::findConstraintItem( const Constraint& c ) const
|
|
{
|
|
GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), 0 );
|
|
if ( item ) {
|
|
QList<ConstraintGraphicsItem*> clst = item->startConstraints();
|
|
QList<ConstraintGraphicsItem*>::iterator it = clst.begin();
|
|
//qDebug()<<"GraphicsScene::Private::findConstraintItem start:"<<c<<item<<clst;
|
|
for( ; it != clst.end() ; ++it )
|
|
if ((*it)->constraint() == c )
|
|
break;
|
|
if ( it != clst.end() ) {
|
|
return *it;
|
|
}
|
|
}
|
|
item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), 0 );
|
|
if ( item ) {
|
|
QList<ConstraintGraphicsItem*> clst = item->endConstraints();
|
|
QList<ConstraintGraphicsItem*>::iterator it = clst.begin();
|
|
//qDebug()<<"GraphicsScene::Private::findConstraintItem end:"<<c<<item<<clst;
|
|
for( ; it != clst.end() ; ++it )
|
|
if ((*it)->constraint() == c )
|
|
break;
|
|
if ( it != clst.end() ) {
|
|
return *it;
|
|
}
|
|
}
|
|
//qDebug()<<"GraphicsScene::Private::findConstraintItem No item or constraintitem"<<c;
|
|
return 0;
|
|
}
|
|
|
|
GraphicsScene::GraphicsScene( QObject* parent )
|
|
: QGraphicsScene( parent ), _d( new Private( this ) )
|
|
{
|
|
init();
|
|
}
|
|
|
|
GraphicsScene::~GraphicsScene()
|
|
{
|
|
clearConstraintItems();
|
|
clearItems();
|
|
}
|
|
|
|
#define d d_func()
|
|
|
|
void GraphicsScene::init()
|
|
{
|
|
setItemIndexMethod( QGraphicsScene::NoIndex );
|
|
setConstraintModel( new ConstraintModel( this ) );
|
|
connect( d->grid, SIGNAL(gridChanged()), this, SLOT(slotGridChanged()) );
|
|
}
|
|
|
|
/* NOTE: The delegate should really be a property
|
|
* of the view, but that doesn't really fit at
|
|
* this time
|
|
*/
|
|
void GraphicsScene::setItemDelegate( ItemDelegate* delegate )
|
|
{
|
|
if ( !d->itemDelegate.isNull() && d->itemDelegate->parent()==this ) delete d->itemDelegate;
|
|
d->itemDelegate = delegate;
|
|
update();
|
|
}
|
|
|
|
ItemDelegate* GraphicsScene::itemDelegate() const
|
|
{
|
|
return d->itemDelegate;
|
|
}
|
|
|
|
QAbstractItemModel* GraphicsScene::model() const
|
|
{
|
|
assert(!d->summaryHandlingModel.isNull());
|
|
return d->summaryHandlingModel->sourceModel();
|
|
}
|
|
|
|
void GraphicsScene::setModel( QAbstractItemModel* model )
|
|
{
|
|
assert(!d->summaryHandlingModel.isNull());
|
|
d->summaryHandlingModel->setSourceModel(model);
|
|
d->grid->setModel( d->summaryHandlingModel );
|
|
setSelectionModel( new QItemSelectionModel( model, this ) );
|
|
}
|
|
|
|
QAbstractProxyModel* GraphicsScene::summaryHandlingModel() const
|
|
{
|
|
return d->summaryHandlingModel;
|
|
}
|
|
|
|
void GraphicsScene::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
|
|
{
|
|
proxyModel->setSourceModel( model() );
|
|
d->summaryHandlingModel = proxyModel;
|
|
}
|
|
|
|
void GraphicsScene::setRootIndex( const QModelIndex& idx )
|
|
{
|
|
d->grid->setRootIndex( idx );
|
|
}
|
|
|
|
QModelIndex GraphicsScene::rootIndex() const
|
|
{
|
|
return d->grid->rootIndex();
|
|
}
|
|
|
|
ConstraintModel* GraphicsScene::constraintModel() const
|
|
{
|
|
return d->constraintModel;
|
|
}
|
|
|
|
void GraphicsScene::setConstraintModel( ConstraintModel* cm )
|
|
{
|
|
if ( !d->constraintModel.isNull() ) {
|
|
disconnect( d->constraintModel );
|
|
}
|
|
d->constraintModel = cm;
|
|
|
|
connect( cm, SIGNAL(constraintAdded(Constraint)), this, SLOT(slotConstraintAdded(Constraint)) );
|
|
connect( cm, SIGNAL(constraintRemoved(Constraint)), this, SLOT(slotConstraintRemoved(Constraint)) );
|
|
d->resetConstraintItems();
|
|
}
|
|
|
|
void GraphicsScene::setSelectionModel( QItemSelectionModel* smodel )
|
|
{
|
|
d->selectionModel = smodel;
|
|
// TODO: update selection from model and connect signals
|
|
}
|
|
|
|
QItemSelectionModel* GraphicsScene::selectionModel() const
|
|
{
|
|
return d->selectionModel;
|
|
}
|
|
|
|
void GraphicsScene::setRowController( AbstractRowController* rc )
|
|
{
|
|
d->rowController = rc;
|
|
}
|
|
|
|
AbstractRowController* GraphicsScene::rowController() const
|
|
{
|
|
return d->rowController;
|
|
}
|
|
|
|
void GraphicsScene::setGrid( AbstractGrid* grid )
|
|
{
|
|
QAbstractItemModel* model = d->grid->model();
|
|
if ( grid == 0 ) grid = &d->default_grid;
|
|
if ( d->grid ) disconnect( d->grid );
|
|
d->grid = grid;
|
|
connect( d->grid, SIGNAL(gridChanged()), this, SLOT(slotGridChanged()) );
|
|
d->grid->setModel( model );
|
|
slotGridChanged();
|
|
}
|
|
|
|
AbstractGrid* GraphicsScene::grid() const
|
|
{
|
|
return d->grid;
|
|
}
|
|
|
|
void GraphicsScene::setReadOnly( bool ro )
|
|
{
|
|
d->readOnly = ro;
|
|
}
|
|
|
|
bool GraphicsScene::isReadOnly() const
|
|
{
|
|
return d->readOnly;
|
|
}
|
|
|
|
/* Returns the index with column=0 fromt the
|
|
* same row as idx and with the same parent.
|
|
* This is used to traverse the tree-structure
|
|
* of the model
|
|
*/
|
|
QModelIndex GraphicsScene::mainIndex( const QModelIndex& idx )
|
|
{
|
|
#if 0
|
|
if ( idx.isValid() ) {
|
|
return idx.model()->index( idx.row(), 0,idx.parent() );
|
|
} else {
|
|
return QModelIndex();
|
|
}
|
|
#else
|
|
return idx;
|
|
#endif
|
|
}
|
|
|
|
/*! Returns the index pointing to the last column
|
|
* in the same row as idx. This can be thought of
|
|
* as in "inverse" of mainIndex()
|
|
*/
|
|
QModelIndex GraphicsScene::dataIndex( const QModelIndex& idx )
|
|
{
|
|
#if 0
|
|
if ( idx.isValid() ) {
|
|
const QAbstractItemModel* model = idx.model();
|
|
return model->index( idx.row(), model->columnCount( idx.parent() )-1,idx.parent() );
|
|
} else {
|
|
return QModelIndex();
|
|
}
|
|
#else
|
|
return idx;
|
|
#endif
|
|
}
|
|
|
|
/*! Creates a new item of type type.
|
|
* TODO: If the user should be allowed to override
|
|
* this in any way, it needs to be in View!
|
|
*/
|
|
GraphicsItem* GraphicsScene::createItem( ItemType type ) const
|
|
{
|
|
#if 0
|
|
switch( type ) {
|
|
case TypeEvent: return 0;
|
|
case TypeTask: return new TaskItem;
|
|
case TypeSummary: return new SummaryItem;
|
|
default: return 0;
|
|
}
|
|
#endif
|
|
//qDebug() << "GraphicsScene::createItem("<<type<<")";
|
|
Q_UNUSED( type );
|
|
return new GraphicsItem;
|
|
}
|
|
|
|
void GraphicsScene::Private::recursiveUpdateMultiItem( const Span& span, const QModelIndex& idx )
|
|
{
|
|
//qDebug() << "recursiveUpdateMultiItem("<<span<<idx<<")";
|
|
GraphicsItem* item = q->findItem( idx );
|
|
const int itemtype = summaryHandlingModel->data( idx, ItemTypeRole ).toInt();
|
|
if (!item) {
|
|
item = q->createItem( static_cast<ItemType>( itemtype ) );
|
|
item->setIndex( idx );
|
|
q->insertItem( idx, item);
|
|
}
|
|
item->updateItem( span, idx );
|
|
QModelIndex child;
|
|
int cr = 0;
|
|
while ( ( child = idx.child( cr, 0 ) ).isValid() ) {
|
|
recursiveUpdateMultiItem( span, child );
|
|
++cr;
|
|
}
|
|
}
|
|
|
|
void GraphicsScene::updateRow( const QModelIndex& rowidx )
|
|
{
|
|
//qDebug() << "GraphicsScene::updateRow("<<rowidx<<")" << rowidx.data( Qt::DisplayRole );
|
|
if ( !rowidx.isValid() ) return;
|
|
const QAbstractItemModel* model = rowidx.model(); // why const?
|
|
assert( model );
|
|
assert( rowController() );
|
|
assert( model == summaryHandlingModel() );
|
|
|
|
const QModelIndex sidx = summaryHandlingModel()->mapToSource( rowidx );
|
|
Span rg = rowController()->rowGeometry( sidx );
|
|
for ( QModelIndex treewalkidx = sidx; treewalkidx.isValid(); treewalkidx = treewalkidx.parent() ) {
|
|
if ( treewalkidx.data( ItemTypeRole ).toInt() == TypeMulti
|
|
&& !rowController()->isRowExpanded( treewalkidx )) {
|
|
rg = rowController()->rowGeometry( treewalkidx );
|
|
}
|
|
}
|
|
|
|
bool blocked = blockSignals( true );
|
|
for ( int col = 0; col < summaryHandlingModel()->columnCount( rowidx.parent() ); ++col ) {
|
|
const QModelIndex idx = summaryHandlingModel()->index( rowidx.row(), col, rowidx.parent() );
|
|
const QModelIndex sidx = summaryHandlingModel()->mapToSource( idx );
|
|
const int itemtype = summaryHandlingModel()->data( idx, ItemTypeRole ).toInt();
|
|
const bool isExpanded = rowController()->isRowExpanded( sidx );
|
|
if ( itemtype == TypeNone ) {
|
|
removeItem( idx );
|
|
continue;
|
|
}
|
|
if ( itemtype == TypeMulti && !isExpanded ) {
|
|
d->recursiveUpdateMultiItem( rg, idx );
|
|
} else {
|
|
if ( summaryHandlingModel()->data( rowidx.parent(), ItemTypeRole ).toInt() == TypeMulti && !isExpanded ) {
|
|
//continue;
|
|
}
|
|
|
|
GraphicsItem* item = findItem( idx );
|
|
if (!item) {
|
|
item = createItem( static_cast<ItemType>( itemtype ) );
|
|
item->setIndex( idx );
|
|
insertItem(idx, item);
|
|
}
|
|
const Span span = rowController()->rowGeometry( sidx );
|
|
item->updateItem( span, idx );
|
|
}
|
|
}
|
|
blockSignals( blocked );
|
|
}
|
|
|
|
void GraphicsScene::insertItem( const QPersistentModelIndex& idx, GraphicsItem* item )
|
|
{
|
|
if ( !d->constraintModel.isNull() ) {
|
|
// Create items for constraints
|
|
const QModelIndex sidx = summaryHandlingModel()->mapToSource( idx );
|
|
const QList<Constraint> clst = d->constraintModel->constraintsForIndex( sidx );
|
|
Q_FOREACH( Constraint c, clst ) {
|
|
QModelIndex other_idx;
|
|
if ( c.startIndex() == sidx ) {
|
|
other_idx = c.endIndex();
|
|
GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),0);
|
|
if ( !other_item ) continue;
|
|
ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
|
|
item->addStartConstraint( citem );
|
|
other_item->addEndConstraint( citem );
|
|
addItem( citem );
|
|
} else if ( c.endIndex() == sidx ) {
|
|
other_idx = c.startIndex();
|
|
GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),0);
|
|
if ( !other_item ) continue;
|
|
ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
|
|
other_item->addStartConstraint( citem );
|
|
item->addEndConstraint( citem );
|
|
addItem( citem );
|
|
} else {
|
|
assert( 0 ); // Impossible
|
|
}
|
|
}
|
|
}
|
|
d->items.insert( idx, item );
|
|
addItem( item );
|
|
}
|
|
|
|
void GraphicsScene::removeItem( const QModelIndex& idx )
|
|
{
|
|
//qDebug() << "GraphicsScene::removeItem("<<idx<<")";
|
|
QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.find( idx );
|
|
if ( it != d->items.end() ) {
|
|
GraphicsItem* item = *it;
|
|
assert( item );
|
|
// We have to remove the item from the list first because
|
|
// there is a good chance there will be reentrant calls
|
|
d->items.erase( it );
|
|
{
|
|
// Remove any constraintitems attached
|
|
const QSet<ConstraintGraphicsItem*> clst = QSet<ConstraintGraphicsItem*>::fromList( item->startConstraints() ) +
|
|
QSet<ConstraintGraphicsItem*>::fromList( item->endConstraints() );
|
|
Q_FOREACH( ConstraintGraphicsItem* citem, clst ) {
|
|
d->deleteConstraintItem( citem );
|
|
}
|
|
}
|
|
// Get rid of the item
|
|
delete item;
|
|
}
|
|
}
|
|
|
|
GraphicsItem* GraphicsScene::findItem( const QModelIndex& idx ) const
|
|
{
|
|
if ( !idx.isValid() ) return 0;
|
|
assert( idx.model() == summaryHandlingModel() );
|
|
QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it = d->items.find( idx );
|
|
return ( it != d->items.end() )?*it:0;
|
|
}
|
|
|
|
GraphicsItem* GraphicsScene::findItem( const QPersistentModelIndex& idx ) const
|
|
{
|
|
if ( !idx.isValid() ) return 0;
|
|
assert( idx.model() == summaryHandlingModel() );
|
|
QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it = d->items.find( idx );
|
|
return ( it != d->items.end() )?*it:0;
|
|
}
|
|
|
|
void GraphicsScene::clearItems()
|
|
{
|
|
// TODO constraints
|
|
qDeleteAll( items() );
|
|
d->items.clear();
|
|
}
|
|
|
|
void GraphicsScene::updateItems()
|
|
{
|
|
for ( QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.begin();
|
|
it != d->items.end(); ++it ) {
|
|
GraphicsItem* const item = it.value();
|
|
const QPersistentModelIndex& idx = it.key();
|
|
item->updateItem( Span( item->pos().y(), item->rect().height() ), idx );
|
|
}
|
|
invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
|
|
}
|
|
|
|
void GraphicsScene::deleteSubtree( const QModelIndex& _idx )
|
|
{
|
|
QModelIndex idx = dataIndex( _idx );
|
|
if ( !idx.model() ) return;
|
|
const QModelIndex parent( idx.parent() );
|
|
const int colcount = idx.model()->columnCount( parent );
|
|
{for ( int i = 0; i < colcount; ++i ) {
|
|
removeItem( parent.child( idx.row(), i ) );
|
|
}}
|
|
const int rowcount = summaryHandlingModel()->rowCount( _idx );
|
|
{for ( int i = 0; i < rowcount; ++i ) {
|
|
deleteSubtree( summaryHandlingModel()->index( i, summaryHandlingModel()->columnCount(_idx)-1, _idx ) );
|
|
}}
|
|
}
|
|
|
|
|
|
ConstraintGraphicsItem* GraphicsScene::findConstraintItem( const Constraint& c ) const
|
|
{
|
|
return d->findConstraintItem( c );
|
|
}
|
|
|
|
void GraphicsScene::clearConstraintItems()
|
|
{
|
|
// TODO
|
|
// d->constraintItems.clearConstraintItems();
|
|
}
|
|
|
|
void GraphicsScene::slotConstraintAdded( const Constraint& c )
|
|
{
|
|
d->createConstraintItem( c );
|
|
}
|
|
|
|
void GraphicsScene::slotConstraintRemoved( const Constraint& c )
|
|
{
|
|
d->deleteConstraintItem( c );
|
|
}
|
|
|
|
void GraphicsScene::slotGridChanged()
|
|
{
|
|
updateItems();
|
|
update();
|
|
emit gridChanged();
|
|
}
|
|
|
|
void GraphicsScene::helpEvent( QGraphicsSceneHelpEvent *helpEvent )
|
|
{
|
|
#ifndef QT_NO_TOOLTIP
|
|
QGraphicsItem *item = itemAt( helpEvent->scenePos() );
|
|
if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
|
|
QToolTip::showText(helpEvent->screenPos(), gitem->ganttToolTip());
|
|
} else if ( ConstraintGraphicsItem* citem = qgraphicsitem_cast<ConstraintGraphicsItem*>( item ) ) {
|
|
QToolTip::showText(helpEvent->screenPos(), citem->ganttToolTip());
|
|
} else {
|
|
QGraphicsScene::helpEvent( helpEvent );
|
|
}
|
|
#endif /* QT_NO_TOOLTIP */
|
|
}
|
|
|
|
void GraphicsScene::drawBackground( QPainter* painter, const QRectF& _rect )
|
|
{
|
|
QRectF scn( sceneRect() );
|
|
QRectF rect( _rect );
|
|
if ( d->isPrinting ) {
|
|
QRectF headerRect( scn.topLeft()+QPointF( d->labelsWidth, 0 ),
|
|
QSizeF( scn.width()-d->labelsWidth, d->rowController->headerHeight() ));
|
|
d->grid->paintHeader( painter, headerRect, rect, 0, 0 );
|
|
|
|
/* We have to blank out the part of the header that is invisible during
|
|
* normal rendering when we are printing.
|
|
*/
|
|
QRectF labelsTabRect( scn.topLeft(), QSizeF( d->labelsWidth, headerRect.height() ) );
|
|
|
|
QStyleOptionHeader opt;
|
|
opt.rect = labelsTabRect.toRect();
|
|
opt.text = "";
|
|
opt.textAlignment = Qt::AlignCenter;
|
|
#if QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)
|
|
style()->drawControl(QStyle::CE_Header, &opt, painter, 0);
|
|
#else
|
|
QApplication::style()->drawControl(QStyle::CE_Header, &opt, painter, 0);
|
|
#endif
|
|
scn.setTop( headerRect.bottom() );
|
|
scn.setLeft( headerRect.left() );
|
|
rect = rect.intersected( scn );
|
|
}
|
|
d->grid->paintGrid( painter, scn, rect, d->rowController );
|
|
}
|
|
|
|
void GraphicsScene::itemEntered( const QModelIndex& idx )
|
|
{
|
|
emit entered( idx );
|
|
}
|
|
|
|
void GraphicsScene::itemPressed( const QModelIndex& idx )
|
|
{
|
|
emit pressed( idx );
|
|
}
|
|
|
|
void GraphicsScene::itemClicked( const QModelIndex& idx )
|
|
{
|
|
emit clicked( idx );
|
|
}
|
|
|
|
void GraphicsScene::itemDoubleClicked( const QModelIndex& idx )
|
|
{
|
|
emit doubleClicked( idx );
|
|
}
|
|
|
|
void GraphicsScene::setDragSource( GraphicsItem* item )
|
|
{
|
|
d->dragSource = item;
|
|
}
|
|
|
|
GraphicsItem* GraphicsScene::dragSource() const
|
|
{
|
|
return d->dragSource;
|
|
}
|
|
|
|
/*! Print the Gantt chart using \a printer. If \a drawRowLabels
|
|
* is true (the default), each row will have it's label printed
|
|
* on the left side.
|
|
*
|
|
* This version of print() will print multiple pages.
|
|
*/
|
|
void GraphicsScene::print( QPrinter* printer, bool drawRowLabels )
|
|
{
|
|
//There is no printer support under wince
|
|
#ifndef _WIN32_WCE
|
|
QPainter painter( printer );
|
|
doPrint( &painter, printer->pageRect(), sceneRect().left(), sceneRect().right(), printer, drawRowLabels );
|
|
#endif
|
|
}
|
|
|
|
/*! Print part of the Gantt chart from \a start to \a end using \a printer.
|
|
* If \a drawRowLabels is true (the default), each row will have it's
|
|
* label printed on the left side.
|
|
*
|
|
* This version of print() will print multiple pages.
|
|
*
|
|
* To print a certain range of a chart with a DateTimeGrid, use
|
|
* qreal DateTimeGrid::mapFromDateTime( const QDateTime& dt) const
|
|
* to figure out the values for \a start and \a end.
|
|
*/
|
|
void GraphicsScene::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels )
|
|
{
|
|
//There is no printer support under wince
|
|
#ifndef _WIN32_WCE
|
|
QPainter painter( printer );
|
|
doPrint( &painter, printer->pageRect(), start, end, printer, drawRowLabels );
|
|
#endif
|
|
}
|
|
|
|
/*! Render the GanttView inside the rectangle \a target using the painter \a painter.
|
|
* If \a drawRowLabels is true (the default), each row will have it's
|
|
* label printed on the left side.
|
|
*/
|
|
void GraphicsScene::print( QPainter* painter, const QRectF& _targetRect, bool drawRowLabels )
|
|
{
|
|
//There is no printer support under wince
|
|
#ifndef _WIN32_WCE
|
|
QRectF targetRect( _targetRect );
|
|
if ( targetRect.isNull() ) {
|
|
targetRect = sceneRect();
|
|
}
|
|
|
|
doPrint( painter, targetRect, sceneRect().left(), sceneRect().right(), 0, drawRowLabels );
|
|
#endif
|
|
}
|
|
|
|
/*! Render the GanttView inside the rectangle \a target using the painter \a painter.
|
|
* If \a drawRowLabels is true (the default), each row will have it's
|
|
* label printed on the left side.
|
|
*
|
|
* To print a certain range of a chart with a DateTimeGrid, use
|
|
* qreal DateTimeGrid::mapFromDateTime( const QDateTime& dt) const
|
|
* to figure out the values for \a start and \a end.
|
|
*/
|
|
void GraphicsScene::print( QPainter* painter, qreal start, qreal end,
|
|
const QRectF& _targetRect, bool drawRowLabels )
|
|
{
|
|
//There is no printer support under wince
|
|
#ifndef _WIN32_WCE
|
|
QRectF targetRect( _targetRect );
|
|
if ( targetRect.isNull() ) {
|
|
targetRect = sceneRect();
|
|
}
|
|
|
|
doPrint( painter, targetRect, start, end, 0, drawRowLabels );
|
|
#endif
|
|
}
|
|
|
|
/*!\internal
|
|
*/
|
|
void GraphicsScene::doPrint( QPainter* painter, const QRectF& targetRect,
|
|
qreal start, qreal end,
|
|
QPrinter* printer, bool drawRowLabels )
|
|
{
|
|
//There is no printer support under wince
|
|
#ifndef _WIN32_WCE
|
|
assert( painter );
|
|
d->isPrinting = true;
|
|
#if QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)
|
|
QFont sceneFont( font() );
|
|
if ( printer ) {
|
|
sceneFont = QFont( font(), printer );
|
|
sceneFont.setPixelSize( font().pointSize() );
|
|
}
|
|
#else
|
|
QFont sceneFont( painter->font() );
|
|
if ( printer ) {
|
|
sceneFont = QFont( painter->font(), printer );
|
|
sceneFont.setPixelSize( painter->font().pointSize() );
|
|
}
|
|
#endif
|
|
|
|
const QRectF oldScnRect( sceneRect() );
|
|
QRectF scnRect( oldScnRect );
|
|
scnRect.setLeft( start );
|
|
scnRect.setRight( end );
|
|
scnRect.setTop( -d->rowController->headerHeight() );
|
|
bool b = blockSignals( true );
|
|
|
|
/* row labels */
|
|
QVector<QGraphicsTextItem*> textLabels;
|
|
if ( drawRowLabels ) {
|
|
qreal textWidth = 0.;
|
|
QModelIndex sidx = summaryHandlingModel()->mapToSource( summaryHandlingModel()->index( 0, 0, rootIndex()) );
|
|
do {
|
|
QModelIndex idx = summaryHandlingModel()->mapFromSource( sidx );
|
|
const Span rg=rowController()->rowGeometry( sidx );
|
|
const QString txt = idx.data( Qt::DisplayRole ).toString();
|
|
QGraphicsTextItem* item = new QGraphicsTextItem( txt );
|
|
addItem( item );
|
|
textLabels << item;
|
|
item->adjustSize();
|
|
textWidth = qMax( item->textWidth(), textWidth );
|
|
item->setPos( 0, rg.start() );
|
|
} while ( ( sidx = rowController()->indexBelow( sidx ) ).isValid() );
|
|
// Add a little margin to textWidth
|
|
textWidth += QFontMetricsF(sceneFont).width( QString::fromLatin1( "X" ) );
|
|
Q_FOREACH( QGraphicsTextItem* item, textLabels ) {
|
|
item->setPos( scnRect.left()-textWidth, item->y() );
|
|
item->show();
|
|
}
|
|
scnRect.setLeft( scnRect.left()-textWidth );
|
|
d->labelsWidth = textWidth;
|
|
}
|
|
|
|
setSceneRect( scnRect );
|
|
|
|
painter->save();
|
|
painter->setClipRect( targetRect );
|
|
|
|
qreal yratio = targetRect.height()/scnRect.height();
|
|
/* If we're not printing multiple pages,
|
|
* check if the span fits and adjust:
|
|
*/
|
|
if ( !printer && targetRect.width()/scnRect.width() < yratio ) {
|
|
yratio = targetRect.width()/scnRect.width();
|
|
}
|
|
|
|
qreal offset = scnRect.left();
|
|
int pagecount = 0;
|
|
while ( offset < scnRect.width() ) {
|
|
painter->setFont( sceneFont );
|
|
render( painter, targetRect, QRectF( QPointF( offset, scnRect.top()),
|
|
QSizeF( targetRect.width()/yratio, scnRect.height() ) ) );
|
|
offset += targetRect.width()/yratio;
|
|
++pagecount;
|
|
if ( printer && offset < scnRect.width() ) {
|
|
printer->newPage();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
d->isPrinting = false;
|
|
qDeleteAll( textLabels );
|
|
blockSignals( b );
|
|
setSceneRect( oldScnRect );
|
|
painter->restore();
|
|
#endif
|
|
}
|
|
|
|
|