on xenial help sign in
Added support for secondary indicator actions Fixes: #1398888
a01a8b4Nick Dedekind
plugins/Unity/Indicators/modelactionrootstate.cpp+76−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013-2016 Canonical Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -32,6 +32,7 @@ extern "C" {
32ModelActionRootState::ModelActionRootState(QObject *parent)
32ModelActionRootState::ModelActionRootState(QObject *parent)
33 : RootStateObject(parent),
33 : RootStateObject(parent),
34 m_menu(nullptr)
34 m_menu(nullptr)
35+ , m_reentryGuard(false)
35{
36{
36}
37}
37
38
@@ -62,6 +63,7 @@ void ModelActionRootState::setMenu(UnityMenuModel* menu)
62 connect(m_menu, &UnityMenuModel::destroyed, this, &ModelActionRootState::reset);
63 connect(m_menu, &UnityMenuModel::destroyed, this, &ModelActionRootState::reset);
63 }
64 }
64 updateActionState();
65 updateActionState();
66+ updateOtherActions();
65 Q_EMIT menuChanged();
67 Q_EMIT menuChanged();
66
68
67 if (wasValid != valid())
69 if (wasValid != valid())
@@ -69,6 +71,21 @@ void ModelActionRootState::setMenu(UnityMenuModel* menu)
69 }
71 }
70}
72}
71
73
74+QString ModelActionRootState::secondaryAction() const
75+{
76+ return m_secondaryAction;
77+}
78+
79+QString ModelActionRootState::scrollAction() const
80+{
81+ return m_scrollAction;
82+}
83+
84+QString ModelActionRootState::submenuAction() const
85+{
86+ return m_submenuAction;
87+}
88+
72bool ModelActionRootState::valid() const
89bool ModelActionRootState::valid() const
73{
90{
74 return !currentState().empty();
91 return !currentState().empty();
@@ -79,6 +96,7 @@ void ModelActionRootState::onModelRowsAdded(const QModelIndex& parent, int start
79 Q_UNUSED(parent);
96 Q_UNUSED(parent);
80 if (start == 0 && end >= 0) {
97 if (start == 0 && end >= 0) {
81 updateActionState();
98 updateActionState();
99+ updateOtherActions();
82 }
100 }
83}
101}
84
102
@@ -87,6 +105,7 @@ void ModelActionRootState::onModelRowsRemoved(const QModelIndex& parent, int sta
87 Q_UNUSED(parent);
105 Q_UNUSED(parent);
88 if (start == 0 && end >= 0) {
106 if (start == 0 && end >= 0) {
89 updateActionState();
107 updateActionState();
108+ updateOtherActions();
90 }
109 }
91}
110}
92
111
@@ -99,6 +118,7 @@ void ModelActionRootState::onModelDataChanged(const QModelIndex& topLeft, const
99
118
100 if (topLeft.row() <= 0 && bottomRight.row() >= 0) {
119 if (topLeft.row() <= 0 && bottomRight.row() >= 0) {
101 updateActionState();
120 updateActionState();
121+ updateOtherActions();
102 }
122 }
103}
123}
104
124
@@ -108,10 +128,15 @@ void ModelActionRootState::reset()
108
128
109 Q_EMIT menuChanged();
129 Q_EMIT menuChanged();
110 setCurrentState(QVariantMap());
130 setCurrentState(QVariantMap());
131+
132+ updateOtherActions();
111}
133}
112
134
113void ModelActionRootState::updateActionState()
135void ModelActionRootState::updateActionState()
114{
136{
137+ if (m_reentryGuard) return;
138+ m_reentryGuard = true;
139+
115 if (m_menu && m_menu->rowCount() > 0) {
140 if (m_menu && m_menu->rowCount() > 0) {
116 ActionStateParser* oldParser = m_menu->actionStateParser();
141 ActionStateParser* oldParser = m_menu->actionStateParser();
117 m_menu->setActionStateParser(&m_parser);
142 m_menu->setActionStateParser(&m_parser);
@@ -126,4 +151,54 @@ void ModelActionRootState::updateActionState()
126 }
151 }
127 // else if m_menu->rowCount() == 0, let's leave existing cache in place
152 // else if m_menu->rowCount() == 0, let's leave existing cache in place
128 // until the new menu comes in, to avoid flashing the UI empty for a moment
153 // until the new menu comes in, to avoid flashing the UI empty for a moment
154+
155+ m_reentryGuard = false;
156+}
157+
158+void 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-canonical-scroll-action")] = QStringLiteral("string");
167+ map[QStringLiteral("x-canonical-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("xCanonicalSecondaryAction")).toString();
172+ if (m_secondaryAction != secondaryAction) {
173+ m_secondaryAction = secondaryAction;
174+ Q_EMIT secondaryActionChanged();
175+ }
176+
177+ QString scrollAction = extMap.value(QStringLiteral("xCanonicalScrollAction")).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;
129}
204}
plugins/Unity/Indicators/modelactionrootstate.h+15−4
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013-2016 Canonical Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -30,6 +30,9 @@ class UNITYINDICATORS_EXPORT ModelActionRootState : public RootStateObject
30{
30{
31 Q_OBJECT
31 Q_OBJECT
32 Q_PROPERTY(UnityMenuModel* menu READ menu WRITE setMenu NOTIFY menuChanged)
32 Q_PROPERTY(UnityMenuModel* menu READ menu WRITE setMenu NOTIFY menuChanged)
33+ Q_PROPERTY(QString secondaryAction READ secondaryAction NOTIFY secondaryActionChanged)
34+ Q_PROPERTY(QString scrollAction READ scrollAction NOTIFY scrollActionChanged)
35+ Q_PROPERTY(QString submenuAction READ submenuAction NOTIFY submenuActionChanged)
33public:
36public:
34 ModelActionRootState(QObject *parent = 0);
37 ModelActionRootState(QObject *parent = 0);
35 virtual ~ModelActionRootState();
38 virtual ~ModelActionRootState();
@@ -37,14 +40,17 @@ public:
37 UnityMenuModel* menu() const;
40 UnityMenuModel* menu() const;
38 void setMenu(UnityMenuModel* menu);
41 void setMenu(UnityMenuModel* menu);
39
42
40− int index() const;
43+ QString secondaryAction() const;
41− void setIndex(int index);
44+ QString scrollAction() const;
45+ QString submenuAction() const;
42
46
43 bool valid() const override;
47 bool valid() const override;
44
48
45Q_SIGNALS:
49Q_SIGNALS:
46 void menuChanged();
50 void menuChanged();
47− void indexChanged();
51+ void secondaryActionChanged();
52+ void scrollActionChanged();
53+ void submenuActionChanged();
48
54
49private Q_SLOTS:
55private Q_SLOTS:
50 void onModelRowsAdded(const QModelIndex& parent, int start, int end);
56 void onModelRowsAdded(const QModelIndex& parent, int start, int end);
@@ -54,8 +60,13 @@ private Q_SLOTS:
54
60
55private:
61private:
56 void updateActionState();
62 void updateActionState();
63+ void updateOtherActions();
57
64
58 UnityMenuModel* m_menu;
65 UnityMenuModel* m_menu;
66+ QString m_secondaryAction;
67+ QString m_scrollAction;
68+ QString m_submenuAction;
69+ bool m_reentryGuard;
59};
70};
60
71
61#endif // MODELACTIONROOTSTATE_H
72#endif // MODELACTIONROOTSTATE_H
qml/Components/VolumeControl.qml+1−6
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013-2015 Canonical, Ltd.
2+ * Copyright (C) 2013-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -28,10 +28,6 @@ Item {
28 readonly property int stepDown: -1
28 readonly property int stepDown: -1
29
29
30 property var indicators // passed from Shell.qml
30 property var indicators // passed from Shell.qml
31− readonly property bool showNotification: indicators && indicators.fullyOpened && indicators.currentIndicator === "indicator-sound"
32− onShowNotificationChanged: { // disallow the volume notification when using the slider, lpbug#1484126
33− actionGroup.indicatorsAction.updateState(root.showNotification);
34− }
35
31
36 GlobalShortcut {
32 GlobalShortcut {
37 id: muteShortcut
33 id: muteShortcut
@@ -47,7 +43,6 @@ Item {
47
43
48 property variant actionObject: action("volume")
44 property variant actionObject: action("volume")
49 property variant muteActionObject: indicators.indicatorsModel.profile === "desktop" ? action("mute") : action("silent-mode")
45 property variant muteActionObject: indicators.indicatorsModel.profile === "desktop" ? action("mute") : action("silent-mode")
50− property variant indicatorsAction: action("indicator-shown")
51 }
46 }
52
47
53 function volumeUp() {
48 function volumeUp() {
qml/Panel/IndicatorItem.qml+57−7
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013-2014 Canonical Ltd.
2+ * Copyright 2013-2016 Canonical Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -17,6 +17,7 @@
17import QtQuick 2.4
17import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Ubuntu.Settings.Components 0.1
19import Ubuntu.Settings.Components 0.1
20+import QMenuModel 0.1
20import "Indicators"
21import "Indicators"
21
22
22IndicatorDelegate {
23IndicatorDelegate {
@@ -36,13 +37,24 @@ IndicatorDelegate {
36 return "#ffffff";
37 return "#ffffff";
37 }
38 }
38
39
39− signal clicked()
40−
41 implicitWidth: mainItems.width
40 implicitWidth: mainItems.width
42
41
43 MouseArea {
42 MouseArea {
43+ readonly property int stepUp: 1
44+ readonly property int stepDown: -1
45+
44 anchors.fill: parent
46 anchors.fill: parent
47+ acceptedButtons: Qt.MiddleButton
45− onClicked: parent.clicked()
48+ onClicked: {
49+ if ((!expanded || selected) && secondaryAction.valid) {
50+ secondaryAction.activate();
51+ }
52+ }
53+ onWheel: {
54+ if ((!expanded || selected) && scrollAction.valid) {
55+ scrollAction.activate(wheel.angleDelta.y > 0 ? stepUp : stepDown);
56+ }
57+ }
46 }
58 }
47
59
48 Item {
60 Item {
@@ -152,9 +164,6 @@ IndicatorDelegate {
152 }
164 }
153
165
154 StateGroup {
166 StateGroup {
155− id: d
156− property bool useFallbackIcon: false
157−
158 states: [
167 states: [
159 State {
168 State {
160 name: "minimised"
169 name: "minimised"
@@ -251,4 +260,45 @@ IndicatorDelegate {
251 rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
260 rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
252 icons = rootActionState.icons;
261 icons = rootActionState.icons;
253 }
262 }
263+
264+ QtObject {
265+ id: d
266+
267+ property bool useFallbackIcon: false
268+ property var shouldIndicatorBeShown: undefined
269+
270+ onShouldIndicatorBeShownChanged: {
271+ if (shouldIndicatorBeShown !== undefined) {
272+ submenuAction.changeState(shouldIndicatorBeShown);
273+ }
274+ }
275+ }
276+
277+ UnityMenuAction {
278+ id: secondaryAction
279+ model: menuModel
280+ index: 0
281+ name: rootActionState.secondaryAction
282+ }
283+
284+ UnityMenuAction {
285+ id: scrollAction
286+ model: menuModel
287+ index: 0
288+ name: rootActionState.scrollAction
289+ }
290+
291+ UnityMenuAction {
292+ id: submenuAction
293+ model: menuModel
294+ index: 0
295+ name: rootActionState.submenuAction
296+ }
297+
298+ Binding {
299+ target: d
300+ property: "shouldIndicatorBeShown"
301+ when: submenuAction.valid
302+ value: root.selected && root.expanded
303+ }
254}
304}
tests/mocks/Unity/Indicators/ModelActionRootState.qml+11−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013-2016 Canonical Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -30,10 +30,20 @@ Item {
30 property bool indicatorVisible: cachedState && cachedState.hasOwnProperty("visible") ? cachedState["visible"] : true
30 property bool indicatorVisible: cachedState && cachedState.hasOwnProperty("visible") ? cachedState["visible"] : true
31
31
32 property var cachedState: menu ? menu.get(0, "actionState") : undefined
32 property var cachedState: menu ? menu.get(0, "actionState") : undefined
33+ property string submenuAction: {
34+ if (!menu) return "";
35+ var ext = menu.get(0, "ext");
36+ var submenuVar = ext ? ext["submenu-action"] : undefined;
37+ return submenuVar ? submenuVar : ""
38+ }
33 Connections {
39 Connections {
34 target: menu
40 target: menu
35 onModelDataChanged: {
41 onModelDataChanged: {
36 cachedState = menu.get(0, "actionState");
42 cachedState = menu.get(0, "actionState");
43+
44+ var ext = menu.get(0, "ext");
45+ var submenuVar = ext ? ext["submenu-action"] : undefined;
46+ submenuAction = submenuVar ? submenuVar : ""
37 }
47 }
38 }
48 }
39
49