Lomiri
Loading...
Searching...
No Matches
modelactionrootstate.cpp
1/*
2 * Copyright 2013-2016 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 */
19
20#include "modelactionrootstate.h"
21#include "indicators.h"
22
23#include <ayatanamenumodel.h>
24#include <QVariant>
25#include <QIcon>
26
27extern "C" {
28#include <glib.h>
29#include <gio/gio.h>
30}
31
32ModelActionRootState::ModelActionRootState(QObject *parent)
33 : RootStateObject(parent),
34 m_menu(nullptr)
35 , m_reentryGuard(false)
36{
37}
38
39ModelActionRootState::~ModelActionRootState()
40{
41}
42
43AyatanaMenuModel* ModelActionRootState::menu() const
44{
45 return m_menu;
46}
47
48void ModelActionRootState::setMenu(AyatanaMenuModel* menu)
49{
50 if (m_menu != menu) {
51 bool wasValid = valid();
52
53 if (m_menu) {
54 m_menu->disconnect(this);
55 }
56 m_menu = menu;
57
58 if (m_menu) {
59 connect(m_menu, &AyatanaMenuModel::rowsInserted, this, &ModelActionRootState::onModelRowsAdded);
60 connect(m_menu, &AyatanaMenuModel::rowsRemoved, this, &ModelActionRootState::onModelRowsRemoved);
61 connect(m_menu, &AyatanaMenuModel::dataChanged, this, &ModelActionRootState::onModelDataChanged);
62
63 connect(m_menu, &AyatanaMenuModel::destroyed, this, &ModelActionRootState::reset);
64 }
65 updateActionState();
66 updateOtherActions();
67 Q_EMIT menuChanged();
68
69 if (wasValid != valid())
70 Q_EMIT validChanged();
71 }
72}
73
74QString ModelActionRootState::secondaryAction() const
75{
76 return m_secondaryAction;
77}
78
79QString ModelActionRootState::scrollAction() const
80{
81 return m_scrollAction;
82}
83
84QString ModelActionRootState::submenuAction() const
85{
86 return m_submenuAction;
87}
88
89bool ModelActionRootState::valid() const
90{
91 return !currentState().empty();
92}
93
94void ModelActionRootState::onModelRowsAdded(const QModelIndex& parent, int start, int end)
95{
96 Q_UNUSED(parent);
97 if (start == 0 && end >= 0) {
98 updateActionState();
99 updateOtherActions();
100 }
101}
102
103void ModelActionRootState::onModelRowsRemoved(const QModelIndex& parent, int start, int end)
104{
105 Q_UNUSED(parent);
106 if (start == 0 && end >= 0) {
107 updateActionState();
108 updateOtherActions();
109 }
110}
111
112void ModelActionRootState::onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
113{
114 Q_UNUSED(roles);
115 if (!topLeft.isValid() || !bottomRight.isValid()) {
116 return;
117 }
118
119 if (topLeft.row() <= 0 && bottomRight.row() >= 0) {
120 updateActionState();
121 updateOtherActions();
122 }
123}
124
125void ModelActionRootState::reset()
126{
127 m_menu = nullptr;
128
129 Q_EMIT menuChanged();
130 setCurrentState(QVariantMap());
131
132 updateOtherActions();
133}
134
135void ModelActionRootState::updateActionState()
136{
137 if (m_reentryGuard) return;
138 m_reentryGuard = true;
139
140 if (m_menu && m_menu->rowCount() > 0) {
141 ActionStateParser* oldParser = m_menu->actionStateParser();
142 m_menu->setActionStateParser(&m_parser);
143
144 QVariantMap state = m_menu->get(0, "actionState").toMap();
145
146 m_menu->setActionStateParser(oldParser);
147
148 setCurrentState(state);
149 } else if (!m_menu) {
150 setCurrentState(QVariantMap());
151 }
152 // else if m_menu->rowCount() == 0, let's leave existing cache in place
153 // until the new menu comes in, to avoid flashing the UI empty for a moment
154
155 m_reentryGuard = false;
156}
157
158void ModelActionRootState::updateOtherActions()
159{
160 if (m_reentryGuard) return;
161 m_reentryGuard = true;
162
163 if (m_menu && m_menu->rowCount() > 0) {
164 QVariantMap map;
165 map[QStringLiteral("submenu-action")] = QStringLiteral("string");
166 map[QStringLiteral("x-ayatana-scroll-action")] = QStringLiteral("string");
167 map[QStringLiteral("x-ayatana-secondary-action")] = QStringLiteral("string");
168 m_menu->loadExtendedAttributes(0, map);
169 QVariantMap extMap = m_menu->get(0, "ext").toMap();
170
171 QString secondaryAction = extMap.value(QStringLiteral("xAyatanaSecondaryAction")).toString();
172 if (m_secondaryAction != secondaryAction) {
173 m_secondaryAction = secondaryAction;
174 Q_EMIT secondaryActionChanged();
175 }
176
177 QString scrollAction = extMap.value(QStringLiteral("xAyatanaScrollAction")).toString();
178 if (m_scrollAction != scrollAction) {
179 m_scrollAction = scrollAction;
180 Q_EMIT scrollActionChanged();
181 }
182
183 QString submenuAction = extMap.value(QStringLiteral("submenuAction")).toString();
184 if (m_submenuAction != submenuAction) {
185 m_submenuAction = submenuAction;
186 Q_EMIT submenuActionChanged();
187 }
188 } else {
189 if (!m_secondaryAction.isEmpty()) {
190 m_secondaryAction.clear();
191 Q_EMIT secondaryActionChanged();
192 }
193 if (!m_scrollAction.isEmpty()) {
194 m_scrollAction.clear();
195 Q_EMIT scrollActionChanged();
196 }
197 if (!m_submenuAction.isEmpty()) {
198 m_submenuAction.clear();
199 Q_EMIT submenuActionChanged();
200 }
201 }
202
203 m_reentryGuard = false;
204}