Merge lp:~nick-dedekind/ubuntu-ui-toolkit/menus into lp:ubuntu-ui-toolkit

Proposed by Nick Dedekind
Status: Superseded
Proposed branch: lp:~nick-dedekind/ubuntu-ui-toolkit/menus
Merge into: lp:ubuntu-ui-toolkit
Prerequisite: lp:~nick-dedekind/ubuntu-ui-toolkit/actionItem-mnemonics
Diff against target: 2175 lines (+1727/-152)
19 files modified
components.api (+27/-6)
src/Ubuntu/Components/1.2/ActionList.qml (+0/-47)
src/Ubuntu/Components/1.3/ActionList.qml (+0/-47)
src/Ubuntu/Components/ComponentModule.pro (+0/-2)
src/Ubuntu/Components/plugin/plugin.cpp (+10/-0)
src/Ubuntu/Components/plugin/plugin.pri (+13/-3)
src/Ubuntu/Components/plugin/ucaction.cpp (+103/-37)
src/Ubuntu/Components/plugin/ucaction.h (+27/-7)
src/Ubuntu/Components/plugin/ucactionlist.cpp (+104/-0)
src/Ubuntu/Components/plugin/ucactionlist.h (+53/-0)
src/Ubuntu/Components/plugin/ucexclusivegroup.cpp (+106/-0)
src/Ubuntu/Components/plugin/ucexclusivegroup.h (+53/-0)
src/Ubuntu/Components/plugin/ucmenu.cpp (+613/-0)
src/Ubuntu/Components/plugin/ucmenu.h (+108/-0)
src/Ubuntu/Components/plugin/ucmenu_p.h (+83/-0)
src/Ubuntu/Components/plugin/ucmenubar.cpp (+299/-0)
src/Ubuntu/Components/plugin/ucmenubar.h (+60/-0)
src/Ubuntu/Components/plugin/ucmenubar_p.h (+68/-0)
src/Ubuntu/Components/qmldir (+0/-3)
To merge this branch: bzr merge lp:~nick-dedekind/ubuntu-ui-toolkit/menus
Reviewer Review Type Date Requested Status
Ubuntu SDK team Pending
Review via email: mp+295432@code.launchpad.net

This proposal has been superseded by a proposal from 2016-06-07.

Commit message

API for MenuBar, Menus, MenuItem & MenuSeparator

To post a comment you must log in.
1323. By Timo Jyrinki

Rebuild for arm64 gles switch.

1324. By Timo Jyrinki

no "-gles" in changelog package name

1325. By Albert Astals Cid

OTA12-2016-05-20

1326. By CI Train Bot Account

Releasing 1.3.1984+16.10.20160527.2

1327. By Zoltan Balogh

OTA12-2016-06-01

1328. By CI Train Bot Account

Releasing 1.3.1988+16.10.20160601

1329. By CI Train Bot Account

Resync trunk.

1330. By Nick Dedekind

merged actionList

1331. By Nick Dedekind

members accessors to functions

1332. By Nick Dedekind

Menu API

1333. By Nick Dedekind

merged with actionList

1334. By Nick Dedekind

new components.api

1335. By Nick Dedekind

fix platform abstraction

1336. By Nick Dedekind

better dynamicness

1337. By Nick Dedekind

updated api

1338. By Nick Dedekind

removed debug

1339. By Nick Dedekind

removed attached properties

1340. By Nick Dedekind

better removal

1341. By Nick Dedekind

activate state

1342. By Nick Dedekind

enable fix

1343. By Nick Dedekind

added MenuGroup::at

1344. By Nick Dedekind

simplified insert

1345. By Nick Dedekind

Added menu unit tests

1346. By Nick Dedekind

updated menu tests

1347. By Nick Dedekind

updated menu tests

1348. By Nick Dedekind

updated menu tests

1349. By Nick Dedekind

removed distfile from pro

1350. By Nick Dedekind

merged exclusiveGroup

1351. By Nick Dedekind

merged with staging

1352. By Nick Dedekind

merged parent

1353. By Nick Dedekind

fixed namespace

1354. By Nick Dedekind

merged with trunk

1355. By Nick Dedekind

removed uc prefix

1356. By Nick Dedekind

moved menus to Labs

1357. By Nick Dedekind

merged parent

1358. By Nick Dedekind

merged staging

1359. By Nick Dedekind

fixed broken build

Unmerged revisions

1359. By Nick Dedekind

fixed broken build

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2016-05-20 17:33:56 +0000
3+++ components.api 2016-06-07 14:25:30 +0000
4@@ -12,6 +12,7 @@
5 Ubuntu.Components.Action 1.3 1.0 0.1 UCAction: QtObject
6 property string description
7 property bool enabled
8+ property ExclusiveGroup exclusiveGroup 1.3
9 property string iconName
10 property url iconSource
11 property Component itemHint
12@@ -19,9 +20,11 @@
13 signal triggered(var value)
14 function trigger(var value)
15 function trigger()
16+ function setState(var )
17 property string name
18 property Type parameterType
19 property var shortcut 1.3
20+ property var state 1.3
21 property string text
22 property bool visible
23 Ubuntu.Components.Action.Type: Enum
24@@ -54,12 +57,12 @@
25 function trigger(var value)
26 function trigger()
27 property string text
28-Ubuntu.Components.ActionList 1.0 0.1: QtObject
29- property list<Action> actions
30- default property list<Action> children
31-Ubuntu.Components.ActionList 1.3: QtObject
32- property list<Action> actions
33- default property list<Action> children
34+Ubuntu.Components.ActionList 1.0 0.1 UCActionList: QtObject
35+ default property list<Action> actions
36+ signal added(Action action)
37+ signal removed(Action action)
38+ function addAction(Action action)
39+ function removeAction(Action action)
40 Ubuntu.Components.ActionManager 1.0 0.1 UCActionManager: QtObject
41 default property list<Action> actions
42 readonly property ActionContext globalContext
43@@ -456,6 +459,8 @@
44 property bool showDivider
45 readonly property string swipingState
46 readonly property bool waitingConfirmationForRemoval
47+Ubuntu.Components.ExclusiveGroup 1.3 UCExclusiveGroup: ActionList
48+ readonly property Action selected
49 Ubuntu.Components.ListItems.Expandable 1.0 0.1: Empty
50 property bool collapseOnClick
51 property double collapsedHeight
52@@ -656,6 +661,22 @@
53 function double lerp(double delta, double from, double to)
54 function double projectValue(double x, double xmin, double xmax, double ymin, double ymax)
55 function double clampAndProject(double x, double xmin, double xmax, double ymin, double ymax)
56+Ubuntu.Components.Menu 1.3 UCMenu: Action
57+ default property list<QtObject> data
58+ function show(Qt.point pt)
59+ function dismiss()
60+ function appendObject(QtObject obj)
61+ function insertObject(int index, QtObject obj)
62+ function removeObject(QtObject obj)
63+Ubuntu.Components.MenuBar 1.3 UCMenuBar: QtObject
64+ default property list<Menu> menus
65+ function appendMenu(Menu menu)
66+ function insertMenu(int index, Menu menu)
67+ function removeMenu(Menu menu)
68+Ubuntu.Components.MenuGroup 1.3 UCMenuGroup: ActionList
69+Ubuntu.Components.Menus 1.3: QtObject
70+ readonly property MenuBar menuBar
71+ readonly property Menu parentMenu
72 Ubuntu.Components.MimeData 1.0 0.1 QQuickMimeData: QtObject
73 property color color
74 property var data
75
76=== removed file 'src/Ubuntu/Components/1.2/ActionList.qml'
77--- src/Ubuntu/Components/1.2/ActionList.qml 2016-05-25 12:48:10 +0000
78+++ src/Ubuntu/Components/1.2/ActionList.qml 1970-01-01 00:00:00 +0000
79@@ -1,47 +0,0 @@
80-/*
81- * Copyright 2012 Canonical Ltd.
82- *
83- * This program is free software; you can redistribute it and/or modify
84- * it under the terms of the GNU Lesser General Public License as published by
85- * the Free Software Foundation; version 3.
86- *
87- * This program is distributed in the hope that it will be useful,
88- * but WITHOUT ANY WARRANTY; without even the implied warranty of
89- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90- * GNU Lesser General Public License for more details.
91- *
92- * You should have received a copy of the GNU Lesser General Public License
93- * along with this program. If not, see <http://www.gnu.org/licenses/>.
94- */
95-
96-import QtQuick 2.4
97-import Ubuntu.Components 1.2
98-
99-/*!
100- \qmltype ActionList
101- \inqmlmodule Ubuntu.Components
102- \ingroup ubuntu
103- \brief List of \l Action items
104-*/
105-
106-QtObject {
107- id: list
108- // internal objects using nested elements,
109- // which isn't allowed by QtObject; this fix makes this possible
110- /*!
111- Default property to allow adding of children.
112- \qmlproperty list<Action> children
113- \default
114- */
115- default property alias children: list.actions
116-
117- /*!
118- List of already defined actions when not defining them as children of the ActionList.
119- Note that when you set this property, the children of the ActionList will be ignored,
120- so do not set the list and define children.
121-
122- The advantage of setting actions over using the children is that the same
123- \l Action items can be used in several sets of actions.
124- */
125- property list<Action> actions
126-}
127
128=== removed file 'src/Ubuntu/Components/1.3/ActionList.qml'
129--- src/Ubuntu/Components/1.3/ActionList.qml 2016-05-25 12:48:10 +0000
130+++ src/Ubuntu/Components/1.3/ActionList.qml 1970-01-01 00:00:00 +0000
131@@ -1,47 +0,0 @@
132-/*
133- * Copyright 2012 Canonical Ltd.
134- *
135- * This program is free software; you can redistribute it and/or modify
136- * it under the terms of the GNU Lesser General Public License as published by
137- * the Free Software Foundation; version 3.
138- *
139- * This program is distributed in the hope that it will be useful,
140- * but WITHOUT ANY WARRANTY; without even the implied warranty of
141- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
142- * GNU Lesser General Public License for more details.
143- *
144- * You should have received a copy of the GNU Lesser General Public License
145- * along with this program. If not, see <http://www.gnu.org/licenses/>.
146- */
147-
148-import QtQuick 2.4
149-import Ubuntu.Components 1.3
150-
151-/*!
152- \qmltype ActionList
153- \inqmlmodule Ubuntu.Components
154- \ingroup ubuntu
155- \brief List of \l Action items
156-*/
157-
158-QtObject {
159- id: list
160- // internal objects using nested elements,
161- // which isn't allowed by QtObject; this fix makes this possible
162- /*!
163- Default property to allow adding of children.
164- \qmlproperty list<Action> children
165- \default
166- */
167- default property alias children: list.actions
168-
169- /*!
170- List of already defined actions when not defining them as children of the ActionList.
171- Note that when you set this property, the children of the ActionList will be ignored,
172- so do not set the list and define children.
173-
174- The advantage of setting actions over using the children is that the same
175- \l Action items can be used in several sets of actions.
176- */
177- property list<Action> actions
178-}
179
180=== modified file 'src/Ubuntu/Components/ComponentModule.pro'
181--- src/Ubuntu/Components/ComponentModule.pro 2016-02-16 11:39:32 +0000
182+++ src/Ubuntu/Components/ComponentModule.pro 2016-06-07 14:25:30 +0000
183@@ -25,7 +25,6 @@
184
185 #1.2
186 QML_FILES += 1.2/AbstractButton.qml \
187- 1.2/ActionList.qml \
188 1.2/ActivityIndicator.qml \
189 1.2/AnimatedItem.qml \
190 1.2/AppHeader.qml \
191@@ -78,7 +77,6 @@
192
193 #1.3
194 QML_FILES += 1.3/ActionBar.qml \
195- 1.3/ActionList.qml \
196 1.3/ActivityIndicator.qml \
197 1.3/AdaptivePageLayout.qml \
198 1.3/AnimatedItem.qml \
199
200=== modified file 'src/Ubuntu/Components/plugin/plugin.cpp'
201--- src/Ubuntu/Components/plugin/plugin.cpp 2016-04-20 15:00:27 +0000
202+++ src/Ubuntu/Components/plugin/plugin.cpp 2016-06-07 14:25:30 +0000
203@@ -78,9 +78,13 @@
204 #include "ucpagetreenode.h"
205 #include "ucmainviewbase.h"
206 #include "ucperformancemonitor.h"
207+#include "ucmenu.h"
208+#include "ucmenubar.h"
209 #include "privates/frame.h"
210 #include "privates/ucpagewrapper.h"
211 #include "privates/appheaderbase.h"
212+#include "ucactionlist.h"
213+#include "ucexclusivegroup.h"
214
215 // From UbuntuGestures
216 #include "private/ucswipearea_p.h"
217@@ -173,6 +177,7 @@
218 qmlRegisterSimpleSingletonType<UCHaptics>(uri, major, minor, "Haptics");
219 qmlRegisterSimpleSingletonType<UCMathUtils>(uri, major, minor, "MathUtils");
220 qmlRegisterSimpleSingletonType<UbuntuToolkit::ColorUtils>(uri, major, minor, "ColorUtils");
221+ qmlRegisterType<UCActionList>(uri, major, minor, "ActionList");
222 }
223
224 void UbuntuComponentsPlugin::registerTypes(const char *uri)
225@@ -235,6 +240,11 @@
226 qmlRegisterType<UCPageTreeNode>(uri, 1, 3, "PageTreeNode");
227 qmlRegisterType<UCPopupContext>(uri, 1, 3, "PopupContext");
228 qmlRegisterType<UCMainViewBase>(uri, 1, 3, "MainViewBase");
229+ qmlRegisterType<UCMenu>(uri, 1, 3, "Menu");
230+ qmlRegisterType<UCMenuBar>(uri, 1, 3, "MenuBar");
231+ qmlRegisterUncreatableType<UCMenuAttached>(uri, 1, 3, "Menus", "Not instantiable");
232+ qmlRegisterType<UCMenuGroup>(uri, 1, 3, "MenuGroup");
233+ qmlRegisterType<UCExclusiveGroup>(uri, 1, 3, "ExclusiveGroup");
234 }
235
236 void UbuntuComponentsPlugin::initializeContextProperties(QQmlEngine *engine)
237
238=== modified file 'src/Ubuntu/Components/plugin/plugin.pri'
239--- src/Ubuntu/Components/plugin/plugin.pri 2016-04-01 05:30:24 +0000
240+++ src/Ubuntu/Components/plugin/plugin.pri 2016-06-07 14:25:30 +0000
241@@ -3,7 +3,7 @@
242 PKGCONFIG += gio-2.0 dbus-1 libnih-dbus
243 }
244
245-QT *= core-private qml qml-private quick quick-private gui-private dbus svg UbuntuGestures UbuntuGestures_private UbuntuToolkit
246+QT *= core-private qml qml-private quick quick-private gui-private dbus svg platformsupport-private UbuntuGestures UbuntuGestures_private UbuntuToolkit
247
248 equals(QT_MAJOR_VERSION, 5):lessThan(QT_MINOR_VERSION, 2) {
249 QT += v8-private
250@@ -117,7 +117,13 @@
251 $$PWD/privates/ucpagewrapperincubator_p.h \
252 $$PWD/privates/appheaderbase.h \
253 $$PWD/label_p.h \
254- $$PWD/ucbottomedgeregion_p.h
255+ $$PWD/ucbottomedgeregion_p.h \
256+ $$PWD/ucactionlist.h \
257+ $$PWD/ucmenu.h \
258+ $$PWD/ucmenu_p.h \
259+ $$PWD/ucmenubar.h \
260+ $$PWD/ucmenubar_p.h \
261+ $$PWD/ucexclusivegroup.h
262
263 SOURCES += $$PWD/plugin.cpp \
264 $$PWD/uctheme.cpp \
265@@ -194,7 +200,11 @@
266 $$PWD/privates/frame.cpp \
267 $$PWD/privates/ucpagewrapper.cpp \
268 $$PWD/privates/ucpagewrapperincubator.cpp \
269- $$PWD/privates/appheaderbase.cpp
270+ $$PWD/privates/appheaderbase.cpp \
271+ $$PWD/ucactionlist.cpp \
272+ $$PWD/ucmenu.cpp \
273+ $$PWD/ucmenubar.cpp \
274+ $$PWD/ucexclusivegroup.cpp
275
276 # adapters
277 SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp
278
279=== modified file 'src/Ubuntu/Components/plugin/ucaction.cpp'
280--- src/Ubuntu/Components/plugin/ucaction.cpp 2016-05-25 12:48:10 +0000
281+++ src/Ubuntu/Components/plugin/ucaction.cpp 2016-06-07 14:25:30 +0000
282@@ -17,6 +17,7 @@
283 #include "ucaction.h"
284 #include "quickutils.h"
285 #include "ucactioncontext.h"
286+#include "ucexclusivegroup.h"
287
288 #include <QtDebug>
289 #include <QtQml/QQmlInfo>
290@@ -248,43 +249,6 @@
291 * \endqml
292 */
293
294-/*!
295- * \qmlproperty enum Action::parameterType
296- * Type of the parameter passed to \l trigger and \l triggered.
297- * Type is an enumeration:
298- * \list
299- * \li \b Action.None: No paramater. (default)
300- * \li \b Action.String: String parameter.
301- * \li \b Action.Integer: Integer parameter.
302- * \li \b Action.Bool: Boolean parameter.
303- * \li \b Action.Real: Single precision floating point parameter.
304- * \li \b Action.Object: The parameter is an object.
305- * \endlist
306- * \qml
307- * Action {
308- * id: action
309- * parameterType: Action.String
310- * onTriggered: {
311- * // value arguments now contain strings
312- * console.log(value);
313- * }
314- * Component.onCompleted: action.trigger("Hello World")
315- * }
316- * \endqml
317- */
318-
319-/*!
320- * \qmlproperty bool Action::enabled
321- * If set to false the action can not be triggered. Components visualizing the
322- * action migth either hide the action or make it insensitive. However visibility
323- * can be controlled separately using the \l visible property.
324- */
325-
326-/*!
327- * \qmlproperty bool Action::visible
328- * Specifies whether the action is visible to the user. Defaults to true.
329- */
330-
331 UCAction::UCAction(QObject *parent)
332 : QObject(parent)
333 , m_itemHint(Q_NULLPTR)
334@@ -293,12 +257,15 @@
335 , m_enabled(true)
336 , m_visible(true)
337 , m_published(false)
338+ , m_exclusiveGroup(Q_NULLPTR)
339 {
340 generateName();
341 // FIXME: we need QInputDeviceInfo to detect the keyboard attechment
342 // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808
343 connect(QuickUtils::instance(), &QuickUtils::keyboardAttachedChanged,
344 this, &UCAction::onKeyboardAttached);
345+
346+ connect(this, &UCAction::triggered, this, &UCAction::setState);
347 }
348
349 UCAction::~UCAction()
350@@ -434,6 +401,100 @@
351 Q_EMIT shortcutChanged();
352 }
353
354+/*!
355+ * \qmlproperty bool Action::visible
356+ * Specifies whether the action is visible to the user. Defaults to true.
357+ */
358+void UCAction::setVisible(bool visible)
359+{
360+ if (m_visible == visible) {
361+ return;
362+ }
363+ m_visible = visible;
364+ Q_EMIT visibleChanged();
365+}
366+
367+/*!
368+ * \qmlproperty bool Action::enabled
369+ * If set to false the action can not be triggered. Components visualizing the
370+ * action migth either hide the action or make it insensitive. However visibility
371+ * can be controlled separately using the \l visible property.
372+ */
373+void UCAction::setEnabled(bool enabled)
374+{
375+ if (m_enabled == enabled) {
376+ return;
377+ }
378+ m_enabled = enabled;
379+ Q_EMIT enabledChanged();
380+
381+}
382+
383+/*!
384+ * \qmlproperty enum Action::parameterType
385+ * Type of the parameter passed to \l trigger and \l triggered.
386+ * Type is an enumeration:
387+ * \list
388+ * \li \b Action.None: No paramater. (default)
389+ * \li \b Action.String: String parameter.
390+ * \li \b Action.Integer: Integer parameter.
391+ * \li \b Action.Bool: Boolean parameter.
392+ * \li \b Action.Real: Single precision floating point parameter.
393+ * \li \b Action.Object: The parameter is an object.
394+ * \endlist
395+ * \qml
396+ * Action {
397+ * id: action
398+ * parameterType: Action.String
399+ * onTriggered: {
400+ * // value arguments now contain strings
401+ * console.log(value);
402+ * }
403+ * Component.onCompleted: action.trigger("Hello World")
404+ * }
405+ * \endqml
406+ */
407+void UCAction::setParameterType(UCAction::Type type)
408+{
409+ if (m_parameterType == type) {
410+ return;
411+ }
412+ m_parameterType = type;
413+ Q_EMIT parameterTypeChanged();
414+}
415+
416+void UCAction::setState(const QVariant &state)
417+{
418+ if (m_state == state) {
419+ return;
420+ }
421+ m_state = state;
422+ Q_EMIT stateChanged();
423+}
424+
425+UCExclusiveGroup *UCAction::exclusiveGroup() const
426+{
427+ return m_exclusiveGroup;
428+}
429+
430+void UCAction::setExclusiveGroup(UCExclusiveGroup *exclusiveGroup)
431+{
432+ if (m_exclusiveGroup == exclusiveGroup) {
433+ return;
434+ }
435+
436+ if (m_exclusiveGroup) {
437+ m_exclusiveGroup->removeAction(this);
438+ }
439+
440+ m_exclusiveGroup = exclusiveGroup;
441+
442+ if (m_exclusiveGroup) {
443+ m_exclusiveGroup->addAction(this);
444+ }
445+ Q_EMIT exclusiveGroupChanged();
446+}
447+
448 bool UCAction::event(QEvent *event)
449 {
450 if (event->type() != QEvent::Shortcut)
451@@ -473,6 +534,11 @@
452 if (!m_enabled) {
453 return;
454 }
455+
456+ if (m_exclusiveGroup && !m_exclusiveGroup->checkValidTrigger(this, value)) {
457+ return;
458+ }
459+
460 if (!isValidType(value.type())) {
461 Q_EMIT triggered(QVariant());
462 } else {
463
464=== modified file 'src/Ubuntu/Components/plugin/ucaction.h'
465--- src/Ubuntu/Components/plugin/ucaction.h 2016-04-28 11:19:46 +0000
466+++ src/Ubuntu/Components/plugin/ucaction.h 2016-06-07 14:25:30 +0000
467@@ -49,7 +49,7 @@
468
469 class QQmlComponent;
470 class QQuickItem;
471-class UCActionAttached;
472+class UCExclusiveGroup;
473 class UCAction : public QObject
474 {
475 Q_OBJECT
476@@ -58,19 +58,21 @@
477 Q_ENUMS(Type)
478 Q_PROPERTY(QString name MEMBER m_name WRITE setName NOTIFY nameChanged)
479 Q_PROPERTY(QString text READ text WRITE setText RESET resetText NOTIFY textChanged)
480- Q_PROPERTY(QString iconName MEMBER m_iconName WRITE setIconName NOTIFY iconNameChanged)
481+ Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged)
482 Q_PROPERTY(QString description MEMBER m_description NOTIFY descriptionChanged)
483 Q_PROPERTY(QString keywords MEMBER m_keywords NOTIFY keywordsChanged)
484- Q_PROPERTY(bool enabled MEMBER m_enabled NOTIFY enabledChanged)
485- Q_PROPERTY(Type parameterType MEMBER m_parameterType NOTIFY parameterTypeChanged)
486+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
487+ Q_PROPERTY(Type parameterType READ parameterType WRITE setParameterType NOTIFY parameterTypeChanged)
488+ Q_PROPERTY(QVariant state READ state WRITE setState NOTIFY stateChanged REVISION 1)
489+ Q_PROPERTY(UCExclusiveGroup* exclusiveGroup READ exclusiveGroup WRITE setExclusiveGroup NOTIFY exclusiveGroupChanged REVISION 1)
490
491 // Toolkit Actions API
492- Q_PROPERTY(QUrl iconSource MEMBER m_iconSource WRITE setIconSource NOTIFY iconSourceChanged)
493- Q_PROPERTY(bool visible MEMBER m_visible NOTIFY visibleChanged)
494+ Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource NOTIFY iconSourceChanged)
495+ Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
496 Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint)
497
498 // QtQuickControls.Action
499- Q_PROPERTY(QVariant shortcut MEMBER m_shortcut WRITE setShortcut RESET resetShortcut NOTIFY shortcutChanged REVISION 1)
500+ Q_PROPERTY(QVariant shortcut READ shortcut WRITE setShortcut RESET resetShortcut NOTIFY shortcutChanged REVISION 1)
501 public:
502 enum Type {
503 None,
504@@ -104,11 +106,24 @@
505 QString text();
506 void setText(const QString &text);
507 void resetText();
508+ QString iconName() const { return m_iconName; }
509 void setIconName(const QString &name);
510+ QUrl iconSource() const { return m_iconSource; }
511 void setIconSource(const QUrl &url);
512 void setItemHint(QQmlComponent *);
513+ QVariant shortcut() const { return m_shortcut; }
514 void setShortcut(const QVariant&);
515 void resetShortcut();
516+ bool visible() const { return m_visible; }
517+ void setVisible(bool visible);
518+ void setEnabled(bool enabled);
519+
520+ void setParameterType(Type type);
521+ Type parameterType() const { return m_parameterType; }
522+ QVariant state() const { return m_state; }
523+
524+ UCExclusiveGroup *exclusiveGroup() const;
525+ void setExclusiveGroup(UCExclusiveGroup *exclusiveGroup);
526
527 Q_SIGNALS:
528 void nameChanged();
529@@ -121,10 +136,13 @@
530 void iconSourceChanged();
531 void visibleChanged();
532 void shortcutChanged();
533+ void stateChanged();
534+ void exclusiveGroupChanged();
535 void triggered(const QVariant &value);
536
537 public Q_SLOTS:
538 void trigger(const QVariant &value = QVariant());
539+ void setState(const QVariant&);
540
541 private:
542 QPODVector<QQuickItem*, 4> m_owningItems;
543@@ -142,6 +160,8 @@
544 bool m_enabled:1;
545 bool m_visible:1;
546 bool m_published:1;
547+ UCExclusiveGroup *m_exclusiveGroup;
548+ QVariant m_state;
549
550 friend class UCActionContext;
551 friend class UCActionItem;
552
553=== added file 'src/Ubuntu/Components/plugin/ucactionlist.cpp'
554--- src/Ubuntu/Components/plugin/ucactionlist.cpp 1970-01-01 00:00:00 +0000
555+++ src/Ubuntu/Components/plugin/ucactionlist.cpp 2016-06-07 14:25:30 +0000
556@@ -0,0 +1,104 @@
557+/*
558+ * Copyright 2016 Canonical Ltd.
559+ *
560+ * This program is free software; you can redistribute it and/or modify
561+ * it under the terms of the GNU Lesser General Public License as published by
562+ * the Free Software Foundation; version 3.
563+ *
564+ * This program is distributed in the hope that it will be useful,
565+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
566+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
567+ * GNU Lesser General Public License for more details.
568+ *
569+ * You should have received a copy of the GNU Lesser General Public License
570+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
571+ */
572+
573+#include "ucactionlist.h"
574+#include "ucaction.h"
575+
576+/*!
577+ * \qmltype ActionList
578+ * \inqmlmodule Ubuntu.Components
579+ * \ingroup ubuntu
580+ * \brief List of \l Action items
581+ */
582+UCActionList::UCActionList(QObject *parent)
583+ : QObject(parent)
584+{
585+}
586+
587+/*!
588+ * \qmlmethod ActionList::addAction(Action action)
589+ * \deprecated
590+ * Adds an Action to the context programatically.
591+ */
592+void UCActionList::addAction(UCAction *action)
593+{
594+ if (m_actions.contains(action)) {
595+ return;
596+ }
597+ m_actions.append(action);
598+ Q_EMIT added(action);
599+}
600+
601+/*!
602+ * \qmlmethod ActionList::removeAction(Action action)
603+ * \deprecated
604+ * Removes an action from the context programatically.
605+ */
606+void UCActionList::removeAction(UCAction *action)
607+{
608+ if (!action) {
609+ return;
610+ }
611+ if (m_actions.removeOne(action)) {
612+ Q_EMIT removed(action);
613+ }
614+}
615+
616+/*!
617+
618+ * \qmlproperty list<Action> ActionContext::actions
619+ * \default
620+ * List of Actions in this ActionContext
621+ * Note that when you set this property, the children of the ActionList will be ignored,
622+ * so do not set the list and define children.
623+ *
624+ * The advantage of setting actions over using the children is that the same
625+ * \l Action items can be used in several sets of actions.
626+ */
627+QQmlListProperty<UCAction> UCActionList::actions()
628+{
629+ return QQmlListProperty<UCAction>(this, 0, UCActionList::append, UCActionList::count, 0, UCActionList::clear);
630+}
631+
632+const QList<UCAction*> &UCActionList::list() const
633+{
634+ return m_actions;
635+}
636+
637+void UCActionList::append(QQmlListProperty<UCAction> *list, UCAction *action)
638+{
639+ UCActionList *actionList = qobject_cast<UCActionList*>(list->object);
640+ if (actionList) {
641+ actionList->addAction(action);
642+ }
643+}
644+
645+void UCActionList::clear(QQmlListProperty<UCAction> *list)
646+{
647+ UCActionList *actionList = qobject_cast<UCActionList*>(list->object);
648+ if (actionList) {
649+ actionList->m_actions.clear();
650+ }
651+}
652+
653+int UCActionList::count(QQmlListProperty<UCAction> *list)
654+{
655+ UCActionList *actionList = qobject_cast<UCActionList*>(list->object);
656+ if (actionList) {
657+ return actionList->m_actions.count();
658+ }
659+ return 0;
660+}
661
662=== added file 'src/Ubuntu/Components/plugin/ucactionlist.h'
663--- src/Ubuntu/Components/plugin/ucactionlist.h 1970-01-01 00:00:00 +0000
664+++ src/Ubuntu/Components/plugin/ucactionlist.h 2016-06-07 14:25:30 +0000
665@@ -0,0 +1,53 @@
666+/*
667+ * Copyright 2016 Canonical Ltd.
668+ *
669+ * This program is free software; you can redistribute it and/or modify
670+ * it under the terms of the GNU Lesser General Public License as published by
671+ * the Free Software Foundation; version 3.
672+ *
673+ * This program is distributed in the hope that it will be useful,
674+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
675+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
676+ * GNU Lesser General Public License for more details.
677+ *
678+ * You should have received a copy of the GNU Lesser General Public License
679+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
680+ */
681+
682+#ifndef UCACTIONLIST_H
683+#define UCACTIONLIST_H
684+
685+#include <QObject>
686+#include <QtQml/QQmlListProperty>
687+
688+class UCAction;
689+
690+class UCActionList : public QObject
691+{
692+ Q_OBJECT
693+ Q_PROPERTY(QQmlListProperty<UCAction> actions READ actions)
694+ Q_CLASSINFO("DefaultProperty", "actions")
695+public:
696+ explicit UCActionList(QObject *parent = 0);
697+
698+ QQmlListProperty<UCAction> actions();
699+
700+ const QList<UCAction*> &list() const;
701+
702+public Q_SLOTS:
703+ void addAction(UCAction *action);
704+ void removeAction(UCAction *action);
705+
706+Q_SIGNALS:
707+ void added(UCAction *action);
708+ void removed(UCAction *action);
709+
710+protected:
711+ QList<UCAction*> m_actions;
712+
713+ static void append(QQmlListProperty<UCAction> *list, UCAction *action);
714+ static void clear(QQmlListProperty<UCAction> *list);
715+ static int count(QQmlListProperty<UCAction> *list);
716+};
717+
718+#endif // UCACTIONLIST_H
719
720=== added file 'src/Ubuntu/Components/plugin/ucexclusivegroup.cpp'
721--- src/Ubuntu/Components/plugin/ucexclusivegroup.cpp 1970-01-01 00:00:00 +0000
722+++ src/Ubuntu/Components/plugin/ucexclusivegroup.cpp 2016-06-07 14:25:30 +0000
723@@ -0,0 +1,106 @@
724+/*
725+ * Copyright 2016 Canonical Ltd.
726+ *
727+ * This program is free software; you can redistribute it and/or modify
728+ * it under the terms of the GNU Lesser General Public License as published by
729+ * the Free Software Foundation; version 3.
730+ *
731+ * This program is distributed in the hope that it will be useful,
732+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
733+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
734+ * GNU Lesser General Public License for more details.
735+ *
736+ * You should have received a copy of the GNU Lesser General Public License
737+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
738+ *
739+ */
740+
741+#include "ucexclusivegroup.h"
742+#include "ucaction.h"
743+
744+UCExclusiveGroup::UCExclusiveGroup(QObject *parent)
745+ : UCActionList(parent)
746+ , m_entranceGuard(false)
747+{
748+ connect(this, &UCActionList::added, this, &UCExclusiveGroup::onActionAdded);
749+ connect(this, &UCActionList::removed, this, &UCExclusiveGroup::onActionRemoved);
750+}
751+
752+void UCExclusiveGroup::onActionAdded(UCAction *action)
753+{
754+ action->setExclusiveGroup(this);
755+ connect(action, &UCAction::stateChanged, this, [this, action]() { stateChanged(action); });
756+}
757+
758+void UCExclusiveGroup::onActionRemoved(UCAction *action)
759+{
760+ action->setExclusiveGroup(nullptr);
761+ disconnect(action, &UCAction::stateChanged, this, 0);
762+}
763+
764+void UCExclusiveGroup::stateChanged(UCAction* action)
765+{
766+ if (m_entranceGuard) return;
767+ m_entranceGuard = true;
768+
769+ if (action->state().type() != QVariant::Bool) {
770+ m_entranceGuard = false;
771+ return;
772+ }
773+
774+ Q_FOREACH(UCAction* fromList, list()) {
775+ if (fromList->parameterType() != UCAction::Bool) {
776+ continue;
777+ }
778+
779+ if (fromList != action && fromList->state().toBool() == true) {
780+ fromList->trigger(false);
781+ }
782+ }
783+
784+ if (action->state().toBool() == true) {
785+ setSelected(action);
786+ } else {
787+ setSelected(nullptr);
788+ }
789+
790+ m_entranceGuard = false;
791+}
792+
793+void UCExclusiveGroup::setSelected(UCAction *action)
794+{
795+ if (m_selected != action) {
796+ if (action) {
797+ m_selected = action;
798+ } else {
799+ m_selected.clear();
800+ }
801+ Q_EMIT selectedChanged();
802+ }
803+}
804+
805+UCAction *UCExclusiveGroup::selected() const
806+{
807+ return m_selected;
808+}
809+
810+bool UCExclusiveGroup::checkValidTrigger(UCAction *action, const QVariant &value)
811+{
812+ // deselect others.
813+ if (value.type() == QVariant::Bool && value.toBool() == false) {
814+
815+ int trueCount = 0;
816+ Q_FOREACH(UCAction* fromList, list()) {
817+ if (fromList->parameterType() != UCAction::Bool ||
818+ action == fromList) {
819+ continue;
820+ }
821+ trueCount += fromList->state().toBool();
822+ }
823+
824+ if (trueCount == 0) {
825+ return false;
826+ }
827+ }
828+ return true;
829+}
830
831=== added file 'src/Ubuntu/Components/plugin/ucexclusivegroup.h'
832--- src/Ubuntu/Components/plugin/ucexclusivegroup.h 1970-01-01 00:00:00 +0000
833+++ src/Ubuntu/Components/plugin/ucexclusivegroup.h 2016-06-07 14:25:30 +0000
834@@ -0,0 +1,53 @@
835+/*
836+ * Copyright 2016 Canonical Ltd.
837+ *
838+ * This program is free software; you can redistribute it and/or modify
839+ * it under the terms of the GNU Lesser General Public License as published by
840+ * the Free Software Foundation; version 3.
841+ *
842+ * This program is distributed in the hope that it will be useful,
843+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
844+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
845+ * GNU Lesser General Public License for more details.
846+ *
847+ * You should have received a copy of the GNU Lesser General Public License
848+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
849+ *
850+ */
851+
852+#ifndef UCEXCLUSIVEGROUP_H
853+#define UCEXCLUSIVEGROUP_H
854+
855+#include "ucactionlist.h"
856+#include "ucaction.h"
857+#include <QQmlParserStatus>
858+
859+class UCExclusiveGroup : public UCActionList
860+{
861+ Q_OBJECT
862+ Q_PROPERTY(UCAction* selected READ selected NOTIFY selectedChanged)
863+
864+public:
865+ explicit UCExclusiveGroup(QObject *parent = 0);
866+
867+ UCAction* selected() const;
868+
869+ bool checkValidTrigger(UCAction* action, const QVariant& value);
870+
871+Q_SIGNALS:
872+ void selectedChanged();
873+
874+
875+protected Q_SLOTS:
876+ void onActionAdded(UCAction* action);
877+ void onActionRemoved(UCAction* action);
878+
879+private:
880+ void stateChanged(UCAction* action);
881+ void setSelected(UCAction* action);
882+
883+ QPointer<UCAction> m_selected;
884+ bool m_entranceGuard;
885+};
886+
887+#endif // UCEXCLUSIVEGROUP_H
888
889=== added file 'src/Ubuntu/Components/plugin/ucmenu.cpp'
890--- src/Ubuntu/Components/plugin/ucmenu.cpp 1970-01-01 00:00:00 +0000
891+++ src/Ubuntu/Components/plugin/ucmenu.cpp 2016-06-07 14:25:30 +0000
892@@ -0,0 +1,613 @@
893+/*
894+ * Copyright 2016 Canonical Ltd.
895+ *
896+ * This program is free software; you can redistribute it and/or modify
897+ * it under the terms of the GNU Lesser General Public License as published by
898+ * the Free Software Foundation; version 3.
899+ *
900+ * This program is distributed in the hope that it will be useful,
901+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
902+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
903+ * GNU Lesser General Public License for more details.
904+ *
905+ * You should have received a copy of the GNU Lesser General Public License
906+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
907+ */
908+
909+#include "ucmenu.h"
910+#include "ucmenu_p.h"
911+#include "ucmenubar.h"
912+#include "ucaction.h"
913+#include "ucactionlist.h"
914+
915+// Qt
916+#include <QtGui/qpa/qplatformtheme.h>
917+#include <QtGui/qpa/qplatformmenu.h>
918+#include <QQuickItem>
919+#include <private/qguiapplication_p.h>
920+#include <private/qquickitem_p.h>
921+#include <QPointer>
922+
923+
924+Q_LOGGING_CATEGORY(ucMenu, "ubuntu.components.Menu", QtMsgType::QtWarningMsg)
925+
926+namespace {
927+
928+QWindow* findWindowForObject(QObject* object)
929+{
930+ QObject* window = object;
931+ while (window && !window->isWindowType()) {
932+ window = window->parent();
933+ if (QQuickItem* item = qobject_cast<QQuickItem*>(window)) {
934+ window = item->window();
935+ }
936+ }
937+ return qobject_cast<QWindow*>(window);
938+}
939+
940+}
941+
942+UCMenuPrivate::UCMenuPrivate(UCMenu *qq)
943+ : q_ptr(qq)
944+ , m_platformMenu(QGuiApplicationPrivate::platformTheme()->createPlatformMenu())
945+{
946+}
947+
948+UCMenuPrivate::~UCMenuPrivate()
949+{
950+ delete m_platformMenu;
951+}
952+
953+void UCMenuPrivate::insertObject(int index, QObject *o)
954+{
955+ Q_Q(UCMenu);
956+ if (!o) return;
957+ qCInfo(ucMenu).nospace() << "UCMenu::insertObject(index="<< index << ", object=" << o << ")";
958+
959+ // If the menus contains lists, we need to alter the insertion index to account for them.
960+ int actualIndex = 0;
961+ for (int i = 0; i < index && i < m_data.count(); i++) {
962+ QObject* data = m_data[i];
963+ auto list = qobject_cast<UCActionList*>(data);
964+ actualIndex += list ? list->list().count() : 1;
965+
966+ // menu group adds a separator item.
967+ if (qobject_cast<UCMenuGroup*>(data)) {
968+ actualIndex++;
969+ }
970+ }
971+
972+ QVector<QObject*>::iterator position = m_data.count() > index ? m_data.begin() + index : m_data.end();
973+ m_data.insert(position, o);
974+
975+ QObjectList objects;
976+ if (UCActionList* actionList = qobject_cast<UCActionList*>(o)) {
977+ Q_FOREACH(UCAction* action, actionList->list()) {
978+ qCInfo(ucMenu).nospace() << " UCMenu::insertObject(actionList=" << actionList << ", action=" << action << ")";
979+ objects << action;
980+ }
981+ // menu group adds a separator item; so add self as well.
982+ if (qobject_cast<UCMenuGroup*>(actionList)) {
983+ objects << o;
984+ }
985+ } else {
986+ objects << o;
987+ }
988+
989+ Q_FOREACH(QObject* object, objects) {
990+
991+ UCMenuAttached *attached = qobject_cast<UCMenuAttached*>(qmlAttachedPropertiesObject<UCMenuAttached>(object));
992+ if (attached) {
993+ attached->setParentObject(q);
994+ }
995+
996+ // add to platform
997+ if (m_platformMenu) {
998+ auto platformWrapper = new PlatformItemWrapper(object, q);
999+ platformWrapper->insert(actualIndex++);
1000+ m_platformItems[object] = platformWrapper;
1001+
1002+ QObject::connect(object, &QObject::destroyed, q, [platformWrapper]() {
1003+ platformWrapper->remove();
1004+ });
1005+ }
1006+ }
1007+}
1008+
1009+void UCMenuPrivate::removeObject(QObject *o)
1010+{
1011+ Q_Q(UCMenu);
1012+ m_data.removeOne(o);
1013+ qCInfo(ucMenu).nospace() << "UCMenu::insertObject(" << o << ")";
1014+
1015+ QObjectList objects;
1016+ if (UCActionList* actionList = qobject_cast<UCActionList*>(o)) {
1017+ Q_FOREACH(UCAction* action, actionList->list()) {
1018+ objects << action;
1019+ }
1020+ if (qobject_cast<UCMenuGroup*>(actionList)) {
1021+ objects << o;
1022+ }
1023+ } else {
1024+ objects << o;
1025+ }
1026+
1027+ Q_FOREACH(QObject* object, objects) {
1028+ // remove from platform.
1029+ if (m_platformMenu && m_platformItems.contains(object)) {
1030+ m_platformItems[object]->remove();
1031+ m_platformItems.remove(object);
1032+ }
1033+ }
1034+}
1035+
1036+void UCMenuPrivate::_q_updateEnabled()
1037+{
1038+ Q_Q(UCMenu);
1039+
1040+ bool isEnabled = q->isEnabled();
1041+ if (m_platformMenu) { m_platformMenu->setEnabled(isEnabled); }
1042+}
1043+
1044+void UCMenuPrivate::_q_updateText()
1045+{
1046+ Q_Q(UCMenu);
1047+
1048+ QString text = q->text();
1049+ if (m_platformMenu) { m_platformMenu->setText(text); }
1050+}
1051+
1052+void UCMenuPrivate::_q_updateIcon()
1053+{
1054+ Q_Q(UCMenu);
1055+
1056+ QIcon icon;
1057+ if (!q->iconSource().isEmpty()) {
1058+ icon = QIcon(q->iconSource().path());
1059+ } else if (!q->iconName().isEmpty()) {
1060+ icon = QIcon::fromTheme(q->iconName());
1061+ }
1062+
1063+ if (m_platformMenu) { m_platformMenu->setIcon(icon); }
1064+}
1065+
1066+void UCMenuPrivate::_q_updateVisible()
1067+{
1068+ Q_Q(UCMenu);
1069+
1070+ bool visible = q->visible();
1071+ if (m_platformMenu) { m_platformMenu->setVisible(visible); }
1072+}
1073+
1074+void UCMenuPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
1075+{
1076+ UCMenu *q = qobject_cast<UCMenu *>(prop->object);
1077+ q->appendObject(o);
1078+}
1079+
1080+int UCMenuPrivate::data_count(QQmlListProperty<QObject> *prop)
1081+{
1082+ UCMenuPrivate *p = static_cast<UCMenuPrivate *>(prop->data);
1083+ return p->m_data.count();
1084+}
1085+
1086+QObject *UCMenuPrivate::data_at(QQmlListProperty<QObject> *prop, int index)
1087+{
1088+ UCMenuPrivate *p = static_cast<UCMenuPrivate *>(prop->data);
1089+ return p->m_data.value(index);
1090+}
1091+
1092+void UCMenuPrivate::data_clear(QQmlListProperty<QObject> *prop)
1093+{
1094+ UCMenuPrivate *p = static_cast<UCMenuPrivate *>(prop->data);
1095+ p->m_data.clear();
1096+}
1097+
1098+/*!
1099+ * \qmltype Menu
1100+ * \instantiates UCMenu
1101+ * \inqmlmodule Ubuntu.Components
1102+ * \ingroup ubuntu
1103+ * \brief Menu defines a context menu or submenu structure of a MenuBar
1104+ *
1105+ * Example usage:
1106+ * \qml
1107+ * import QtQuick 2.4
1108+ * import Ubuntu.Components 1.3
1109+ * Menu {
1110+ * text: "&File"
1111+ *
1112+ * MenuGroup {
1113+ * Action {
1114+ * text: "&New"
1115+ * shortcut: "Ctrl+N"
1116+ * }
1117+ *
1118+ * Action {
1119+ * text: "&Open"
1120+ * shortcut: "Ctrl+O"
1121+ * }
1122+ * }
1123+ *
1124+ * Menu {
1125+ * text: "Recent Files"
1126+ *
1127+ * ActionList {
1128+ * Action { text: "1.txt" }
1129+ * Action { text: "2.txt" }
1130+ * Action { text: "3.txt" }
1131+ * }
1132+ * }
1133+ *
1134+ * Action {
1135+ * action: Action {
1136+ * text: "E&xit"
1137+ * shortcut: "Ctrl+X"
1138+ * }
1139+ * }
1140+ * }
1141+ * \endqml
1142+ */
1143+UCMenu::UCMenu(QObject *parent)
1144+ : UCAction(parent)
1145+ , d_ptr(new UCMenuPrivate(this))
1146+{
1147+ Q_D(UCMenu);
1148+
1149+ connect(this, SIGNAL(enabledChanged()), this, SLOT(_q_updateEnabled()));
1150+ connect(this, SIGNAL(textChanged()), this, SLOT(_q_updateText()));
1151+ connect(this, SIGNAL(iconNameChanged()), this, SLOT(_q_updateIcon()));
1152+ connect(this, SIGNAL(iconSourceChanged()), this, SLOT(_q_updateIcon()));
1153+ connect(this, SIGNAL(visibleChanged()), this, SLOT(_q_updateVisible()));
1154+}
1155+
1156+UCMenu::~UCMenu()
1157+{
1158+}
1159+
1160+/*!
1161+ * \qmlproperty list<Object> Menu::data
1162+ * \default
1163+ * List of objects representing menu items within the menu.
1164+ *
1165+ * Currently supports Menu, MenuItem, MenuSeparator & Item objects.
1166+ * \note Item object which do not support platformItem will not be exported for native menus.
1167+ */
1168+QQmlListProperty<QObject> UCMenu::data()
1169+{
1170+ Q_D(UCMenu);
1171+ return QQmlListProperty<QObject>(this, d,
1172+ &UCMenuPrivate::data_append,
1173+ &UCMenuPrivate::data_count,
1174+ &UCMenuPrivate::data_at,
1175+ &UCMenuPrivate::data_clear);
1176+}
1177+
1178+/*!
1179+ * \qmlmethod Menu::appendObject(object o)
1180+ * Add a object tto the menu
1181+ */
1182+void UCMenu::appendObject(QObject *o)
1183+{
1184+ Q_D(UCMenu);
1185+
1186+ insertObject(d->m_data.count(), o);
1187+}
1188+
1189+/*!
1190+ * \qmlmethod Menu::insertObject(int index, object o)
1191+ * Inserts an item at the index in the menu.
1192+ *
1193+ * Currently supports Menu, MenuItem, MenuSeparator & Item objects.
1194+ * \note Item object which do not support platformItem will not be exported for native menus.
1195+ */
1196+void UCMenu::insertObject(int index, QObject *o)
1197+{
1198+ Q_D(UCMenu);
1199+ d->insertObject(index, o);
1200+}
1201+
1202+/*!
1203+ * \qmlmethod Menu::removeObject(object o)
1204+ * Removes the item from the menu.
1205+ */
1206+void UCMenu::removeObject(QObject *o)
1207+{
1208+ Q_D(UCMenu);
1209+ qCInfo(ucMenu) << "UCMenu::removeObject" << o;
1210+
1211+ d->removeObject(o);
1212+}
1213+
1214+QPlatformMenu* UCMenu::platformMenu() const
1215+{
1216+ Q_D(const UCMenu);
1217+ return d->m_platformMenu;
1218+}
1219+
1220+/*!
1221+ * \qmlmethod Menu::show(point point)
1222+ * Show the menu popup at the given point
1223+ */
1224+void UCMenu::show(const QPoint &point)
1225+{
1226+ Q_D(UCMenu);
1227+ qCInfo(ucMenu, "UCMenu::popup(%s, point(%d,%d))", qPrintable(text()), point.x(), point.y());
1228+
1229+ if (d->m_platformMenu) {
1230+ d->m_platformMenu->showPopup(findWindowForObject(this), QRect(point, QSize()), nullptr);
1231+ }
1232+}
1233+
1234+/*!
1235+ * \qmlmethod Menu::dismiss()
1236+ * Dismiss and destroy the menu popup.
1237+ */
1238+void UCMenu::dismiss()
1239+{
1240+ Q_D(UCMenu);
1241+ qCInfo(ucMenu, "UCMenu::dismiss(%s)", qPrintable(text()));
1242+
1243+ if (d->m_platformMenu) {
1244+ d->m_platformMenu->dismiss();
1245+ }
1246+}
1247+
1248+/*!
1249+ * \qmltype Menus
1250+ * \instantiates UCMenuAttached
1251+ * \inqmlmodule Ubuntu.Components 1.3
1252+ * \ingroup ubuntu
1253+ * \since Ubuntu.Components 1.3
1254+ * \brief A set of properties attached to the Menu.
1255+ *
1256+ */
1257+UCMenuAttached::UCMenuAttached(QObject *parent)
1258+ : QObject(parent)
1259+ , m_parentObject(nullptr)
1260+{
1261+}
1262+
1263+UCMenuAttached *UCMenuAttached::qmlAttachedProperties(QObject *o)
1264+{
1265+ return new UCMenuAttached(o);
1266+}
1267+
1268+void UCMenuAttached::setParentObject(QObject *o)
1269+{
1270+ if (m_parentObject != o) {
1271+ UCMenu* oldMenu = parentMenu();
1272+ UCMenuBar* oldBar = menuBar();
1273+
1274+ m_parentObject = o;
1275+
1276+ if (oldMenu != parentMenu()) Q_EMIT parentMenuChanged();
1277+ if (oldBar != menuBar()) Q_EMIT menuBarChanged();
1278+ }
1279+}
1280+
1281+/*!
1282+ * \qmlattachedproperty bool Menus::parentMenu
1283+ * The property returns the parent Menu of the object, or null if there is none.
1284+ */
1285+UCMenu *UCMenuAttached::parentMenu() const
1286+{
1287+ return qobject_cast<UCMenu*>(m_parentObject);
1288+}
1289+
1290+/*!
1291+ * \qmlattachedproperty bool Menus::menuBar
1292+ * The property returns the parent MenuBar of the object, or null if there is none.
1293+ */
1294+UCMenuBar *UCMenuAttached::menuBar() const
1295+{
1296+ return qobject_cast<UCMenuBar*>(m_parentObject);
1297+}
1298+
1299+
1300+PlatformItemWrapper::PlatformItemWrapper(QObject *target, UCMenu* menu)
1301+ : QObject(menu)
1302+ , m_target(target)
1303+ , m_menu(menu)
1304+ , m_platformItem(menu->platformMenu() ? menu->platformMenu()->createMenuItem() : Q_NULLPTR)
1305+{
1306+ connect(m_target, &QObject::destroyed, this, &QObject::deleteLater);
1307+
1308+ if (UCMenu* menu = qobject_cast<UCMenu*>(m_target)) {
1309+ if (m_platformItem) {
1310+ m_platformItem->setMenu(menu->platformMenu());
1311+ }
1312+
1313+ connect(menu, &UCMenu::visibleChanged, this, &PlatformItemWrapper::updateVisible);
1314+ connect(menu, &UCMenu::textChanged, this, &PlatformItemWrapper::updateText);
1315+ connect(menu, &UCMenu::enabledChanged, this, &PlatformItemWrapper::updateEnabled);
1316+ connect(menu, &UCMenu::iconSourceChanged, this, &PlatformItemWrapper::updateIcon);
1317+ connect(menu, &UCMenu::iconNameChanged, this, &PlatformItemWrapper::updateIcon);
1318+
1319+ } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
1320+
1321+ connect(action, &UCAction::visibleChanged, this, &PlatformItemWrapper::updateVisible);
1322+ connect(action, &UCAction::textChanged, this, &PlatformItemWrapper::updateText);
1323+ connect(action, &UCAction::enabledChanged, this, &PlatformItemWrapper::updateEnabled);
1324+ connect(action, &UCAction::iconSourceChanged, this, &PlatformItemWrapper::updateIcon);
1325+ connect(action, &UCAction::iconNameChanged, this, &PlatformItemWrapper::updateIcon);
1326+ connect(action, &UCAction::shortcutChanged, this, &PlatformItemWrapper::updateShortcut);
1327+ connect(action, &UCAction::parameterTypeChanged, this, &PlatformItemWrapper::updateCheck);
1328+ connect(action, &UCAction::stateChanged, this, &PlatformItemWrapper::updateCheck);
1329+
1330+ if (m_platformItem) {
1331+ connect(m_platformItem, SIGNAL(activated()), action, SLOT(trigger()));
1332+ }
1333+
1334+ } else if (qobject_cast<UCActionList*>(m_target)) {
1335+ if (m_platformItem) {
1336+ m_platformItem->setIsSeparator(true);
1337+ }
1338+ }
1339+
1340+ syncPlatformItem();
1341+}
1342+
1343+void PlatformItemWrapper::insert(int index)
1344+{
1345+ auto platformMenu = m_menu->platformMenu();
1346+ if (!platformMenu) return;
1347+ if (!m_platformItem) return;
1348+
1349+ QPlatformMenuItem* before = platformMenu->menuItemAt(index);
1350+ platformMenu->insertMenuItem(m_platformItem, before);
1351+}
1352+
1353+void PlatformItemWrapper::remove()
1354+{
1355+ auto platformMenu = m_menu->platformMenu();
1356+ if (!platformMenu) return;
1357+ if (!m_platformItem) return;
1358+
1359+ platformMenu->removeMenuItem(m_platformItem);
1360+}
1361+
1362+void PlatformItemWrapper::updateVisible()
1363+{
1364+ if (!m_platformItem) return;
1365+
1366+ if (UCMenu* menu = qobject_cast<UCMenu*>(m_target)) {
1367+ m_platformItem->setVisible(menu->visible());
1368+ if (menu->platformMenu()) menu->platformMenu()->setVisible(menu->visible());
1369+ } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
1370+ m_platformItem->setVisible(action->visible());
1371+ }
1372+}
1373+
1374+void PlatformItemWrapper::updateEnabled()
1375+{
1376+ if (!m_platformItem) return;
1377+
1378+ if (UCMenu* menu = qobject_cast<UCMenu*>(m_target)) {
1379+ m_platformItem->setEnabled(menu->isEnabled());
1380+ if (menu->platformMenu()) menu->platformMenu()->setEnabled(menu->isEnabled());
1381+ } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
1382+ m_platformItem->setText(action->text());
1383+ }
1384+}
1385+
1386+void PlatformItemWrapper::updateText()
1387+{
1388+ if (!m_platformItem) return;
1389+
1390+ if (UCMenu* menu = qobject_cast<UCMenu*>(m_target)) {
1391+ m_platformItem->setText(menu->text());
1392+ if (menu->platformMenu()) menu->platformMenu()->setText(menu->text());
1393+ } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
1394+ m_platformItem->setText(action->text());
1395+ }
1396+}
1397+
1398+void PlatformItemWrapper::updateIcon()
1399+{
1400+ if (!m_platformItem) return;
1401+
1402+ QIcon icon;
1403+ if (UCMenu* menu = qobject_cast<UCMenu*>(m_target)) {
1404+
1405+ if (!menu->iconSource().isEmpty()) {
1406+ icon = QIcon(menu->iconSource().path());
1407+ } else if (!menu->iconName().isEmpty()) {
1408+ icon = QIcon::fromTheme(menu->iconName());
1409+ }
1410+ if (menu->platformMenu()) menu->platformMenu()->setIcon(icon);
1411+
1412+ } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
1413+
1414+ if (!action->iconSource().isEmpty()) {
1415+ icon = QIcon(action->iconSource().path());
1416+ } else if (!action->iconName().isEmpty()) {
1417+ icon = QIcon::fromTheme(action->iconName());
1418+ }
1419+ }
1420+ m_platformItem->setIcon(icon);
1421+}
1422+
1423+
1424+inline QKeySequence sequenceFromVariant(const QVariant& variant)
1425+{
1426+ if (variant.type() == QVariant::Int) {
1427+ return static_cast<QKeySequence::StandardKey>(variant.toInt());
1428+ }
1429+ if (variant.type() == QVariant::String) {
1430+ return QKeySequence::fromString(variant.toString());
1431+ }
1432+ return QKeySequence();
1433+}
1434+
1435+void PlatformItemWrapper::updateShortcut()
1436+{
1437+ if (!m_platformItem) return;
1438+
1439+ if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
1440+ m_platformItem->setShortcut(sequenceFromVariant(action->shortcut()));
1441+ }
1442+}
1443+
1444+void PlatformItemWrapper::updateCheck()
1445+{
1446+ if (!m_platformItem) return;
1447+
1448+ if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
1449+ bool checkable = action->parameterType() == UCAction::Bool;
1450+ m_platformItem->setCheckable(checkable);
1451+ m_platformItem->setChecked(checkable && action->state().toBool());
1452+ }
1453+}
1454+
1455+void PlatformItemWrapper::syncPlatformItem()
1456+{
1457+ updateVisible();
1458+ updateEnabled();
1459+ updateText();
1460+ updateIcon();
1461+ updateShortcut();
1462+ updateCheck();
1463+
1464+ if (m_menu->platformMenu() && m_platformItem) {
1465+ m_menu->platformMenu()->syncMenuItem(m_platformItem);
1466+ }
1467+}
1468+
1469+
1470+/*!
1471+ * \qmltype MenuGroup
1472+ * \inqmlmodule Ubuntu.Components
1473+ * \ingroup ubuntu
1474+ * \brief List of \l Action items for a menu which adds a separator between logical groups of menus.
1475+ *
1476+ * Example usage:
1477+ * \qml
1478+ * import QtQuick 2.4
1479+ * import Ubuntu.Components 1.3
1480+ * Menu {
1481+ * text: "Edit"
1482+ *
1483+ * MenuGroup {
1484+ * Action { text: "Undo" }
1485+ * Action { text: "Redo" }
1486+ * }
1487+ *
1488+ * MenuGroup {
1489+ * Action { text: "Cut" }
1490+ * Action { text: "Copy" }
1491+ * Action { text: "Paste" }
1492+ * }
1493+ *
1494+ * MenuGroup {
1495+ * Action { text: "Select All" }
1496+ * }
1497+ * }
1498+ * \endqml
1499+ */
1500+UCMenuGroup::UCMenuGroup(QObject *parent)
1501+ : UCActionList(parent)
1502+{
1503+}
1504+
1505+#include "moc_ucmenu.cpp"
1506
1507=== added file 'src/Ubuntu/Components/plugin/ucmenu.h'
1508--- src/Ubuntu/Components/plugin/ucmenu.h 1970-01-01 00:00:00 +0000
1509+++ src/Ubuntu/Components/plugin/ucmenu.h 2016-06-07 14:25:30 +0000
1510@@ -0,0 +1,108 @@
1511+/*
1512+ * Copyright 2016 Canonical Ltd.
1513+ *
1514+ * This program is free software; you can redistribute it and/or modify
1515+ * it under the terms of the GNU Lesser General Public License as published by
1516+ * the Free Software Foundation; version 3.
1517+ *
1518+ * This program is distributed in the hope that it will be useful,
1519+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1520+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1521+ * GNU Lesser General Public License for more details.
1522+ *
1523+ * You should have received a copy of the GNU Lesser General Public License
1524+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1525+ *
1526+ */
1527+
1528+#ifndef UCMENU_H
1529+#define UCMENU_H
1530+
1531+#include <QQmlListProperty>
1532+#include <QUrl>
1533+#include <QLoggingCategory>
1534+#include <QPointer>
1535+#include <qqml.h>
1536+#include <QtQml/qqml.h>
1537+#include <private/qquickitemchangelistener_p.h>
1538+
1539+#include "ucaction.h"
1540+#include "ucactionlist.h"
1541+
1542+Q_DECLARE_LOGGING_CATEGORY(ucMenu);
1543+
1544+class QPlatformMenu;
1545+class QPlatformMenuItem;
1546+class QQuickItem;
1547+class UCMenuPrivate;
1548+class UCMenuAttached;
1549+class UCMenuBar;
1550+class UCAction;
1551+
1552+class UCMenu : public UCAction
1553+{
1554+ Q_OBJECT
1555+
1556+ Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL)
1557+ Q_CLASSINFO("DefaultProperty", "data")
1558+
1559+public:
1560+ explicit UCMenu(QObject *parent = 0);
1561+ ~UCMenu();
1562+
1563+ QQmlListProperty<QObject> data();
1564+
1565+ Q_INVOKABLE void appendObject(QObject* obj);
1566+ Q_INVOKABLE void insertObject(int index, QObject* obj);
1567+ Q_INVOKABLE void removeObject(QObject* obj);
1568+
1569+ QPlatformMenu *platformMenu() const;
1570+
1571+public Q_SLOTS:
1572+ void show(const QPoint& pt);
1573+ void dismiss();
1574+
1575+private:
1576+ Q_DISABLE_COPY(UCMenu)
1577+ Q_DECLARE_PRIVATE(UCMenu)
1578+ QScopedPointer<UCMenuPrivate> d_ptr;
1579+
1580+ Q_PRIVATE_SLOT(d_func(), void _q_updateEnabled())
1581+ Q_PRIVATE_SLOT(d_func(), void _q_updateText())
1582+ Q_PRIVATE_SLOT(d_func(), void _q_updateIcon())
1583+ Q_PRIVATE_SLOT(d_func(), void _q_updateVisible())
1584+};
1585+
1586+class UCMenuAttached : public QObject
1587+{
1588+ Q_OBJECT
1589+ Q_PROPERTY(UCMenu* parentMenu READ parentMenu NOTIFY parentMenuChanged)
1590+ Q_PROPERTY(UCMenuBar* menuBar READ menuBar NOTIFY parentMenuChanged)
1591+public:
1592+ explicit UCMenuAttached(QObject *parent);
1593+
1594+ static UCMenuAttached *qmlAttachedProperties(QObject *);
1595+
1596+ void setParentObject(QObject* o);
1597+
1598+ UCMenu *parentMenu() const;
1599+ UCMenuBar *menuBar() const;
1600+
1601+Q_SIGNALS:
1602+ void parentMenuChanged();
1603+ void menuBarChanged();
1604+
1605+private:
1606+ QPointer<QObject> m_parentObject;
1607+};
1608+QML_DECLARE_TYPEINFO(UCMenuAttached, QML_HAS_ATTACHED_PROPERTIES)
1609+
1610+
1611+class UCMenuGroup : public UCActionList
1612+{
1613+ Q_OBJECT
1614+public:
1615+ explicit UCMenuGroup(QObject *parent = 0);
1616+};
1617+
1618+#endif // UCMENU_H
1619
1620=== added file 'src/Ubuntu/Components/plugin/ucmenu_p.h'
1621--- src/Ubuntu/Components/plugin/ucmenu_p.h 1970-01-01 00:00:00 +0000
1622+++ src/Ubuntu/Components/plugin/ucmenu_p.h 2016-06-07 14:25:30 +0000
1623@@ -0,0 +1,83 @@
1624+/*
1625+ * Copyright 2016 Canonical Ltd.
1626+ *
1627+ * This program is free software; you can redistribute it and/or modify
1628+ * it under the terms of the GNU Lesser General Public License as published by
1629+ * the Free Software Foundation; version 3.
1630+ *
1631+ * This program is distributed in the hope that it will be useful,
1632+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1633+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1634+ * GNU Lesser General Public License for more details.
1635+ *
1636+ * You should have received a copy of the GNU Lesser General Public License
1637+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1638+ *
1639+ */
1640+
1641+#ifndef UCMENU_P
1642+#define UCMENU_P
1643+
1644+#include <private/qquickitemchangelistener_p.h>
1645+#include "ucmenu.h"
1646+
1647+class QObject;
1648+class UCAction;
1649+class QQmlComponent;
1650+class UCMenu;
1651+class PlatformItemWrapper;
1652+
1653+class UCMenuPrivate
1654+{
1655+ Q_DECLARE_PUBLIC(UCMenu)
1656+public:
1657+ UCMenuPrivate(UCMenu *qq);
1658+ virtual ~UCMenuPrivate();
1659+
1660+ void insertObject(int index, QObject *obj);
1661+ void removeObject(QObject *obj);
1662+
1663+ void _q_updateEnabled();
1664+ void _q_updateText();
1665+ void _q_updateIcon();
1666+ void _q_updateVisible();
1667+
1668+ static void data_append(QQmlListProperty<QObject> *prop, QObject *o);
1669+ static int data_count(QQmlListProperty<QObject> *prop);
1670+ static QObject *data_at(QQmlListProperty<QObject> *prop, int index);
1671+ static void data_clear(QQmlListProperty<QObject> *prop);
1672+
1673+ UCMenu* q_ptr;
1674+ QPlatformMenu* m_platformMenu;
1675+ UCAction* m_action;
1676+
1677+ QHash<QObject*, PlatformItemWrapper*> m_platformItems;
1678+ QVector<QObject*> m_data;
1679+};
1680+
1681+class PlatformItemWrapper : public QObject
1682+{
1683+ Q_OBJECT
1684+public:
1685+ PlatformItemWrapper(QObject *target, UCMenu* menu);
1686+
1687+ void insert(int index);
1688+ void remove();
1689+
1690+public Q_SLOTS:
1691+ void updateVisible();
1692+ void updateEnabled();
1693+ void updateText();
1694+ void updateIcon();
1695+ void updateShortcut();
1696+ void updateCheck();
1697+
1698+private:
1699+ void syncPlatformItem();
1700+
1701+ QObject* m_target;
1702+ UCMenu* m_menu;
1703+ QPlatformMenuItem* m_platformItem;
1704+};
1705+
1706+#endif // UCMENU_P
1707
1708=== added file 'src/Ubuntu/Components/plugin/ucmenubar.cpp'
1709--- src/Ubuntu/Components/plugin/ucmenubar.cpp 1970-01-01 00:00:00 +0000
1710+++ src/Ubuntu/Components/plugin/ucmenubar.cpp 2016-06-07 14:25:30 +0000
1711@@ -0,0 +1,299 @@
1712+/*
1713+ * Copyright 2016 Canonical Ltd.
1714+ *
1715+ * This program is free software; you can redistribute it and/or modify
1716+ * it under the terms of the GNU Lesser General Public License as published by
1717+ * the Free Software Foundation; version 3.
1718+ *
1719+ * This program is distributed in the hope that it will be useful,
1720+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1721+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1722+ * GNU Lesser General Public License for more details.
1723+ *
1724+ * You should have received a copy of the GNU Lesser General Public License
1725+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1726+ *
1727+ */
1728+
1729+#include "ucmenubar.h"
1730+#include "ucmenubar_p.h"
1731+
1732+// Qt
1733+#include <QQuickItem>
1734+#include <QQuickWindow>
1735+#include <private/qguiapplication_p.h>
1736+#include <QtGui/qpa/qplatformtheme.h>
1737+#include <QtGui/qpa/qplatformmenu.h>
1738+
1739+UCMenuBarPrivate::UCMenuBarPrivate(UCMenuBar *qq)
1740+ : q_ptr(qq)
1741+{
1742+ m_platformBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar();
1743+}
1744+
1745+void UCMenuBarPrivate::insertMenu(int index, UCMenu* menu)
1746+{
1747+ Q_Q(UCMenuBar);
1748+ UCMenu* prevMenu = m_menus.count() > index ? m_menus[index] : nullptr;
1749+
1750+ m_menus.insert(index, menu);
1751+
1752+ UCMenuAttached *attached = qobject_cast<UCMenuAttached*>(qmlAttachedPropertiesObject<UCMenuAttached>(menu));
1753+ if (attached) {
1754+ attached->setParentObject(q);
1755+ }
1756+
1757+ if (m_platformBar && menu->platformMenu()) {
1758+ m_platformBar->insertMenu(menu->platformMenu(), prevMenu ? prevMenu->platformMenu() : nullptr);
1759+ }
1760+}
1761+
1762+void UCMenuBarPrivate::menu_append(QQmlListProperty<UCMenu> *prop, UCMenu *o)
1763+{
1764+ UCMenuBarPrivate *q = static_cast<UCMenuBarPrivate *>(prop->data);
1765+ // menubar is the menus parent
1766+ o->setParent(prop->object);
1767+ q->insertMenu(q->m_menus.count(), o);
1768+}
1769+
1770+int UCMenuBarPrivate::menu_count(QQmlListProperty<UCMenu> *prop)
1771+{
1772+ UCMenuBarPrivate *p = static_cast<UCMenuBarPrivate *>(prop->data);
1773+ return p->m_menus.count();
1774+}
1775+
1776+UCMenu *UCMenuBarPrivate::menu_at(QQmlListProperty<UCMenu> *prop, int index)
1777+{
1778+ UCMenuBarPrivate *p = static_cast<UCMenuBarPrivate *>(prop->data);
1779+ return p->m_menus.value(index);
1780+}
1781+
1782+void UCMenuBarPrivate::menu_clear(QQmlListProperty<UCMenu> *prop)
1783+{
1784+ UCMenuBarPrivate *p = static_cast<UCMenuBarPrivate *>(prop->data);
1785+ p->m_menus.clear();
1786+}
1787+
1788+/*!
1789+ * \qmltype MenuBar
1790+ * \instantiates UCMenuBar
1791+ * \inqmlmodule Ubuntu.Components 1.3
1792+ * \ingroup ubuntu
1793+ * \brief MenuBar defines an application menu bar structure
1794+ *
1795+ * Example usage:
1796+ * \qml
1797+ * import QtQuick 2.4
1798+ * import Ubuntu.Components 1.3
1799+ * MainView {
1800+ * MenuBar {
1801+ * Menu {
1802+ * text: "_File"
1803+ *
1804+ * MenuItem {
1805+ * text: "_New"
1806+ * shortcut: "Ctrl+N"
1807+ * }
1808+ *
1809+ * MenuItem {
1810+ * text: "_Open"
1811+ * shortcut: "Ctrl+O"
1812+ * }
1813+ *
1814+ * MenuSeparator {}
1815+ *
1816+ * MenuItem {
1817+ * action: exitAction
1818+ * }
1819+ * }
1820+ *
1821+ * Menu {
1822+ * text: "_Edit"
1823+ *
1824+ * MenuItem {
1825+ * text: "_Undo"
1826+ * iconSource: "image://theme/undo"
1827+ * }
1828+ * }
1829+ * Menu {
1830+ * text: "_Window"
1831+ *
1832+ * MenuItem {
1833+ * text: "Fullscreen"
1834+ * checkable: true
1835+ * checked: false
1836+ * }
1837+ * }
1838+ * }
1839+ * Action {
1840+ * id: boundAction
1841+ * text: "E_xit"
1842+ * onTriggered: {
1843+ * Qt.quit();
1844+ * }
1845+ * }
1846+ * }
1847+ * \endqml
1848+ */
1849+UCMenuBar::UCMenuBar(QObject *parent)
1850+ : QObject(parent)
1851+ , d_ptr(new UCMenuBarPrivate(this))
1852+{
1853+}
1854+
1855+UCMenuBar::~UCMenuBar()
1856+{
1857+}
1858+
1859+/*!
1860+ * \qmlmethod void MenuBar::appendMenu(Menu menu)
1861+ * Append a Menu to the MenuBar
1862+ */
1863+void UCMenuBar::appendMenu(UCMenu *menu)
1864+{
1865+ Q_D(UCMenuBar);
1866+ insertMenu(d->m_menus.count(), menu);
1867+}
1868+
1869+/*!
1870+ * \qmlmethod void MenuBar::insertMenu(int index, Menu menu)
1871+ * Insert a Menu to the MenuBar at the specified position
1872+ */
1873+void UCMenuBar::insertMenu(int index, UCMenu *menu)
1874+{
1875+ Q_D(UCMenuBar);
1876+ if (!menu) return;
1877+
1878+ d->insertMenu(index, menu);
1879+ Q_EMIT menusChanged();
1880+}
1881+
1882+/*!
1883+ * \qmlmethod void MenuBar::removeMenu(Menu menu)
1884+ * Remove a Menu from the MenuBar
1885+ */
1886+void UCMenuBar::removeMenu(UCMenu *menu)
1887+{
1888+ Q_D(UCMenuBar);
1889+ if (!menu) return;
1890+
1891+ if (d->m_menus.removeOne(menu)) {
1892+ Q_EMIT menusChanged();
1893+ }
1894+}
1895+/*!
1896+ * \qmlproperty list<Menu> MenuBar::menus
1897+ * \default
1898+ * List of Menus in this MenuBar.
1899+ */
1900+QQmlListProperty<UCMenu> UCMenuBar::menus()
1901+{
1902+ Q_D(UCMenuBar);
1903+ return QQmlListProperty<UCMenu>(this, d,
1904+ &UCMenuBarPrivate::menu_append,
1905+ &UCMenuBarPrivate::menu_count,
1906+ &UCMenuBarPrivate::menu_at,
1907+ &UCMenuBarPrivate::menu_clear);
1908+}
1909+
1910+QPlatformMenuBar *UCMenuBar::platformMenuBar() const
1911+{
1912+ Q_D(const UCMenuBar);
1913+ return d->m_platformBar;
1914+}
1915+
1916+void UCMenuBar::classBegin()
1917+{
1918+}
1919+
1920+void UCMenuBar::componentComplete()
1921+{
1922+ Q_D(UCMenuBar);
1923+
1924+ auto parentItem = qobject_cast<QQuickItem*>(parent());
1925+ if (parentItem && d->m_platformBar) {
1926+ d->m_platformBar->handleReparent(parentItem->window());
1927+ }
1928+}
1929+
1930+PlatformMenuWrapper::PlatformMenuWrapper(UCMenu *target, UCMenuBar* bar)
1931+ : QObject(bar)
1932+ , m_bar(bar)
1933+ , m_target(target)
1934+ , m_platformItem(target->platformMenu() ? target->platformMenu()->createMenuItem() : Q_NULLPTR)
1935+{
1936+ connect(m_target, &QObject::destroyed, this, &QObject::deleteLater);
1937+
1938+ connect(m_target, &UCMenu::visibleChanged, this, &PlatformMenuWrapper::updateVisible);
1939+ connect(m_target, &UCMenu::textChanged, this, &PlatformMenuWrapper::updateText);
1940+ connect(m_target, &UCMenu::enabledChanged, this, &PlatformMenuWrapper::updateEnabled);
1941+ connect(m_target, &UCMenu::iconSourceChanged, this, &PlatformMenuWrapper::updateIcon);
1942+ connect(m_target, &UCMenu::iconNameChanged, this, &PlatformMenuWrapper::updateIcon);
1943+
1944+ if (m_platformItem) {
1945+ m_platformItem->setMenu(target->platformMenu());
1946+ }
1947+ syncPlatformItem();
1948+}
1949+
1950+void PlatformMenuWrapper::insert(int index)
1951+{
1952+ Q_UNUSED(index);
1953+
1954+ auto platformBar = m_bar->platformMenuBar();
1955+ if (!platformBar) return;
1956+ auto platformMenu = m_target->platformMenu();
1957+ if (!platformMenu) return;
1958+
1959+ platformBar->insertMenu(platformMenu, Q_NULLPTR);
1960+}
1961+
1962+void PlatformMenuWrapper::remove()
1963+{
1964+ auto platformBar = m_bar->platformMenuBar();
1965+ if (!platformBar) return;
1966+ auto platformMenu = m_target->platformMenu();
1967+ if (!platformMenu) return;
1968+
1969+ platformBar->removeMenu(platformMenu);
1970+}
1971+
1972+void PlatformMenuWrapper::updateVisible()
1973+{
1974+ if (m_platformItem) m_platformItem->setVisible(m_target->visible());
1975+ if (m_target->platformMenu()) m_target->platformMenu()->setVisible(m_target->visible());
1976+}
1977+
1978+void PlatformMenuWrapper::updateEnabled()
1979+{
1980+ if (!m_platformItem) m_platformItem->setEnabled(m_target->isEnabled());
1981+ if (m_target->platformMenu()) m_target->platformMenu()->setEnabled(m_target->isEnabled());
1982+}
1983+
1984+void PlatformMenuWrapper::updateText()
1985+{
1986+ if (!m_platformItem) m_platformItem->setText(m_target->text());
1987+ if (m_target->platformMenu()) m_target->platformMenu()->setText(m_target->text());
1988+}
1989+
1990+void PlatformMenuWrapper::updateIcon()
1991+{
1992+ QIcon icon;
1993+ if (!m_target->iconSource().isEmpty()) {
1994+ icon = QIcon(m_target->iconSource().path());
1995+ } else if (!m_target->iconName().isEmpty()) {
1996+ icon = QIcon::fromTheme(m_target->iconName());
1997+ }
1998+ if (m_target->platformMenu()) m_target->platformMenu()->setIcon(icon);
1999+ if (!m_platformItem) m_platformItem->setIcon(icon);
2000+}
2001+
2002+void PlatformMenuWrapper::syncPlatformItem()
2003+{
2004+ updateVisible();
2005+ updateEnabled();
2006+ updateText();
2007+ updateIcon();
2008+}
2009+
2010+#include "moc_ucmenubar.cpp"
2011
2012=== added file 'src/Ubuntu/Components/plugin/ucmenubar.h'
2013--- src/Ubuntu/Components/plugin/ucmenubar.h 1970-01-01 00:00:00 +0000
2014+++ src/Ubuntu/Components/plugin/ucmenubar.h 2016-06-07 14:25:30 +0000
2015@@ -0,0 +1,60 @@
2016+/*
2017+ * Copyright 2016 Canonical Ltd.
2018+ *
2019+ * This program is free software; you can redistribute it and/or modify
2020+ * it under the terms of the GNU Lesser General Public License as published by
2021+ * the Free Software Foundation; version 3.
2022+ *
2023+ * This program is distributed in the hope that it will be useful,
2024+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2025+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2026+ * GNU Lesser General Public License for more details.
2027+ *
2028+ * You should have received a copy of the GNU Lesser General Public License
2029+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2030+ *
2031+ */
2032+
2033+#ifndef UCMENUBAR_H
2034+#define UCMENUBAR_H
2035+
2036+#include "ucmenu.h"
2037+
2038+#include <QQmlParserStatus>
2039+
2040+class UCMenuBarPrivate;
2041+class QPlatformMenuBar;
2042+
2043+class UCMenuBar : public QObject, public QQmlParserStatus
2044+{
2045+ Q_OBJECT
2046+ Q_INTERFACES(QQmlParserStatus)
2047+
2048+ Q_PROPERTY(QQmlListProperty<UCMenu> menus READ menus NOTIFY menusChanged FINAL)
2049+ Q_CLASSINFO("DefaultProperty", "menus")
2050+
2051+public:
2052+ explicit UCMenuBar(QObject *parent = 0);
2053+ ~UCMenuBar();
2054+
2055+ Q_INVOKABLE void appendMenu(UCMenu *menu);
2056+ Q_INVOKABLE void insertMenu(int index, UCMenu *menu);
2057+ Q_INVOKABLE void removeMenu(UCMenu *menu);
2058+
2059+ QQmlListProperty<UCMenu> menus();
2060+
2061+ QPlatformMenuBar *platformMenuBar() const;
2062+
2063+ void classBegin() Q_DECL_OVERRIDE;
2064+ void componentComplete() Q_DECL_OVERRIDE;
2065+
2066+Q_SIGNALS:
2067+ void menusChanged();
2068+
2069+private:
2070+ Q_DISABLE_COPY(UCMenuBar)
2071+ Q_DECLARE_PRIVATE(UCMenuBar)
2072+ QScopedPointer<UCMenuBarPrivate> d_ptr;
2073+};
2074+
2075+#endif // UCMENUBAR_H
2076
2077=== added file 'src/Ubuntu/Components/plugin/ucmenubar_p.h'
2078--- src/Ubuntu/Components/plugin/ucmenubar_p.h 1970-01-01 00:00:00 +0000
2079+++ src/Ubuntu/Components/plugin/ucmenubar_p.h 2016-06-07 14:25:30 +0000
2080@@ -0,0 +1,68 @@
2081+/*
2082+ * Copyright 2016 Canonical Ltd.
2083+ *
2084+ * This program is free software; you can redistribute it and/or modify
2085+ * it under the terms of the GNU Lesser General Public License as published by
2086+ * the Free Software Foundation; version 3.
2087+ *
2088+ * This program is distributed in the hope that it will be useful,
2089+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2090+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2091+ * GNU Lesser General Public License for more details.
2092+ *
2093+ * You should have received a copy of the GNU Lesser General Public License
2094+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2095+ *
2096+ */
2097+
2098+#ifndef UCMENUBAR_P
2099+#define UCMENUBAR_P
2100+
2101+#include "ucmenubar.h"
2102+
2103+class QPlatformMenuBar;
2104+
2105+class UCMenuBarPrivate : public QQuickItemChangeListener
2106+{
2107+ Q_DECLARE_PUBLIC(UCMenuBar)
2108+public:
2109+ UCMenuBarPrivate(UCMenuBar *qq);
2110+
2111+ void insertMenu(int index, UCMenu *menu);
2112+
2113+ static void menu_append(QQmlListProperty<UCMenu> *prop, UCMenu *o);
2114+ static int menu_count(QQmlListProperty<UCMenu> *prop);
2115+ static UCMenu *menu_at(QQmlListProperty<UCMenu> *prop, int index);
2116+ static void menu_clear(QQmlListProperty<UCMenu> *prop);
2117+
2118+ UCMenuBar* q_ptr;
2119+ QPlatformMenuBar* m_platformBar;
2120+ QVector<UCMenu*> m_menus;
2121+};
2122+
2123+class PlatformMenuWrapper : public QObject
2124+{
2125+ Q_OBJECT
2126+public:
2127+ PlatformMenuWrapper(UCMenu *target, UCMenuBar *bar);
2128+
2129+ void insert(int index);
2130+ void remove();
2131+
2132+public Q_SLOTS:
2133+ void updateVisible();
2134+ void updateEnabled();
2135+ void updateText();
2136+ void updateIcon();
2137+ void updateShortcut();
2138+
2139+private:
2140+ void syncPlatformItem();
2141+
2142+ UCMenuBar* m_bar;
2143+ UCMenu* m_target;
2144+ QPlatformMenuItem* m_platformItem;
2145+};
2146+
2147+#endif // UCMENUBAR_P
2148+
2149
2150=== modified file 'src/Ubuntu/Components/qmldir'
2151--- src/Ubuntu/Components/qmldir 2016-02-16 11:39:32 +0000
2152+++ src/Ubuntu/Components/qmldir 2016-06-07 14:25:30 +0000
2153@@ -1,6 +1,5 @@
2154 module Ubuntu.Components
2155 plugin UbuntuComponents
2156-ActionList 0.1 1.2/ActionList.qml
2157 ToolbarItems 0.1 1.2/ToolbarItems.qml
2158 ToolbarButton 0.1 1.2/ToolbarButton.qml
2159 MainView 0.1 1.2/MainView.qml
2160@@ -40,7 +39,6 @@
2161 DateUtils 0.1 1.2/dateUtils.js
2162
2163 #version 1.0
2164-ActionList 1.0 1.2/ActionList.qml
2165 ToolbarItems 1.0 1.2/ToolbarItems.qml
2166 ToolbarButton 1.0 1.2/ToolbarButton.qml
2167 MainView 1.0 1.2/MainView.qml
2168@@ -95,7 +93,6 @@
2169 #################################################
2170 #version 1.3
2171 ActionBar 1.3 1.3/ActionBar.qml
2172-ActionList 1.3 1.3/ActionList.qml
2173 AdaptivePageLayout 1.3 1.3/AdaptivePageLayout.qml
2174 PageColumnsLayout 1.3 1.3/PageColumnsLayout.qml
2175 PageColumn 1.3 1.3/PageColumn.qml

Subscribers

People subscribed via source and target branches

to status/vote changes: