Branch 'kolab/integration/4.13.0' - 6 commits - akonadi/calendar kcalutils/incidenceformatter.cpp kpimidentities/CMakeLists.txt kpimidentities/utils.cpp kpimidentities/utils.h
Sandro Knauß
knauss at kolabsys.com
Wed Sep 24 21:16:20 CEST 2014
akonadi/calendar/CMakeLists.txt | 1
akonadi/calendar/calendarbase.cpp | 45 ++++++
akonadi/calendar/calendarbase_p.h | 7 +
akonadi/calendar/calfilterpartstatusproxymodel_p.cpp | 124 +++++++++++++++++++
akonadi/calendar/calfilterpartstatusproxymodel_p.h | 58 ++++++++
akonadi/calendar/etmcalendar.cpp | 14 +-
akonadi/calendar/etmcalendar_p.h | 3
akonadi/calendar/fetchjobcalendar.cpp | 26 ++-
akonadi/calendar/fetchjobcalendar_p.h | 3
akonadi/calendar/itiphandler.cpp | 3
akonadi/calendar/scheduler_p.cpp | 4
akonadi/calendar/tests/etmcalendartest.cpp | 70 ++++++++++
akonadi/calendar/tests/etmcalendartest.h | 2
akonadi/calendar/tests/itiphandlertest.cpp | 12 +
akonadi/calendar/utils_p.cpp | 51 +------
akonadi/calendar/utils_p.h | 4
kcalutils/incidenceformatter.cpp | 70 +++-------
kpimidentities/CMakeLists.txt | 3
kpimidentities/utils.cpp | 69 ++++++++++
kpimidentities/utils.h | 45 ++++++
20 files changed, 513 insertions(+), 101 deletions(-)
New commits:
commit fd0b82b0813fc2b5ea8bad6b0851cc0c7797b699
Author: Sandro Knauà <knauss at kolabsys.com>
Date: Thu Sep 4 15:22:02 2014 +0200
Filter out new invitatins and declined events from etmcalendar.
invitations and declined events are available over a search collection,
so we don't want to show them in normal calendars.
Kolab: #3549
diff --git a/akonadi/calendar/CMakeLists.txt b/akonadi/calendar/CMakeLists.txt
index 951c700..3e68aa9 100644
--- a/akonadi/calendar/CMakeLists.txt
+++ b/akonadi/calendar/CMakeLists.txt
@@ -22,6 +22,7 @@ set(akonadicalendar_LIB_SRC
calendarclipboard.cpp
calendarmodel.cpp
calfilterproxymodel_p.cpp
+ calfilterpartstatusproxymodel_p.cpp
etmcalendar.cpp
history.cpp
history_p.cpp
diff --git a/akonadi/calendar/calfilterpartstatusproxymodel_p.cpp b/akonadi/calendar/calfilterpartstatusproxymodel_p.cpp
new file mode 100644
index 0000000..648f9a2
--- /dev/null
+++ b/akonadi/calendar/calfilterpartstatusproxymodel_p.cpp
@@ -0,0 +1,124 @@
+/*
+ Copyright (c) 2014 Sandro Knauà <knauss at kolabsys.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 "calfilterpartstatusproxymodel_p.h"
+#include "utils_p.h"
+
+#include <akonadi/collection.h>
+#include <akonadi/item.h>
+#include <akonadi/entitytreemodel.h>
+
+#include <kcalcore/incidence.h>
+#include <kcalcore/attendee.h>
+#include <kpimutils/email.h>
+
+#include <KPIMIdentities/IdentityManager>
+#include <KEMailSettings>
+
+using namespace Akonadi;
+
+class CalFilterPartStatusProxyModel::Private
+{
+public:
+ explicit Private()
+ : mFilterVirtual(false)
+ , mIdentityManager(/*ro=*/ true)
+ {
+ }
+
+ bool mFilterVirtual;
+ QList<KCalCore::Attendee::PartStat> mBlockedStatusList;
+ KPIMIdentities::IdentityManager mIdentityManager;
+};
+
+void CalFilterPartStatusProxyModel::slotIdentitiesChanged()
+{
+ emit invalidate();
+}
+
+CalFilterPartStatusProxyModel::CalFilterPartStatusProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+ , d(new Private())
+{
+ connect(&(d->mIdentityManager), SIGNAL(changed()),
+ SLOT(slotIdentitiesChanged()));
+}
+
+CalFilterPartStatusProxyModel::~CalFilterPartStatusProxyModel()
+{
+ delete d;
+}
+
+const QList<KCalCore::Attendee::PartStat> &CalFilterPartStatusProxyModel::blockedStatusList() const
+{
+ return d->mBlockedStatusList;
+}
+
+void CalFilterPartStatusProxyModel::setBlockedStatusList(const QList<KCalCore::Attendee::PartStat> &blockStatusList)
+{
+ d->mBlockedStatusList = blockStatusList;
+}
+
+
+bool CalFilterPartStatusProxyModel::filterVirtual() const
+{
+ return d->mFilterVirtual;
+}
+
+void CalFilterPartStatusProxyModel::setFilterVirtual(bool filterVirtual)
+{
+ d->mFilterVirtual = filterVirtual;
+}
+
+
+bool CalFilterPartStatusProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ const QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
+ if (!idx.isValid())
+ return false;
+
+ const Akonadi::Item item = idx.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
+ if (!item.isValid() || !item.hasPayload<KCalCore::Incidence::Ptr>()) {
+ return false;
+ }
+
+ const KCalCore::Incidence::Ptr incidence = item.payload<KCalCore::Incidence::Ptr>();
+ if (!incidence) {
+ return false;
+ }
+
+ // Incidences from virtual collections are always ok
+ const Akonadi::Collection col = idx.data(Akonadi::EntityTreeModel::ParentCollectionRole).value<Akonadi::Collection>();
+ if (!d->mFilterVirtual && col.isVirtual()) {
+ return true;
+ }
+
+ foreach (const KCalCore::Attendee::Ptr &attendee, incidence->attendees()) {
+ if ( CalendarUtils::thatIsMe(attendee) ) {
+ if ( d->mBlockedStatusList.contains(attendee->status()) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ // We are not attendee, so we accept the incidence
+ return true;
+}
diff --git a/akonadi/calendar/calfilterpartstatusproxymodel_p.h b/akonadi/calendar/calfilterpartstatusproxymodel_p.h
new file mode 100644
index 0000000..a12ccb7
--- /dev/null
+++ b/akonadi/calendar/calfilterpartstatusproxymodel_p.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (c) 2014 Sandro Knauà <knauss at kolabsys.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.
+*/
+
+#ifndef AKONADI_CALFILTERPARTSTATUSPROXYMODEL_P_H
+#define AKONADI_CALFILTERPARTSTATUSPROXYMODEL_P_H
+
+#include <QSortFilterProxyModel>
+#include <kcalcore/attendee.h>
+
+namespace Akonadi {
+
+class CalFilterPartStatusProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ explicit CalFilterPartStatusProxyModel(QObject *parent=0);
+ ~CalFilterPartStatusProxyModel();
+
+ void setFilterVirtual(bool filterVirtual);
+ bool filterVirtual() const;
+
+ void setBlockedStatusList(const QList<KCalCore::Attendee::PartStat> &blockStatusList);
+ const QList<KCalCore::Attendee::PartStat> &blockedStatusList() const;
+
+protected:
+ /* reimp */
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+
+private:
+ //@cond PRIVATE
+ class Private;
+ Private *const d;
+
+ //Q_PRIVATE_SLOT(d, void slotIdentitiesChanged())
+ //@endcond
+private slots:
+ void slotIdentitiesChanged();
+};
+
+}
+
+#endif
diff --git a/akonadi/calendar/etmcalendar.cpp b/akonadi/calendar/etmcalendar.cpp
index 194091c..ff051c3 100644
--- a/akonadi/calendar/etmcalendar.cpp
+++ b/akonadi/calendar/etmcalendar.cpp
@@ -23,6 +23,7 @@
#include "calendarmodel_p.h"
#include "kcolumnfilterproxymodel_p.h"
#include "calfilterproxymodel_p.h"
+#include "calfilterpartstatusproxymodel_p.h"
#include "utils_p.h"
#include <akonadi/item.h>
@@ -66,6 +67,7 @@ ETMCalendarPrivate::ETMCalendarPrivate(ETMCalendar *qq) : CalendarBasePrivate(qq
, mCheckableProxyModel(0)
, mCollectionProxyModel(0)
, mCalFilterProxyModel(0)
+ , mCalFilterPartStatusProxyModel(0)
, mSelectionProxy(0)
, mCollectionFilteringEnabled(true)
, q(qq)
@@ -185,8 +187,18 @@ void ETMCalendarPrivate::setupFilteredETM()
mCalFilterProxyModel->setSourceModel(mSelectionProxy);
mCalFilterProxyModel->setObjectName("KCalCore::CalFilter filtering");
+ mCalFilterPartStatusProxyModel = new CalFilterPartStatusProxyModel(this);
+ mCalFilterPartStatusProxyModel->setFilterVirtual(false);
+ QList<KCalCore::Attendee::PartStat> blockedStatusList;
+ blockedStatusList << KCalCore::Attendee::NeedsAction;
+ blockedStatusList << KCalCore::Attendee::Declined;
+ mCalFilterPartStatusProxyModel->setDynamicSortFilter(true);
+ mCalFilterPartStatusProxyModel->setBlockedStatusList(blockedStatusList);
+ mCalFilterPartStatusProxyModel->setSourceModel(mCalFilterProxyModel);
+ mCalFilterPartStatusProxyModel->setObjectName("PartStatus filtering");
+
mFilteredETM = new Akonadi::EntityMimeTypeFilterModel(this);
- mFilteredETM->setSourceModel(mCalFilterProxyModel);
+ mFilteredETM->setSourceModel(mCalFilterPartStatusProxyModel);
mFilteredETM->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
mFilteredETM->setSortRole(CalendarModel::SortRole);
mFilteredETM->setObjectName("Show headers");
diff --git a/akonadi/calendar/etmcalendar_p.h b/akonadi/calendar/etmcalendar_p.h
index ec57722..c998c01 100644
--- a/akonadi/calendar/etmcalendar_p.h
+++ b/akonadi/calendar/etmcalendar_p.h
@@ -41,6 +41,7 @@ class EntityTreeModel;
class EntityMimeTypeFilterModel;
class CollectionFilterProxyModel;
class CalFilterProxyModel;
+class CalFilterPartStatusProxyModel;
static bool isStructuralCollection(const Akonadi::Collection &collection)
{
@@ -133,6 +134,8 @@ public:
CheckableProxyModel *mCheckableProxyModel;
Akonadi::CollectionFilterProxyModel *mCollectionProxyModel;
Akonadi::CalFilterProxyModel *mCalFilterProxyModel; //KCalCore::CalFilter stuff
+ //filter out all invitations and declined events
+ Akonadi::CalFilterPartStatusProxyModel *mCalFilterPartStatusProxyModel;
KSelectionProxyModel *mSelectionProxy;
bool mCollectionFilteringEnabled;
QSet<Akonadi::Collection::Id> mPopulatedCollectionIds;
diff --git a/akonadi/calendar/tests/etmcalendartest.cpp b/akonadi/calendar/tests/etmcalendartest.cpp
index f093363..c45684e 100644
--- a/akonadi/calendar/tests/etmcalendartest.cpp
+++ b/akonadi/calendar/tests/etmcalendartest.cpp
@@ -30,6 +30,7 @@
#include <akonadi/itemdeletejob.h>
#include <akonadi/itemmodifyjob.h>
#include <KCheckableProxyModel>
+#include <KEMailSettings>
#include <QTestEventLoop>
#include <QSignalSpy>
@@ -532,6 +533,75 @@ void ETMCalendarTest::testShareETM()
QVERIFY(calendar2->incidences().isEmpty());
}
+void ETMCalendarTest::testFilterInvitations()
+{
+ int anz = mCalendar->model()->rowCount();
+ QString uid = QLatin1String("invite-01");
+ Item item;
+ Incidence::Ptr incidence = Incidence::Ptr(new Event());
+ KEMailSettings emailSettings;
+ KCalCore::Attendee::Ptr me(new KCalCore::Attendee(QLatin1String("me"), emailSettings.getSetting(KEMailSettings::EmailAddress)));
+
+ item.setMimeType(Event::eventMimeType());
+ incidence->setUid(uid);
+ incidence->setDtStart(KDateTime::currentDateTime(KDateTime::UTC));
+ incidence->setSummary(QLatin1String("summary"));
+
+ me->setStatus(KCalCore::Attendee::NeedsAction);
+ incidence->addAttendee(me);
+
+ item.setPayload<KCalCore::Incidence::Ptr>(incidence);
+ ItemCreateJob *job = new ItemCreateJob(item, mCollection, this);
+ AKVERIFYEXEC(job);
+ waitForIt();
+ // incidence do not pop up in model
+ QCOMPARE(mCalendar->model()->rowCount(), anz);
+
+ kDebug() << "first invite ended";
+}
+
+void ETMCalendarTest::testFilterInvitationsChanged()
+{
+ int anz = mCalendar->model()->rowCount();
+
+ KEMailSettings emailSettings;
+ KCalCore::Attendee::Ptr me(new KCalCore::Attendee(QLatin1String("me"), emailSettings.getSetting(KEMailSettings::EmailAddress)));
+
+ QString uid = QLatin1String("invite-02");
+ mIncidencesToAdd = 1;
+ createIncidence(uid);
+ waitForIt();
+ QCOMPARE(mCalendar->model()->rowCount(), anz+1);
+
+ Incidence::Ptr incidence = mCalendar->incidence(uid);
+ Item item = mCalendar->item(uid);
+
+ incidence->addAttendee(me);
+ incidence->setRevision(1);
+ item.setPayload<KCalCore::Incidence::Ptr>(incidence);
+
+ mIncidencesToDelete = 1;
+ ItemModifyJob *modifyJob = new ItemModifyJob(item, this);
+ AKVERIFYEXEC(modifyJob);
+ waitForIt();
+ QCOMPARE(mCalendar->model()->rowCount(), anz);
+
+ me->setStatus(KCalCore::Attendee::Accepted);
+ incidence->clearAttendees();
+ incidence->addAttendee(me);
+
+ incidence->setRevision(2);
+
+ item.setPayload<KCalCore::Incidence::Ptr>(incidence);
+ item.setRevision(2);
+ mIncidencesToAdd = 1;
+ modifyJob = new ItemModifyJob(item, this);
+ AKVERIFYEXEC(modifyJob);
+ waitForIt();
+ QCOMPARE(mCalendar->model()->rowCount(), anz+1);
+}
+
+
void ETMCalendarTest::waitForIt()
{
QTestEventLoop::instance().enterLoop(10);
diff --git a/akonadi/calendar/tests/etmcalendartest.h b/akonadi/calendar/tests/etmcalendartest.h
index 1d219e7..22f3e38 100644
--- a/akonadi/calendar/tests/etmcalendartest.h
+++ b/akonadi/calendar/tests/etmcalendartest.h
@@ -50,6 +50,8 @@ private Q_SLOTS:
void testUidChange();
void testItem(); // tests item()
void testShareETM();
+ void testFilterInvitations();
+ void testFilterInvitationsChanged();
public Q_SLOTS:
void calendarIncidenceAdded(const KCalCore::Incidence::Ptr &incidence); /**Q_DECL_OVERRIDE*/
commit 50db79b548b767945ee9c5ae809cb73b0873e1eb
Author: Sandro Knauà <knauss at kolabsys.com>
Date: Wed Sep 24 21:00:03 2014 +0200
Used cached version of thatIsMe
diff --git a/kcalutils/incidenceformatter.cpp b/kcalutils/incidenceformatter.cpp
index e996f19..4ef8c1a 100644
--- a/kcalutils/incidenceformatter.cpp
+++ b/kcalutils/incidenceformatter.cpp
@@ -45,7 +45,7 @@
#include <kcalcore/visitor.h>
using namespace KCalCore;
-#include <kpimidentities/identitymanager.h>
+#include <kpimidentities/utils.h>
#include <kpimutils/email.h>
#include <kpimutils/linklocator.h>
@@ -78,44 +78,17 @@ static QString string2HTML(const QString &str)
return KPIMUtils::LinkLocator::convertToHtml(str);
}
-static KPIMIdentities::IdentityManager *s_identityManager = 0;
-
-// Performance optimization so we only create one IdentityManager instead of 1 per attendee.
-// Using RAII to protect against future return statements in the middle of code
-struct RAIIIdentityManager{
- RAIIIdentityManager()
- {
- //t.start();
- s_identityManager = new KPIMIdentities::IdentityManager(true);
- }
-
- ~RAIIIdentityManager()
- {
- delete s_identityManager;
- s_identityManager = 0;
- //qDebug() << "Elapsed time: " << t.elapsed();
- }
- //QElapsedTimer t;
-};
-
static bool thatIsMe(const QString &email)
{
- return s_identityManager ? s_identityManager->thatIsMe(email)
- : KPIMIdentities::IdentityManager(true).thatIsMe(email);
+ return KPIMIdentities::thatIsMe(email);
}
-static bool iamAttendee(Attendee::Ptr attendee)
+static bool iamAttendee(const Attendee::Ptr &attendee)
{
// Check if this attendee is the user
return thatIsMe(attendee->email());
}
-static bool iamPerson(const Person &person)
-{
- // Check if this person is the user. test email only
- return thatIsMe(person.email());
-}
-
static QString htmlAddLink(const QString &ref, const QString &text,
bool newline = true)
{
@@ -130,22 +103,20 @@ static QString htmlAddMailtoLink(const QString &email, const QString &name)
{
QString str;
- if (!email.isEmpty()) {
+ if (!email.isEmpty() && !thatIsMe(email)) {
Person person(name, email);
- if (!iamPerson(person)) { // do not add a link for the user's email
- QString path = person.fullName().simplified();
- if (path.isEmpty() || path.startsWith(QLatin1Char('"'))) {
- path = email;
- }
- KUrl mailto;
- mailto.setProtocol(QLatin1String("mailto"));
- mailto.setPath(path);
-
- // static for performance
- static const QString iconPath =
- KIconLoader::global()->iconPath(QLatin1String("mail-message-new"), KIconLoader::Small);
- str = htmlAddLink(mailto.url(), QLatin1String("<img valign=\"top\" src=\"") + iconPath + QLatin1String("\">"));
+ QString path = person.fullName().simplified();
+ if (path.isEmpty() || path.startsWith(QLatin1Char('"'))) {
+ path = email;
}
+ KUrl mailto;
+ mailto.setProtocol(QLatin1String("mailto"));
+ mailto.setPath(path);
+
+ // static for performance
+ static const QString iconPath =
+ KIconLoader::global()->iconPath(QLatin1String("mail-message-new"), KIconLoader::Small);
+ str = htmlAddLink(mailto.url(), QLatin1String("<img valign=\"top\" src=\"") + iconPath + QLatin1String("\">"));
}
return str;
}
@@ -1318,7 +1289,6 @@ static Attendee::Ptr findDelegatedFromMyAttendee(const Incidence::Ptr &incidence
return attendee;
}
- RAIIIdentityManager raiiHelper;
QString delegatorName, delegatorEmail;
Attendee::List attendees = incidence->attendees();
Attendee::List::ConstIterator it;
@@ -1343,12 +1313,11 @@ static Attendee::Ptr findMyAttendee(const Incidence::Ptr &incidence)
return attendee;
}
- RAIIIdentityManager raiiHelper;
Attendee::List attendees = incidence->attendees();
Attendee::List::ConstIterator it;
for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
Attendee::Ptr a = *it;
- if (thatIsMe(a->email())) {
+ if (iamAttendee(a)) {
attendee = a;
break;
}
@@ -1367,7 +1336,6 @@ static Attendee::Ptr findAttendee(const Incidence::Ptr &incidence,
return attendee;
}
- RAIIIdentityManager raiiHelper;
Attendee::List attendees = incidence->attendees();
Attendee::List::ConstIterator it;
for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
@@ -2408,8 +2376,6 @@ static QString invitationHeaderFreeBusy(const FreeBusy::Ptr &fb,
static QString invitationAttendeeList(const Incidence::Ptr &incidence)
{
- RAIIIdentityManager raiiHelper;
-
QString tmpStr;
if (!incidence) {
return tmpStr;
commit 759d61446af11fbb7fd6f260bf9cb0242fcabc1a
Author: Sandro Knauà <knauss at kolabsys.com>
Date: Wed Sep 24 14:33:41 2014 +0200
Used cached version of thatIsMe and allEmails
diff --git a/akonadi/calendar/utils_p.cpp b/akonadi/calendar/utils_p.cpp
index 21f7371..2bb60c7 100644
--- a/akonadi/calendar/utils_p.cpp
+++ b/akonadi/calendar/utils_p.cpp
@@ -22,6 +22,7 @@
#include <kpimutils/email.h>
#include <kpimidentities/identitymanager.h>
#include <kpimidentities/identity.h>
+#include <kpimidentities/utils.h>
#include <kmime/kmime_header_parsing.h>
#include <KEMailSettings>
@@ -85,25 +86,13 @@ QString Akonadi::CalendarUtils::email()
return emailSettings.getSetting(KEMailSettings::EmailAddress);
}
-bool Akonadi::CalendarUtils::thatIsMe(const QString &_email)
+bool Akonadi::CalendarUtils::thatIsMe(const KCalCore::Attendee::Ptr &attendee)
{
- KPIMIdentities::IdentityManager identityManager(/*ro=*/ true);
-
- // NOTE: this method is called for every created agenda view item,
- // so we need to keep performance in mind
-
- /* identityManager()->thatIsMe() is quite expensive since it does parsing of
- _email in a way which is unnecessarily complex for what we can have here,
- so we do that ourselves. This makes sense since this
-
- if ( Akonadi::identityManager()->thatIsMe( _email ) ) {
- return true;
- }
- */
+ return KPIMIdentities::thatIsMe(attendee->email());
+}
- // in case email contains a full name, strip it out.
- // the below is the simpler but slower version of the following code:
- // const QString email = KPIM::getEmailAddress( _email );
+bool Akonadi::CalendarUtils::thatIsMe(const QString &_email)
+{
const QByteArray tmp = _email.toUtf8();
const char *cursor = tmp.constData();
const char *end = tmp.data() + tmp.length();
@@ -111,30 +100,16 @@ bool Akonadi::CalendarUtils::thatIsMe(const QString &_email)
KMime::HeaderParsing::parseMailbox(cursor, end, mbox);
const QString email = mbox.addrSpec().asString();
- KEMailSettings emailSettings;
- const QString myEmail = emailSettings.getSetting(KEMailSettings::EmailAddress);
-
- if (myEmail == email) {
- return true;
- }
-
- KPIMIdentities::IdentityManager::ConstIterator it;
- for (it = identityManager.begin();
- it != identityManager.end(); ++it) {
- if ((*it).matchesEmailAddress(email)) {
- return true;
- }
- }
-
- return false;
+ return KPIMIdentities::thatIsMe(email);
}
QStringList Akonadi::CalendarUtils::allEmails()
{
- KPIMIdentities::IdentityManager identityManager(/*ro=*/ true);
- // Grab emails from the email identities
- // Warning, this list could contain duplicates.
- return identityManager.allEmails();
+ QStringList emails;
+ foreach(const QString &email, KPIMIdentities::allEmails()) {
+ emails.append(email);
+ }
+ return emails;
}
KCalCore::Incidence::Ptr Akonadi::CalendarUtils::incidence(const Akonadi::Item &item)
@@ -146,4 +121,4 @@ KCalCore::Incidence::Ptr Akonadi::CalendarUtils::incidence(const Akonadi::Item &
} catch (Akonadi::PayloadException) {
return KCalCore::Incidence::Ptr();
}
-}
+}
\ No newline at end of file
diff --git a/akonadi/calendar/utils_p.h b/akonadi/calendar/utils_p.h
index f4cb12e..d024753 100644
--- a/akonadi/calendar/utils_p.h
+++ b/akonadi/calendar/utils_p.h
@@ -39,6 +39,10 @@ namespace CalendarUtils {
QString fullName();
QString email();
bool thatIsMe(const QString &email);
+
+//faster version, because we know that attendee->email() is only the email address
+bool thatIsMe(const KCalCore::Attendee::Ptr &attendee);
+
QStringList allEmails();
KCalCore::Incidence::Ptr incidence(const Akonadi::Item &item);
commit 9b1869004ac7c9b7c6c0d6300efc6b4c0aa705f7
Author: Sandro Knauà <knauss at kolabsys.com>
Date: Wed Sep 24 13:31:28 2014 +0200
Added utils for cached version for thatIsMe and allEmails
diff --git a/kpimidentities/CMakeLists.txt b/kpimidentities/CMakeLists.txt
index 8957f69..2692c82 100644
--- a/kpimidentities/CMakeLists.txt
+++ b/kpimidentities/CMakeLists.txt
@@ -2,7 +2,7 @@
add_definitions( -DQT_NO_CAST_FROM_ASCII )
add_definitions( -DQT_NO_CAST_TO_ASCII )
-set(kpimidentities_LIB_SRCS identitymanager.cpp identity.cpp signature.cpp signatureconfigurator.cpp identitycombo.cpp)
+set(kpimidentities_LIB_SRCS identitymanager.cpp identity.cpp signature.cpp signatureconfigurator.cpp identitycombo.cpp utils.cpp)
add_subdirectory( tests )
@@ -28,6 +28,7 @@ install(FILES
signatureconfigurator.h
identitymanager.h
identitycombo.h
+ utils.h
${CMAKE_CURRENT_BINARY_DIR}/kpimidentities_export.h
DESTINATION ${INCLUDE_INSTALL_DIR}/kpimidentities COMPONENT Devel)
diff --git a/kpimidentities/utils.cpp b/kpimidentities/utils.cpp
new file mode 100644
index 0000000..20f59a8
--- /dev/null
+++ b/kpimidentities/utils.cpp
@@ -0,0 +1,69 @@
+/*
+ Copyright (c) 2014 Sandro Knauà <knauss at kolabsys.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 "utils.h"
+#include "identitymanager.h"
+
+#include <QObject>
+
+using namespace KPIMIdentities;
+
+class IdendentitiesCache : public QObject
+{
+ Q_OBJECT
+public:
+ IdendentitiesCache()
+ : mIdentityManager(/*ro=*/ true)
+ {
+ connect(&mIdentityManager, SIGNAL(changed()),
+ SLOT(slotIdentitiesChanged()));
+ slotIdentitiesChanged();
+ }
+ const QSet<QString> &emails()
+ {
+ return mEmails;
+ }
+
+private slots:
+ void slotIdentitiesChanged()
+ {
+ mEmails.clear();
+ foreach(const QString &email, mIdentityManager.allEmails()) {
+ mEmails.insert(email.toLower());
+ }
+ }
+
+private:
+ IdentityManager mIdentityManager;
+ QSet<QString> mEmails;
+};
+
+Q_GLOBAL_STATIC(IdendentitiesCache, sIdentitiesCache)
+
+bool KPIMIdentities::thatIsMe(const QString &email)
+{
+ return allEmails().contains(email.toLower());
+}
+
+const QSet<QString> & KPIMIdentities::allEmails()
+{
+ return sIdentitiesCache()->emails();
+}
+
+#include "utils.moc"
diff --git a/kpimidentities/utils.h b/kpimidentities/utils.h
new file mode 100644
index 0000000..98b5392
--- /dev/null
+++ b/kpimidentities/utils.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (c) 2014 Sandro Knauà <knauss at kolabsys.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.
+*/
+
+#ifndef KPIMIDENTITES_UTILS_H
+#define KPIMIDENTITES_UTILS_H
+
+#include <kpimidentities/kpimidentities_export.h>
+
+#include <QString>
+#include <QSet>
+
+namespace KPIMIdentities
+{
+ /*
+ * Very fast version of IdentityManager::thatIsMe, that is using an internal cache (allEmails)
+ * - make sure that only an email address is used as parameter and NO name <email>
+ * - emails are tested with email.toLower(), so no need to lower them before.
+ */
+ KPIMIDENTITIES_EXPORT bool thatIsMe(const QString &email);
+
+ /*
+ * Very fast version of IdentityManager::allEmails , that is using an internal cache.
+ * The cache is updated with IdentityManager::changed signal.
+ * All email addresses + alias of the identities. The email addresses are all lowered.
+ */
+ KPIMIDENTITIES_EXPORT const QSet<QString> &allEmails();
+}
+
+#endif
commit 33eec57d4844da9682cce4be54e219c92f195547
Author: Sandro Knauà <knauss at kolabsys.com>
Date: Wed Sep 3 13:28:46 2014 +0200
Postpose button for invitations
* show postpone button
* handle postpone -> only store event in calendar
* add test for postpone
diff --git a/akonadi/calendar/itiphandler.cpp b/akonadi/calendar/itiphandler.cpp
index ffaccf5..b3cb61c 100644
--- a/akonadi/calendar/itiphandler.cpp
+++ b/akonadi/calendar/itiphandler.cpp
@@ -221,6 +221,9 @@ void ITIPHandler::processiTIPMessage(const QString &receiver,
d->m_scheduler->acceptCounterProposal(d->m_incidence, d->calendar());
}
return; // signal emitted in onSchedulerFinished().
+ } else if (action.startsWith(QLatin1String("request"))) {
+ d->m_scheduler->acceptTransaction(d->m_incidence, d->calendar(), d->m_method, status, receiver);
+ return;
} else {
kError() << "Unknown incoming action" << action;
diff --git a/akonadi/calendar/scheduler_p.cpp b/akonadi/calendar/scheduler_p.cpp
index 11e93c1..4c18a58 100644
--- a/akonadi/calendar/scheduler_p.cpp
+++ b/akonadi/calendar/scheduler_p.cpp
@@ -304,7 +304,7 @@ void Scheduler::acceptRequest(const IncidenceBase::Ptr &incidenceBase,
KMessageBox::information(
0,
i18nc("@info",
- "<para>You accepted an invitation update, but an earlier version of the "
+ "<para>You added an invitation update, but an earlier version of the "
"item could not be found in your calendar.</para>"
"<para>This may have occurred because:<list>"
"<item>the organizer did not include you in the original invitation</item>"
@@ -313,7 +313,7 @@ void Scheduler::acceptRequest(const IncidenceBase::Ptr &incidenceBase,
"<item>you no longer have access to the calendar containing the invitation</item>"
"</list></para>"
"<para>This is not a problem, but we thought you should know.</para>"),
- i18nc("@title", "Cannot find invitation to be updated"), "AcceptCantFindIncidence");
+ i18nc("@title", "Cannot find invitation to be updated"), "CantFindIncidence");
}
kDebug() << "Storing new incidence with scheduling uid=" << schedulingUid << " and uid=" << incidence->uid();
diff --git a/akonadi/calendar/tests/itiphandlertest.cpp b/akonadi/calendar/tests/itiphandlertest.cpp
index 92c9e37..d7d85bb 100644
--- a/akonadi/calendar/tests/itiphandlertest.cpp
+++ b/akonadi/calendar/tests/itiphandlertest.cpp
@@ -182,6 +182,18 @@ void ITIPHandlerTest::testProcessITIPMessage_data()
<< expectedNumIncidences
<< expectedPartStat;
//----------------------------------------------------------------------------------------------
+ // Process a REQUEST without having the incidence in our calendar.
+ // itiphandler should return success and add the rquest to a calendar
+ expectedResult = ITIPHandler::ResultSuccess;
+ data_filename = QLatin1String("invited_us");
+ expectedNumIncidences = 1;
+ expectedPartStat = KCalCore::Attendee::NeedsAction;
+ action = QLatin1String("request");
+ QTest::newRow("invited us5") << data_filename << action << receiver << incidenceUid
+ << expectedResult
+ << expectedNumIncidences
+ << expectedPartStat;
+ //----------------------------------------------------------------------------------------------
// Here we're testing an error case, where data is null.
expectedResult = ITIPHandler::ResultError;
expectedNumIncidences = 0;
diff --git a/kcalutils/incidenceformatter.cpp b/kcalutils/incidenceformatter.cpp
index 215131c..e996f19 100644
--- a/kcalutils/incidenceformatter.cpp
+++ b/kcalutils/incidenceformatter.cpp
@@ -2928,6 +2928,10 @@ static QString responseButtons(const Incidence::Ptr &incidence,
// Decline
html += inviteButton(helper, QLatin1String("decline"),
i18nc("decline invitation", "Decline"));
+
+ // Postpone
+ html += inviteButton(helper, QLatin1String("postpone"),
+ i18nc("postpone invitation", "Postpone"));
}
if (!rsvpRec || (incidence && incidence->revision() > 0)) {
commit c748944e39079c75e3b07d2676113869f887eb5e
Author: Sandro Knauà <knauss at kolabsys.com>
Date: Tue Sep 2 14:56:43 2014 +0200
ReadOnly is read from storageCollection
diff --git a/akonadi/calendar/calendarbase.cpp b/akonadi/calendar/calendarbase.cpp
index 4c49142..5cc7d8c 100644
--- a/akonadi/calendar/calendarbase.cpp
+++ b/akonadi/calendar/calendarbase.cpp
@@ -23,6 +23,7 @@
#include "incidencechanger.h"
#include "utils_p.h"
+#include <Akonadi/CollectionFetchJob>
#include <akonadi/item.h>
#include <akonadi/collection.h>
@@ -124,7 +125,20 @@ void CalendarBasePrivate::internalInsert(const Akonadi::Item &item)
Akonadi::Collection collection = item.parentCollection();
if (collection.isValid()) {
// Some items don't have collection set
- incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem));
+ if (item.storageCollectionId() != collection.id() && item.storageCollectionId() > -1) {
+ if (mCollections.contains(item.storageCollectionId())) {
+ collection = mCollections.value(item.storageCollectionId());
+ incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem));
+ } else if (!mCollectionJobs.key(item.storageCollectionId())) {
+ collection = Akonadi::Collection(item.storageCollectionId());
+ Akonadi::CollectionFetchJob *job = new Akonadi::CollectionFetchJob(collection, Akonadi::CollectionFetchJob::Base, this);
+ connect(job, SIGNAL(result(KJob*)), this, SLOT(collectionFetchResult(KJob*)));
+ mCollectionJobs.insert(job, collection.id());
+ }
+ } else {
+ mCollections.insert(collection.id(), collection);
+ incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem));
+ }
}
mItemById.insert(item.id(), item);
@@ -149,6 +163,35 @@ void CalendarBasePrivate::internalInsert(const Akonadi::Item &item)
}
}
+void CalendarBasePrivate::collectionFetchResult(KJob* job)
+{
+ Akonadi::Collection::Id colid = mCollectionJobs.take(job);
+
+ if ( job->error() ) {
+ qDebug() << "Error occurred";
+ return;
+ }
+
+ Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob*>( job );
+
+ const Akonadi::Collection collection = fetchJob->collections().first();
+ if (collection.id() != colid) {
+ kError() << "Fetched the wrong collection, should fetch: " << colid << "fetched: " << collection.id();
+ }
+
+ bool isReadOnly = !(collection.rights() & Akonadi::Collection::CanChangeItem);
+ foreach (const Akonadi::Item &item, mItemsByCollection.values(collection.id())) {
+ KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence(item);
+ incidence->setReadOnly(isReadOnly);
+ }
+
+ mCollections.insert(collection.id(), collection);
+
+ if (mCollectionJobs.count() == 0) {
+ emit fetchFinished();
+ }
+}
+
void CalendarBasePrivate::internalRemove(const Akonadi::Item &item)
{
Q_ASSERT(item.isValid());
diff --git a/akonadi/calendar/calendarbase_p.h b/akonadi/calendar/calendarbase_p.h
index 87bec31..eb233c3 100644
--- a/akonadi/calendar/calendarbase_p.h
+++ b/akonadi/calendar/calendarbase_p.h
@@ -64,8 +64,15 @@ public Q_SLOTS:
Akonadi::IncidenceChanger::ResultCode,
const QString &errorMessage);
+ void collectionFetchResult(KJob *job);
+
+signals:
+ void fetchFinished();
+
public:
QMultiHash<Akonadi::Collection::Id, Akonadi::Item> mItemsByCollection;
+ QHash<Akonadi::Collection::Id, Akonadi::Collection> mCollections;
+ QHash<KJob*, Akonadi::Collection::Id> mCollectionJobs;
QHash<QString,Akonadi::Item::Id> mItemIdByUid;
QHash<Akonadi::Item::Id, Akonadi::Item> mItemById;
Akonadi::IncidenceChanger *mIncidenceChanger;
diff --git a/akonadi/calendar/fetchjobcalendar.cpp b/akonadi/calendar/fetchjobcalendar.cpp
index e1928de..a12d4d9 100644
--- a/akonadi/calendar/fetchjobcalendar.cpp
+++ b/akonadi/calendar/fetchjobcalendar.cpp
@@ -35,6 +35,8 @@ FetchJobCalendarPrivate::FetchJobCalendarPrivate(FetchJobCalendar *qq) : Calenda
IncidenceFetchJob *job = new IncidenceFetchJob();
connect(job, SIGNAL(result(KJob*)),
SLOT(slotSearchJobFinished(KJob*)));
+ connect(this, SIGNAL(fetchFinished()),
+ SLOT(slotFetchJobFinished()));
}
FetchJobCalendarPrivate::~FetchJobCalendarPrivate()
@@ -44,27 +46,35 @@ FetchJobCalendarPrivate::~FetchJobCalendarPrivate()
void FetchJobCalendarPrivate::slotSearchJobFinished(KJob *job)
{
IncidenceFetchJob *searchJob = static_cast<Akonadi::IncidenceFetchJob*>(job);
- bool success = true;
- QString errorMessage;
+ mSuccess = true;
+ mErrorMessage = QString();
if (searchJob->error()) {
- success = false;
- errorMessage = searchJob->errorText();
+ mSuccess = false;
+ mErrorMessage = searchJob->errorText();
kWarning() << "Unable to fetch incidences:" << searchJob->errorText();
} else {
foreach(const Akonadi::Item &item, searchJob->items()) {
if (!item.isValid() || !item.hasPayload<KCalCore::Incidence::Ptr>()) {
- success = false;
- errorMessage = QString("Invalid item or payload: %1").arg(item.id());
- kWarning() << "Unable to fetch incidences:" << errorMessage;
+ mSuccess = false;
+ mErrorMessage = QString("Invalid item or payload: %1").arg(item.id());
+ kWarning() << "Unable to fetch incidences:" << mErrorMessage;
continue;
}
internalInsert(item);
}
}
+
+ if (mCollectionJobs.count() == 0) {
+ slotFetchJobFinished();
+ }
+}
+
+void FetchJobCalendarPrivate::slotFetchJobFinished()
+{
m_isLoaded = true;
// emit loadFinished() in a delayed manner, due to freezes because of execs.
QMetaObject::invokeMethod(q, "loadFinished", Qt::QueuedConnection,
- Q_ARG(bool, success), Q_ARG(QString, errorMessage));
+ Q_ARG(bool, mSuccess), Q_ARG(QString, mErrorMessage));
}
FetchJobCalendar::FetchJobCalendar(QObject *parent) : CalendarBase(new FetchJobCalendarPrivate(this), parent)
diff --git a/akonadi/calendar/fetchjobcalendar_p.h b/akonadi/calendar/fetchjobcalendar_p.h
index e3aba8f..5923cb1 100644
--- a/akonadi/calendar/fetchjobcalendar_p.h
+++ b/akonadi/calendar/fetchjobcalendar_p.h
@@ -38,12 +38,15 @@ public:
public Q_SLOTS:
void slotSearchJobFinished(KJob *job);
+ void slotFetchJobFinished();
public:
bool m_isLoaded;
private:
FetchJobCalendar *const q;
+ QString mErrorMessage;
+ bool mSuccess;
};
}
More information about the commits
mailing list