~ubuntu-branches/ubuntu/raring/calligra/raring-proposed

« back to all changes in this revision

Viewing changes to 3rdparty/kdgantt/kdganttgraphicsscene.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-01-15 17:26:10 UTC
  • mfrom: (1.1.17)
  • Revision ID: package-import@ubuntu.com-20130115172610-b193s9546hyssmym
Tags: 1:2.5.94-0ubuntu1
New upstream RC release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
 ** Copyright (C) 2001-2006 Klarälvdalens Datakonsult AB.  All rights reserved.
 
3
 **
 
4
 ** This file is part of the KD Gantt library.
 
5
 **
 
6
 ** This file may be used under the terms of the GNU General Public
 
7
 ** License versions 2.0 or 3.0 as published by the Free Software
 
8
 ** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
 
9
 ** included in the packaging of this file.  Alternatively you may (at
 
10
 ** your option) use any later version of the GNU General Public
 
11
 ** License if such license has been publicly approved by
 
12
 ** Klarälvdalens Datakonsult AB (or its successors, if any).
 
13
 ** 
 
14
 ** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
 
15
 ** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
 
16
 ** A PARTICULAR PURPOSE. Klarälvdalens Datakonsult AB reserves all rights
 
17
 ** not expressly granted herein.
 
18
 ** 
 
19
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
20
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
21
 **
 
22
 **********************************************************************/
 
23
#include "kdganttgraphicsscene.h"
 
24
#include "kdganttgraphicsscene_p.h"
 
25
#include "kdganttgraphicsitem.h"
 
26
#include "kdganttconstraint.h"
 
27
#include "kdganttconstraintgraphicsitem.h"
 
28
#include "kdganttitemdelegate.h"
 
29
#include "kdganttabstractrowcontroller.h"
 
30
#include "kdganttdatetimegrid.h"
 
31
#include "kdganttsummaryhandlingproxymodel.h"
 
32
#include "kdganttgraphicsview.h"
 
33
 
 
34
#include <QApplication>
 
35
#include <QToolTip>
 
36
#include <QGraphicsSceneHelpEvent>
 
37
#include <QTextDocument>
 
38
#include <QDebug>
 
39
 
 
40
#include <functional>
 
41
#include <algorithm>
 
42
#include <cassert>
 
43
 
 
44
/*!\class KDGantt::GraphicsScene
 
45
 * \internal
 
46
 */
 
47
 
 
48
using namespace KDGantt;
 
49
 
 
50
GraphicsScene::Private::Private( GraphicsScene* _q )
 
51
    : q( _q ),
 
52
      dragSource( 0 ),
 
53
      itemDelegate( new ItemDelegate( _q ) ),
 
54
      rowController( 0 ),
 
55
      grid( &default_grid ),
 
56
      readOnly( false ),
 
57
      summaryHandlingModel( new SummaryHandlingProxyModel( _q ) ),
 
58
      selectionModel( 0 )
 
59
{
 
60
    default_grid.setStartDateTime( QDateTime::currentDateTime().addDays( -1 ) );
 
61
}
 
62
 
 
63
void GraphicsScene::Private::resetConstraintItems()
 
64
{
 
65
    q->clearConstraintItems();
 
66
    if ( constraintModel.isNull() ) return;
 
67
    QList<Constraint> clst = constraintModel->constraints();
 
68
    Q_FOREACH( Constraint c, clst ) {
 
69
        createConstraintItem( c );
 
70
    }
 
71
    q->updateItems();
 
72
}
 
73
 
 
74
void GraphicsScene::Private::createConstraintItem( const Constraint& c )
 
75
{
 
76
    GraphicsItem* sitem = q->findItem( summaryHandlingModel->mapFromSource( c.startIndex() ) );
 
77
    GraphicsItem* eitem = q->findItem( summaryHandlingModel->mapFromSource( c.endIndex() ) );
 
78
 
 
79
    if ( sitem && eitem ) {
 
80
        ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
 
81
        sitem->addStartConstraint( citem );
 
82
        eitem->addEndConstraint( citem );
 
83
        q->addItem( citem );
 
84
    }
 
85
 
 
86
 
 
87
 
 
88
    //q->insertConstraintItem( c, citem );
 
89
}
 
90
 
 
91
// Delete the constraint item, and clean up pointers in the start- and end item
 
92
void GraphicsScene::Private::deleteConstraintItem( ConstraintGraphicsItem *citem )
 
93
{
 
94
    //qDebug()<<"GraphicsScene::Private::deleteConstraintItem citem="<<(void*)citem;
 
95
    if ( citem == 0 ) {
 
96
        return;
 
97
    }
 
98
    Constraint c = citem->constraint();
 
99
    GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), 0 );
 
100
    if ( item ) {
 
101
        //qDebug()<<"GraphicsScene::Private::deleteConstraintItem startConstraints"<<item<<(void*)citem;
 
102
        item->removeStartConstraint( citem );
 
103
    } //else qDebug()<<"GraphicsScene::Private::deleteConstraintItem"<<c.startIndex()<<"start item not found";
 
104
    item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), 0 );
 
105
    if ( item ) {
 
106
        //qDebug()<<"GraphicsScene::Private::deleteConstraintItem endConstraints"<<item<<(void*)citem;
 
107
        item->removeEndConstraint( citem );
 
108
    } //else qDebug()<<"GraphicsScene::Private::deleteConstraintItem"<<c.endIndex()<<"end item not found";
 
109
    //qDebug()<<"GraphicsScene::Private::deleteConstraintItem"<<citem<<"deleted";
 
110
    delete citem;
 
111
}
 
112
 
 
113
void GraphicsScene::Private::deleteConstraintItem( const Constraint& c )
 
114
{
 
115
    //qDebug()<<"GraphicsScene::Private::deleteConstraintItem c="<<c;
 
116
    deleteConstraintItem( findConstraintItem( c ) );
 
117
}
 
118
 
 
119
namespace {
 
120
    /* Very useful functional to compose functions.
 
121
     * Unfortunately an SGI extension and not standard
 
122
     */
 
123
    template<typename Operation1,typename Operation2>
 
124
    struct unary_compose : public std::unary_function<typename Operation1::result_type,typename Operation2::argument_type> {
 
125
        unary_compose( const Operation1& f, const Operation2& g ) : _f( f ), _g( g ) {}
 
126
 
 
127
        inline typename Operation1::result_type operator()( const typename Operation2::argument_type& arg ) {
 
128
            return _f( _g( arg ) );
 
129
        }
 
130
 
 
131
        Operation1 _f;
 
132
        Operation2 _g;
 
133
    };
 
134
 
 
135
    template<typename Operation1,typename Operation2>
 
136
    inline unary_compose<Operation1,Operation2> compose1( const Operation1& f, const Operation2& g )
 
137
    {
 
138
        return unary_compose<Operation1,Operation2>( f, g );
 
139
    }
 
140
}
 
141
 
 
142
ConstraintGraphicsItem* GraphicsScene::Private::findConstraintItem( const Constraint& c ) const
 
143
{
 
144
    GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), 0 );
 
145
    if ( item ) {
 
146
        QList<ConstraintGraphicsItem*> clst = item->startConstraints();
 
147
        QList<ConstraintGraphicsItem*>::iterator it = clst.begin();
 
148
        //qDebug()<<"GraphicsScene::Private::findConstraintItem start:"<<c<<item<<clst;
 
149
        for( ; it != clst.end() ; ++it )
 
150
            if ((*it)->constraint() == c )
 
151
                break;
 
152
        if (  it != clst.end() ) {
 
153
            return *it;
 
154
        }
 
155
    }
 
156
    item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), 0 );
 
157
    if ( item ) {
 
158
        QList<ConstraintGraphicsItem*> clst = item->endConstraints();
 
159
        QList<ConstraintGraphicsItem*>::iterator it = clst.begin();
 
160
        //qDebug()<<"GraphicsScene::Private::findConstraintItem end:"<<c<<item<<clst;
 
161
        for( ; it != clst.end() ; ++it )
 
162
            if ((*it)->constraint() == c )
 
163
                break;
 
164
        if (  it != clst.end() ) {
 
165
            return *it;
 
166
        }
 
167
    }
 
168
    //qDebug()<<"GraphicsScene::Private::findConstraintItem No item or constraintitem"<<c;
 
169
    return 0;
 
170
}
 
171
 
 
172
GraphicsScene::GraphicsScene( QObject* parent )
 
173
    : QGraphicsScene( parent ), _d( new Private( this ) )
 
174
{
 
175
    init();
 
176
}
 
177
 
 
178
#define d d_func()
 
179
GraphicsScene::~GraphicsScene()
 
180
{
 
181
    clearConstraintItems();
 
182
    clearItems();
 
183
    delete d;
 
184
}
 
185
 
 
186
void GraphicsScene::init()
 
187
{
 
188
    setConstraintModel( new ConstraintModel( this ) );
 
189
    connect( d->grid, SIGNAL( gridChanged() ), this, SLOT( slotGridChanged() ) );
 
190
}
 
191
 
 
192
/* NOTE: The delegate should really be a property
 
193
 * of the view, but that doesn't really fit at
 
194
 * this time
 
195
 */
 
196
void GraphicsScene::setItemDelegate( ItemDelegate* delegate )
 
197
{
 
198
    if ( !d->itemDelegate.isNull() && d->itemDelegate->parent()==this ) delete d->itemDelegate;
 
199
    d->itemDelegate = delegate;
 
200
    update();
 
201
}
 
202
 
 
203
ItemDelegate* GraphicsScene::itemDelegate() const
 
204
{
 
205
    return d->itemDelegate;
 
206
}
 
207
 
 
208
QAbstractItemModel* GraphicsScene::model() const
 
209
{
 
210
    assert(!d->summaryHandlingModel.isNull());
 
211
    return d->summaryHandlingModel->sourceModel();
 
212
}
 
213
 
 
214
void GraphicsScene::setModel( QAbstractItemModel* model )
 
215
{
 
216
    assert(!d->summaryHandlingModel.isNull());
 
217
    d->summaryHandlingModel->setSourceModel(model);
 
218
    d->grid->setModel( d->summaryHandlingModel );
 
219
    setSelectionModel( new QItemSelectionModel( model, this ) );
 
220
}
 
221
 
 
222
QAbstractProxyModel* GraphicsScene::summaryHandlingModel() const
 
223
{
 
224
    return d->summaryHandlingModel;
 
225
}
 
226
 
 
227
void GraphicsScene::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
 
228
{
 
229
    proxyModel->setSourceModel( model() );
 
230
    d->summaryHandlingModel = proxyModel;
 
231
}
 
232
 
 
233
void GraphicsScene::setRootIndex( const QModelIndex& idx )
 
234
{
 
235
    d->grid->setRootIndex( idx );
 
236
}
 
237
 
 
238
QModelIndex GraphicsScene::rootIndex() const
 
239
{
 
240
    return d->grid->rootIndex();
 
241
}
 
242
 
 
243
ConstraintModel* GraphicsScene::constraintModel() const
 
244
{
 
245
    return d->constraintModel;
 
246
}
 
247
 
 
248
void GraphicsScene::setConstraintModel( ConstraintModel* cm )
 
249
{
 
250
    if ( !d->constraintModel.isNull() ) {
 
251
        disconnect( d->constraintModel );
 
252
    }
 
253
    d->constraintModel = cm;
 
254
 
 
255
    connect( cm, SIGNAL( constraintAdded( const Constraint& ) ), this, SLOT( slotConstraintAdded( const Constraint& ) ) );
 
256
    connect( cm, SIGNAL( constraintRemoved( const Constraint& ) ), this, SLOT( slotConstraintRemoved( const Constraint& ) ) );
 
257
    d->resetConstraintItems();
 
258
}
 
259
 
 
260
void GraphicsScene::setSelectionModel( QItemSelectionModel* smodel )
 
261
{
 
262
    d->selectionModel = smodel;
 
263
    // TODO: update selection from model and connect signals
 
264
}
 
265
 
 
266
QItemSelectionModel* GraphicsScene::selectionModel() const
 
267
{
 
268
    return d->selectionModel;
 
269
}
 
270
 
 
271
void GraphicsScene::setRowController( AbstractRowController* rc )
 
272
{
 
273
    d->rowController = rc;
 
274
}
 
275
 
 
276
AbstractRowController* GraphicsScene::rowController() const
 
277
{
 
278
    return d->rowController;
 
279
}
 
280
 
 
281
void GraphicsScene::setGrid( AbstractGrid* grid )
 
282
{
 
283
    QAbstractItemModel* model = d->grid->model();
 
284
    if ( grid == 0 ) grid = &d->default_grid;
 
285
    if ( d->grid ) disconnect( d->grid );
 
286
    d->grid = grid;
 
287
    connect( d->grid, SIGNAL( gridChanged() ), this, SLOT( slotGridChanged() ) );
 
288
    d->grid->setModel( model );
 
289
    slotGridChanged();
 
290
}
 
291
 
 
292
AbstractGrid* GraphicsScene::grid() const
 
293
{
 
294
    return d->grid;
 
295
}
 
296
 
 
297
void GraphicsScene::setReadOnly( bool ro )
 
298
{
 
299
    d->readOnly = ro;
 
300
}
 
301
 
 
302
bool GraphicsScene::isReadOnly() const
 
303
{
 
304
    return d->readOnly;
 
305
}
 
306
 
 
307
/* Returns the index with column=0 fromt the
 
308
 * same row as idx and with the same parent.
 
309
 * This is used to traverse the tree-structure
 
310
 * of the model
 
311
 */
 
312
QModelIndex GraphicsScene::mainIndex( const QModelIndex& idx )
 
313
{
 
314
#if 0
 
315
    if ( idx.isValid() ) {
 
316
        return idx.model()->index( idx.row(), 0,idx.parent() );
 
317
    } else {
 
318
        return QModelIndex();
 
319
    }
 
320
#else
 
321
    return idx;
 
322
#endif
 
323
}
 
324
 
 
325
/*! Returns the index pointing to the last column
 
326
 * in the same row as idx. This can be thought of
 
327
 * as in "inverse" of mainIndex()
 
328
 */
 
329
QModelIndex GraphicsScene::dataIndex( const QModelIndex& idx )
 
330
{
 
331
#if 0
 
332
    if ( idx.isValid() ) {
 
333
        const QAbstractItemModel* model = idx.model();
 
334
        return model->index( idx.row(), model->columnCount( idx.parent() )-1,idx.parent() );
 
335
    } else {
 
336
        return QModelIndex();
 
337
    }
 
338
#else
 
339
    return idx;
 
340
#endif
 
341
}
 
342
 
 
343
/*! Creates a new item of type type.
 
344
 * TODO: If the user should be allowed to override
 
345
 * this in any way, it needs to be in View!
 
346
 */
 
347
GraphicsItem* GraphicsScene::createItem( ItemType type ) const
 
348
{
 
349
#if 0
 
350
    switch( type ) {
 
351
    case TypeEvent:   return 0;
 
352
    case TypeTask:    return new TaskItem;
 
353
    case TypeSummary: return new SummaryItem;
 
354
    default:          return 0;
 
355
    }
 
356
#endif
 
357
    //qDebug() << "GraphicsScene::createItem("<<type<<")";
 
358
    Q_UNUSED( type );
 
359
    return new GraphicsItem;
 
360
}
 
361
 
 
362
void GraphicsScene::updateRow( const QModelIndex& rowidx )
 
363
{
 
364
    //qDebug() << "GraphicsScene::updateRow("<<rowidx<<")";
 
365
    if ( !rowidx.isValid() ) return;
 
366
    const QAbstractItemModel* model = rowidx.model(); // why const?
 
367
    assert( model );
 
368
    assert( rowController() );
 
369
    assert( model == summaryHandlingModel() );
 
370
 
 
371
    const QModelIndex sidx = summaryHandlingModel()->mapToSource( rowidx );
 
372
    const Span rg=rowController()->rowGeometry( sidx );
 
373
    for ( int col = 0; col < summaryHandlingModel()->columnCount( rowidx.parent() ); ++col ) {
 
374
        const QModelIndex idx = summaryHandlingModel()->index( rowidx.row(), col, rowidx.parent() );
 
375
        const int itemtype = summaryHandlingModel()->data( idx, ItemTypeRole ).toInt();
 
376
        if ( itemtype == TypeNone ) {
 
377
            removeItem( idx );
 
378
            continue;
 
379
        }
 
380
        if ( itemtype == TypeMulti ) {
 
381
            int cr=0;
 
382
            QModelIndex child;
 
383
            while ( ( child = idx.child( cr, 0 ) ).isValid() ) {
 
384
                GraphicsItem* item = findItem( child );
 
385
                if (!item) {
 
386
                    item = createItem( static_cast<ItemType>( itemtype ) );
 
387
                    item->setIndex( child );
 
388
                    insertItem( child, item);
 
389
                }
 
390
                item->updateItem( rg, child );
 
391
                setSceneRect( sceneRect().united( item->boundingRect() ) );
 
392
                ++cr;
 
393
            }
 
394
        }
 
395
        {
 
396
            if ( summaryHandlingModel()->data( rowidx.parent(), ItemTypeRole ).toInt() == TypeMulti ) continue;
 
397
 
 
398
            GraphicsItem* item = findItem( idx );
 
399
            if (!item) {
 
400
                item = createItem( static_cast<ItemType>( itemtype ) );
 
401
                item->setIndex( idx );
 
402
                insertItem(idx, item);
 
403
            }
 
404
            item->updateItem( rg, idx );
 
405
            setSceneRect( sceneRect().united( item->boundingRect() ) );
 
406
        }
 
407
    }
 
408
}
 
409
 
 
410
void GraphicsScene::insertItem( const QPersistentModelIndex& idx, GraphicsItem* item )
 
411
{
 
412
    if ( !d->constraintModel.isNull() ) {
 
413
        // Create items for constraints
 
414
        const QModelIndex sidx = summaryHandlingModel()->mapToSource( idx );
 
415
        const QList<Constraint> clst = d->constraintModel->constraintsForIndex( sidx );
 
416
        Q_FOREACH( Constraint c,  clst ) {
 
417
            QModelIndex other_idx;
 
418
            if ( c.startIndex() == sidx ) {
 
419
                other_idx = c.endIndex();
 
420
                GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),0);
 
421
                if ( !other_item ) continue;
 
422
                ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
 
423
                item->addStartConstraint( citem );
 
424
                other_item->addEndConstraint( citem );
 
425
                addItem( citem );
 
426
            } else if ( c.endIndex() == sidx ) {
 
427
                other_idx = c.startIndex();
 
428
                GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),0);
 
429
                if ( !other_item ) continue;
 
430
                ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
 
431
                other_item->addStartConstraint( citem );
 
432
                item->addEndConstraint( citem );
 
433
                addItem( citem );
 
434
            } else {
 
435
                assert( 0 ); // Impossible
 
436
            }
 
437
        }
 
438
    }
 
439
    d->items.insert( idx, item );
 
440
    addItem( item );
 
441
}
 
442
 
 
443
void GraphicsScene::removeItem( const QModelIndex& idx )
 
444
{
 
445
    //qDebug() << "GraphicsScene::removeItem("<<idx<<")";
 
446
    QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.find( idx );
 
447
    if ( it != d->items.end() ) {
 
448
        GraphicsItem* item = *it;
 
449
        // We have to remove the item from the list first because
 
450
        // there is a good chance there will be reentrant calls
 
451
        d->items.erase( it );
 
452
        //qDebug() << "GraphicsScene::removeItem item="<<item;
 
453
        {
 
454
            // Remove any constraintitems starting here
 
455
            const QList<ConstraintGraphicsItem*> clst = item->startConstraints();
 
456
            //qDebug()<<"GraphicsScene::removeItem start:"<<clst;
 
457
            Q_FOREACH( ConstraintGraphicsItem* citem, clst ) {
 
458
                //qDebug()<<"GraphicsScene::removeItem start citem="<<citem;
 
459
                d->deleteConstraintItem( citem );
 
460
            }
 
461
        }
 
462
        {// Remove any constraintitems ending here
 
463
            const QList<ConstraintGraphicsItem*> clst = item->endConstraints();
 
464
            //qDebug()<<"GraphicsScene::removeItem end:"<<clst;
 
465
            Q_FOREACH( ConstraintGraphicsItem* citem, clst ) {
 
466
                //qDebug()<<"GraphicsScene::removeItem end citem="<<citem;
 
467
                d->deleteConstraintItem( citem );
 
468
            }
 
469
        }
 
470
        // Get rid of the item
 
471
        delete item;
 
472
    }
 
473
}
 
474
 
 
475
GraphicsItem* GraphicsScene::findItem( const QModelIndex& idx ) const
 
476
{
 
477
    if ( !idx.isValid() ) return 0;
 
478
    assert( idx.model() == summaryHandlingModel() );
 
479
    QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it = d->items.find( idx );
 
480
    return ( it != d->items.end() )?*it:0;
 
481
}
 
482
 
 
483
GraphicsItem* GraphicsScene::findItem( const QPersistentModelIndex& idx ) const
 
484
{
 
485
    if ( !idx.isValid() ) return 0;
 
486
    assert( idx.model() == summaryHandlingModel() );
 
487
    QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it = d->items.find( idx );
 
488
    return ( it != d->items.end() )?*it:0;
 
489
}
 
490
 
 
491
void GraphicsScene::clearItems()
 
492
{
 
493
    // TODO constraints
 
494
    qDeleteAll( items() );
 
495
    d->items.clear();
 
496
}
 
497
 
 
498
void GraphicsScene::updateItems()
 
499
{
 
500
    for ( QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.begin();
 
501
          it != d->items.end(); ++it ) {
 
502
        GraphicsItem* const item = it.value();
 
503
        const QPersistentModelIndex& idx = it.key();
 
504
        item->updateItem( Span( item->pos().y(), item->rect().height() ), idx );
 
505
    }
 
506
}
 
507
 
 
508
void GraphicsScene::deleteSubtree( const QModelIndex& _idx )
 
509
{
 
510
    QModelIndex idx = dataIndex( _idx );
 
511
    removeItem( idx );
 
512
    for ( int i = 0; i < summaryHandlingModel()->rowCount( _idx ); ++i ) {
 
513
        deleteSubtree( summaryHandlingModel()->index( i, summaryHandlingModel()->columnCount(_idx)-1, _idx ) );
 
514
    }
 
515
}
 
516
 
 
517
 
 
518
ConstraintGraphicsItem* GraphicsScene::findConstraintItem( const Constraint& c ) const
 
519
{
 
520
    return d->findConstraintItem( c );
 
521
}
 
522
 
 
523
void GraphicsScene::clearConstraintItems()
 
524
{
 
525
    // TODO
 
526
    // d->constraintItems.clearConstraintItems();
 
527
}
 
528
 
 
529
void GraphicsScene::slotConstraintAdded( const Constraint& c )
 
530
{
 
531
    d->createConstraintItem( c );
 
532
}
 
533
 
 
534
void GraphicsScene::slotConstraintRemoved( const Constraint& c )
 
535
{
 
536
    d->deleteConstraintItem( c );
 
537
}
 
538
 
 
539
void GraphicsScene::slotGridChanged()
 
540
{
 
541
    updateItems();
 
542
    update();
 
543
    emit gridChanged();
 
544
}
 
545
 
 
546
void GraphicsScene::helpEvent( QGraphicsSceneHelpEvent *helpEvent )
 
547
{
 
548
#ifndef QT_NO_TOOLTIP
 
549
    QGraphicsItem *item = itemAt( helpEvent->scenePos() );
 
550
    if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
 
551
        QToolTip::showText(helpEvent->screenPos(), gitem->ganttToolTip());
 
552
    } else if ( ConstraintGraphicsItem* citem = qgraphicsitem_cast<ConstraintGraphicsItem*>( item ) ) {
 
553
        QToolTip::showText(helpEvent->screenPos(), citem->ganttToolTip());
 
554
    } else {
 
555
        QGraphicsScene::helpEvent( helpEvent );
 
556
    }
 
557
#endif /* QT_NO_TOOLTIP */
 
558
}
 
559
 
 
560
void GraphicsScene::drawBackground( QPainter* painter, const QRectF& rect )
 
561
{
 
562
    d->grid->paintGrid( painter, sceneRect(), rect, d->rowController );
 
563
}
 
564
 
 
565
void GraphicsScene::itemEntered( const QModelIndex& idx )
 
566
{
 
567
    emit entered( idx );
 
568
}
 
569
 
 
570
void GraphicsScene::itemPressed( const QModelIndex& idx )
 
571
{
 
572
    emit pressed( idx );
 
573
}
 
574
 
 
575
void GraphicsScene::itemClicked( const QModelIndex& idx )
 
576
{
 
577
    emit clicked( idx );
 
578
}
 
579
 
 
580
void GraphicsScene::itemDoubleClicked( const QModelIndex& idx )
 
581
{
 
582
    emit doubleClicked( idx );
 
583
}
 
584
 
 
585
void GraphicsScene::setDragSource( GraphicsItem* item )
 
586
{
 
587
    d->dragSource = item;
 
588
}
 
589
 
 
590
GraphicsItem* GraphicsScene::dragSource() const
 
591
{
 
592
    return d->dragSource;
 
593
}
 
594
 
 
595
#define KDGANTT_LIST_CHART_GAP 0.0
 
596
QRectF GraphicsScene::printRect( bool drawRowLabels, GraphicsView *view )
 
597
{
 
598
    assert(rowController());
 
599
 
 
600
    int indentation = 20;
 
601
    bool indentRoot = true;
 
602
 
 
603
    qreal leftEdge = sceneRect().left();
 
604
    QVector<QGraphicsTextItem*> labelItems;
 
605
    if ( drawRowLabels ) {
 
606
        labelItems.reserve(d->items.size());
 
607
        qreal textWidth = 0.;
 
608
        qreal rowHeight = 0.;
 
609
        {Q_FOREACH( GraphicsItem* item, d->items ) {
 
610
            QModelIndex sidx = summaryHandlingModel()->mapToSource( item->index() );
 
611
            if ( sidx.parent().isValid() && sidx.parent().data( ItemTypeRole ).toInt() == TypeMulti ) {
 
612
                continue;
 
613
            }
 
614
            const Span rg = rowController()->rowGeometry( sidx );
 
615
            const QString txt = item->index().data( Qt::DisplayRole ).toString();
 
616
            QGraphicsTextItem* ti = new QGraphicsTextItem( txt, 0, this );
 
617
            ti->setPos( 0, rg.start() );
 
618
            ti->document()->size().setWidth( ti->document()->size().width() + KDGANTT_LIST_CHART_GAP );
 
619
            int indent = indentation * ( level( item->index() ) + ( indentRoot ? 1 : 0 ) );
 
620
            if ( ti->document()->size().width() + indentation > textWidth ) {
 
621
                textWidth = ti->document()->size().width() + indent;
 
622
            }
 
623
            if ( rg.length() > rowHeight ) {
 
624
                rowHeight = rg.length();
 
625
            }
 
626
            labelItems << ti;
 
627
        }}
 
628
        {Q_FOREACH( QGraphicsTextItem* item, labelItems ) {
 
629
            item->setPos( leftEdge-textWidth-rowHeight, item->pos().y() );
 
630
            item->show();
 
631
        }}
 
632
    }
 
633
    QRectF res = itemsBoundingRect();
 
634
    if ( view ) {
 
635
        res.setHeight( res.height() + view->headerHeight() );
 
636
    }
 
637
    qDeleteAll( labelItems );
 
638
    //qDebug()<<"printRect()"<<res;
 
639
    return res;
 
640
}
 
641
 
 
642
void GraphicsScene::drawTreeIndication( QPainter *painter, const QModelIndex &idx, const QRect &rect, int indent, bool drawRoot )
 
643
{
 
644
//    qDebug()<<"drawTreeIndication:"<<idx.data().toString()<<rect;
 
645
 
 
646
    QStyleOptionViewItemV4 option;
 
647
    option.rect.setRect( rect.left(), rect.top(), rect.width(), rect.height() );
 
648
    option.state = option.state | QStyle::State_Enabled | QStyle::State_Active | QStyle::State_Item;
 
649
    if ( idx.sibling(idx.row()+1, 0).isValid() ) {
 
650
        option.state |= QStyle::State_Sibling;
 
651
    }
 
652
    if ( idx.model()->hasChildren( idx ) ) {
 
653
        option.state |= QStyle::State_Children;
 
654
    }
 
655
 
 
656
    QPalette::ColorGroup cg;
 
657
    cg = QPalette::Active;
 
658
    option.palette.setCurrentColorGroup(cg);
 
659
 
 
660
    QModelIndex parent = idx.parent();
 
661
    QModelIndex currentParent = parent;
 
662
    QModelIndex ancestor = currentParent.parent();
 
663
 
 
664
    QRect area( option.rect.right() + 1, option.rect.top(), indent, option.rect.height() ); // moved left before use
 
665
 
 
666
    if ( currentParent.isValid() || drawRoot ) {
 
667
        // draw for idx
 
668
        area.moveLeft(area.left() - indent);
 
669
        option.rect = area;
 
670
        style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter, 0);
 
671
    }
 
672
    option.state &= ~QStyle::State_Item;
 
673
    option.state &= ~QStyle::State_Children;
 
674
    while ( currentParent.isValid() ) {
 
675
        // then draw ancestors
 
676
        if ( ! ancestor.isValid() && ! drawRoot ) {
 
677
            break;
 
678
        }
 
679
        area.moveLeft(area.left() - indent);
 
680
        option.rect = area;
 
681
        if ( currentParent.sibling( currentParent.row() + 1, 0 ).isValid() ) {
 
682
            option.state |= QStyle::State_Sibling;
 
683
        } else {
 
684
            option.state &= ~QStyle::State_Sibling;
 
685
        }
 
686
        style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter);
 
687
        currentParent = ancestor;
 
688
        ancestor = currentParent.parent();
 
689
    }
 
690
}
 
691
 
 
692
int GraphicsScene::level( const QModelIndex &idx ) const
 
693
{
 
694
    int l = 0;
 
695
    for ( QModelIndex p = idx.parent(); p.isValid(); p = p.parent() ) {
 
696
        ++l;
 
697
    }
 
698
    return l;
 
699
}
 
700
 
 
701
void GraphicsScene::print( QPainter* painter, const QRectF& target, const QRectF& source, bool drawRowLabels, GraphicsView *view )
 
702
{
 
703
    QRectF targetRect(target);
 
704
 
 
705
    assert(rowController());
 
706
 
 
707
    int indentation = 20;
 
708
    bool indentRoot = true;
 
709
 
 
710
    qreal scale = 1.0;
 
711
    if ( source.width() > target.width() ) {
 
712
        scale = target.width() / source.width();
 
713
    }
 
714
    if ( source.height() > target.height() ) {
 
715
        scale = qMin( scale, target.height() / source.height() );
 
716
    }
 
717
    painter->scale( scale, scale );
 
718
    targetRect.setWidth( targetRect.width() / scale );
 
719
    targetRect.setHeight( targetRect.height() / scale );
 
720
 
 
721
    qreal textWidth = 0.;
 
722
    if (drawRowLabels) {
 
723
        painter->save();
 
724
 
 
725
        qreal top = view ? view->headerHeight() : 0.0;
 
726
        {Q_FOREACH( GraphicsItem* item, d->items ) {
 
727
            QModelIndex sidx = summaryHandlingModel()->mapToSource( item->index() );
 
728
            if ( sidx.parent().isValid() && sidx.parent().data( ItemTypeRole ).toInt() == TypeMulti ) {
 
729
                continue;
 
730
            }
 
731
            const Span rg = rowController()->rowGeometry( sidx );
 
732
            const QString txt = item->index().data( Qt::DisplayRole ).toString();
 
733
            int indent = indentation * (level( item->index() ) + ( indentRoot ? 1 : 0 ) );
 
734
            QRectF r( indent, rg.start() + top, 0.0, rg.length() );
 
735
            r = painter->boundingRect( r, Qt::AlignLeft | Qt::AlignVCenter, txt );
 
736
            painter->drawText( r, Qt::AlignLeft | Qt::AlignVCenter, txt );
 
737
            if ( r.width() > textWidth ) {
 
738
                textWidth = r.width() + indent;
 
739
            }
 
740
            QRect rect = r.toRect();
 
741
            rect.setLeft( 1 );
 
742
            rect.setRight( r.left() );
 
743
            drawTreeIndication( painter, item->index(), rect, indentation, indentRoot );
 
744
        }}
 
745
        painter->restore();
 
746
        if ( view ) {
 
747
            QStyle* style = QApplication::style();
 
748
            QRectF r( 0.0, 0.0, textWidth, view->headerHeight() );
 
749
            QStyleOptionHeader opt;
 
750
            opt.init( view );
 
751
            opt.rect = r.toRect();
 
752
            opt.text = summaryHandlingModel()->headerData( 0, Qt::Horizontal, Qt::DisplayRole ).toString();
 
753
            opt.textAlignment = Qt::AlignCenter;
 
754
            // NOTE:CE_Header does not honor clipRegion(), so we do the CE_Header logic here
 
755
            style->drawControl( QStyle::CE_HeaderSection, &opt, painter, view );
 
756
            QStyleOptionHeader subopt = opt;
 
757
            subopt.rect = style->subElementRect( QStyle::SE_HeaderLabel, &opt, view );
 
758
            if ( subopt.rect.isValid() ) {
 
759
                style->drawControl( QStyle::CE_HeaderLabel, &subopt, painter, view );
 
760
            }
 
761
        }
 
762
        if ( textWidth > 0 ) {
 
763
            textWidth += KDGANTT_LIST_CHART_GAP;
 
764
        }
 
765
    }
 
766
    QRectF oldSceneRect( sceneRect() );
 
767
    setSceneRect( itemsBoundingRect() );
 
768
    QRectF sourceRect = source.adjusted( textWidth, (qreal)0.0, (qreal)0.0, (qreal)0.0 );
 
769
    targetRect.adjust( textWidth, (qreal)0.0, (qreal)0.0, (qreal)0.0 );
 
770
    //qDebug()<<"GraphicsScene::print() 1"<<"scene"<<sceneRect()<<"target"<<targetRect<<"source"<<source<<"sourceRect"<<sourceRect<<"text"<<textWidth<<"scale"<<scale;
 
771
    if ( view ) {
 
772
        qreal width = sourceRect.width();
 
773
        qreal height = sourceRect.height();
 
774
        qreal scale = 1.0;
 
775
        if ( width > targetRect.width() ) {
 
776
            scale = targetRect.width() / width;
 
777
        }
 
778
        if ( height > targetRect.height() ) {
 
779
            scale = qMin( scale, targetRect.height() / height );
 
780
        }
 
781
        QRectF t = targetRect;
 
782
        QRectF s = sourceRect;
 
783
        s.setHeight( view->headerHeight() );
 
784
        t.setWidth( s.width() * scale );
 
785
        t.setHeight( s.height() * scale );
 
786
        view->renderHeader( painter, t, s, Qt::KeepAspectRatio );
 
787
        targetRect.translate( (qreal)0.0, t.height() );
 
788
        targetRect.setHeight( targetRect.height() - t.height() );
 
789
    }
 
790
    //qDebug()<<"GraphicsScene::print() 3"<<sceneRect()<<targetRect<<sourceRect;
 
791
 
 
792
    if ( targetRect.width() > sourceRect.width() && targetRect.height() > sourceRect.height() ) {
 
793
        // do not scale up
 
794
        sourceRect.setSize( targetRect.size() );
 
795
        render( painter, targetRect, sourceRect, Qt::IgnoreAspectRatio );
 
796
    } else {
 
797
        render( painter, targetRect, sourceRect );
 
798
    }
 
799
 
 
800
    setSceneRect( oldSceneRect );
 
801
}
 
802
 
 
803
 
 
804
#include "moc_kdganttgraphicsscene.cpp"
 
805