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

« back to all changes in this revision

Viewing changes to kdgantt/kdganttsummaryhandlingproxymodel.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 "kdganttsummaryhandlingproxymodel.h"
24
 
#include "kdganttsummaryhandlingproxymodel_p.h"
25
 
 
26
 
#include <QDebug>
27
 
 
28
 
#include <cassert>
29
 
 
30
 
using namespace KDGantt;
31
 
 
32
 
/*!\class KDGantt::SummaryHandlingProxyModel
33
 
 * \brief Proxy model that supports summary gantt items.
34
 
 *
35
 
 * This proxy model provides the functionality of summary items.
36
 
 * A summary item is an item with type KDGantt::TypeSummary and
37
 
 * zero or more children in the model that it summarizes.
38
 
 * GraphicsView itself does not dictate any policy for summary items,
39
 
 * instead the logic for making the summary items start and end points
40
 
 * span it's children is provided by this proxy.
41
 
 *
42
 
 * The start and end times of a summary is the min/max of the
43
 
 * start/end times of it's children.
44
 
 *
45
 
 * \see GraphicsView::setModel
46
 
 */
47
 
 
48
 
typedef ForwardingProxyModel BASE;
49
 
 
50
 
bool SummaryHandlingProxyModel::Private::cacheLookup( const QModelIndex& idx,
51
 
                                                      QPair<QDateTime,QDateTime>* result ) const
52
 
{
53
 
    //qDebug() << "cacheLookup("<<idx<<"), cache has " << cached_summary_items.count() << "items";
54
 
    QHash<QModelIndex,QPair<QDateTime,QDateTime> >::const_iterator it =
55
 
        cached_summary_items.constFind( idx );
56
 
    if ( it != cached_summary_items.constEnd() ) {
57
 
        *result = *it;
58
 
        return true;
59
 
    } else {
60
 
        return false;
61
 
    }
62
 
}
63
 
 
64
 
void SummaryHandlingProxyModel::Private::insertInCache( const SummaryHandlingProxyModel* model,
65
 
                                                        const QModelIndex& sourceIdx ) const
66
 
{
67
 
    QAbstractItemModel* sourceModel = model->sourceModel();
68
 
    const QModelIndex& mainIdx = sourceIdx;
69
 
    QDateTime st;
70
 
    QDateTime et;
71
 
 
72
 
    for ( int r = 0; r < sourceModel->rowCount( mainIdx ); ++r ) {
73
 
        QModelIndex pdIdx = model->mapFromSource( sourceModel->index( r, 0, mainIdx ) );
74
 
        /* The probably results in recursive calls here */
75
 
        QVariant tmpsv = model->data( pdIdx, StartTimeRole );
76
 
        QVariant tmpev = model->data( pdIdx, EndTimeRole );
77
 
        if( !qVariantCanConvert<QDateTime>(tmpsv) ||
78
 
            !qVariantCanConvert<QDateTime>(tmpev) ) {
79
 
            qDebug() << "Skipping item " << sourceIdx << " because it doesn't contain QDateTime";
80
 
            continue;
81
 
        }
82
 
 
83
 
    // check for valid datetimes
84
 
    if( tmpsv.type() == QVariant::DateTime && !qVariantValue<QDateTime>(tmpsv).isValid()) continue;
85
 
    if( tmpev.type() == QVariant::DateTime && !qVariantValue<QDateTime>(tmpev).isValid()) continue;
86
 
 
87
 
        // We need to test for empty strings to
88
 
        // avoid a stupid Qt warning
89
 
        if( tmpsv.type() == QVariant::String && qVariantValue<QString>(tmpsv).isEmpty()) continue;
90
 
        if( tmpev.type() == QVariant::String && qVariantValue<QString>(tmpev).isEmpty()) continue;
91
 
        QDateTime tmpst = tmpsv.toDateTime();
92
 
        QDateTime tmpet = tmpev.toDateTime();
93
 
        if ( st.isNull() || st > tmpst ) st = tmpst;
94
 
        if ( et.isNull() || et < tmpet ) et = tmpet;
95
 
    }
96
 
    QVariant tmpssv = sourceModel->data( mainIdx, StartTimeRole );
97
 
    QVariant tmpsev = sourceModel->data( mainIdx, EndTimeRole );
98
 
    if ( qVariantCanConvert<QDateTime>( tmpssv )
99
 
         && !( qVariantCanConvert<QString>( tmpssv ) && qVariantValue<QString>( tmpssv ).isEmpty() )
100
 
         && qVariantValue<QDateTime>( tmpssv ) != st )
101
 
        sourceModel->setData( mainIdx, st, StartTimeRole );
102
 
    if ( qVariantCanConvert<QDateTime>( tmpsev )
103
 
         && !( qVariantCanConvert<QString>( tmpsev ) && qVariantValue<QString>( tmpsev ).isEmpty() )
104
 
         && qVariantValue<QDateTime>( tmpsev ) != et )
105
 
        sourceModel->setData( mainIdx, et, EndTimeRole );
106
 
    cached_summary_items[sourceIdx]=qMakePair( st, et );
107
 
}
108
 
 
109
 
void SummaryHandlingProxyModel::Private::removeFromCache( const QModelIndex& idx ) const
110
 
{
111
 
    cached_summary_items.remove( idx );
112
 
}
113
 
 
114
 
void SummaryHandlingProxyModel::Private::clearCache() const
115
 
{
116
 
    cached_summary_items.clear();
117
 
}
118
 
 
119
 
/*! Constructor. Creates a new SummaryHandlingProxyModel with
120
 
 * parent \a parent
121
 
 */
122
 
SummaryHandlingProxyModel::SummaryHandlingProxyModel( QObject* parent )
123
 
    : BASE( parent ), _d( new Private )
124
 
{
125
 
    init();
126
 
}
127
 
 
128
 
#define d d_func()
129
 
SummaryHandlingProxyModel::~SummaryHandlingProxyModel()
130
 
{
131
 
    delete d;
132
 
}
133
 
 
134
 
void SummaryHandlingProxyModel::init()
135
 
{
136
 
}
137
 
 
138
 
namespace {
139
 
 
140
 
    // Think this is ugly? Well, it's not from me, it comes from QProxyModel
141
 
    struct KDPrivateModelIndex {
142
 
        int r, c;
143
 
        void *p;
144
 
        const QAbstractItemModel *m;
145
 
    };
146
 
}
147
 
 
148
 
/*! Sets the model to be used as the source model for this proxy.
149
 
 * The proxy does not take ownership of the model.
150
 
 * \see QAbstractProxyModel::setSourceModel
151
 
 */
152
 
void SummaryHandlingProxyModel::setSourceModel( QAbstractItemModel* model )
153
 
{
154
 
    BASE::setSourceModel( model );
155
 
    d->clearCache();
156
 
}
157
 
 
158
 
void SummaryHandlingProxyModel::sourceModelReset()
159
 
{
160
 
    d->clearCache();
161
 
    BASE::sourceModelReset();
162
 
}
163
 
 
164
 
void SummaryHandlingProxyModel::sourceLayoutChanged()
165
 
{
166
 
    d->clearCache();
167
 
    BASE::sourceLayoutChanged();
168
 
}
169
 
 
170
 
void SummaryHandlingProxyModel::sourceDataChanged( const QModelIndex& from, const QModelIndex& to )
171
 
{
172
 
    QAbstractItemModel* model = sourceModel();
173
 
    QModelIndex parentIdx = from;
174
 
    do {
175
 
        const QModelIndex& dataIdx = parentIdx;
176
 
        if ( model->data( dataIdx, ItemTypeRole )==TypeSummary ) {
177
 
            //qDebug() << "removing " << parentIdx << "from cache";
178
 
            d->removeFromCache( dataIdx );
179
 
            QModelIndex proxyDataIdx = mapFromSource( dataIdx );
180
 
            emit dataChanged( proxyDataIdx, proxyDataIdx );
181
 
        }
182
 
    } while ( ( parentIdx=model->parent( parentIdx ) ) != QModelIndex() );
183
 
 
184
 
    BASE::sourceDataChanged( from, to );
185
 
}
186
 
 
187
 
void SummaryHandlingProxyModel::sourceColumnsAboutToBeInserted( const QModelIndex& parentIdx,
188
 
                                                                    int start,
189
 
                                                                    int end )
190
 
{
191
 
    BASE::sourceColumnsAboutToBeInserted( parentIdx, start, end );
192
 
    d->clearCache();
193
 
}
194
 
 
195
 
void SummaryHandlingProxyModel::sourceColumnsAboutToBeRemoved( const QModelIndex& parentIdx,
196
 
                                                                    int start,
197
 
                                                                    int end )
198
 
{
199
 
    BASE::sourceColumnsAboutToBeRemoved( parentIdx, start, end );
200
 
    d->clearCache();
201
 
}
202
 
 
203
 
void SummaryHandlingProxyModel::sourceRowsAboutToBeInserted( const QModelIndex & parentIdx, int start, int end )
204
 
{
205
 
    BASE::sourceRowsAboutToBeInserted( parentIdx, start, end );
206
 
    d->clearCache();
207
 
}
208
 
 
209
 
void SummaryHandlingProxyModel::sourceRowsAboutToBeRemoved( const QModelIndex & parentIdx, int start, int end )
210
 
{
211
 
    BASE::sourceRowsAboutToBeRemoved( parentIdx, start, end );
212
 
    d->clearCache();
213
 
}
214
 
 
215
 
/*! \see QAbstractItemModel::flags */
216
 
Qt::ItemFlags SummaryHandlingProxyModel::flags( const QModelIndex& idx ) const
217
 
{
218
 
    const QModelIndex sidx = mapToSource( idx );
219
 
    const QAbstractItemModel* model = sourceModel();
220
 
    Qt::ItemFlags f = model->flags( sidx );
221
 
    if ( d->isSummary(sidx) ) {
222
 
        f &= !Qt::ItemIsEditable;
223
 
    }
224
 
    return f;
225
 
}
226
 
 
227
 
/*! \see QAbstractItemModel::data */
228
 
QVariant SummaryHandlingProxyModel::data( const QModelIndex& proxyIndex, int role) const
229
 
{
230
 
    //qDebug() << "SummaryHandlingProxyModel::data("<<proxyIndex<<role<<")";
231
 
    const QModelIndex sidx = mapToSource( proxyIndex );
232
 
    const QAbstractItemModel* model = sourceModel();
233
 
    if ( d->isSummary(sidx) && ( role==StartTimeRole || role==EndTimeRole )) {
234
 
      //qDebug() << "requested summary";
235
 
        QPair<QDateTime,QDateTime> result;
236
 
        if ( d->cacheLookup( sidx, &result ) ) {
237
 
          //qDebug() << "SummaryHandlingProxyModel::data(): Looking up summary for " << proxyIndex << role;
238
 
            switch( role ) {
239
 
            case StartTimeRole: return result.first;
240
 
            case EndTimeRole: return result.second;
241
 
            default: /* fall thru */;
242
 
            }
243
 
        } else {
244
 
            d->insertInCache( this, sidx );
245
 
            return data( proxyIndex, role ); /* TODO: Optimise */
246
 
        }
247
 
    }
248
 
    return model->data( sidx, role );
249
 
}
250
 
 
251
 
/*! \see QAbstractItemModel::setData */
252
 
bool SummaryHandlingProxyModel::setData( const QModelIndex& index, const QVariant& value, int role )
253
 
{
254
 
    QAbstractItemModel* model = sourceModel();
255
 
    if ( role==StartTimeRole || role==EndTimeRole ) {
256
 
        QModelIndex parentIdx = mapToSource( index );
257
 
        do {
258
 
            if ( d->isSummary(parentIdx) ) {
259
 
              //qDebug() << "removing " << parentIdx << "from cache";
260
 
                d->removeFromCache( parentIdx );
261
 
                QModelIndex proxyParentIdx = mapFromSource( parentIdx );
262
 
                emit dataChanged( proxyParentIdx, proxyParentIdx );
263
 
            }
264
 
        } while ( ( parentIdx=model->parent( parentIdx ) ) != QModelIndex() );
265
 
    }
266
 
    return BASE::setData( index, value, role );
267
 
}
268
 
 
269
 
#undef d
270
 
 
271
 
#ifndef KDAB_NO_UNIT_TESTS
272
 
 
273
 
#include "unittest/test.h"
274
 
 
275
 
#include <QStandardItemModel>
276
 
 
277
 
namespace {
278
 
    std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
279
 
    {
280
 
        os << dt.toString().toStdString();
281
 
        return os;
282
 
    }
283
 
}
284
 
 
285
 
KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, SummaryHandlingProxyModel, "test" ) {
286
 
    SummaryHandlingProxyModel model;
287
 
    QStandardItemModel sourceModel;
288
 
 
289
 
    model.setSourceModel( &sourceModel );
290
 
 
291
 
    QStandardItem* topitem = new QStandardItem( QString::fromLatin1( "Summary" ) );
292
 
    topitem->setData( KDGantt::TypeSummary,  KDGantt::ItemTypeRole );
293
 
    sourceModel.appendRow( topitem );
294
 
 
295
 
    QStandardItem* task1 = new QStandardItem( QString::fromLatin1( "Task1" ) );
296
 
    task1->setData( KDGantt::TypeTask, KDGantt::ItemTypeRole );
297
 
    QStandardItem* task2 = new QStandardItem( QString::fromLatin1( "Task2" ) );
298
 
    task2->setData( KDGantt::TypeTask, KDGantt::ItemTypeRole );
299
 
    topitem->appendRow( task1 );
300
 
    topitem->appendRow( task2 );
301
 
 
302
 
 
303
 
    QDateTime startdt = QDateTime::currentDateTime();
304
 
    QDateTime enddt = startdt.addDays( 1 );
305
 
 
306
 
 
307
 
    task1->setData( startdt, KDGantt::StartTimeRole );
308
 
    task1->setData( enddt, KDGantt::EndTimeRole );
309
 
    task2->setData( startdt, KDGantt::StartTimeRole );
310
 
    task2->setData( enddt, KDGantt::EndTimeRole );
311
 
 
312
 
    const QModelIndex topidx = model.index( 0, 0, QModelIndex() );
313
 
 
314
 
    assertEqual( model.data( topidx, KDGantt::ItemTypeRole ).toInt(), KDGantt::TypeSummary );
315
 
    assertEqual( model.data( model.index( 0, 0, topidx ), KDGantt::ItemTypeRole ).toInt(), KDGantt::TypeTask );
316
 
 
317
 
    QDateTime task1startdt = model.data( model.index( 0, 0, topidx ), KDGantt::StartTimeRole ).toDateTime();
318
 
    assertEqual( task1startdt, startdt );
319
 
 
320
 
    QDateTime summarystartdt = model.data( topidx, KDGantt::StartTimeRole ).toDateTime();
321
 
    assertEqual( summarystartdt, startdt );
322
 
    assertTrue( model.flags( model.index( 0, 0, topidx ) ) & Qt::ItemIsEditable );
323
 
    assertFalse( model.flags( topidx ) & Qt::ItemIsEditable );
324
 
}
325
 
 
326
 
#endif /* KDAB_NO_UNIT_TESTS */
327
 
 
328
 
#include "moc_kdganttsummaryhandlingproxymodel.cpp"