on xenial help sign in
Added menu overflow
0c2d897Nick Dedekind
plugins/Utils/CMakeLists.txt+1
@@ -34,6 +34,7 @@ set(QMLPLUGIN_SRC
34 deviceconfigparser.cpp
34 deviceconfigparser.cpp
35 globalfunctions.cpp
35 globalfunctions.cpp
36 URLDispatcher.cpp
36 URLDispatcher.cpp
37+ expressionfiltermodel.cpp
37 plugin.cpp
38 plugin.cpp
38 )
39 )
39
40
plugins/Utils/expressionfiltermodel.cppnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
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
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 General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "expressionfiltermodel.h"
18+
19+ExpressionFilterModel::ExpressionFilterModel(QObject *parent)
20+ : UnitySortFilterProxyModelQML(parent)
21+{
22+}
23+
24+QJSValue ExpressionFilterModel::matchExpression() const
25+{
26+ return m_matchExpression;
27+}
28+
29+void ExpressionFilterModel::setMatchExpression(const QJSValue &value)
30+{
31+ m_matchExpression = value;
32+ invalidateFilter();
33+}
34+
35+bool
36+ExpressionFilterModel::filterAcceptsRow(int sourceRow,
37+ const QModelIndex &sourceParent) const
38+{
39+ if (m_matchExpression.isCallable()) {
40+ QJSValueList args;
41+ args << sourceRow;
42+ QJSValue ret = m_matchExpression.call(args);
43+ if (ret.isBool()) {
44+ return ret.toBool();
45+ }
46+ }
47+
48+ return UnitySortFilterProxyModelQML::filterAcceptsRow(sourceRow, sourceParent);
49+}
plugins/Utils/expressionfiltermodel.hnew file+42
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
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
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 General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef EXPRESSIONFILTERMODEL_H
18+#define EXPRESSIONFILTERMODEL_H
19+
20+#include "unitysortfilterproxymodelqml.h"
21+#include <QJSValue>
22+
23+class ExpressionFilterModel : public UnitySortFilterProxyModelQML
24+{
25+ Q_OBJECT
26+ Q_PROPERTY(QJSValue matchExpression READ matchExpression WRITE setMatchExpression NOTIFY matchExpressionChanged)
27+public:
28+ explicit ExpressionFilterModel(QObject *parent = 0);
29+
30+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
31+
32+ QJSValue matchExpression() const;
33+ void setMatchExpression(const QJSValue& value);
34+
35+Q_SIGNALS:
36+ void matchExpressionChanged();
37+
38+private:
39+ mutable QJSValue m_matchExpression;
40+};
41+
42+#endif // EXPRESSIONFILTERMODEL_H
plugins/Utils/plugin.cpp+2
@@ -40,6 +40,7 @@
40#include "globalfunctions.h"
40#include "globalfunctions.h"
41#include "URLDispatcher.h"
41#include "URLDispatcher.h"
42#include "appdrawerproxymodel.h"
42#include "appdrawerproxymodel.h"
43+#include "expressionfiltermodel.h"
43
44
44static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
45static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
45{
46{
@@ -84,4 +85,5 @@ void UtilsPlugin::registerTypes(const char *uri)
84 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
85 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
85 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
86 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
86 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
87 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
88+ qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
87}
89}
qml/ApplicationMenus/MenuBar.qml+154−29
@@ -66,11 +66,6 @@ Item {
66 onPressed: d.dismissAll()
66 onPressed: d.dismissAll()
67 }
67 }
68
68
69− Rectangle {
70− anchors.fill: row
71− color: Qt.rgba(1,0,0,0.4)
72− }
73−
74 Row {
69 Row {
75 id: row
70 id: row
76 spacing: units.gu(2)
71 spacing: units.gu(2)
@@ -82,9 +77,17 @@ Item {
82 active: !d.currentItem && enableKeyFilter
77 active: !d.currentItem && enableKeyFilter
83 }
78 }
84
79
80+ Connections {
81+ target: root.unityMenuModel
82+ onModelReset: d.firstInvisibleIndex = undefined
83+ }
84+
85 Repeater {
85 Repeater {
86 id: rowRepeater
86 id: rowRepeater
87
87
88+ onItemAdded: d.recalcFirstInvisibleIndexAdded(index, item)
89+ onCountChanged: d.recalcFirstInvisibleIndex()
90+
88 Item {
91 Item {
89 id: visualItem
92 id: visualItem
90 objectName: root.objectName + "-item" + __ownIndex
93 objectName: root.objectName + "-item" + __ownIndex
@@ -92,8 +95,8 @@ Item {
92 readonly property int __ownIndex: index
95 readonly property int __ownIndex: index
93 property Item __popup: null;
96 property Item __popup: null;
94 property bool popupVisible: __popup && __popup.visible
97 property bool popupVisible: __popup && __popup.visible
95− property bool shouldDisplay: x + width + ((index < rowRepeater.count-1) ? units.gu(1) : 0) <
98+ property bool shouldDisplay: x + width + ((__ownIndex < rowRepeater.count-1) ? units.gu(2) : 0) <
96− (root.overflowWidth - (overflowButton.visible ? overflowButton.width : 0))
99+ root.overflowWidth - ((__ownIndex < rowRepeater.count-1) ? overflowButton.width : 0)
97
100
98 implicitWidth: column.implicitWidth
101 implicitWidth: column.implicitWidth
99 implicitHeight: row.height
102 implicitHeight: row.height
@@ -129,6 +132,18 @@ Item {
129 }
132 }
130 }
133 }
131
134
135+ onVisibleChanged: {
136+ if (!visible && __popup) dismiss();
137+ }
138+
139+ Component.onCompleted: {
140+ shouldDisplayChanged.connect(function() {
141+ if ((!shouldDisplay && d.firstInvisibleIndex == undefined) || __ownIndex <= d.firstInvisibleIndex) {
142+ d.recalcFirstInvisibleIndex();
143+ }
144+ });
145+ }
146+
132 Connections {
147 Connections {
133 target: d
148 target: d
134 onDismissAll: visualItem.dismiss()
149 onDismissAll: visualItem.dismiss()
@@ -167,6 +182,7 @@ Item {
167 height: _title.height
182 height: _title.height
168
183
169 action: Action {
184 action: Action {
185+ enabled: visualItem.enabled
170 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
186 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
171 text: model.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
187 text: model.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
172
188
@@ -187,23 +203,6 @@ Item {
187 } // Repeater
203 } // Repeater
188 } // Row
204 } // Row
189
205
190− MouseArea {
191− id: overflowButton
192− visible: root.implicitWidth > root.width
193− height: parent.height
194− width: units.gu(4)
195− anchors.right: parent.right
196−
197− Icon {
198− id: icon
199− width: units.gu(2)
200− height: units.gu(2)
201− anchors.centerIn: parent
202− color: theme.palette.normal.overlayText
203− name: "toolkit_chevron-down_2gu"
204− }
205− }
206−
207 MouseArea {
206 MouseArea {
208 anchors.fill: parent
207 anchors.fill: parent
209 hoverEnabled: d.currentItem
208 hoverEnabled: d.currentItem
@@ -226,12 +225,109 @@ Item {
226 if (!d.hoveredItem || !d.currentItem || !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
225 if (!d.hoveredItem || !d.currentItem || !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
227 d.hoveredItem = row.childAt(pos.x, pos.y);
226 d.hoveredItem = row.childAt(pos.x, pos.y);
228 if (!d.hoveredItem || !d.hoveredItem.enabled)
227 if (!d.hoveredItem || !d.hoveredItem.enabled)
229− return false;
228+ return;
230 if (d.currentItem != d.hoveredItem) {
229 if (d.currentItem != d.hoveredItem) {
231 d.currentItem = d.hoveredItem;
230 d.currentItem = d.hoveredItem;
232 }
231 }
233 }
232 }
234− return true;
233+ }
234+ }
235+
236+ MouseArea {
237+ id: overflowButton
238+ objectName: "overflow"
239+
240+ hoverEnabled: d.currentItem
241+ onEntered: d.currentItem = this
242+ onPositionChanged: d.currentItem = this
243+ onClicked: d.currentItem = this
244+
245+ property Item __popup: null;
246+ property bool popupVisible: __popup && __popup.visible
247+ property Item firstInvisibleItem: d.firstInvisibleIndex !== undefined ? rowRepeater.itemAt(d.firstInvisibleIndex) : null
248+
249+ visible: d.firstInvisibleIndex != undefined
250+ x: firstInvisibleItem ? firstInvisibleItem.x : 0
251+
252+ height: parent.height
253+ width: units.gu(4)
254+
255+ onVisibleChanged: {
256+ if (!visible && __popup) dismiss();
257+ }
258+
259+ Icon {
260+ id: icon
261+ width: units.gu(2)
262+ height: units.gu(2)
263+ anchors.centerIn: parent
264+ color: theme.palette.normal.overlayText
265+ name: "toolkit_chevron-down_2gu"
266+ }
267+
268+ function show() {
269+ if (!__popup) {
270+ __popup = overflowComponent.createObject(root, { objectName: overflowButton.objectName + "-menu" });
271+ // force the current item to be the newly popped up menu
272+ } else {
273+ __popup.show();
274+ }
275+ d.currentItem = overflowButton;
276+ }
277+ function hide() {
278+ if (__popup) {
279+ __popup.hide();
280+
281+ if (d.currentItem === overflowButton) {
282+ d.currentItem = null;
283+ }
284+ }
285+ }
286+ function dismiss() {
287+ if (__popup) {
288+ __popup.destroy();
289+ __popup = null;
290+
291+ if (d.currentItem === overflowButton) {
292+ d.currentItem = null;
293+ }
294+ }
295+ }
296+
297+ Connections {
298+ target: d
299+ onDismissAll: overflowButton.dismiss()
300+ }
301+
302+ Component {
303+ id: overflowComponent
304+ MenuPopup {
305+ id: overflowPopup
306+ x: overflowButton.x - units.gu(1)
307+ anchors.top: parent.bottom
308+ unityMenuModel: overflowModel
309+
310+ ExpressionFilterModel {
311+ id: overflowModel
312+ sourceModel: root.unityMenuModel
313+ matchExpression: function(index) {
314+ if (d.firstInvisibleIndex === undefined) return false;
315+ return index >= d.firstInvisibleIndex;
316+ }
317+
318+ function submenu(index) {
319+ return sourceModel.submenu(mapRowToSource(index));
320+ }
321+ function activate(index) {
322+ return sourceModel.activate(mapRowToSource(index));
323+ }
324+ }
325+
326+ Connections {
327+ target: d
328+ onFirstInvisibleIndexChanged: overflowModel.invalidate()
329+ }
330+ }
235 }
331 }
236 }
332 }
237
333
@@ -251,18 +347,43 @@ Item {
251 id: d
347 id: d
252 objectName: "d"
348 objectName: "d"
253 itemView: rowRepeater
349 itemView: rowRepeater
350+ hasOverflow: overflowButton.visible
254
351
255 property Item currentItem: null
352 property Item currentItem: null
256 property Item hoveredItem: null
353 property Item hoveredItem: null
257 property Item prevCurrentItem: null
354 property Item prevCurrentItem: null
258−
259− readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
260−
261 property bool altPressed: false
355 property bool altPressed: false
262 property bool longAltPressed: false
356 property bool longAltPressed: false
357+ property var firstInvisibleIndex: undefined
358+
359+ readonly property int currentIndex: currentItem && currentItem.hasOwnProperty("__ownIndex") ? currentItem.__ownIndex : -1
263
360
264 signal dismissAll()
361 signal dismissAll()
265
362
363+ function recalcFirstInvisibleIndexAdded(index, item) {
364+ if (firstInvisibleIndex === undefined) {
365+ if (!item.shouldDisplay) {
366+ firstInvisibleIndex = index;
367+ }
368+ } else if (index <= firstInvisibleIndex) {
369+ if (!item.shouldDisplay) {
370+ firstInvisibleIndex = index;
371+ } else {
372+ firstInvisibleIndex++;
373+ }
374+ }
375+ }
376+
377+ function recalcFirstInvisibleIndex() {
378+ for (var i = 0; i < rowRepeater.count; i++) {
379+ if (!rowRepeater.itemAt(i).shouldDisplay) {
380+ firstInvisibleIndex = i;
381+ return;
382+ }
383+ }
384+ firstInvisibleIndex = undefined;
385+ }
386+
266 onSelect: {
387 onSelect: {
267 var delegate = rowRepeater.itemAt(index);
388 var delegate = rowRepeater.itemAt(index);
268 if (delegate) {
389 if (delegate) {
@@ -270,6 +391,10 @@ Item {
270 }
391 }
271 }
392 }
272
393
394+ onOverflow: {
395+ d.currentItem = overflowButton;
396+ }
397+
273 onCurrentItemChanged: {
398 onCurrentItemChanged: {
274 if (prevCurrentItem && prevCurrentItem != currentItem) {
399 if (prevCurrentItem && prevCurrentItem != currentItem) {
275 if (currentItem) {
400 if (currentItem) {
qml/ApplicationMenus/MenuNavigator.qml+24−1
@@ -18,8 +18,10 @@ import QtQuick 2.4
18
18
19QtObject {
19QtObject {
20 property Item itemView: null
20 property Item itemView: null
21+ property bool hasOverflow: false
21
22
22 signal select(int index)
23 signal select(int index)
24+ signal overflow()
23
25
24 function selectNext(currentIndex) {
26 function selectNext(currentIndex) {
25 var menu;
27 var menu;
@@ -32,6 +34,11 @@ QtObject {
32 break;
34 break;
33 }
35 }
34 newIndex++;
36 newIndex++;
37+
38+ if (hasOverflow && newIndex === itemView.count) {
39+ overflow()
40+ break;
41+ }
35 }
42 }
36 } else if (currentIndex !== -1 && itemView.count > 1) {
43 } else if (currentIndex !== -1 && itemView.count > 1) {
37 var startIndex = (currentIndex + 1) % itemView.count;
44 var startIndex = (currentIndex + 1) % itemView.count;
@@ -42,6 +49,12 @@ QtObject {
42 select(newIndex);
49 select(newIndex);
43 break;
50 break;
44 }
51 }
52+
53+ if (hasOverflow && newIndex + 1 === itemView.count) {
54+ overflow()
55+ break;
56+ }
57+
45 newIndex = (newIndex + 1) % itemView.count;
58 newIndex = (newIndex + 1) % itemView.count;
46 } while (newIndex !== startIndex)
59 } while (newIndex !== startIndex)
47 }
60 }
@@ -58,12 +71,21 @@ QtObject {
58 break;
71 break;
59 }
72 }
60 newIndex--;
73 newIndex--;
74+
75+ if (hasOverflow && newIndex < 0 ) {
76+ overflow();
77+ break;
78+ }
61 }
79 }
62 } else if (currentIndex !== -1 && itemView.count > 1) {
80 } else if (currentIndex !== -1 && itemView.count > 1) {
63 var startIndex = currentIndex - 1;
81 var startIndex = currentIndex - 1;
64 newIndex = startIndex;
82 newIndex = startIndex;
65− do {
83+ do {
66 if (newIndex < 0) {
84 if (newIndex < 0) {
85+ if (hasOverflow) {
86+ overflow();
87+ break;
88+ }
67 newIndex = itemView.count - 1;
89 newIndex = itemView.count - 1;
68 }
90 }
69 menu = itemView.itemAt(newIndex);
91 menu = itemView.itemAt(newIndex);
@@ -72,6 +94,7 @@ QtObject {
72 break;
94 break;
73 }
95 }
74 newIndex--;
96 newIndex--;
97+
75 } while (newIndex !== startIndex)
98 } while (newIndex !== startIndex)
76 }
99 }
77 }
100 }
qml/ApplicationMenus/MenuPopup.qml+1−2
@@ -203,10 +203,9 @@ UbuntuShape {
203 !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
203 !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
204 d.hoveredItem = menuColumn.childAt(pos.x, pos.y)
204 d.hoveredItem = menuColumn.childAt(pos.x, pos.y)
205 if (!d.hoveredItem || !d.hoveredItem.enabled)
205 if (!d.hoveredItem || !d.hoveredItem.enabled)
206− return false;
206+ return;
207 d.currentItem = d.hoveredItem;
207 d.currentItem = d.hoveredItem;
208 }
208 }
209− return true;
210 }
209 }
211 }
210 }
212
211
tests/mocks/Utils/CMakeLists.txt+1
@@ -25,6 +25,7 @@ set(QMLPLUGIN_SRC
25 ${CMAKE_SOURCE_DIR}/plugins/Utils/deviceconfigparser.cpp
25 ${CMAKE_SOURCE_DIR}/plugins/Utils/deviceconfigparser.cpp
26 ${CMAKE_SOURCE_DIR}/plugins/Utils/globalfunctions.cpp
26 ${CMAKE_SOURCE_DIR}/plugins/Utils/globalfunctions.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp
28+ ${CMAKE_SOURCE_DIR}/plugins/Utils/expressionfiltermodel.cpp
28 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
29 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
29 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
tests/mocks/Utils/plugin.cpp+2
@@ -41,6 +41,7 @@
41#include <deviceconfigparser.h>
41#include <deviceconfigparser.h>
42#include <globalfunctions.h>
42#include <globalfunctions.h>
43#include <appdrawerproxymodel.h>
43#include <appdrawerproxymodel.h>
44+#include <expressionfiltermodel.h>
44
45
45static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
46static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
46{
47{
@@ -84,4 +85,5 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
84 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
85 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
85 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
86 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
86 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
87 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
88+ qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
87}
89}
tests/qmltests/ApplicationMenus/tst_MenuBar.qml+35−8
@@ -28,8 +28,8 @@ import ".."
28
28
29Item {
29Item {
30 id: root
30 id: root
31− width: units.gu(100)
31+ width: units.gu(120)
32− height: units.gu(50)
32+ height: units.gu(70)
33
33
34 Component.onCompleted: {
34 Component.onCompleted: {
35 QuickUtils.keyboardAttached = true;
35 QuickUtils.keyboardAttached = true;
@@ -51,11 +51,11 @@ Item {
51 Rectangle {
51 Rectangle {
52 anchors {
52 anchors {
53 left: parent.left
53 left: parent.left
54− right: parent.right
55 top: parent.top
54 top: parent.top
56 margins: units.gu(1)
55 margins: units.gu(1)
57 }
56 }
58 height: units.gu(3)
57 height: units.gu(3)
58+ width: parent.width * 2/3
59 color: "grey"
59 color: "grey"
60
60
61 MenuBar {
61 MenuBar {
@@ -65,7 +65,7 @@ Item {
65
65
66 unityMenuModel: UnityMenuModel {
66 unityMenuModel: UnityMenuModel {
67 id: menuBackend
67 id: menuBackend
68− modelData: appMenuData.generateTestData(17,5,2,3)
68+ modelData: appMenuData.generateTestData(10,5,2,3)
69 }
69 }
70 }
70 }
71 }
71 }
@@ -83,12 +83,12 @@ Item {
83
83
84 function init() {
84 function init() {
85 menuBar.dismiss();
85 menuBar.dismiss();
86− menuBackend.modelData = appMenuData.generateTestData(5,5,2,3)
86+ menuBackend.modelData = appMenuData.generateTestData(5,5,2,3, "menu")
87 activatedSpy.clear();
87 activatedSpy.clear();
88 }
88 }
89
89
90 function test_mouseNavigation() {
90 function test_mouseNavigation() {
91− menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
91+ menuBackend.modelData = appMenuData.generateTestData(3,3,0,0, "menu");
92 wait(50) // wait for row to build
92 wait(50) // wait for row to build
93 var priv = findInvisibleChild(menuBar, "d");
93 var priv = findInvisibleChild(menuBar, "d");
94
94
@@ -114,7 +114,7 @@ Item {
114 }
114 }
115
115
116 function test_keyboardNavigation_RightKeySelectsNextMenuItem(data) {
116 function test_keyboardNavigation_RightKeySelectsNextMenuItem(data) {
117− menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
117+ menuBackend.modelData = appMenuData.generateTestData(3,3,0,0, "menu");
118 var priv = findInvisibleChild(menuBar, "d");
118 var priv = findInvisibleChild(menuBar, "d");
119
119
120 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
120 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
@@ -139,7 +139,7 @@ Item {
139 }
139 }
140
140
141 function test_keyboardNavigation_LeftKeySelectsPreviousMenuItem(data) {
141 function test_keyboardNavigation_LeftKeySelectsPreviousMenuItem(data) {
142− menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
142+ menuBackend.modelData = appMenuData.generateTestData(3,3,0,0, "menu");
143 var priv = findInvisibleChild(menuBar, "d");
143 var priv = findInvisibleChild(menuBar, "d");
144
144
145 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
145 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
@@ -179,5 +179,32 @@ Item {
179 keyPress(data.tag, Qt.AltModifier, 100);
179 keyPress(data.tag, Qt.AltModifier, 100);
180 tryCompare(priv, "currentItem", menuItem);
180 tryCompare(priv, "currentItem", menuItem);
181 }
181 }
182+
183+
184+ function test_overfow() {
185+ menuBackend.modelData = appMenuData.generateTestData(5,2,0,0,"menu");
186+
187+ var overflow = findChild(menuBar, "overflow");
188+ compare(overflow.visible, false, "Overflow should not be visible");
189+
190+ var menu = { "rowData": { "label": "Short" } };
191+ tryCompareFunction(function() {
192+ menuBackend.insertRow(0, menu);
193+ wait(1);
194+ if (overflow.visible) {
195+ return true;
196+ }
197+ return false;
198+ }, true);
199+
200+ tryCompareFunction(function() {
201+ menuBackend.removeRow(0);
202+ wait(1);
203+ if (!overflow.visible) {
204+ return true;
205+ }
206+ return false;
207+ }, true);
208+ }
182 }
209 }
183}
210}