aboutsummaryrefslogtreecommitdiff
path: root/libqmenumodel/src/qmenumodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libqmenumodel/src/qmenumodel.cpp')
-rw-r--r--libqmenumodel/src/qmenumodel.cpp225
1 files changed, 225 insertions, 0 deletions
diff --git a/libqmenumodel/src/qmenumodel.cpp b/libqmenumodel/src/qmenumodel.cpp
new file mode 100644
index 0000000..e88bc66
--- /dev/null
+++ b/libqmenumodel/src/qmenumodel.cpp
@@ -0,0 +1,225 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Renato Araujo Oliveira Filho <renato@canonical.com>
+ */
+
+#include "qmenumodel.h"
+#include "converter.h"
+
+#include <QDebug>
+
+/*!
+ \qmlclass QMenuModel
+ \brief The QMenuModel class implements the base list model for menus
+
+ \bold {This component is under heavy development.}
+
+ This is a abstracted class used by \l QDBusMenuModel.
+*/
+
+/*! \internal */
+QMenuModel::QMenuModel(GMenuModel *other, QObject *parent)
+ : QAbstractListModel(parent),
+ m_menuModel(0),
+ m_signalChangedId(0)
+{
+ static QHash<int, QByteArray> rolesNames;
+ if (rolesNames.empty()) {
+ rolesNames[Action] = "action";
+ rolesNames[Label] = "label";
+ rolesNames[LinkSection] = "linkSection";
+ rolesNames[LinkSubMenu] = "linkSubMenu";
+ rolesNames[Extra] = "extra";
+ }
+ setRoleNames(rolesNames);
+ setMenuModel(other);
+}
+
+/*! \internal */
+QMenuModel::~QMenuModel()
+{
+ setMenuModel(NULL);
+}
+
+/*! \internal */
+void QMenuModel::setMenuModel(GMenuModel *other)
+{
+ if (m_menuModel == other) {
+ return;
+ }
+
+ beginResetModel();
+
+ if (m_menuModel) {
+ g_signal_handler_disconnect(m_menuModel, m_signalChangedId);
+ m_signalChangedId = 0;
+ g_object_unref(m_menuModel);
+ }
+
+ m_menuModel = other;
+
+ if (m_menuModel) {
+ // this will trigger the menu load
+ (void) g_menu_model_get_n_items(m_menuModel);
+ m_signalChangedId = g_signal_connect(m_menuModel,
+ "items-changed",
+ G_CALLBACK(QMenuModel::onItemsChanged),
+ this);
+ }
+
+ endResetModel();
+}
+
+/*! \internal */
+GMenuModel *QMenuModel::menuModel() const
+{
+ return m_menuModel;
+}
+
+/*! \internal */
+QVariant QMenuModel::data(const QModelIndex &index, int role) const
+{
+ QVariant attribute;
+ int rowCountValue = rowCount();
+
+ if ((rowCountValue > 0) && (index.row() >= 0) && (index.row() < rowCountValue)) {
+ if (m_menuModel) {
+ switch (role) {
+ case Action:
+ attribute = getStringAttribute(index, G_MENU_ATTRIBUTE_ACTION);
+ break;
+ case Label:
+ attribute = getStringAttribute(index, G_MENU_ATTRIBUTE_LABEL);
+ break;
+ case LinkSection:
+ attribute = getLink(index, G_MENU_LINK_SECTION);
+ break;
+ case LinkSubMenu:
+ attribute = getLink(index, G_MENU_LINK_SUBMENU);
+ break;
+ case Extra:
+ attribute = getExtraProperties(index);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return attribute;
+}
+
+/*! \internal */
+QModelIndex QMenuModel::parent(const QModelIndex &index) const
+{
+ return QModelIndex();
+}
+
+/*! \internal */
+int QMenuModel::rowCount(const QModelIndex &) const
+{
+ if (m_menuModel) {
+ return g_menu_model_get_n_items(m_menuModel);
+ }
+ return 0;
+}
+
+/*! \internal */
+QVariant QMenuModel::getStringAttribute(const QModelIndex &index,
+ const QString &attribute) const
+{
+ QVariant result;
+ gchar* value = NULL;
+ g_menu_model_get_item_attribute(m_menuModel,
+ index.row(),
+ attribute.toLatin1(),
+ "s", &value);
+ if (value) {
+ result = QVariant(QString::fromLatin1(value));
+ g_free(value);
+ }
+ return result;
+}
+
+/*! \internal */
+QVariant QMenuModel::getLink(const QModelIndex &index,
+ const QString &linkName) const
+{
+ GMenuModel *link;
+
+ link = g_menu_model_get_item_link(m_menuModel,
+ index.row(),
+ linkName.toLatin1());
+
+ if (link) {
+ QMenuModel *other = new QMenuModel(link, const_cast<QMenuModel*>(this));
+ return QVariant::fromValue<QObject*>(other);
+ }
+
+ return QVariant();
+}
+
+/*! \internal */
+QString QMenuModel::parseExtraPropertyName(const QString &name) const
+{
+ QString newName(name);
+ if (name.startsWith("x-")) {
+ newName = name.mid(2);
+ }
+ return newName.replace("-", "_");
+}
+
+/*! \internal */
+QVariant QMenuModel::getExtraProperties(const QModelIndex &index) const
+{
+ GMenuAttributeIter *iter = g_menu_model_iterate_item_attributes(m_menuModel, index.row());
+ if (iter == NULL) {
+ return QVariant();
+ }
+
+ QVariantMap extra;
+ const gchar *attrName = NULL;
+ GVariant *value = NULL;
+ while (g_menu_attribute_iter_get_next (iter, &attrName, &value)) {
+ if (strncmp("x-", attrName, 2) == 0) {
+ extra.insert(parseExtraPropertyName(attrName),
+ Converter::toQVariant(value));
+ }
+ }
+
+ return extra;
+}
+
+/*! \internal */
+void QMenuModel::onItemsChanged(GMenuModel *,
+ gint position,
+ gint removed,
+ gint added,
+ gpointer data)
+{
+ QMenuModel *self = reinterpret_cast<QMenuModel*>(data);
+
+ if (removed > 0) {
+ self->beginRemoveRows(QModelIndex(), position, position + removed - 1);
+ self->endRemoveRows();
+ }
+
+ if (added > 0) {
+ self->beginInsertRows(QModelIndex(), position, position + added - 1);
+ self->endInsertRows();
+ }
+}
+