/* * Copyright 2013 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: * Nick Dedekind */ #include "rootactionstate.h" #include "indicators.h" #include #include #include extern "C" { #include #include } RootActionState::RootActionState(QObject *parent) : ActionStateParser(parent), m_menu(NULL) { } RootActionState::~RootActionState() { } UnityMenuModel* RootActionState::menu() const { return m_menu; } void RootActionState::setMenu(UnityMenuModel* menu) { if (m_menu != menu) { if (m_menu) { m_menu->disconnect(this); } m_menu = menu; if (m_menu) { connect(m_menu, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(onModelRowsAdded(const QModelIndex&, int, int))); connect(m_menu, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(onModelRowsRemoved(const QModelIndex&, int, int))); connect(m_menu, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector&)), SLOT(onModelDataChanged(const QModelIndex&, const QModelIndex&, const QVector&))); connect(m_menu, SIGNAL(destroyed()), SLOT(reset())); } updateActionState(); Q_EMIT menuChanged(); } } void RootActionState::onModelRowsAdded(const QModelIndex& parent, int start, int end) { Q_UNUSED(parent); if (start == 0 && end >= 0) { updateActionState(); } } void RootActionState::onModelRowsRemoved(const QModelIndex& parent, int start, int end) { Q_UNUSED(parent); if (start == 0 && end >= 0) { updateActionState(); } } void RootActionState::onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector& roles) { Q_UNUSED(roles); if (!topLeft.isValid() || !bottomRight.isValid()) { return; } if (topLeft.row() <= 0 && bottomRight.row() >= 0) { updateActionState(); } } void RootActionState::reset() { m_cachedState.clear(); m_menu = NULL; Q_EMIT menuChanged(); Q_EMIT updated(); } void RootActionState::updateActionState() { if (m_menu && m_menu->rowCount() > 0) { ActionStateParser* oldParser = m_menu->actionStateParser(); m_menu->setActionStateParser(this); m_cachedState = m_menu->get(0, "actionState").toMap(); m_menu->setActionStateParser(oldParser); } else { m_cachedState.clear(); } Q_EMIT updated(); } bool RootActionState::isValid() const { return m_menu && m_menu->rowCount() > 0; } QString RootActionState::title() const { if (!isValid()) return QString(); return m_cachedState.value("title", QVariant::fromValue(QString())).toString(); } QString RootActionState::leftLabel() const { if (!isValid()) return QString(); return m_cachedState.value("pre-label", QVariant::fromValue(QString())).toString(); } QString RootActionState::rightLabel() const { if (!isValid()) return QString(); return m_cachedState.value("label", QVariant::fromValue(QString())).toString(); } QStringList RootActionState::icons() const { if (!isValid()) return QStringList(); return m_cachedState.value("icons", QVariant::fromValue(QStringList())).toStringList(); } QString RootActionState::accessibleName() const { if (!isValid()) return QString(); return m_cachedState.value("accessible-desc", QVariant::fromValue(QString())).toString(); } bool RootActionState::isVisible() const { if (!isValid()) return false; return m_cachedState.value("visible", QVariant::fromValue(true)).toBool(); } static QString iconUri(GIcon *icon) { QString uri; if (G_IS_THEMED_ICON (icon)) { const gchar* const* iconNames = g_themed_icon_get_names (G_THEMED_ICON (icon)); QStringList iconNameList; for (uint index = 0; iconNames[index] != NULL; index++) { iconNameList << iconNames[index]; } if (!iconNameList.empty()) { uri = QString("image://theme/%1").arg(iconNameList.join(",")); } } else if (G_IS_FILE_ICON (icon)) { GFile *file; file = g_file_icon_get_file (G_FILE_ICON (icon)); if (g_file_is_native (file)) { gchar *fileuri; fileuri = g_file_get_path (file); uri = QString(fileuri); g_free (fileuri); } } else if (G_IS_BYTES_ICON (icon)) { gsize size; gconstpointer data; gchar *base64; data = g_bytes_get_data (g_bytes_icon_get_bytes (G_BYTES_ICON (icon)), &size); base64 = g_base64_encode ((const guchar *) data, size); uri = QString("data://"); uri.append (base64); g_free (base64); } return uri; } QVariant RootActionState::toQVariant(GVariant* state) const { if (!state) { return QVariant(); } if (g_variant_is_of_type(state, G_VARIANT_TYPE_VARDICT)) { GVariantIter iter; GVariant *vvalue; gchar *key; QVariantMap qmap; g_variant_iter_init (&iter, state); while (g_variant_iter_loop (&iter, "{sv}", &key, &vvalue)) { QString str = QString::fromUtf8(key); if (str == "icon" && !qmap.contains("icons")) { QStringList icons; // FIXME - should be sending a url. GIcon *gicon = g_icon_deserialize (vvalue); if (gicon) { icons << iconUri(gicon); g_object_unref (gicon); } qmap.insert("icons", icons); } else if (str == "icons") { QStringList icons; if (g_variant_type_is_array(g_variant_get_type(vvalue))) { for (int i = 0, iMax = g_variant_n_children(vvalue); i < iMax; i++) { GVariant *child = g_variant_get_child_value(vvalue, i); // FIXME - should be sending a url. GIcon *gicon = g_icon_deserialize (child); if (gicon) { icons << iconUri(gicon); g_object_unref (gicon); } g_variant_unref(child); } } // will overwrite icon. qmap.insert("icons", icons); } else { qmap.insert(str, ActionStateParser::toQVariant(vvalue)); } } return QVariant::fromValue(qmap); } else if (g_variant_is_of_type (state, G_VARIANT_TYPE ("(sssb)"))) { QVariantMap qmap; char* label; char* icon; char* accessible_name; gboolean visible; GIcon *gicon; g_variant_get(state, "(sssb)", &label, &icon, &accessible_name, &visible); qmap["label"] = label ? QString::fromUtf8(label) : ""; qmap["accessible-desc"] = accessible_name ? QString::fromUtf8(accessible_name) : ""; qmap["visible"] = visible; gicon = g_icon_new_for_string (icon, NULL); if (gicon) { qmap["icons"] = QStringList() << iconUri(gicon); g_object_unref (gicon); } if (label) g_free(label); if (icon) g_free(icon); if (accessible_name) g_free(accessible_name); return QVariant::fromValue(qmap); } return ActionStateParser::toQVariant(state); }