20 #include "etmcalendar.h"
21 #include "etmcalendar_p.h"
22 #include "blockalarmsattribute.h"
23 #include "incidencefetchjob_p.h"
24 #include "calendarmodel_p.h"
25 #include "kcolumnfilterproxymodel_p.h"
26 #include "calfilterproxymodel_p.h"
29 #include <akonadi/item.h>
30 #include <akonadi/session.h>
31 #include <akonadi/collection.h>
32 #include <akonadi/changerecorder.h>
33 #include <akonadi/itemfetchscope.h>
34 #include <akonadi/entitydisplayattribute.h>
35 #include <akonadi/entitymimetypefiltermodel.h>
36 #include <akonadi/collectionfilterproxymodel.h>
37 #include <KSelectionProxyModel>
38 #include <KDescendantsProxyModel>
40 #include <QSortFilterProxyModel>
41 #include <QItemSelectionModel>
44 using namespace Akonadi;
45 using namespace KCalCore;
49 ETMCalendarPrivate::ETMCalendarPrivate(
ETMCalendar *qq) : CalendarBasePrivate(qq)
52 , mCheckableProxyModel(0)
53 , mCollectionProxyModel(0)
54 , mCalFilterProxyModel(0)
56 , mCollectionFilteringEnabled(true)
59 mListensForNewItems =
true;
62 void ETMCalendarPrivate::init()
78 QStringList allMimeTypes;
79 allMimeTypes << KCalCore::Event::eventMimeType() << KCalCore::Todo::todoMimeType()
80 << KCalCore::Journal::journalMimeType();
82 foreach(
const QString &mimetype, allMimeTypes) {
86 mETM =
new CalendarModel(monitor, q);
87 mETM->setObjectName(
"ETM");
91 connect(q, SIGNAL(filterChanged()), SLOT(onFilterChanged()));
95 connect(mETM, SIGNAL(rowsInserted(QModelIndex,
int,
int)),
96 SLOT(onRowsInserted(QModelIndex,
int,
int)));
97 connect(mETM, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
98 SLOT(onDataChanged(QModelIndex,QModelIndex)));
99 connect(mETM, SIGNAL(rowsMoved(QModelIndex,
int,
int,QModelIndex,
int)),
100 SLOT(onRowsMoved(QModelIndex,
int,
int,QModelIndex,
int)));
101 connect(mETM, SIGNAL(rowsRemoved(QModelIndex,
int,
int)),
102 SLOT(onRowsRemoved(QModelIndex,
int,
int)));
104 connect(mFilteredETM, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
105 SLOT(onDataChangedInFilteredModel(QModelIndex,QModelIndex)));
106 connect(mFilteredETM, SIGNAL(layoutChanged()),
107 SLOT(onLayoutChangedInFilteredModel()));
108 connect(mFilteredETM, SIGNAL(modelReset()),
109 SLOT(onModelResetInFilteredModel()));
110 connect(mFilteredETM, SIGNAL(rowsInserted(QModelIndex,
int,
int)),
111 SLOT(onRowsInsertedInFilteredModel(QModelIndex,
int,
int)));
112 connect(mFilteredETM, SIGNAL(rowsAboutToBeRemoved(QModelIndex,
int,
int)),
113 SLOT(onRowsAboutToBeRemovedInFilteredModel(QModelIndex,
int,
int)));
119 const QSet<QByteArray> &attributeNames)
121 Q_ASSERT(collection.
isValid());
123 if (attributeNames.contains(
"AccessRights")) {
127 KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence(item);
134 emit q->collectionChanged(collection, attributeNames);
137 void ETMCalendarPrivate::setupFilteredETM()
141 columnFilterProxy->setSourceModel(mETM);
143 columnFilterProxy->setObjectName(
"Remove columns");
146 mCollectionProxyModel->setObjectName(
"Only show collections");
147 mCollectionProxyModel->setDynamicSortFilter(
true);
148 mCollectionProxyModel->addMimeTypeFilter(QString::fromLatin1(
"text/calendar"));
149 mCollectionProxyModel->setExcludeVirtualCollections(
true);
150 mCollectionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
151 mCollectionProxyModel->setSourceModel(columnFilterProxy);
154 QItemSelectionModel* selectionModel =
new QItemSelectionModel(mCollectionProxyModel);
155 selectionModel->setObjectName(
"Calendar Selection Model");
158 mCheckableProxyModel =
new CheckableProxyModel(
this);
159 mCheckableProxyModel->setSelectionModel(selectionModel);
160 mCheckableProxyModel->setSourceModel(mCollectionProxyModel);
161 mCheckableProxyModel->setObjectName(
"Add checkboxes");
163 mSelectionProxy =
new KSelectionProxyModel(selectionModel,
this);
164 mSelectionProxy->setObjectName(
"Only show items of selected collection");
165 mSelectionProxy->setFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection);
166 mSelectionProxy->setSourceModel(mETM);
168 mCalFilterProxyModel =
new CalFilterProxyModel(
this);
169 mCalFilterProxyModel->setFilter(q->filter());
170 mCalFilterProxyModel->setSourceModel(mSelectionProxy);
171 mCalFilterProxyModel->setObjectName(
"KCalCore::CalFilter filtering");
174 mFilteredETM->setSourceModel(mCalFilterProxyModel);
176 mFilteredETM->setSortRole(CalendarModel::SortRole);
177 mFilteredETM->setObjectName(
"Show headers");
179 #ifdef AKONADI_CALENDAR_DEBUG_MODEL
180 QTreeView *view =
new QTreeView;
181 view->setModel(mFilteredETM);
186 ETMCalendarPrivate::~ETMCalendarPrivate()
190 void ETMCalendarPrivate::loadFromETM()
192 itemsAdded(itemsFromModel(mETM));
195 void ETMCalendarPrivate::clear()
197 mCollectionMap.clear();
198 mItemsByCollection.clear();
200 itemsRemoved(mItemById.values());
202 if (!mItemById.isEmpty()) {
204 kDebug() <<
"This shouldnt happen: !mItemById.isEmpty()";
206 kDebug() <<
"Id = " << id;
213 if (!mItemIdByUid.isEmpty()) {
215 kDebug() <<
"This shouldnt happen: !mItemIdByUid.isEmpty()";
216 foreach(
const QString &uid, mItemIdByUid.keys()) {
217 kDebug() <<
"uid: " << uid;
219 mItemIdByUid.clear();
222 mParentUidToChildrenUid.clear();
227 const QModelIndex &parentIndex,
230 const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
233 QModelIndex i = model->index(row, 0, parentIndex);
234 while (row <= endRow) {
236 if (item.
hasPayload<KCalCore::Incidence::Ptr>()) {
239 const QModelIndex childIndex = i.child(0, 0);
240 if (childIndex.isValid()) {
241 items << itemsFromModel(model, i);
245 i = i.sibling(row, 0);
251 const QModelIndex &parentIndex,
254 const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
257 QModelIndex i = model->index(row, 0, parentIndex);
258 while (row <= endRow) {
261 collections << collection;
262 QModelIndex childIndex = i.child(0, 0);
263 if (childIndex.isValid()) {
264 collections << collectionsFromModel(model, i);
268 i = i.sibling(row, 0);
273 Akonadi::Item ETMCalendarPrivate::itemFromIndex(
const QModelIndex &idx)
283 if (!items.isEmpty()) {
285 internalInsert(item);
289 if (mPopulatedCollectionIds.contains(
id)) {
292 emit q->calendarChanged();
300 internalRemove(item);
302 emit q->calendarChanged();
310 void ETMCalendarPrivate::onRowsInserted(
const QModelIndex &index,
317 mCollectionMap[collection.
id()] = collection;
320 if (!collections.isEmpty())
321 emit q->collectionsAdded(collections);
326 mPopulatedCollectionIds.insert(
id);
327 emit q->calendarChanged();
330 void ETMCalendarPrivate::onRowsRemoved(
const QModelIndex &index,
int start,
int end)
334 mCollectionMap.remove(collection.
id());
337 if (!collections.isEmpty())
338 emit q->collectionsRemoved(collections);
341 void ETMCalendarPrivate::onDataChanged(
const QModelIndex &topLeft,
342 const QModelIndex &bottomRight)
345 Q_ASSERT(topLeft.row() <= bottomRight.row());
346 const int endRow = bottomRight.row();
347 QModelIndex i(topLeft);
349 while (row <= endRow) {
353 mCollectionMap.insert(col.
id(), col);
359 void ETMCalendarPrivate::onRowsMoved(
const QModelIndex &sourceParent,
362 const QModelIndex &destinationParent,
366 Q_UNUSED(sourceParent);
367 Q_UNUSED(sourceStart);
369 Q_UNUSED(destinationParent);
370 Q_UNUSED(destinationRow);
373 void ETMCalendarPrivate::onLayoutChangedInFilteredModel()
379 void ETMCalendarPrivate::onModelResetInFilteredModel()
385 void ETMCalendarPrivate::onDataChangedInFilteredModel(
const QModelIndex &topLeft,
386 const QModelIndex &bottomRight)
388 Q_ASSERT(topLeft.row() <= bottomRight.row());
389 const int endRow = bottomRight.row();
390 QModelIndex i(topLeft);
392 while (row <= endRow) {
398 i = i.sibling(row, topLeft.column());
401 emit q->calendarChanged();
404 void ETMCalendarPrivate::updateItem(
const Akonadi::Item &item)
406 Incidence::Ptr newIncidence = CalendarUtils::incidence(item);
407 Q_ASSERT(newIncidence);
408 Q_ASSERT(!newIncidence->uid().isEmpty());
409 newIncidence->setCustomProperty(
"VOLATILE",
"AKONADI-ID", QString::number(item.
id()));
410 IncidenceBase::Ptr existingIncidence = q->incidence(newIncidence->uid(), newIncidence->recurrenceId());
412 if (!existingIncidence && !mItemById.contains(item.
id())) {
420 if (existingIncidence) {
423 updatedItem.
setPayload<KCalCore::Incidence::Ptr>(existingIncidence.staticCast<KCalCore::Incidence>());
424 mItemById.insert(item.
id(), updatedItem);
427 handleParentChanged(newIncidence);
428 *(existingIncidence.data()) = *(newIncidence.data());
430 mItemById.insert(item.
id(), item);
432 handleUidChange(oldItem, item, newIncidence->instanceIdentifier());
436 void ETMCalendarPrivate::onRowsInsertedInFilteredModel(
const QModelIndex &index,
439 itemsAdded(itemsFromModel(mFilteredETM, index, start, end));
442 void ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel(
const QModelIndex &index,
445 itemsRemoved(itemsFromModel(mFilteredETM, index, start, end));
448 void ETMCalendarPrivate::onFilterChanged()
450 mCalFilterProxyModel->setFilter(q->filter());
462 d->mMimeTypes = mimeTypes;
474 return d->mCollectionMap.value(
id);
488 return col.
rights() & right;
494 return d->mFilteredETM;
500 return d->mCheckableProxyModel;
503 KCalCore::Alarm::List ETMCalendar::alarms(
const KDateTime &from,
505 bool excludeBlockedAlarms)
const
508 KCalCore::Alarm::List alarmList;
509 QHashIterator<Akonadi::Item::Id, Akonadi::Item> i(d->mItemById);
510 while (i.hasNext()) {
515 if (excludeBlockedAlarms) {
528 KCalCore::Incidence::Ptr incidence;
530 incidence = KCalCore::Incidence::Ptr(item.
payload<KCalCore::Incidence::Ptr>()->clone());
541 Q_FOREACH(
const KCalCore::Alarm::Ptr &alarm, incidence->alarms()) {
543 incidence->removeAlarm(alarm);
548 if (incidence->alarms().isEmpty()) {
553 if (incidence->recurs()) {
554 appendRecurringAlarms(tmpList, incidence, from, to);
556 appendAlarms(tmpList, incidence, from, to);
562 QVectorIterator<Alarm::Ptr> a(tmpList);
563 while (a.hasNext()) {
564 a.next()->setCustomProperty(
"ETMCalendar",
"parentUid", incidence->uid());
566 alarmList += tmpList;
580 if (d->mCollectionFilteringEnabled != enable) {
581 d->mCollectionFilteringEnabled = enable;
583 d->mSelectionProxy->setSourceModel(d->mETM);
584 QAbstractItemModel *oldModel = d->mCalFilterProxyModel->sourceModel();
585 d->mCalFilterProxyModel->setSourceModel(d->mSelectionProxy);
586 delete qobject_cast<KDescendantsProxyModel *>(oldModel);
588 KDescendantsProxyModel *flatner =
new KDescendantsProxyModel(
this);
589 flatner->setSourceModel(d->mETM);
590 d->mCalFilterProxyModel->setSourceModel(flatner);
598 return d->mCollectionFilteringEnabled;
601 #include "etmcalendar.moc"
602 #include "etmcalendar_p.moc"