diff --git a/src/declarativeimports/calendar/daysmodel.cpp b/src/declarativeimports/calendar/daysmodel.cpp index df5260b6a..6961b6b1b 100644 --- a/src/declarativeimports/calendar/daysmodel.cpp +++ b/src/declarativeimports/calendar/daysmodel.cpp @@ -1,246 +1,249 @@ /* Copyright (C) 2013 Mark Gaiser Copyright (C) 2016 Martin Klapetek 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 "daysmodel.h" #include "eventdatadecorator.h" #include "eventpluginsmanager.h" #include #include #include #include DaysModel::DaysModel(QObject *parent) : QAbstractListModel(parent), m_pluginsManager(0), m_lastRequestedEventsStartDate(QDate()), m_agendaNeedsUpdate(false) { - QHash roleNames; - roleNames.insert(isCurrent, "isCurrent"); - roleNames.insert(containsEventItems, "containsEventItems"); - roleNames.insert(dayNumber, "dayNumber"); - roleNames.insert(monthNumber, "monthNumber"); - roleNames.insert(yearNumber, "yearNumber"); - - setRoleNames(roleNames); } DaysModel::~DaysModel() { qDeleteAll(m_eventPlugins); } void DaysModel::setSourceData(QList *data) { if (m_data != data) { beginResetModel(); m_data = data; endResetModel(); } } int DaysModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) if (m_data->size() <= 0) { return 0; } else { return m_data->size(); } } QVariant DaysModel::data(const QModelIndex &index, int role) const { if (index.isValid()) { const DayData ¤tData = m_data->at(index.row()); const QDate currentDate(currentData.yearNumber, currentData.monthNumber, currentData.dayNumber); switch (role) { case isCurrent: return currentData.isCurrent; case containsEventItems: return m_eventsData.contains(currentDate); case dayNumber: return currentData.dayNumber; case monthNumber: return currentData.monthNumber; case yearNumber: return currentData.yearNumber; } } return QVariant(); } void DaysModel::update() { if (m_data->size() <= 0) { return; } m_eventsData.clear(); const QDate modelFirstDay(m_data->at(0).yearNumber, m_data->at(0).monthNumber, m_data->at(0).dayNumber); if (m_pluginsManager) { Q_FOREACH (CalendarEvents::CalendarEventsPlugin *eventsPlugin, m_pluginsManager->plugins()) { eventsPlugin->loadEventsForDateRange(modelFirstDay, modelFirstDay.addDays(42)); } } // We always have 42 items (or weeks * num of days in week) so we only have to tell the view that the data changed. emit dataChanged(index(0, 0), index(m_data->count() - 1, 0)); } void DaysModel::onDataReady(const QMultiHash &data) { m_eventsData.reserve(m_eventsData.size() + data.size()); m_eventsData += data; if (data.contains(QDate::currentDate())) { m_agendaNeedsUpdate = true; } // only the containsEventItems role may have changed emit dataChanged(index(0, 0), index(m_data->count() - 1, 0), {containsEventItems}); Q_EMIT agendaUpdated(QDate::currentDate()); } void DaysModel::onEventModified(const CalendarEvents::EventData &data) { QList 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; } Q_FOREACH (const QDate date, updatesList) { const QModelIndex changedIndex = indexForDate(date); if (changedIndex.isValid()) { Q_EMIT dataChanged(changedIndex, changedIndex, {containsEventItems}); } Q_EMIT agendaUpdated(date); } } void DaysModel::onEventRemoved(const QString &uid) { QList 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; } Q_FOREACH (const QDate date, updatesList) { const QModelIndex changedIndex = indexForDate(date); if (changedIndex.isValid()) { Q_EMIT dataChanged(changedIndex, changedIndex, {containsEventItems}); } Q_EMIT agendaUpdated(date); } } QList DaysModel::eventsForDate(const QDate &date) { if (m_lastRequestedAgendaDate == date && !m_agendaNeedsUpdate) { return m_qmlData; } m_lastRequestedAgendaDate = date; qDeleteAll(m_qmlData); m_qmlData.clear(); QList events = m_eventsData.values(date); m_qmlData.reserve(events.size()); // 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(); }); Q_FOREACH (const CalendarEvents::EventData &event, events) { 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); } void DaysModel::setPluginsManager(QObject *manager) { EventPluginsManager *m = qobject_cast(manager); if (!m) { return; } if (m_pluginsManager != 0) { m_pluginsManager->deleteLater(); m_pluginsManager = 0; } m_pluginsManager = m; 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); QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); } + +QHash DaysModel::roleNames() const +{ + return { + {isCurrent, "isCurrent"}, + {containsEventItems, "containsEventItems"}, + {dayNumber, "dayNumber"}, + {monthNumber, "monthNumber"}, + {yearNumber, "yearNumber"} + }; +} diff --git a/src/declarativeimports/calendar/daysmodel.h b/src/declarativeimports/calendar/daysmodel.h index 62b955be2..c2423a53d 100644 --- a/src/declarativeimports/calendar/daysmodel.h +++ b/src/declarativeimports/calendar/daysmodel.h @@ -1,81 +1,83 @@ /* Copyright (C) 2013 Mark Gaiser Copyright (C) 2016 Martin Klapetek 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 DAYSMODEL_H #define DAYSMODEL_H #include #include "daydata.h" #include class EventPluginsManager; class DaysModel : public QAbstractListModel { Q_OBJECT public: enum Roles { isCurrent = Qt::UserRole + 1, //containsHolidayItems, containsEventItems, //containsTodoItems, //containsJournalItems, dayNumber, monthNumber, yearNumber }; explicit DaysModel(QObject *parent = 0); virtual ~DaysModel(); void setSourceData(QList *data); int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; Q_INVOKABLE void setPluginsManager(QObject *manager); Q_INVOKABLE QList eventsForDate(const QDate &date); + QHash roleNames() const Q_DECL_OVERRIDE; + Q_SIGNALS: void agendaUpdated(const QDate &updatedDate); public Q_SLOTS: void update(); private Q_SLOTS: void onDataReady(const QMultiHash &data); void onEventModified(const CalendarEvents::EventData &data); void onEventRemoved(const QString &uid); private: QModelIndex indexForDate(const QDate &date); EventPluginsManager *m_pluginsManager; QList *m_data; QList m_qmlData; QDate m_lastRequestedAgendaDate; QList m_eventPlugins; QMultiHash m_eventsData; QDate m_lastRequestedEventsStartDate; // this is always this+42 days bool m_agendaNeedsUpdate; }; #endif // DAYSMODEL_H diff --git a/src/plasmaquick/configmodel.cpp b/src/plasmaquick/configmodel.cpp index 65b9b8da4..9a4b38ca4 100644 --- a/src/plasmaquick/configmodel.cpp +++ b/src/plasmaquick/configmodel.cpp @@ -1,312 +1,316 @@ /* * Copyright 2013 Marco Martin * Copyright 2015 Eike Hein * * This program 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, 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 Library 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 "private/configcategory_p.h" #include "configview.h" #include "configmodel.h" #include "Plasma/Applet" #include "Plasma/Containment" //#include "plasmoid/wallpaperinterface.h" #include "kdeclarative/configpropertymap.h" #include #include #include #include #include #include #include #include #include #include #include namespace PlasmaQuick { //////////////////////////////ConfigModel class ConfigModelPrivate { public: ConfigModelPrivate(ConfigModel *model); ~ConfigModelPrivate(); ConfigModel *q; QList categories; QWeakPointer appletInterface; QHash kcms; void appendCategory(ConfigCategory *c); void clear(); QVariant get(int row) const; static ConfigCategory *categories_at(QQmlListProperty *prop, int index); static void categories_append(QQmlListProperty *prop, ConfigCategory *o); static int categories_count(QQmlListProperty *prop); static void categories_clear(QQmlListProperty *prop); }; ConfigModelPrivate::ConfigModelPrivate(ConfigModel *model) : q(model) { } ConfigModelPrivate::~ConfigModelPrivate() { } ConfigCategory *ConfigModelPrivate::categories_at(QQmlListProperty *prop, int index) { ConfigModel *model = qobject_cast(prop->object); if (!model || index >= model->d->categories.count() || index < 0) { return 0; } else { return model->d->categories.at(index); } } void ConfigModelPrivate::categories_append(QQmlListProperty *prop, ConfigCategory *o) { ConfigModel *model = qobject_cast(prop->object); if (!o || !model) { return; } if (o->parent() == prop->object) { o->setParent(0); } o->setParent(prop->object); model->d->appendCategory(o); } int ConfigModelPrivate::categories_count(QQmlListProperty *prop) { ConfigModel *model = qobject_cast(prop->object); if (model) { return model->d->categories.count(); } else { return 0; } } void ConfigModelPrivate::categories_clear(QQmlListProperty *prop) { ConfigModel *model = qobject_cast(prop->object); if (!model) { return; } model->clear(); } void ConfigModelPrivate::clear() { q->beginResetModel(); while (!categories.isEmpty()) { categories.first()->setParent(0); categories.pop_front(); } q->endResetModel(); emit q->countChanged(); } void ConfigModelPrivate::appendCategory(ConfigCategory *c) { q->beginInsertRows(QModelIndex(), categories.size(), categories.size()); categories.append(c); auto emitChange = [this, c] { const int row = categories.indexOf(c); if (row > -1) { QModelIndex modelIndex = q->index(row); emit q->dataChanged(modelIndex, modelIndex); } }; QObject::connect(c, &ConfigCategory::nameChanged, q, emitChange); QObject::connect(c, &ConfigCategory::iconChanged, q, emitChange); QObject::connect(c, &ConfigCategory::sourceChanged, q, emitChange); QObject::connect(c, &ConfigCategory::pluginNameChanged, q, emitChange); QObject::connect(c, &ConfigCategory::visibleChanged, q, emitChange); q->endInsertRows(); emit q->countChanged(); } QVariant ConfigModelPrivate::get(int row) const { QVariantMap value; if (row < 0 || row >= categories.count()) { return value; } value[QStringLiteral("name")] = categories.at(row)->name(); value[QStringLiteral("icon")] = categories.at(row)->icon(); value[QStringLiteral("pluginName")] = categories.at(row)->pluginName(); value[QStringLiteral("source")] = q->data(q->index(row, 0), ConfigModel::SourceRole); value[QStringLiteral("visible")] = categories.at(row)->visible(); value[QStringLiteral("kcm")] = q->data(q->index(row, 0), ConfigModel::KCMRole); return value; } ConfigModel::ConfigModel(QObject *parent) : QAbstractListModel(parent), d(new ConfigModelPrivate(this)) { - QHash roleNames; - roleNames[NameRole] = "name"; - roleNames[IconRole] = "icon"; - roleNames[SourceRole] = "source"; - roleNames[PluginNameRole] = "pluginName"; - roleNames[VisibleRole] = "visible"; - roleNames[KCMRole] = "kcm"; - - setRoleNames(roleNames); + } ConfigModel::~ConfigModel() { delete d; } int ConfigModel::rowCount(const QModelIndex &index) const { if (index.column() > 0) { return 0; } return d->categories.count(); } QVariant ConfigModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= d->categories.count()) { return QVariant(); } switch (role) { case NameRole: return d->categories.at(index.row())->name(); case IconRole: return d->categories.at(index.row())->icon(); case SourceRole: { const QString source = d->categories.at(index.row())->source(); // Quick check if source is an absolute path or not if (d->appletInterface && !source.isEmpty() && !(source.startsWith('/') && source.endsWith(QLatin1String("qml")))) { if(!d->appletInterface.data()->kPackage().isValid()) qWarning() << "wrong applet" << d->appletInterface.data()->pluginMetaData().name(); return QUrl::fromLocalFile(d->appletInterface.data()->kPackage().filePath("ui", source)); } else { return source; } } case PluginNameRole: return d->categories.at(index.row())->pluginName(); case VisibleRole: return d->categories.at(index.row())->visible(); case KCMRole: { const QString pluginName = d->categories.at(index.row())->pluginName(); const QString pluginPath = KPluginLoader::findPlugin(pluginName); //no kcm is registered for this row, it's a normal qml-only entry if (pluginName.isEmpty() || pluginPath.isEmpty()) { return QVariant(); } if (d->kcms.contains(pluginName)) { return QVariant::fromValue(d->kcms.value(pluginName)); } KPluginLoader loader(pluginPath); KPluginFactory* factory = loader.factory(); if (!factory) { qWarning() << "Error loading KCM:" << loader.errorString(); } else { KQuickAddons::ConfigModule *cm = factory->create(const_cast(this)); if (!cm) { qWarning() << "Error creating KCM object from plugin" << loader.fileName(); } d->kcms[pluginName] = cm; return QVariant::fromValue(cm); } } default: return QVariant(); } } +QHash ConfigModel::roleNames() const +{ + return { + {NameRole, "name"}, + {IconRole, "icon"}, + {SourceRole, "source"}, + {PluginNameRole, "pluginName"}, + {VisibleRole, "visible"}, + {KCMRole, "kcm"}, + }; +} + QVariant ConfigModel::get(int row) const { return d->get(row); } void ConfigModel::appendCategory(const QString &iconName, const QString &name, const QString &path, const QString &pluginName) { ConfigCategory *cat = new ConfigCategory(this); cat->setIcon(iconName); cat->setName(name); cat->setSource(path); cat->setPluginName(pluginName); d->appendCategory(cat); } void ConfigModel::appendCategory(const QString &iconName, const QString &name, const QString &path, const QString &pluginName, bool visible) { ConfigCategory *cat = new ConfigCategory(this); cat->setIcon(iconName); cat->setName(name); cat->setSource(path); cat->setPluginName(pluginName); cat->setVisible(visible); d->appendCategory(cat); } void ConfigModel::clear() { d->clear(); } void ConfigModel::setApplet(Plasma::Applet *interface) { d->appletInterface = interface; } Plasma::Applet *ConfigModel::applet() const { return d->appletInterface.data(); } QQmlListProperty ConfigModel::categories() { return QQmlListProperty(this, 0, ConfigModelPrivate::categories_append, ConfigModelPrivate::categories_count, ConfigModelPrivate::categories_at, ConfigModelPrivate::categories_clear); } } #include "moc_configmodel.cpp" diff --git a/src/plasmaquick/configmodel.h b/src/plasmaquick/configmodel.h index 7a5e72c52..f95649fe9 100644 --- a/src/plasmaquick/configmodel.h +++ b/src/plasmaquick/configmodel.h @@ -1,128 +1,129 @@ /* * Copyright 2013 Marco Martin * Copyright 2015 Eike Hein * * This program 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, 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 Library 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 CONFIGMODEL_H #define CONFIGMODEL_H #include #include #include // // W A R N I N G // ------------- // // This file is not part of the public Plasma API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // namespace Plasma { class Applet; } namespace PlasmaQuick { class ConfigPropertyMap; class ConfigCategoryPrivate; class ConfigModelPrivate; class ConfigCategory; /* * This model contains all the possible config categories for a dialog, * such as categories of the config dialog for an Applet * TODO: it should probably become an import instead of a library? */ class PLASMAQUICK_EXPORT ConfigModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QQmlListProperty categories READ categories CONSTANT) Q_CLASSINFO("DefaultProperty", "categories") Q_PROPERTY(int count READ count NOTIFY countChanged) public: enum Roles { NameRole = Qt::UserRole + 1, IconRole, SourceRole, PluginNameRole, VisibleRole, KCMRole }; ConfigModel(QObject *parent = 0); ~ConfigModel(); /** * add a new category in the model * @param ConfigCategory the new category **/ void appendCategory(const QString &iconName, const QString &name, const QString &path, const QString &pluginName); Q_INVOKABLE void appendCategory(const QString &iconName, const QString &name, const QString &path, const QString &pluginName, bool visible); /** * clears the model **/ void clear(); void setApplet(Plasma::Applet *interface); Plasma::Applet *applet() const; int count() { return rowCount(); } int rowCount(const QModelIndex &index = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &, int) const Q_DECL_OVERRIDE; + QHash roleNames() const Q_DECL_OVERRIDE; /** * @param row the row for which the data will be returned * @raturn the data of the specified row **/ Q_INVOKABLE QVariant get(int row) const; /** * @return the categories of the model **/ QQmlListProperty categories(); Q_SIGNALS: /** * emitted when the count is changed **/ void countChanged(); private: friend class ConfigModelPrivate; ConfigModelPrivate *const d; }; } #endif // multiple inclusion guard