Commit 3ac4586e authored by Daniel Vrátil's avatar Daniel Vrátil 🤖
Browse files

Merge branch 'dev/plasmacalendarplugin'

parents d8ce6626 6b0d0019
...@@ -54,6 +54,7 @@ find_package(KF5Config ${KF5_VERSION} CONFIG REQUIRED) ...@@ -54,6 +54,7 @@ find_package(KF5Config ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5DBusAddons ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5DBusAddons ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5AkonadiNotes ${AKONADINOTES_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiNotes ${AKONADINOTES_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5XmlGui ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5XmlGui ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5Declarative ${KF5_VERSION} CONFIG REQUIRED)
set(MAILCOMMN_LIB_VERSION "5.2.40") set(MAILCOMMN_LIB_VERSION "5.2.40")
set(GRAVATAR_LIB_VERSION "5.2.40") set(GRAVATAR_LIB_VERSION "5.2.40")
...@@ -69,6 +70,7 @@ set(GRAVATAR_LIB_VERSION "5.2.40") ...@@ -69,6 +70,7 @@ set(GRAVATAR_LIB_VERSION "5.2.40")
set(INCIDENCEEDITOR_LIB_VERSION "5.2.40") set(INCIDENCEEDITOR_LIB_VERSION "5.2.40")
set(KTNEF_LIB_VERSION "5.2.40") set(KTNEF_LIB_VERSION "5.2.40")
set(MESSAGELIB_LIB_VERSION "5.2.62") set(MESSAGELIB_LIB_VERSION "5.2.62")
set(AKONADICALENDAR_LIB_VERSION "5.2.40")
find_package(KF5WebEngineViewer ${MESSAGELIB_LIB_VERSION} CONFIG REQUIRED) find_package(KF5WebEngineViewer ${MESSAGELIB_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5MailCommon ${MAILCOMMN_LIB_VERSION} CONFIG REQUIRED) find_package(KF5MailCommon ${MAILCOMMN_LIB_VERSION} CONFIG REQUIRED)
...@@ -85,6 +87,7 @@ find_package(KF5MessageList ${MESSAGELIB_LIB_VERSION} CONFIG REQUIRED) ...@@ -85,6 +87,7 @@ find_package(KF5MessageList ${MESSAGELIB_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5CalendarSupport ${CALENDARSUPPORT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarSupport ${CALENDARSUPPORT_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5EventViews ${EVENTVIEW_LIB_VERSION} CONFIG REQUIRED) find_package(KF5EventViews ${EVENTVIEW_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED) find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED)
find_package(KF5AkonadiCalendar ${AKONADICALENDAR_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5Gravatar ${GRAVATAR_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Gravatar ${GRAVATAR_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5Tnef ${KTNEF_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Tnef ${KTNEF_LIB_VERSION} CONFIG REQUIRED)
......
...@@ -16,3 +16,5 @@ log_externalscriptplugin kdepim-addons (External Script Plugin) ...@@ -16,3 +16,5 @@ log_externalscriptplugin kdepim-addons (External Script Plugin)
log_text_calendar kdepim-addons (messageviewer calendar plugins) log_text_calendar kdepim-addons (messageviewer calendar plugins)
log_ms_tnef kdepim-addons (ms_tnef) log_ms_tnef kdepim-addons (ms_tnef)
log_vcard kdepim-addons (vcard) log_vcard kdepim-addons (vcard)
log_pimeventsplugin kdepim-addons (Plasma calendar plugin)
...@@ -3,5 +3,6 @@ add_subdirectory(messageviewerplugins) ...@@ -3,5 +3,6 @@ add_subdirectory(messageviewerplugins)
add_subdirectory(messageviewerheaderplugins) add_subdirectory(messageviewerheaderplugins)
add_subdirectory(storageservices) add_subdirectory(storageservices)
add_subdirectory(messageviewer) add_subdirectory(messageviewer)
add_subdirectory(plasma)
add_subdirectory(webengineurlinterceptor) add_subdirectory(webengineurlinterceptor)
add_subdirectory(pimeventsplugin)
if (BUILD_TESTING)
add_subdirectory(autotests)
endif()
set(pimeventsplugin_SRCS
pimeventsplugin.cpp
akonadipimdatasource.cpp
eventdatavisitor.cpp
settingschangenotifier.cpp
)
ecm_qt_declare_logging_category(loggingcategory_SRCS
HEADER pimeventsplugin_debug.h
IDENTIFIER PIMEVENTSPLUGIN_LOG
CATEGORY_NAME log_pimeventsplugin
)
add_library(pimevents MODULE ${pimeventsplugin_SRCS} ${loggingcategory_SRCS})
target_link_libraries(pimevents
Qt5::Core
KF5::AkonadiCore
KF5::AkonadiCalendar
KF5::CalendarCore
KF5::CalendarEvents
KF5::EventViews # for reading KOrganizer calendar colors
)
install(TARGETS pimevents
DESTINATION ${PLUGIN_INSTALL_DIR}/plasmacalendarplugins
)
######################### NEXT TARGET #######################33
set(plasmapimcalendarsplugin_SRCS
pimcalendarsplugin.cpp
pimcalendarsmodel.cpp
settingschangenotifier.cpp
)
add_library(pimcalendarsplugin SHARED ${plasmapimcalendarsplugin_SRCS} ${loggingcategory_SRCS})
target_link_libraries(pimcalendarsplugin
Qt5::Core
Qt5::Qml
KF5::AkonadiCore
KF5::CalendarCore
)
install(TARGETS pimcalendarsplugin
DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/PimCalendars
)
install(FILES qmldir
DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/PimCalendars
)
install(FILES PimEventsConfig.qml
DESTINATION ${PLUGIN_INSTALL_DIR}/plasmacalendarplugins/pimevents
)
/*
* Copyright 2016 Daniel Vrátil <dvratil@kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
import QtQuick 2.0
import QtQuick.Controls 1.4
// gives us TextSingleton
import QtQuick.Controls.Private 1.0
import QtQuick.Layouts 1.0
import QtQuick.Dialogs 1.1
import org.kde.plasma.core 2.0
import org.kde.plasma.PimCalendars 1.0
Item {
id: pimEventsConfig
width: parent.width
height: parent.height
signal configurationChanged
function saveConfig()
{
calendarModel.saveConfig();
}
PimCalendarsModel {
id: calendarModel
}
// Invisible, used to measure implicitHeight of checkboxes so we can
// adjust row height in rowDelegate
CheckBox {
id: checkboxSize
visible: false
}
TreeView {
id: calendarTreeView;
anchors.fill: parent
model: calendarModel
TableViewColumn {
role: "data"
title: "Select Calendars";
delegate: Item {
CheckBox {
id: checkbox
visible: styleData.value["enabled"]
checked: styleData.value["checked"]
onCheckedChanged: {
if (checked == styleData.value["checked"]) {
return;
}
calendarModel.setChecked(styleData.value["id"], checked);
pimEventsConfig.configurationChanged();
}
width: 24
height: 24
}
IconItem {
id: icon
anchors.left: checkbox.visible ? checkbox.right : parent.left
visible: valid
source: styleData.value["iconName"]
height: 20
width: 20
}
Text {
anchors.left: icon.visible ? icon.right : checkbox.visible ? checkbox.right : parent.left
text: styleData.value["name"]
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
color: styleData.textColor
height: 24
}
}
}
// Based on Desktop.TableViewStyle
rowDelegate: BorderImage {
visible: styleData.selected || styleData.alternate
source: "image://__tablerow/" + (styleData.alternate ? "alternate_" : "")
+ (styleData.selected ? "selected_" : "")
+ (calendarTreeView.activeFocus ? "active" : "")
// Make sure the checkbox always fits, add 4 for some small margin
height: Math.min(checkboxSize.implicitHeight, Math.max(16, TextSingleton.implicitHeight * 1.2)) + 4
border {
left: 4
right: 4
}
}
}
}
/*
* Copyright (C) 2016 Daniel Vrátil <dvratil@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "akonadipimdatasource.h"
#include "settingschangenotifier.h"
#include "pimeventsplugin_debug.h"
#include <AkonadiCore/ChangeRecorder>
#include <AkonadiCore/ItemFetchScope>
#include <AkonadiCore/EntityDisplayAttribute>
#include <AkonadiCore/CollectionColorAttribute>
#include <AkonadiCore/AttributeFactory>
#include <Akonadi/Calendar/ETMCalendar>
#include <KSharedConfig>
#include <KConfigGroup>
#include <KCoreConfigSkeleton>
#include <EventViews/Prefs>
AkonadiPimDataSource::AkonadiPimDataSource(QObject *parent)
: QObject(parent)
{
Akonadi::AttributeFactory::registerAttribute<Akonadi::CollectionColorAttribute>();
connect(SettingsChangeNotifier::self(), &SettingsChangeNotifier::settingsChanged,
this, &AkonadiPimDataSource::onSettingsChanged);
mMonitor = new Akonadi::ChangeRecorder(this);
mMonitor->setChangeRecordingEnabled(false);
mMonitor->itemFetchScope().fetchFullPayload(true);
mMonitor->itemFetchScope().fetchAttribute<Akonadi::EntityDisplayAttribute>();
mMonitor->itemFetchScope().fetchAttribute<Akonadi::CollectionColorAttribute>();
onSettingsChanged();
mCalendar = new Akonadi::ETMCalendar(mMonitor, this);
// TOOD: Only retrieve PLD:HEAD once it's supported
mCalendar->setCollectionFilteringEnabled(false);
// Would be nice to have a proper API to read KOrganizer calendar colors...
KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("korganizerrc"));
KCoreConfigSkeleton *skel = new KCoreConfigSkeleton(config);
mEventViewsPrefs = EventViews::PrefsPtr(new EventViews::Prefs(skel));
mEventViewsPrefs->readConfig();
}
AkonadiPimDataSource::~AkonadiPimDataSource()
{
}
qint64 AkonadiPimDataSource::akonadiIdForIncidence(const KCalCore::Incidence::Ptr &incidence) const
{
return mCalendar->item(incidence).id();
}
KCalCore::Calendar *AkonadiPimDataSource::calendar() const
{
return mCalendar;
}
QString AkonadiPimDataSource::calendarColorForIncidence(const KCalCore::Incidence::Ptr &incidence) const
{
const auto &item = mCalendar->item(incidence);
if (!item.isValid()) {
return QString();
}
const auto &col = mCalendar->collection(item.parentCollection().id());
if (!col.isValid()) {
return QString();
}
auto it = mColorCache.find(col.id());
if (it == mColorCache.end()) {
if (col.hasAttribute<Akonadi::CollectionColorAttribute>()) {
const auto attr = col.attribute<Akonadi::CollectionColorAttribute>();
it = mColorCache.insert(col.id(), attr->color().name());
} else {
QColor color = mEventViewsPrefs->resourceColorKnown(QString::number(col.id()));
if (color.isValid()) {
it = mColorCache.insert(col.id(), color.name());
} else {
it = mColorCache.insert(col.id(), QString());
}
}
}
return (*it);
}
void AkonadiPimDataSource::onSettingsChanged()
{
QSet<Akonadi::Collection> currentCols;
Q_FOREACH (const Akonadi::Collection &col, mMonitor->collectionsMonitored()) {
currentCols.insert(col);
}
auto config = KSharedConfig::openConfig();
auto group = config->group("PIMEventsPlugin");
const QList<qint64> calendars = group.readEntry(QStringLiteral("calendars"), QList<qint64>());
QSet<Akonadi::Collection> configuredCols;
Q_FOREACH (qint64 colId, calendars) {
configuredCols.insert(Akonadi::Collection(colId));
}
Q_FOREACH (const Akonadi::Collection &col, (currentCols - configuredCols)) {
mMonitor->setCollectionMonitored(col, false);
}
Q_FOREACH (const Akonadi::Collection &col, (configuredCols - currentCols)) {
mMonitor->setCollectionMonitored(col, true);
}
const bool hasSelectedCols = mMonitor->collectionsMonitored().isEmpty();
mMonitor->setMimeTypeMonitored(KCalCore::Event::eventMimeType(), hasSelectedCols);
mMonitor->setMimeTypeMonitored(KCalCore::Todo::todoMimeType(), hasSelectedCols);
}
/*
* Copyright (C) 2016 Daniel Vrátil <dvratil@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef AKONADIPIMDATASOURCE_H
#define AKONADIPIMDATASOURCE_H
#include "pimdatasource.h"
#include <QObject>
#include <EventViews/Prefs>
namespace Akonadi {
class ChangeRecorder;
class ETMCalendar;
}
class AkonadiPimDataSource : public QObject,
public PimDataSource
{
Q_OBJECT
public:
explicit AkonadiPimDataSource(QObject *parent = Q_NULLPTR);
~AkonadiPimDataSource();
qint64 akonadiIdForIncidence(const KCalCore::Incidence::Ptr &incidence) const Q_DECL_OVERRIDE;
KCalCore::Calendar *calendar() const Q_DECL_OVERRIDE;
QString calendarColorForIncidence(const KCalCore::Incidence::Ptr &incidence) const Q_DECL_OVERRIDE;
private Q_SLOTS:
void onSettingsChanged();
private:
Akonadi::ChangeRecorder *mMonitor;
Akonadi::ETMCalendar *mCalendar;
EventViews::PrefsPtr mEventViewsPrefs;
mutable QHash<qint64, QString> mColorCache;
};
#endif
macro(add_plasma_pimeventsplugin_test _source _additional)
set(_test ${_source}
${_additional}
testdataparser.cpp
fakepimdatasource.cpp
${CMAKE_CURRENT_BINARY_DIR}/../pimeventsplugin_debug.cpp
)
get_filename_component(_name ${_source} NAME_WE)
add_executable(${_name} ${_test})
add_test(${_name} ${_name})
ecm_mark_as_test(plasma-pimeventsplugin-${_name})
add_definitions(-DQT_TESTCASE_BUILDDIR=\"${CMAKE_CURRENT_SOURCE_DIR}\")
target_link_libraries(${_name} Qt5::Core
Qt5::Test
KF5::AkonadiCore
KF5::AkonadiCalendar
KF5::CalendarCore
KF5::CalendarEvents
KF5::EventViews
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_BINARY_DIR}/..
)
endmacro()
add_plasma_pimeventsplugin_test(eventdatavisitortest.cpp ../eventdatavisitor.cpp)
add_plasma_pimeventsplugin_test(pimeventsplugintest.cpp "../eventdatavisitor.cpp;../pimeventsplugin.cpp;../akonadipimdatasource.cpp;../settingschangenotifier.cpp")
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTAMP:20160529T143409Z
CREATED:20160529T143351Z
UID:43f8fa38-6794-4862-a389-11e78d1ad584
LAST-MODIFIED:20160529T143409Z
DESCRIPTION:This is an all-day multi-day event
SUMMARY:Multi day all day event
DTSTART;VALUE=DATE:20160528
DTEND;VALUE=DATE:20160531
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
{
"rangeStart": "2016-05-01",
"rangeEnd": "2016-05-31",
"akonadiId": 1,
"eventData": [
{
"summary": "Multi day all day event",
"description": "This is an all-day multi-day event",
"type": "Event",
"allDay": true,
"isMinor": false,
"startDateTime": {
"date": "2016-05-28",
"time": ""
},
"endDateTime": {
"date": "2016-05-30",
"time": ""
},
"uid": "Akonadi-1"
}
]
}
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTAMP:20160529T143104Z
CREATED:20160529T143019Z
UID:c843300a-856d-4567-8ecc-a29255b6f5f5
LAST-MODIFIED:20160529T143104Z
DESCRIPTION:This is an all-day one day non-recurring event.
SUMMARY:All day one day non-recurring event
DTSTART;VALUE=DATE:20160529
DTEND;VALUE=DATE:20160530
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
{
"rangeStart": "2016-05-01",
"rangeEnd": "2016-05-31",
"akonadiId": 2,
"eventData": [
{
"summary": "All day one day non-recurring event",
"description": "This is an all-day one day non-recurring event.",
"type": "Event",
"allDay": true,
"isMinor": false,
"startDateTime": {
"date": "2016-05-29",
"time": ""
},
"endDateTime": {
"date": "2016-05-29",
"time": ""
},
"uid": "Akonadi-2"
}
]
}
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTAMP:20160529T143448Z
CREATED:20160529T143412Z
UID:1fceddbc-d1b9-4e20-8fea-1d36e191a42d
LAST-MODIFIED:20160529T143448Z
DESCRIPTION:This is an all-day multi-day recurring event
SUMMARY:All day multi-day recurring event
RRULE:FREQ=WEEKLY;BYDAY=FR
DTSTART;VALUE=DATE:20160408
DTEND;VALUE=DATE:20160411
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
{
"rangeStart": "2016-05-01",
"rangeEnd": "2016-05-31",
"akonadiId": 3,
"eventData": [
{
"summary": "All day multi-day recurring event",
"description": "This is an all-day multi-day recurring event",
"type": "Event",
"allDay": true,
"isMinor": false,
"startDateTime": {
"date": "2016-05-06",
"time": ""
},
"endDateTime": {
"date": "2016-05-08",
"time": ""
},
"uid": "Akonadi-3-20160506T000000"
},
{
"summary": "All day multi-day recurring event",
"description": "This is an all-day multi-day recurring event",
"type": "Event",
"allDay": true,
"isMinor": false,
"startDateTime": {
"date": "2016-05-13",
"time": ""
},
"endDateTime": {
"date": "2016-05-15",
"time": ""
},
"uid": "Akonadi-3-20160513T000000"
},
{
"summary": "All day multi-day recurring event",
"description": "This is an all-day multi-day recurring event",