Merge lp:~nick-dedekind/unity8/menu.overflow into lp:unity8
- menu.overflow
- Merge into trunk
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 |
Related bugs: |
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
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
Lukáš Tinkl (lukas-kde) wrote : | # |
/<<BUILDDIR>
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2778
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2779
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2780
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2781
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Michał Sawicz (saviq) wrote : | # |
MenuNavigator.qml: bad whitespace in line 83
Albert Astals Cid (aacid) wrote : | # |
Text conflict in plugins/
Text conflict in plugins/
Text conflict in tests/mocks/
Text conflict in tests/mocks/
Text conflict in tests/qmltests/
5 conflicts encountered.
Nick Dedekind (nick-dedekind) wrote : | # |
> Text conflict in plugins/
> Text conflict in plugins/
> Text conflict in tests/mocks/
> Text conflict in tests/mocks/
> Text conflict in tests/qmltests/
> 5 conflicts encountered.
merged
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2782
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2782
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2785
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 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
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 | } |
FAILED: Continuous integration, rev:2777 /unity8- jenkins. ubuntu. com/job/ lp-unity8- ci/3007/ /unity8- jenkins. ubuntu. com/job/ build/3912/ console /unity8- jenkins. ubuntu. com/job/ build-0- fetch/3940 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 3785/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= zesty/3785/ console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 3785/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= zesty/3785/ console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 3785/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= zesty/3785/ console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /unity8- jenkins. ubuntu. com/job/ lp-unity8- ci/3007/ rebuild
https:/