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
=== modified file 'plugins/Utils/CMakeLists.txt'
--- plugins/Utils/CMakeLists.txt 2016-12-21 10:20:36 +0000
+++ plugins/Utils/CMakeLists.txt 2017-01-30 14:46:20 +0000
@@ -35,6 +35,7 @@
35 globalfunctions.cpp35 globalfunctions.cpp
36 URLDispatcher.cpp36 URLDispatcher.cpp
37 tabfocusfence.cpp37 tabfocusfence.cpp
38 expressionfiltermodel.cpp
38 plugin.cpp39 plugin.cpp
39 )40 )
4041
4142
=== added file 'plugins/Utils/expressionfiltermodel.cpp'
--- plugins/Utils/expressionfiltermodel.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Utils/expressionfiltermodel.cpp 2017-01-30 14:46:20 +0000
@@ -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
19ExpressionFilterModel::ExpressionFilterModel(QObject *parent)
20 : UnitySortFilterProxyModelQML(parent)
21{
22}
23
24QJSValue ExpressionFilterModel::matchExpression() const
25{
26 return m_matchExpression;
27}
28
29void ExpressionFilterModel::setMatchExpression(const QJSValue &value)
30{
31 m_matchExpression = value;
32 invalidateFilter();
33}
34
35bool
36ExpressionFilterModel::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}
050
=== added file 'plugins/Utils/expressionfiltermodel.h'
--- plugins/Utils/expressionfiltermodel.h 1970-01-01 00:00:00 +0000
+++ plugins/Utils/expressionfiltermodel.h 2017-01-30 14:46:20 +0000
@@ -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
23class ExpressionFilterModel : public UnitySortFilterProxyModelQML
24{
25 Q_OBJECT
26 Q_PROPERTY(QJSValue matchExpression READ matchExpression WRITE setMatchExpression NOTIFY matchExpressionChanged)
27public:
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
35Q_SIGNALS:
36 void matchExpressionChanged();
37
38private:
39 mutable QJSValue m_matchExpression;
40};
41
42#endif // EXPRESSIONFILTERMODEL_H
043
=== modified file 'plugins/Utils/plugin.cpp'
--- plugins/Utils/plugin.cpp 2017-01-03 12:16:00 +0000
+++ plugins/Utils/plugin.cpp 2017-01-30 14:46:20 +0000
@@ -41,6 +41,7 @@
41#include "URLDispatcher.h"41#include "URLDispatcher.h"
42#include "appdrawerproxymodel.h"42#include "appdrawerproxymodel.h"
43#include "tabfocusfence.h"43#include "tabfocusfence.h"
44#include "expressionfiltermodel.h"
4445
45static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)46static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
46{47{
@@ -86,4 +87,5 @@
86 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");87 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
87 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");88 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
88 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");89 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
90 qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
89}91}
9092
=== modified file 'qml/ApplicationMenus/MenuBar.qml'
--- qml/ApplicationMenus/MenuBar.qml 2017-01-17 09:45:22 +0000
+++ qml/ApplicationMenus/MenuBar.qml 2017-01-30 14:46:20 +0000
@@ -24,12 +24,13 @@
24 id: root24 id: root
25 objectName: "menuBar"25 objectName: "menuBar"
2626
27 // set from outside
27 property alias unityMenuModel: rowRepeater.model28 property alias unityMenuModel: rowRepeater.model
29 property bool enableKeyFilter: false
30 property real overflowWidth: width
2831
32 // read from outside
29 readonly property bool valid: rowRepeater.count > 033 readonly property bool valid: rowRepeater.count > 0
30
31 property bool enableKeyFilter: false
32
33 readonly property bool showRequested: d.longAltPressed || d.currentItem != null34 readonly property bool showRequested: d.longAltPressed || d.currentItem != null
3435
35 implicitWidth: row.width36 implicitWidth: row.width
@@ -78,186 +79,325 @@
78 onPressed: d.dismissAll()79 onPressed: d.dismissAll()
79 }80 }
8081
81 Item {82 Row {
82 id: clippingItem83 id: row
8384 spacing: units.gu(2)
84 height: root.height85 height: parent.height
85 width: root.width86
86 clip: true87 ActionContext {
8788 id: menuBarContext
88 Row {89 objectName: "barContext"
89 id: row90 active: !d.currentItem && enableKeyFilter
90 spacing: units.gu(2)91 }
91 height: parent.height92
9293 Connections {
93 ActionContext {94 target: root.unityMenuModel
94 id: menuBarContext95 onModelReset: d.firstInvisibleIndex = undefined
95 objectName: "barContext"96 }
96 active: !d.currentItem && enableKeyFilter97
97 }98 Repeater {
9899 id: rowRepeater
99 Repeater {100
100 id: rowRepeater101 onItemAdded: d.recalcFirstInvisibleIndexAdded(index, item)
101102 onCountChanged: d.recalcFirstInvisibleIndex()
102 Item {103
103 id: visualItem104 Item {
104 objectName: root.objectName + "-item" + __ownIndex105 id: visualItem
105106 objectName: root.objectName + "-item" + __ownIndex
106 readonly property int __ownIndex: index107
107 property Item __popup: null;108 readonly property int __ownIndex: index
108 property bool popupVisible: __popup && __popup.visible109 property Item __popup: null;
109110 property bool popupVisible: __popup && __popup.visible
110 implicitWidth: column.implicitWidth111 property bool shouldDisplay: x + width + ((__ownIndex < rowRepeater.count-1) ? units.gu(2) : 0) <
111 implicitHeight: row.height112 root.overflowWidth - ((__ownIndex < rowRepeater.count-1) ? overflowButton.width : 0)
112 enabled: model.sensitive113
113114 implicitWidth: column.implicitWidth
114 function show() {115 implicitHeight: row.height
115 if (!__popup) {116 enabled: model.sensitive && shouldDisplay
116 __popup = menuComponent.createObject(root, { objectName: visualItem.objectName + "-menu" });117 opacity: shouldDisplay ? 1 : 0
117 // force the current item to be the newly popped up menu118
118 } else {119 function show() {
119 __popup.show();120 if (!__popup) {
120 }121 __popup = menuComponent.createObject(root, { objectName: visualItem.objectName + "-menu" });
121 d.currentItem = visualItem;122 __popup.childActivated.connect(dismiss);
122 }123 // force the current item to be the newly popped up menu
123 function hide() {124 } else {
124 if (__popup) {125 __popup.show();
125 __popup.hide();126 }
126127 d.currentItem = visualItem;
127 if (d.currentItem === visualItem) {128 }
128 d.currentItem = null;129 function hide() {
129 }130 if (__popup) {
130 }131 __popup.hide();
131 }132
132 function dismiss() {133 if (d.currentItem === visualItem) {
133 if (__popup) {134 d.currentItem = null;
134 __popup.destroy();135 }
135 __popup = null;136 }
136137 }
137 if (d.currentItem === visualItem) {138 function dismiss() {
138 d.currentItem = null;139 if (__popup) {
139 }140 __popup.destroy();
140 }141 __popup = null;
141 }142
142143 if (d.currentItem === visualItem) {
143 Connections {144 d.currentItem = null;
144 target: d145 }
145 onDismissAll: visualItem.dismiss()146 }
146 }147 }
147148
148 Component {149 onVisibleChanged: {
149 id: menuComponent150 if (!visible && __popup) dismiss();
150 MenuPopup {151 }
151 x: visualItem.x - units.gu(1)152
152 anchors.top: parent.bottom153 Component.onCompleted: {
153 unityMenuModel: root.unityMenuModel.submenu(visualItem.__ownIndex)154 shouldDisplayChanged.connect(function() {
154155 if ((!shouldDisplay && d.firstInvisibleIndex == undefined) || __ownIndex <= d.firstInvisibleIndex) {
155 Component.onCompleted: reset();156 d.recalcFirstInvisibleIndex();
156 }157 }
157 }158 });
158159 }
159 RowLayout {160
160 id: column161 Connections {
161 spacing: units.gu(1)162 target: d
162 anchors {163 onDismissAll: visualItem.dismiss()
163 centerIn: parent164 }
164 }165
165166 Component {
166 Icon {167 id: menuComponent
167 Layout.preferredWidth: units.gu(2)168 MenuPopup {
168 Layout.preferredHeight: units.gu(2)169 x: visualItem.x - units.gu(1)
169 Layout.alignment: Qt.AlignVCenter170 anchors.top: parent.bottom
170171 unityMenuModel: root.unityMenuModel.submenu(visualItem.__ownIndex)
171 visible: model.icon || false172
172 source: model.icon || ""173 Component.onCompleted: reset();
173 }174 }
174175 }
175 ActionItem {176
176 id: actionItem177 RowLayout {
177 width: _title.width178 id: column
178 height: _title.height179 spacing: units.gu(1)
179180 anchors {
180 action: Action {181 centerIn: parent
181 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic182 }
182 text: model.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")183
183184 Icon {
184 onTriggered: {185 Layout.preferredWidth: units.gu(2)
185 visualItem.show();186 Layout.preferredHeight: units.gu(2)
186 }187 Layout.alignment: Qt.AlignVCenter
187 }188
188189 visible: model.icon || false
189 Label {190 source: model.icon || ""
190 id: _title191 }
191 text: actionItem.text192
192 horizontalAlignment: Text.AlignLeft193 ActionItem {
193 color: enabled ? "white" : "#5d5d5d"194 id: actionItem
194 }195 width: _title.width
195 }196 height: _title.height
196 }197
197 } // Item ( delegate )198 action: Action {
198 } // Repeater199 enabled: visualItem.enabled
199 } // Row200 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
200201 text: model.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
201 MouseArea {202
202 anchors.fill: parent203 onTriggered: {
203 hoverEnabled: d.currentItem204 visualItem.show();
204205 }
205 onEntered: {206 }
206 if (d.currentItem) {207
207 updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))208 Label {
208 }209 id: _title
209 }210 text: actionItem.text
210 onPositionChanged: {211 horizontalAlignment: Text.AlignLeft
211 if (d.currentItem) {212 color: enabled ? "white" : "#5d5d5d"
212 updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))213 }
213 }214 }
214 }215 }
215 onClicked: updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))216 } // Item ( delegate )
216217 } // Repeater
217 function updateCurrentItemFromPosition(point) {218 } // Row
218 var pos = mapToItem(row, point.x, point.y);219
219220 MouseArea {
220 if (!d.hoveredItem || !d.currentItem || !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {221 anchors.fill: parent
221 d.hoveredItem = row.childAt(pos.x, pos.y);222 hoverEnabled: d.currentItem
222 if (!d.hoveredItem || !d.hoveredItem.enabled)223
223 return false;224 onEntered: {
224 if (d.currentItem != d.hoveredItem) {225 if (d.currentItem) {
225 d.currentItem = d.hoveredItem;226 updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))
226 }227 }
227 }228 }
228 return true;229 onPositionChanged: {
229 }230 if (d.currentItem) {
230 }231 updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
231232 }
232 Rectangle {233 }
233 id: underline234 onClicked: updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
234 anchors {235
235 bottom: row.bottom236 function updateCurrentItemFromPosition(point) {
236 }237 var pos = mapToItem(row, point.x, point.y);
237 x: d.currentItem ? row.x + d.currentItem.x - units.gu(1) : 0238
238 width: d.currentItem ? d.currentItem.width + units.gu(2) : 0239 if (!d.hoveredItem || !d.currentItem || !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
239 height: units.dp(4)240 d.hoveredItem = row.childAt(pos.x, pos.y);
240 color: UbuntuColors.orange241 if (!d.hoveredItem || !d.hoveredItem.enabled)
241 visible: d.currentItem242 return;
242 }243 if (d.currentItem != d.hoveredItem) {
244 d.currentItem = d.hoveredItem;
245 }
246 }
247 }
248 }
249
250 MouseArea {
251 id: overflowButton
252 objectName: "overflow"
253
254 hoverEnabled: d.currentItem
255 onEntered: d.currentItem = this
256 onPositionChanged: d.currentItem = this
257 onClicked: d.currentItem = this
258
259 property Item __popup: null;
260 property bool popupVisible: __popup && __popup.visible
261 property Item firstInvisibleItem: d.firstInvisibleIndex !== undefined ? rowRepeater.itemAt(d.firstInvisibleIndex) : null
262
263 visible: d.firstInvisibleIndex != undefined
264 x: firstInvisibleItem ? firstInvisibleItem.x : 0
265
266 height: parent.height
267 width: units.gu(4)
268
269 onVisibleChanged: {
270 if (!visible && __popup) dismiss();
271 }
272
273 Icon {
274 id: icon
275 width: units.gu(2)
276 height: units.gu(2)
277 anchors.centerIn: parent
278 color: theme.palette.normal.overlayText
279 name: "toolkit_chevron-down_2gu"
280 }
281
282 function show() {
283 if (!__popup) {
284 __popup = overflowComponent.createObject(root, { objectName: overflowButton.objectName + "-menu" });
285 // force the current item to be the newly popped up menu
286 } else {
287 __popup.show();
288 }
289 d.currentItem = overflowButton;
290 }
291 function hide() {
292 if (__popup) {
293 __popup.hide();
294
295 if (d.currentItem === overflowButton) {
296 d.currentItem = null;
297 }
298 }
299 }
300 function dismiss() {
301 if (__popup) {
302 __popup.destroy();
303 __popup = null;
304
305 if (d.currentItem === overflowButton) {
306 d.currentItem = null;
307 }
308 }
309 }
310
311 Connections {
312 target: d
313 onDismissAll: overflowButton.dismiss()
314 }
315
316 Component {
317 id: overflowComponent
318 MenuPopup {
319 id: overflowPopup
320 x: overflowButton.x - units.gu(1)
321 anchors.top: parent.bottom
322 unityMenuModel: overflowModel
323
324 ExpressionFilterModel {
325 id: overflowModel
326 sourceModel: root.unityMenuModel
327 matchExpression: function(index) {
328 if (d.firstInvisibleIndex === undefined) return false;
329 return index >= d.firstInvisibleIndex;
330 }
331
332 function submenu(index) {
333 return sourceModel.submenu(mapRowToSource(index));
334 }
335 function activate(index) {
336 return sourceModel.activate(mapRowToSource(index));
337 }
338 }
339
340 Connections {
341 target: d
342 onFirstInvisibleIndexChanged: overflowModel.invalidate()
343 }
344 }
345 }
346 }
347
348 Rectangle {
349 id: underline
350 anchors {
351 bottom: row.bottom
352 }
353 x: d.currentItem ? row.x + d.currentItem.x - units.gu(1) : 0
354 width: d.currentItem ? d.currentItem.width + units.gu(2) : 0
355 height: units.dp(4)
356 color: UbuntuColors.orange
357 visible: d.currentItem
243 }358 }
244359
245 MenuNavigator {360 MenuNavigator {
246 id: d361 id: d
247 objectName: "d"362 objectName: "d"
248 itemView: rowRepeater363 itemView: rowRepeater
364 hasOverflow: overflowButton.visible
249365
250 property Item currentItem: null366 property Item currentItem: null
251 property Item hoveredItem: null367 property Item hoveredItem: null
252 property Item prevCurrentItem: null368 property Item prevCurrentItem: null
253
254 readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
255
256 property bool altPressed: false369 property bool altPressed: false
257 property bool longAltPressed: false370 property bool longAltPressed: false
371 property var firstInvisibleIndex: undefined
372
373 readonly property int currentIndex: currentItem && currentItem.hasOwnProperty("__ownIndex") ? currentItem.__ownIndex : -1
258374
259 signal dismissAll()375 signal dismissAll()
260376
377 function recalcFirstInvisibleIndexAdded(index, item) {
378 if (firstInvisibleIndex === undefined) {
379 if (!item.shouldDisplay) {
380 firstInvisibleIndex = index;
381 }
382 } else if (index <= firstInvisibleIndex) {
383 if (!item.shouldDisplay) {
384 firstInvisibleIndex = index;
385 } else {
386 firstInvisibleIndex++;
387 }
388 }
389 }
390
391 function recalcFirstInvisibleIndex() {
392 for (var i = 0; i < rowRepeater.count; i++) {
393 if (!rowRepeater.itemAt(i).shouldDisplay) {
394 firstInvisibleIndex = i;
395 return;
396 }
397 }
398 firstInvisibleIndex = undefined;
399 }
400
261 onSelect: {401 onSelect: {
262 var delegate = rowRepeater.itemAt(index);402 var delegate = rowRepeater.itemAt(index);
263 if (delegate) {403 if (delegate) {
@@ -265,6 +405,10 @@
265 }405 }
266 }406 }
267407
408 onOverflow: {
409 d.currentItem = overflowButton;
410 }
411
268 onCurrentItemChanged: {412 onCurrentItemChanged: {
269 if (prevCurrentItem && prevCurrentItem != currentItem) {413 if (prevCurrentItem && prevCurrentItem != currentItem) {
270 if (currentItem) {414 if (currentItem) {
271415
=== modified file 'qml/ApplicationMenus/MenuItem.qml'
--- qml/ApplicationMenus/MenuItem.qml 2016-12-13 09:56:20 +0000
+++ qml/ApplicationMenus/MenuItem.qml 2017-01-30 14:46:20 +0000
@@ -46,6 +46,8 @@
46 enabled: menuData ? menuData.sensitive : false46 enabled: menuData ? menuData.sensitive : false
4747
48 action: Action {48 action: Action {
49 enabled: root.enabled
50
49 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic51 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
50 text: menuData.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")52 text: menuData.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
51 checkable: menuData.isCheck || menuData.isRadio53 checkable: menuData.isCheck || menuData.isRadio
@@ -137,7 +139,7 @@
137 theme.palette.disabled.backgroundSecondaryText139 theme.palette.disabled.backgroundSecondaryText
138140
139 visible: root.hasSubmenu141 visible: root.hasSubmenu
140 name: "chevron"142 name: "toolkit_chevron-ltr_2gu"
141 }143 }
142 }144 }
143145
144146
=== modified file 'qml/ApplicationMenus/MenuNavigator.qml'
--- qml/ApplicationMenus/MenuNavigator.qml 2016-11-28 13:44:30 +0000
+++ qml/ApplicationMenus/MenuNavigator.qml 2017-01-30 14:46:20 +0000
@@ -18,8 +18,10 @@
1818
19QtObject {19QtObject {
20 property Item itemView: null20 property Item itemView: null
21 property bool hasOverflow: false
2122
22 signal select(int index)23 signal select(int index)
24 signal overflow()
2325
24 function selectNext(currentIndex) {26 function selectNext(currentIndex) {
25 var menu;27 var menu;
@@ -32,6 +34,11 @@
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 @@
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 @@
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 @@
72 break;94 break;
73 }95 }
74 newIndex--;96 newIndex--;
97
75 } while (newIndex !== startIndex)98 } while (newIndex !== startIndex)
76 }99 }
77 }100 }
78101
=== modified file 'qml/ApplicationMenus/MenuPopup.qml'
--- qml/ApplicationMenus/MenuPopup.qml 2017-01-18 12:08:05 +0000
+++ qml/ApplicationMenus/MenuPopup.qml 2017-01-30 14:46:20 +0000
@@ -26,6 +26,8 @@
26 objectName: "menu"26 objectName: "menu"
27 backgroundColor: theme.palette.normal.overlay27 backgroundColor: theme.palette.normal.overlay
2828
29 signal childActivated()
30
29 property alias unityMenuModel: repeater.model31 property alias unityMenuModel: repeater.model
3032
31 function show() {33 function show() {
@@ -66,7 +68,7 @@
66 property real __minimumWidth: units.gu(20)68 property real __minimumWidth: units.gu(20)
67 property real __maximumWidth: Screen.width * 0.769 property real __maximumWidth: Screen.width * 0.7
68 property real __minimumHeight: units.gu(2)70 property real __minimumHeight: units.gu(2)
69 property real __maximumHeight: Screen.height * 0.771 property real __maximumHeight: Screen.height - mapToItem(null, 0, y).y
7072
71 signal dismissAll()73 signal dismissAll()
7274
@@ -147,8 +149,20 @@
147 }149 }
148150
149 MouseArea {151 MouseArea {
152 id: previousMA
150 anchors.fill: parent153 anchors.fill: parent
151 onPressed: {154 hoverEnabled: enabled
155 onPressed: progress()
156
157 Timer {
158 running: previousMA.containsMouse && !listView.atYBeginning
159 interval: 1000
160 repeat: true
161 onTriggered: previousMA.progress()
162 }
163
164 function progress() {
165 console.log("progress!")
152 var item = menuColumn.childAt(0, listView.contentY);166 var item = menuColumn.childAt(0, listView.contentY);
153 if (item) {167 if (item) {
154 var previousItem = item;168 var previousItem = item;
@@ -191,10 +205,9 @@
191 !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {205 !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
192 d.hoveredItem = menuColumn.childAt(pos.x, pos.y)206 d.hoveredItem = menuColumn.childAt(pos.x, pos.y)
193 if (!d.hoveredItem || !d.hoveredItem.enabled)207 if (!d.hoveredItem || !d.hoveredItem.enabled)
194 return false;208 return;
195 d.currentItem = d.hoveredItem;209 d.currentItem = d.hoveredItem;
196 }210 }
197 return true;
198 }211 }
199 }212 }
200213
@@ -263,16 +276,22 @@
263 return mapToItem(container, 0, y).y;276 return mapToItem(container, 0, y).y;
264 })277 })
265 });278 });
279 popup.retreat.connect(function() {
280 popup.destroy();
281 popup = null;
282 menuItem.forceActiveFocus();
283 });
284 popup.childActivated.connect(function() {
285 popup.destroy();
286 popup = null;
287 root.childActivated();
288 });
266 } else if (popup) {289 } else if (popup) {
267 popup.visible = true;290 popup.visible = true;
268 }291 }
269 popup.retreat.connect(function() {
270 popup.destroy();
271 popup = null;
272 menuItem.forceActiveFocus();
273 })
274 } else {292 } else {
275 root.unityMenuModel.activate(__ownIndex);293 root.unityMenuModel.activate(__ownIndex);
294 root.childActivated();
276 }295 }
277 }296 }
278297
@@ -349,8 +368,19 @@
349 }368 }
350369
351 MouseArea {370 MouseArea {
371 id: nextMA
352 anchors.fill: parent372 anchors.fill: parent
353 onPressed: {373 hoverEnabled: enabled
374 onPressed: progress()
375
376 Timer {
377 running: nextMA.containsMouse && !listView.atYEnd
378 interval: 1000
379 repeat: true
380 onTriggered: nextMA.progress()
381 }
382
383 function progress() {
354 var item = menuColumn.childAt(0, listView.contentY + listView.height);384 var item = menuColumn.childAt(0, listView.contentY + listView.height);
355 if (item) {385 if (item) {
356 var nextItem = item;386 var nextItem = item;
@@ -377,6 +407,7 @@
377407
378 property var unityMenuModel: null408 property var unityMenuModel: null
379 signal retreat()409 signal retreat()
410 signal childActivated()
380411
381 Binding {412 Binding {
382 target: item413 target: item
@@ -392,6 +423,11 @@
392423
393 Keys.onLeftPressed: retreat()424 Keys.onLeftPressed: retreat()
394425
426 Connections {
427 target: item
428 onChildActivated: childActivated();
429 }
430
395 Component.onCompleted: item.select(0);431 Component.onCompleted: item.select(0);
396 onVisibleChanged: if (visible) { item.select(0); }432 onVisibleChanged: if (visible) { item.select(0); }
397 }433 }
398434
=== modified file 'qml/Panel/Panel.qml'
--- qml/Panel/Panel.qml 2017-01-09 14:10:17 +0000
+++ qml/Panel/Panel.qml 2017-01-30 14:46:20 +0000
@@ -209,6 +209,8 @@
209 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }209 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
210 active: __applicationMenus.model210 active: __applicationMenus.model
211211
212 width: parent.width - windowControlButtons.width - units.gu(2) - __indicators.barWidth
213
212 property bool menusRequested: menuBarLoader.item ? menuBarLoader.item.showRequested : false214 property bool menusRequested: menuBarLoader.item ? menuBarLoader.item.showRequested : false
213215
214 sourceComponent: MenuBar {216 sourceComponent: MenuBar {
@@ -385,7 +387,7 @@
385 }387 }
386388
387 enabled: !applicationMenus.expanded389 enabled: !applicationMenus.expanded
388 opacity: !applicationMenus.expanded ? 1 : 0390 opacity: !callHint.visible && !applicationMenus.expanded ? 1 : 0
389 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }391 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
390392
391 onEnabledChanged: {393 onEnabledChanged: {
392394
=== modified file 'tests/mocks/Utils/CMakeLists.txt'
--- tests/mocks/Utils/CMakeLists.txt 2016-12-21 10:20:36 +0000
+++ tests/mocks/Utils/CMakeLists.txt 2017-01-30 14:46:20 +0000
@@ -26,6 +26,7 @@
26 ${CMAKE_SOURCE_DIR}/plugins/Utils/globalfunctions.cpp26 ${CMAKE_SOURCE_DIR}/plugins/Utils/globalfunctions.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp27 ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp
28 ${CMAKE_SOURCE_DIR}/plugins/Utils/tabfocusfence.cpp28 ${CMAKE_SOURCE_DIR}/plugins/Utils/tabfocusfence.cpp
29 ${CMAKE_SOURCE_DIR}/plugins/Utils/expressionfiltermodel.cpp
29 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
3233
=== modified file 'tests/mocks/Utils/plugin.cpp'
--- tests/mocks/Utils/plugin.cpp 2017-01-03 12:16:00 +0000
+++ tests/mocks/Utils/plugin.cpp 2017-01-30 14:46:20 +0000
@@ -42,6 +42,7 @@
42#include <globalfunctions.h>42#include <globalfunctions.h>
43#include <appdrawerproxymodel.h>43#include <appdrawerproxymodel.h>
44#include <tabfocusfence.h>44#include <tabfocusfence.h>
45#include <expressionfiltermodel.h>
4546
46static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)47static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
47{48{
@@ -86,4 +87,5 @@
86 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");87 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
87 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");88 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
88 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");89 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
90 qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
89}91}
9092
=== modified file 'tests/qmltests/ApplicationMenus/tst_MenuBar.qml'
--- tests/qmltests/ApplicationMenus/tst_MenuBar.qml 2017-01-24 07:41:35 +0000
+++ tests/qmltests/ApplicationMenus/tst_MenuBar.qml 2017-01-30 14:46:20 +0000
@@ -28,8 +28,8 @@
2828
29Item {29Item {
30 id: root30 id: root
31 width: units.gu(100)31 width: units.gu(120)
32 height: units.gu(50)32 height: units.gu(70)
3333
34 Component.onCompleted: {34 Component.onCompleted: {
35 QuickUtils.keyboardAttached = true;35 QuickUtils.keyboardAttached = true;
@@ -51,11 +51,11 @@
51 Rectangle {51 Rectangle {
52 anchors {52 anchors {
53 left: parent.left53 left: parent.left
54 right: parent.right
55 top: parent.top54 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"
6060
61 MenuBar {61 MenuBar {
@@ -65,7 +65,7 @@
6565
66 unityMenuModel: UnityMenuModel {66 unityMenuModel: UnityMenuModel {
67 id: menuBackend67 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 @@
8383
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 }
8989
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 build92 wait(50) // wait for row to build
93 var priv = findInvisibleChild(menuBar, "d");93 var priv = findInvisibleChild(menuBar, "d");
9494
@@ -114,7 +114,7 @@
114 }114 }
115115
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");
119119
120 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);120 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
@@ -139,7 +139,7 @@
139 }139 }
140140
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");
144144
145 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);145 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
@@ -180,6 +180,41 @@
180 tryCompare(priv, "currentItem", menuItem);180 tryCompare(priv, "currentItem", menuItem);
181 }181 }
182182
183 function test_menuActivateClosesMenu() {
184 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0,"menu");
185 var priv = findInvisibleChild(menuBar, "d");
186
187 var menuItem = findChild(menuBar, "menuBar-item0");
188 menuItem.show();
189 compare(priv.currentItem, menuItem, "CurrentItem should be set to item 0");
190 compare(priv.currentItem.popupVisible, true, "Popup should be visible");
191
192 var actionItem = findChild(menuBar, "menuBar-item0-menu-item0-actionItem");
193 mouseClick(actionItem);
194 compare(priv.currentItem, null, "CurrentItem should be null");
195 }
196
197 function test_subMenuActivateClosesMenu() {
198 menuBackend.modelData = appMenuData.generateTestData(3,4,1,0,"menu");
199 var priv = findInvisibleChild(menuBar, "d");
200
201 var menuItem = findChild(menuBar, "menuBar-item0");
202 menuItem.show();
203 compare(priv.currentItem, menuItem, "CurrentItem should be set to item 0");
204 compare(priv.currentItem.popupVisible, true, "Popup should be visible");
205
206 var actionItem = findChild(menuBar, "menuBar-item0-menu-item0-actionItem");
207 mouseClick(actionItem);
208
209 actionItem = findChild(menuBar, "menuBar-item0-menu-item0-menu-item0-actionItem");
210 mouseClick(actionItem);
211
212 actionItem = findChild(menuBar, "menuBar-item0-menu-item0-menu-item0-menu-item0-actionItem");
213 mouseClick(actionItem);
214
215 compare(priv.currentItem, null, "CurrentItem should be null");
216 }
217
183 function test_openAppMenuShortcut() {218 function test_openAppMenuShortcut() {
184 var priv = findInvisibleChild(menuBar, "d");219 var priv = findInvisibleChild(menuBar, "d");
185220
@@ -192,5 +227,31 @@
192 keyClick(Qt.Key_F10, Qt.AltModifier);227 keyClick(Qt.Key_F10, Qt.AltModifier);
193 compare(priv.currentItem, menuItem1, "First enabled item should be opened");228 compare(priv.currentItem, menuItem1, "First enabled item should be opened");
194 }229 }
230
231 function test_overfow() {
232 menuBackend.modelData = appMenuData.generateTestData(5,2,0,0,"menu");
233
234 var overflow = findChild(menuBar, "overflow");
235 compare(overflow.visible, false, "Overflow should not be visible");
236
237 var menu = { "rowData": { "label": "Short" } };
238 tryCompareFunction(function() {
239 menuBackend.insertRow(0, menu);
240 wait(1);
241 if (overflow.visible) {
242 return true;
243 }
244 return false;
245 }, true);
246
247 tryCompareFunction(function() {
248 menuBackend.removeRow(0);
249 wait(1);
250 if (!overflow.visible) {
251 return true;
252 }
253 return false;
254 }, true);
255 }
195 }256 }
196}257}

Subscribers

People subscribed via source and target branches