Merge lp:~zeller-benjamin/ubuntu-ui-toolkit/trusty-builds into lp:ubuntu-ui-toolkit

Proposed by Benjamin Zeller
Status: Superseded
Proposed branch: lp:~zeller-benjamin/ubuntu-ui-toolkit/trusty-builds
Merge into: lp:ubuntu-ui-toolkit
Diff against target: 7454 lines (+5770/-511)
69 files modified
apicheck/apicheck.pro (+2/-4)
app-launch-profiler/app-launch-tracepoints.c (+2/-2)
components.api (+14/-3)
debian/control (+1/-0)
debian/control.gles (+1/-0)
debian/libubuntugestures5-dev.install (+0/-1)
debian/libubuntumetrics5-dev.install (+0/-1)
debian/libubuntutoolkit5-dev.install (+0/-1)
debian/rules (+1/-0)
documentation/overview.qdoc (+16/-0)
src/Ubuntu/Components/1.2/ActivityIndicator.qml (+5/-0)
src/Ubuntu/Components/1.3/ActionList.qml (+0/-47)
src/Ubuntu/Components/1.3/ActivityIndicator.qml (+5/-0)
src/Ubuntu/Components/ComponentModule.pro (+0/-1)
src/Ubuntu/Components/Popups/1.3/Popover.qml (+30/-25)
src/Ubuntu/Components/Popups/1.3/popupUtils.js (+5/-0)
src/Ubuntu/Components/Themes/Ambiance/1.2/ActivityIndicatorStyle.qml (+0/-2)
src/Ubuntu/Components/Themes/Ambiance/1.3/ActivityIndicatorStyle.qml (+0/-2)
src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollbarStyle.qml (+49/-28)
src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollingActionBarStyle.qml (+203/-0)
src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro (+1/-0)
src/Ubuntu/Components/Themes/Ambiance/qmldir (+1/-0)
src/Ubuntu/Components/qmldir (+0/-1)
src/Ubuntu/Test/UbuntuTestCase13.qml (+1/-1)
src/Ubuntu/UbuntuMetrics/applicationmonitor.cpp (+3/-1)
src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro (+22/-4)
src/Ubuntu/UbuntuToolkit/actionlist.cpp (+158/-0)
src/Ubuntu/UbuntuToolkit/actionlist_p.h (+58/-0)
src/Ubuntu/UbuntuToolkit/exclusivegroup.cpp (+168/-0)
src/Ubuntu/UbuntuToolkit/exclusivegroup_p.h (+62/-0)
src/Ubuntu/UbuntuToolkit/menu.cpp (+671/-0)
src/Ubuntu/UbuntuToolkit/menu_p.h (+75/-0)
src/Ubuntu/UbuntuToolkit/menu_p_p.h (+95/-0)
src/Ubuntu/UbuntuToolkit/menubar.cpp (+340/-0)
src/Ubuntu/UbuntuToolkit/menubar_p.h (+65/-0)
src/Ubuntu/UbuntuToolkit/menubar_p_p.h (+78/-0)
src/Ubuntu/UbuntuToolkit/menugroup.cpp (+164/-0)
src/Ubuntu/UbuntuToolkit/menugroup_p.h (+60/-0)
src/Ubuntu/UbuntuToolkit/privates/splitviewhandler.cpp (+137/-0)
src/Ubuntu/UbuntuToolkit/privates/splitviewhandler_p_p.h (+52/-0)
src/Ubuntu/UbuntuToolkit/quickutils.cpp (+4/-2)
src/Ubuntu/UbuntuToolkit/quickutils_p.h (+1/-0)
src/Ubuntu/UbuntuToolkit/splitview.cpp (+675/-0)
src/Ubuntu/UbuntuToolkit/splitview_p.h (+160/-0)
src/Ubuntu/UbuntuToolkit/splitview_p_p.h (+154/-0)
src/Ubuntu/UbuntuToolkit/splitviewlayout.cpp (+252/-0)
src/Ubuntu/UbuntuToolkit/ubuntutoolkitmodule.cpp (+18/-4)
src/Ubuntu/UbuntuToolkit/ucaction.cpp (+186/-37)
src/Ubuntu/UbuntuToolkit/ucaction_p.h (+33/-7)
src/Ubuntu/UbuntuToolkit/uclistitem.cpp (+46/-22)
src/Ubuntu/UbuntuToolkit/ucmathutils_p.h (+4/-4)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_actionbar.py (+43/-11)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py (+13/-13)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/MyDialog.qml (+36/-0)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_actionbar.ActionBarTestCase.qml (+13/-1)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_actionbar.ScrollingActionBarTestCase.qml (+79/-0)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_actionbar.py (+18/-8)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_popups.WindowTestCase.qml (+36/-0)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_popups.py (+19/-0)
tests/unit/components/tst_action.qml (+107/-1)
tests/unit/components/tst_activityindicator.qml (+7/-0)
tests/unit/components/tst_menu.qml (+137/-0)
tests/unit/visual/ScrollbarTestCase13.qml (+3/-0)
tests/unit/visual/tst_actionbar.13.qml (+299/-148)
tests/unit/visual/tst_scrollbar.13.qml (+238/-126)
tests/unit/visual/tst_splitview.13.qml (+383/-0)
tests/unit/visual/tst_splitview_page.13.qml (+143/-0)
tests/unit/visual/tst_splitview_repeater.13.qml (+116/-0)
ubuntu-ui-toolkit-launcher/ubuntu-ui-toolkit-launcher.pro (+2/-3)
To merge this branch: bzr merge lp:~zeller-benjamin/ubuntu-ui-toolkit/trusty-builds
Reviewer Review Type Date Requested Status
Zoltan Balogh Pending
Review via email: mp+304850@code.launchpad.net

This proposal has been superseded by a proposal from 2016-09-03.

Commit message

- Some out of source build fixes
- Implicit casting of QPointer<QObject> to QObject* does not work on trusty

Description of the change

- Some out of source build fixes
- Implicit casting of QPointer<QObject> to QObject* does not work on trusty

To post a comment you must log in.

Unmerged revisions

2090. By Benjamin Zeller

Implicit casting of QPointer<QObject> to QObject* does not work on trusty

2089. By Benjamin Zeller

Fix out of source builds

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'apicheck/apicheck.pro'
--- apicheck/apicheck.pro 2016-01-22 09:31:54 +0000
+++ apicheck/apicheck.pro 2016-09-03 13:06:01 +0000
@@ -4,7 +4,5 @@
4QT += core-private gui-private testlib quick-private4QT += core-private gui-private testlib quick-private
5CONFIG += no_keywords5CONFIG += no_keywords
6SOURCES += apicheck.cpp6SOURCES += apicheck.cpp
7installPath = $$[QT_INSTALL_LIBS]/ubuntu-ui-toolkit7target.path = $$[QT_INSTALL_LIBS]/ubuntu-ui-toolkit
8apicheck.path = $$installPath8INSTALLS += target
9apicheck.files = apicheck
10INSTALLS += $$TARGET
119
=== modified file 'app-launch-profiler/app-launch-tracepoints.c'
--- app-launch-profiler/app-launch-tracepoints.c 2016-08-16 08:43:28 +0000
+++ app-launch-profiler/app-launch-tracepoints.c 2016-09-03 13:06:01 +0000
@@ -28,8 +28,8 @@
2828
29int main (int argc, char* argv[])29int main (int argc, char* argv[])
30{30{
31 #pragma unused(argc)31 (void)argc;
32 #pragma unused(argv)32 (void)argv;
33 tracepoint(app,invokeApplauncher);33 tracepoint(app,invokeApplauncher);
34 return 0;34 return 0;
35}35}
3636
=== modified file 'components.api'
--- components.api 2016-08-09 03:48:53 +0000
+++ components.api 2016-09-03 13:06:01 +0000
@@ -10,13 +10,17 @@
10 readonly property bool pressed10 readonly property bool pressed
11 readonly property UCMargins sensingMargins11 readonly property UCMargins sensingMargins
12Ubuntu.Components.Action 1.3 1.0 0.1 UCAction: QtObject12Ubuntu.Components.Action 1.3 1.0 0.1 UCAction: QtObject
13 property bool checkable 1.3
14 property bool checked 1.3
13 property string description15 property string description
14 property bool enabled16 property bool enabled
17 property ExclusiveGroup exclusiveGroup 1.3
15 property string iconName18 property string iconName
16 property url iconSource19 property url iconSource
17 property Component itemHint20 property Component itemHint
18 property string keywords21 property string keywords
19 signal triggered(var value)22 signal triggered(var value)
23 signal toggled(bool value) 1.3
20 function trigger(var value)24 function trigger(var value)
21 function trigger()25 function trigger()
22 property string name26 property string name
@@ -59,9 +63,12 @@
59Ubuntu.Components.ActionList 1.0 0.1: QtObject63Ubuntu.Components.ActionList 1.0 0.1: QtObject
60 property list<Action> actions64 property list<Action> actions
61 default property list<Action> children65 default property list<Action> children
62Ubuntu.Components.ActionList 1.3: QtObject66Ubuntu.Components.ActionList 1.3 ActionList: QtObject
63 property list<Action> actions67 default property list<Action> actions
64 default property list<Action> children68 signal added(Action action)
69 signal removed(Action action)
70 function addAction(Action action)
71 function removeAction(Action action)
65Ubuntu.Components.ActionManager 1.0 0.1 UCActionManager: QtObject72Ubuntu.Components.ActionManager 1.0 0.1 UCActionManager: QtObject
66 default property list<Action> actions73 default property list<Action> actions
67 readonly property ActionContext globalContext74 readonly property ActionContext globalContext
@@ -458,6 +465,10 @@
458 OperationPending465 OperationPending
459Ubuntu.Metrics.Event: Enum466Ubuntu.Metrics.Event: Enum
460 UserInterfaceReady467 UserInterfaceReady
468Ubuntu.Components.ExclusiveGroup 1.3 ExclusiveGroup: ActionList
469 readonly property QtObject current
470 function bindCheckable(QtObject object)
471 function unbindCheckable(QtObject object)
461Ubuntu.Components.ListItems.Expandable 1.0 0.1: Empty472Ubuntu.Components.ListItems.Expandable 1.0 0.1: Empty
462 property bool collapseOnClick473 property bool collapseOnClick
463 property double collapsedHeight474 property double collapsedHeight
464475
=== modified file 'debian/control'
--- debian/control 2016-08-18 16:51:24 +0000
+++ debian/control 2016-09-03 13:06:01 +0000
@@ -77,6 +77,7 @@
77 qml-module-qtquick-layouts,77 qml-module-qtquick-layouts,
78 qml-module-qtquick-window2,78 qml-module-qtquick-window2,
79 qml-module-qtquick2,79 qml-module-qtquick2,
80 qml-module-ubuntu-components-labs,
80 qml-module-ubuntu-performancemetrics,81 qml-module-ubuntu-performancemetrics,
81 qtdeclarative5-unity-action-plugin (>= 1.1.0),82 qtdeclarative5-unity-action-plugin (>= 1.1.0),
82 suru-icon-theme,83 suru-icon-theme,
8384
=== modified file 'debian/control.gles'
--- debian/control.gles 2016-07-28 10:54:13 +0000
+++ debian/control.gles 2016-09-03 13:06:01 +0000
@@ -103,6 +103,7 @@
103 qml-module-qtquick-layouts,103 qml-module-qtquick-layouts,
104 qml-module-qtquick-window2,104 qml-module-qtquick-window2,
105 qml-module-qtquick2,105 qml-module-qtquick2,
106 qml-module-ubuntu-components-labs,
106 qml-module-ubuntu-performancemetrics-gles,107 qml-module-ubuntu-performancemetrics-gles,
107 qtdeclarative5-unity-action-plugin (>= 1.1.0),108 qtdeclarative5-unity-action-plugin (>= 1.1.0),
108 suru-icon-theme,109 suru-icon-theme,
109110
=== modified file 'debian/libubuntugestures5-dev.install'
--- debian/libubuntugestures5-dev.install 2016-07-06 11:27:11 +0000
+++ debian/libubuntugestures5-dev.install 2016-09-03 13:06:01 +0000
@@ -5,7 +5,6 @@
5usr/include/*/qt5/UbuntuGestures/ubuntugesturesglobal.h5usr/include/*/qt5/UbuntuGestures/ubuntugesturesglobal.h
6usr/include/*/qt5/UbuntuGestures/ubuntugesturesmodule.h6usr/include/*/qt5/UbuntuGestures/ubuntugesturesmodule.h
7usr/include/*/qt5/UbuntuGestures/ubuntugesturesversion.h7usr/include/*/qt5/UbuntuGestures/ubuntugesturesversion.h
8usr/lib/*/libUbuntuGestures.la
9usr/lib/*/libUbuntuGestures.prl8usr/lib/*/libUbuntuGestures.prl
10usr/lib/*/libUbuntuGestures.so9usr/lib/*/libUbuntuGestures.so
11usr/lib/*/pkgconfig/UbuntuGestures.pc10usr/lib/*/pkgconfig/UbuntuGestures.pc
1211
=== modified file 'debian/libubuntumetrics5-dev.install'
--- debian/libubuntumetrics5-dev.install 2016-07-26 16:33:27 +0000
+++ debian/libubuntumetrics5-dev.install 2016-09-03 13:06:01 +0000
@@ -6,7 +6,6 @@
6usr/include/*/qt5/UbuntuMetrics/logger.h6usr/include/*/qt5/UbuntuMetrics/logger.h
7usr/include/*/qt5/UbuntuMetrics/ubuntumetricsglobal.h7usr/include/*/qt5/UbuntuMetrics/ubuntumetricsglobal.h
8usr/include/*/qt5/UbuntuMetrics/ubuntumetricsversion.h8usr/include/*/qt5/UbuntuMetrics/ubuntumetricsversion.h
9usr/lib/*/libUbuntuMetrics.la
10usr/lib/*/libUbuntuMetrics.prl9usr/lib/*/libUbuntuMetrics.prl
11usr/lib/*/libUbuntuMetrics.so10usr/lib/*/libUbuntuMetrics.so
12usr/lib/*/pkgconfig/UbuntuMetrics.pc11usr/lib/*/pkgconfig/UbuntuMetrics.pc
1312
=== modified file 'debian/libubuntutoolkit5-dev.install'
--- debian/libubuntutoolkit5-dev.install 2016-07-07 07:21:48 +0000
+++ debian/libubuntutoolkit5-dev.install 2016-09-03 13:06:01 +0000
@@ -5,7 +5,6 @@
5usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitglobal.h5usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitglobal.h
6usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitmodule.h6usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitmodule.h
7usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitversion.h7usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitversion.h
8usr/lib/*/libUbuntuToolkit.la
9usr/lib/*/libUbuntuToolkit.prl8usr/lib/*/libUbuntuToolkit.prl
10usr/lib/*/libUbuntuToolkit.so9usr/lib/*/libUbuntuToolkit.so
11usr/lib/*/pkgconfig/UbuntuToolkit.pc10usr/lib/*/pkgconfig/UbuntuToolkit.pc
1211
=== modified file 'debian/rules'
--- debian/rules 2016-07-07 18:47:22 +0000
+++ debian/rules 2016-09-03 13:06:01 +0000
@@ -43,6 +43,7 @@
43 mkdir -p debian/tmp/`qmake -query QT_INSTALL_DOCS`/qch43 mkdir -p debian/tmp/`qmake -query QT_INSTALL_DOCS`/qch
44 mkdir -p debian/tmp/usr/share/ubuntu-ui-toolkit/doc44 mkdir -p debian/tmp/usr/share/ubuntu-ui-toolkit/doc
45 cp -r $(CURDIR)/documentation/*qch debian/tmp/`qmake -query QT_INSTALL_DOCS`/qch45 cp -r $(CURDIR)/documentation/*qch debian/tmp/`qmake -query QT_INSTALL_DOCS`/qch
46 rm -f debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/*.la
46 # FIXME: Due to autopilot not being in the archive we ship docs for now47 # FIXME: Due to autopilot not being in the archive we ship docs for now
47 # sphinx-build -b singlehtml documentation/autopilot-helpers documentation/autopilot-helpers/_build/html48 # sphinx-build -b singlehtml documentation/autopilot-helpers documentation/autopilot-helpers/_build/html
48 # sphinx-build -b json documentation/autopilot-helpers documentation/autopilot-helpers/_build/json49 # sphinx-build -b json documentation/autopilot-helpers documentation/autopilot-helpers/_build/json
4950
=== modified file 'documentation/overview.qdoc'
--- documentation/overview.qdoc 2016-07-27 15:40:52 +0000
+++ documentation/overview.qdoc 2016-09-03 13:06:01 +0000
@@ -129,6 +129,22 @@
129 \endcode129 \endcode
130 \annotatedlist ubuntu-services130 \annotatedlist ubuntu-services
131131
132 \part Performance Metrics
133 Available through:
134 \code
135 import Ubuntu.PerformanceMetrics 1.0
136 \endcode
137 \annotatedlist ubuntu-performance-metrics
138
139 \part Labs
140 The Labs module contains a set of components which have unstable API. Those
141 should not be used in applications as their interface may change any time.
142 Available through:
143 \code
144 import Ubuntu.Components.Labs 1.0
145 \endcode
146 \annotatedlist ubuntu-labs
147
132 \part Test extensions148 \part Test extensions
133 Available through:149 Available through:
134 \code150 \code
135151
=== modified file 'src/Ubuntu/Components/1.2/ActivityIndicator.qml'
--- src/Ubuntu/Components/1.2/ActivityIndicator.qml 2016-08-17 14:42:42 +0000
+++ src/Ubuntu/Components/1.2/ActivityIndicator.qml 2016-09-03 13:06:01 +0000
@@ -52,5 +52,10 @@
52 */52 */
53 property bool running: false53 property bool running: false
5454
55 implicitWidth: units.gu(3)
56 implicitHeight: units.gu(3)
57 width: units.gu(3)
58 height: units.gu(3)
59
55 style: Theme.createStyleComponent("ActivityIndicatorStyle.qml", indicator)60 style: Theme.createStyleComponent("ActivityIndicatorStyle.qml", indicator)
56}61}
5762
=== removed file 'src/Ubuntu/Components/1.3/ActionList.qml'
--- src/Ubuntu/Components/1.3/ActionList.qml 2016-05-25 12:48:10 +0000
+++ src/Ubuntu/Components/1.3/ActionList.qml 1970-01-01 00:00:00 +0000
@@ -1,47 +0,0 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19
20/*!
21 \qmltype ActionList
22 \inqmlmodule Ubuntu.Components
23 \ingroup ubuntu
24 \brief List of \l Action items
25*/
26
27QtObject {
28 id: list
29 // internal objects using nested elements,
30 // which isn't allowed by QtObject; this fix makes this possible
31 /*!
32 Default property to allow adding of children.
33 \qmlproperty list<Action> children
34 \default
35 */
36 default property alias children: list.actions
37
38 /*!
39 List of already defined actions when not defining them as children of the ActionList.
40 Note that when you set this property, the children of the ActionList will be ignored,
41 so do not set the list and define children.
42
43 The advantage of setting actions over using the children is that the same
44 \l Action items can be used in several sets of actions.
45 */
46 property list<Action> actions
47}
480
=== modified file 'src/Ubuntu/Components/1.3/ActivityIndicator.qml'
--- src/Ubuntu/Components/1.3/ActivityIndicator.qml 2016-08-17 14:42:42 +0000
+++ src/Ubuntu/Components/1.3/ActivityIndicator.qml 2016-09-03 13:06:01 +0000
@@ -52,5 +52,10 @@
52 */52 */
53 property bool running: false53 property bool running: false
5454
55 implicitWidth: units.gu(3)
56 implicitHeight: units.gu(3)
57 width: units.gu(3)
58 height: units.gu(3)
59
55 styleName: "ActivityIndicatorStyle"60 styleName: "ActivityIndicatorStyle"
56}61}
5762
=== modified file 'src/Ubuntu/Components/ComponentModule.pro'
--- src/Ubuntu/Components/ComponentModule.pro 2016-07-29 13:21:05 +0000
+++ src/Ubuntu/Components/ComponentModule.pro 2016-09-03 13:06:01 +0000
@@ -78,7 +78,6 @@
7878
79#1.379#1.3
80QML_FILES += 1.3/ActionBar.qml \80QML_FILES += 1.3/ActionBar.qml \
81 1.3/ActionList.qml \
82 1.3/ActivityIndicator.qml \81 1.3/ActivityIndicator.qml \
83 1.3/AdaptivePageLayout.qml \82 1.3/AdaptivePageLayout.qml \
84 1.3/AnimatedItem.qml \83 1.3/AnimatedItem.qml \
8584
=== modified file 'src/Ubuntu/Components/Popups/1.3/Popover.qml'
--- src/Ubuntu/Components/Popups/1.3/Popover.qml 2016-03-17 17:40:51 +0000
+++ src/Ubuntu/Components/Popups/1.3/Popover.qml 2016-09-03 13:06:01 +0000
@@ -33,9 +33,8 @@
33 \qml33 \qml
34 import QtQuick 2.434 import QtQuick 2.4
35 import Ubuntu.Components 1.335 import Ubuntu.Components 1.3
36 import Ubuntu.Components.ListItems 1.3 as ListItem
37 import Ubuntu.Components.Popups 1.336 import Ubuntu.Components.Popups 1.3
3837 import Ubuntu.Components.ListItems 1.3 as Old_ListItem
39 Rectangle {38 Rectangle {
40 color: theme.palette.normal.background39 color: theme.palette.normal.background
41 width: units.gu(80)40 width: units.gu(80)
@@ -52,29 +51,35 @@
52 top: parent.top51 top: parent.top
53 right: parent.right52 right: parent.right
54 }53 }
55 ListItem.Header { text: "Standard list items" }54
56 ListItem.Standard { text: "Do something" }55 // there is no equivalent yet to ListItem.Header
57 ListItem.Standard { text: "Do something else" }56 Old_ListItem.Header { text: "Standard list items" }
58 ListItem.Header { text: "Buttons" }57
59 ListItem.SingleControl {58 ListItem {
60 highlightWhenPressed: false59 // shall specify the height when Using ListItemLayout inside ListItem
61 control: Button {60 height: somethingLayout.height + (divider.visible ? divider.height : 0)
62 text: "Do nothing"61 ListItemLayout {
63 anchors {62 id: somethingLayout
64 fill: parent63 title.text: "Do somethings"
65 margins: units.gu(1)64 }
66 }65 onClicked: console.log("clicked on ListItem with onClicked implemented")
67 }66 }
68 }67 ListItem {
69 ListItem.SingleControl {68 // shall specify the height when Using ListItemLayout inside ListItem
70 highlightWhenPressed: false69 height: somethingElseLayout.height + (divider.visible ? divider.height : 0)
71 control: Button {70 ListItemLayout {
72 text: "Close"71 id: somethingElseLayout
73 anchors {72 title.text: "Do somethings"
74 fill: parent73 subtitle.text: "else"
75 margins: units.gu(1)74 }
76 }75 }
77 onClicked: PopupUtils.close(popover)76 ListItem {
77 // shall specify the height when Using ListItemLayout inside ListItem
78 height: closeBtn.height + (divider.visible ? divider.height : 0)
79 Button {
80 id: closeBtn
81 text: "Close button"
82 onClicked: PopupUtils.close(popover);
78 }83 }
79 }84 }
80 }85 }
8186
=== modified file 'src/Ubuntu/Components/Popups/1.3/popupUtils.js'
--- src/Ubuntu/Components/Popups/1.3/popupUtils.js 2016-04-13 19:32:20 +0000
+++ src/Ubuntu/Components/Popups/1.3/popupUtils.js 2016-09-03 13:06:01 +0000
@@ -60,6 +60,11 @@
60 return null;60 return null;
61 }61 }
6262
63 if (!rootObject) {
64 print("PopupUtils.open(): Failed to get the root object.");
65 return null;
66 }
67
63 var popupObject;68 var popupObject;
64 if (params !== undefined) {69 if (params !== undefined) {
65 popupObject = popupComponent.createObject(rootObject, params);70 popupObject = popupComponent.createObject(rootObject, params);
6671
=== modified file 'src/Ubuntu/Components/Themes/Ambiance/1.2/ActivityIndicatorStyle.qml'
--- src/Ubuntu/Components/Themes/Ambiance/1.2/ActivityIndicatorStyle.qml 2016-08-17 14:42:42 +0000
+++ src/Ubuntu/Components/Themes/Ambiance/1.2/ActivityIndicatorStyle.qml 2016-09-03 13:06:01 +0000
@@ -20,8 +20,6 @@
20Image {20Image {
21 id: container21 id: container
2222
23 implicitWidth: units.gu(3)
24 implicitHeight: units.gu(3)
25 smooth: true23 smooth: true
26 visible: styledItem.running24 visible: styledItem.running
27 fillMode: Image.PreserveAspectFit25 fillMode: Image.PreserveAspectFit
2826
=== modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/ActivityIndicatorStyle.qml'
--- src/Ubuntu/Components/Themes/Ambiance/1.3/ActivityIndicatorStyle.qml 2016-08-17 14:42:42 +0000
+++ src/Ubuntu/Components/Themes/Ambiance/1.3/ActivityIndicatorStyle.qml 2016-09-03 13:06:01 +0000
@@ -20,8 +20,6 @@
20Image {20Image {
21 id: container21 id: container
2222
23 implicitWidth: units.gu(3)
24 implicitHeight: units.gu(3)
25 smooth: true23 smooth: true
26 visible: styledItem.running && styledItem.visible24 visible: styledItem.running && styledItem.visible
27 fillMode: Image.PreserveAspectFit25 fillMode: Image.PreserveAspectFit
2826
=== modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollbarStyle.qml'
--- src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollbarStyle.qml 2016-08-02 11:18:34 +0000
+++ src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollbarStyle.qml 2016-09-03 13:06:01 +0000
@@ -316,7 +316,9 @@
316 property string propPosRatio: (isVertical) ? "yPosition" : "xPosition"316 property string propPosRatio: (isVertical) ? "yPosition" : "xPosition"
317 property string propSizeRatio: (isVertical) ? "heightRatio" : "widthRatio"317 property string propSizeRatio: (isVertical) ? "heightRatio" : "widthRatio"
318 property string propCoordinate: (isVertical) ? "y" : "x"318 property string propCoordinate: (isVertical) ? "y" : "x"
319 property string otherPropCoordinate: (isVertical) ? "x" : "y"
319 property string propSize: (isVertical) ? "height" : "width"320 property string propSize: (isVertical) ? "height" : "width"
321 property string otherPropSize: (isVertical) ? "width" : "height"
320 property string propAtBeginning: (isVertical) ? "atYBeginning" : "atXBeginning"322 property string propAtBeginning: (isVertical) ? "atYBeginning" : "atXBeginning"
321 property string propAtEnd: (isVertical) ? "atYEnd" : "atXEnd"323 property string propAtEnd: (isVertical) ? "atYEnd" : "atXEnd"
322324
@@ -622,8 +624,6 @@
622 property bool lockDrag: false624 property bool lockDrag: false
623625
624 property bool hoveringThumb: false626 property bool hoveringThumb: false
625 property string scrollingProp: isVertical ? "y" : "x"
626 property string sizeProp: isVertical ? "height" : "width"
627627
628 function initDrag(isMouse) {628 function initDrag(isMouse) {
629 __disableStateBinding = true629 __disableStateBinding = true
@@ -648,20 +648,29 @@
648 if (!thumbArea.pressed) return648 if (!thumbArea.pressed) return
649649
650 var mouseScrollingProp = isVertical ? mouseY : mouseX650 var mouseScrollingProp = isVertical ? mouseY : mouseX
651 if (mouseScrollingProp < slider[scrollingProp]) {651 if (mouseScrollingProp < slider[scrollbarUtils.propCoordinate]) {
652 scrollBy(-pageSize*visuals.longScrollingRatio, true)652 scrollBy(-pageSize*visuals.longScrollingRatio, true)
653 } else if (mouseScrollingProp > slider[scrollingProp] + slider[sizeProp]) {653 } else if (mouseScrollingProp > slider[scrollbarUtils.propCoordinate] + slider[scrollbarUtils.propSize]) {
654 scrollBy(pageSize*visuals.longScrollingRatio, true)654 scrollBy(pageSize*visuals.longScrollingRatio, true)
655 }655 }
656 }656 }
657657
658 //we consider hover if it's inside the TROUGH along the scrolling axis
659 //and inside the THUMB along the non-scrolling axis
660 //NOTE: mouseX and mouseY are assumed to be relative to thumbArea
658 function handleHover(mouseX, mouseY) {661 function handleHover(mouseX, mouseY) {
662 //NOTE: we're assuming thumbArea has same size/position as the trough.
663 //Use mapToItem to map the coordinates if that assumption falls (i.e. to implement
664 //a larger touch detection area around the thumb)
659 var mouseScrollingProp = isVertical ? mouseY : mouseX665 var mouseScrollingProp = isVertical ? mouseY : mouseX
660 //don't count as hover if the user is already press-and-holding the trough to666 var otherProp = isVertical ? mouseX : mouseY
661 //scroll page by page667
668 //don't count as hover if the user is already press-and-holding
669 //the trough to scroll page by page
662 hoveringThumb = !(pressHoldTimer.running && pressHoldTimer.startedBy === thumbArea)670 hoveringThumb = !(pressHoldTimer.running && pressHoldTimer.startedBy === thumbArea)
663 && mouseScrollingProp >= slider[scrollingProp] &&671 && mouseScrollingProp >= slider[scrollbarUtils.propCoordinate] &&
664 mouseScrollingProp <= slider[scrollingProp] + slider[sizeProp]672 mouseScrollingProp <= slider[scrollbarUtils.propCoordinate] + slider[scrollbarUtils.propSize] &&
673 otherProp >= 0 && otherProp <= trough[scrollbarUtils.otherPropSize]
665 }674 }
666675
667 function saveFlickableScrollingState() {676 function saveFlickableScrollingState() {
@@ -691,14 +700,9 @@
691 previousY = mouse.y700 previousY = mouse.y
692 }701 }
693702
694 anchors {703 //NOTE: remember to update the handleHover check if you add anchor margins
695 fill: trough704 anchors.fill: trough
696 // set margins adding 2 dp for error area705
697 leftMargin: (!isVertical || frontAligned) ? 0 : units.dp(-2)
698 rightMargin: (!isVertical || rearAligned) ? 0 : units.dp(-2)
699 topMargin: (isVertical || topAligned) ? 0 : units.dp(-2)
700 bottomMargin: (isVertical || bottomAligned) ? 0 : units.dp(-2)
701 }
702 enabled: isScrollable && interactive && __canFitSteppersAndShorterThumb706 enabled: isScrollable && interactive && __canFitSteppersAndShorterThumb
703 onPressed: {707 onPressed: {
704 cacheMousePosition(mouse)708 cacheMousePosition(mouse)
@@ -710,8 +714,8 @@
710 if (firstStepper.visible) {714 if (firstStepper.visible) {
711 var mouseScrollingProp = isVertical ? mouseY : mouseX715 var mouseScrollingProp = isVertical ? mouseY : mouseX
712 //don't start the press and hold timer to avoid conflicts with the drag716 //don't start the press and hold timer to avoid conflicts with the drag
713 if (mouseScrollingProp < slider[scrollingProp] ||717 if (mouseScrollingProp < slider[scrollbarUtils.propCoordinate] ||
714 mouseScrollingProp > (slider[scrollingProp] + slider[sizeProp])) {718 mouseScrollingProp > (slider[scrollbarUtils.propCoordinate] + slider[scrollbarUtils.propSize])) {
715 handlePress(mouseX, mouseY)719 handlePress(mouseX, mouseY)
716 pressHoldTimer.startTimer(thumbArea)720 pressHoldTimer.startTimer(thumbArea)
717 } else {721 } else {
@@ -761,7 +765,8 @@
761 pressHoldTimer.stop()765 pressHoldTimer.stop()
762 }766 }
763 onReleased: {767 onReleased: {
764 handleHover(mouseX, mouseY)768 //don't call handleHover here as touch release also triggers this handler
769 //see bug #1616868
765 resetDrag()770 resetDrag()
766 pressHoldTimer.stop()771 pressHoldTimer.stop()
767 }772 }
@@ -797,18 +802,29 @@
797802
798 //logic to support different colour on hovering803 //logic to support different colour on hovering
799 hoverEnabled: true804 hoverEnabled: true
805 //This means this mouse filter will only handle real mouse events!
806 //i.e. the synthesized mouse events created when you use
807 //touchscreen will not trigger it! This way we can have logic that
808 //will not trigger when using touch
809 Mouse.ignoreSynthesizedEvents: true
800 Mouse.enabled: true810 Mouse.enabled: true
801 Mouse.ignoreSynthesizedEvents: true
802 Mouse.onEntered: {811 Mouse.onEntered: {
803 hoveringThumb = false812 hoveringThumb = false
804 handleHover(event.x, event.y)813 handleHover(event.x, event.y)
805 }814 }
806 Mouse.onPositionChanged: {815 Mouse.onPositionChanged: {
816 //We need to update the hover state also onPosChanged because this area
817 //covers the whole trough, not just the thumb, so entered/exited are not enough
818 //e.g. when mouse moves from inside the thumb to inside the trough, or when you
819 //click on the trough and the thumb scrolls and goes under the mouse cursor
807 handleHover(mouse.x, mouse.y)820 handleHover(mouse.x, mouse.y)
808 }821 }
809 Mouse.onExited: {822 Mouse.onExited: {
810 hoveringThumb = false823 hoveringThumb = false
811 }824 }
825 Mouse.onReleased: {
826 handleHover(mouse.x, mouse.y)
827 }
812828
813 Timer {829 Timer {
814 id: pressHoldTimer830 id: pressHoldTimer
@@ -845,6 +861,7 @@
845861
846 MouseArea {862 MouseArea {
847 id: steppersMouseArea863 id: steppersMouseArea
864 objectName: "steppersMouseArea"
848 //size is handled by the states865 //size is handled by the states
849866
850 property bool hoveringFirstStepper: false867 property bool hoveringFirstStepper: false
@@ -897,12 +914,7 @@
897 hoveringFirstStepper = false914 hoveringFirstStepper = false
898 hoveringSecondStepper = false915 hoveringSecondStepper = false
899 }916 }
900917 Mouse.onPressed: {
901 //We don't change the size of the images because we let the image reader figure the size out,
902 //though that means we have to hide the images somehow while the mousearea is visible but has
903 //null size. We choose to enable clipping here instead of creating bindings on images' visible prop
904 clip: true
905 onPressed: {
906 //This additional trigger of the hovering logic is useful especially in testing918 //This additional trigger of the hovering logic is useful especially in testing
907 //environments, where simulating a click on the first stepper will generate onEntered,919 //environments, where simulating a click on the first stepper will generate onEntered,
908 //but then clicking on the second one (without a mouseMove) won't, because they're920 //but then clicking on the second one (without a mouseMove) won't, because they're
@@ -910,7 +922,16 @@
910 //we ensure that the hovering logic is correct even when there are no mouse moves between922 //we ensure that the hovering logic is correct even when there are no mouse moves between
911 //clicks on different steppers (like it happens in tst_actionSteppers test).923 //clicks on different steppers (like it happens in tst_actionSteppers test).
912 handleHover(mouse)924 handleHover(mouse)
925 }
926 Mouse.onReleased: {
927 handleHover(mouse)
928 }
913929
930 //We don't change the size of the images because we let the image reader figure the size out,
931 //though that means we have to hide the images somehow while the mousearea is visible but has
932 //null size. We choose to enable clipping here instead of creating bindings on images' visible prop
933 clip: true
934 onPressed: {
914 handlePress()935 handlePress()
915 pressHoldTimer.startTimer(steppersMouseArea)936 pressHoldTimer.startTimer(steppersMouseArea)
916 }937 }
@@ -952,7 +973,7 @@
952 anchors.centerIn: parent973 anchors.centerIn: parent
953 width: __stepperAssetWidth974 width: __stepperAssetWidth
954 rotation: isVertical ? 180 : 90975 rotation: isVertical ? 180 : 90
955 //NOTE: Qt.resolvedUrl was removed because it does not seem to be needed and 976 //NOTE: Qt.resolvedUrl was removed because it does not seem to be needed and
956 //the QML profiler showed it's relatively expensive977 //the QML profiler showed it's relatively expensive
957 source: visible ? "../artwork/toolkit_scrollbar-stepper.svg" : ""978 source: visible ? "../artwork/toolkit_scrollbar-stepper.svg" : ""
958 asynchronous: true979 asynchronous: true
@@ -998,7 +1019,7 @@
998 anchors.centerIn: parent1019 anchors.centerIn: parent
999 width: __stepperAssetWidth1020 width: __stepperAssetWidth
1000 rotation: isVertical ? 0 : -901021 rotation: isVertical ? 0 : -90
1001 //NOTE: Qt.resolvedUrl was removed because it does not seem to be needed and 1022 //NOTE: Qt.resolvedUrl was removed because it does not seem to be needed and
1002 //the QML profiler showed it's relatively expensive1023 //the QML profiler showed it's relatively expensive
1003 source: visible ? "../artwork/toolkit_scrollbar-stepper.svg" : ""1024 source: visible ? "../artwork/toolkit_scrollbar-stepper.svg" : ""
1004 asynchronous: true1025 asynchronous: true
10051026
=== added file 'src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollingActionBarStyle.qml'
--- src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollingActionBarStyle.qml 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollingActionBarStyle.qml 2016-09-03 13:06:01 +0000
@@ -0,0 +1,203 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16import QtQuick 2.4
17import Ubuntu.Components 1.3
18import Ubuntu.Components.Styles 1.3 as Style
19
20Style.ActionBarStyle {
21 id: actionBarStyle
22 implicitHeight: units.gu(5)
23
24 clip: true // avoid showing the icons that are scrolled out of the view.
25 backgroundColor: theme.palette.normal.background
26 buttons {
27 foregroundColor: theme.palette.normal.backgroundText
28 pressedForegroundColor: buttons.foregroundColor
29 disabledForegroundColor: theme.palette.disabled.backgroundText
30 backgroundColor: "transparent" // background is already colored
31 pressedBackgroundColor: theme.palette.highlighted.background
32 disabledBackgroundColor: buttons.backgroundColor
33 }
34
35 property QtObject scrollButtons: Style.ActionItemProperties {
36 foregroundColor: actionBarStyle.buttons.foregroundColor
37 pressedForegroundColor: actionBarStyle.buttons.pressedForegroundColor
38 backgroundColor: actionBarStyle.backgroundColor // must be opaque to hide the icon buttons
39 pressedBackgroundColor: actionBarStyle.buttons.pressedBackgroundColor
40 property real width: units.gu(4)
41 property int fadeDuration: UbuntuAnimation.FastDuration
42 }
43
44 /*!
45 The default action delegate if the styled item does
46 not provide a delegate.
47 */
48 // FIXME: This ListItem { AbstractButton { } } construction can be avoided
49 // when StyledItem supports cursor keys navigation, see bug #1573616.
50 // FIXME: For the first and last item in the list, it is possible to move
51 // the focus inside the ListItem to the AbstractButton, see bug #1590005.
52 // FIXME: Focus can go on disabled item. See bug #1611327.
53 defaultDelegate: ListItem {
54 width: units.gu(4)
55 height: actionBarStyle.height
56 enabled: modelData.enabled
57 objectName: modelData.objectName + "_button"
58 AbstractButton {
59 id: button
60 anchors.fill: parent
61 style: IconButtonStyle {
62 foregroundColor: button.pressed ?
63 actionBarStyle.buttons.pressedForegroundColor :
64 button.enabled ?
65 actionBarStyle.buttons.foregroundColor :
66 actionBarStyle.buttons.disabledForegroundColor
67 backgroundColor: button.pressed ?
68 actionBarStyle.buttons.pressedBackgroundColor :
69 button.enabled ?
70 actionBarStyle.buttons.backgroundColor :
71 actionBarStyle.buttons.disabledBackgroundColor
72 }
73 action: modelData
74 activeFocusOnTab: false
75 }
76 divider.visible: false
77 }
78
79 Rectangle {
80 color: actionBarStyle.backgroundColor
81 id: listViewContainer
82 anchors.fill: parent
83
84 property var visibleActions: getVisibleActions(styledItem.actions)
85 function getVisibleActions(actions) {
86 var visibleActionList = [];
87 for (var i = 0; i < actions.length; i++) {
88 var action = actions[i];
89 if (action && action.hasOwnProperty("visible") && action.visible) {
90 visibleActionList.push(action);
91 }
92 }
93 return visibleActionList;
94 }
95
96 ListView {
97 id: actionsListView
98 objectName: "actions_listview"
99 anchors {
100 right: parent.right
101 top: parent.top
102 bottom: parent.bottom
103 rightMargin: scrollButtons.width
104 }
105 displayMarginBeginning: scrollButtons.width
106 displayMarginEnd: scrollButtons.width
107 leftMargin: -scrollButtons.width
108 rightMargin: -scrollButtons.width
109 width: listViewContainer.width - 2*scrollButtons.width
110 layoutDirection: Qt.RightToLeft
111
112 orientation: ListView.Horizontal
113 boundsBehavior: Flickable.StopAtBounds
114 delegate: styledItem.delegate
115 model: listViewContainer.visibleActions
116
117 // This gives the correct behavior when scrollButtons.width is
118 // larger/smaller/equal compared to the width of the delegate.
119 onCurrentIndexChanged: positionViewAtIndex(currentIndex, ListView.Contain)
120
121 SmoothedAnimation {
122 objectName: "actions_scroll_animation"
123 id: contentXAnim
124 target: actionsListView
125 property: "contentX"
126 duration: UbuntuAnimation.FastDuration
127 }
128
129 // direction == 1 to show more icons on the left
130 // direction == -1 to show more icons on the right
131 function scroll(direction) {
132 if (contentXAnim.running) contentXAnim.stop();
133 var newContentX = actionsListView.contentX - (actionsListView.width * direction);
134 contentXAnim.from = actionsListView.contentX;
135 // make sure we don't overshoot bounds
136 contentXAnim.to = MathUtils.clamp(
137 newContentX,
138 originX + scrollButtons.width,
139 actionsListView.originX + actionsListView.contentWidth
140 - actionsListView.width - scrollButtons.width);
141 contentXAnim.start();
142 }
143 }
144
145 Component {
146 id: scrollButtonComponent
147 AbstractButton {
148 id: scrollButton
149 width: actionBarStyle.scrollButtons.width
150 enabled: opacity === 1.0
151 onClicked: actionsListView.scroll(scrollDirection)
152 opacity: buttonOpacity
153 objectName: buttonName
154 Behavior on opacity {
155 UbuntuNumberAnimation {
156 duration: actionBarStyle.scrollButtons.fadeDuration
157 }
158 }
159 Rectangle {
160 anchors.fill: parent
161 color: scrollButton.pressed ? actionBarStyle.scrollButtons.pressedBackgroundColor
162 : actionBarStyle.scrollButtons.backgroundColor
163 }
164 Icon {
165 // FIXME: Use new theme icon from
166 // https://code.launchpad.net/~tiheum/ubuntu-themes/toolkit-arrows/+merge/298609
167 // after it lands in overlay and archive.
168 anchors.centerIn: parent
169 width: units.gu(1)
170 height: units.gu(1)
171 rotation: iconRotation
172 name: "chevron"
173 color: scrollButton.pressed ? actionBarStyle.scrollButtons.pressedForegroundColor
174 : actionBarStyle.scrollButtons.foregroundColor
175 }
176 }
177 }
178 Loader {
179 anchors {
180 left: parent.left
181 top: parent.top
182 bottom: parent.bottom
183 }
184 sourceComponent: scrollButtonComponent
185 property int iconRotation: 180
186 property real buttonOpacity: actionsListView.atXBeginning ? 0.0 : 1.0
187 property int scrollDirection: 1
188 property string buttonName: "leading_scroll_button"
189 }
190 Loader {
191 anchors {
192 right: parent.right
193 top: parent.top
194 bottom: parent.bottom
195 }
196 sourceComponent: scrollButtonComponent
197 property int iconRotation: 0
198 property real buttonOpacity: actionsListView.atXEnd ? 0.0 : 1.0
199 property int scrollDirection: -1
200 property string buttonName: "trailing_scroll_button"
201 }
202 }
203}
0204
=== modified file 'src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro'
--- src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro 2016-04-21 11:34:55 +0000
+++ src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro 2016-09-03 13:06:01 +0000
@@ -103,6 +103,7 @@
103 1.3/ProgressionVisualStyle.qml \103 1.3/ProgressionVisualStyle.qml \
104 1.3/PullToRefreshStyle.qml \104 1.3/PullToRefreshStyle.qml \
105 1.3/ScrollbarStyle.qml \105 1.3/ScrollbarStyle.qml \
106 1.3/ScrollingActionBarStyle.qml \
106 1.3/SectionsStyle.qml \107 1.3/SectionsStyle.qml \
107 1.3/SheetForegroundStyle.qml \108 1.3/SheetForegroundStyle.qml \
108 1.3/SliderStyle.qml \109 1.3/SliderStyle.qml \
109110
=== modified file 'src/Ubuntu/Components/Themes/Ambiance/qmldir'
--- src/Ubuntu/Components/Themes/Ambiance/qmldir 2016-02-19 11:18:51 +0000
+++ src/Ubuntu/Components/Themes/Ambiance/qmldir 2016-09-03 13:06:01 +0000
@@ -59,6 +59,7 @@
59#version 1.359#version 1.3
60AmbianceNormal 1.3 ./1.3/AmbianceNormal.qml60AmbianceNormal 1.3 ./1.3/AmbianceNormal.qml
61ActionBarStyle 1.3 ./1.3/ActionBarStyle.qml61ActionBarStyle 1.3 ./1.3/ActionBarStyle.qml
62ScrollingActionBarStyle 1.3 ./1.3/ScrollingActionBarStyle.qml
62MainViewStyle 1.3 ./1.3/MainViewStyle.qml63MainViewStyle 1.3 ./1.3/MainViewStyle.qml
63ListItemOptionSelector 1.3 ./1.3/ListItemOptionSelector.qml64ListItemOptionSelector 1.3 ./1.3/ListItemOptionSelector.qml
64OptionSelectorStyle 1.3 ./1.3/OptionSelectorStyle.qml65OptionSelectorStyle 1.3 ./1.3/OptionSelectorStyle.qml
6566
=== modified file 'src/Ubuntu/Components/qmldir'
--- src/Ubuntu/Components/qmldir 2016-07-29 13:21:05 +0000
+++ src/Ubuntu/Components/qmldir 2016-09-03 13:06:01 +0000
@@ -96,7 +96,6 @@
96#################################################96#################################################
97#version 1.397#version 1.3
98ActionBar 1.3 1.3/ActionBar.qml98ActionBar 1.3 1.3/ActionBar.qml
99ActionList 1.3 1.3/ActionList.qml
100AdaptivePageLayout 1.3 1.3/AdaptivePageLayout.qml99AdaptivePageLayout 1.3 1.3/AdaptivePageLayout.qml
101PageColumnsLayout 1.3 1.3/PageColumnsLayout.qml100PageColumnsLayout 1.3 1.3/PageColumnsLayout.qml
102PageColumn 1.3 1.3/PageColumn.qml101PageColumn 1.3 1.3/PageColumn.qml
103102
=== modified file 'src/Ubuntu/Test/UbuntuTestCase13.qml'
--- src/Ubuntu/Test/UbuntuTestCase13.qml 2016-03-15 13:17:53 +0000
+++ src/Ubuntu/Test/UbuntuTestCase13.qml 2016-09-03 13:06:01 +0000
@@ -15,7 +15,7 @@
15 */15 */
1616
17import QtQuick 2.417import QtQuick 2.4
18import QtTest 1.018import QtTest 1.1
19import Ubuntu.Components 1.319import Ubuntu.Components 1.3
2020
21/*!21/*!
2222
=== modified file 'src/Ubuntu/UbuntuMetrics/applicationmonitor.cpp'
--- src/Ubuntu/UbuntuMetrics/applicationmonitor.cpp 2016-08-06 00:54:30 +0000
+++ src/Ubuntu/UbuntuMetrics/applicationmonitor.cpp 2016-09-03 13:06:01 +0000
@@ -567,7 +567,9 @@
567 event.generic.id = id;567 event.generic.id = id;
568 // We don't bother fixing up non null-terminated string, just potential568 // We don't bother fixing up non null-terminated string, just potential
569 // overflows.569 // overflows.
570 event.generic.stringSize = qMin(size, UMGenericEvent::maxStringSize);570 // Note: GCC5 comoiler/linker cannot find UMGenericEvent::maxStringSize
571 // if used in qMin(); force type to satisfy it
572 event.generic.stringSize = qMin(size, quint32(UMGenericEvent::maxStringSize));
571 memcpy(event.generic.string, string, event.generic.stringSize);573 memcpy(event.generic.string, string, event.generic.stringSize);
572 d->m_loggingThread->push(&event);574 d->m_loggingThread->push(&event);
573 return true;575 return true;
574576
=== modified file 'src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro'
--- src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro 2016-08-04 17:25:09 +0000
+++ src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro 2016-09-03 13:06:01 +0000
@@ -44,7 +44,15 @@
44 mousetouchadaptor_p.h \44 mousetouchadaptor_p.h \
45 mousetouchadaptor_p_p.h \45 mousetouchadaptor_p_p.h \
46 propertychange_p.h \46 propertychange_p.h \
47 ubuntutoolkitmodule.h47 ubuntutoolkitmodule.h \
48 splitview_p.h \
49 splitview_p_p.h \
50 privates/splitviewhandler_p_p.h \
51 menu_p_p.h \
52 menubar_p_p.h \
53 menu_p.h \
54 menubar_p.h \
55 menugroup_p.h
4856
49SOURCES += \ 57SOURCES += \
50 colorutils.cpp \58 colorutils.cpp \
@@ -52,7 +60,13 @@
52 asyncloader.cpp \60 asyncloader.cpp \
53 mousetouchadaptor.cpp \61 mousetouchadaptor.cpp \
54 propertychange.cpp \62 propertychange.cpp \
55 ubuntutoolkitmodule.cpp63 ubuntutoolkitmodule.cpp \
64 splitview.cpp \
65 privates/splitviewhandler.cpp \
66 splitviewlayout.cpp \
67 menu.cpp \
68 menubar.cpp \
69 menugroup.cpp
5670
57HEADERS += \71HEADERS += \
58 uctheme_p.h \72 uctheme_p.h \
@@ -149,7 +163,9 @@
149 privates/appheaderbase_p.h \163 privates/appheaderbase_p.h \
150 label_p.h \164 label_p.h \
151 ucbottomedgeregion_p_p.h \165 ucbottomedgeregion_p_p.h \
152 privates/ucscrollbarutils_p.h166 privates/ucscrollbarutils_p.h \
167 actionlist_p.h \
168 exclusivegroup_p.h
153169
154SOURCES += \170SOURCES += \
155 uctheme.cpp \171 uctheme.cpp \
@@ -226,7 +242,9 @@
226 privates/ucpagewrapper.cpp \242 privates/ucpagewrapper.cpp \
227 privates/ucpagewrapperincubator.cpp \243 privates/ucpagewrapperincubator.cpp \
228 privates/appheaderbase.cpp \244 privates/appheaderbase.cpp \
229 privates/ucscrollbarutils.cpp245 privates/ucscrollbarutils.cpp \
246 actionlist.cpp \
247 exclusivegroup.cpp
230248
231# adapters249# adapters
232SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp250SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp
233251
=== added file 'src/Ubuntu/UbuntuToolkit/actionlist.cpp'
--- src/Ubuntu/UbuntuToolkit/actionlist.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/actionlist.cpp 2016-09-03 13:06:01 +0000
@@ -0,0 +1,158 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "actionlist_p.h"
18#include "ucaction_p.h"
19
20UT_NAMESPACE_BEGIN
21
22/*!
23 * \qmltype ActionList
24 * \inqmlmodule Ubuntu.Components
25 * \ingroup ubuntu
26 * \brief List of \l Action items
27 * An ActionList provies a way of grouping actions together.
28 * \qml
29 * ActionList {
30 * Action {
31 * id: action1
32 * }
33 * Action {
34 * id: action2
35 * }
36 * }
37 * \endqml
38 */
39/*!
40 * \qmlsignal ActionList::added(Action action)
41 * \since Ubuntu.Components 1.3
42 * Signal called when an action is added to the list
43 */
44/*!
45 * \qmlsignal ActionList::removed(Action action)
46 * \since Ubuntu.Components 1.3
47 * Signal called when an action is removed from the list
48 */
49ActionList::ActionList(QObject *parent)
50 : QObject(parent)
51{
52}
53
54/*!
55 * \qmlmethod ActionList::addAction(Action action)
56 * \since Ubuntu.Components 1.3
57 * Adds an Action to the list programatically.
58 * \qml
59 * Item {
60 * Instantiator {
61 * model: 4
62 * onObjectAdded: actionList.addAction(object)
63 * onObjectRemoved: actionList.removeAction(object)
64 *
65 * Action {}
66 * }
67 *
68 * ActionList {
69 * id: actionList
70 * }
71 * }
72 * \endqml
73 * \sa ActionList::removeAction
74 */
75void ActionList::addAction(UCAction *action)
76{
77 if (m_actions.contains(action)) {
78 return;
79 }
80 m_actions.append(action);
81 Q_EMIT added(action);
82}
83
84/*!
85 * \qmlmethod ActionList::removeAction(Action action)
86 * \since Ubuntu.Components 1.3
87 * Removes an action from the list programatically.
88 * \sa ActionList::addAction
89 */
90void ActionList::removeAction(UCAction *action)
91{
92 if (!action) {
93 return;
94 }
95 if (m_actions.removeOne(action)) {
96 Q_EMIT removed(action);
97 }
98}
99
100/*!
101 * \qmlproperty list<Action> ActionList::actions
102 * \default
103 * List of Actions in this ActionList
104 * Note that when you set this property, the children of the ActionList will be ignored,
105 * so do not set the list and define children.
106 *
107 * The advantage of setting actions over using the children is that the same
108 * \l Action items can be used in several sets of actions.
109 */
110QQmlListProperty<UCAction> ActionList::actions()
111{
112 return QQmlListProperty<UCAction>(this, 0,
113 ActionList::append,
114 ActionList::count,
115 ActionList::at,
116 ActionList::clear);
117}
118
119const QList<UCAction*> &ActionList::list() const
120{
121 return m_actions;
122}
123
124void ActionList::append(QQmlListProperty<UCAction> *list, UCAction *action)
125{
126 ActionList *actionList = qobject_cast<ActionList*>(list->object);
127 if (actionList) {
128 actionList->addAction(action);
129 }
130}
131
132void ActionList::clear(QQmlListProperty<UCAction> *list)
133{
134 ActionList *actionList = qobject_cast<ActionList*>(list->object);
135 if (actionList) {
136 actionList->m_actions.clear();
137 }
138}
139
140UCAction* ActionList::at(QQmlListProperty<UCAction> *list, int index)
141{
142 ActionList *actionList = qobject_cast<ActionList*>(list->object);
143 if (actionList) {
144 return actionList->m_actions.value(index, nullptr);
145 }
146 return Q_NULLPTR;
147}
148
149int ActionList::count(QQmlListProperty<UCAction> *list)
150{
151 ActionList *actionList = qobject_cast<ActionList*>(list->object);
152 if (actionList) {
153 return actionList->m_actions.count();
154 }
155 return 0;
156}
157
158UT_NAMESPACE_END
0159
=== added file 'src/Ubuntu/UbuntuToolkit/actionlist_p.h'
--- src/Ubuntu/UbuntuToolkit/actionlist_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/actionlist_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,58 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef ACTIONLIST_H
18#define ACTIONLIST_H
19
20#include <QObject>
21#include <QtQml/QQmlListProperty>
22#include "ubuntutoolkitglobal.h"
23
24UT_NAMESPACE_BEGIN
25
26class UCAction;
27class UBUNTUTOOLKIT_EXPORT ActionList : public QObject
28{
29 Q_OBJECT
30 Q_PROPERTY(QQmlListProperty<UT_PREPEND_NAMESPACE(UCAction)> actions READ actions)
31 Q_CLASSINFO("DefaultProperty", "actions")
32public:
33 explicit ActionList(QObject *parent = 0);
34
35 QQmlListProperty<UCAction> actions();
36
37 const QList<UCAction*> &list() const;
38
39public Q_SLOTS:
40 void addAction(UT_PREPEND_NAMESPACE(UCAction) *action);
41 void removeAction(UT_PREPEND_NAMESPACE(UCAction) *action);
42
43Q_SIGNALS:
44 void added(UCAction *action);
45 void removed(UCAction *action);
46
47protected:
48 QList<UCAction*> m_actions;
49
50 static void append(QQmlListProperty<UCAction> *list, UCAction *action);
51 static void clear(QQmlListProperty<UCAction> *list);
52 static UCAction* at(QQmlListProperty<UCAction> *list, int index);
53 static int count(QQmlListProperty<UCAction> *list);
54};
55
56UT_NAMESPACE_END
57
58#endif // ACTIONLIST_H
059
=== added file 'src/Ubuntu/UbuntuToolkit/exclusivegroup.cpp'
--- src/Ubuntu/UbuntuToolkit/exclusivegroup.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/exclusivegroup.cpp 2016-09-03 13:06:01 +0000
@@ -0,0 +1,168 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include "exclusivegroup_p.h"
19#include "ucaction_p.h"
20
21#include <QSignalMapper>
22
23#define CHECKED_PROPERTY "checked"
24
25UT_NAMESPACE_BEGIN
26
27static const char *checkableSignals[] = {
28 "toggled(bool)",
29 0
30};
31
32static bool isChecked(const QObject *o)
33{
34 if (!o) return false;
35 QVariant checkedVariant = o->property(CHECKED_PROPERTY);
36 return checkedVariant.isValid() && checkedVariant.toBool();
37}
38
39/*!
40 * \qmltype ExclusiveGroup
41 * \inqmlmodule Ubuntu.Components
42 * \since Ubuntu.Components 1.3
43 * \ingroup ubuntu
44 * \inherits ActionList
45 * \brief ExclusiveGroup provides a way to declare several checkable controls as mutually exclusive.
46 *
47 * The ExclusiveGroup will only allow a single object to have it's checkable property set to "true"
48 * at any one time. The exclusive group accepts child Actions, but objects other than Actions can be
49 * used by using the \l bindCheckable function as long as they support one of the required signals,
50 * and a "checked" property.
51 * \qml
52 * ExclusiveGroup {
53 * Action {
54 * parameterType: Action.Bool
55 * state: true
56 * }
57 * Action {
58 * parameterType: Action.Bool
59 * state: false
60 * }
61 * }
62 * \endqml
63 */
64ExclusiveGroup::ExclusiveGroup(QObject *parent)
65 : ActionList(parent)
66 , m_signalMapper(new QSignalMapper(this))
67 , m_entranceGuard(false)
68{
69 connect(this, &ActionList::added, this, &ExclusiveGroup::onActionAdded);
70 connect(this, &ActionList::removed, this, &ExclusiveGroup::onActionRemoved);
71
72 int index = m_signalMapper->metaObject()->indexOfMethod("map()");
73 m_updateCurrentMethod = m_signalMapper->metaObject()->method(index);
74 connect(m_signalMapper, static_cast<void(QSignalMapper::*)(QObject *)>(&QSignalMapper::mapped), this, [this](QObject *object) {
75 if (isChecked(object)) {
76 setCurrent(object);
77 }
78 });
79}
80
81void ExclusiveGroup::onActionAdded(UCAction *action)
82{
83 action->setExclusiveGroup(this);
84}
85
86void ExclusiveGroup::onActionRemoved(UCAction *action)
87{
88 action->setExclusiveGroup(nullptr);
89}
90
91/*!
92 * \qmlproperty Action ExclusiveGroup::current
93 * Returns the currently checked action
94 */
95void ExclusiveGroup::setCurrent(QObject *object)
96{
97 if (m_current == object)
98 return;
99
100 if (m_current)
101 m_current->setProperty(CHECKED_PROPERTY, QVariant(false));
102 m_current = object;
103 if (m_current)
104 m_current->setProperty(CHECKED_PROPERTY, QVariant(true));
105 Q_EMIT currentChanged();
106}
107
108QObject *ExclusiveGroup::current() const
109{
110 return m_current.data();
111}
112
113/*!
114 * \qmlmethod void ExclusiveGroup::bindCheckable(object object)
115 * Explicitly bind an objects checkability to this exclusive group.
116 * \note This only works with objects which support the following signals signals:
117 * \list
118 * \li \b toggled(bool)
119 * \endlist
120 * \qml
121 * Item {
122 * ExclusiveGroup {
123 * id: exclusiveGroup
124 * }
125 * Instantiator {
126 * model: 4
127 * onObjectAdded: exclusiveGroup.bindCheckable(object)
128 * onObjectRemoved: exclusiveGroup.unbindCheckable(object)
129 *
130 * Action {
131 * checkable: true
132 * }
133 * }
134 * }
135 * \endqml
136 * \sa ExclusiveGroup::unbindCheckable
137 */
138void ExclusiveGroup::bindCheckable(QObject *object)
139{
140 for (const char **signalName = checkableSignals; *signalName; signalName++) {
141 int signalIndex = object->metaObject()->indexOfSignal(*signalName);
142 if (signalIndex != -1) {
143 QMetaMethod signalMethod = object->metaObject()->method(signalIndex);
144 connect(object, signalMethod, m_signalMapper, m_updateCurrentMethod, Qt::UniqueConnection);
145 m_signalMapper->setMapping(object, object);
146 connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unbindCheckable(QObject*)), Qt::UniqueConnection);
147 if (!m_current && isChecked(object))
148 setCurrent(object);
149 break;
150 }
151 }
152}
153
154/*!
155 * \qmlmethod void ExclusiveGroup::unbindCheckable(object object)
156 * Explicitly unbind an objects checkability from this exclusive group.
157 * \sa ExclusiveGroup::bindCheckable
158 */
159void ExclusiveGroup::unbindCheckable(QObject *object)
160{
161 if (m_current == object)
162 setCurrent(0);
163
164 disconnect(object, 0, m_signalMapper, 0);
165 disconnect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unbindCheckable(QObject*)));
166}
167
168UT_NAMESPACE_END
0169
=== added file 'src/Ubuntu/UbuntuToolkit/exclusivegroup_p.h'
--- src/Ubuntu/UbuntuToolkit/exclusivegroup_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/exclusivegroup_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,62 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef EXCLUSIVEGROUP_H
19#define EXCLUSIVEGROUP_H
20
21#include "actionlist_p.h"
22#include "ubuntutoolkitglobal.h"
23
24#include <QMetaMethod>
25#include <QPointer>
26
27class QSignalMapper;
28
29UT_NAMESPACE_BEGIN
30
31class UBUNTUTOOLKIT_EXPORT ExclusiveGroup : public ActionList
32{
33 Q_OBJECT
34 Q_PROPERTY(QObject* current READ current NOTIFY currentChanged)
35
36public:
37 explicit ExclusiveGroup(QObject *parent = 0);
38
39 QObject* current() const;
40
41 Q_INVOKABLE void bindCheckable(QObject* object);
42 Q_INVOKABLE void unbindCheckable(QObject* object);
43
44Q_SIGNALS:
45 void currentChanged();
46
47protected Q_SLOTS:
48 void onActionAdded(UCAction* action);
49 void onActionRemoved(UCAction* action);
50
51private:
52 void setCurrent(QObject* action);
53
54 QSignalMapper* m_signalMapper;
55 QPointer<QObject> m_current;
56 QMetaMethod m_updateCurrentMethod;
57 bool m_entranceGuard;
58};
59
60UT_NAMESPACE_END
61
62#endif // EXCLUSIVEGROUP_H
063
=== added file 'src/Ubuntu/UbuntuToolkit/menu.cpp'
--- src/Ubuntu/UbuntuToolkit/menu.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/menu.cpp 2016-09-03 13:06:01 +0000
@@ -0,0 +1,671 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "menu_p.h"
18#include "menu_p_p.h"
19#include "menubar_p.h"
20#include "actionlist_p.h"
21#include "menugroup_p.h"
22
23// Qt
24#include <QPointer>
25#include <QQuickItem>
26#include <QLoggingCategory>
27#include <QtGui/qpa/qplatformtheme.h>
28#include <QtGui/qpa/qplatformmenu.h>
29#include <private/qguiapplication_p.h>
30#include <private/qquickitem_p.h>
31
32#include <functional>
33
34Q_LOGGING_CATEGORY(ucMenu, "ubuntu.components.Menu", QtMsgType::QtWarningMsg)
35
36UT_NAMESPACE_BEGIN
37
38namespace {
39
40QWindow* findWindowForObject(QObject* object)
41{
42 QObject* window = object;
43 while (window && !window->isWindowType()) {
44 window = window->parent();
45 if (QQuickItem* item = qobject_cast<QQuickItem*>(window)) {
46 window = item->window();
47 }
48 }
49 return qobject_cast<QWindow*>(window);
50}
51
52// recursively get the all the object from the menu group which are not lists or groups.
53QObjectList getActionsFromMenuGroup(MenuGroup* menuGroup) {
54
55 QObjectList objectList;
56
57 Q_FOREACH(QObject* data, menuGroup->list()) {
58
59 if (auto actionList = qobject_cast<ActionList*>(data)) {
60 Q_FOREACH(UCAction* action, actionList->list()) {
61 objectList << action;
62 }
63 } else if (auto subMenuGroup = qobject_cast<MenuGroup*>(data)) {
64 objectList << getActionsFromMenuGroup(subMenuGroup);
65 } else {
66 objectList << data;
67 }
68 }
69 return objectList;
70}
71
72// recursively get the first object from the menu group which is not a list or a group.
73QObject* getFirstObject(MenuGroup* menuGroup) {
74
75 Q_FOREACH(QObject* data, menuGroup->list()) {
76
77 if (auto subMenuGroup = qobject_cast<MenuGroup*>(data)) {
78 QObject* object = getFirstObject(subMenuGroup);
79 if (object) { return object; }
80 } else if (auto actionList = qobject_cast<ActionList*>(data)) {
81 return actionList->list().count() > 0 ? actionList->list()[0] : 0;
82 } else {
83 return data;
84 }
85 }
86 return Q_NULLPTR;
87}
88
89}
90
91MenuPrivate::MenuPrivate(Menu *qq)
92 : q_ptr(qq)
93 , m_platformMenu(QGuiApplicationPrivate::platformTheme()->createPlatformMenu())
94{
95}
96
97MenuPrivate::~MenuPrivate()
98{
99 qDeleteAll(m_platformItems);
100 m_platformItems.clear();
101
102 delete m_platformMenu;
103 m_platformMenu = Q_NULLPTR;
104}
105
106void MenuPrivate::insertObject(int index, QObject *o)
107{
108 Q_Q(Menu);
109 if (!o) return;
110 qCDebug(ucMenu).nospace() << "Menu::insertObject(index="<< index << ", object=" << o << ")";
111
112 if (!m_platformMenu) {
113 m_data.insert(m_data.count() > index ? index : m_data.count(), o);
114 return;
115 }
116
117 // If the menus contains lists or groups, we need to alter the insertion index to account for them.
118 int actualIndex = 0;
119 bool insertSeparator = false;
120 for (int i = 0; i < index && i < m_data.count(); i++) {
121 QObject* data = m_data[i];
122
123 int dataObjectCount = 0;
124 if (auto menuGroup = qobject_cast<MenuGroup*>(data)) {
125 dataObjectCount = getActionsFromMenuGroup(menuGroup).count();
126 } else if (auto list = qobject_cast<ActionList*>(data)) {
127 dataObjectCount = list->list().count();
128 } else {
129 dataObjectCount = 1;
130 }
131 actualIndex += dataObjectCount;
132 // insert a separator before the new item if there are previous items.
133 insertSeparator |= dataObjectCount > 0;
134
135 // account for item separators if it's not the last data item.
136 actualIndex += dataObjectCount > 0 && (i+1 < index && i+1 < m_data.count()) ? 1: 0;
137 }
138
139 // need to make sure the item after the insertion index has a separator
140 if (index < m_data.count()) {
141 QObject* data = m_data.at(index);
142 QObject* objectToSeparate(Q_NULLPTR);
143
144 if (auto menuGroup = qobject_cast<MenuGroup*>(data)) {
145 objectToSeparate = getFirstObject(menuGroup);
146 } else if (auto actionList = qobject_cast<ActionList*>(data)) {
147 objectToSeparate = actionList->list().count() > 0 ? actionList->list()[0] : 0;
148 } else {
149 objectToSeparate = data;
150 }
151
152 if (objectToSeparate && m_platformItems.contains(objectToSeparate)) {
153 m_platformItems.value(objectToSeparate)->setSeparator();
154 }
155 }
156
157 m_data.insert(m_data.count() > index ? index : m_data.count(), o);
158
159 // if an object changes, we need to remove and re-add it.
160 std::function<void()> refreshObject = [o, this]() {
161 int index = m_data.indexOf(o);
162 if (index >= 0) {
163 removeObject(o);
164 insertObject(index, o);
165 }
166 };
167
168 // Get All the menu item objects
169 QObjectList objects;
170 if (auto menuGroup = qobject_cast<MenuGroup*>(o)) {
171 Q_FOREACH(QObject* menuGroupObject, getActionsFromMenuGroup(menuGroup)) {
172 objects << menuGroupObject;
173 }
174 // connect to content changes
175 QObject::connect(menuGroup, &MenuGroup::changed, q, refreshObject);
176 } else if (auto actionList = qobject_cast<ActionList*>(o)) {
177 Q_FOREACH(UCAction* action, actionList->list()) {
178 objects << action;
179 }
180 // connect to content changes
181 QObject::connect(actionList, &ActionList::added, q, refreshObject);
182 QObject::connect(actionList, &ActionList::removed, q, refreshObject);
183 } else {
184 objects << o;
185 }
186
187 Q_FOREACH(QObject* platformObject, objects) {
188 // add to platform
189 auto platformWrapper = new PlatformItemWrapper(platformObject, q);
190 platformWrapper->insert(actualIndex++, insertSeparator);
191 if (platformWrapper->hasSeparator()) { // we also inserted an separator, need to increment for next position.
192 actualIndex++;
193 }
194 insertSeparator = false;
195 m_platformItems[platformObject] = platformWrapper;
196 // map the inserted item with the object which sources the platformItem info.
197 if (!m_dataPlatformObjectMap.contains(o, platformObject)) {
198 m_dataPlatformObjectMap.insertMulti(o, platformObject);
199 }
200
201 QObject::connect(platformObject, &QObject::destroyed, q, [o, this](QObject* platformObject) {
202 m_dataPlatformObjectMap.remove(o, platformObject);
203
204 if (m_platformItems.contains(platformObject)) {
205 PlatformItemWrapper* wrapper = m_platformItems.take(platformObject);
206 wrapper->remove();
207 delete wrapper;
208 }
209 });
210 }
211}
212
213void MenuPrivate::removeObject(QObject *o)
214{
215 Q_Q(Menu);
216 m_data.removeOne(o);
217 qCDebug(ucMenu).nospace() << "Menu::removeObject(" << o << ")";
218
219 if (m_platformMenu) {
220 if (auto menuGroup = qobject_cast<MenuGroup*>(o)) {
221 // disconnect from content changes
222 QObject::disconnect(menuGroup, &MenuGroup::changed, q, 0);
223 } else if (ActionList* actionList = qobject_cast<ActionList*>(o)) {
224 // disconnect from content changes
225 QObject::disconnect(actionList, &ActionList::added, q, 0);
226 QObject::disconnect(actionList, &ActionList::removed, q, 0);
227 }
228
229 QList<QObject*> platformObjects = m_dataPlatformObjectMap.values(o);
230 m_dataPlatformObjectMap.remove(o);
231
232 Q_FOREACH(QObject* platformObject, platformObjects) {
233 // remove from platform.
234 if (m_platformItems.contains(platformObject)) {
235 PlatformItemWrapper* wrapper = m_platformItems.take(platformObject);
236 wrapper->remove();
237 delete wrapper;
238 }
239 }
240 }
241}
242
243void MenuPrivate::_q_updateEnabled()
244{
245 Q_Q(Menu);
246
247 bool isEnabled = q->isEnabled();
248 if (m_platformMenu) { m_platformMenu->setEnabled(isEnabled); }
249}
250
251void MenuPrivate::_q_updateText()
252{
253 Q_Q(Menu);
254
255 QString text = q->text();
256 if (m_platformMenu) { m_platformMenu->setText(text); }
257}
258
259void MenuPrivate::_q_updateIcon()
260{
261 Q_Q(Menu);
262
263 QIcon icon;
264 if (!q->iconSource().isEmpty()) {
265 icon = QIcon(q->iconSource().path());
266 } else if (!q->iconName().isEmpty()) {
267 icon = QIcon::fromTheme(q->iconName());
268 }
269
270 if (m_platformMenu) { m_platformMenu->setIcon(icon); }
271}
272
273void MenuPrivate::_q_updateVisible()
274{
275 Q_Q(Menu);
276
277 bool visible = q->visible();
278 if (m_platformMenu) { m_platformMenu->setVisible(visible); }
279}
280
281void MenuPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
282{
283 Menu *q = qobject_cast<Menu *>(prop->object);
284 q->appendObject(o);
285}
286
287int MenuPrivate::data_count(QQmlListProperty<QObject> *prop)
288{
289 MenuPrivate *p = static_cast<MenuPrivate *>(prop->data);
290 return p->m_data.count();
291}
292
293QObject *MenuPrivate::data_at(QQmlListProperty<QObject> *prop, int index)
294{
295 MenuPrivate *p = static_cast<MenuPrivate *>(prop->data);
296 return p->m_data.value(index, Q_NULLPTR);
297}
298
299void MenuPrivate::data_clear(QQmlListProperty<QObject> *prop)
300{
301 MenuPrivate *p = static_cast<MenuPrivate *>(prop->data);
302 p->m_data.clear();
303}
304
305/*!
306 * \qmltype Menu
307 * \inqmlmodule Ubuntu.Components
308 * \ingroup ubuntu
309 * \brief Menu defines a context menu or submenu structure of a MenuBar
310 *
311 * Example usage:
312 * \qml
313 * import QtQuick 2.4
314 * import Ubuntu.Components 1.3
315 * Menu {
316 * text: "&File"
317 *
318 * MenuGroup {
319 * Action {
320 * text: "&New"
321 * shortcut: "Ctrl+N"
322 * }
323 *
324 * Action {
325 * text: "&Open"
326 * shortcut: "Ctrl+O"
327 * }
328 * }
329 *
330 * Menu {
331 * text: "Recent Files"
332 *
333 * ActionList {
334 * Action { text: "1.txt" }
335 * Action { text: "2.txt" }
336 * Action { text: "3.txt" }
337 * }
338 * }
339 *
340 * Action {
341 * action: Action {
342 * text: "E&xit"
343 * shortcut: "Ctrl+X"
344 * }
345 * }
346 * }
347 * \endqml
348 */
349Menu::Menu(QObject *parent)
350 : UCAction(parent)
351 , d_ptr(new MenuPrivate(this))
352{
353 Q_D(Menu);
354
355 connect(this, SIGNAL(enabledChanged()), this, SLOT(_q_updateEnabled()));
356 connect(this, SIGNAL(textChanged()), this, SLOT(_q_updateText()));
357 connect(this, SIGNAL(iconNameChanged()), this, SLOT(_q_updateIcon()));
358 connect(this, SIGNAL(iconSourceChanged()), this, SLOT(_q_updateIcon()));
359 connect(this, SIGNAL(visibleChanged()), this, SLOT(_q_updateVisible()));
360}
361
362Menu::~Menu()
363{
364}
365
366/*!
367 * \qmlproperty list<Object> Menu::data
368 * \default
369 * List of objects representing menu items within the menu.
370 *
371 * Currently supports Menu, Action, AcionList & MenuGroup objects.
372 * \note Item object which do not support platformItem will not be exported for native menus.
373 */
374QQmlListProperty<QObject> Menu::data()
375{
376 Q_D(Menu);
377 return QQmlListProperty<QObject>(this, d,
378 &MenuPrivate::data_append,
379 &MenuPrivate::data_count,
380 &MenuPrivate::data_at,
381 &MenuPrivate::data_clear);
382}
383
384/*!
385 * \qmlmethod Menu::appendObject(object o)
386 * Add a object tto the menu
387 */
388void Menu::appendObject(QObject *o)
389{
390 Q_D(Menu);
391
392 insertObject(d->m_data.count(), o);
393}
394
395/*!
396 * \qmlmethod Menu::insertObject(int index, object o)
397 * Inserts an item at the index in the menu.
398 *
399 * Currently supports Menu, Action, AcionList & MenuGroup objects.
400 * \note Item object which do not support platformItem will not be exported for native menus.
401 */
402void Menu::insertObject(int index, QObject *o)
403{
404 Q_D(Menu);
405 d->insertObject(index, o);
406}
407
408/*!
409 * \qmlmethod Menu::removeObject(object o)
410 * Removes the item from the menu.
411 */
412void Menu::removeObject(QObject *o)
413{
414 Q_D(Menu);
415 qCDebug(ucMenu) << "Menu::removeObject" << o;
416
417 d->removeObject(o);
418}
419
420QPlatformMenu* Menu::platformMenu() const
421{
422 Q_D(const Menu);
423 return d->m_platformMenu;
424}
425
426/*!
427 * \qmlmethod Menu::show(point point)
428 * Show the menu popup at the given point
429 */
430void Menu::show(const QPoint &point)
431{
432 Q_D(Menu);
433 qCDebug(ucMenu, "Menu::popup(%s, point(%d,%d))", qPrintable(text()), point.x(), point.y());
434
435 if (d->m_platformMenu) {
436 d->m_platformMenu->showPopup(findWindowForObject(this), QRect(point, QSize()), Q_NULLPTR);
437 }
438}
439
440/*!
441 * \qmlmethod Menu::dismiss()
442 * Dismiss and destroy the menu popup.
443 */
444void Menu::dismiss()
445{
446 Q_D(Menu);
447 qCDebug(ucMenu, "Menu::dismiss(%s)", qPrintable(text()));
448
449 if (d->m_platformMenu) {
450 d->m_platformMenu->dismiss();
451 }
452}
453
454
455PlatformItemWrapper::PlatformItemWrapper(QObject *target, Menu* menu)
456 : QObject(menu)
457 , m_target(target)
458 , m_menu(menu)
459 , m_platformItem(menu->platformMenu() ? menu->platformMenu()->createMenuItem() : Q_NULLPTR)
460 , m_platformItemSeparator(Q_NULLPTR)
461 , m_inserted(false)
462{
463 if (Menu* menu = qobject_cast<Menu*>(m_target)) {
464 if (m_platformItem) {
465 m_platformItem->setMenu(menu->platformMenu());
466 }
467
468 connect(menu, &Menu::visibleChanged, this, &PlatformItemWrapper::updateVisible);
469 connect(menu, &Menu::textChanged, this, &PlatformItemWrapper::updateText);
470 connect(menu, &Menu::enabledChanged, this, &PlatformItemWrapper::updateEnabled);
471 connect(menu, &Menu::iconSourceChanged, this, &PlatformItemWrapper::updateIcon);
472 connect(menu, &Menu::iconNameChanged, this, &PlatformItemWrapper::updateIcon);
473
474 } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
475
476 connect(action, &UCAction::visibleChanged, this, &PlatformItemWrapper::updateVisible);
477 connect(action, &UCAction::textChanged, this, &PlatformItemWrapper::updateText);
478 connect(action, &UCAction::enabledChanged, this, &PlatformItemWrapper::updateEnabled);
479 connect(action, &UCAction::iconSourceChanged, this, &PlatformItemWrapper::updateIcon);
480 connect(action, &UCAction::iconNameChanged, this, &PlatformItemWrapper::updateIcon);
481 connect(action, &UCAction::shortcutChanged, this, &PlatformItemWrapper::updateShortcut);
482 connect(action, &UCAction::checkableChanged, this, &PlatformItemWrapper::updateCheck);
483 connect(action, &UCAction::toggled, this, &PlatformItemWrapper::updateCheck);
484
485 if (m_platformItem) {
486 // Connect to activate (with inversion for checkables)
487 connect(m_platformItem, &QPlatformMenuItem::activated, action, [action]() {
488 action->trigger();
489 });
490 }
491
492 }
493 syncPlatformItem();
494}
495
496PlatformItemWrapper::~PlatformItemWrapper()
497{
498 if (m_inserted && m_menu && m_menu->platformMenu()) {
499 m_menu->platformMenu()->removeMenuItem(m_platformItem);
500 if (m_platformItemSeparator) {
501 m_menu->platformMenu()->removeMenuItem(m_platformItemSeparator);
502 delete m_platformItemSeparator;
503 }
504 }
505 delete m_platformItem;
506}
507
508void PlatformItemWrapper::insert(int index, bool withSeparator)
509{
510 if (m_inserted) return;
511 qCDebug(ucMenu).nospace() << " PlatformItemWrapper::insert(menu=" << m_menu
512 << ", index=" << index
513 << ", object=" << m_target << ")";
514
515 auto platformMenu = m_menu->platformMenu();
516 if (!platformMenu) return;
517 if (!m_platformItem) return;
518
519 QPlatformMenuItem* before = platformMenu->menuItemAt(index);
520 platformMenu->insertMenuItem(m_platformItem, before);
521 m_inserted = true;
522
523 if (withSeparator) setSeparator();
524}
525
526void PlatformItemWrapper::remove()
527{
528 if (!m_inserted) return;
529 qCDebug(ucMenu).nospace() << " PlatformItemWrapper::remove(menu=" << m_menu
530 << ", object=" << m_target << ")";
531
532 auto platformMenu = m_menu->platformMenu();
533 if (!platformMenu) return;
534 if (!m_platformItem) return;
535
536 platformMenu->removeMenuItem(m_platformItem);
537 m_inserted = false;
538
539 if (m_platformItemSeparator) {
540 qCDebug(ucMenu).nospace() << " PlatformItemWrapper::removeSeparator(menu=" << m_menu
541 << ", object=" << m_target << ")";
542 platformMenu->removeMenuItem(m_platformItemSeparator);
543 delete m_platformItemSeparator;
544 m_platformItemSeparator = Q_NULLPTR;
545 }
546}
547
548void PlatformItemWrapper::setSeparator()
549{
550 // already created
551 if (m_platformItemSeparator) return;
552 // not inserted yet.
553 if (!m_inserted) return;
554
555 auto platformMenu = m_menu->platformMenu();
556 if (!platformMenu) return;
557
558 // insert separator before?
559 m_platformItemSeparator = platformMenu->createMenuItem();
560 if (m_platformItemSeparator) {
561 qCDebug(ucMenu).nospace() << " PlatformItemWrapper::setSeparator(menu=" << m_menu
562 << ", object=" << m_target << ")";
563
564 m_platformItemSeparator->setIsSeparator(true);
565 platformMenu->insertMenuItem(m_platformItemSeparator, m_platformItem);
566 }
567}
568
569void PlatformItemWrapper::updateVisible()
570{
571 if (Menu* menu = qobject_cast<Menu*>(m_target)) {
572 if (m_platformItem) m_platformItem->setVisible(menu->visible());
573 if (menu->platformMenu()) menu->platformMenu()->setVisible(menu->visible());
574 } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
575 if (m_platformItem) m_platformItem->setVisible(action->visible());
576 }
577}
578
579void PlatformItemWrapper::updateEnabled()
580{
581 if (Menu* menu = qobject_cast<Menu*>(m_target)) {
582 if (m_platformItem) m_platformItem->setEnabled(menu->isEnabled());
583 if (menu->platformMenu()) menu->platformMenu()->setEnabled(menu->isEnabled());
584 } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
585 if (m_platformItem) m_platformItem->setEnabled(action->isEnabled());
586 }
587}
588
589void PlatformItemWrapper::updateText()
590{
591 if (Menu* menu = qobject_cast<Menu*>(m_target)) {
592 if (m_platformItem) m_platformItem->setText(menu->text());
593 if (menu->platformMenu()) menu->platformMenu()->setText(menu->text());
594 } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
595 if (m_platformItem) m_platformItem->setText(action->text());
596 }
597}
598
599void PlatformItemWrapper::updateIcon()
600{
601 QIcon icon;
602 if (Menu* menu = qobject_cast<Menu*>(m_target)) {
603
604 if (!menu->iconSource().isEmpty()) {
605 icon = QIcon(menu->iconSource().path());
606 } else if (!menu->iconName().isEmpty()) {
607 icon = QIcon::fromTheme(menu->iconName());
608 }
609 if (menu->platformMenu()) menu->platformMenu()->setIcon(icon);
610
611 } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
612
613 if (!action->iconSource().isEmpty()) {
614 icon = QIcon(action->iconSource().path());
615 } else if (!action->iconName().isEmpty()) {
616 icon = QIcon::fromTheme(action->iconName());
617 }
618 }
619
620 if (m_platformItem) { m_platformItem->setIcon(icon); }
621}
622
623
624inline QKeySequence sequenceFromVariant(const QVariant& variant)
625{
626 if (variant.type() == QVariant::Int) {
627 return static_cast<QKeySequence::StandardKey>(variant.toInt());
628 }
629 if (variant.type() == QVariant::String) {
630 return QKeySequence::fromString(variant.toString());
631 }
632 return QKeySequence();
633}
634
635void PlatformItemWrapper::updateShortcut()
636{
637 if (!m_platformItem) return;
638
639 if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
640 m_platformItem->setShortcut(sequenceFromVariant(action->shortcut()));
641 }
642}
643
644void PlatformItemWrapper::updateCheck()
645{
646 if (!m_platformItem) return;
647
648 if (UCAction* action = qobject_cast<UCAction*>(m_target)) {
649 bool checkable = action->isCheckable();
650 m_platformItem->setCheckable(checkable);
651 m_platformItem->setChecked(checkable && action->isChecked());
652 }
653}
654
655void PlatformItemWrapper::syncPlatformItem()
656{
657 updateVisible();
658 updateEnabled();
659 updateText();
660 updateIcon();
661 updateShortcut();
662 updateCheck();
663
664 if (m_menu->platformMenu() && m_platformItem) {
665 m_menu->platformMenu()->syncMenuItem(m_platformItem);
666 }
667}
668
669UT_NAMESPACE_END
670
671#include "moc_menu_p.cpp"
0672
=== added file 'src/Ubuntu/UbuntuToolkit/menu_p.h'
--- src/Ubuntu/UbuntuToolkit/menu_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/menu_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,75 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MENU_P_H
19#define MENU_P_H
20
21#include <QQmlListProperty>
22#include <QLoggingCategory>
23#include <QPointer>
24#include <ubuntutoolkitglobal.h>
25
26#include "ucaction_p.h"
27
28Q_DECLARE_LOGGING_CATEGORY(ucMenu);
29
30class QPlatformMenu;
31class QPlatformMenuItem;
32class QQuickItem;
33
34UT_NAMESPACE_BEGIN
35
36class MenuPrivate;
37class MenuBar;
38class UCAction;
39class UBUNTUTOOLKIT_EXPORT Menu : public UCAction
40{
41 Q_OBJECT
42
43 Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL)
44 Q_CLASSINFO("DefaultProperty", "data")
45
46public:
47 explicit Menu(QObject *parent = 0);
48 ~Menu();
49
50 QQmlListProperty<QObject> data();
51
52 Q_INVOKABLE void appendObject(QObject* obj);
53 Q_INVOKABLE void insertObject(int index, QObject* obj);
54 Q_INVOKABLE void removeObject(QObject* obj);
55
56 QPlatformMenu *platformMenu() const;
57
58public Q_SLOTS:
59 void show(const QPoint& pt);
60 void dismiss();
61
62private:
63 Q_DISABLE_COPY(Menu)
64 Q_DECLARE_PRIVATE(Menu)
65 QScopedPointer<MenuPrivate> d_ptr;
66
67 Q_PRIVATE_SLOT(d_func(), void _q_updateEnabled())
68 Q_PRIVATE_SLOT(d_func(), void _q_updateText())
69 Q_PRIVATE_SLOT(d_func(), void _q_updateIcon())
70 Q_PRIVATE_SLOT(d_func(), void _q_updateVisible())
71};
72
73UT_NAMESPACE_END
74
75#endif // MENU_P_H
076
=== added file 'src/Ubuntu/UbuntuToolkit/menu_p_p.h'
--- src/Ubuntu/UbuntuToolkit/menu_p_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/menu_p_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,95 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MENU_P_P_H
19#define MENU_P_P_H
20
21#include "menu_p.h"
22#include <ubuntutoolkitglobal.h>
23
24class QObject;
25class QQmlComponent;
26
27UT_NAMESPACE_BEGIN
28
29class UCAction;
30class Menu;
31class PlatformItemWrapper;
32
33class MenuPrivate
34{
35 Q_DECLARE_PUBLIC(Menu)
36public:
37 MenuPrivate(Menu *qq);
38 virtual ~MenuPrivate();
39
40 void insertObject(int index, QObject *obj);
41 void removeObject(QObject *obj);
42
43 void _q_updateEnabled();
44 void _q_updateText();
45 void _q_updateIcon();
46 void _q_updateVisible();
47
48 static void data_append(QQmlListProperty<QObject> *prop, QObject *o);
49 static int data_count(QQmlListProperty<QObject> *prop);
50 static QObject *data_at(QQmlListProperty<QObject> *prop, int index);
51 static void data_clear(QQmlListProperty<QObject> *prop);
52
53 Menu* q_ptr;
54 QPlatformMenu* m_platformMenu;
55 UCAction* m_action;
56
57 QHash<QObject*, PlatformItemWrapper*> m_platformItems;
58 QMultiHash<QObject*, QObject*> m_dataPlatformObjectMap;
59 QVector<QObject*> m_data;
60};
61
62class PlatformItemWrapper : public QObject
63{
64 Q_OBJECT
65public:
66 PlatformItemWrapper(QObject *target, Menu* menu);
67 ~PlatformItemWrapper();
68
69 void insert(int index, bool withSeparator);
70 void remove();
71 void setSeparator();
72
73 bool hasSeparator() const { return m_platformItemSeparator != Q_NULLPTR; }
74
75public Q_SLOTS:
76 void updateVisible();
77 void updateEnabled();
78 void updateText();
79 void updateIcon();
80 void updateShortcut();
81 void updateCheck();
82
83private:
84 void syncPlatformItem();
85
86 QObject* m_target;
87 QPointer<Menu> m_menu;
88 QPlatformMenuItem* m_platformItem;
89 QPlatformMenuItem* m_platformItemSeparator;
90 bool m_inserted;
91};
92
93UT_NAMESPACE_END
94
95#endif // MENU_P_P_H
096
=== added file 'src/Ubuntu/UbuntuToolkit/menubar.cpp'
--- src/Ubuntu/UbuntuToolkit/menubar.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/menubar.cpp 2016-09-03 13:06:01 +0000
@@ -0,0 +1,340 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include "menubar_p.h"
19#include "menubar_p_p.h"
20
21// Qt
22#include <QQuickItem>
23#include <QQuickWindow>
24#include <QLoggingCategory>
25#include <private/qguiapplication_p.h>
26#include <QtGui/qpa/qplatformtheme.h>
27#include <QtGui/qpa/qplatformmenu.h>
28
29UT_NAMESPACE_BEGIN
30
31MenuBarPrivate::MenuBarPrivate(MenuBar *qq)
32 : q_ptr(qq)
33{
34 m_platformBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar();
35}
36
37MenuBarPrivate::~MenuBarPrivate()
38{
39 qDeleteAll(m_platformMenus);
40 m_platformMenus.clear();
41
42 delete m_platformBar;
43 m_platformBar = Q_NULLPTR;
44}
45
46void MenuBarPrivate::insertMenu(int index, Menu* menu)
47{
48 Q_Q(MenuBar);
49 Menu* prevMenu = m_menus.count() > index ? m_menus[index] : Q_NULLPTR;
50
51 m_menus.insert(index, menu);
52
53 // add to platform
54 if (m_platformBar && menu->platformMenu()) {
55 auto platformWrapper = new PlatformMenuWrapper(menu, q);
56 platformWrapper->insert(prevMenu ? prevMenu->platformMenu() : Q_NULLPTR);
57 m_platformMenus[menu] = platformWrapper;
58
59 QObject::connect(menu, &QObject::destroyed, q, [this](QObject* object) {
60 if (m_platformMenus.contains(object)) {
61 PlatformMenuWrapper* wrapper = m_platformMenus.take(object);
62 wrapper->remove();
63 delete wrapper;
64 }
65 });
66 }
67}
68
69void MenuBarPrivate::removeMenu(Menu *menu)
70{
71 m_menus.removeOne(menu);
72
73 if (m_platformBar) {
74 if (m_platformMenus.contains(menu)) {
75 PlatformMenuWrapper* wrapper = m_platformMenus.take(menu);
76 wrapper->remove();
77 delete wrapper;
78 }
79 }
80}
81
82void MenuBarPrivate::menu_append(QQmlListProperty<Menu> *prop, Menu *o)
83{
84 MenuBarPrivate *q = static_cast<MenuBarPrivate *>(prop->data);
85 // menubar is the menus parent
86 o->setParent(prop->object);
87 q->insertMenu(q->m_menus.count(), o);
88}
89
90int MenuBarPrivate::menu_count(QQmlListProperty<Menu> *prop)
91{
92 MenuBarPrivate *p = static_cast<MenuBarPrivate *>(prop->data);
93 return p->m_menus.count();
94}
95
96Menu *MenuBarPrivate::menu_at(QQmlListProperty<Menu> *prop, int index)
97{
98 MenuBarPrivate *p = static_cast<MenuBarPrivate *>(prop->data);
99 return p->m_menus.value(index);
100}
101
102void MenuBarPrivate::menu_clear(QQmlListProperty<Menu> *prop)
103{
104 MenuBarPrivate *p = static_cast<MenuBarPrivate *>(prop->data);
105 p->m_menus.clear();
106}
107
108/*!
109 * \qmltype MenuBar
110 * \inqmlmodule Ubuntu.Components 1.3
111 * \ingroup ubuntu
112 * \brief MenuBar defines an application menu bar structure
113 *
114 * Example usage:
115 * \qml
116 * import QtQuick 2.4
117 * import Ubuntu.Components 1.3
118 * MainView {
119 * MenuBar {
120 * Menu {
121 * text: "_File"
122 *
123 * MenuItem {
124 * text: "_New"
125 * shortcut: "Ctrl+N"
126 * }
127 *
128 * MenuItem {
129 * text: "_Open"
130 * shortcut: "Ctrl+O"
131 * }
132 *
133 * MenuSeparator {}
134 *
135 * MenuItem {
136 * action: exitAction
137 * }
138 * }
139 *
140 * Menu {
141 * text: "_Edit"
142 *
143 * MenuItem {
144 * text: "_Undo"
145 * iconSource: "image://theme/undo"
146 * }
147 * }
148 * Menu {
149 * text: "_Window"
150 *
151 * MenuItem {
152 * text: "Fullscreen"
153 * checkable: true
154 * checked: false
155 * }
156 * }
157 * }
158 * Action {
159 * id: boundAction
160 * text: "E_xit"
161 * onTriggered: {
162 * Qt.quit();
163 * }
164 * }
165 * }
166 * \endqml
167 */
168MenuBar::MenuBar(QObject *parent)
169 : QObject(parent)
170 , d_ptr(new MenuBarPrivate(this))
171{
172}
173
174MenuBar::~MenuBar()
175{
176}
177
178/*!
179 * \qmlmethod void MenuBar::appendMenu(Menu menu)
180 * Append a Menu to the MenuBar
181 */
182void MenuBar::appendMenu(Menu *menu)
183{
184 Q_D(MenuBar);
185 insertMenu(d->m_menus.count(), menu);
186}
187
188/*!
189 * \qmlmethod void MenuBar::insertMenu(int index, Menu menu)
190 * Insert a Menu to the MenuBar at the specified position
191 */
192void MenuBar::insertMenu(int index, Menu *menu)
193{
194 Q_D(MenuBar);
195 if (!menu) return;
196
197 d->insertMenu(index, menu);
198 Q_EMIT menusChanged();
199}
200
201/*!
202 * \qmlmethod void MenuBar::removeMenu(Menu menu)
203 * Remove a Menu from the MenuBar
204 */
205void MenuBar::removeMenu(Menu *menu)
206{
207 Q_D(MenuBar);
208 if (!menu) return;
209
210 d->removeMenu(menu);
211 Q_EMIT menusChanged();
212}
213/*!
214 * \qmlproperty list<Menu> MenuBar::menus
215 * \default
216 * List of Menus in this MenuBar.
217 */
218QQmlListProperty<Menu> MenuBar::menus()
219{
220 Q_D(MenuBar);
221 return QQmlListProperty<Menu>(this, d,
222 &MenuBarPrivate::menu_append,
223 &MenuBarPrivate::menu_count,
224 &MenuBarPrivate::menu_at,
225 &MenuBarPrivate::menu_clear);
226}
227
228QPlatformMenuBar *MenuBar::platformMenuBar() const
229{
230 Q_D(const MenuBar);
231 return d->m_platformBar;
232}
233
234void MenuBar::classBegin()
235{
236}
237
238void MenuBar::componentComplete()
239{
240 Q_D(MenuBar);
241
242 auto parentItem = qobject_cast<QQuickItem*>(parent());
243 if (parentItem && d->m_platformBar) {
244 d->m_platformBar->handleReparent(parentItem->window());
245 }
246}
247
248
249PlatformMenuWrapper::PlatformMenuWrapper(Menu *target, MenuBar* bar)
250 : QObject(bar)
251 , m_bar(bar)
252 , m_target(target)
253 , m_inserted(false)
254{
255 connect(m_target.data(), &Menu::visibleChanged, this, &PlatformMenuWrapper::updateVisible);
256 connect(m_target.data(), &Menu::textChanged, this, &PlatformMenuWrapper::updateText);
257 connect(m_target.data(), &Menu::enabledChanged, this, &PlatformMenuWrapper::updateEnabled);
258 connect(m_target.data(), &Menu::iconSourceChanged, this, &PlatformMenuWrapper::updateIcon);
259 connect(m_target.data(), &Menu::iconNameChanged, this, &PlatformMenuWrapper::updateIcon);
260
261 syncPlatformMenu();
262}
263
264PlatformMenuWrapper::~PlatformMenuWrapper()
265{
266 if (m_inserted && m_bar && m_bar->platformMenuBar()) {
267 if (m_target && m_target->platformMenu()) {
268 m_bar->platformMenuBar()->removeMenu(m_target->platformMenu());
269 }
270 }
271}
272
273void PlatformMenuWrapper::insert(QPlatformMenu *before)
274{
275 if (m_inserted) return;
276 qCDebug(ucMenu).nospace() << " PlatformMenuWrapper::insert(bar=" << m_bar
277 << ", before=" << before
278 << ", menu=" << m_target << ")";
279
280 auto platformBar = m_bar->platformMenuBar();
281 if (!platformBar) return;
282 auto platformMenu = m_target->platformMenu();
283 if (!platformMenu) return;
284
285 platformBar->insertMenu(platformMenu, before);
286 m_inserted = true;
287}
288
289void PlatformMenuWrapper::remove()
290{
291 if (!m_inserted) return;
292 qCDebug(ucMenu).nospace() << " PlatformMenuWrapper::remove(bar=" << m_bar
293 << ", menu=" << m_target << ")";
294
295 auto platformBar = m_bar->platformMenuBar();
296 if (!platformBar) return;
297 auto platformMenu = m_target->platformMenu();
298 if (!platformMenu) return;
299
300 platformBar->removeMenu(platformMenu);
301 m_inserted = false;
302}
303
304void PlatformMenuWrapper::updateVisible()
305{
306 if (m_target->platformMenu()) m_target->platformMenu()->setVisible(m_target->visible());
307}
308
309void PlatformMenuWrapper::updateEnabled()
310{
311 if (m_target->platformMenu()) m_target->platformMenu()->setEnabled(m_target->isEnabled());
312}
313
314void PlatformMenuWrapper::updateText()
315{
316 if (m_target->platformMenu()) m_target->platformMenu()->setText(m_target->text());
317}
318
319void PlatformMenuWrapper::updateIcon()
320{
321 QIcon icon;
322 if (!m_target->iconSource().isEmpty()) {
323 icon = QIcon(m_target->iconSource().path());
324 } else if (!m_target->iconName().isEmpty()) {
325 icon = QIcon::fromTheme(m_target->iconName());
326 }
327 if (m_target->platformMenu()) m_target->platformMenu()->setIcon(icon);
328}
329
330void PlatformMenuWrapper::syncPlatformMenu()
331{
332 updateVisible();
333 updateEnabled();
334 updateText();
335 updateIcon();
336}
337
338UT_NAMESPACE_END
339
340#include "moc_menubar_p.cpp"
0341
=== added file 'src/Ubuntu/UbuntuToolkit/menubar_p.h'
--- src/Ubuntu/UbuntuToolkit/menubar_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/menubar_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,65 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MENUBAR_P_H
19#define MENUBAR_P_H
20
21#include "menu_p.h"
22#include <ubuntutoolkitglobal.h>
23
24#include <QQmlParserStatus>
25
26class QPlatformMenuBar;
27
28UT_NAMESPACE_BEGIN
29
30class MenuBarPrivate;
31class UBUNTUTOOLKIT_EXPORT MenuBar : public QObject, public QQmlParserStatus
32{
33 Q_OBJECT
34 Q_INTERFACES(QQmlParserStatus)
35
36 Q_PROPERTY(QQmlListProperty<UT_PREPEND_NAMESPACE(Menu)> menus READ menus NOTIFY menusChanged FINAL)
37 Q_CLASSINFO("DefaultProperty", "menus")
38
39public:
40 explicit MenuBar(QObject *parent = 0);
41 ~MenuBar();
42
43 Q_INVOKABLE void appendMenu(Menu *menu);
44 Q_INVOKABLE void insertMenu(int index, Menu *menu);
45 Q_INVOKABLE void removeMenu(Menu *menu);
46
47 QQmlListProperty<Menu> menus();
48
49 QPlatformMenuBar *platformMenuBar() const;
50
51 void classBegin() Q_DECL_OVERRIDE;
52 void componentComplete() Q_DECL_OVERRIDE;
53
54Q_SIGNALS:
55 void menusChanged();
56
57private:
58 Q_DISABLE_COPY(MenuBar)
59 Q_DECLARE_PRIVATE(MenuBar)
60 QScopedPointer<MenuBarPrivate> d_ptr;
61};
62
63UT_NAMESPACE_END
64
65#endif // MENUBAR_P_H
066
=== added file 'src/Ubuntu/UbuntuToolkit/menubar_p_p.h'
--- src/Ubuntu/UbuntuToolkit/menubar_p_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/menubar_p_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,78 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MENUBAR_P_P_H
19#define MENUBAR_P_P_H
20
21#include "menubar_p.h"
22#include <ubuntutoolkitglobal.h>
23
24class QPlatformMenuBar;
25
26UT_NAMESPACE_BEGIN
27
28class PlatformMenuWrapper;
29
30class MenuBarPrivate
31{
32 Q_DECLARE_PUBLIC(MenuBar)
33public:
34 MenuBarPrivate(MenuBar *qq);
35 ~MenuBarPrivate();
36
37 void insertMenu(int index, Menu *menu);
38 void removeMenu(Menu *menu);
39
40 static void menu_append(QQmlListProperty<Menu> *prop, Menu *o);
41 static int menu_count(QQmlListProperty<Menu> *prop);
42 static Menu *menu_at(QQmlListProperty<Menu> *prop, int index);
43 static void menu_clear(QQmlListProperty<Menu> *prop);
44
45 MenuBar* q_ptr;
46 QPlatformMenuBar* m_platformBar;
47 QVector<Menu*> m_menus;
48 QHash<QObject*, PlatformMenuWrapper*> m_platformMenus;
49};
50
51class PlatformMenuWrapper : public QObject
52{
53 Q_OBJECT
54public:
55 PlatformMenuWrapper(Menu *target, MenuBar *bar);
56 ~PlatformMenuWrapper();
57
58 void insert(QPlatformMenu *before);
59 void remove();
60
61public Q_SLOTS:
62 void updateVisible();
63 void updateEnabled();
64 void updateText();
65 void updateIcon();
66
67private:
68 void syncPlatformMenu();
69
70 QPointer<MenuBar> m_bar;
71 QPointer<Menu> m_target;
72 bool m_inserted;
73};
74
75UT_NAMESPACE_END
76
77#endif // MENUBAR_P_P_H
78
079
=== added file 'src/Ubuntu/UbuntuToolkit/menugroup.cpp'
--- src/Ubuntu/UbuntuToolkit/menugroup.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/menugroup.cpp 2016-09-03 13:06:01 +0000
@@ -0,0 +1,164 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "menugroup_p.h"
18#include "actionlist_p.h"
19#include "ucaction_p.h"
20
21UT_NAMESPACE_BEGIN
22
23/*!
24 * \qmltype MenuGroup
25 * \inqmlmodule Ubuntu.Components
26 * \ingroup ubuntu
27 * \brief Logical list of items for a menu.
28 *
29 * Example usage:
30 * \qml
31 * import QtQuick 2.4
32 * import Ubuntu.Components 1.3
33 * Menu {
34 * text: "Edit"
35 *
36 * MenuGroup {
37 * Action { text: "Undo" }
38 * Action { text: "Redo" }
39 * }
40 *
41 * MenuGroup {
42 * Action { text: "Cut" }
43 * ActionList {
44 * Action { text: "Copy" }
45 * Action { text: "Paste" }
46 * }
47 * }
48 *
49 * MenuGroup {
50 * Action { text: "Select All" }
51 * }
52 * }
53 * \endqml
54 */
55/*!
56 * \qmlsignal MenuGroup::added(Object action)
57 * Signal called when a action is added to the list
58 */
59
60/*!
61 * \qmlsignal MenuGroup::removed(Object action)
62 * Signal called when a action is removed from the list
63 */
64/*!
65 * \qmlsignal MenuGroup::changed()
66 * Signal called when the contents of the group change,
67 * including child content changes (eg. \l ActionList child add/remove)
68 */
69MenuGroup::MenuGroup(QObject *parent)
70 : QObject(parent)
71{
72}
73
74/*!
75 * \qmlmethod MenuGroup::addObject(Object object)
76 * Adds an Object to the list programatically.
77 */
78void MenuGroup::addObject(QObject *object)
79{
80 if (m_data.contains(object)) {
81 return;
82 }
83 m_data.push_back(object);
84
85 if (auto childGroup = qobject_cast<MenuGroup*>(object)) {
86 connect(childGroup, &MenuGroup::changed, this, &MenuGroup::changed);
87 } else if (auto actionList = qobject_cast<ActionList*>(object)) {
88 connect(actionList, &ActionList::added, this, &MenuGroup::changed);
89 connect(actionList, &ActionList::removed, this, &MenuGroup::changed);
90 }
91
92 Q_EMIT added(object);
93 Q_EMIT changed();
94}
95
96/*!
97 * \qmlmethod MenuGroup::removeObject(Object object)
98 * Removes an object from the list programatically.
99 */
100void MenuGroup::removeObject(QObject *object)
101{
102 if (!object) {
103 return;
104 }
105 if (m_data.removeOne(object)) {
106 disconnect(object, 0, this, 0);
107 Q_EMIT removed(object);
108 Q_EMIT changed();
109 }
110}
111
112/*!
113
114 * \qmlproperty list<Object> MenuGroup::data
115 * \default
116 * List of Objects in this MenuGroup
117 * Note that when you set this property, the children of the MenuGroup will be ignored,
118 * so do not set the list and define children.
119 */
120QQmlListProperty<QObject> MenuGroup::data()
121{
122 return QQmlListProperty<QObject>(this, 0, MenuGroup::append, MenuGroup::count, MenuGroup::at, MenuGroup::clear);
123}
124
125const QVector<QObject*> &MenuGroup::list() const
126{
127 return m_data;
128}
129
130void MenuGroup::append(QQmlListProperty<QObject> *list, QObject *object)
131{
132 MenuGroup *menuGroup = qobject_cast<MenuGroup*>(list->object);
133 if (menuGroup) {
134 menuGroup->addObject(object);
135 }
136}
137
138int MenuGroup::count(QQmlListProperty<QObject> *list)
139{
140 MenuGroup *menuGroup = qobject_cast<MenuGroup*>(list->object);
141 if (menuGroup) {
142 return menuGroup->m_data.count();
143 }
144 return 0;
145}
146
147QObject* MenuGroup::at(QQmlListProperty<QObject> *list, int index)
148{
149 MenuGroup *menuGroup = qobject_cast<MenuGroup*>(list->object);
150 if (menuGroup && index >=0 && menuGroup->m_data.count() > index) {
151 return menuGroup->m_data[index];
152 }
153 return Q_NULLPTR;
154}
155
156void MenuGroup::clear(QQmlListProperty<QObject> *list)
157{
158 MenuGroup *menuGroup = qobject_cast<MenuGroup*>(list->object);
159 if (menuGroup) {
160 menuGroup->m_data.clear();
161 }
162}
163
164UT_NAMESPACE_END
0165
=== added file 'src/Ubuntu/UbuntuToolkit/menugroup_p.h'
--- src/Ubuntu/UbuntuToolkit/menugroup_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/menugroup_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,60 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MENUGROUP_P_H
18#define MENUGROUP_P_H
19
20#include <ubuntutoolkitglobal.h>
21
22#include <QObject>
23#include <QVector>
24#include <QQmlListProperty>
25
26UT_NAMESPACE_BEGIN
27
28class MenuGroup : public QObject
29{
30 Q_OBJECT
31 Q_PROPERTY(QQmlListProperty<QObject> data READ data)
32 Q_CLASSINFO("DefaultProperty", "data")
33public:
34 explicit MenuGroup(QObject *parent = 0);
35
36 QQmlListProperty<QObject> data();
37
38 const QVector<QObject*> &list() const;
39
40public Q_SLOTS:
41 void addObject(QObject *object);
42 void removeObject(QObject *object);
43
44Q_SIGNALS:
45 void added(QObject *object);
46 void removed(QObject *object);
47 void changed();
48
49protected:
50 QVector<QObject*> m_data;
51
52 static void append(QQmlListProperty<QObject> *list, QObject *action);
53 static int count(QQmlListProperty<QObject> *list);
54 static QObject* at(QQmlListProperty<QObject> *list, int);
55 static void clear(QQmlListProperty<QObject> *list);
56};
57
58UT_NAMESPACE_END
59
60#endif // MENUGROUP_P_H
061
=== added file 'src/Ubuntu/UbuntuToolkit/privates/splitviewhandler.cpp'
--- src/Ubuntu/UbuntuToolkit/privates/splitviewhandler.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/privates/splitviewhandler.cpp 2016-09-03 13:06:01 +0000
@@ -0,0 +1,137 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Zsombor Egri <zsombor.egri@canonical.com>
17 */
18
19#include "splitviewhandler_p_p.h"
20#include <QtQuick/private/qquickanchors_p.h>
21#include <QtQuick/private/qquickitem_p.h>
22#include <QtQuick/private/qquickevents_p_p.h>
23#include <QtQml/QQmlEngine>
24#include <QtQml/QQmlInfo>
25#include <splitview_p_p.h>
26
27UT_NAMESPACE_BEGIN
28
29SplitViewHandler::SplitViewHandler(QQuickItem *parent)
30 : QQuickMouseArea(parent)
31{
32 // for testing purposes
33 setObjectName("resize_handle");
34 setFlag(ItemHasContents);
35 setHoverEnabled(true);
36 setAcceptedButtons(Qt::LeftButton);
37
38 setCursorShape(Qt::SplitHCursor);
39 setParentItem(parent);
40
41 // attach the handler to the parent's rigth edge
42 QQuickItemPrivate *dParent = QQuickItemPrivate::get(parentItem());
43 QQuickAnchors *anchors = QQuickItemPrivate::get(this)->anchors();
44 anchors->setTop(dParent->top());
45 anchors->setBottom(dParent->bottom());
46 anchors->setLeft(dParent->right());
47
48 // capture mouse events
49 connect(this, SIGNAL(pressed(QQuickMouseEvent*)), this, SLOT(onPressed(QQuickMouseEvent*)));
50 connect(this, &SplitViewHandler::released, this, &SplitViewHandler::onReleased);
51 connect(this, &SplitViewHandler::positionChanged, this, &SplitViewHandler::onPositionChanged);
52}
53
54SplitViewHandler::~SplitViewHandler()
55{
56 if (spacing) {
57 disconnect(*spacing);
58 }
59 delete spacing;
60}
61
62void SplitViewHandler::connectToView(SplitView *view)
63{
64 this->view = view;
65 // grab the context of the parent
66 QQmlEngine::setContextForObject(this, qmlContext(view));
67
68 // bind SplitView spacing, use it to specify the resize handle
69 auto resizer = [view, this]() {
70 setWidth(view->spacing());
71 };
72 spacing = new QMetaObject::Connection;
73 *spacing = connect(view, &SplitView::spacingChanged, resizer);
74 setWidth(view->spacing());
75
76 // connect to receive handle delegate
77 connect(view, &SplitView::handleDelegateChanged,
78 this, &SplitViewHandler::onDelegateChanged);
79
80 onDelegateChanged();
81}
82
83void SplitViewHandler::onPressed(QQuickMouseEvent *event)
84{
85 prevPos = QPointF(event->x(), event->y());
86}
87
88void SplitViewHandler::onReleased(QQuickMouseEvent *event)
89{
90 Q_UNUSED(event);
91 prevPos = QPointF();
92}
93
94void SplitViewHandler::onPositionChanged(QQuickMouseEvent *event)
95{
96 if (!pressed()) {
97 return;
98 }
99 qreal dx = event->x() - prevPos.x();
100 SplitViewAttached *attached = SplitViewAttached::get(parentItem());
101 if (attached) {
102 attached->resize(dx);
103 }
104}
105
106void SplitViewHandler::onDelegateChanged()
107{
108 static bool warningShown = false;
109 // the child is an instance of the delegate
110 QList<QQuickItem*> children = childItems();
111 qDeleteAll(children);
112
113 // and set the new delegate - if any
114 if (SplitViewPrivate::get(view)->handleDelegate) {
115 QQmlContext *context = new QQmlContext(qmlContext(this), this);
116 context->setContextProperty("handle", QVariant::fromValue(this));
117 QObject *object = SplitViewPrivate::get(view)->handleDelegate->beginCreate(context);
118 if (object) {
119 QQuickItem *item = qobject_cast<QQuickItem*>(object);
120 if (!item) {
121 if (!warningShown) {
122 qmlInfo(view) << "handle delegate not an Item";
123 warningShown = true;
124 }
125 SplitViewPrivate::get(view)->handleDelegate->completeCreate();
126 delete object;
127 } else {
128 warningShown = false;
129 QQml_setParent_noEvent(item, this);
130 item->setParentItem(this);
131 SplitViewPrivate::get(view)->handleDelegate->completeCreate();
132 }
133 }
134 }
135}
136
137UT_NAMESPACE_END
0138
=== added file 'src/Ubuntu/UbuntuToolkit/privates/splitviewhandler_p_p.h'
--- src/Ubuntu/UbuntuToolkit/privates/splitviewhandler_p_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/privates/splitviewhandler_p_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,52 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Zsombor Egri <zsombor.egri@canonical.com>
17 */
18
19#ifndef SPLITVIEWHANDLER_H
20#define SPLITVIEWHANDLER_H
21
22#include <QtQuick/QQuickItem>
23#include <QtCore/QPointer>
24#include <QtQuick/private/qquickmousearea_p.h>
25#include <ubuntutoolkitglobal.h>
26
27UT_NAMESPACE_BEGIN
28
29class SplitView;
30class SplitViewHandler : public QQuickMouseArea
31{
32 Q_OBJECT
33public:
34 explicit SplitViewHandler(QQuickItem *parent = 0);
35 ~SplitViewHandler();
36 void connectToView(SplitView *view);
37
38protected:
39 QPointF prevPos;
40 QPointer<SplitView> view;
41 QMetaObject::Connection *spacing{nullptr};
42
43private Q_SLOTS:
44 void onPressed(QQuickMouseEvent *event);
45 void onReleased(QQuickMouseEvent *event);
46 void onPositionChanged(QQuickMouseEvent *event);
47 void onDelegateChanged();
48};
49
50UT_NAMESPACE_END
51
52#endif // SPLITVIEWHANDLER_H
053
=== modified file 'src/Ubuntu/UbuntuToolkit/quickutils.cpp'
--- src/Ubuntu/UbuntuToolkit/quickutils.cpp 2016-07-07 07:21:48 +0000
+++ src/Ubuntu/UbuntuToolkit/quickutils.cpp 2016-09-03 13:06:01 +0000
@@ -36,6 +36,7 @@
3636
37QuickUtils::QuickUtils(QObject *parent) :37QuickUtils::QuickUtils(QObject *parent) :
38 QObject(parent),38 QObject(parent),
39 m_rootWindow(0),
39 m_rootView(0),40 m_rootView(0),
40 m_mouseAttached(false),41 m_mouseAttached(false),
41 m_keyboardAttached(false)42 m_keyboardAttached(false)
@@ -86,7 +87,7 @@
86 // make sure we have the m_rootView updated87 // make sure we have the m_rootView updated
87 lookupQuickView();88 lookupQuickView();
88 if (!object) {89 if (!object) {
89 return (m_rootView) ? m_rootView->rootObject() : 0;90 return m_rootView ? m_rootView->rootObject() : (m_rootWindow ? m_rootWindow->contentItem() : 0);
90 }91 }
9192
92 QQuickItem *item = qobject_cast<QQuickItem*>(object);93 QQuickItem *item = qobject_cast<QQuickItem*>(object);
@@ -175,9 +176,10 @@
175 */176 */
176void QuickUtils::lookupQuickView()177void QuickUtils::lookupQuickView()
177{178{
178 if (m_rootView)179 if (m_rootWindow)
179 return;180 return;
180 Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) {181 Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) {
182 m_rootWindow = qobject_cast<QQuickWindow*>(w);
181 m_rootView = qobject_cast<QQuickView*>(w);183 m_rootView = qobject_cast<QQuickView*>(w);
182 if (m_rootView) {184 if (m_rootView) {
183 // connect in case we get the root object changed185 // connect in case we get the root object changed
184186
=== modified file 'src/Ubuntu/UbuntuToolkit/quickutils_p.h'
--- src/Ubuntu/UbuntuToolkit/quickutils_p.h 2016-07-07 07:21:48 +0000
+++ src/Ubuntu/UbuntuToolkit/quickutils_p.h 2016-09-03 13:06:01 +0000
@@ -85,6 +85,7 @@
8585
86private:86private:
87 explicit QuickUtils(QObject *parent = 0);87 explicit QuickUtils(QObject *parent = 0);
88 QPointer<QQuickWindow> m_rootWindow;
88 QPointer<QQuickView> m_rootView;89 QPointer<QQuickView> m_rootView;
89 QStringList m_omitIM;90 QStringList m_omitIM;
90 bool m_mouseAttached;91 bool m_mouseAttached;
9192
=== added file 'src/Ubuntu/UbuntuToolkit/splitview.cpp'
--- src/Ubuntu/UbuntuToolkit/splitview.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/splitview.cpp 2016-09-03 13:06:01 +0000
@@ -0,0 +1,675 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Zsombor Egri <zsombor.egri@canonical.com>
17 */
18
19#include <QtQuick/private/qquickitem_p.h>
20#include <QtQuick/private/qquickanchors_p.h>
21#include <QtQml/QQmlInfo>
22
23#include "splitview_p.h"
24#include "splitview_p_p.h"
25#include "ucunits_p.h"
26#include "ucpagetreenode_p.h"
27
28#include "privates/splitviewhandler_p_p.h"
29
30#define DEFAULT_SPACING_DP 4
31
32UT_NAMESPACE_BEGIN
33
34/*!
35 * \qmltype SplitView
36 * \inqmlmodule Ubuntu.Components.Labs 1.0
37 * \inherits QQuickBasePositioner
38 * \ingroup ubuntu-labs
39 * \brief A view component with a flexible layout configuration setup.
40 *
41 * The component arranges the declared child elements horizontally based on an active
42 * column configuration layout. Child elements are considered to be views, and each view
43 * is identified with a column index, specified by the SplitView.column attached property.
44 * Views should not have width declared, because the width of each view is specified
45 * by the active layout's configuration (ViewColumn) and will overwrite the value
46 * specified by the view. On the other hand they should have a height specified, or
47 * they can be anchored to the top and bottom of the view. SplitView being a positioner,
48 * remember not to anchor horizontal anchor lines or anchor fill the columns.
49 *
50 * In order for a SplitView to show some content it must have at least one active layout
51 * present. Views which are not configured by the active layout will be hidden. Hidden
52 * views may be resized, therefore if the content is size sensitive (i.e. the amount
53 * shown differs depending on the space available), make sure the content of your view
54 * does take this into account.
55 * \code
56 * import QtQuick 2.4
57 * import Ubuntu.Components 1.3
58 * import Ubuntu.Components.Labs 1.0
59 *
60 * MainView {
61 * id: main
62 * width: units.gu(300)
63 * height: units.gu(80)
64 * SplitView {
65 * anchors.fill: parent
66 * layouts: [
67 * SplitViewLayout {
68 * when: main.width < units.gu(80)
69 * ViewColumn {
70 * fillWidth: true
71 * }
72 * },
73 * SplitViewLayout {
74 * when: main.width >= units.gu(80)
75 * ViewColumn {
76 * minimumWidth: units.gu(30)
77 * maximumWidth: units.gu(100)
78 * preferredWidth: units.gu(40)
79 * }
80 * ViewColumn {
81 * minimumWidth: units.gu(40)
82 * fillWidth: true
83 * }
84 * }
85 * ]
86 * }
87 *
88 * Page {
89 * id: column1
90 * height: parent.height
91 * }
92 * Page {
93 * id: column2
94 * height: parent.height
95 * }
96 * }
97 * \endcode
98 *
99 * The SplitView can be used with a Repeater in case the content of the view columns
100 * doesn't need to be preserved between layout changes. The example above with a
101 * Repeater would look as follows:
102 * \code
103 * import QtQuick 2.4
104 * import Ubuntu.Components 1.3
105 * import Ubuntu.Components.Labs 1.0
106 *
107 * MainView {
108 * id: main
109 * width: units.gu(300)
110 * height: units.gu(80)
111 * SplitView {
112 * id: view
113 * anchors.fill: parent
114 * layouts: [
115 * SplitViewLayout {
116 * when: main.width < units.gu(80)
117 * ViewColumn {
118 * fillWidth: true
119 * }
120 * },
121 * SplitViewLayout {
122 * when: main.width >= units.gu(80)
123 * ViewColumn {
124 * minimumWidth: units.gu(30)
125 * maximumWidth: units.gu(100)
126 * preferredWidth: units.gu(40)
127 * }
128 * ViewColumn {
129 * minimumWidth: units.gu(40)
130 * fillWidth: true
131 * }
132 * }
133 * ]
134 * }
135 *
136 * Repeater {
137 * model: view.activeLayout.columns
138 * Page {
139 * height: parent.height
140 * }
141 * }
142 * }
143 * \endcode
144 *
145 * \section2 Resizing
146 * SplitView provides the ability to resize view columns. Each column has an attached
147 * handle which provides the ability to resize the columns using a mouse or touch.
148 * Columns can be resized if the spacing property is set and the column configurations
149 * allow that (see \l spacing property).
150 *
151 * \section2 Attached properties
152 * SplitView provides a set of attached properties to each column view. Views can in
153 * this way have access to various values of the SplitView and configurations.
154 */
155
156/*!
157 * \qmlproperty real SplitView::spacing
158 * Spacing between view columns. A value bigger than 0 enables resizing of columns with
159 * a \l{ViewColumn::minimumWidth}{minimumWidth} lower than \l {ViewColumn::maximumWidth}{maximumWidth}.
160 * If spacing is 0 the columns cannot be resized.
161 * Defaults to 4 device pixels.
162 */
163void SplitView::setSpacing2(qreal spacing, bool reset)
164{
165 Q_D(SplitView);
166 if (reset && d->defaultSpacing) {
167 QObject::disconnect(*d->defaultSpacing);
168 delete d->defaultSpacing;
169 d->defaultSpacing = Q_NULLPTR;
170 }
171 if (qFuzzyCompare(this->spacing(), spacing)) {
172 return;
173 }
174 static_cast<QQuickBasePositioner*>(this)->setSpacing(spacing);
175}
176
177/******************************************************************************
178 * SplitViewAttached
179 */
180SplitViewAttached::SplitViewAttached(QObject *parent)
181 : QObject(*(new SplitViewAttachedPrivate), parent)
182{
183}
184
185SplitViewAttached *SplitViewAttached::get(QQuickItem *item)
186{
187 SplitViewAttached *attached = static_cast<SplitViewAttached*>(
188 qmlAttachedPropertiesObject<SplitView>(item, false));
189 return attached;
190}
191
192ViewColumn *SplitViewAttachedPrivate::getConfig(QQuickItem *attachee)
193{
194 SplitViewAttached *attached = SplitViewAttached::get(attachee);
195 if (!attached) {
196 return nullptr;
197 }
198 return get(attached)->config();
199}
200
201void SplitViewAttachedPrivate::configure(SplitView *view, int column)
202{
203 this->column = column;
204 splitView = view;
205 Q_EMIT q_func()->columnChanged();
206}
207
208void SplitViewAttached::resize(qreal delta)
209{
210 Q_D(SplitViewAttached);
211 ViewColumn *config = d->config();
212 if (config) {
213 config->resize(delta);
214 }
215}
216
217/*!
218 * \qmlattachedproperty ViewColumn SplitView::columnConfig
219 * The attached property holds the active layout's column configuration data.
220 * The value is null if there is no active configuration value provided for
221 * the column.
222 */
223UT_PREPEND_NAMESPACE(ViewColumn*) SplitViewAttachedPrivate::config()
224{
225 if (!splitView || column < 0) {
226 return nullptr;
227 }
228 SplitViewPrivate *d = SplitViewPrivate::get(splitView);
229 if (!d->activeLayout) {
230 return nullptr;
231 }
232 if (SplitViewLayoutPrivate::get(d->activeLayout)->columnData.size() <= column) {
233 return nullptr;
234 }
235 return SplitViewLayoutPrivate::get(d->activeLayout)->columnData[column];
236}
237
238/*!
239 * \qmlattachedproperty SplitView SplitView::view
240 * Contains the SplitView instance of the column.
241 */
242
243/*!
244 * \qmlattachedproperty int SplitView::column
245 * The property holds the column index the view is configured to.
246 */
247
248/******************************************************************************
249 * SplitView
250 */
251SplitViewPrivate::SplitViewPrivate(SplitView *qq)
252 : q_ptr(qq)
253{
254}
255
256SplitViewPrivate::~SplitViewPrivate()
257{
258}
259
260UT_PREPEND_NAMESPACE(SplitViewAttached) *SplitView::qmlAttachedProperties(QObject *owner)
261{
262 return new SplitViewAttached(owner);
263}
264
265// layouts property
266/*!
267 * \qmlproperty list<SplitViewLayout> SplitView::layouts
268 * The property holds the layout configurations declared for the given SplitView.
269 * \sa SplitViewLayout
270 */
271void SplitViewPrivate::layout_Append(QQmlListProperty<SplitViewLayout> *list, SplitViewLayout* layout)
272{
273 SplitView *view = static_cast<SplitView*>(list->object);
274 SplitViewPrivate *d = SplitViewPrivate::get(view);
275 d->columnLatouts.append(layout);
276 // parent layout to view
277 layout->setParent(view);
278 // capture layout activation
279 QObject::connect(layout, SIGNAL(whenChanged()), view, SLOT(changeLayout()), Qt::DirectConnection);
280 Q_EMIT view->layoutsChanged();
281}
282int SplitViewPrivate::layout_Count(QQmlListProperty<SplitViewLayout> *list)
283{
284 SplitView *view = static_cast<SplitView*>(list->object);
285 SplitViewPrivate *d = SplitViewPrivate::get(view);
286 return d->columnLatouts.size();
287}
288SplitViewLayout *SplitViewPrivate::layout_At(QQmlListProperty<SplitViewLayout> *list, int index)
289{
290 SplitView *view = static_cast<SplitView*>(list->object);
291 SplitViewPrivate *d = SplitViewPrivate::get(view);
292 return d->columnLatouts.at(index);
293}
294void SplitViewPrivate::layout_Clear(QQmlListProperty<SplitViewLayout> *list)
295{
296 SplitView *view = static_cast<SplitView*>(list->object);
297 SplitViewPrivate *d = SplitViewPrivate::get(view);
298 for (SplitViewLayout *layout : d->columnLatouts) {
299 // disconnect layout activation
300 QObject::disconnect(layout, SIGNAL(whenChanged()), view, SLOT(changeLayout()));
301 delete layout;
302 }
303 d->columnLatouts.clear();
304 d->activeLayout = nullptr;
305 Q_EMIT view->layoutsChanged();
306}
307QQmlListProperty<SplitViewLayout> SplitViewPrivate::layouts()
308{
309 Q_Q(SplitView);
310 return QQmlListProperty<SplitViewLayout>(q, (void*)&columnLatouts,
311 &layout_Append,
312 &layout_Count,
313 &layout_At,
314 &layout_Clear);
315}
316
317/*!
318 * \qmlproperty SplitViewLayout SplitView::activeLayout
319 * \readonly
320 * The property holds the active SplitViewLayout instance, or null is no layout
321 * is active.
322 */
323UT_PREPEND_NAMESPACE(SplitViewLayout) *SplitViewPrivate::getActiveLayout()
324{
325 return activeLayout;
326}
327
328// invoked when one of the SplitViewLayouts emits whenChanged()
329void SplitViewPrivate::changeLayout()
330{
331 // go through layouts and check who's the active one
332 SplitViewLayout *newActive = nullptr;
333 for (SplitViewLayout *layout : columnLatouts) {
334 if (SplitViewLayoutPrivate::get(layout)->when) {
335 newActive = layout;
336 break;
337 }
338 }
339 if (newActive == activeLayout) {
340 return;
341 }
342
343 // Q: should we reset the sizes of the previous layout?
344 // at least it feels right to preserve the last state of the layout...
345 activeLayout = newActive;
346
347 Q_EMIT q_func()->activeLayoutChanged();
348
349 updateLayout();
350 if (q_func()->sender()) {
351 // was called by a whenChanged() signal invocation
352 recalculateWidths(RecalculateAll);
353 }
354}
355
356void SplitViewPrivate::updateLayout()
357{
358 Q_Q(SplitView);
359 for (QQuickItem *child : q->childItems()) {
360 bool visible = true;
361 ViewColumn *columnConfig = SplitViewAttachedPrivate::getConfig(child);
362 if (!columnConfig) {
363 // no configuration for the column, hide it
364 visible = false;
365 } else {
366 ViewColumnPrivate *config = ViewColumnPrivate::get(columnConfig);
367 visible = activeLayout
368 && (config->column < SplitViewLayoutPrivate::get(activeLayout)->columnData.size());
369 }
370 dirty = dirty | (child->isVisible() != visible);
371 child->setVisible(visible);
372 }
373}
374
375void SplitViewPrivate::recalculateWidths(RelayoutOperation operation)
376{
377 if (!activeLayout || (!QQuickItemPrivate::get(q_func())->componentComplete && !dirty)) {
378 return;
379 }
380 Q_Q(SplitView);
381
382 // remove the spacing from the width
383 qreal fillWidth = q->width() - q->spacing() * (SplitViewLayoutPrivate::get(activeLayout)->columnData.size() - 1);
384 // stack of columns with fillWidth true
385 QList<QQuickItem*> fillStack;
386
387 for (QQuickItem *child : q->childItems()) {
388 ViewColumn *columnConfig = SplitViewAttachedPrivate::getConfig(child);
389 if (!columnConfig) {
390 continue;
391 }
392 ViewColumnPrivate *config = ViewColumnPrivate::get(columnConfig);
393
394 if (config->fillWidth && !config->resized) {
395 // add to the fillWidth stack
396 if (operation & CalculateFillWidth) {
397 fillStack << child;
398 }
399 } else {
400 if (operation & SetPreferredSize) {
401 child->setWidth(config->preferredWidth);
402 }
403 if (operation & CalculateFillWidth) {
404 fillWidth -= config->preferredWidth;
405 }
406 }
407 }
408
409 // split the width between the stacked fillWidth columns
410 if (fillStack.size() && (operation & CalculateFillWidth)) {
411 fillWidth /= fillStack.size();
412 for (QQuickItem *child : fillStack) {
413 // even though the column is fillWidth, it may have min and max specified;
414 // check if the size can be applied
415 ViewColumnPrivate *config = ViewColumnPrivate::get(SplitViewAttachedPrivate::getConfig(child));
416 config->setPreferredWidth(fillWidth, false);
417 // update preferredWidth so it can be used in case of resize
418 child->setWidth(config->preferredWidth);
419 }
420 }
421 dirty = false;
422}
423
424/*!
425 * \qmlproperty Component SplitView::handleDelegate
426 * The property holds the delegate to be shown for the column resizing handle.
427 * The delegate is for pure visual, mouse and touch handling is provided by the
428 * SplitView component itself. The component provides a context property called
429 * \e handle which embeds the visuals. This can be used to anchor the visuals
430 * to the resize handle. The thickness of the handle is driven by the \l spacing
431 * property.
432 * \code
433 * import QtQuick 2.4
434 * import Ubuntu.Components 1.3
435 * import Ubuntu.Components.Labs 1.0
436 *
437 * MainView {
438 * id: main
439 * width: units.gu(300)
440 * height: units.gu(80)
441 *
442 * SplitView {
443 * anchors.fill: parent
444 * handleDelegate: Rectangle {
445 * anchors {
446 * fill: parent
447 * leftMargin: units.dp(2)
448 * rightMargin: units.dp(2)
449 * topMargin: handle.height / 2 - units.gu(3)
450 * bottomMargin: handle.height / 2 - units.gu(3)
451 * }
452 * color: UbuntuColors.graphite
453 * scale: handle.containsMouse || handle.pressed ? 1.6 : 1.0
454 * Behavior on scale { UbuntuNumberAnimation {} }
455 * }
456 * layouts: [
457 * SplitViewLayout {
458 * when: main.width < units.gu(80)
459 * ViewColumn {
460 * fillWidth: true
461 * }
462 * },
463 * SplitViewLayout {
464 * when: main.width >= units.gu(80)
465 * ViewColumn {
466 * minimumWidth: units.gu(30)
467 * maximumWidth: units.gu(100)
468 * preferredWidth: units.gu(40)
469 * }
470 * ViewColumn {
471 * minimumWidth: units.gu(40)
472 * fillWidth: true
473 * }
474 * }
475 * ]
476 * }
477 *
478 * Page {
479 * id: column1
480 * height: parent.height
481 * }
482 * Page {
483 * id: column2
484 * height: parent.height
485 * }
486 * }
487 * \endcode
488 */
489
490SplitView::SplitView(QQuickItem *parent)
491 : QQuickBasePositioner(Horizontal, parent)
492 , d_ptr(new SplitViewPrivate(this))
493{
494 Q_D(SplitView);
495 d->init();
496}
497
498SplitView::SplitView(SplitViewPrivate &dd, QQuickItem *parent)
499 : QQuickBasePositioner(Vertical, parent)
500 , d_ptr(&dd)
501{
502 Q_D(SplitView);
503 d->init();
504}
505
506SplitView::~SplitView()
507{
508 Q_D(SplitView);
509 delete d;
510}
511
512void SplitViewPrivate::init()
513{
514 Q_Q(SplitView);
515 auto spacingHandle = [q]() {
516 q->setSpacing2(UCUnits::instance(q)->dp(DEFAULT_SPACING_DP), false);
517 };
518 defaultSpacing = new QMetaObject::Connection;
519 *defaultSpacing = QObject::connect(UCUnits::instance(q), &UCUnits::gridUnitChanged, spacingHandle);
520
521 // connect the spacingChanged signals
522 QObject::connect(q, SIGNAL(spacingChanged()), q, SIGNAL(spacingChanged2()));
523
524 // set the defaults
525 q->setSpacing2(UCUnits::instance(q)->dp(DEFAULT_SPACING_DP), false);
526}
527
528void SplitView::doPositioning(QSizeF *contentSize)
529{
530 // Inspired from QtQuick QQuickRow code
531 // FIXME: revisit the code once we move to Qt 5.6 as there were more properties added to positioner
532
533 // calculate the layout before we go into the positioning
534 d_func()->recalculateWidths(SplitViewPrivate::RecalculateAll);
535
536 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
537 QQuickItemPrivate *d = QQuickItemPrivate::get(this);
538 qreal hoffset = 0;
539
540 QList<qreal> hoffsets;
541 for (int ii = 0; ii < positionedItems.count(); ++ii) {
542 PositionedItem &child = positionedItems[ii];
543
544 if (!d->effectiveLayoutMirror) {
545 positionItemX(hoffset, &child);
546 } else {
547 hoffsets << hoffset;
548 }
549
550 contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
551
552 hoffset += child.item->width();
553 hoffset += spacing();
554 }
555
556 if (hoffset != 0) { //If we positioned any items, undo the extra spacing from the last item
557 hoffset -= spacing();
558 }
559 contentSize->setWidth(hoffset);
560
561 if (!d->effectiveLayoutMirror) {
562 return;
563 }
564
565 //Right to Left layout
566 qreal end = 0;
567 if (!widthValid()) {
568 end = contentSize->width();
569 } else {
570 end = width();
571 }
572
573 int acc = 0;
574 for (int ii = 0; ii < positionedItems.count(); ++ii) {
575 PositionedItem &child = positionedItems[ii];
576 hoffset = end - hoffsets[acc++] - child.item->width();
577 positionItemX(hoffset, &child);
578 }
579}
580
581void SplitView::reportConflictingAnchors()
582{
583 // Inspired from QtQuick QQuickColumn code
584 bool anchorConflict = false;
585 for (int ii = 0; ii < positionedItems.count(); ++ii) {
586 const PositionedItem &child = positionedItems.at(ii);
587 if (child.item) {
588 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
589 if (anchors) {
590 // can we patch out the anchors (Page?)
591 if (qobject_cast<UCPageTreeNode*>(child.item)) {
592 // unset left anchor
593 anchors->resetLeft();
594 }
595 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
596 if (usedAnchors & QQuickAnchors::LeftAnchor ||
597 usedAnchors & QQuickAnchors::RightAnchor ||
598 usedAnchors & QQuickAnchors::HCenterAnchor ||
599 anchors->fill() || anchors->centerIn()) {
600 anchorConflict = true;
601 break;
602 }
603 }
604 }
605 }
606 if (anchorConflict) {
607 qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside SplitView."
608 << " SplitView will not function.";
609 }
610}
611
612void SplitView::componentComplete()
613{
614 Q_D(SplitView);
615 d->changeLayout();
616 QQuickBasePositioner::componentComplete();
617}
618
619void SplitView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
620{
621 QQuickBasePositioner::geometryChanged(newGeometry, oldGeometry);
622 // if we have fillWidths, recalculate those!
623 // call this on horizontal resize, vertical one will do its job
624 if (newGeometry.width() != oldGeometry.width()) {
625 Q_D(SplitView);
626 d->recalculateWidths(SplitViewPrivate::CalculateFillWidth);
627 }
628}
629
630void SplitView::itemChange(ItemChange change, const ItemChangeData &data)
631{
632 QQuickBasePositioner::itemChange(change, data);
633 // we must exclude Repeater
634 switch (change) {
635 case ItemChildAddedChange:
636 if (data.item && !data.item->inherits("QQuickRepeater")) {
637 // attach properties and configure
638 SplitViewAttached *attached = static_cast<SplitViewAttached*>(
639 qmlAttachedPropertiesObject<SplitView>(data.item, true));
640
641 Q_D(SplitView);
642 SplitViewAttachedPrivate::get(attached)->configure(this, d->viewCount++);
643
644 // attach the split handler to it
645 SplitViewHandler *handler = new SplitViewHandler(data.item);
646 handler->connectToView(this);
647 }
648 break;
649 case ItemChildRemovedChange:
650 if (data.item && !data.item->inherits("QQuickRepeater")) {
651 Q_D(SplitView);
652 d->viewCount--;
653 }
654 break;
655 default: // ommit the rest
656 break;
657 }
658}
659
660/******************************************************************
661 * properties
662 */
663
664void SplitViewPrivate::setHandle(QQmlComponent *delegate)
665{
666 if (handleDelegate == delegate) {
667 return;
668 }
669 handleDelegate = delegate;
670 Q_EMIT q_func()->handleDelegateChanged();
671}
672
673UT_NAMESPACE_END
674
675#include "moc_splitview_p.cpp"
0676
=== added file 'src/Ubuntu/UbuntuToolkit/splitview_p.h'
--- src/Ubuntu/UbuntuToolkit/splitview_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/splitview_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,160 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Zsombor Egri <zsombor.egri@canonical.com>
17 */
18
19#ifndef SPLITVIEW_P_H
20#define SPLITVIEW_P_H
21
22#include <QtQuick/private/qquickpositioners_p.h>
23
24#include "ubuntutoolkitglobal.h"
25
26UT_NAMESPACE_BEGIN
27
28class ViewColumnPrivate;
29class ViewColumn : public QObject, public QQmlParserStatus
30{
31 Q_OBJECT
32 Q_INTERFACES(QQmlParserStatus)
33 Q_PRIVATE_PROPERTY(ViewColumn::d_func(), bool fillWidth MEMBER fillWidth WRITE setFillWidth NOTIFY fillWidthChanged)
34 Q_PRIVATE_PROPERTY(ViewColumn::d_func(), qreal minimumWidth MEMBER minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged)
35 Q_PRIVATE_PROPERTY(ViewColumn::d_func(), qreal maximumWidth MEMBER maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged)
36 Q_PRIVATE_PROPERTY(ViewColumn::d_func(), qreal preferredWidth MEMBER preferredWidth WRITE setPreferredWidth NOTIFY preferredWidthChanged)
37public:
38 explicit ViewColumn(QObject *parent = 0);
39
40 bool resize(qreal delta);
41
42Q_SIGNALS:
43 void minimumWidthChanged();
44 void maximumWidthChanged();
45 void preferredWidthChanged();
46 void fillWidthChanged();
47
48protected:
49 // from QQmlParserStatus
50 void classBegin() override {}
51 void componentComplete() override;
52private:
53 Q_DECLARE_PRIVATE(ViewColumn)
54};
55
56class SplitViewLayoutPrivate;
57class SplitViewLayout : public QObject
58{
59 Q_OBJECT
60
61 Q_PRIVATE_PROPERTY(SplitViewLayout::d_func(), bool when MEMBER when NOTIFY whenChanged)
62#ifdef Q_QDOC
63 Q_PRIVATE_PROPERTY(SplitViewLayout::d_func(), QQmlListProperty<ViewColumn> columns READ columns NOTIFY columnsChanged DESIGNABLE false)
64#else
65 Q_PRIVATE_PROPERTY(SplitViewLayout::d_func(), QQmlListProperty<UT_PREPEND_NAMESPACE(ViewColumn)> columns READ columns NOTIFY columnsChanged DESIGNABLE false)
66#endif
67 Q_CLASSINFO("DefaultProperty", "columns")
68public:
69 explicit SplitViewLayout(QObject *parent = 0);
70
71Q_SIGNALS:
72 void whenChanged();
73 void columnsChanged();
74
75private:
76 Q_DECLARE_PRIVATE(SplitViewLayout)
77};
78
79class SplitView;
80class SplitViewAttachedPrivate;
81class SplitViewAttached : public QObject
82{
83 Q_OBJECT
84 Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), int column READ getColumn NOTIFY columnChanged)
85#ifdef Q_QDOC
86 Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), SplitView* view READ view)
87 Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), ViewColumn* columnConfig READ config NOTIFY columnChanged)
88#else
89 Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), UT_PREPEND_NAMESPACE(SplitView*) view READ view)
90 Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), UT_PREPEND_NAMESPACE(ViewColumn*) columnConfig READ config NOTIFY columnChanged)
91#endif
92public:
93 explicit SplitViewAttached(QObject *parent = 0);
94
95 static SplitViewAttached *get(QQuickItem *item);
96
97 void resize(qreal delta);
98
99Q_SIGNALS:
100 void columnChanged();
101
102private:
103 Q_DECLARE_PRIVATE(SplitViewAttached)
104};
105
106class SplitViewPrivate;
107class SplitView : public QQuickBasePositioner
108{
109 Q_OBJECT
110#ifdef Q_QDOC
111 Q_PRIVATE_PROPERTY(SplitView::d_func(), QQmlListProperty<SplitViewLayout> layouts READ layouts NOTIFY layoutsChanged DESIGNABLE false)
112 Q_PRIVATE_PROPERTY(SplitView::d_func(), SplitViewLayout *activeLayout READ getActiveLayout NOTIFY activeLayoutChanged)
113#else
114 Q_PRIVATE_PROPERTY(SplitView::d_func(), QQmlListProperty<UT_PREPEND_NAMESPACE(SplitViewLayout)> layouts READ layouts NOTIFY layoutsChanged DESIGNABLE false)
115 Q_PRIVATE_PROPERTY(SplitView::d_func(), UT_PREPEND_NAMESPACE(SplitViewLayout) *activeLayout READ getActiveLayout NOTIFY activeLayoutChanged)
116#endif
117 Q_PRIVATE_PROPERTY(SplitView::d_func(), QQmlComponent *handleDelegate MEMBER handleDelegate WRITE setHandle NOTIFY handleDelegateChanged)
118 // overrides
119 Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing2 NOTIFY spacingChanged2)
120public:
121 explicit SplitView(QQuickItem *parent = 0);
122
123 static UT_PREPEND_NAMESPACE(SplitViewAttached) *qmlAttachedProperties(QObject*);
124
125Q_SIGNALS:
126 void layoutsChanged();
127 void activeLayoutChanged();
128 void handleDelegateChanged();
129 void spacingChanged2();
130
131protected:
132 SplitView(SplitViewPrivate &, QQuickItem *);
133 ~SplitView();
134
135 // property setters
136 void setSpacing2(qreal spacing, bool reset = true);
137
138 // from QQuickBasePositioner
139 void doPositioning(QSizeF *contentSize) override;
140 void reportConflictingAnchors() override;
141
142 // overrides
143 void componentComplete() override;
144 void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
145 void itemChange(ItemChange, const ItemChangeData &) override;
146private:
147 // QQuickBasePositionerPrivate is not an exported API, therefore we cannot derive from it
148 SplitViewPrivate* const d_ptr;
149 Q_DECLARE_PRIVATE_D(d_ptr, SplitView)
150 Q_PRIVATE_SLOT(d_func(), void changeLayout())
151};
152
153UT_NAMESPACE_END
154
155QML_DECLARE_TYPE(UT_PREPEND_NAMESPACE(ViewColumn))
156QML_DECLARE_TYPE(UT_PREPEND_NAMESPACE(SplitViewLayout))
157QML_DECLARE_TYPE(UT_PREPEND_NAMESPACE(SplitView))
158QML_DECLARE_TYPEINFO(UT_PREPEND_NAMESPACE(SplitView), QML_HAS_ATTACHED_PROPERTIES)
159
160#endif // SPLITVIEW_P_H
0161
=== added file 'src/Ubuntu/UbuntuToolkit/splitview_p_p.h'
--- src/Ubuntu/UbuntuToolkit/splitview_p_p.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/splitview_p_p.h 2016-09-03 13:06:01 +0000
@@ -0,0 +1,154 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Zsombor Egri <zsombor.egri@canonical.com>
17 */
18
19#ifndef SPLITVIEW_P_P_H
20#define SPLITVIEW_P_P_H
21
22#include "splitview_p.h"
23#include <QtCore/private/qobject_p.h>
24
25UT_NAMESPACE_BEGIN
26
27class ViewColumnPrivate : public QObjectPrivate
28{
29 Q_DECLARE_PUBLIC(ViewColumn)
30
31public:
32 ViewColumnPrivate() {}
33
34 static ViewColumnPrivate *get(ViewColumn *q)
35 {
36 return q ? q->d_func() : nullptr;
37 }
38
39 void setMinimumWidth(qreal width);
40 void setMaximumWidth(qreal width);
41 void setPreferredWidth(qreal width, bool notify = true);
42 void setFillWidth(bool fill);
43
44 void recalculateLayoutContent();
45
46 qreal minimumWidth{0.0};
47 qreal maximumWidth{std::numeric_limits<qreal>::max()};
48 qreal preferredWidth{0.0};
49 int column{-1};
50 bool fillWidth{false};
51 bool resized{false};
52 bool completed{false};
53};
54
55class SplitViewLayoutPrivate : public QObjectPrivate
56{
57 Q_DECLARE_PUBLIC(SplitViewLayout)
58public:
59 SplitViewLayoutPrivate() {}
60 static SplitViewLayoutPrivate *get(SplitViewLayout *q)
61 {
62 return q->d_func();
63 }
64
65 QQmlListProperty<UT_PREPEND_NAMESPACE(ViewColumn)> columns();
66
67 QList<ViewColumn*> columnData;
68 bool when{false};
69
70private:
71 static void columns_Append(QQmlListProperty<ViewColumn> *, ViewColumn*);
72 static int columns_Count(QQmlListProperty<ViewColumn> *);
73 static ViewColumn *columns_At(QQmlListProperty<ViewColumn> *, int);
74 static void columns_Clear(QQmlListProperty<ViewColumn> *);
75};
76
77class SplitViewAttachedPrivate : public QObjectPrivate
78{
79 Q_DECLARE_PUBLIC(SplitViewAttached)
80public:
81 SplitViewAttachedPrivate() {}
82
83 static SplitViewAttachedPrivate *get(SplitViewAttached *q)
84 {
85 return q->d_func();
86 }
87 static ViewColumn *getConfig(QQuickItem *attachee);
88
89 UT_PREPEND_NAMESPACE(SplitView*) view() const
90 {
91 return splitView;
92 }
93 int getColumn() const
94 {
95 return column;
96 }
97 void configure(SplitView *view, int column);
98 UT_PREPEND_NAMESPACE(ViewColumn*) config();
99
100 SplitView *splitView{nullptr};
101 int column{-1};
102};
103
104class SplitViewPrivate
105{
106 SplitView *const q_ptr{nullptr};
107 Q_DECLARE_PUBLIC(SplitView)
108
109public:
110 enum RelayoutOperation {
111 SetPreferredSize = 0x01,
112 CalculateFillWidth = 0x02,
113 RecalculateAll = 0xFF
114 };
115
116 SplitViewPrivate(SplitView *qq);
117 virtual ~SplitViewPrivate();
118 void init();
119
120 static SplitViewPrivate *get(SplitView *q)
121 {
122 return q->d_func();
123 }
124
125 QQmlListProperty<QObject> data();
126 QQmlListProperty<UT_PREPEND_NAMESPACE(SplitViewLayout)> layouts();
127 UT_PREPEND_NAMESPACE(SplitViewLayout) *getActiveLayout();
128
129 void updateLayout();
130 void recalculateWidths(RelayoutOperation operation);
131 void setHandle(QQmlComponent *delegate);
132
133 // private slots
134 void changeLayout();
135
136 // members
137 QList<SplitViewLayout*> columnLatouts;
138 SplitViewLayout* activeLayout{nullptr};
139 QQmlComponent *handleDelegate{nullptr};
140 QMetaObject::Connection *defaultSpacing{nullptr};
141 int viewCount{0};
142 bool dirty{false};
143
144private:
145 static void layout_Append(QQmlListProperty<SplitViewLayout> *, SplitViewLayout*);
146 static int layout_Count(QQmlListProperty<SplitViewLayout> *);
147 static SplitViewLayout *layout_At(QQmlListProperty<SplitViewLayout> *, int);
148 static void layout_Clear(QQmlListProperty<SplitViewLayout> *);
149};
150
151UT_NAMESPACE_END
152
153#endif // SPLITVIEW_P_P_H
154
0155
=== added file 'src/Ubuntu/UbuntuToolkit/splitviewlayout.cpp'
--- src/Ubuntu/UbuntuToolkit/splitviewlayout.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/UbuntuToolkit/splitviewlayout.cpp 2016-09-03 13:06:01 +0000
@@ -0,0 +1,252 @@
1/* Copyright 2016 Canonical Ltd.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * Author: Zsombor Egri <zsombor.egri@canonical.com>
16 */
17
18#include <QtQuick/private/qquickitem_p.h>
19#include <QtQuick/private/qquickanchors_p.h>
20#include <QtQml/QQmlInfo>
21
22#include "splitview_p.h"
23#include "splitview_p_p.h"
24#include "ucmathutils_p.h"
25
26UT_NAMESPACE_BEGIN
27
28/******************************************************************************
29 * ViewColumn configuration object
30 */
31/*!
32 * \qmltype ViewColumn
33 * \inmodule Ubuntu.Components.Labs
34 * \ingroup ubuntu-labs
35 * \brief View column metrics configuration for SplitView.
36 *
37 * The component provides width metrics configuration for SplitView layout
38 * columns. The values are applied on columns by an active SplitViewLayout.
39 * On resizing, the values are preserved for the entire lifetime of the
40 * component, even when the active layout is changed into an other one.
41 * When changed back, the previous values will be used.
42 */
43ViewColumn::ViewColumn(QObject *parent)
44 : QObject(*(new ViewColumnPrivate), parent)
45{
46}
47
48void ViewColumn::componentComplete()
49{
50 // check preferredWidth, its value may need fixing
51 Q_D(ViewColumn);
52 d->setPreferredWidth(d->preferredWidth);
53 d->completed = true;
54}
55
56void ViewColumnPrivate::recalculateLayoutContent()
57{
58 SplitViewLayout *layout = qobject_cast<SplitViewLayout*>(parent);
59 if (!layout) {
60 qFatal("ViewColumn declared outside of SplitViewLayout");
61 }
62 SplitView *view = qobject_cast<SplitView*>(SplitViewLayoutPrivate::get(layout)->parent);
63 if (!view) {
64 qFatal("SplitViewLayout not used in any SplitView");
65 }
66
67 SplitViewPrivate *dView = SplitViewPrivate::get(view);
68 if (dView->activeLayout == layout) {
69 dView->recalculateWidths(SplitViewPrivate::RecalculateAll);
70 }
71}
72
73/*!
74 * \qmlproperty real ViewColumn::minimumWidth
75 * Specifies the minimum width of the column. The number must be a positive value
76 * and less or equal than the maximumWidth value.
77 */
78void ViewColumnPrivate::setMinimumWidth(qreal width)
79{
80 if (qFuzzyCompare(minimumWidth, width)) {
81 return;
82 }
83 if (width < 0.0) {
84 qmlInfo(q_func()) << "minimumWidth cannot be a negative value";
85 return;
86 }
87 if (width > maximumWidth) {
88 qmlInfo(q_func()) << "minimumWidth is greater than maximumWidth";
89 return;
90 }
91 minimumWidth = width;
92 Q_EMIT q_func()->minimumWidthChanged();
93 // clamp preferredWidth if needed
94 setPreferredWidth(preferredWidth);
95 recalculateLayoutContent();
96}
97
98/*!
99 * \qmlproperty real ViewColumn::maximumWidth
100 * Specifies the maximum width of the column. The number must be a positive value
101 * and bigger than the minimumWidth value.
102 */
103void ViewColumnPrivate::setMaximumWidth(qreal width)
104{
105 if (qFuzzyCompare(maximumWidth, width)) {
106 return;
107 }
108 if (width < 0.0) {
109 qmlInfo(q_func()) << "maximumWidth cannot be a negative value";
110 return;
111 }
112 if (width < minimumWidth) {
113 qmlInfo(q_func()) << "maximumWidth is smaller than minimumWidth";
114 return;
115 }
116 maximumWidth = width;
117 Q_EMIT q_func()->maximumWidthChanged();
118 setPreferredWidth(preferredWidth);
119 recalculateLayoutContent();
120}
121
122/*!
123 * \qmlproperty real ViewColumn::preferredWidth
124 * The property holds the preferred width of the column. The value must be situated
125 * in between minimumWidth and maximumWidth. In case fillWidth is set, the value will
126 * hold the actual width of the column, but setting its value will not affect the
127 * width of the column.
128 */
129void ViewColumnPrivate::setPreferredWidth(qreal width, bool notify)
130{
131 // clamp
132 width = UCMathUtils::clamp(width, minimumWidth, maximumWidth);
133 if (qFuzzyCompare(preferredWidth, width)) {
134 return;
135 }
136 preferredWidth = width;
137 if (notify) {
138 Q_EMIT q_func()->preferredWidthChanged();
139 recalculateLayoutContent();
140 }
141}
142
143/*!
144 * \qmlproperty bool ViewColumn::fillWidth
145 * If set, the column width will take the space available after all the other
146 * columns with non-fill width are configured. This means that if there is more
147 * than one column configured to fill width, the reminder width is split evenly
148 * between these columns. If all columns are configured to fill width, the colum
149 * widths will be split evenly between all the columns.
150 * \note When a column configured with fillWidth is resized, the properties will
151 * not be altered, but the fillWidth wioll no longer be taken into account. Instead,
152 * the preferredWidth will drive the width of that column from that point on.
153 */
154void ViewColumnPrivate::setFillWidth(bool fill)
155{
156 if (fill == fillWidth) {
157 return;
158 }
159 fillWidth = fill;
160 Q_EMIT q_func()->fillWidthChanged();
161 recalculateLayoutContent();
162}
163
164bool ViewColumn::resize(qreal delta)
165{
166 Q_D(ViewColumn);
167 // apply limits
168 qreal newWidth = d->preferredWidth + delta;
169 // clamp
170 newWidth = UCMathUtils::clamp(newWidth, d->minimumWidth, d->maximumWidth);
171 if (newWidth != d->preferredWidth) {
172 d->resized = true;
173 d->setPreferredWidth(newWidth);
174 return true;
175 }
176 return false;
177}
178
179/******************************************************************************
180 * SplitViewLayout layouts configuration
181 */
182/*!
183 * \qmltype SplitViewLayout
184 * \inmodule Ubuntu.Components.Labs
185 * \ingroup ubuntu-labs
186 * \brief Layout configuration for SplitView.
187 *
188 * SplitViewLayout defines a layout configuration and the condition when the layout is
189 * expected to be applied. In case multiple layout conditions evaluate to true, the first
190 * one in the list will be activated.
191 */
192SplitViewLayout::SplitViewLayout(QObject *parent)
193 : QObject(*(new SplitViewLayoutPrivate), parent)
194{
195}
196
197void SplitViewLayoutPrivate::columns_Append(QQmlListProperty<ViewColumn> *list, ViewColumn* data)
198{
199 SplitViewLayout *layout = static_cast<SplitViewLayout*>(list->object);
200 SplitViewLayoutPrivate *d = SplitViewLayoutPrivate::get(layout);
201 ViewColumnPrivate::get(data)->column = d->columnData.size();
202 // make sure ViewColumn is parented to the layout definition
203 data->setParent(layout);
204 d->columnData.append(data);
205 Q_EMIT layout->columnsChanged();
206}
207int SplitViewLayoutPrivate::columns_Count(QQmlListProperty<ViewColumn> *list)
208{
209 SplitViewLayout *layout = static_cast<SplitViewLayout*>(list->object);
210 SplitViewLayoutPrivate *d = SplitViewLayoutPrivate::get(layout);
211 return d->columnData.size();
212}
213ViewColumn *SplitViewLayoutPrivate::columns_At(QQmlListProperty<ViewColumn> *list, int index)
214{
215 SplitViewLayout *layout = static_cast<SplitViewLayout*>(list->object);
216 SplitViewLayoutPrivate *d = SplitViewLayoutPrivate::get(layout);
217 return d->columnData.at(index);
218}
219void SplitViewLayoutPrivate::columns_Clear(QQmlListProperty<ViewColumn> *list)
220{
221 SplitViewLayout *layout = static_cast<SplitViewLayout*>(list->object);
222 SplitViewLayoutPrivate *d = SplitViewLayoutPrivate::get(layout);
223 qDeleteAll(d->columnData);
224 d->columnData.clear();
225 Q_EMIT layout->columnsChanged();
226}
227
228/*!
229 * \qmlproperty list<ViewColumn> SplitViewLayout::columns
230 * \default
231 * The property holds the column configurations for the layout. If the view has more
232 * columns than the configuration specifies, the extra columns will be hidden (their
233 * visible property will be set to false!). Also, the hidden column sizes may change,
234 * therefore size-sensitive content must be aware of this.
235 */
236QQmlListProperty<UT_PREPEND_NAMESPACE(ViewColumn)> SplitViewLayoutPrivate::columns()
237{
238 Q_Q(SplitViewLayout);
239 return QQmlListProperty<UT_PREPEND_NAMESPACE(ViewColumn)>(q, &columnData,
240 &columns_Append,
241 &columns_Count,
242 &columns_At,
243 &columns_Clear);
244}
245
246/*!
247 * \qmlproperty bool SplitViewLayout::when
248 * Specifies the condition when to apply the layout. Usually holds a binding which
249 * evaluates to true or false to activate the layout.
250 */
251
252UT_NAMESPACE_END
0253
=== modified file 'src/Ubuntu/UbuntuToolkit/ubuntutoolkitmodule.cpp'
--- src/Ubuntu/UbuntuToolkit/ubuntutoolkitmodule.cpp 2016-08-06 00:55:32 +0000
+++ src/Ubuntu/UbuntuToolkit/ubuntutoolkitmodule.cpp 2016-09-03 13:06:01 +0000
@@ -89,6 +89,13 @@
89#include <privates/ucpagewrapper_p.h>89#include <privates/ucpagewrapper_p.h>
90#include <privates/appheaderbase_p.h>90#include <privates/appheaderbase_p.h>
91#include <privates/ucscrollbarutils_p.h>91#include <privates/ucscrollbarutils_p.h>
92#include <actionlist_p.h>
93#include <exclusivegroup_p.h>
94#include <menu_p.h>
95#include <menubar_p.h>
96#include <menugroup_p.h>
97
98#include <splitview_p.h>
9299
93// styles100// styles
94#include <ucbottomedgestyle_p.h>101#include <ucbottomedgestyle_p.h>
@@ -374,6 +381,8 @@
374 qmlRegisterType<UCPageTreeNode>(uri, 1, 3, "PageTreeNode");381 qmlRegisterType<UCPageTreeNode>(uri, 1, 3, "PageTreeNode");
375 qmlRegisterType<UCPopupContext>(uri, 1, 3, "PopupContext");382 qmlRegisterType<UCPopupContext>(uri, 1, 3, "PopupContext");
376 qmlRegisterType<UCMainViewBase>(uri, 1, 3, "MainViewBase");383 qmlRegisterType<UCMainViewBase>(uri, 1, 3, "MainViewBase");
384 qmlRegisterType<ActionList>(uri, 1, 3, "ActionList");
385 qmlRegisterType<ExclusiveGroup>(uri, 1, 3, "ExclusiveGroup");
377}386}
378387
379void UbuntuToolkitModule::undefineModule()388void UbuntuToolkitModule::undefineModule()
@@ -404,15 +413,20 @@
404 */413 */
405void UbuntuLabsModule::initializeModule(QQmlEngine *engine, QQmlExtensionPlugin *plugin)414void UbuntuLabsModule::initializeModule(QQmlEngine *engine, QQmlExtensionPlugin *plugin)
406{415{
407 Q_UNUSED(engine);
408 Q_UNUSED(plugin);416 Q_UNUSED(plugin);
417
418 // qmlplugindump requires that quickutils is initialized.
419 QuickUtils::instance(engine);
409}420}
410421
411void UbuntuLabsModule::defineModule(const char *uri)422void UbuntuLabsModule::defineModule(const char *uri)
412{423{
413 Q_UNUSED(uri);424 qmlRegisterType<SplitView>(uri, 1, 0, "SplitView");
414 // a fake component so we can have the module types file created425 qmlRegisterType<SplitViewLayout>(uri, 1, 0, "SplitViewLayout");
415 qmlRegisterType<QObject>(uri, 1, 0, "ZiObject");426 qmlRegisterType<ViewColumn>(uri, 1, 0, "ViewColumn");
427 qmlRegisterType<Menu>(uri, 1, 0, "Menu");
428 qmlRegisterType<MenuBar>(uri, 1, 0, "MenuBar");
429 qmlRegisterType<MenuGroup>(uri, 1, 0, "MenuGroup");
416}430}
417431
418void UbuntuLabsModule::undefineModule()432void UbuntuLabsModule::undefineModule()
419433
=== modified file 'src/Ubuntu/UbuntuToolkit/ucaction.cpp'
--- src/Ubuntu/UbuntuToolkit/ucaction.cpp 2016-07-07 07:21:48 +0000
+++ src/Ubuntu/UbuntuToolkit/ucaction.cpp 2016-09-03 13:06:01 +0000
@@ -17,6 +17,7 @@
17#include "ucaction_p.h"17#include "ucaction_p.h"
18#include "quickutils_p.h"18#include "quickutils_p.h"
19#include "ucactioncontext_p.h"19#include "ucactioncontext_p.h"
20#include "exclusivegroup_p.h"
2021
21#include <QtDebug>22#include <QtDebug>
22#include <QtQml/QQmlInfo>23#include <QtQml/QQmlInfo>
@@ -149,6 +150,18 @@
149 * text: "&Call"150 * text: "&Call"
150 * }151 * }
151 * \endqml152 * \endqml
153 *
154 * \section2 Checkable property
155 * Since Ubuntu.Components 1.3 Action supports the checkable/checked properties.
156 * \qml
157 * Button {
158 * action: Action {
159 * checkable: true
160 * checked: false
161 * }
162 * color: action.checked ? UbuntuColor.green : UbuntuColor.red
163 * }
164 * \endqml
152 */165 */
153166
154/*!167/*!
@@ -160,6 +173,14 @@
160 */173 */
161174
162/*!175/*!
176 * \qmlsignal Action::toggled(bool value)
177 * Signal called when the action's checked property changes.
178 * \note The toggled signal should be used for checkable actions rather than the
179 * triggered signal.
180 * \sa Action::checkable, Action::checked, ExclusiveGroup
181 */
182
183/*!
163 * \qmlproperty string Action::description184 * \qmlproperty string Action::description
164 * User visible secondary description for the action. Description is more verbose185 * User visible secondary description for the action. Description is more verbose
165 * than the \l text and should describe the Action with couple of words.186 * than the \l text and should describe the Action with couple of words.
@@ -250,51 +271,17 @@
250 * \endqml271 * \endqml
251 */272 */
252273
253/*!
254 * \qmlproperty enum Action::parameterType
255 * Type of the parameter passed to \l trigger and \l triggered.
256 * Type is an enumeration:
257 * \list
258 * \li \b Action.None: No paramater. (default)
259 * \li \b Action.String: String parameter.
260 * \li \b Action.Integer: Integer parameter.
261 * \li \b Action.Bool: Boolean parameter.
262 * \li \b Action.Real: Single precision floating point parameter.
263 * \li \b Action.Object: The parameter is an object.
264 * \endlist
265 * \qml
266 * Action {
267 * id: action
268 * parameterType: Action.String
269 * onTriggered: {
270 * // value arguments now contain strings
271 * console.log(value);
272 * }
273 * Component.onCompleted: action.trigger("Hello World")
274 * }
275 * \endqml
276 */
277
278/*!
279 * \qmlproperty bool Action::enabled
280 * If set to false the action can not be triggered. Components visualizing the
281 * action migth either hide the action or make it insensitive. However visibility
282 * can be controlled separately using the \l visible property.
283 */
284
285/*!
286 * \qmlproperty bool Action::visible
287 * Specifies whether the action is visible to the user. Defaults to true.
288 */
289
290UCAction::UCAction(QObject *parent)274UCAction::UCAction(QObject *parent)
291 : QObject(parent)275 : QObject(parent)
276 , m_exclusiveGroup(Q_NULLPTR)
292 , m_itemHint(Q_NULLPTR)277 , m_itemHint(Q_NULLPTR)
293 , m_parameterType(None)278 , m_parameterType(None)
294 , m_factoryIconSource(true)279 , m_factoryIconSource(true)
295 , m_enabled(true)280 , m_enabled(true)
296 , m_visible(true)281 , m_visible(true)
297 , m_published(false)282 , m_published(false)
283 , m_checkable(false)
284 , m_checked(false)
298{285{
299 generateName();286 generateName();
300 // FIXME: we need QInputDeviceInfo to detect the keyboard attechment287 // FIXME: we need QInputDeviceInfo to detect the keyboard attechment
@@ -436,6 +423,163 @@
436 Q_EMIT shortcutChanged();423 Q_EMIT shortcutChanged();
437}424}
438425
426/*!
427 * \qmlproperty bool Action::visible
428 * Specifies whether the action is visible to the user. Defaults to true.
429 */
430void UCAction::setVisible(bool visible)
431{
432 if (m_visible == visible) {
433 return;
434 }
435 m_visible = visible;
436 Q_EMIT visibleChanged();
437}
438
439/*!
440 * \qmlproperty bool Action::enabled
441 * If set to false the action can not be triggered. Components visualizing the
442 * action migth either hide the action or make it insensitive. However visibility
443 * can be controlled separately using the \l visible property.
444 */
445void UCAction::setEnabled(bool enabled)
446{
447 if (m_enabled == enabled) {
448 return;
449 }
450 m_enabled = enabled;
451 Q_EMIT enabledChanged();
452
453}
454
455/*!
456 * \qmlproperty enum Action::parameterType
457 * Type of the parameter passed to \l trigger and \l triggered.
458 * Type is an enumeration:
459 * \list
460 * \li \b Action.None: No paramater. (default)
461 * \li \b Action.String: String parameter.
462 * \li \b Action.Integer: Integer parameter.
463 * \li \b Action.Bool: Boolean parameter.
464 * \li \b Action.Real: Single precision floating point parameter.
465 * \li \b Action.Object: The parameter is an object.
466 * \endlist
467 * \qml
468 * Action {
469 * id: action
470 * parameterType: Action.String
471 * onTriggered: {
472 * // value arguments now contain strings
473 * console.log(value);
474 * }
475 * Component.onCompleted: action.trigger("Hello World")
476 * }
477 * \endqml
478 */
479void UCAction::setParameterType(UCAction::Type type)
480{
481 if (m_parameterType == type) {
482 return;
483 }
484 m_parameterType = type;
485 Q_EMIT parameterTypeChanged();
486}
487
488/*!
489 * \qmlproperty bool Action::checkable
490 * \since Ubuntu.Components 1.3
491 * Whether the action can be checked. Defaults to false.
492 * \sa Action::checked, Action::toggled, ExclusiveGroup
493 */
494void UCAction::setCheckable(bool checkable)
495{
496 if (m_checkable == checkable) {
497 return;
498 }
499 m_checkable = checkable;
500 Q_EMIT checkableChanged();
501
502 // If the Action is already checked, assert the check state.
503 if (m_checked)
504 Q_EMIT toggled(m_checkable);
505}
506
507/*!
508 * \qmlproperty bool Action::checked
509 * \since Ubuntu.Components 1.3
510 * If the action is checkable, this property reflects its checked state. Defaults to false.
511 * Its value is also false while checkable is false.
512 * \sa Action::checkable, Action::toggled, ExclusiveGroup
513 */
514void UCAction::setChecked(bool checked)
515{
516 if (m_checked == checked) {
517 return;
518 }
519 m_checked = checked;
520
521 if (m_checkable) {
522 Q_EMIT toggled(checked);
523 }
524}
525
526/*!
527 * \qmlproperty ExclusiveGroup Action::exclusiveGroup
528 * \since Ubuntu.Components 1.3
529 * The \l ExclusiveGroup associated with this action.
530 * An exclusive group allows the \l checked property to belinked to other actions,
531 * as in radio controls.
532 * \qml
533 * Column {
534 * ExclusiveGroup {
535 * Action {
536 * id: action1
537 * checkable: true
538 * checked: true
539 * }
540 * Action {
541 * id: action2
542 * checkable: true
543 * }
544 * Action {
545 * id: action3
546 * checkable: true
547 * }
548 * }
549 *
550 * Button {
551 * action: action1
552 * color: action.checked ? UbuntuColor.green : UbuntuColor.red
553 * }
554 * Button {
555 * action: action2
556 * color: action.checked ? UbuntuColor.green : UbuntuColor.red
557 * }
558 * Button {
559 * action: action3
560 * color: action.checked ? UbuntuColor.green : UbuntuColor.grey
561 * }
562 * }
563 * \endqml
564 */
565void UCAction::setExclusiveGroup(ExclusiveGroup *exclusiveGroup)
566{
567 if (m_exclusiveGroup == exclusiveGroup) {
568 return;
569 }
570
571 if (m_exclusiveGroup) {
572 m_exclusiveGroup->unbindCheckable(this);
573 }
574
575 m_exclusiveGroup = exclusiveGroup;
576
577 if (m_exclusiveGroup) {
578 m_exclusiveGroup->bindCheckable(this);
579 }
580 Q_EMIT exclusiveGroupChanged();
581}
582
439bool UCAction::event(QEvent *event)583bool UCAction::event(QEvent *event)
440{584{
441 if (event->type() != QEvent::Shortcut)585 if (event->type() != QEvent::Shortcut)
@@ -475,6 +619,11 @@
475 if (!m_enabled) {619 if (!m_enabled) {
476 return;620 return;
477 }621 }
622
623 if (m_checkable && !(m_checked && m_exclusiveGroup)) {
624 setChecked(!m_checked);
625 }
626
478 if (!isValidType(value.type())) {627 if (!isValidType(value.type())) {
479 Q_EMIT triggered(QVariant());628 Q_EMIT triggered(QVariant());
480 } else {629 } else {
481630
=== modified file 'src/Ubuntu/UbuntuToolkit/ucaction_p.h'
--- src/Ubuntu/UbuntuToolkit/ucaction_p.h 2016-07-07 07:21:48 +0000
+++ src/Ubuntu/UbuntuToolkit/ucaction_p.h 2016-09-03 13:06:01 +0000
@@ -53,7 +53,7 @@
53 }53 }
54}54}
5555
56class UCActionAttached;56class ExclusiveGroup;
57class UBUNTUTOOLKIT_EXPORT UCAction : public QObject57class UBUNTUTOOLKIT_EXPORT UCAction : public QObject
58{58{
59 Q_OBJECT59 Q_OBJECT
@@ -62,19 +62,23 @@
62 Q_ENUMS(Type)62 Q_ENUMS(Type)
63 Q_PROPERTY(QString name MEMBER m_name WRITE setName NOTIFY nameChanged)63 Q_PROPERTY(QString name MEMBER m_name WRITE setName NOTIFY nameChanged)
64 Q_PROPERTY(QString text READ text WRITE setText RESET resetText NOTIFY textChanged)64 Q_PROPERTY(QString text READ text WRITE setText RESET resetText NOTIFY textChanged)
65 Q_PROPERTY(QString iconName MEMBER m_iconName WRITE setIconName NOTIFY iconNameChanged)65 Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged)
66 Q_PROPERTY(QString description MEMBER m_description NOTIFY descriptionChanged)66 Q_PROPERTY(QString description MEMBER m_description NOTIFY descriptionChanged)
67 Q_PROPERTY(QString keywords MEMBER m_keywords NOTIFY keywordsChanged)67 Q_PROPERTY(QString keywords MEMBER m_keywords NOTIFY keywordsChanged)
68 Q_PROPERTY(bool enabled MEMBER m_enabled NOTIFY enabledChanged)68 Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
69 Q_PROPERTY(Type parameterType MEMBER m_parameterType NOTIFY parameterTypeChanged)69 Q_PROPERTY(Type parameterType READ parameterType WRITE setParameterType NOTIFY parameterTypeChanged)
70
71 Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged REVISION 1)
72 Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY toggled REVISION 1)
73 Q_PROPERTY(ExclusiveGroup* exclusiveGroup READ exclusiveGroup WRITE setExclusiveGroup NOTIFY exclusiveGroupChanged REVISION 1)
7074
71 // Toolkit Actions API75 // Toolkit Actions API
72 Q_PROPERTY(QUrl iconSource MEMBER m_iconSource WRITE setIconSource NOTIFY iconSourceChanged)76 Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource NOTIFY iconSourceChanged)
73 Q_PROPERTY(bool visible MEMBER m_visible NOTIFY visibleChanged)77 Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
74 Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint)78 Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint)
7579
76 // QtQuickControls.Action80 // QtQuickControls.Action
77 Q_PROPERTY(QVariant shortcut MEMBER m_shortcut WRITE setShortcut RESET resetShortcut NOTIFY shortcutChanged REVISION 1)81 Q_PROPERTY(QVariant shortcut READ shortcut WRITE setShortcut RESET resetShortcut NOTIFY shortcutChanged REVISION 1)
78public:82public:
79 enum Type {83 enum Type {
80 None,84 None,
@@ -108,11 +112,26 @@
108 QString text();112 QString text();
109 void setText(const QString &text);113 void setText(const QString &text);
110 void resetText();114 void resetText();
115 QString iconName() const { return m_iconName; }
111 void setIconName(const QString &name);116 void setIconName(const QString &name);
117 QUrl iconSource() const { return m_iconSource; }
112 void setIconSource(const QUrl &url);118 void setIconSource(const QUrl &url);
113 void setItemHint(QQmlComponent *);119 void setItemHint(QQmlComponent *);
120 QVariant shortcut() const { return m_shortcut; }
114 void setShortcut(const QVariant&);121 void setShortcut(const QVariant&);
115 void resetShortcut();122 void resetShortcut();
123 bool visible() const { return m_visible; }
124 void setVisible(bool visible);
125 void setEnabled(bool enabled);
126 void setParameterType(Type type);
127 Type parameterType() const { return m_parameterType; }
128 void setCheckable(bool checkable);
129 bool isCheckable() const { return m_checkable; }
130 void setChecked(bool checked);
131 bool isChecked() const { return m_checkable && m_checked; }
132
133 ExclusiveGroup *exclusiveGroup() const { return m_exclusiveGroup; }
134 void setExclusiveGroup(ExclusiveGroup *exclusiveGroup);
116135
117Q_SIGNALS:136Q_SIGNALS:
118 void nameChanged();137 void nameChanged();
@@ -125,13 +144,18 @@
125 void iconSourceChanged();144 void iconSourceChanged();
126 void visibleChanged();145 void visibleChanged();
127 void shortcutChanged();146 void shortcutChanged();
147 Q_REVISION(1) void checkableChanged();
148 Q_REVISION(1) void exclusiveGroupChanged();
149
128 void triggered(const QVariant &value);150 void triggered(const QVariant &value);
151 Q_REVISION(1) void toggled(bool value);
129152
130public Q_SLOTS:153public Q_SLOTS:
131 void trigger(const QVariant &value = QVariant());154 void trigger(const QVariant &value = QVariant());
132155
133private:156private:
134 QPODVector<QQuickItem*, 4> m_owningItems;157 QPODVector<QQuickItem*, 4> m_owningItems;
158 ExclusiveGroup *m_exclusiveGroup;
135 QString m_name;159 QString m_name;
136 QString m_text;160 QString m_text;
137 QString m_iconName;161 QString m_iconName;
@@ -146,6 +170,8 @@
146 bool m_enabled:1;170 bool m_enabled:1;
147 bool m_visible:1;171 bool m_visible:1;
148 bool m_published:1;172 bool m_published:1;
173 bool m_checkable:1;
174 bool m_checked:1;
149175
150 friend class UCActionContext;176 friend class UCActionContext;
151 friend class UCActionItem;177 friend class UCActionItem;
152178
=== modified file 'src/Ubuntu/UbuntuToolkit/uclistitem.cpp'
--- src/Ubuntu/UbuntuToolkit/uclistitem.cpp 2016-07-14 07:41:06 +0000
+++ src/Ubuntu/UbuntuToolkit/uclistitem.cpp 2016-09-03 13:06:01 +0000
@@ -537,7 +537,7 @@
537 * there will be no highlight happening if the click happens on the active component.537 * there will be no highlight happening if the click happens on the active component.
538 * \qml538 * \qml
539 * import QtQuick 2.4539 * import QtQuick 2.4
540 * import Ubuntu.Components 1.2540 * import Ubuntu.Components 1.3
541 *541 *
542 * MainView {542 * MainView {
543 * width: units.gu(40)543 * width: units.gu(40)
@@ -572,20 +572,29 @@
572 * onClicked: console.log("clicked on ListItem with trailingActions set")572 * onClicked: console.log("clicked on ListItem with trailingActions set")
573 * }573 * }
574 * ListItem {574 * ListItem {
575 * Label {575 * // shall specify the height when Using ListItemLayout inside ListItem
576 * text: "onClicked implemented"576 * height: clickImplementedLayout.height + (divider.visible ? divider.height : 0)
577 * ListItemLayout {
578 * id: clickImplementedLayout
579 * title.text: "onClicked implemented"
577 * }580 * }
578 * onClicked: console.log("clicked on ListItem with onClicked implemented")581 * onClicked: console.log("clicked on ListItem with onClicked implemented")
579 * }582 * }
580 * ListItem {583 * ListItem {
581 * Label {584 * // shall specify the height when Using ListItemLayout inside ListItem
582 * text: "onPressAndHold implemented"585 * height: pressHoldLayout.height + (divider.visible ? divider.height : 0)
586 * ListItemLayout {
587 * id: pressHoldLayout
588 * title.text: "onPressAndHold implemented"
583 * }589 * }
584 * onPressAndHold: console.log("long-pressed on ListItem with onPressAndHold implemented")590 * onPressAndHold: console.log("long-pressed on ListItem with onPressAndHold implemented")
585 * }591 * }
586 * ListItem {592 * ListItem {
587 * Label {593 * // shall specify the height when Using ListItemLayout inside ListItem
588 * text: "No highlight"594 * height: noHighlightLayout.height + (divider.visible ? divider.height : 0)
595 * ListItemLayout {
596 * id: noHighlightLayout
597 * title.text: "No highlight"
589 * }598 * }
590 * }599 * }
591 * }600 * }
@@ -671,7 +680,7 @@
671 * to the view itself.680 * to the view itself.
672 * \qml681 * \qml
673 * import QtQuick 2.4682 * import QtQuick 2.4
674 * import Ubuntu.Components 1.2683 * import Ubuntu.Components 1.3
675 *684 *
676 * Flickable {685 * Flickable {
677 * width: units.gu(40)686 * width: units.gu(40)
@@ -735,7 +744,7 @@
735 * Example of live drag implementation:744 * Example of live drag implementation:
736 * \qml745 * \qml
737 * import QtQuick 2.4746 * import QtQuick 2.4
738 * import Ubuntu.Components 1.2747 * import Ubuntu.Components 1.3
739 *748 *
740 * ListView {749 * ListView {
741 * model: ListModel {750 * model: ListModel {
@@ -746,8 +755,11 @@
746 * }755 * }
747 * }756 * }
748 * delegate: ListItem {757 * delegate: ListItem {
749 * Label {758 * // shall specify the height when Using ListItemLayout inside ListItem
750 * text: modelData759 * height: modelLayout.height + (divider.visible ? divider.height : 0)
760 * ListItemLayout {
761 * id: modelLayout
762 * title.text: modelData
751 * }763 * }
752 * color: dragMode ? "lightblue" : "lightgray"764 * color: dragMode ? "lightblue" : "lightgray"
753 * onPressAndHold: ListView.view.ViewItems.dragMode =765 * onPressAndHold: ListView.view.ViewItems.dragMode =
@@ -769,7 +781,7 @@
769 * Example of drag'n'drop implementation:781 * Example of drag'n'drop implementation:
770 * \qml782 * \qml
771 * import QtQuick 2.4783 * import QtQuick 2.4
772 * import Ubuntu.Components 1.2784 * import Ubuntu.Components 1.3
773 *785 *
774 * ListView {786 * ListView {
775 * model: ListModel {787 * model: ListModel {
@@ -780,8 +792,11 @@
780 * }792 * }
781 * }793 * }
782 * delegate: ListItem {794 * delegate: ListItem {
783 * Label {795 * // shall specify the height when Using ListItemLayout inside ListItem
784 * text: modelData796 * height: modelLayout.height + (divider.visible ? divider.height : 0)
797 * ListItemLayout {
798 * id: modelLayout
799 * title.text: modelData
785 * }800 * }
786 * color: dragMode ? "lightblue" : "lightgray"801 * color: dragMode ? "lightblue" : "lightgray"
787 * onPressAndHold: ListView.view.ViewItems.dragMode =802 * onPressAndHold: ListView.view.ViewItems.dragMode =
@@ -815,13 +830,16 @@
815 * can still be implemented with these kind of lists as well.830 * can still be implemented with these kind of lists as well.
816 * \qml831 * \qml
817 * import QtQuick 2.4832 * import QtQuick 2.4
818 * import Ubuntu.Components 1.2833 * import Ubuntu.Components 1.3
819 *834 *
820 * ListView {835 * ListView {
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: