Merge lp:~nick-dedekind/unity8/menu.overflow into lp:unity8

Proposed by Nick Dedekind
Status: Superseded
Proposed branch: lp:~nick-dedekind/unity8/menu.overflow
Merge into: lp:unity8
Prerequisite: lp:~nick-dedekind/unity8/menu.width.fix
Diff against target: 1066 lines (+553/-188)
12 files modified
plugins/Utils/CMakeLists.txt (+1/-0)
plugins/Utils/expressionfiltermodel.cpp (+49/-0)
plugins/Utils/expressionfiltermodel.h (+42/-0)
plugins/Utils/plugin.cpp (+2/-0)
qml/ApplicationMenus/MenuBar.qml (+312/-168)
qml/ApplicationMenus/MenuItem.qml (+3/-1)
qml/ApplicationMenus/MenuNavigator.qml (+23/-0)
qml/ApplicationMenus/MenuPopup.qml (+46/-10)
qml/Panel/Panel.qml (+3/-1)
tests/mocks/Utils/CMakeLists.txt (+1/-0)
tests/mocks/Utils/plugin.cpp (+2/-0)
tests/qmltests/ApplicationMenus/tst_MenuBar.qml (+69/-8)
To merge this branch: bzr merge lp:~nick-dedekind/unity8/menu.overflow
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
Lukáš Tinkl (community) Needs Fixing
Review via email: mp+315449@code.launchpad.net

This proposal has been superseded by a proposal from 2017-01-30.

Commit message

Added overflow support to application menus.
Hover timer for auto-scrolling menu popup overflow.

Description of the change

* Are there any related MPs required for this MP to build/function as expected? Please list.
N/A

 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

 * If you changed the UI, has there been a design review?
Yes

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

/<<BUILDDIR>>/unity8-8.15+17.04.20170110.4+fetch3941bzr2778/qml/ApplicationMenus/MenuNavigator.qml: bad whitespace in line 83

review: Needs Fixing
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:2780
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3015/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3922
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2299
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2299
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3950
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3795
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3795/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3795
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3795/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3795
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3795/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3795
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3795/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3795
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3795/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3795
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3795/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3015/rebuild

review: Approve (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2781
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3018/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3925
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2301
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2301
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3953
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3798
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3798/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3798
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3798/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3798
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3798/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3798
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3798/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3798
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3798/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3798
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3798/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3018/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

MenuNavigator.qml: bad whitespace in line 83

Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in plugins/Utils/CMakeLists.txt
Text conflict in plugins/Utils/plugin.cpp
Text conflict in tests/mocks/Utils/CMakeLists.txt
Text conflict in tests/mocks/Utils/plugin.cpp
Text conflict in tests/qmltests/ApplicationMenus/tst_MenuBar.qml
5 conflicts encountered.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> Text conflict in plugins/Utils/CMakeLists.txt
> Text conflict in plugins/Utils/plugin.cpp
> Text conflict in tests/mocks/Utils/CMakeLists.txt
> Text conflict in tests/mocks/Utils/plugin.cpp
> Text conflict in tests/qmltests/ApplicationMenus/tst_MenuBar.qml
> 5 conflicts encountered.

merged

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2782
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3042/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3957
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2313
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2313
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3985
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3830
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3830/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3830
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3830/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3830
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3830/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3830
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3830/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3830
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3830/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3830
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3830/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3042/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:2782
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3049/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3964
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2317
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2317
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3992
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3837
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3837/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3837
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3837/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3837
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3837/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3837
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3837/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3837
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3837/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3837
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3837/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3049/rebuild

review: Approve (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2785
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3085/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/4010
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2350
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2350
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4038
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3882
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3882/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3882
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3882/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3882
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3882/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3882
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3882/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3882
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3882/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3882
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3882/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3085/rebuild

review: Needs Fixing (continuous-integration)
2786. By Nick Dedekind

removed height change

2787. By Nick Dedekind

moved shouldDisplay connection

2788. By Nick Dedekind

include panel height in max height calc

2789. By Nick Dedekind

readd tests

2790. By Nick Dedekind

review comments

2791. By Nick Dedekind

merged with parent

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Utils/CMakeLists.txt'
2--- plugins/Utils/CMakeLists.txt 2016-12-21 10:20:36 +0000
3+++ plugins/Utils/CMakeLists.txt 2017-01-30 14:46:20 +0000
4@@ -35,6 +35,7 @@
5 globalfunctions.cpp
6 URLDispatcher.cpp
7 tabfocusfence.cpp
8+ expressionfiltermodel.cpp
9 plugin.cpp
10 )
11
12
13=== added file 'plugins/Utils/expressionfiltermodel.cpp'
14--- plugins/Utils/expressionfiltermodel.cpp 1970-01-01 00:00:00 +0000
15+++ plugins/Utils/expressionfiltermodel.cpp 2017-01-30 14:46:20 +0000
16@@ -0,0 +1,49 @@
17+/*
18+ * Copyright (C) 2017 Canonical, Ltd.
19+ *
20+ * This program is free software; you can redistribute it and/or modify
21+ * it under the terms of the GNU General Public License as published by
22+ * the Free Software Foundation; version 3.
23+ *
24+ * This program is distributed in the hope that it will be useful,
25+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+ * GNU General Public License for more details.
28+ *
29+ * You should have received a copy of the GNU General Public License
30+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
31+ */
32+
33+#include "expressionfiltermodel.h"
34+
35+ExpressionFilterModel::ExpressionFilterModel(QObject *parent)
36+ : UnitySortFilterProxyModelQML(parent)
37+{
38+}
39+
40+QJSValue ExpressionFilterModel::matchExpression() const
41+{
42+ return m_matchExpression;
43+}
44+
45+void ExpressionFilterModel::setMatchExpression(const QJSValue &value)
46+{
47+ m_matchExpression = value;
48+ invalidateFilter();
49+}
50+
51+bool
52+ExpressionFilterModel::filterAcceptsRow(int sourceRow,
53+ const QModelIndex &sourceParent) const
54+{
55+ if (m_matchExpression.isCallable()) {
56+ QJSValueList args;
57+ args << sourceRow;
58+ QJSValue ret = m_matchExpression.call(args);
59+ if (ret.isBool()) {
60+ return ret.toBool();
61+ }
62+ }
63+
64+ return UnitySortFilterProxyModelQML::filterAcceptsRow(sourceRow, sourceParent);
65+}
66
67=== added file 'plugins/Utils/expressionfiltermodel.h'
68--- plugins/Utils/expressionfiltermodel.h 1970-01-01 00:00:00 +0000
69+++ plugins/Utils/expressionfiltermodel.h 2017-01-30 14:46:20 +0000
70@@ -0,0 +1,42 @@
71+/*
72+ * Copyright (C) 2017 Canonical, Ltd.
73+ *
74+ * This program is free software; you can redistribute it and/or modify
75+ * it under the terms of the GNU General Public License as published by
76+ * the Free Software Foundation; version 3.
77+ *
78+ * This program is distributed in the hope that it will be useful,
79+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
80+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81+ * GNU General Public License for more details.
82+ *
83+ * You should have received a copy of the GNU General Public License
84+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
85+ */
86+
87+#ifndef EXPRESSIONFILTERMODEL_H
88+#define EXPRESSIONFILTERMODEL_H
89+
90+#include "unitysortfilterproxymodelqml.h"
91+#include <QJSValue>
92+
93+class ExpressionFilterModel : public UnitySortFilterProxyModelQML
94+{
95+ Q_OBJECT
96+ Q_PROPERTY(QJSValue matchExpression READ matchExpression WRITE setMatchExpression NOTIFY matchExpressionChanged)
97+public:
98+ explicit ExpressionFilterModel(QObject *parent = 0);
99+
100+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
101+
102+ QJSValue matchExpression() const;
103+ void setMatchExpression(const QJSValue& value);
104+
105+Q_SIGNALS:
106+ void matchExpressionChanged();
107+
108+private:
109+ mutable QJSValue m_matchExpression;
110+};
111+
112+#endif // EXPRESSIONFILTERMODEL_H
113
114=== modified file 'plugins/Utils/plugin.cpp'
115--- plugins/Utils/plugin.cpp 2017-01-03 12:16:00 +0000
116+++ plugins/Utils/plugin.cpp 2017-01-30 14:46:20 +0000
117@@ -41,6 +41,7 @@
118 #include "URLDispatcher.h"
119 #include "appdrawerproxymodel.h"
120 #include "tabfocusfence.h"
121+#include "expressionfiltermodel.h"
122
123 static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
124 {
125@@ -86,4 +87,5 @@
126 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
127 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
128 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
129+ qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
130 }
131
132=== modified file 'qml/ApplicationMenus/MenuBar.qml'
133--- qml/ApplicationMenus/MenuBar.qml 2017-01-17 09:45:22 +0000
134+++ qml/ApplicationMenus/MenuBar.qml 2017-01-30 14:46:20 +0000
135@@ -24,12 +24,13 @@
136 id: root
137 objectName: "menuBar"
138
139+ // set from outside
140 property alias unityMenuModel: rowRepeater.model
141+ property bool enableKeyFilter: false
142+ property real overflowWidth: width
143
144+ // read from outside
145 readonly property bool valid: rowRepeater.count > 0
146-
147- property bool enableKeyFilter: false
148-
149 readonly property bool showRequested: d.longAltPressed || d.currentItem != null
150
151 implicitWidth: row.width
152@@ -78,186 +79,325 @@
153 onPressed: d.dismissAll()
154 }
155
156- Item {
157- id: clippingItem
158-
159- height: root.height
160- width: root.width
161- clip: true
162-
163- Row {
164- id: row
165- spacing: units.gu(2)
166- height: parent.height
167-
168- ActionContext {
169- id: menuBarContext
170- objectName: "barContext"
171- active: !d.currentItem && enableKeyFilter
172- }
173-
174- Repeater {
175- id: rowRepeater
176-
177- Item {
178- id: visualItem
179- objectName: root.objectName + "-item" + __ownIndex
180-
181- readonly property int __ownIndex: index
182- property Item __popup: null;
183- property bool popupVisible: __popup && __popup.visible
184-
185- implicitWidth: column.implicitWidth
186- implicitHeight: row.height
187- enabled: model.sensitive
188-
189- function show() {
190- if (!__popup) {
191- __popup = menuComponent.createObject(root, { objectName: visualItem.objectName + "-menu" });
192- // force the current item to be the newly popped up menu
193- } else {
194- __popup.show();
195- }
196- d.currentItem = visualItem;
197- }
198- function hide() {
199- if (__popup) {
200- __popup.hide();
201-
202- if (d.currentItem === visualItem) {
203- d.currentItem = null;
204- }
205- }
206- }
207- function dismiss() {
208- if (__popup) {
209- __popup.destroy();
210- __popup = null;
211-
212- if (d.currentItem === visualItem) {
213- d.currentItem = null;
214- }
215- }
216- }
217-
218- Connections {
219- target: d
220- onDismissAll: visualItem.dismiss()
221- }
222-
223- Component {
224- id: menuComponent
225- MenuPopup {
226- x: visualItem.x - units.gu(1)
227- anchors.top: parent.bottom
228- unityMenuModel: root.unityMenuModel.submenu(visualItem.__ownIndex)
229-
230- Component.onCompleted: reset();
231- }
232- }
233-
234- RowLayout {
235- id: column
236- spacing: units.gu(1)
237- anchors {
238- centerIn: parent
239- }
240-
241- Icon {
242- Layout.preferredWidth: units.gu(2)
243- Layout.preferredHeight: units.gu(2)
244- Layout.alignment: Qt.AlignVCenter
245-
246- visible: model.icon || false
247- source: model.icon || ""
248- }
249-
250- ActionItem {
251- id: actionItem
252- width: _title.width
253- height: _title.height
254-
255- action: Action {
256- // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
257- text: model.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
258-
259- onTriggered: {
260- visualItem.show();
261- }
262- }
263-
264- Label {
265- id: _title
266- text: actionItem.text
267- horizontalAlignment: Text.AlignLeft
268- color: enabled ? "white" : "#5d5d5d"
269- }
270- }
271- }
272- } // Item ( delegate )
273- } // Repeater
274- } // Row
275-
276- MouseArea {
277- anchors.fill: parent
278- hoverEnabled: d.currentItem
279-
280- onEntered: {
281- if (d.currentItem) {
282- updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))
283- }
284- }
285- onPositionChanged: {
286- if (d.currentItem) {
287- updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
288- }
289- }
290- onClicked: updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
291-
292- function updateCurrentItemFromPosition(point) {
293- var pos = mapToItem(row, point.x, point.y);
294-
295- if (!d.hoveredItem || !d.currentItem || !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
296- d.hoveredItem = row.childAt(pos.x, pos.y);
297- if (!d.hoveredItem || !d.hoveredItem.enabled)
298- return false;
299- if (d.currentItem != d.hoveredItem) {
300- d.currentItem = d.hoveredItem;
301- }
302- }
303- return true;
304- }
305- }
306-
307- Rectangle {
308- id: underline
309- anchors {
310- bottom: row.bottom
311- }
312- x: d.currentItem ? row.x + d.currentItem.x - units.gu(1) : 0
313- width: d.currentItem ? d.currentItem.width + units.gu(2) : 0
314- height: units.dp(4)
315- color: UbuntuColors.orange
316- visible: d.currentItem
317- }
318+ Row {
319+ id: row
320+ spacing: units.gu(2)
321+ height: parent.height
322+
323+ ActionContext {
324+ id: menuBarContext
325+ objectName: "barContext"
326+ active: !d.currentItem && enableKeyFilter
327+ }
328+
329+ Connections {
330+ target: root.unityMenuModel
331+ onModelReset: d.firstInvisibleIndex = undefined
332+ }
333+
334+ Repeater {
335+ id: rowRepeater
336+
337+ onItemAdded: d.recalcFirstInvisibleIndexAdded(index, item)
338+ onCountChanged: d.recalcFirstInvisibleIndex()
339+
340+ Item {
341+ id: visualItem
342+ objectName: root.objectName + "-item" + __ownIndex
343+
344+ readonly property int __ownIndex: index
345+ property Item __popup: null;
346+ property bool popupVisible: __popup && __popup.visible
347+ property bool shouldDisplay: x + width + ((__ownIndex < rowRepeater.count-1) ? units.gu(2) : 0) <
348+ root.overflowWidth - ((__ownIndex < rowRepeater.count-1) ? overflowButton.width : 0)
349+
350+ implicitWidth: column.implicitWidth
351+ implicitHeight: row.height
352+ enabled: model.sensitive && shouldDisplay
353+ opacity: shouldDisplay ? 1 : 0
354+
355+ function show() {
356+ if (!__popup) {
357+ __popup = menuComponent.createObject(root, { objectName: visualItem.objectName + "-menu" });
358+ __popup.childActivated.connect(dismiss);
359+ // force the current item to be the newly popped up menu
360+ } else {
361+ __popup.show();
362+ }
363+ d.currentItem = visualItem;
364+ }
365+ function hide() {
366+ if (__popup) {
367+ __popup.hide();
368+
369+ if (d.currentItem === visualItem) {
370+ d.currentItem = null;
371+ }
372+ }
373+ }
374+ function dismiss() {
375+ if (__popup) {
376+ __popup.destroy();
377+ __popup = null;
378+
379+ if (d.currentItem === visualItem) {
380+ d.currentItem = null;
381+ }
382+ }
383+ }
384+
385+ onVisibleChanged: {
386+ if (!visible && __popup) dismiss();
387+ }
388+
389+ Component.onCompleted: {
390+ shouldDisplayChanged.connect(function() {
391+ if ((!shouldDisplay && d.firstInvisibleIndex == undefined) || __ownIndex <= d.firstInvisibleIndex) {
392+ d.recalcFirstInvisibleIndex();
393+ }
394+ });
395+ }
396+
397+ Connections {
398+ target: d
399+ onDismissAll: visualItem.dismiss()
400+ }
401+
402+ Component {
403+ id: menuComponent
404+ MenuPopup {
405+ x: visualItem.x - units.gu(1)
406+ anchors.top: parent.bottom
407+ unityMenuModel: root.unityMenuModel.submenu(visualItem.__ownIndex)
408+
409+ Component.onCompleted: reset();
410+ }
411+ }
412+
413+ RowLayout {
414+ id: column
415+ spacing: units.gu(1)
416+ anchors {
417+ centerIn: parent
418+ }
419+
420+ Icon {
421+ Layout.preferredWidth: units.gu(2)
422+ Layout.preferredHeight: units.gu(2)
423+ Layout.alignment: Qt.AlignVCenter
424+
425+ visible: model.icon || false
426+ source: model.icon || ""
427+ }
428+
429+ ActionItem {
430+ id: actionItem
431+ width: _title.width
432+ height: _title.height
433+
434+ action: Action {
435+ enabled: visualItem.enabled
436+ // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
437+ text: model.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
438+
439+ onTriggered: {
440+ visualItem.show();
441+ }
442+ }
443+
444+ Label {
445+ id: _title
446+ text: actionItem.text
447+ horizontalAlignment: Text.AlignLeft
448+ color: enabled ? "white" : "#5d5d5d"
449+ }
450+ }
451+ }
452+ } // Item ( delegate )
453+ } // Repeater
454+ } // Row
455+
456+ MouseArea {
457+ anchors.fill: parent
458+ hoverEnabled: d.currentItem
459+
460+ onEntered: {
461+ if (d.currentItem) {
462+ updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))
463+ }
464+ }
465+ onPositionChanged: {
466+ if (d.currentItem) {
467+ updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
468+ }
469+ }
470+ onClicked: updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
471+
472+ function updateCurrentItemFromPosition(point) {
473+ var pos = mapToItem(row, point.x, point.y);
474+
475+ if (!d.hoveredItem || !d.currentItem || !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
476+ d.hoveredItem = row.childAt(pos.x, pos.y);
477+ if (!d.hoveredItem || !d.hoveredItem.enabled)
478+ return;
479+ if (d.currentItem != d.hoveredItem) {
480+ d.currentItem = d.hoveredItem;
481+ }
482+ }
483+ }
484+ }
485+
486+ MouseArea {
487+ id: overflowButton
488+ objectName: "overflow"
489+
490+ hoverEnabled: d.currentItem
491+ onEntered: d.currentItem = this
492+ onPositionChanged: d.currentItem = this
493+ onClicked: d.currentItem = this
494+
495+ property Item __popup: null;
496+ property bool popupVisible: __popup && __popup.visible
497+ property Item firstInvisibleItem: d.firstInvisibleIndex !== undefined ? rowRepeater.itemAt(d.firstInvisibleIndex) : null
498+
499+ visible: d.firstInvisibleIndex != undefined
500+ x: firstInvisibleItem ? firstInvisibleItem.x : 0
501+
502+ height: parent.height
503+ width: units.gu(4)
504+
505+ onVisibleChanged: {
506+ if (!visible && __popup) dismiss();
507+ }
508+
509+ Icon {
510+ id: icon
511+ width: units.gu(2)
512+ height: units.gu(2)
513+ anchors.centerIn: parent
514+ color: theme.palette.normal.overlayText
515+ name: "toolkit_chevron-down_2gu"
516+ }
517+
518+ function show() {
519+ if (!__popup) {
520+ __popup = overflowComponent.createObject(root, { objectName: overflowButton.objectName + "-menu" });
521+ // force the current item to be the newly popped up menu
522+ } else {
523+ __popup.show();
524+ }
525+ d.currentItem = overflowButton;
526+ }
527+ function hide() {
528+ if (__popup) {
529+ __popup.hide();
530+
531+ if (d.currentItem === overflowButton) {
532+ d.currentItem = null;
533+ }
534+ }
535+ }
536+ function dismiss() {
537+ if (__popup) {
538+ __popup.destroy();
539+ __popup = null;
540+
541+ if (d.currentItem === overflowButton) {
542+ d.currentItem = null;
543+ }
544+ }
545+ }
546+
547+ Connections {
548+ target: d
549+ onDismissAll: overflowButton.dismiss()
550+ }
551+
552+ Component {
553+ id: overflowComponent
554+ MenuPopup {
555+ id: overflowPopup
556+ x: overflowButton.x - units.gu(1)
557+ anchors.top: parent.bottom
558+ unityMenuModel: overflowModel
559+
560+ ExpressionFilterModel {
561+ id: overflowModel
562+ sourceModel: root.unityMenuModel
563+ matchExpression: function(index) {
564+ if (d.firstInvisibleIndex === undefined) return false;
565+ return index >= d.firstInvisibleIndex;
566+ }
567+
568+ function submenu(index) {
569+ return sourceModel.submenu(mapRowToSource(index));
570+ }
571+ function activate(index) {
572+ return sourceModel.activate(mapRowToSource(index));
573+ }
574+ }
575+
576+ Connections {
577+ target: d
578+ onFirstInvisibleIndexChanged: overflowModel.invalidate()
579+ }
580+ }
581+ }
582+ }
583+
584+ Rectangle {
585+ id: underline
586+ anchors {
587+ bottom: row.bottom
588+ }
589+ x: d.currentItem ? row.x + d.currentItem.x - units.gu(1) : 0
590+ width: d.currentItem ? d.currentItem.width + units.gu(2) : 0
591+ height: units.dp(4)
592+ color: UbuntuColors.orange
593+ visible: d.currentItem
594 }
595
596 MenuNavigator {
597 id: d
598 objectName: "d"
599 itemView: rowRepeater
600+ hasOverflow: overflowButton.visible
601
602 property Item currentItem: null
603 property Item hoveredItem: null
604 property Item prevCurrentItem: null
605-
606- readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
607-
608 property bool altPressed: false
609 property bool longAltPressed: false
610+ property var firstInvisibleIndex: undefined
611+
612+ readonly property int currentIndex: currentItem && currentItem.hasOwnProperty("__ownIndex") ? currentItem.__ownIndex : -1
613
614 signal dismissAll()
615
616+ function recalcFirstInvisibleIndexAdded(index, item) {
617+ if (firstInvisibleIndex === undefined) {
618+ if (!item.shouldDisplay) {
619+ firstInvisibleIndex = index;
620+ }
621+ } else if (index <= firstInvisibleIndex) {
622+ if (!item.shouldDisplay) {
623+ firstInvisibleIndex = index;
624+ } else {
625+ firstInvisibleIndex++;
626+ }
627+ }
628+ }
629+
630+ function recalcFirstInvisibleIndex() {
631+ for (var i = 0; i < rowRepeater.count; i++) {
632+ if (!rowRepeater.itemAt(i).shouldDisplay) {
633+ firstInvisibleIndex = i;
634+ return;
635+ }
636+ }
637+ firstInvisibleIndex = undefined;
638+ }
639+
640 onSelect: {
641 var delegate = rowRepeater.itemAt(index);
642 if (delegate) {
643@@ -265,6 +405,10 @@
644 }
645 }
646
647+ onOverflow: {
648+ d.currentItem = overflowButton;
649+ }
650+
651 onCurrentItemChanged: {
652 if (prevCurrentItem && prevCurrentItem != currentItem) {
653 if (currentItem) {
654
655=== modified file 'qml/ApplicationMenus/MenuItem.qml'
656--- qml/ApplicationMenus/MenuItem.qml 2016-12-13 09:56:20 +0000
657+++ qml/ApplicationMenus/MenuItem.qml 2017-01-30 14:46:20 +0000
658@@ -46,6 +46,8 @@
659 enabled: menuData ? menuData.sensitive : false
660
661 action: Action {
662+ enabled: root.enabled
663+
664 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
665 text: menuData.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
666 checkable: menuData.isCheck || menuData.isRadio
667@@ -137,7 +139,7 @@
668 theme.palette.disabled.backgroundSecondaryText
669
670 visible: root.hasSubmenu
671- name: "chevron"
672+ name: "toolkit_chevron-ltr_2gu"
673 }
674 }
675
676
677=== modified file 'qml/ApplicationMenus/MenuNavigator.qml'
678--- qml/ApplicationMenus/MenuNavigator.qml 2016-11-28 13:44:30 +0000
679+++ qml/ApplicationMenus/MenuNavigator.qml 2017-01-30 14:46:20 +0000
680@@ -18,8 +18,10 @@
681
682 QtObject {
683 property Item itemView: null
684+ property bool hasOverflow: false
685
686 signal select(int index)
687+ signal overflow()
688
689 function selectNext(currentIndex) {
690 var menu;
691@@ -32,6 +34,11 @@
692 break;
693 }
694 newIndex++;
695+
696+ if (hasOverflow && newIndex === itemView.count) {
697+ overflow()
698+ break;
699+ }
700 }
701 } else if (currentIndex !== -1 && itemView.count > 1) {
702 var startIndex = (currentIndex + 1) % itemView.count;
703@@ -42,6 +49,12 @@
704 select(newIndex);
705 break;
706 }
707+
708+ if (hasOverflow && newIndex + 1 === itemView.count) {
709+ overflow()
710+ break;
711+ }
712+
713 newIndex = (newIndex + 1) % itemView.count;
714 } while (newIndex !== startIndex)
715 }
716@@ -58,12 +71,21 @@
717 break;
718 }
719 newIndex--;
720+
721+ if (hasOverflow && newIndex < 0 ) {
722+ overflow();
723+ break;
724+ }
725 }
726 } else if (currentIndex !== -1 && itemView.count > 1) {
727 var startIndex = currentIndex - 1;
728 newIndex = startIndex;
729 do {
730 if (newIndex < 0) {
731+ if (hasOverflow) {
732+ overflow();
733+ break;
734+ }
735 newIndex = itemView.count - 1;
736 }
737 menu = itemView.itemAt(newIndex);
738@@ -72,6 +94,7 @@
739 break;
740 }
741 newIndex--;
742+
743 } while (newIndex !== startIndex)
744 }
745 }
746
747=== modified file 'qml/ApplicationMenus/MenuPopup.qml'
748--- qml/ApplicationMenus/MenuPopup.qml 2017-01-18 12:08:05 +0000
749+++ qml/ApplicationMenus/MenuPopup.qml 2017-01-30 14:46:20 +0000
750@@ -26,6 +26,8 @@
751 objectName: "menu"
752 backgroundColor: theme.palette.normal.overlay
753
754+ signal childActivated()
755+
756 property alias unityMenuModel: repeater.model
757
758 function show() {
759@@ -66,7 +68,7 @@
760 property real __minimumWidth: units.gu(20)
761 property real __maximumWidth: Screen.width * 0.7
762 property real __minimumHeight: units.gu(2)
763- property real __maximumHeight: Screen.height * 0.7
764+ property real __maximumHeight: Screen.height - mapToItem(null, 0, y).y
765
766 signal dismissAll()
767
768@@ -147,8 +149,20 @@
769 }
770
771 MouseArea {
772+ id: previousMA
773 anchors.fill: parent
774- onPressed: {
775+ hoverEnabled: enabled
776+ onPressed: progress()
777+
778+ Timer {
779+ running: previousMA.containsMouse && !listView.atYBeginning
780+ interval: 1000
781+ repeat: true
782+ onTriggered: previousMA.progress()
783+ }
784+
785+ function progress() {
786+ console.log("progress!")
787 var item = menuColumn.childAt(0, listView.contentY);
788 if (item) {
789 var previousItem = item;
790@@ -191,10 +205,9 @@
791 !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
792 d.hoveredItem = menuColumn.childAt(pos.x, pos.y)
793 if (!d.hoveredItem || !d.hoveredItem.enabled)
794- return false;
795+ return;
796 d.currentItem = d.hoveredItem;
797 }
798- return true;
799 }
800 }
801
802@@ -263,16 +276,22 @@
803 return mapToItem(container, 0, y).y;
804 })
805 });
806+ popup.retreat.connect(function() {
807+ popup.destroy();
808+ popup = null;
809+ menuItem.forceActiveFocus();
810+ });
811+ popup.childActivated.connect(function() {
812+ popup.destroy();
813+ popup = null;
814+ root.childActivated();
815+ });
816 } else if (popup) {
817 popup.visible = true;
818 }
819- popup.retreat.connect(function() {
820- popup.destroy();
821- popup = null;
822- menuItem.forceActiveFocus();
823- })
824 } else {
825 root.unityMenuModel.activate(__ownIndex);
826+ root.childActivated();
827 }
828 }
829
830@@ -349,8 +368,19 @@
831 }
832
833 MouseArea {
834+ id: nextMA
835 anchors.fill: parent
836- onPressed: {
837+ hoverEnabled: enabled
838+ onPressed: progress()
839+
840+ Timer {
841+ running: nextMA.containsMouse && !listView.atYEnd
842+ interval: 1000
843+ repeat: true
844+ onTriggered: nextMA.progress()
845+ }
846+
847+ function progress() {
848 var item = menuColumn.childAt(0, listView.contentY + listView.height);
849 if (item) {
850 var nextItem = item;
851@@ -377,6 +407,7 @@
852
853 property var unityMenuModel: null
854 signal retreat()
855+ signal childActivated()
856
857 Binding {
858 target: item
859@@ -392,6 +423,11 @@
860
861 Keys.onLeftPressed: retreat()
862
863+ Connections {
864+ target: item
865+ onChildActivated: childActivated();
866+ }
867+
868 Component.onCompleted: item.select(0);
869 onVisibleChanged: if (visible) { item.select(0); }
870 }
871
872=== modified file 'qml/Panel/Panel.qml'
873--- qml/Panel/Panel.qml 2017-01-09 14:10:17 +0000
874+++ qml/Panel/Panel.qml 2017-01-30 14:46:20 +0000
875@@ -209,6 +209,8 @@
876 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
877 active: __applicationMenus.model
878
879+ width: parent.width - windowControlButtons.width - units.gu(2) - __indicators.barWidth
880+
881 property bool menusRequested: menuBarLoader.item ? menuBarLoader.item.showRequested : false
882
883 sourceComponent: MenuBar {
884@@ -385,7 +387,7 @@
885 }
886
887 enabled: !applicationMenus.expanded
888- opacity: !applicationMenus.expanded ? 1 : 0
889+ opacity: !callHint.visible && !applicationMenus.expanded ? 1 : 0
890 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
891
892 onEnabledChanged: {
893
894=== modified file 'tests/mocks/Utils/CMakeLists.txt'
895--- tests/mocks/Utils/CMakeLists.txt 2016-12-21 10:20:36 +0000
896+++ tests/mocks/Utils/CMakeLists.txt 2017-01-30 14:46:20 +0000
897@@ -26,6 +26,7 @@
898 ${CMAKE_SOURCE_DIR}/plugins/Utils/globalfunctions.cpp
899 ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp
900 ${CMAKE_SOURCE_DIR}/plugins/Utils/tabfocusfence.cpp
901+ ${CMAKE_SOURCE_DIR}/plugins/Utils/expressionfiltermodel.cpp
902 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
903 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
904 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
905
906=== modified file 'tests/mocks/Utils/plugin.cpp'
907--- tests/mocks/Utils/plugin.cpp 2017-01-03 12:16:00 +0000
908+++ tests/mocks/Utils/plugin.cpp 2017-01-30 14:46:20 +0000
909@@ -42,6 +42,7 @@
910 #include <globalfunctions.h>
911 #include <appdrawerproxymodel.h>
912 #include <tabfocusfence.h>
913+#include <expressionfiltermodel.h>
914
915 static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
916 {
917@@ -86,4 +87,5 @@
918 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
919 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
920 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
921+ qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
922 }
923
924=== modified file 'tests/qmltests/ApplicationMenus/tst_MenuBar.qml'
925--- tests/qmltests/ApplicationMenus/tst_MenuBar.qml 2017-01-24 07:41:35 +0000
926+++ tests/qmltests/ApplicationMenus/tst_MenuBar.qml 2017-01-30 14:46:20 +0000
927@@ -28,8 +28,8 @@
928
929 Item {
930 id: root
931- width: units.gu(100)
932- height: units.gu(50)
933+ width: units.gu(120)
934+ height: units.gu(70)
935
936 Component.onCompleted: {
937 QuickUtils.keyboardAttached = true;
938@@ -51,11 +51,11 @@
939 Rectangle {
940 anchors {
941 left: parent.left
942- right: parent.right
943 top: parent.top
944 margins: units.gu(1)
945 }
946 height: units.gu(3)
947+ width: parent.width * 2/3
948 color: "grey"
949
950 MenuBar {
951@@ -65,7 +65,7 @@
952
953 unityMenuModel: UnityMenuModel {
954 id: menuBackend
955- modelData: appMenuData.generateTestData(17,5,2,3)
956+ modelData: appMenuData.generateTestData(10,5,2,3)
957 }
958 }
959 }
960@@ -83,12 +83,12 @@
961
962 function init() {
963 menuBar.dismiss();
964- menuBackend.modelData = appMenuData.generateTestData(5,5,2,3)
965+ menuBackend.modelData = appMenuData.generateTestData(5,5,2,3, "menu")
966 activatedSpy.clear();
967 }
968
969 function test_mouseNavigation() {
970- menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
971+ menuBackend.modelData = appMenuData.generateTestData(3,3,0,0, "menu");
972 wait(50) // wait for row to build
973 var priv = findInvisibleChild(menuBar, "d");
974
975@@ -114,7 +114,7 @@
976 }
977
978 function test_keyboardNavigation_RightKeySelectsNextMenuItem(data) {
979- menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
980+ menuBackend.modelData = appMenuData.generateTestData(3,3,0,0, "menu");
981 var priv = findInvisibleChild(menuBar, "d");
982
983 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
984@@ -139,7 +139,7 @@
985 }
986
987 function test_keyboardNavigation_LeftKeySelectsPreviousMenuItem(data) {
988- menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
989+ menuBackend.modelData = appMenuData.generateTestData(3,3,0,0, "menu");
990 var priv = findInvisibleChild(menuBar, "d");
991
992 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
993@@ -180,6 +180,41 @@
994 tryCompare(priv, "currentItem", menuItem);
995 }
996
997+ function test_menuActivateClosesMenu() {
998+ menuBackend.modelData = appMenuData.generateTestData(3,3,0,0,"menu");
999+ var priv = findInvisibleChild(menuBar, "d");
1000+
1001+ var menuItem = findChild(menuBar, "menuBar-item0");
1002+ menuItem.show();
1003+ compare(priv.currentItem, menuItem, "CurrentItem should be set to item 0");
1004+ compare(priv.currentItem.popupVisible, true, "Popup should be visible");
1005+
1006+ var actionItem = findChild(menuBar, "menuBar-item0-menu-item0-actionItem");
1007+ mouseClick(actionItem);
1008+ compare(priv.currentItem, null, "CurrentItem should be null");
1009+ }
1010+
1011+ function test_subMenuActivateClosesMenu() {
1012+ menuBackend.modelData = appMenuData.generateTestData(3,4,1,0,"menu");
1013+ var priv = findInvisibleChild(menuBar, "d");
1014+
1015+ var menuItem = findChild(menuBar, "menuBar-item0");
1016+ menuItem.show();
1017+ compare(priv.currentItem, menuItem, "CurrentItem should be set to item 0");
1018+ compare(priv.currentItem.popupVisible, true, "Popup should be visible");
1019+
1020+ var actionItem = findChild(menuBar, "menuBar-item0-menu-item0-actionItem");
1021+ mouseClick(actionItem);
1022+
1023+ actionItem = findChild(menuBar, "menuBar-item0-menu-item0-menu-item0-actionItem");
1024+ mouseClick(actionItem);
1025+
1026+ actionItem = findChild(menuBar, "menuBar-item0-menu-item0-menu-item0-menu-item0-actionItem");
1027+ mouseClick(actionItem);
1028+
1029+ compare(priv.currentItem, null, "CurrentItem should be null");
1030+ }
1031+
1032 function test_openAppMenuShortcut() {
1033 var priv = findInvisibleChild(menuBar, "d");
1034
1035@@ -192,5 +227,31 @@
1036 keyClick(Qt.Key_F10, Qt.AltModifier);
1037 compare(priv.currentItem, menuItem1, "First enabled item should be opened");
1038 }
1039+
1040+ function test_overfow() {
1041+ menuBackend.modelData = appMenuData.generateTestData(5,2,0,0,"menu");
1042+
1043+ var overflow = findChild(menuBar, "overflow");
1044+ compare(overflow.visible, false, "Overflow should not be visible");
1045+
1046+ var menu = { "rowData": { "label": "Short" } };
1047+ tryCompareFunction(function() {
1048+ menuBackend.insertRow(0, menu);
1049+ wait(1);
1050+ if (overflow.visible) {
1051+ return true;
1052+ }
1053+ return false;
1054+ }, true);
1055+
1056+ tryCompareFunction(function() {
1057+ menuBackend.removeRow(0);
1058+ wait(1);
1059+ if (!overflow.visible) {
1060+ return true;
1061+ }
1062+ return false;
1063+ }, true);
1064+ }
1065 }
1066 }

Subscribers

People subscribed via source and target branches