on 1bfad40 help sign in
unity8/plugins/Unity/Indicators/rootactionstate.cpp
290 lines 8.1 kB history raw
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Nick Dedekind <nick.dedekind@canonical.com>
18 */
20#include "rootactionstate.h"
21#include "indicators.h"
23#include <unitymenumodel.h>
24#include <QVariant>
25#include <QIcon>
27extern "C" {
28#include <glib.h>
29#include <gio/gio.h>
32RootActionState::RootActionState(QObject *parent)
33 : ActionStateParser(parent),
34 m_menu(NULL)
38RootActionState::~RootActionState()
40 if (m_menu) {
41 m_menu->disconnect(this);
42 m_menu->setActionStateParser(NULL);
43 }
46UnityMenuModel* RootActionState::menu() const
48 return m_menu;
51void RootActionState::setMenu(UnityMenuModel* menu)
53 if (m_menu != menu) {
54 if (m_menu) {
55 m_menu->disconnect(this);
56 m_menu->setActionStateParser(NULL);
57 }
58 m_menu = menu;
60 if (m_menu) {
61 connect(m_menu, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(onModelRowsAdded(const QModelIndex&, int, int)));
62 connect(m_menu, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(onModelRowsRemoved(const QModelIndex&, int, int)));
63 connect(m_menu, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)), SLOT(onModelDataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
65 m_menu->setActionStateParser(this);
66 }
67 updateActionState();
68 Q_EMIT menuChanged();
69 }
72void RootActionState::onModelRowsAdded(const QModelIndex& parent, int start, int end)
74 Q_UNUSED(parent);
75 if (start == 0 && end >= 0) {
76 updateActionState();
77 }
80void RootActionState::onModelRowsRemoved(const QModelIndex& parent, int start, int end)
82 Q_UNUSED(parent);
83 if (start == 0 && end >= 0) {
84 updateActionState();
85 }
88void RootActionState::onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
90 Q_UNUSED(roles);
91 if (!topLeft.isValid() || !bottomRight.isValid()) {
92 return;
93 }
95 if (topLeft.row() <= 0 && bottomRight.row() >= 0) {
96 updateActionState();
97 }
100void RootActionState::updateActionState()
102 if (m_menu && m_menu->rowCount() > 0) {
103 m_cachedState = m_menu->get(0, "actionState").toMap();
104 } else {
105 m_cachedState.clear();
106 }
107 Q_EMIT updated();
110bool RootActionState::isValid() const
112 return m_menu && m_menu->rowCount() > 0;
115QString RootActionState::title() const
117 if (!isValid()) return QString();
119 return m_cachedState.value("title", QVariant::fromValue(QString())).toString();
122QString RootActionState::leftLabel() const
124 if (!isValid()) return QString();
126 return m_cachedState.value("pre-label", QVariant::fromValue(QString())).toString();
129QString RootActionState::rightLabel() const
131 if (!isValid()) return QString();
133 return m_cachedState.value("label", QVariant::fromValue(QString())).toString();
136QStringList RootActionState::icons() const
138 if (!isValid()) return QStringList();
140 return m_cachedState.value("icons", QVariant::fromValue(QStringList())).toStringList();
143QString RootActionState::accessibleName() const
145 if (!isValid()) return QString();
147 return m_cachedState.value("accessible-desc", QVariant::fromValue(QString())).toString();
150bool RootActionState::isVisible() const
152 if (!isValid()) return false;
154 return m_cachedState.value("visible", QVariant::fromValue(true)).toBool();
157static QString iconUri(GIcon *icon)
159 QString uri;
161 if (G_IS_THEMED_ICON (icon)) {
162 const gchar* const* iconNames = g_themed_icon_get_names (G_THEMED_ICON (icon));
164 QStringList iconNameList;
165 for (uint index = 0; iconNames[index] != NULL; index++) {
166 iconNameList << iconNames[index];
167 }
169 if (!iconNameList.empty()) {
170 uri = QString("image://theme/%1").arg(iconNameList.join(","));
171 }
172 }
173 else if (G_IS_FILE_ICON (icon)) {
174 GFile *file;
176 file = g_file_icon_get_file (G_FILE_ICON (icon));
177 if (g_file_is_native (file)) {
178 gchar *fileuri;
180 fileuri = g_file_get_path (file);
181 uri = QString(fileuri);
183 g_free (fileuri);
184 }
185 }
186 else if (G_IS_BYTES_ICON (icon)) {
187 gsize size;
188 gconstpointer data;
189 gchar *base64;
191 data = g_bytes_get_data (g_bytes_icon_get_bytes (G_BYTES_ICON (icon)), &size);
192 base64 = g_base64_encode ((const guchar *) data, size);
194 uri = QString("data://");
195 uri.append (base64);
197 g_free (base64);
198 }
200 return uri;
203QVariant RootActionState::toQVariant(GVariant* state) const
205 if (!state) {
206 return QVariant();
207 }
209 if (g_variant_is_of_type(state, G_VARIANT_TYPE_VARDICT)) {
210 GVariantIter iter;
211 GVariant *vvalue;
212 gchar *key;
213 QVariantMap qmap;
215 g_variant_iter_init (&iter, state);
216 while (g_variant_iter_loop (&iter, "{sv}", &key, &vvalue))
217 {
218 QString str = QString::fromUtf8(key);
219 if (str == "icon" && !qmap.contains("icons")) {
220 QStringList icons;
222 // FIXME - should be sending a url.
223 GIcon *gicon = g_icon_deserialize (vvalue);
224 if (gicon) {
225 icons << iconUri(gicon);
226 g_object_unref (gicon);
227 }
228 qmap.insert("icons", icons);
230 } else if (str == "icons") {
232 QStringList icons;
234 if (g_variant_type_is_array(g_variant_get_type(vvalue))) {
237 for (int i = 0, iMax = g_variant_n_children(vvalue); i < iMax; i++) {
238 GVariant *child = g_variant_get_child_value(vvalue, i);
240 // FIXME - should be sending a url.
241 GIcon *gicon = g_icon_deserialize (child);
242 if (gicon) {
243 icons << iconUri(gicon);
244 g_object_unref (gicon);
245 }
246 g_variant_unref(child);
247 }
248 }
249 // will overwrite icon.
250 qmap.insert("icons", icons);
252 } else {
253 qmap.insert(str, ActionStateParser::toQVariant(vvalue));
254 }
255 }
257 return QVariant::fromValue(qmap);
259 } else if (g_variant_is_of_type (state, G_VARIANT_TYPE ("(sssb)"))) {
260 QVariantMap qmap;
262 char* label;
263 char* icon;
264 char* accessible_name;
265 gboolean visible;
266 GIcon *gicon;
268 g_variant_get(state, "(sssb)", &label,
269 &icon,
270 &accessible_name,
271 &visible);
273 qmap["label"] = label ? QString::fromUtf8(label) : "";
274 qmap["accessible-desc"] = accessible_name ? QString::fromUtf8(accessible_name) : "";
275 qmap["visible"] = visible;
277 gicon = g_icon_new_for_string (icon, NULL);
278 if (gicon) {
279 qmap["icons"] = QStringList() << iconUri(gicon);
280 g_object_unref (gicon);
281 }
283 if (label) g_free(label);
284 if (icon) g_free(icon);
285 if (accessible_name) g_free(accessible_name);
287 return QVariant::fromValue(qmap);
288 }
289 return ActionStateParser::toQVariant(state);