Merge lp:~aacid/unity8/select_first_submenu_when_it_appears into lp:unity8

Proposed by Albert Astals Cid
Status: Superseded
Proposed branch: lp:~aacid/unity8/select_first_submenu_when_it_appears
Merge into: lp:unity8
Diff against target: 463 lines (+251/-38)
11 files modified
qml/ApplicationMenus/MenuBar.qml (+0/-4)
qml/ApplicationMenus/MenuPopup.qml (+9/-4)
tests/mocks/QMenuModel/unitymenumodel.cpp (+23/-4)
tests/mocks/QMenuModel/unitymenumodel.h (+7/-0)
tests/qmltests/ApplicationMenus/tst_MenuPopup.qml (+17/-14)
tools/CMakeLists.txt (+2/-12)
tools/menutool/CMakeLists.txt (+5/-0)
tools/menutool/README (+11/-0)
tools/menutool/menutool.cpp (+62/-0)
tools/menutool/menutool.qml (+103/-0)
tools/scopetool/CMakeLists.txt (+12/-0)
To merge this branch: bzr merge lp:~aacid/unity8/select_first_submenu_when_it_appears
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Approve
Michael Zanetti (community) Needs Fixing
Review via email: mp+317974@code.launchpad.net

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

Commit message

Fix real world submenus (e.g. kate) not getting their first item selected on open

MenuBar.qml: remove unused function
MenuPopup.qml: Select first item when one arrives if there's no currentItem instead of on completion
unitymenumodel.cpp: trick rowCount() to simulate "real world late" menus
tst_MenuPopup.qml: adapt to unitymenumodel.cpp changes (and make the Up test actually press Up and not Down)

Description of the change

* Are there any related MPs required for this MP to build/function as expected?
https://code.launchpad.net/~aacid/qmenumodel/batch_insert_remove_from_menu

 * 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?
N/A

To post a comment you must log in.
Revision history for this message
Michael Zanetti (mzanetti) wrote :

It does improve the situation but there is something odd:

again, using kate as an example, opening the Tools menu, navigate down to a submenu, enter it, navigate down to the third entry, press left, go to another submenu, enter it. Now the highlight will be at the third entry instead of starting at the first again.

also I managed to get into the situation where I lost keyboard focus altogether in the menu by navigating through the main menu entries. While I'm not 100% sure that is introduced by this branch, I haven't seen it in trunk so far.

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

PASSED: Continuous integration, rev:2835
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/3177/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/4172
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2456
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2456
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4200
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4037
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4037/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4037
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4037/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4037
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4037/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4037
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4037/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4037
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4037/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4037
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4037/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
2836. By Albert Astals Cid

Merge menutool branch

2837. By Albert Astals Cid

We want to select the first enabled, not necessarily 0

2838. By Albert Astals Cid

this is a bit clearer

2839. By Albert Astals Cid

Test++

2840. By Albert Astals Cid

only submenus select first, not first level menus

2841. By Albert Astals Cid

Merge

Unmerged revisions

2834. By Launchpad Translations on behalf of unity-team

Launchpad automatic translations update.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qml/ApplicationMenus/MenuBar.qml'
2--- qml/ApplicationMenus/MenuBar.qml 2017-02-16 13:43:18 +0000
3+++ qml/ApplicationMenus/MenuBar.qml 2017-03-01 14:27:32 +0000
4@@ -36,10 +36,6 @@
5 implicitWidth: row.width
6 height: parent.height
7
8- function select(index) {
9- d.select(index);
10- }
11-
12 function dismiss() {
13 d.dismissAll();
14 }
15
16=== modified file 'qml/ApplicationMenus/MenuPopup.qml'
17--- qml/ApplicationMenus/MenuPopup.qml 2017-01-31 15:24:06 +0000
18+++ qml/ApplicationMenus/MenuPopup.qml 2017-03-01 14:27:32 +0000
19@@ -73,8 +73,8 @@
20 d.currentItem = null;
21 }
22
23- function select(index) {
24- d.select(index)
25+ function selectFirstIndex() {
26+ d.selectNext(-1);
27 }
28
29 function reset() {
30@@ -285,6 +285,12 @@
31 Repeater {
32 id: repeater
33
34+ onCountChanged: {
35+ if (!d.currentItem && count > 0) {
36+ root.selectFirstIndex();
37+ }
38+ }
39+
40 Loader {
41 id: loader
42 objectName: root.objectName + "-item" + __ownIndex
43@@ -483,8 +489,7 @@
44 onChildActivated: childActivated();
45 }
46
47- Component.onCompleted: item.select(0);
48- onVisibleChanged: if (visible) { item.select(0); }
49+ onVisibleChanged: if (visible) { item.selectFirstIndex(); }
50 }
51 }
52 }
53
54=== modified file 'tests/mocks/QMenuModel/unitymenumodel.cpp'
55--- tests/mocks/QMenuModel/unitymenumodel.cpp 2017-01-10 14:46:09 +0000
56+++ tests/mocks/QMenuModel/unitymenumodel.cpp 2017-03-01 14:27:32 +0000
57@@ -18,6 +18,8 @@
58
59 #include "unitymenumodel.h"
60
61+#include <QTimer>
62+
63 enum MenuRoles {
64 LabelRole = Qt::DisplayRole + 1,
65 SensitiveRole,
66@@ -35,7 +37,8 @@
67 };
68
69 UnityMenuModel::UnityMenuModel(QObject *parent)
70-: QAbstractListModel(parent)
71+ : QAbstractListModel(parent)
72+ , m_rowCountStatus(NoRequestMade)
73 {
74 }
75
76@@ -60,7 +63,7 @@
77
78 void UnityMenuModel::insertRow(int row, const QVariant& data)
79 {
80- row = qMin(row, rowCount());
81+ row = qMin(row, m_modelData.count());
82
83 beginInsertRows(QModelIndex(), row, row);
84
85@@ -71,12 +74,12 @@
86
87 void UnityMenuModel::appendRow(const QVariant& data)
88 {
89- insertRow(rowCount(), data);
90+ insertRow(m_modelData.count(), data);
91 }
92
93 void UnityMenuModel::removeRow(int row)
94 {
95- if (row < 0 || rowCount() <= row) {
96+ if (row < 0 || m_modelData.count() <= row) {
97 return;
98 }
99
100@@ -133,6 +136,22 @@
101
102 int UnityMenuModel::rowCount(const QModelIndex&) const
103 {
104+ // Fake the rowCount to be 0 for a while (100ms)
105+ // This emulates menus in real world that don't load immediately
106+ if (m_rowCountStatus == TimerRunning)
107+ return 0;
108+
109+ if (m_rowCountStatus == NoRequestMade) {
110+ UnityMenuModel *that = const_cast<UnityMenuModel*>(this);
111+ that->m_rowCountStatus = TimerRunning;
112+ QTimer::singleShot(100, that, [that] {
113+ that->beginInsertRows(QModelIndex(), 0, that->m_modelData.count() - 1);
114+ that->m_rowCountStatus = TimerFinished;
115+ that->endInsertRows();
116+ });
117+ return 0;
118+ }
119+
120 return m_modelData.count();
121 }
122
123
124=== modified file 'tests/mocks/QMenuModel/unitymenumodel.h'
125--- tests/mocks/QMenuModel/unitymenumodel.h 2016-09-29 09:15:04 +0000
126+++ tests/mocks/QMenuModel/unitymenumodel.h 2017-03-01 14:27:32 +0000
127@@ -101,6 +101,13 @@
128 QByteArray m_busName;
129 QVariantMap m_actions;
130 QByteArray m_menuObjectPath;
131+
132+ enum RowCountStatus {
133+ NoRequestMade,
134+ TimerRunning,
135+ TimerFinished
136+ };
137+ RowCountStatus m_rowCountStatus;
138 };
139
140 #endif // MOCK_UNITYMENUMODEL_H
141
142=== modified file 'tests/qmltests/ApplicationMenus/tst_MenuPopup.qml'
143--- tests/qmltests/ApplicationMenus/tst_MenuPopup.qml 2017-01-25 14:10:44 +0000
144+++ tests/qmltests/ApplicationMenus/tst_MenuPopup.qml 2017-03-01 14:27:32 +0000
145@@ -160,9 +160,6 @@
146 var priv = findInvisibleChild(menu, "d");
147
148 keyClick(Qt.Key_Down, Qt.NoModifier);
149- compare(priv.currentItem, item0, "CurrentItem should have moved to item 0");
150-
151- keyClick(Qt.Key_Down, Qt.NoModifier);
152 compare(priv.currentItem, item1, "CurrentItem should have moved to item 1");
153
154 keyClick(Qt.Key_Down, Qt.NoModifier);
155@@ -170,6 +167,9 @@
156
157 keyClick(Qt.Key_Down, Qt.NoModifier);
158 compare(priv.currentItem, item0, "CurrentItem should have moved to item 0");
159+
160+ keyClick(Qt.Key_Down, Qt.NoModifier);
161+ compare(priv.currentItem, item1, "CurrentItem should have moved to item 1");
162 }
163
164 function test_keyboardNavigation_UpKeySelectsAndOpensPreviousMenuItemAndRotates() {
165@@ -181,17 +181,17 @@
166
167 var priv = findInvisibleChild(menu, "d");
168
169- keyClick(Qt.Key_Down, Qt.NoModifier);
170- compare(priv.currentItem, item0, "CurrentItem should have moved to item 2");
171+ keyClick(Qt.Key_Up, Qt.NoModifier);
172+ compare(priv.currentItem, item2, "CurrentItem should have moved to item 2");
173
174- keyClick(Qt.Key_Down, Qt.NoModifier);
175+ keyClick(Qt.Key_Up, Qt.NoModifier);
176 compare(priv.currentItem, item1, "CurrentItem should have moved to item 1");
177
178- keyClick(Qt.Key_Down, Qt.NoModifier);
179- compare(priv.currentItem, item2, "CurrentItem should have moved to item 0");
180+ keyClick(Qt.Key_Up, Qt.NoModifier);
181+ compare(priv.currentItem, item0, "CurrentItem should have moved to item 0");
182
183- keyClick(Qt.Key_Down, Qt.NoModifier);
184- compare(priv.currentItem, item0, "CurrentItem should have moved to item 2");
185+ keyClick(Qt.Key_Up, Qt.NoModifier);
186+ compare(priv.currentItem, item2, "CurrentItem should have moved to item 2");
187 }
188
189 function test_keyboardNavigation_RightKeyEntersSubMenu() {
190@@ -217,7 +217,7 @@
191
192 var menuItem = findChild(menu, "menu-item0"); verify(menuItem);
193 mouseClick(menuItem, menuItem.width/2, menuItem.height/2);
194- tryCompareFunction(function() { return menuItem.popup !== null && menuItem.popup.visible }, true);
195+ tryCompareFunction(function() { return menuItem.popup !== null && findInvisibleChild(menuItem.popup, "d").currentItem !== null }, true);
196
197 keyClick(Qt.Key_Left, Qt.NoModifier);
198 tryCompareFunction(function() { return menuItem.popup !== null && menuItem.popup.visible }, false);
199@@ -245,13 +245,16 @@
200
201 menu.unityMenuModel.modelData = differentSizesMenu;
202
203- waitForRendering(menu);
204+ // Wait for the two items to be there
205+ tryCompareFunction(function() { return findChild(menu, "menu-item1") !== null; }, true);
206 var longWidth = menu.width;
207+
208+ // Now pop one item and make sure it's smaller
209 differentSizesMenu.pop();
210 menu.unityMenuModel.modelData = differentSizesMenu;
211
212- waitForRendering(menu);
213- verify(menu.width < longWidth);
214+ tryCompareFunction(function() { return findChild(menu, "menu-item0") !== null; }, true);
215+ tryCompareFunction(function() { return menu.width < longWidth; }, true);
216 }
217
218 function test_minimumWidth() {
219
220=== modified file 'tools/CMakeLists.txt'
221--- tools/CMakeLists.txt 2016-05-09 12:38:10 +0000
222+++ tools/CMakeLists.txt 2017-03-01 14:27:32 +0000
223@@ -1,14 +1,4 @@
224-add_executable(${SCOPE_TOOL}
225- scopetool.cpp
226- registry-tracker.cpp
227- ../src/UnixSignalHandler.cpp
228- )
229-
230-qt5_use_modules(${SCOPE_TOOL} Qml Quick)
231-
232-# install binaries
233-install(TARGETS ${SCOPE_TOOL}
234- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
235- )
236+add_subdirectory(menutool)
237+add_subdirectory(scopetool)
238
239 install(FILES unlock-device DESTINATION ${SHELL_APP_DIR})
240
241=== added directory 'tools/menutool'
242=== added file 'tools/menutool/CMakeLists.txt'
243--- tools/menutool/CMakeLists.txt 1970-01-01 00:00:00 +0000
244+++ tools/menutool/CMakeLists.txt 2017-03-01 14:27:32 +0000
245@@ -0,0 +1,5 @@
246+add_executable(menutool
247+ menutool.cpp
248+ )
249+
250+qt5_use_modules(menutool Qml Quick)
251
252=== added file 'tools/menutool/README'
253--- tools/menutool/README 1970-01-01 00:00:00 +0000
254+++ tools/menutool/README 2017-03-01 14:27:32 +0000
255@@ -0,0 +1,11 @@
256+This tool can be used to browse the menus of another application
257+
258+How to use:
259+ * Start application that exports menus
260+ e.g. QT_QPA_PLATFORMTHEME=ubuntuappmenu kate
261+ * Figure out which is the dbus address
262+ * This is a bit tricky, but using qdbusviewer to see the addresses
263+ that appear when starting the app and looking for one that
264+ contains com/Ubuntu/Menu/0 should be enough
265+ * Start tool passing the dbus address
266+ builddir/menutool/menutool :1.293
267
268=== added file 'tools/menutool/menutool.cpp'
269--- tools/menutool/menutool.cpp 1970-01-01 00:00:00 +0000
270+++ tools/menutool/menutool.cpp 2017-03-01 14:27:32 +0000
271@@ -0,0 +1,62 @@
272+/*
273+ * Copyright (C) 2017 Canonical, Ltd.
274+ *
275+ * This program is free software; you can redistribute it and/or modify
276+ * it under the terms of the GNU General Public License as published by
277+ * the Free Software Foundation; version 3.
278+ *
279+ * This program is distributed in the hope that it will be useful,
280+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
281+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
282+ * GNU General Public License for more details.
283+ *
284+ * You should have received a copy of the GNU General Public License
285+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
286+ */
287+
288+// Qt
289+#include <QDebug>
290+#include <QCommandLineParser>
291+#include <QGuiApplication>
292+#include <QQmlContext>
293+#include <QQmlEngine>
294+#include <QQuickView>
295+
296+// local
297+#include <paths.h>
298+
299+int main(int argc, char *argv[])
300+{
301+ QGuiApplication::setApplicationName("Menu Test Tool");
302+ QGuiApplication *application = new QGuiApplication(argc, argv);
303+
304+ QCommandLineParser parser;
305+ parser.parse(application->arguments());
306+ const QStringList args = parser.positionalArguments();
307+
308+ if (args.count() != 1) {
309+ qWarning() << "You need to pass the dbus address";
310+ return 1;
311+ }
312+
313+ QQuickView* view = new QQuickView();
314+ view->setResizeMode(QQuickView::SizeRootObjectToView);
315+ view->setTitle(QGuiApplication::applicationName());
316+ view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
317+ view->rootContext()->setContextProperty("contextBusName", args[0]);
318+
319+ QUrl source(::sourceDirectory() + "/tools/menutool/menutool.qml");
320+ prependImportPaths(view->engine(), ::overrideImportPaths());
321+ prependImportPaths(view->engine(), ::nonMirImportPaths());
322+
323+ view->setSource(source);
324+
325+ view->show();
326+
327+ int result = application->exec();
328+
329+ delete view;
330+ delete application;
331+
332+ return result;
333+}
334
335=== added file 'tools/menutool/menutool.qml'
336--- tools/menutool/menutool.qml 1970-01-01 00:00:00 +0000
337+++ tools/menutool/menutool.qml 2017-03-01 14:27:32 +0000
338@@ -0,0 +1,103 @@
339+/*
340+* Copyright (C) 2017 Canonical, Ltd.
341+*
342+* This program is free software; you can redistribute it and/or modify
343+* it under the terms of the GNU General Public License as published by
344+* the Free Software Foundation; version 3.
345+*
346+* This program is distributed in the hope that it will be useful,
347+* but WITHOUT ANY WARRANTY; without even the implied warranty of
348+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
349+* GNU General Public License for more details.
350+*
351+* You should have received a copy of the GNU General Public License
352+* along with this program. If not, see <http://www.gnu.org/licenses/>.
353+*/
354+
355+import QtQuick 2.4
356+import Ubuntu.Components 1.3
357+
358+import "../../qml/ApplicationMenus"
359+import "../../qml/Panel"
360+import "../../qml/Components/PanelState"
361+
362+import QMenuModel 0.1
363+import Unity.Indicators 0.1 as Indicators
364+
365+Item {
366+ width: units.gu(180)
367+ height: units.gu(120)
368+
369+ UnityMenuModel {
370+ id: menuModel
371+ busName: contextBusName
372+ menuObjectPath: "/com/ubuntu/Menu/0"
373+ actions: { "unity": "/com/ubuntu/Menu/0" }
374+ }
375+
376+ Panel {
377+ id: panel
378+
379+ height: parent.height
380+ width: parent.width / 2
381+ minimizedPanelHeight: units.gu(6)
382+
383+ mode: "windowed"
384+
385+ applicationMenus {
386+ model: menuModel
387+ }
388+
389+ Rectangle {
390+ width: 50
391+ height: 50
392+ anchors.centerIn: parent
393+ color: "gray"
394+ rotation: 45
395+ Timer {
396+ interval: 20
397+ running: true
398+ repeat: true
399+ onTriggered: parent.rotation = parent.rotation+1
400+ }
401+ }
402+
403+ Rectangle {
404+ color: "green"
405+ anchors.bottom: parent.bottom
406+ anchors.right: parent.right
407+ Label {
408+ id: label
409+ anchors.centerIn: parent
410+ text: "Click here to open touch menu manually"
411+ }
412+ width: label.width + units.gu(2)
413+ height: label.height + units.gu(2)
414+ MouseArea {
415+ anchors.fill: parent
416+ onClicked: panel.applicationMenus.show();
417+ }
418+ visible: !panel.applicationMenus.shown
419+ }
420+ }
421+
422+ Rectangle {
423+ color: "blue"
424+ height: parent.height
425+ width: parent.width / 2
426+ x: width
427+
428+ MenuBar {
429+ id: menuBar
430+ height: units.gu(3)
431+ width: parent.width
432+ enableKeyFilter: true
433+ unityMenuModel: menuModel
434+ }
435+ }
436+
437+ Component.onCompleted: {
438+ theme.name = "Ubuntu.Components.Themes.SuruDark";
439+ PanelState.title = "Drag here to open touch menu";
440+ }
441+}
442
443=== added directory 'tools/scopetool'
444=== added file 'tools/scopetool/CMakeLists.txt'
445--- tools/scopetool/CMakeLists.txt 1970-01-01 00:00:00 +0000
446+++ tools/scopetool/CMakeLists.txt 2017-03-01 14:27:32 +0000
447@@ -0,0 +1,12 @@
448+add_executable(${SCOPE_TOOL}
449+ scopetool.cpp
450+ registry-tracker.cpp
451+ ../../src/UnixSignalHandler.cpp
452+ )
453+
454+qt5_use_modules(${SCOPE_TOOL} Qml Quick)
455+
456+# install binaries
457+install(TARGETS ${SCOPE_TOOL}
458+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
459+ )
460
461=== renamed file 'tools/registry-tracker.cpp' => 'tools/scopetool/registry-tracker.cpp'
462=== renamed file 'tools/registry-tracker.h' => 'tools/scopetool/registry-tracker.h'
463=== renamed file 'tools/scopetool.cpp' => 'tools/scopetool/scopetool.cpp'

Subscribers

People subscribed via source and target branches