2013-11-13 13:41:04 +01:00
|
|
|
/*
|
2020-08-13 21:08:54 +02:00
|
|
|
SPDX-FileCopyrightText: 2013 Mark Gaiser <markg85@gmail.com>
|
|
|
|
SPDX-FileCopyrightText: 2016 Martin Klapetek <mklapetek@kde.org>
|
2021-04-29 23:38:46 +02:00
|
|
|
SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
|
2013-11-13 13:41:04 +01:00
|
|
|
|
2020-08-13 21:08:54 +02:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
2013-11-13 13:41:04 +01:00
|
|
|
*/
|
|
|
|
|
2013-08-31 15:23:04 +02:00
|
|
|
#include "daysmodel.h"
|
2015-11-04 19:55:32 +01:00
|
|
|
#include "eventdatadecorator.h"
|
|
|
|
#include "eventpluginsmanager.h"
|
2015-11-02 21:33:15 +01:00
|
|
|
|
2013-08-31 15:23:04 +02:00
|
|
|
#include <QByteArray>
|
2021-03-05 19:15:32 +01:00
|
|
|
#include <QDebug>
|
2015-11-02 21:33:15 +01:00
|
|
|
#include <QDir>
|
2015-12-02 18:57:47 +01:00
|
|
|
#include <QMetaObject>
|
2013-08-31 15:23:04 +02:00
|
|
|
|
2021-06-03 15:32:20 +02:00
|
|
|
constexpr int maxEventDisplayed = 5;
|
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
DaysModel::DaysModel(QObject *parent)
|
2021-04-29 23:38:46 +02:00
|
|
|
: QAbstractItemModel(parent)
|
2021-03-05 19:15:32 +01:00
|
|
|
, m_pluginsManager(nullptr)
|
|
|
|
, m_lastRequestedEventsStartDate(QDate())
|
|
|
|
, m_agendaNeedsUpdate(false)
|
2013-08-31 15:23:04 +02:00
|
|
|
{
|
2015-11-02 21:33:15 +01:00
|
|
|
}
|
2013-08-31 15:23:04 +02:00
|
|
|
|
2015-11-02 21:33:15 +01:00
|
|
|
DaysModel::~DaysModel()
|
|
|
|
{
|
|
|
|
qDeleteAll(m_eventPlugins);
|
2013-08-31 15:23:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DaysModel::setSourceData(QList<DayData> *data)
|
|
|
|
{
|
2014-04-26 01:45:47 +02:00
|
|
|
if (m_data != data) {
|
2016-12-28 16:15:42 +01:00
|
|
|
beginResetModel();
|
2013-08-31 15:23:04 +02:00
|
|
|
m_data = data;
|
2016-12-28 16:15:42 +01:00
|
|
|
endResetModel();
|
2013-08-31 15:23:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int DaysModel::rowCount(const QModelIndex &parent) const
|
|
|
|
{
|
2021-04-29 23:38:46 +02:00
|
|
|
if (!parent.isValid()) {
|
|
|
|
// day count
|
|
|
|
if (m_data->size() <= 0) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return m_data->size();
|
|
|
|
}
|
2013-08-31 15:23:04 +02:00
|
|
|
} else {
|
2021-04-29 23:38:46 +02:00
|
|
|
// event count
|
|
|
|
const auto &eventDatas = data(parent, Roles::Events).value<QList<CalendarEvents::EventData>>();
|
2021-06-03 15:32:20 +02:00
|
|
|
Q_ASSERT(eventDatas.count() <= maxEventDisplayed);
|
2021-04-29 23:38:46 +02:00
|
|
|
return eventDatas.count();
|
2013-08-31 15:23:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-29 23:38:46 +02:00
|
|
|
int DaysModel::columnCount(const QModelIndex &parent) const
|
|
|
|
{
|
|
|
|
Q_UNUSED(parent)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-08-31 15:23:04 +02:00
|
|
|
QVariant DaysModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
2021-04-29 23:38:46 +02:00
|
|
|
if (!index.isValid()) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const int row = index.row();
|
|
|
|
|
|
|
|
if (!index.parent().isValid()) {
|
|
|
|
// Fetch days in month
|
|
|
|
const DayData ¤tData = m_data->at(row);
|
2015-11-02 21:33:15 +01:00
|
|
|
const QDate currentDate(currentData.yearNumber, currentData.monthNumber, currentData.dayNumber);
|
2013-08-31 15:23:04 +02:00
|
|
|
|
2014-04-26 01:45:47 +02:00
|
|
|
switch (role) {
|
2015-07-27 11:41:35 +02:00
|
|
|
case isCurrent:
|
|
|
|
return currentData.isCurrent;
|
2015-11-02 21:33:15 +01:00
|
|
|
case containsEventItems:
|
|
|
|
return m_eventsData.contains(currentDate);
|
2021-04-29 23:38:46 +02:00
|
|
|
case Events:
|
|
|
|
return QVariant::fromValue(m_eventsData.values(currentDate));
|
|
|
|
case EventCount:
|
|
|
|
return m_eventsData.values(currentDate).count();
|
Fix PlasmaCalendar widget to not mark days with minor events
Summary:
CalendarEvents::EventData (in KDeclarative) has a property isMinor, which is
described as "If set to true, it won't be marked in the calendar grid".
This patch fulfils that promise, by introducing separate roles on the model
which explicitly report the existance of any major or any minor events at a
given day, so that the marker loader can concentrate on the major events.
Test Plan:
Using a plasmacalendar plugin which feeds events with isMinor=true the
widget now only marks days which have major events.
Reviewers: #plasma, broulik, davidedmundson
Reviewed By: #plasma, broulik, davidedmundson
Subscribers: davidedmundson, broulik, #frameworks
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D12438
2018-04-22 12:09:10 +02:00
|
|
|
case containsMajorEventItems:
|
|
|
|
return hasMajorEventAtDate(currentDate);
|
|
|
|
case containsMinorEventItems:
|
|
|
|
return hasMinorEventAtDate(currentDate);
|
2013-08-31 15:23:04 +02:00
|
|
|
case dayNumber:
|
|
|
|
return currentData.dayNumber;
|
|
|
|
case monthNumber:
|
|
|
|
return currentData.monthNumber;
|
|
|
|
case yearNumber:
|
|
|
|
return currentData.yearNumber;
|
|
|
|
}
|
2021-04-29 23:38:46 +02:00
|
|
|
} else {
|
|
|
|
// Fetch event in day
|
|
|
|
const auto &eventDatas = data(index.parent(), Roles::Events).value<QList<CalendarEvents::EventData>>();
|
|
|
|
if (eventDatas.count() < row) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto &eventData = eventDatas[row];
|
|
|
|
switch (role) {
|
|
|
|
case EventColor:
|
|
|
|
return eventData.eventColor();
|
|
|
|
}
|
2013-08-31 15:23:04 +02:00
|
|
|
}
|
2021-04-29 23:38:46 +02:00
|
|
|
return {};
|
2013-08-31 15:23:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DaysModel::update()
|
|
|
|
{
|
2014-04-26 01:45:47 +02:00
|
|
|
if (m_data->size() <= 0) {
|
2013-08-31 15:23:04 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-29 23:38:46 +02:00
|
|
|
// We need to reset the model since m_data has already been changed here
|
|
|
|
// and we can't remove the events manually with beginRemoveRows() since
|
|
|
|
// we don't know where the old events were located.
|
|
|
|
beginResetModel();
|
2015-11-02 21:33:15 +01:00
|
|
|
m_eventsData.clear();
|
2021-04-29 23:38:46 +02:00
|
|
|
endResetModel();
|
2015-11-02 21:33:15 +01:00
|
|
|
|
|
|
|
const QDate modelFirstDay(m_data->at(0).yearNumber, m_data->at(0).monthNumber, m_data->at(0).dayNumber);
|
|
|
|
|
2015-11-04 19:55:32 +01:00
|
|
|
if (m_pluginsManager) {
|
2019-03-20 07:12:03 +01:00
|
|
|
const auto plugins = m_pluginsManager->plugins();
|
|
|
|
for (CalendarEvents::CalendarEventsPlugin *eventsPlugin : plugins) {
|
2015-11-04 19:55:32 +01:00
|
|
|
eventsPlugin->loadEventsForDateRange(modelFirstDay, modelFirstDay.addDays(42));
|
|
|
|
}
|
2015-11-02 21:33:15 +01:00
|
|
|
}
|
2016-08-14 11:48:11 +02:00
|
|
|
|
|
|
|
// We always have 42 items (or weeks * num of days in week) so we only have to tell the view that the data changed.
|
2021-01-18 12:08:40 +01:00
|
|
|
Q_EMIT dataChanged(index(0, 0), index(m_data->count() - 1, 0));
|
2015-11-02 21:33:15 +01:00
|
|
|
}
|
|
|
|
|
2015-11-16 20:26:26 +01:00
|
|
|
void DaysModel::onDataReady(const QMultiHash<QDate, CalendarEvents::EventData> &data)
|
2015-11-02 21:33:15 +01:00
|
|
|
{
|
|
|
|
m_eventsData.reserve(m_eventsData.size() + data.size());
|
2021-04-29 23:38:46 +02:00
|
|
|
for (int i = 0; i < m_data->count(); i++) {
|
|
|
|
const DayData ¤tData = m_data->at(i);
|
|
|
|
const QDate currentDate(currentData.yearNumber, currentData.monthNumber, currentData.dayNumber);
|
|
|
|
if (!data.values(currentDate).isEmpty()) {
|
2021-06-03 15:32:20 +02:00
|
|
|
// Make sure we don't display more than maxEventDisplayed events.
|
2021-04-29 23:38:46 +02:00
|
|
|
const int currentCount = m_eventsData.values(currentDate).count();
|
2021-06-03 15:32:20 +02:00
|
|
|
if (currentCount >= maxEventDisplayed) {
|
2021-04-29 23:38:46 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-06-03 15:32:20 +02:00
|
|
|
const int addedEventCount = std::min(currentCount + data.values(currentDate).count(), maxEventDisplayed) - currentCount;
|
2021-04-29 23:38:46 +02:00
|
|
|
|
|
|
|
// Add event
|
2021-06-03 15:32:20 +02:00
|
|
|
beginInsertRows(index(i, 0), 0, addedEventCount - 1);
|
|
|
|
int stopCounter = currentCount;
|
2021-04-29 23:38:46 +02:00
|
|
|
for (const auto &dataDay : data.values(currentDate)) {
|
2021-06-03 15:32:20 +02:00
|
|
|
if (stopCounter >= maxEventDisplayed) {
|
2021-04-29 23:38:46 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
stopCounter++;
|
|
|
|
m_eventsData.insert(currentDate, dataDay);
|
|
|
|
}
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
}
|
2016-04-21 05:41:13 +02:00
|
|
|
|
2016-05-30 01:14:36 +02:00
|
|
|
if (data.contains(QDate::currentDate())) {
|
|
|
|
m_agendaNeedsUpdate = true;
|
|
|
|
}
|
2016-08-14 11:48:11 +02:00
|
|
|
|
Fix PlasmaCalendar widget to not mark days with minor events
Summary:
CalendarEvents::EventData (in KDeclarative) has a property isMinor, which is
described as "If set to true, it won't be marked in the calendar grid".
This patch fulfils that promise, by introducing separate roles on the model
which explicitly report the existance of any major or any minor events at a
given day, so that the marker loader can concentrate on the major events.
Test Plan:
Using a plasmacalendar plugin which feeds events with isMinor=true the
widget now only marks days which have major events.
Reviewers: #plasma, broulik, davidedmundson
Reviewed By: #plasma, broulik, davidedmundson
Subscribers: davidedmundson, broulik, #frameworks
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D12438
2018-04-22 12:09:10 +02:00
|
|
|
// only the containsEventItems roles may have changed
|
2021-04-29 23:38:46 +02:00
|
|
|
Q_EMIT dataChanged(index(0, 0), index(m_data->count() - 1, 0), {containsEventItems, containsMajorEventItems, containsMinorEventItems, Events, EventCount});
|
2016-08-14 11:48:11 +02:00
|
|
|
|
2016-04-21 05:41:13 +02:00
|
|
|
Q_EMIT agendaUpdated(QDate::currentDate());
|
2013-08-31 15:23:04 +02:00
|
|
|
}
|
|
|
|
|
2015-11-16 20:26:26 +01:00
|
|
|
void DaysModel::onEventModified(const CalendarEvents::EventData &data)
|
2015-11-02 21:33:15 +01:00
|
|
|
{
|
|
|
|
QList<QDate> updatesList;
|
|
|
|
auto i = m_eventsData.begin();
|
|
|
|
while (i != m_eventsData.end()) {
|
|
|
|
if (i->uid() == data.uid()) {
|
|
|
|
*i = data;
|
|
|
|
updatesList << i.key();
|
|
|
|
}
|
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!updatesList.isEmpty()) {
|
|
|
|
m_agendaNeedsUpdate = true;
|
|
|
|
}
|
|
|
|
|
2019-03-20 07:12:03 +01:00
|
|
|
for (const QDate date : qAsConst(updatesList)) {
|
2015-11-02 21:33:15 +01:00
|
|
|
const QModelIndex changedIndex = indexForDate(date);
|
|
|
|
if (changedIndex.isValid()) {
|
2021-04-29 23:38:46 +02:00
|
|
|
Q_EMIT dataChanged(changedIndex, changedIndex, {containsEventItems, containsMajorEventItems, containsMinorEventItems, EventColor});
|
2015-11-02 21:33:15 +01:00
|
|
|
}
|
|
|
|
Q_EMIT agendaUpdated(date);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DaysModel::onEventRemoved(const QString &uid)
|
|
|
|
{
|
2021-04-29 23:38:46 +02:00
|
|
|
// HACK We should update the model with beginRemoveRows instead of
|
|
|
|
// using beginResetModel() since this creates a small visual glitches
|
|
|
|
// if an event is removed in Korganizer and the calendar is open.
|
|
|
|
// Using beginRemoveRows instead we make the code a lot more complex
|
2021-07-14 10:55:55 +02:00
|
|
|
// and if not done correctly will introduce bugs.
|
2021-04-29 23:38:46 +02:00
|
|
|
beginResetModel();
|
2015-11-02 21:33:15 +01:00
|
|
|
QList<QDate> updatesList;
|
|
|
|
auto i = m_eventsData.begin();
|
|
|
|
while (i != m_eventsData.end()) {
|
|
|
|
if (i->uid() == uid) {
|
|
|
|
updatesList << i.key();
|
|
|
|
i = m_eventsData.erase(i);
|
|
|
|
} else {
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!updatesList.isEmpty()) {
|
|
|
|
m_agendaNeedsUpdate = true;
|
|
|
|
}
|
|
|
|
|
2019-03-20 07:12:03 +01:00
|
|
|
for (const QDate date : qAsConst(updatesList)) {
|
2015-11-02 21:33:15 +01:00
|
|
|
const QModelIndex changedIndex = indexForDate(date);
|
|
|
|
if (changedIndex.isValid()) {
|
2021-03-05 19:15:32 +01:00
|
|
|
Q_EMIT dataChanged(changedIndex, changedIndex, {containsEventItems, containsMajorEventItems, containsMinorEventItems});
|
2015-11-02 21:33:15 +01:00
|
|
|
}
|
2021-04-29 23:38:46 +02:00
|
|
|
|
2015-11-02 21:33:15 +01:00
|
|
|
Q_EMIT agendaUpdated(date);
|
|
|
|
}
|
2021-04-29 23:38:46 +02:00
|
|
|
endResetModel();
|
2015-11-02 21:33:15 +01:00
|
|
|
}
|
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
QList<QObject *> DaysModel::eventsForDate(const QDate &date)
|
2015-11-02 21:33:15 +01:00
|
|
|
{
|
|
|
|
if (m_lastRequestedAgendaDate == date && !m_agendaNeedsUpdate) {
|
|
|
|
return m_qmlData;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_lastRequestedAgendaDate = date;
|
|
|
|
qDeleteAll(m_qmlData);
|
|
|
|
m_qmlData.clear();
|
|
|
|
|
2015-11-18 01:07:10 +01:00
|
|
|
QList<CalendarEvents::EventData> events = m_eventsData.values(date);
|
2015-11-02 21:33:15 +01:00
|
|
|
m_qmlData.reserve(events.size());
|
|
|
|
|
2015-11-18 01:07:10 +01:00
|
|
|
// sort events by their time and type
|
|
|
|
std::sort(events.begin(), events.end(), [](const CalendarEvents::EventData &a, const CalendarEvents::EventData &b) {
|
|
|
|
return b.type() > a.type() || b.startDateTime() > a.startDateTime();
|
|
|
|
});
|
|
|
|
|
2019-03-20 07:12:03 +01:00
|
|
|
for (const CalendarEvents::EventData &event : qAsConst(events)) {
|
2015-11-02 21:33:15 +01:00
|
|
|
m_qmlData << new EventDataDecorator(event, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_agendaNeedsUpdate = false;
|
|
|
|
return m_qmlData;
|
|
|
|
}
|
|
|
|
|
|
|
|
QModelIndex DaysModel::indexForDate(const QDate &date)
|
|
|
|
{
|
|
|
|
if (!m_data) {
|
|
|
|
return QModelIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
const DayData &firstDay = m_data->at(0);
|
|
|
|
const QDate firstDate(firstDay.yearNumber, firstDay.monthNumber, firstDay.dayNumber);
|
|
|
|
|
|
|
|
qint64 daysTo = firstDate.daysTo(date);
|
|
|
|
|
|
|
|
return createIndex(daysTo, 0);
|
|
|
|
}
|
2015-11-04 19:55:32 +01:00
|
|
|
|
Fix PlasmaCalendar widget to not mark days with minor events
Summary:
CalendarEvents::EventData (in KDeclarative) has a property isMinor, which is
described as "If set to true, it won't be marked in the calendar grid".
This patch fulfils that promise, by introducing separate roles on the model
which explicitly report the existance of any major or any minor events at a
given day, so that the marker loader can concentrate on the major events.
Test Plan:
Using a plasmacalendar plugin which feeds events with isMinor=true the
widget now only marks days which have major events.
Reviewers: #plasma, broulik, davidedmundson
Reviewed By: #plasma, broulik, davidedmundson
Subscribers: davidedmundson, broulik, #frameworks
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D12438
2018-04-22 12:09:10 +02:00
|
|
|
bool DaysModel::hasMajorEventAtDate(const QDate &date) const
|
|
|
|
{
|
|
|
|
auto it = m_eventsData.find(date);
|
|
|
|
while (it != m_eventsData.end() && it.key() == date) {
|
|
|
|
if (!it.value().isMinor()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DaysModel::hasMinorEventAtDate(const QDate &date) const
|
|
|
|
{
|
|
|
|
auto it = m_eventsData.find(date);
|
|
|
|
while (it != m_eventsData.end() && it.key() == date) {
|
|
|
|
if (it.value().isMinor()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-04 19:55:32 +01:00
|
|
|
void DaysModel::setPluginsManager(QObject *manager)
|
|
|
|
{
|
2021-03-05 19:15:32 +01:00
|
|
|
EventPluginsManager *m = qobject_cast<EventPluginsManager *>(manager);
|
2015-11-04 19:55:32 +01:00
|
|
|
|
|
|
|
if (!m) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-13 09:05:17 +02:00
|
|
|
if (m_pluginsManager) {
|
2015-11-04 19:55:32 +01:00
|
|
|
m_pluginsManager->deleteLater();
|
2018-04-13 09:05:17 +02:00
|
|
|
m_pluginsManager = nullptr;
|
2015-11-04 19:55:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
m_pluginsManager = m;
|
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
connect(m_pluginsManager, &EventPluginsManager::dataReady, this, &DaysModel::onDataReady);
|
|
|
|
connect(m_pluginsManager, &EventPluginsManager::eventModified, this, &DaysModel::onEventModified);
|
|
|
|
connect(m_pluginsManager, &EventPluginsManager::eventRemoved, this, &DaysModel::onEventRemoved);
|
|
|
|
connect(m_pluginsManager, &EventPluginsManager::pluginsChanged, this, &DaysModel::update);
|
2015-11-04 19:55:32 +01:00
|
|
|
|
2015-12-02 18:57:47 +01:00
|
|
|
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
2015-11-04 19:55:32 +01:00
|
|
|
}
|
2017-03-06 13:36:17 +01:00
|
|
|
|
|
|
|
QHash<int, QByteArray> DaysModel::roleNames() const
|
|
|
|
{
|
2021-03-05 19:15:32 +01:00
|
|
|
return {{isCurrent, "isCurrent"},
|
|
|
|
{containsEventItems, "containsEventItems"},
|
|
|
|
{containsMajorEventItems, "containsMajorEventItems"},
|
|
|
|
{containsMinorEventItems, "containsMinorEventItems"},
|
|
|
|
{dayNumber, "dayNumber"},
|
|
|
|
{monthNumber, "monthNumber"},
|
2021-04-29 23:38:46 +02:00
|
|
|
{yearNumber, "yearNumber"},
|
|
|
|
{EventColor, "eventColor"},
|
|
|
|
{EventCount, "eventCount"},
|
|
|
|
{Events, "events"}};
|
2017-03-06 13:36:17 +01:00
|
|
|
}
|
2021-04-29 23:38:46 +02:00
|
|
|
|
|
|
|
QModelIndex DaysModel::index(int row, int column, const QModelIndex &parent) const
|
|
|
|
{
|
|
|
|
if (parent.isValid()) {
|
|
|
|
return createIndex(row, column, (intptr_t)parent.row());
|
|
|
|
}
|
|
|
|
return createIndex(row, column, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
QModelIndex DaysModel::parent(const QModelIndex &child) const
|
|
|
|
{
|
|
|
|
if (child.internalId()) {
|
|
|
|
return createIndex(child.internalId(), 0, nullptr);
|
|
|
|
}
|
|
|
|
return QModelIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_DECLARE_METATYPE(CalendarEvents::EventData)
|