KGantt

kganttsummaryhandlingproxymodel.cpp
1/*
2 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KGantt library.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "kganttsummaryhandlingproxymodel.h"
10#include "kganttsummaryhandlingproxymodel_p.h"
11
12#include <QDebug>
13
14#include <cassert>
15
16using namespace KGantt;
17
18
19
20typedef ForwardingProxyModel BASE;
21
22bool SummaryHandlingProxyModel::Private::cacheLookup( const QModelIndex& idx,
23 QPair<QDateTime,QDateTime>* result ) const
24{
25 //qDebug() << "cacheLookup("<<idx<<"), cache has " << cached_summary_items.count() << "items";
27 cached_summary_items.constFind( idx );
28 if ( it != cached_summary_items.constEnd() ) {
29 *result = *it;
30 return true;
31 } else {
32 return false;
33 }
34}
35
36void SummaryHandlingProxyModel::Private::insertInCache( const SummaryHandlingProxyModel* model,
37 const QModelIndex& sourceIdx ) const
38{
39 QAbstractItemModel* sourceModel = model->sourceModel();
40 const QModelIndex& mainIdx = sourceIdx;
41 QDateTime st;
42 QDateTime et;
43
44 for ( int r = 0; r < sourceModel->rowCount( mainIdx ); ++r ) {
45 QModelIndex pdIdx = model->mapFromSource( sourceModel->index( r, 0, mainIdx ) );
46 /* The probably results in recursive calls here */
47 QVariant tmpsv = model->data( pdIdx, StartTimeRole );
48 QVariant tmpev = model->data( pdIdx, EndTimeRole );
49 if ( !tmpsv.canConvert( QVariant::DateTime ) ||
50 !tmpev.canConvert( QVariant::DateTime ) ) {
51 qDebug() << "Skipping item " << sourceIdx << " because it doesn't contain QDateTime";
52 continue;
53 }
54
55 // check for valid datetimes
56 if ( tmpsv.type() == QVariant::DateTime && !tmpsv.value<QDateTime>().isValid()) continue;
57 if ( tmpev.type() == QVariant::DateTime && !tmpev.value<QDateTime>().isValid()) continue;
58
59 // We need to test for empty strings to
60 // avoid a stupid Qt warning
61 if ( tmpsv.type() == QVariant::String && tmpsv.value<QString>().isEmpty()) continue;
62 if ( tmpev.type() == QVariant::String && tmpev.value<QString>().isEmpty()) continue;
63 QDateTime tmpst = tmpsv.toDateTime();
64 QDateTime tmpet = tmpev.toDateTime();
65 if ( st.isNull() || st > tmpst ) st = tmpst;
66 if ( et.isNull() || et < tmpet ) et = tmpet;
67 }
68 QVariant tmpssv = sourceModel->data( mainIdx, StartTimeRole );
69 QVariant tmpsev = sourceModel->data( mainIdx, EndTimeRole );
70 if ( tmpssv.canConvert( QVariant::DateTime )
71 && !( tmpssv.canConvert( QVariant::String ) && tmpssv.toString().isEmpty() )
72 && tmpssv.toDateTime() != st )
73 sourceModel->setData( mainIdx, st, StartTimeRole );
74 if ( tmpsev.canConvert( QVariant::DateTime )
75 && !( tmpsev.canConvert( QVariant::String ) && tmpsev.toString().isEmpty() )
76 && tmpsev.toDateTime() != et )
77 sourceModel->setData( mainIdx, et, EndTimeRole );
78 cached_summary_items[sourceIdx]=qMakePair( st, et );
79}
80
81void SummaryHandlingProxyModel::Private::removeFromCache( const QModelIndex& idx ) const
82{
83 cached_summary_items.remove( idx );
84}
85
86void SummaryHandlingProxyModel::Private::clearCache() const
87{
88 cached_summary_items.clear();
89}
90
91
93 : BASE( parent ), _d( new Private )
94{
95 init();
96}
97
98#define d d_func()
99SummaryHandlingProxyModel::~SummaryHandlingProxyModel()
100{
101 delete _d;
102}
103
104void SummaryHandlingProxyModel::init()
105{
106}
107
108
110{
111 BASE::setSourceModel( model );
112 d->clearCache();
113}
114
115void SummaryHandlingProxyModel::sourceModelReset()
116{
117 d->clearCache();
118 BASE::sourceModelReset();
119}
120
121void SummaryHandlingProxyModel::sourceLayoutChanged()
122{
123 d->clearCache();
124 BASE::sourceLayoutChanged();
125}
126
127void SummaryHandlingProxyModel::sourceDataChanged( const QModelIndex& from, const QModelIndex& to )
128{
130 QModelIndex parentIdx = from;
131 do {
132 const QModelIndex& dataIdx = parentIdx;
133 if ( model->data( dataIdx, ItemTypeRole )==TypeSummary ) {
134 //qDebug() << "removing " << parentIdx << "from cache";
135 d->removeFromCache( dataIdx );
136 QModelIndex proxyDataIdx = mapFromSource( dataIdx );
137 Q_EMIT dataChanged( proxyDataIdx, proxyDataIdx );
138 }
139 } while ( ( parentIdx=model->parent( parentIdx ) ) != QModelIndex() );
140
141 BASE::sourceDataChanged( from, to );
142}
143
144void SummaryHandlingProxyModel::sourceColumnsAboutToBeInserted( const QModelIndex& parentIdx,
145 int start,
146 int end )
147{
148 BASE::sourceColumnsAboutToBeInserted( parentIdx, start, end );
149 d->clearCache();
150}
151
152void SummaryHandlingProxyModel::sourceColumnsAboutToBeRemoved( const QModelIndex& parentIdx,
153 int start,
154 int end )
155{
156 BASE::sourceColumnsAboutToBeRemoved( parentIdx, start, end );
157 d->clearCache();
158}
159
160void SummaryHandlingProxyModel::sourceRowsAboutToBeInserted( const QModelIndex & parentIdx, int start, int end )
161{
162 BASE::sourceRowsAboutToBeInserted( parentIdx, start, end );
163 d->clearCache();
164}
165
166void SummaryHandlingProxyModel::sourceRowsAboutToBeRemoved( const QModelIndex & parentIdx, int start, int end )
167{
168 BASE::sourceRowsAboutToBeRemoved( parentIdx, start, end );
169 d->clearCache();
170}
171
172
174{
175 const QModelIndex sidx = mapToSource( idx );
176 const QAbstractItemModel* model = sourceModel();
177 Qt::ItemFlags f = model->flags( sidx );
178 if ( d->isSummary(sidx) ) {
179 f &= ~Qt::ItemIsEditable;
180 }
181 return f;
182}
183
184
185QVariant SummaryHandlingProxyModel::data( const QModelIndex& proxyIndex, int role) const
186{
187 //qDebug() << "SummaryHandlingProxyModel::data("<<proxyIndex<<role<<")";
188 const QModelIndex sidx = mapToSource( proxyIndex );
189 const QAbstractItemModel* model = sourceModel();
190 if ( d->isSummary(sidx) && ( role==StartTimeRole || role==EndTimeRole )) {
191 //qDebug() << "requested summary";
192 QPair<QDateTime,QDateTime> result;
193 if ( d->cacheLookup( sidx, &result ) ) {
194 //qDebug() << "SummaryHandlingProxyModel::data(): Looking up summary for " << proxyIndex << role;
195 switch ( role ) {
196 case StartTimeRole: return result.first;
197 case EndTimeRole: return result.second;
198 default: /* fall thru */;
199 }
200 } else {
201 d->insertInCache( this, sidx );
202 return data( proxyIndex, role ); /* TODO: Optimize */
203 }
204 }
205 return model->data( sidx, role );
206}
207
208
209bool SummaryHandlingProxyModel::setData( const QModelIndex& index, const QVariant& value, int role )
210{
212 if ( role==StartTimeRole || role==EndTimeRole ) {
213 QModelIndex parentIdx = mapToSource( index );
214 do {
215 if ( d->isSummary(parentIdx) ) {
216 //qDebug() << "removing " << parentIdx << "from cache";
217 d->removeFromCache( parentIdx );
218 QModelIndex proxyParentIdx = mapFromSource( parentIdx );
219 Q_EMIT dataChanged( proxyParentIdx, proxyParentIdx );
220 }
221 } while ( ( parentIdx=model->parent( parentIdx ) ) != QModelIndex() );
222 }
223 return BASE::setData( index, value, role );
224}
225
226#undef d
227
228#ifndef KDAB_NO_UNIT_TESTS
229
230#include "unittest/test.h"
231
232#include <QStandardItemModel>
233
234static std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
235{
236#ifdef QT_NO_STL
237 os << dt.toString().toLatin1().constData();
238#else
239 os << dt.toString().toStdString();
240#endif
241 return os;
242}
243
244KDAB_SCOPED_UNITTEST_SIMPLE( KGantt, SummaryHandlingProxyModel, "test" ) {
246 QStandardItemModel sourceModel;
247
248 model.setSourceModel( &sourceModel );
249
250 QStandardItem* topitem = new QStandardItem( QString::fromLatin1( "Summary" ) );
251 topitem->setData( KGantt::TypeSummary, KGantt::ItemTypeRole );
252 sourceModel.appendRow( topitem );
253
254 QStandardItem* task1 = new QStandardItem( QString::fromLatin1( "Task1" ) );
255 task1->setData( KGantt::TypeTask, KGantt::ItemTypeRole );
256 QStandardItem* task2 = new QStandardItem( QString::fromLatin1( "Task2" ) );
257 task2->setData( KGantt::TypeTask, KGantt::ItemTypeRole );
258 topitem->appendRow( task1 );
259 topitem->appendRow( task2 );
260
261
263 QDateTime enddt = startdt.addDays( 1 );
264
265
266 task1->setData( startdt, KGantt::StartTimeRole );
267 task1->setData( enddt, KGantt::EndTimeRole );
268 task2->setData( startdt, KGantt::StartTimeRole );
269 task2->setData( enddt, KGantt::EndTimeRole );
270
271 const QModelIndex topidx = model.index( 0, 0, QModelIndex() );
272
273 assertEqual( model.data( topidx, KGantt::ItemTypeRole ).toInt(), KGantt::TypeSummary );
274 assertEqual( model.data( model.index( 0, 0, topidx ), KGantt::ItemTypeRole ).toInt(), KGantt::TypeTask );
275
276 QDateTime task1startdt = model.data( model.index( 0, 0, topidx ), KGantt::StartTimeRole ).toDateTime();
277 assertEqual( task1startdt, startdt );
278
279 QDateTime summarystartdt = model.data( topidx, KGantt::StartTimeRole ).toDateTime();
280 assertEqual( summarystartdt, startdt );
281 assertTrue( model.flags( model.index( 0, 0, topidx ) ) & Qt::ItemIsEditable );
282 assertFalse( model.flags( topidx ) & Qt::ItemIsEditable );
283}
284
285#endif /* KDAB_NO_UNIT_TESTS */
286
287#include "moc_kganttsummaryhandlingproxymodel.cpp"
Proxy model that supports summary gantt items.
Qt::ItemFlags flags(const QModelIndex &idx) const override
void setSourceModel(QAbstractItemModel *model) override
QVariant data(const QModelIndex &proxyIndex, int role=Qt::DisplayRole) const override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Q_SCRIPTABLE Q_NOREPLY void start()
Global namespace.
@ ItemTypeRole
The item type.
@ StartTimeRole
Start time (or other start value) for a gantt item.
@ EndTimeRole
End time (or other end value) for a gantt item.
virtual QVariant data(const QModelIndex &index, int role) const const=0
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
virtual Qt::ItemFlags flags(const QModelIndex &index) const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual QModelIndex parent(const QModelIndex &index) const const=0
virtual int rowCount(const QModelIndex &parent) const const=0
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override
virtual void setSourceModel(QAbstractItemModel *sourceModel)
const char * constData() const const
QDateTime addDays(qint64 ndays) const const
QDateTime currentDateTime()
bool isNull() const const
bool isValid() const const
QString toString(QStringView format, QCalendar cal) const const
const_iterator constFind(const Key &key) const const
Q_EMITQ_EMIT
void appendRow(QStandardItem *item)
virtual void setData(const QVariant &value, int role)
void appendRow(QStandardItem *item)
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QByteArray toLatin1() const const
std::string toStdString() const const
typedef ItemFlags
Type type() const const
bool canConvert() const const
QDateTime toDateTime() const const
int toInt(bool *ok) const const
QString toString() const const
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Sep 27 2024 11:49:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.