mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 10:52:52 +00:00
631 lines
21 KiB
C++
631 lines
21 KiB
C++
/*
|
|
Copyright (C) 2011-2013 Sérgio Martins <iamsergio@gmail.com>
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to the
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301, USA.
|
|
*/
|
|
|
|
#include "etmcalendar.h"
|
|
#include "etmcalendar_p.h"
|
|
#include "blockalarmsattribute.h"
|
|
#include "calendarmodel_p.h"
|
|
#include "kcolumnfilterproxymodel_p.h"
|
|
#include "calfilterproxymodel_p.h"
|
|
#include "utils_p.h"
|
|
|
|
#include <akonadi/item.h>
|
|
#include <akonadi/session.h>
|
|
#include <akonadi/collection.h>
|
|
#include <akonadi/changerecorder.h>
|
|
#include <akonadi/itemfetchscope.h>
|
|
#include <akonadi/entitydisplayattribute.h>
|
|
#include <akonadi/entitymimetypefiltermodel.h>
|
|
#include <akonadi/collectionfilterproxymodel.h>
|
|
#include <KSelectionProxyModel>
|
|
#include <KDescendantsProxyModel>
|
|
|
|
#include <QItemSelectionModel>
|
|
#include <QTreeView>
|
|
|
|
using namespace Akonadi;
|
|
using namespace KCalCore;
|
|
|
|
//TODO: implement batchAdding
|
|
|
|
ETMCalendarPrivate::ETMCalendarPrivate(ETMCalendar *qq) : CalendarBasePrivate(qq)
|
|
, mETM(0)
|
|
, mFilteredETM(0)
|
|
, mCheckableProxyModel(0)
|
|
, mCollectionProxyModel(0)
|
|
, mCalFilterProxyModel(0)
|
|
, mSelectionProxy(0)
|
|
, mCollectionFilteringEnabled(true)
|
|
, q(qq)
|
|
{
|
|
mListensForNewItems = true;
|
|
}
|
|
|
|
void ETMCalendarPrivate::init()
|
|
{
|
|
if (!mETM) {
|
|
Akonadi::Session *session = new Akonadi::Session("ETMCalendar", q);
|
|
Akonadi::ChangeRecorder *monitor = new Akonadi::ChangeRecorder(q);
|
|
connect(monitor, SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)),
|
|
SLOT(onCollectionChanged(Akonadi::Collection,QSet<QByteArray>)));
|
|
|
|
Akonadi::ItemFetchScope scope;
|
|
scope.fetchFullPayload(true);
|
|
scope.fetchAttribute<Akonadi::EntityDisplayAttribute>();
|
|
|
|
monitor->setSession(session);
|
|
monitor->setCollectionMonitored(Akonadi::Collection::root());
|
|
monitor->fetchCollection(true);
|
|
monitor->setItemFetchScope(scope);
|
|
|
|
QStringList allMimeTypes;
|
|
allMimeTypes << KCalCore::Event::eventMimeType() << KCalCore::Todo::todoMimeType()
|
|
<< KCalCore::Journal::journalMimeType();
|
|
|
|
foreach(const QString &mimetype, allMimeTypes) {
|
|
monitor->setMimeTypeMonitored(mimetype, mMimeTypes.isEmpty() || mMimeTypes.contains(mimetype));
|
|
}
|
|
|
|
mETM = CalendarModel::create(monitor);
|
|
mETM->setObjectName("ETM");
|
|
}
|
|
|
|
setupFilteredETM();
|
|
|
|
connect(q, SIGNAL(filterChanged()), SLOT(onFilterChanged()));
|
|
|
|
connect(mETM.data(), SIGNAL(collectionPopulated(Akonadi::Collection::Id)),
|
|
SLOT(onCollectionPopulated(Akonadi::Collection::Id)));
|
|
connect(mETM.data(), SIGNAL(rowsInserted(QModelIndex,int,int)),
|
|
SLOT(onRowsInserted(QModelIndex,int,int)));
|
|
connect(mETM.data(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
|
|
SLOT(onDataChanged(QModelIndex,QModelIndex)));
|
|
connect(mETM.data(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
|
|
SLOT(onRowsMoved(QModelIndex,int,int,QModelIndex,int)));
|
|
connect(mETM.data(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
|
SLOT(onRowsRemoved(QModelIndex,int,int)));
|
|
|
|
connect(mFilteredETM, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
|
|
SLOT(onDataChangedInFilteredModel(QModelIndex,QModelIndex)));
|
|
connect(mFilteredETM, SIGNAL(layoutChanged()),
|
|
SLOT(onLayoutChangedInFilteredModel()));
|
|
connect(mFilteredETM, SIGNAL(modelReset()),
|
|
SLOT(onModelResetInFilteredModel()));
|
|
connect(mFilteredETM, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
|
SLOT(onRowsInsertedInFilteredModel(QModelIndex,int,int)));
|
|
connect(mFilteredETM, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
|
SLOT(onRowsAboutToBeRemovedInFilteredModel(QModelIndex,int,int)));
|
|
|
|
loadFromETM();
|
|
}
|
|
|
|
void ETMCalendarPrivate::onCollectionChanged(const Akonadi::Collection &collection,
|
|
const QSet<QByteArray> &attributeNames)
|
|
{
|
|
Q_ASSERT(collection.isValid());
|
|
// Is the collection changed to read-only, we update all Incidences
|
|
if (attributeNames.contains("AccessRights")) {
|
|
Akonadi::Item::List items = q->items();
|
|
foreach(const Akonadi::Item &item, items) {
|
|
if (item.storageCollectionId() == collection.id()) {
|
|
KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence(item);
|
|
if (incidence)
|
|
incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem));
|
|
}
|
|
}
|
|
}
|
|
|
|
emit q->collectionChanged(collection, attributeNames);
|
|
}
|
|
|
|
void ETMCalendarPrivate::setupFilteredETM()
|
|
{
|
|
// We're only interested in the CollectionTitle column
|
|
KColumnFilterProxyModel *columnFilterProxy = new KColumnFilterProxyModel(this);
|
|
columnFilterProxy->setSourceModel(mETM.data());
|
|
columnFilterProxy->setVisibleColumn(CalendarModel::CollectionTitle);
|
|
columnFilterProxy->setObjectName("Remove columns");
|
|
|
|
mCollectionProxyModel = new Akonadi::CollectionFilterProxyModel(this);
|
|
mCollectionProxyModel->setObjectName("Only show collections");
|
|
mCollectionProxyModel->setDynamicSortFilter(true);
|
|
mCollectionProxyModel->addMimeTypeFilter(QString::fromLatin1("text/calendar"));
|
|
mCollectionProxyModel->setExcludeVirtualCollections(true);
|
|
mCollectionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
|
mCollectionProxyModel->setSourceModel(columnFilterProxy);
|
|
|
|
// Keep track of selected items.
|
|
QItemSelectionModel* selectionModel = new QItemSelectionModel(mCollectionProxyModel);
|
|
selectionModel->setObjectName("Calendar Selection Model");
|
|
|
|
// Make item selection work by means of checkboxes.
|
|
mCheckableProxyModel = new CheckableProxyModel(this);
|
|
mCheckableProxyModel->setSelectionModel(selectionModel);
|
|
mCheckableProxyModel->setSourceModel(mCollectionProxyModel);
|
|
mCheckableProxyModel->setObjectName("Add checkboxes");
|
|
|
|
mSelectionProxy = new KSelectionProxyModel(selectionModel, /**parent=*/this);
|
|
mSelectionProxy->setObjectName("Only show items of selected collection");
|
|
mSelectionProxy->setFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection);
|
|
mSelectionProxy->setSourceModel(mETM.data());
|
|
|
|
mCalFilterProxyModel = new CalFilterProxyModel(this);
|
|
mCalFilterProxyModel->setFilter(q->filter());
|
|
mCalFilterProxyModel->setSourceModel(mSelectionProxy);
|
|
mCalFilterProxyModel->setObjectName("KCalCore::CalFilter filtering");
|
|
|
|
mFilteredETM = new Akonadi::EntityMimeTypeFilterModel(this);
|
|
mFilteredETM->setSourceModel(mCalFilterProxyModel);
|
|
mFilteredETM->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
|
|
mFilteredETM->setSortRole(CalendarModel::SortRole);
|
|
mFilteredETM->setObjectName("Show headers");
|
|
|
|
#ifdef AKONADI_CALENDAR_DEBUG_MODEL
|
|
QTreeView *view = new QTreeView;
|
|
view->setModel(mFilteredETM);
|
|
view->show();
|
|
#endif
|
|
}
|
|
|
|
ETMCalendarPrivate::~ETMCalendarPrivate()
|
|
{
|
|
}
|
|
|
|
void ETMCalendarPrivate::loadFromETM()
|
|
{
|
|
itemsAdded(itemsFromModel(mFilteredETM));
|
|
}
|
|
|
|
void ETMCalendarPrivate::clear()
|
|
{
|
|
mCollectionMap.clear();
|
|
mItemsByCollection.clear();
|
|
|
|
itemsRemoved(mItemById.values());
|
|
|
|
if (!mItemById.isEmpty()) {
|
|
// This never happens
|
|
kDebug() << "This shouldnt happen: !mItemById.isEmpty()";
|
|
foreach(Akonadi::Item::Id id, mItemById.keys()) {
|
|
kDebug() << "Id = " << id;
|
|
}
|
|
|
|
mItemById.clear();
|
|
//Q_ASSERT(false); // TODO: discover why this happens
|
|
}
|
|
|
|
if (!mItemIdByUid.isEmpty()) {
|
|
// This never happens
|
|
kDebug() << "This shouldnt happen: !mItemIdByUid.isEmpty()";
|
|
foreach(const QString &uid, mItemIdByUid.keys()) {
|
|
kDebug() << "uid: " << uid;
|
|
}
|
|
mItemIdByUid.clear();
|
|
//Q_ASSERT(false);
|
|
}
|
|
mParentUidToChildrenUid.clear();
|
|
//m_virtualItems.clear();
|
|
}
|
|
|
|
Akonadi::Item::List ETMCalendarPrivate::itemsFromModel(const QAbstractItemModel *model,
|
|
const QModelIndex &parentIndex,
|
|
int start, int end)
|
|
{
|
|
const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
|
|
Akonadi::Item::List items;
|
|
int row = start;
|
|
QModelIndex i = model->index(row, 0, parentIndex);
|
|
while (row <= endRow) {
|
|
const Akonadi::Item item = itemFromIndex(i);
|
|
if (item.hasPayload<KCalCore::Incidence::Ptr>()) {
|
|
items << item;
|
|
} else {
|
|
const QModelIndex childIndex = i.child(0, 0);
|
|
if (childIndex.isValid()) {
|
|
items << itemsFromModel(model, i);
|
|
}
|
|
}
|
|
++row;
|
|
i = i.sibling(row, 0);
|
|
}
|
|
return items;
|
|
}
|
|
|
|
Akonadi::Collection::List ETMCalendarPrivate::collectionsFromModel(const QAbstractItemModel *model,
|
|
const QModelIndex &parentIndex,
|
|
int start, int end)
|
|
{
|
|
const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
|
|
Akonadi::Collection::List collections;
|
|
int row = start;
|
|
QModelIndex i = model->index(row, 0, parentIndex);
|
|
while (row <= endRow) {
|
|
const Akonadi::Collection collection = collectionFromIndex(i);
|
|
if (collection.isValid()) {
|
|
collections << collection;
|
|
QModelIndex childIndex = i.child(0, 0);
|
|
if (childIndex.isValid()) {
|
|
collections << collectionsFromModel(model, i);
|
|
}
|
|
}
|
|
++row;
|
|
i = i.sibling(row, 0);
|
|
}
|
|
return collections;
|
|
}
|
|
|
|
Akonadi::Item ETMCalendarPrivate::itemFromIndex(const QModelIndex &idx)
|
|
{
|
|
Akonadi::Item item = idx.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
|
|
item.setParentCollection(
|
|
idx.data(Akonadi::EntityTreeModel::ParentCollectionRole).value<Akonadi::Collection>());
|
|
return item;
|
|
}
|
|
|
|
void ETMCalendarPrivate::itemsAdded(const Akonadi::Item::List &items)
|
|
{
|
|
if (!items.isEmpty()) {
|
|
foreach(const Akonadi::Item &item, items) {
|
|
internalInsert(item);
|
|
}
|
|
|
|
Akonadi::Collection::Id id = items.first().storageCollectionId();
|
|
if (mPopulatedCollectionIds.contains(id)) {
|
|
// If the collection isn't populated yet, it will be sent later
|
|
// Saves some cpu cycles
|
|
emit q->calendarChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ETMCalendarPrivate::itemsRemoved(const Akonadi::Item::List &items)
|
|
{
|
|
foreach(const Akonadi::Item &item, items) {
|
|
internalRemove(item);
|
|
}
|
|
emit q->calendarChanged();
|
|
}
|
|
|
|
Akonadi::Collection ETMCalendarPrivate::collectionFromIndex(const QModelIndex &index)
|
|
{
|
|
return index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
|
|
}
|
|
|
|
void ETMCalendarPrivate::onRowsInserted(const QModelIndex &index,
|
|
int start, int end)
|
|
{
|
|
Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index,
|
|
start, end);
|
|
|
|
foreach(const Akonadi::Collection &collection, collections) {
|
|
mCollectionMap[collection.id()] = collection;
|
|
}
|
|
|
|
if (!collections.isEmpty())
|
|
emit q->collectionsAdded(collections);
|
|
}
|
|
|
|
void ETMCalendarPrivate::onCollectionPopulated(Akonadi::Collection::Id id)
|
|
{
|
|
mPopulatedCollectionIds.insert(id);
|
|
emit q->calendarChanged();
|
|
}
|
|
|
|
void ETMCalendarPrivate::onRowsRemoved(const QModelIndex &index, int start, int end)
|
|
{
|
|
Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index, start, end);
|
|
foreach(const Akonadi::Collection &collection, collections) {
|
|
mCollectionMap.remove(collection.id());
|
|
}
|
|
|
|
if (!collections.isEmpty())
|
|
emit q->collectionsRemoved(collections);
|
|
}
|
|
|
|
void ETMCalendarPrivate::onDataChanged(const QModelIndex &topLeft,
|
|
const QModelIndex &bottomRight)
|
|
{
|
|
// We only update collections, because items are handled in the filtered model
|
|
Q_ASSERT(topLeft.row() <= bottomRight.row());
|
|
const int endRow = bottomRight.row();
|
|
QModelIndex i(topLeft);
|
|
int row = i.row();
|
|
while (row <= endRow) {
|
|
const Akonadi::Collection col = collectionFromIndex(i);
|
|
if (col.isValid()) {
|
|
// Attributes might have changed, store the new collection and discard the old one
|
|
mCollectionMap.insert(col.id(), col);
|
|
}
|
|
++row;
|
|
}
|
|
}
|
|
|
|
void ETMCalendarPrivate::onRowsMoved(const QModelIndex &sourceParent,
|
|
int sourceStart,
|
|
int sourceEnd,
|
|
const QModelIndex &destinationParent,
|
|
int destinationRow)
|
|
{
|
|
//TODO
|
|
Q_UNUSED(sourceParent);
|
|
Q_UNUSED(sourceStart);
|
|
Q_UNUSED(sourceEnd);
|
|
Q_UNUSED(destinationParent);
|
|
Q_UNUSED(destinationRow);
|
|
}
|
|
|
|
void ETMCalendarPrivate::onLayoutChangedInFilteredModel()
|
|
{
|
|
clear();
|
|
loadFromETM();
|
|
}
|
|
|
|
void ETMCalendarPrivate::onModelResetInFilteredModel()
|
|
{
|
|
clear();
|
|
loadFromETM();
|
|
}
|
|
|
|
void ETMCalendarPrivate::onDataChangedInFilteredModel(const QModelIndex &topLeft,
|
|
const QModelIndex &bottomRight)
|
|
{
|
|
Q_ASSERT(topLeft.row() <= bottomRight.row());
|
|
const int endRow = bottomRight.row();
|
|
QModelIndex i(topLeft);
|
|
int row = i.row();
|
|
while (row <= endRow) {
|
|
const Akonadi::Item item = itemFromIndex(i);
|
|
if (item.isValid() && item.hasPayload<KCalCore::Incidence::Ptr>())
|
|
updateItem(item);
|
|
|
|
++row;
|
|
i = i.sibling(row, topLeft.column());
|
|
}
|
|
|
|
emit q->calendarChanged();
|
|
}
|
|
|
|
void ETMCalendarPrivate::updateItem(const Akonadi::Item &item)
|
|
{
|
|
Incidence::Ptr newIncidence = CalendarUtils::incidence(item);
|
|
Q_ASSERT(newIncidence);
|
|
Q_ASSERT(!newIncidence->uid().isEmpty());
|
|
newIncidence->setCustomProperty("VOLATILE", "AKONADI-ID", QString::number(item.id()));
|
|
IncidenceBase::Ptr existingIncidence = q->incidence(newIncidence->uid(), newIncidence->recurrenceId());
|
|
|
|
if (!existingIncidence && !mItemById.contains(item.id())) {
|
|
// We don't know about this one because it was discarded, for example because of not having DTSTART
|
|
return;
|
|
}
|
|
|
|
mItemsByCollection.insert(item.storageCollectionId(), item);
|
|
Akonadi::Item oldItem = mItemById.value(item.id());
|
|
|
|
if (existingIncidence) {
|
|
// We set the payload so that the internal incidence pointer and the one in mItemById stay the same
|
|
Akonadi::Item updatedItem = item;
|
|
updatedItem.setPayload<KCalCore::Incidence::Ptr>(existingIncidence.staticCast<KCalCore::Incidence>());
|
|
mItemById.insert(item.id(), updatedItem); // The item needs updating too, revision changed.
|
|
|
|
// Check if RELATED-TO changed, updating parenting information
|
|
handleParentChanged(newIncidence);
|
|
*(existingIncidence.data()) = *(newIncidence.data());
|
|
} else {
|
|
mItemById.insert(item.id(), item); // The item needs updating too, revision changed.
|
|
// The item changed it's UID, update our maps, the Google resource changes the UID when we create incidences.
|
|
handleUidChange(oldItem, item, newIncidence->instanceIdentifier());
|
|
}
|
|
}
|
|
|
|
void ETMCalendarPrivate::onRowsInsertedInFilteredModel(const QModelIndex &index,
|
|
int start, int end)
|
|
{
|
|
itemsAdded(itemsFromModel(mFilteredETM, index, start, end));
|
|
}
|
|
|
|
void ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel(const QModelIndex &index,
|
|
int start, int end)
|
|
{
|
|
itemsRemoved(itemsFromModel(mFilteredETM, index, start, end));
|
|
}
|
|
|
|
void ETMCalendarPrivate::onFilterChanged()
|
|
{
|
|
mCalFilterProxyModel->setFilter(q->filter());
|
|
}
|
|
|
|
ETMCalendar::ETMCalendar(QObject *parent) : CalendarBase(new ETMCalendarPrivate(this), parent)
|
|
{
|
|
Q_D(ETMCalendar);
|
|
d->init();
|
|
}
|
|
|
|
ETMCalendar::ETMCalendar(const QStringList &mimeTypes, QObject *parent) : CalendarBase(new ETMCalendarPrivate(this), parent)
|
|
{
|
|
Q_D(ETMCalendar);
|
|
d->mMimeTypes = mimeTypes;
|
|
d->init();
|
|
}
|
|
|
|
ETMCalendar::ETMCalendar(ETMCalendar *other, QObject *parent)
|
|
: CalendarBase(new ETMCalendarPrivate(this), parent)
|
|
{
|
|
Q_D(ETMCalendar);
|
|
|
|
CalendarModel *model = qobject_cast<Akonadi::CalendarModel*>(other->entityTreeModel());
|
|
if (model) {
|
|
d->mETM = model->weakPointer().toStrongRef();
|
|
}
|
|
|
|
d->init();
|
|
}
|
|
|
|
ETMCalendar::~ETMCalendar()
|
|
{
|
|
}
|
|
|
|
//TODO: move this up?
|
|
Akonadi::Collection ETMCalendar::collection(Akonadi::Collection::Id id) const
|
|
{
|
|
Q_D(const ETMCalendar);
|
|
return d->mCollectionMap.value(id);
|
|
}
|
|
|
|
bool ETMCalendar::hasRight(const QString &uid, Akonadi::Collection::Right right) const
|
|
{
|
|
return hasRight(item(uid), right);
|
|
}
|
|
|
|
bool ETMCalendar::hasRight(const Akonadi::Item &item, Akonadi::Collection::Right right) const
|
|
{
|
|
// if the users changes the rights, item.parentCollection()
|
|
// can still have the old rights, so we use call collection()
|
|
// which returns the updated one
|
|
const Akonadi::Collection col = collection(item.storageCollectionId());
|
|
return col.rights() & right;
|
|
}
|
|
|
|
QAbstractItemModel *ETMCalendar::model() const
|
|
{
|
|
Q_D(const ETMCalendar);
|
|
return d->mFilteredETM;
|
|
}
|
|
|
|
KCheckableProxyModel *ETMCalendar::checkableProxyModel() const
|
|
{
|
|
Q_D(const ETMCalendar);
|
|
return d->mCheckableProxyModel;
|
|
}
|
|
|
|
KCalCore::Alarm::List ETMCalendar::alarms(const KDateTime &from,
|
|
const KDateTime &to,
|
|
bool excludeBlockedAlarms) const
|
|
{
|
|
Q_D(const ETMCalendar);
|
|
KCalCore::Alarm::List alarmList;
|
|
QHashIterator<Akonadi::Item::Id, Akonadi::Item> i(d->mItemById);
|
|
while (i.hasNext()) {
|
|
const Akonadi::Item item = i.next().value();
|
|
|
|
BlockAlarmsAttribute *blockedAttr = 0;
|
|
|
|
if (excludeBlockedAlarms) {
|
|
// take the collection from m_collectionMap, because we need the up-to-date collection attrs
|
|
Akonadi::Collection parentCollection = d->mCollectionMap.value(item.storageCollectionId());
|
|
if (parentCollection.isValid() && parentCollection.hasAttribute<BlockAlarmsAttribute>()) {
|
|
blockedAttr = parentCollection.attribute<BlockAlarmsAttribute>();
|
|
if (blockedAttr->isAlarmTypeBlocked(Alarm::Audio) && blockedAttr->isAlarmTypeBlocked(Alarm::Display)
|
|
&& blockedAttr->isAlarmTypeBlocked(Alarm::Email) && blockedAttr->isAlarmTypeBlocked(Alarm::Procedure))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
KCalCore::Incidence::Ptr incidence;
|
|
if (item.isValid() && item.hasPayload<KCalCore::Incidence::Ptr>()) {
|
|
incidence = KCalCore::Incidence::Ptr(item.payload<KCalCore::Incidence::Ptr>()->clone());
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (!incidence) {
|
|
continue;
|
|
}
|
|
|
|
if (blockedAttr) {
|
|
// Remove all blocked types of alarms
|
|
Q_FOREACH(const KCalCore::Alarm::Ptr &alarm, incidence->alarms()) {
|
|
if (blockedAttr->isAlarmTypeBlocked(alarm->type())) {
|
|
incidence->removeAlarm(alarm);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (incidence->alarms().isEmpty()) {
|
|
continue;
|
|
}
|
|
|
|
Alarm::List tmpList;
|
|
if (incidence->recurs()) {
|
|
appendRecurringAlarms(tmpList, incidence, from, to);
|
|
} else {
|
|
appendAlarms(tmpList, incidence, from, to);
|
|
}
|
|
|
|
// We need to tag them with the incidence uid in case
|
|
// the caller will need it, because when we get out of
|
|
// this scope the incidence will be destroyed.
|
|
QVectorIterator<Alarm::Ptr> a(tmpList);
|
|
while (a.hasNext()) {
|
|
a.next()->setCustomProperty("ETMCalendar", "parentUid", incidence->uid());
|
|
}
|
|
alarmList += tmpList;
|
|
}
|
|
return alarmList;
|
|
}
|
|
|
|
Akonadi::EntityTreeModel *ETMCalendar::entityTreeModel() const
|
|
{
|
|
Q_D(const ETMCalendar);
|
|
return d->mETM.data();
|
|
}
|
|
|
|
void ETMCalendar::setCollectionFilteringEnabled(bool enable)
|
|
{
|
|
Q_D(ETMCalendar);
|
|
if (d->mCollectionFilteringEnabled != enable) {
|
|
d->mCollectionFilteringEnabled = enable;
|
|
if (enable) {
|
|
d->mSelectionProxy->setSourceModel(d->mETM.data());
|
|
QAbstractItemModel *oldModel = d->mCalFilterProxyModel->sourceModel();
|
|
d->mCalFilterProxyModel->setSourceModel(d->mSelectionProxy);
|
|
delete qobject_cast<KDescendantsProxyModel *>(oldModel);
|
|
} else {
|
|
KDescendantsProxyModel *flatner = new KDescendantsProxyModel(this);
|
|
flatner->setSourceModel(d->mETM.data());
|
|
d->mCalFilterProxyModel->setSourceModel(flatner);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ETMCalendar::collectionFilteringEnabled() const
|
|
{
|
|
Q_D(const ETMCalendar);
|
|
return d->mCollectionFilteringEnabled;
|
|
}
|
|
|
|
bool ETMCalendar::isLoaded() const
|
|
{
|
|
Q_D(const ETMCalendar);
|
|
|
|
if (!entityTreeModel()->isCollectionTreeFetched())
|
|
return false;
|
|
|
|
Akonadi::Collection::List collections = d->mCollectionMap.values();
|
|
foreach (const Akonadi::Collection &collection, collections) {
|
|
if (!entityTreeModel()->isCollectionPopulated(collection.id()))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#include "moc_etmcalendar.cpp"
|
|
#include "moc_etmcalendar_p.cpp"
|