/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "indicatorsmodel.h" #include "indicatorsmanager.h" #include "indicator.h" #include "paths.h" #include #include #include /*! \qmltype IndicatorsModel \inherits QAbstractListModel \brief The IndicatorsModel class defines the list model for indicators plugins \b {This component is under heavy development.} This class expose the available indicators. \code IndicatorsModel { id: menuModel } ListView { id: view model: menuModel Component.onCompleted: menuModel.load() } \endcode */ IndicatorsModel::IndicatorsModel(QObject *parent) : QAbstractListModel(parent) { m_manager = new IndicatorsManager(this); QObject::connect(m_manager, SIGNAL(indicatorLoaded(const QString&)), this, SLOT(onIndicatorLoaded(const QString&))); QObject::connect(m_manager, SIGNAL(indicatorAboutToBeUnloaded(const QString&)), this, SLOT(onIndicatorAboutToBeUnloaded(const QString&))); QObject::connect(this, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SIGNAL(countChanged())); QObject::connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SIGNAL(countChanged())); QObject::connect(this, SIGNAL(modelReset()), this, SIGNAL(countChanged())); } /*! \internal */ IndicatorsModel::~IndicatorsModel() { disconnect(m_manager, 0, 0, 0); m_manager->deleteLater(); } /*! \qmlmethod IndicatorsModel::get(int) Returns the item at index in the model. This allows the item data to be accessed from JavaScript: \b Note: methods should only be called after the Component has completed. */ QVariantMap IndicatorsModel::get(int row) const { QVariantMap result; QModelIndex index = this->index(row); if (index.isValid()) { QMap data = itemData(index); const QHash roleNames = this->roleNames(); Q_FOREACH(int i, roleNames.keys()) { result.insert(roleNames[i], data[i]); } } return result; } /*! \qmlproperty IndicatorsModel::count The number of data entries in the model. \b Note: methods should only be called after the Component has completed. */ int IndicatorsModel::count() const { return rowCount(); } /*! \qmlmethod IndicatorsModel::unload() Load all plugins. */ void IndicatorsModel::load() { m_plugins.clear(); m_manager->load(); } /*! \qmlmethod IndicatorsModel::unload() Unload all plugins. */ void IndicatorsModel::unload() { m_manager->unload(); } /*! \internal */ void IndicatorsModel::onIndicatorLoaded(const QString& indicator) { Indicator::Ptr plugin = m_manager->indicator(indicator); if (!plugin) return; if (m_plugins.indexOf(plugin) >= 0) return; // find the insert position int pos = 0; while (pos < count()) { // keep going while the existing priority is less. if (indicatorData(plugin, Priority).toInt() < data(index(pos), Priority).toInt()) break; pos++; } QObject::connect(plugin.data(), SIGNAL(identifierChanged(const QString&)), this, SLOT(onIdentifierChanged())); QObject::connect(plugin.data(), SIGNAL(indicatorPropertiesChanged(const QVariant&)), this, SLOT(onIndicatorPropertiesChanged())); beginInsertRows(QModelIndex(), pos, pos); m_plugins.insert(pos, plugin); endInsertRows(); } /*! \internal */ void IndicatorsModel::onIndicatorAboutToBeUnloaded(const QString& indicator) { Indicator::Ptr plugin = m_manager->indicator(indicator); if (!plugin) return; int i = 0; QMutableListIterator iter(m_plugins); while(iter.hasNext()) { if (plugin == iter.next()) { beginRemoveRows(QModelIndex(), i, i); iter.remove(); endRemoveRows(); } i++; } } /*! \internal */ void IndicatorsModel::onIdentifierChanged() { notifyDataChanged(QObject::sender(), Identifier); } /*! \internal */ void IndicatorsModel::onIndicatorPropertiesChanged() { notifyDataChanged(QObject::sender(), IndicatorProperties); } /*! \internal */ void IndicatorsModel::notifyDataChanged(QObject *sender, int role) { Indicator* plugin = qobject_cast(sender); if (!plugin) return; int index = 0; QMutableListIterator iter(m_plugins); while(iter.hasNext()) { if (iter.next().data() == plugin) { QModelIndex changedIndex = this->index(index); dataChanged(changedIndex, changedIndex, QVector() << role); break; } index++; } } /*! \internal */ QHash IndicatorsModel::roleNames() const { static QHash roles; if (roles.isEmpty()) { roles[Identifier] = "identifier"; roles[Priority] = "priority"; roles[Title] = "title"; roles[Description] = "description"; roles[WidgetSource] = "widgetSource"; roles[PageSource] = "pageSource"; roles[IndicatorProperties] = "indicatorProperties"; roles[IsValid] = "isValid"; } return roles; } /*! \internal */ int IndicatorsModel::columnCount(const QModelIndex &) const { return 1; } /*! \internal */ QVariant IndicatorsModel::defaultData(Indicator::Ptr plugin, int role) { switch (role) { case Priority: return 0; case Title: return plugin ? plugin->identifier() : "Unknown"; case Description: return ""; case WidgetSource: return shellAppDirectory()+"/Panel/Indicators/DefaultIndicatorWidget.qml"; case PageSource: return shellAppDirectory()+"/Panel/Indicators/DefaultIndicatorPage.qml"; } return QVariant(); } /*! \internal */ QVariant IndicatorsModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= m_plugins.size()) return QVariant(); Indicator::Ptr plugin = m_plugins[index.row()]; switch (role) { case Identifier: if (plugin) { return QVariant(plugin->identifier()); } break; case IndicatorProperties: if (plugin) { return QVariant(plugin->indicatorProperties()); } break; case IsValid: return (plugin ? true : false); case Priority: case Title: case Description: case WidgetSource: case PageSource: return indicatorData(plugin, role); default: break; } return QVariant(); } QVariant IndicatorsModel::indicatorData(const Indicator::Ptr& plugin, int role) const { if (plugin && m_parsed_indicator_data.contains(plugin->identifier())) { QVariantMap data = m_parsed_indicator_data[plugin->identifier()]; return data.value(roleNames()[role], QVariant()); } return defaultData(plugin, role); } /*! \internal */ QModelIndex IndicatorsModel::parent(const QModelIndex&) const { return QModelIndex(); } /*! \internal */ int IndicatorsModel::rowCount(const QModelIndex&) const { return m_plugins.count(); } void IndicatorsModel::setIndicatorData(const QVariant& data) { m_indicator_data = data; m_parsed_indicator_data.clear(); QMap map = data.toMap(); QMapIterator iter(map); while(iter.hasNext()) { iter.next(); m_parsed_indicator_data[iter.key()] = iter.value().toMap(); } Q_EMIT indicatorDataChanged(m_indicator_data); } QVariant IndicatorsModel::indicatorData() const { return m_indicator_data; }