Merge lp:~bzoltan/ubuntu-ui-toolkit/more_1618581 into lp:ubuntu-ui-toolkit
- more_1618581
- Merge into trunk
Proposed by
Zoltan Balogh
Status: | Superseded |
---|---|
Proposed branch: | lp:~bzoltan/ubuntu-ui-toolkit/more_1618581 |
Merge into: | lp:ubuntu-ui-toolkit |
Diff against target: |
7457 lines (+5769/-506) 68 files modified
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 (+14/-14) tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py (+2/-1) 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) |
To merge this branch: | bzr merge lp:~bzoltan/ubuntu-ui-toolkit/more_1618581 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu SDK team | Pending | ||
Review via email: mp+304454@code.launchpad.net |
This proposal has been superseded by a proposal from 2016-08-31.
Commit message
Fix the header tests. Fixes LP: #1618581
Description of the change
Fix the header tests. Fixes LP: #1618581
To post a comment you must log in.
Unmerged revisions
- 2089. By Zoltan Balogh
-
Fix the header tests. Fixes LP: #Bug #1618581
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'app-launch-profiler/app-launch-tracepoints.c' | |||
2 | --- app-launch-profiler/app-launch-tracepoints.c 2016-08-16 08:43:28 +0000 | |||
3 | +++ app-launch-profiler/app-launch-tracepoints.c 2016-08-31 08:57:26 +0000 | |||
4 | @@ -28,8 +28,8 @@ | |||
5 | 28 | 28 | ||
6 | 29 | int main (int argc, char* argv[]) | 29 | int main (int argc, char* argv[]) |
7 | 30 | { | 30 | { |
10 | 31 | #pragma unused(argc) | 31 | (void)argc; |
11 | 32 | #pragma unused(argv) | 32 | (void)argv; |
12 | 33 | tracepoint(app,invokeApplauncher); | 33 | tracepoint(app,invokeApplauncher); |
13 | 34 | return 0; | 34 | return 0; |
14 | 35 | } | 35 | } |
15 | 36 | 36 | ||
16 | === modified file 'components.api' | |||
17 | --- components.api 2016-08-09 03:48:53 +0000 | |||
18 | +++ components.api 2016-08-31 08:57:26 +0000 | |||
19 | @@ -10,13 +10,17 @@ | |||
20 | 10 | readonly property bool pressed | 10 | readonly property bool pressed |
21 | 11 | readonly property UCMargins sensingMargins | 11 | readonly property UCMargins sensingMargins |
22 | 12 | Ubuntu.Components.Action 1.3 1.0 0.1 UCAction: QtObject | 12 | Ubuntu.Components.Action 1.3 1.0 0.1 UCAction: QtObject |
23 | 13 | property bool checkable 1.3 | ||
24 | 14 | property bool checked 1.3 | ||
25 | 13 | property string description | 15 | property string description |
26 | 14 | property bool enabled | 16 | property bool enabled |
27 | 17 | property ExclusiveGroup exclusiveGroup 1.3 | ||
28 | 15 | property string iconName | 18 | property string iconName |
29 | 16 | property url iconSource | 19 | property url iconSource |
30 | 17 | property Component itemHint | 20 | property Component itemHint |
31 | 18 | property string keywords | 21 | property string keywords |
32 | 19 | signal triggered(var value) | 22 | signal triggered(var value) |
33 | 23 | signal toggled(bool value) 1.3 | ||
34 | 20 | function trigger(var value) | 24 | function trigger(var value) |
35 | 21 | function trigger() | 25 | function trigger() |
36 | 22 | property string name | 26 | property string name |
37 | @@ -59,9 +63,12 @@ | |||
38 | 59 | Ubuntu.Components.ActionList 1.0 0.1: QtObject | 63 | Ubuntu.Components.ActionList 1.0 0.1: QtObject |
39 | 60 | property list<Action> actions | 64 | property list<Action> actions |
40 | 61 | default property list<Action> children | 65 | default property list<Action> children |
44 | 62 | Ubuntu.Components.ActionList 1.3: QtObject | 66 | Ubuntu.Components.ActionList 1.3 ActionList: QtObject |
45 | 63 | property list<Action> actions | 67 | default property list<Action> actions |
46 | 64 | default property list<Action> children | 68 | signal added(Action action) |
47 | 69 | signal removed(Action action) | ||
48 | 70 | function addAction(Action action) | ||
49 | 71 | function removeAction(Action action) | ||
50 | 65 | Ubuntu.Components.ActionManager 1.0 0.1 UCActionManager: QtObject | 72 | Ubuntu.Components.ActionManager 1.0 0.1 UCActionManager: QtObject |
51 | 66 | default property list<Action> actions | 73 | default property list<Action> actions |
52 | 67 | readonly property ActionContext globalContext | 74 | readonly property ActionContext globalContext |
53 | @@ -458,6 +465,10 @@ | |||
54 | 458 | OperationPending | 465 | OperationPending |
55 | 459 | Ubuntu.Metrics.Event: Enum | 466 | Ubuntu.Metrics.Event: Enum |
56 | 460 | UserInterfaceReady | 467 | UserInterfaceReady |
57 | 468 | Ubuntu.Components.ExclusiveGroup 1.3 ExclusiveGroup: ActionList | ||
58 | 469 | readonly property QtObject current | ||
59 | 470 | function bindCheckable(QtObject object) | ||
60 | 471 | function unbindCheckable(QtObject object) | ||
61 | 461 | Ubuntu.Components.ListItems.Expandable 1.0 0.1: Empty | 472 | Ubuntu.Components.ListItems.Expandable 1.0 0.1: Empty |
62 | 462 | property bool collapseOnClick | 473 | property bool collapseOnClick |
63 | 463 | property double collapsedHeight | 474 | property double collapsedHeight |
64 | 464 | 475 | ||
65 | === modified file 'debian/control' | |||
66 | --- debian/control 2016-08-18 16:51:24 +0000 | |||
67 | +++ debian/control 2016-08-31 08:57:26 +0000 | |||
68 | @@ -77,6 +77,7 @@ | |||
69 | 77 | qml-module-qtquick-layouts, | 77 | qml-module-qtquick-layouts, |
70 | 78 | qml-module-qtquick-window2, | 78 | qml-module-qtquick-window2, |
71 | 79 | qml-module-qtquick2, | 79 | qml-module-qtquick2, |
72 | 80 | qml-module-ubuntu-components-labs, | ||
73 | 80 | qml-module-ubuntu-performancemetrics, | 81 | qml-module-ubuntu-performancemetrics, |
74 | 81 | qtdeclarative5-unity-action-plugin (>= 1.1.0), | 82 | qtdeclarative5-unity-action-plugin (>= 1.1.0), |
75 | 82 | suru-icon-theme, | 83 | suru-icon-theme, |
76 | 83 | 84 | ||
77 | === modified file 'debian/control.gles' | |||
78 | --- debian/control.gles 2016-07-28 10:54:13 +0000 | |||
79 | +++ debian/control.gles 2016-08-31 08:57:26 +0000 | |||
80 | @@ -103,6 +103,7 @@ | |||
81 | 103 | qml-module-qtquick-layouts, | 103 | qml-module-qtquick-layouts, |
82 | 104 | qml-module-qtquick-window2, | 104 | qml-module-qtquick-window2, |
83 | 105 | qml-module-qtquick2, | 105 | qml-module-qtquick2, |
84 | 106 | qml-module-ubuntu-components-labs, | ||
85 | 106 | qml-module-ubuntu-performancemetrics-gles, | 107 | qml-module-ubuntu-performancemetrics-gles, |
86 | 107 | qtdeclarative5-unity-action-plugin (>= 1.1.0), | 108 | qtdeclarative5-unity-action-plugin (>= 1.1.0), |
87 | 108 | suru-icon-theme, | 109 | suru-icon-theme, |
88 | 109 | 110 | ||
89 | === modified file 'debian/libubuntugestures5-dev.install' | |||
90 | --- debian/libubuntugestures5-dev.install 2016-07-06 11:27:11 +0000 | |||
91 | +++ debian/libubuntugestures5-dev.install 2016-08-31 08:57:26 +0000 | |||
92 | @@ -5,7 +5,6 @@ | |||
93 | 5 | usr/include/*/qt5/UbuntuGestures/ubuntugesturesglobal.h | 5 | usr/include/*/qt5/UbuntuGestures/ubuntugesturesglobal.h |
94 | 6 | usr/include/*/qt5/UbuntuGestures/ubuntugesturesmodule.h | 6 | usr/include/*/qt5/UbuntuGestures/ubuntugesturesmodule.h |
95 | 7 | usr/include/*/qt5/UbuntuGestures/ubuntugesturesversion.h | 7 | usr/include/*/qt5/UbuntuGestures/ubuntugesturesversion.h |
96 | 8 | usr/lib/*/libUbuntuGestures.la | ||
97 | 9 | usr/lib/*/libUbuntuGestures.prl | 8 | usr/lib/*/libUbuntuGestures.prl |
98 | 10 | usr/lib/*/libUbuntuGestures.so | 9 | usr/lib/*/libUbuntuGestures.so |
99 | 11 | usr/lib/*/pkgconfig/UbuntuGestures.pc | 10 | usr/lib/*/pkgconfig/UbuntuGestures.pc |
100 | 12 | 11 | ||
101 | === modified file 'debian/libubuntumetrics5-dev.install' | |||
102 | --- debian/libubuntumetrics5-dev.install 2016-07-26 16:33:27 +0000 | |||
103 | +++ debian/libubuntumetrics5-dev.install 2016-08-31 08:57:26 +0000 | |||
104 | @@ -6,7 +6,6 @@ | |||
105 | 6 | usr/include/*/qt5/UbuntuMetrics/logger.h | 6 | usr/include/*/qt5/UbuntuMetrics/logger.h |
106 | 7 | usr/include/*/qt5/UbuntuMetrics/ubuntumetricsglobal.h | 7 | usr/include/*/qt5/UbuntuMetrics/ubuntumetricsglobal.h |
107 | 8 | usr/include/*/qt5/UbuntuMetrics/ubuntumetricsversion.h | 8 | usr/include/*/qt5/UbuntuMetrics/ubuntumetricsversion.h |
108 | 9 | usr/lib/*/libUbuntuMetrics.la | ||
109 | 10 | usr/lib/*/libUbuntuMetrics.prl | 9 | usr/lib/*/libUbuntuMetrics.prl |
110 | 11 | usr/lib/*/libUbuntuMetrics.so | 10 | usr/lib/*/libUbuntuMetrics.so |
111 | 12 | usr/lib/*/pkgconfig/UbuntuMetrics.pc | 11 | usr/lib/*/pkgconfig/UbuntuMetrics.pc |
112 | 13 | 12 | ||
113 | === modified file 'debian/libubuntutoolkit5-dev.install' | |||
114 | --- debian/libubuntutoolkit5-dev.install 2016-07-07 07:21:48 +0000 | |||
115 | +++ debian/libubuntutoolkit5-dev.install 2016-08-31 08:57:26 +0000 | |||
116 | @@ -5,7 +5,6 @@ | |||
117 | 5 | usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitglobal.h | 5 | usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitglobal.h |
118 | 6 | usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitmodule.h | 6 | usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitmodule.h |
119 | 7 | usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitversion.h | 7 | usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitversion.h |
120 | 8 | usr/lib/*/libUbuntuToolkit.la | ||
121 | 9 | usr/lib/*/libUbuntuToolkit.prl | 8 | usr/lib/*/libUbuntuToolkit.prl |
122 | 10 | usr/lib/*/libUbuntuToolkit.so | 9 | usr/lib/*/libUbuntuToolkit.so |
123 | 11 | usr/lib/*/pkgconfig/UbuntuToolkit.pc | 10 | usr/lib/*/pkgconfig/UbuntuToolkit.pc |
124 | 12 | 11 | ||
125 | === modified file 'debian/rules' | |||
126 | --- debian/rules 2016-07-07 18:47:22 +0000 | |||
127 | +++ debian/rules 2016-08-31 08:57:26 +0000 | |||
128 | @@ -43,6 +43,7 @@ | |||
129 | 43 | mkdir -p debian/tmp/`qmake -query QT_INSTALL_DOCS`/qch | 43 | mkdir -p debian/tmp/`qmake -query QT_INSTALL_DOCS`/qch |
130 | 44 | mkdir -p debian/tmp/usr/share/ubuntu-ui-toolkit/doc | 44 | mkdir -p debian/tmp/usr/share/ubuntu-ui-toolkit/doc |
131 | 45 | cp -r $(CURDIR)/documentation/*qch debian/tmp/`qmake -query QT_INSTALL_DOCS`/qch | 45 | cp -r $(CURDIR)/documentation/*qch debian/tmp/`qmake -query QT_INSTALL_DOCS`/qch |
132 | 46 | rm -f debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/*.la | ||
133 | 46 | # FIXME: Due to autopilot not being in the archive we ship docs for now | 47 | # FIXME: Due to autopilot not being in the archive we ship docs for now |
134 | 47 | # sphinx-build -b singlehtml documentation/autopilot-helpers documentation/autopilot-helpers/_build/html | 48 | # sphinx-build -b singlehtml documentation/autopilot-helpers documentation/autopilot-helpers/_build/html |
135 | 48 | # sphinx-build -b json documentation/autopilot-helpers documentation/autopilot-helpers/_build/json | 49 | # sphinx-build -b json documentation/autopilot-helpers documentation/autopilot-helpers/_build/json |
136 | 49 | 50 | ||
137 | === modified file 'documentation/overview.qdoc' | |||
138 | --- documentation/overview.qdoc 2016-07-27 15:40:52 +0000 | |||
139 | +++ documentation/overview.qdoc 2016-08-31 08:57:26 +0000 | |||
140 | @@ -129,6 +129,22 @@ | |||
141 | 129 | \endcode | 129 | \endcode |
142 | 130 | \annotatedlist ubuntu-services | 130 | \annotatedlist ubuntu-services |
143 | 131 | 131 | ||
144 | 132 | \part Performance Metrics | ||
145 | 133 | Available through: | ||
146 | 134 | \code | ||
147 | 135 | import Ubuntu.PerformanceMetrics 1.0 | ||
148 | 136 | \endcode | ||
149 | 137 | \annotatedlist ubuntu-performance-metrics | ||
150 | 138 | |||
151 | 139 | \part Labs | ||
152 | 140 | The Labs module contains a set of components which have unstable API. Those | ||
153 | 141 | should not be used in applications as their interface may change any time. | ||
154 | 142 | Available through: | ||
155 | 143 | \code | ||
156 | 144 | import Ubuntu.Components.Labs 1.0 | ||
157 | 145 | \endcode | ||
158 | 146 | \annotatedlist ubuntu-labs | ||
159 | 147 | |||
160 | 132 | \part Test extensions | 148 | \part Test extensions |
161 | 133 | Available through: | 149 | Available through: |
162 | 134 | \code | 150 | \code |
163 | 135 | 151 | ||
164 | === modified file 'src/Ubuntu/Components/1.2/ActivityIndicator.qml' | |||
165 | --- src/Ubuntu/Components/1.2/ActivityIndicator.qml 2016-08-17 14:42:42 +0000 | |||
166 | +++ src/Ubuntu/Components/1.2/ActivityIndicator.qml 2016-08-31 08:57:26 +0000 | |||
167 | @@ -52,5 +52,10 @@ | |||
168 | 52 | */ | 52 | */ |
169 | 53 | property bool running: false | 53 | property bool running: false |
170 | 54 | 54 | ||
171 | 55 | implicitWidth: units.gu(3) | ||
172 | 56 | implicitHeight: units.gu(3) | ||
173 | 57 | width: units.gu(3) | ||
174 | 58 | height: units.gu(3) | ||
175 | 59 | |||
176 | 55 | style: Theme.createStyleComponent("ActivityIndicatorStyle.qml", indicator) | 60 | style: Theme.createStyleComponent("ActivityIndicatorStyle.qml", indicator) |
177 | 56 | } | 61 | } |
178 | 57 | 62 | ||
179 | === removed file 'src/Ubuntu/Components/1.3/ActionList.qml' | |||
180 | --- src/Ubuntu/Components/1.3/ActionList.qml 2016-05-25 12:48:10 +0000 | |||
181 | +++ src/Ubuntu/Components/1.3/ActionList.qml 1970-01-01 00:00:00 +0000 | |||
182 | @@ -1,47 +0,0 @@ | |||
183 | 1 | /* | ||
184 | 2 | * Copyright 2012 Canonical Ltd. | ||
185 | 3 | * | ||
186 | 4 | * This program is free software; you can redistribute it and/or modify | ||
187 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
188 | 6 | * the Free Software Foundation; version 3. | ||
189 | 7 | * | ||
190 | 8 | * This program is distributed in the hope that it will be useful, | ||
191 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
192 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
193 | 11 | * GNU Lesser General Public License for more details. | ||
194 | 12 | * | ||
195 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
196 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
197 | 15 | */ | ||
198 | 16 | |||
199 | 17 | import QtQuick 2.4 | ||
200 | 18 | import Ubuntu.Components 1.3 | ||
201 | 19 | |||
202 | 20 | /*! | ||
203 | 21 | \qmltype ActionList | ||
204 | 22 | \inqmlmodule Ubuntu.Components | ||
205 | 23 | \ingroup ubuntu | ||
206 | 24 | \brief List of \l Action items | ||
207 | 25 | */ | ||
208 | 26 | |||
209 | 27 | QtObject { | ||
210 | 28 | id: list | ||
211 | 29 | // internal objects using nested elements, | ||
212 | 30 | // which isn't allowed by QtObject; this fix makes this possible | ||
213 | 31 | /*! | ||
214 | 32 | Default property to allow adding of children. | ||
215 | 33 | \qmlproperty list<Action> children | ||
216 | 34 | \default | ||
217 | 35 | */ | ||
218 | 36 | default property alias children: list.actions | ||
219 | 37 | |||
220 | 38 | /*! | ||
221 | 39 | List of already defined actions when not defining them as children of the ActionList. | ||
222 | 40 | Note that when you set this property, the children of the ActionList will be ignored, | ||
223 | 41 | so do not set the list and define children. | ||
224 | 42 | |||
225 | 43 | The advantage of setting actions over using the children is that the same | ||
226 | 44 | \l Action items can be used in several sets of actions. | ||
227 | 45 | */ | ||
228 | 46 | property list<Action> actions | ||
229 | 47 | } | ||
230 | 48 | 0 | ||
231 | === modified file 'src/Ubuntu/Components/1.3/ActivityIndicator.qml' | |||
232 | --- src/Ubuntu/Components/1.3/ActivityIndicator.qml 2016-08-17 14:42:42 +0000 | |||
233 | +++ src/Ubuntu/Components/1.3/ActivityIndicator.qml 2016-08-31 08:57:26 +0000 | |||
234 | @@ -52,5 +52,10 @@ | |||
235 | 52 | */ | 52 | */ |
236 | 53 | property bool running: false | 53 | property bool running: false |
237 | 54 | 54 | ||
238 | 55 | implicitWidth: units.gu(3) | ||
239 | 56 | implicitHeight: units.gu(3) | ||
240 | 57 | width: units.gu(3) | ||
241 | 58 | height: units.gu(3) | ||
242 | 59 | |||
243 | 55 | styleName: "ActivityIndicatorStyle" | 60 | styleName: "ActivityIndicatorStyle" |
244 | 56 | } | 61 | } |
245 | 57 | 62 | ||
246 | === modified file 'src/Ubuntu/Components/ComponentModule.pro' | |||
247 | --- src/Ubuntu/Components/ComponentModule.pro 2016-07-29 13:21:05 +0000 | |||
248 | +++ src/Ubuntu/Components/ComponentModule.pro 2016-08-31 08:57:26 +0000 | |||
249 | @@ -78,7 +78,6 @@ | |||
250 | 78 | 78 | ||
251 | 79 | #1.3 | 79 | #1.3 |
252 | 80 | QML_FILES += 1.3/ActionBar.qml \ | 80 | QML_FILES += 1.3/ActionBar.qml \ |
253 | 81 | 1.3/ActionList.qml \ | ||
254 | 82 | 1.3/ActivityIndicator.qml \ | 81 | 1.3/ActivityIndicator.qml \ |
255 | 83 | 1.3/AdaptivePageLayout.qml \ | 82 | 1.3/AdaptivePageLayout.qml \ |
256 | 84 | 1.3/AnimatedItem.qml \ | 83 | 1.3/AnimatedItem.qml \ |
257 | 85 | 84 | ||
258 | === modified file 'src/Ubuntu/Components/Popups/1.3/Popover.qml' | |||
259 | --- src/Ubuntu/Components/Popups/1.3/Popover.qml 2016-03-17 17:40:51 +0000 | |||
260 | +++ src/Ubuntu/Components/Popups/1.3/Popover.qml 2016-08-31 08:57:26 +0000 | |||
261 | @@ -33,9 +33,8 @@ | |||
262 | 33 | \qml | 33 | \qml |
263 | 34 | import QtQuick 2.4 | 34 | import QtQuick 2.4 |
264 | 35 | import Ubuntu.Components 1.3 | 35 | import Ubuntu.Components 1.3 |
265 | 36 | import Ubuntu.Components.ListItems 1.3 as ListItem | ||
266 | 37 | import Ubuntu.Components.Popups 1.3 | 36 | import Ubuntu.Components.Popups 1.3 |
268 | 38 | 37 | import Ubuntu.Components.ListItems 1.3 as Old_ListItem | |
269 | 39 | Rectangle { | 38 | Rectangle { |
270 | 40 | color: theme.palette.normal.background | 39 | color: theme.palette.normal.background |
271 | 41 | width: units.gu(80) | 40 | width: units.gu(80) |
272 | @@ -52,29 +51,35 @@ | |||
273 | 52 | top: parent.top | 51 | top: parent.top |
274 | 53 | right: parent.right | 52 | right: parent.right |
275 | 54 | } | 53 | } |
299 | 55 | ListItem.Header { text: "Standard list items" } | 54 | |
300 | 56 | ListItem.Standard { text: "Do something" } | 55 | // there is no equivalent yet to ListItem.Header |
301 | 57 | ListItem.Standard { text: "Do something else" } | 56 | Old_ListItem.Header { text: "Standard list items" } |
302 | 58 | ListItem.Header { text: "Buttons" } | 57 | |
303 | 59 | ListItem.SingleControl { | 58 | ListItem { |
304 | 60 | highlightWhenPressed: false | 59 | // shall specify the height when Using ListItemLayout inside ListItem |
305 | 61 | control: Button { | 60 | height: somethingLayout.height + (divider.visible ? divider.height : 0) |
306 | 62 | text: "Do nothing" | 61 | ListItemLayout { |
307 | 63 | anchors { | 62 | id: somethingLayout |
308 | 64 | fill: parent | 63 | title.text: "Do somethings" |
309 | 65 | margins: units.gu(1) | 64 | } |
310 | 66 | } | 65 | onClicked: console.log("clicked on ListItem with onClicked implemented") |
311 | 67 | } | 66 | } |
312 | 68 | } | 67 | ListItem { |
313 | 69 | ListItem.SingleControl { | 68 | // shall specify the height when Using ListItemLayout inside ListItem |
314 | 70 | highlightWhenPressed: false | 69 | height: somethingElseLayout.height + (divider.visible ? divider.height : 0) |
315 | 71 | control: Button { | 70 | ListItemLayout { |
316 | 72 | text: "Close" | 71 | id: somethingElseLayout |
317 | 73 | anchors { | 72 | title.text: "Do somethings" |
318 | 74 | fill: parent | 73 | subtitle.text: "else" |
319 | 75 | margins: units.gu(1) | 74 | } |
320 | 76 | } | 75 | } |
321 | 77 | onClicked: PopupUtils.close(popover) | 76 | ListItem { |
322 | 77 | // shall specify the height when Using ListItemLayout inside ListItem | ||
323 | 78 | height: closeBtn.height + (divider.visible ? divider.height : 0) | ||
324 | 79 | Button { | ||
325 | 80 | id: closeBtn | ||
326 | 81 | text: "Close button" | ||
327 | 82 | onClicked: PopupUtils.close(popover); | ||
328 | 78 | } | 83 | } |
329 | 79 | } | 84 | } |
330 | 80 | } | 85 | } |
331 | 81 | 86 | ||
332 | === modified file 'src/Ubuntu/Components/Popups/1.3/popupUtils.js' | |||
333 | --- src/Ubuntu/Components/Popups/1.3/popupUtils.js 2016-04-13 19:32:20 +0000 | |||
334 | +++ src/Ubuntu/Components/Popups/1.3/popupUtils.js 2016-08-31 08:57:26 +0000 | |||
335 | @@ -60,6 +60,11 @@ | |||
336 | 60 | return null; | 60 | return null; |
337 | 61 | } | 61 | } |
338 | 62 | 62 | ||
339 | 63 | if (!rootObject) { | ||
340 | 64 | print("PopupUtils.open(): Failed to get the root object."); | ||
341 | 65 | return null; | ||
342 | 66 | } | ||
343 | 67 | |||
344 | 63 | var popupObject; | 68 | var popupObject; |
345 | 64 | if (params !== undefined) { | 69 | if (params !== undefined) { |
346 | 65 | popupObject = popupComponent.createObject(rootObject, params); | 70 | popupObject = popupComponent.createObject(rootObject, params); |
347 | 66 | 71 | ||
348 | === modified file 'src/Ubuntu/Components/Themes/Ambiance/1.2/ActivityIndicatorStyle.qml' | |||
349 | --- src/Ubuntu/Components/Themes/Ambiance/1.2/ActivityIndicatorStyle.qml 2016-08-17 14:42:42 +0000 | |||
350 | +++ src/Ubuntu/Components/Themes/Ambiance/1.2/ActivityIndicatorStyle.qml 2016-08-31 08:57:26 +0000 | |||
351 | @@ -20,8 +20,6 @@ | |||
352 | 20 | Image { | 20 | Image { |
353 | 21 | id: container | 21 | id: container |
354 | 22 | 22 | ||
355 | 23 | implicitWidth: units.gu(3) | ||
356 | 24 | implicitHeight: units.gu(3) | ||
357 | 25 | smooth: true | 23 | smooth: true |
358 | 26 | visible: styledItem.running | 24 | visible: styledItem.running |
359 | 27 | fillMode: Image.PreserveAspectFit | 25 | fillMode: Image.PreserveAspectFit |
360 | 28 | 26 | ||
361 | === modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/ActivityIndicatorStyle.qml' | |||
362 | --- src/Ubuntu/Components/Themes/Ambiance/1.3/ActivityIndicatorStyle.qml 2016-08-17 14:42:42 +0000 | |||
363 | +++ src/Ubuntu/Components/Themes/Ambiance/1.3/ActivityIndicatorStyle.qml 2016-08-31 08:57:26 +0000 | |||
364 | @@ -20,8 +20,6 @@ | |||
365 | 20 | Image { | 20 | Image { |
366 | 21 | id: container | 21 | id: container |
367 | 22 | 22 | ||
368 | 23 | implicitWidth: units.gu(3) | ||
369 | 24 | implicitHeight: units.gu(3) | ||
370 | 25 | smooth: true | 23 | smooth: true |
371 | 26 | visible: styledItem.running && styledItem.visible | 24 | visible: styledItem.running && styledItem.visible |
372 | 27 | fillMode: Image.PreserveAspectFit | 25 | fillMode: Image.PreserveAspectFit |
373 | 28 | 26 | ||
374 | === modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollbarStyle.qml' | |||
375 | --- src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollbarStyle.qml 2016-08-02 11:18:34 +0000 | |||
376 | +++ src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollbarStyle.qml 2016-08-31 08:57:26 +0000 | |||
377 | @@ -316,7 +316,9 @@ | |||
378 | 316 | property string propPosRatio: (isVertical) ? "yPosition" : "xPosition" | 316 | property string propPosRatio: (isVertical) ? "yPosition" : "xPosition" |
379 | 317 | property string propSizeRatio: (isVertical) ? "heightRatio" : "widthRatio" | 317 | property string propSizeRatio: (isVertical) ? "heightRatio" : "widthRatio" |
380 | 318 | property string propCoordinate: (isVertical) ? "y" : "x" | 318 | property string propCoordinate: (isVertical) ? "y" : "x" |
381 | 319 | property string otherPropCoordinate: (isVertical) ? "x" : "y" | ||
382 | 319 | property string propSize: (isVertical) ? "height" : "width" | 320 | property string propSize: (isVertical) ? "height" : "width" |
383 | 321 | property string otherPropSize: (isVertical) ? "width" : "height" | ||
384 | 320 | property string propAtBeginning: (isVertical) ? "atYBeginning" : "atXBeginning" | 322 | property string propAtBeginning: (isVertical) ? "atYBeginning" : "atXBeginning" |
385 | 321 | property string propAtEnd: (isVertical) ? "atYEnd" : "atXEnd" | 323 | property string propAtEnd: (isVertical) ? "atYEnd" : "atXEnd" |
386 | 322 | 324 | ||
387 | @@ -622,8 +624,6 @@ | |||
388 | 622 | property bool lockDrag: false | 624 | property bool lockDrag: false |
389 | 623 | 625 | ||
390 | 624 | property bool hoveringThumb: false | 626 | property bool hoveringThumb: false |
391 | 625 | property string scrollingProp: isVertical ? "y" : "x" | ||
392 | 626 | property string sizeProp: isVertical ? "height" : "width" | ||
393 | 627 | 627 | ||
394 | 628 | function initDrag(isMouse) { | 628 | function initDrag(isMouse) { |
395 | 629 | __disableStateBinding = true | 629 | __disableStateBinding = true |
396 | @@ -648,20 +648,29 @@ | |||
397 | 648 | if (!thumbArea.pressed) return | 648 | if (!thumbArea.pressed) return |
398 | 649 | 649 | ||
399 | 650 | var mouseScrollingProp = isVertical ? mouseY : mouseX | 650 | var mouseScrollingProp = isVertical ? mouseY : mouseX |
401 | 651 | if (mouseScrollingProp < slider[scrollingProp]) { | 651 | if (mouseScrollingProp < slider[scrollbarUtils.propCoordinate]) { |
402 | 652 | scrollBy(-pageSize*visuals.longScrollingRatio, true) | 652 | scrollBy(-pageSize*visuals.longScrollingRatio, true) |
404 | 653 | } else if (mouseScrollingProp > slider[scrollingProp] + slider[sizeProp]) { | 653 | } else if (mouseScrollingProp > slider[scrollbarUtils.propCoordinate] + slider[scrollbarUtils.propSize]) { |
405 | 654 | scrollBy(pageSize*visuals.longScrollingRatio, true) | 654 | scrollBy(pageSize*visuals.longScrollingRatio, true) |
406 | 655 | } | 655 | } |
407 | 656 | } | 656 | } |
408 | 657 | 657 | ||
409 | 658 | //we consider hover if it's inside the TROUGH along the scrolling axis | ||
410 | 659 | //and inside the THUMB along the non-scrolling axis | ||
411 | 660 | //NOTE: mouseX and mouseY are assumed to be relative to thumbArea | ||
412 | 658 | function handleHover(mouseX, mouseY) { | 661 | function handleHover(mouseX, mouseY) { |
413 | 662 | //NOTE: we're assuming thumbArea has same size/position as the trough. | ||
414 | 663 | //Use mapToItem to map the coordinates if that assumption falls (i.e. to implement | ||
415 | 664 | //a larger touch detection area around the thumb) | ||
416 | 659 | var mouseScrollingProp = isVertical ? mouseY : mouseX | 665 | var mouseScrollingProp = isVertical ? mouseY : mouseX |
419 | 660 | //don't count as hover if the user is already press-and-holding the trough to | 666 | var otherProp = isVertical ? mouseX : mouseY |
420 | 661 | //scroll page by page | 667 | |
421 | 668 | //don't count as hover if the user is already press-and-holding | ||
422 | 669 | //the trough to scroll page by page | ||
423 | 662 | hoveringThumb = !(pressHoldTimer.running && pressHoldTimer.startedBy === thumbArea) | 670 | hoveringThumb = !(pressHoldTimer.running && pressHoldTimer.startedBy === thumbArea) |
426 | 663 | && mouseScrollingProp >= slider[scrollingProp] && | 671 | && mouseScrollingProp >= slider[scrollbarUtils.propCoordinate] && |
427 | 664 | mouseScrollingProp <= slider[scrollingProp] + slider[sizeProp] | 672 | mouseScrollingProp <= slider[scrollbarUtils.propCoordinate] + slider[scrollbarUtils.propSize] && |
428 | 673 | otherProp >= 0 && otherProp <= trough[scrollbarUtils.otherPropSize] | ||
429 | 665 | } | 674 | } |
430 | 666 | 675 | ||
431 | 667 | function saveFlickableScrollingState() { | 676 | function saveFlickableScrollingState() { |
432 | @@ -691,14 +700,9 @@ | |||
433 | 691 | previousY = mouse.y | 700 | previousY = mouse.y |
434 | 692 | } | 701 | } |
435 | 693 | 702 | ||
444 | 694 | anchors { | 703 | //NOTE: remember to update the handleHover check if you add anchor margins |
445 | 695 | fill: trough | 704 | anchors.fill: trough |
446 | 696 | // set margins adding 2 dp for error area | 705 | |
439 | 697 | leftMargin: (!isVertical || frontAligned) ? 0 : units.dp(-2) | ||
440 | 698 | rightMargin: (!isVertical || rearAligned) ? 0 : units.dp(-2) | ||
441 | 699 | topMargin: (isVertical || topAligned) ? 0 : units.dp(-2) | ||
442 | 700 | bottomMargin: (isVertical || bottomAligned) ? 0 : units.dp(-2) | ||
443 | 701 | } | ||
447 | 702 | enabled: isScrollable && interactive && __canFitSteppersAndShorterThumb | 706 | enabled: isScrollable && interactive && __canFitSteppersAndShorterThumb |
448 | 703 | onPressed: { | 707 | onPressed: { |
449 | 704 | cacheMousePosition(mouse) | 708 | cacheMousePosition(mouse) |
450 | @@ -710,8 +714,8 @@ | |||
451 | 710 | if (firstStepper.visible) { | 714 | if (firstStepper.visible) { |
452 | 711 | var mouseScrollingProp = isVertical ? mouseY : mouseX | 715 | var mouseScrollingProp = isVertical ? mouseY : mouseX |
453 | 712 | //don't start the press and hold timer to avoid conflicts with the drag | 716 | //don't start the press and hold timer to avoid conflicts with the drag |
456 | 713 | if (mouseScrollingProp < slider[scrollingProp] || | 717 | if (mouseScrollingProp < slider[scrollbarUtils.propCoordinate] || |
457 | 714 | mouseScrollingProp > (slider[scrollingProp] + slider[sizeProp])) { | 718 | mouseScrollingProp > (slider[scrollbarUtils.propCoordinate] + slider[scrollbarUtils.propSize])) { |
458 | 715 | handlePress(mouseX, mouseY) | 719 | handlePress(mouseX, mouseY) |
459 | 716 | pressHoldTimer.startTimer(thumbArea) | 720 | pressHoldTimer.startTimer(thumbArea) |
460 | 717 | } else { | 721 | } else { |
461 | @@ -761,7 +765,8 @@ | |||
462 | 761 | pressHoldTimer.stop() | 765 | pressHoldTimer.stop() |
463 | 762 | } | 766 | } |
464 | 763 | onReleased: { | 767 | onReleased: { |
466 | 764 | handleHover(mouseX, mouseY) | 768 | //don't call handleHover here as touch release also triggers this handler |
467 | 769 | //see bug #1616868 | ||
468 | 765 | resetDrag() | 770 | resetDrag() |
469 | 766 | pressHoldTimer.stop() | 771 | pressHoldTimer.stop() |
470 | 767 | } | 772 | } |
471 | @@ -797,18 +802,29 @@ | |||
472 | 797 | 802 | ||
473 | 798 | //logic to support different colour on hovering | 803 | //logic to support different colour on hovering |
474 | 799 | hoverEnabled: true | 804 | hoverEnabled: true |
475 | 805 | //This means this mouse filter will only handle real mouse events! | ||
476 | 806 | //i.e. the synthesized mouse events created when you use | ||
477 | 807 | //touchscreen will not trigger it! This way we can have logic that | ||
478 | 808 | //will not trigger when using touch | ||
479 | 809 | Mouse.ignoreSynthesizedEvents: true | ||
480 | 800 | Mouse.enabled: true | 810 | Mouse.enabled: true |
481 | 801 | Mouse.ignoreSynthesizedEvents: true | ||
482 | 802 | Mouse.onEntered: { | 811 | Mouse.onEntered: { |
483 | 803 | hoveringThumb = false | 812 | hoveringThumb = false |
484 | 804 | handleHover(event.x, event.y) | 813 | handleHover(event.x, event.y) |
485 | 805 | } | 814 | } |
486 | 806 | Mouse.onPositionChanged: { | 815 | Mouse.onPositionChanged: { |
487 | 816 | //We need to update the hover state also onPosChanged because this area | ||
488 | 817 | //covers the whole trough, not just the thumb, so entered/exited are not enough | ||
489 | 818 | //e.g. when mouse moves from inside the thumb to inside the trough, or when you | ||
490 | 819 | //click on the trough and the thumb scrolls and goes under the mouse cursor | ||
491 | 807 | handleHover(mouse.x, mouse.y) | 820 | handleHover(mouse.x, mouse.y) |
492 | 808 | } | 821 | } |
493 | 809 | Mouse.onExited: { | 822 | Mouse.onExited: { |
494 | 810 | hoveringThumb = false | 823 | hoveringThumb = false |
495 | 811 | } | 824 | } |
496 | 825 | Mouse.onReleased: { | ||
497 | 826 | handleHover(mouse.x, mouse.y) | ||
498 | 827 | } | ||
499 | 812 | 828 | ||
500 | 813 | Timer { | 829 | Timer { |
501 | 814 | id: pressHoldTimer | 830 | id: pressHoldTimer |
502 | @@ -845,6 +861,7 @@ | |||
503 | 845 | 861 | ||
504 | 846 | MouseArea { | 862 | MouseArea { |
505 | 847 | id: steppersMouseArea | 863 | id: steppersMouseArea |
506 | 864 | objectName: "steppersMouseArea" | ||
507 | 848 | //size is handled by the states | 865 | //size is handled by the states |
508 | 849 | 866 | ||
509 | 850 | property bool hoveringFirstStepper: false | 867 | property bool hoveringFirstStepper: false |
510 | @@ -897,12 +914,7 @@ | |||
511 | 897 | hoveringFirstStepper = false | 914 | hoveringFirstStepper = false |
512 | 898 | hoveringSecondStepper = false | 915 | hoveringSecondStepper = false |
513 | 899 | } | 916 | } |
520 | 900 | 917 | Mouse.onPressed: { | |
515 | 901 | //We don't change the size of the images because we let the image reader figure the size out, | ||
516 | 902 | //though that means we have to hide the images somehow while the mousearea is visible but has | ||
517 | 903 | //null size. We choose to enable clipping here instead of creating bindings on images' visible prop | ||
518 | 904 | clip: true | ||
519 | 905 | onPressed: { | ||
521 | 906 | //This additional trigger of the hovering logic is useful especially in testing | 918 | //This additional trigger of the hovering logic is useful especially in testing |
522 | 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, |
523 | 908 | //but then clicking on the second one (without a mouseMove) won't, because they're | 920 | //but then clicking on the second one (without a mouseMove) won't, because they're |
524 | @@ -910,7 +922,16 @@ | |||
525 | 910 | //we ensure that the hovering logic is correct even when there are no mouse moves between | 922 | //we ensure that the hovering logic is correct even when there are no mouse moves between |
526 | 911 | //clicks on different steppers (like it happens in tst_actionSteppers test). | 923 | //clicks on different steppers (like it happens in tst_actionSteppers test). |
527 | 912 | handleHover(mouse) | 924 | handleHover(mouse) |
528 | 925 | } | ||
529 | 926 | Mouse.onReleased: { | ||
530 | 927 | handleHover(mouse) | ||
531 | 928 | } | ||
532 | 913 | 929 | ||
533 | 930 | //We don't change the size of the images because we let the image reader figure the size out, | ||
534 | 931 | //though that means we have to hide the images somehow while the mousearea is visible but has | ||
535 | 932 | //null size. We choose to enable clipping here instead of creating bindings on images' visible prop | ||
536 | 933 | clip: true | ||
537 | 934 | onPressed: { | ||
538 | 914 | handlePress() | 935 | handlePress() |
539 | 915 | pressHoldTimer.startTimer(steppersMouseArea) | 936 | pressHoldTimer.startTimer(steppersMouseArea) |
540 | 916 | } | 937 | } |
541 | @@ -952,7 +973,7 @@ | |||
542 | 952 | anchors.centerIn: parent | 973 | anchors.centerIn: parent |
543 | 953 | width: __stepperAssetWidth | 974 | width: __stepperAssetWidth |
544 | 954 | rotation: isVertical ? 180 : 90 | 975 | rotation: isVertical ? 180 : 90 |
546 | 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 |
547 | 956 | //the QML profiler showed it's relatively expensive | 977 | //the QML profiler showed it's relatively expensive |
548 | 957 | source: visible ? "../artwork/toolkit_scrollbar-stepper.svg" : "" | 978 | source: visible ? "../artwork/toolkit_scrollbar-stepper.svg" : "" |
549 | 958 | asynchronous: true | 979 | asynchronous: true |
550 | @@ -998,7 +1019,7 @@ | |||
551 | 998 | anchors.centerIn: parent | 1019 | anchors.centerIn: parent |
552 | 999 | width: __stepperAssetWidth | 1020 | width: __stepperAssetWidth |
553 | 1000 | rotation: isVertical ? 0 : -90 | 1021 | rotation: isVertical ? 0 : -90 |
555 | 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 |
556 | 1002 | //the QML profiler showed it's relatively expensive | 1023 | //the QML profiler showed it's relatively expensive |
557 | 1003 | source: visible ? "../artwork/toolkit_scrollbar-stepper.svg" : "" | 1024 | source: visible ? "../artwork/toolkit_scrollbar-stepper.svg" : "" |
558 | 1004 | asynchronous: true | 1025 | asynchronous: true |
559 | 1005 | 1026 | ||
560 | === added file 'src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollingActionBarStyle.qml' | |||
561 | --- src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollingActionBarStyle.qml 1970-01-01 00:00:00 +0000 | |||
562 | +++ src/Ubuntu/Components/Themes/Ambiance/1.3/ScrollingActionBarStyle.qml 2016-08-31 08:57:26 +0000 | |||
563 | @@ -0,0 +1,203 @@ | |||
564 | 1 | /* | ||
565 | 2 | * Copyright 2016 Canonical Ltd. | ||
566 | 3 | * | ||
567 | 4 | * This program is free software; you can redistribute it and/or modify | ||
568 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
569 | 6 | * the Free Software Foundation; version 3. | ||
570 | 7 | * | ||
571 | 8 | * This program is distributed in the hope that it will be useful, | ||
572 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
573 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
574 | 11 | * GNU Lesser General Public License for more details. | ||
575 | 12 | * | ||
576 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
577 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
578 | 15 | */ | ||
579 | 16 | import QtQuick 2.4 | ||
580 | 17 | import Ubuntu.Components 1.3 | ||
581 | 18 | import Ubuntu.Components.Styles 1.3 as Style | ||
582 | 19 | |||
583 | 20 | Style.ActionBarStyle { | ||
584 | 21 | id: actionBarStyle | ||
585 | 22 | implicitHeight: units.gu(5) | ||
586 | 23 | |||
587 | 24 | clip: true // avoid showing the icons that are scrolled out of the view. | ||
588 | 25 | backgroundColor: theme.palette.normal.background | ||
589 | 26 | buttons { | ||
590 | 27 | foregroundColor: theme.palette.normal.backgroundText | ||
591 | 28 | pressedForegroundColor: buttons.foregroundColor | ||
592 | 29 | disabledForegroundColor: theme.palette.disabled.backgroundText | ||
593 | 30 | backgroundColor: "transparent" // background is already colored | ||
594 | 31 | pressedBackgroundColor: theme.palette.highlighted.background | ||
595 | 32 | disabledBackgroundColor: buttons.backgroundColor | ||
596 | 33 | } | ||
597 | 34 | |||
598 | 35 | property QtObject scrollButtons: Style.ActionItemProperties { | ||
599 | 36 | foregroundColor: actionBarStyle.buttons.foregroundColor | ||
600 | 37 | pressedForegroundColor: actionBarStyle.buttons.pressedForegroundColor | ||
601 | 38 | backgroundColor: actionBarStyle.backgroundColor // must be opaque to hide the icon buttons | ||
602 | 39 | pressedBackgroundColor: actionBarStyle.buttons.pressedBackgroundColor | ||
603 | 40 | property real width: units.gu(4) | ||
604 | 41 | property int fadeDuration: UbuntuAnimation.FastDuration | ||
605 | 42 | } | ||
606 | 43 | |||
607 | 44 | /*! | ||
608 | 45 | The default action delegate if the styled item does | ||
609 | 46 | not provide a delegate. | ||
610 | 47 | */ | ||
611 | 48 | // FIXME: This ListItem { AbstractButton { } } construction can be avoided | ||
612 | 49 | // when StyledItem supports cursor keys navigation, see bug #1573616. | ||
613 | 50 | // FIXME: For the first and last item in the list, it is possible to move | ||
614 | 51 | // the focus inside the ListItem to the AbstractButton, see bug #1590005. | ||
615 | 52 | // FIXME: Focus can go on disabled item. See bug #1611327. | ||
616 | 53 | defaultDelegate: ListItem { | ||
617 | 54 | width: units.gu(4) | ||
618 | 55 | height: actionBarStyle.height | ||
619 | 56 | enabled: modelData.enabled | ||
620 | 57 | objectName: modelData.objectName + "_button" | ||
621 | 58 | AbstractButton { | ||
622 | 59 | id: button | ||
623 | 60 | anchors.fill: parent | ||
624 | 61 | style: IconButtonStyle { | ||
625 | 62 | foregroundColor: button.pressed ? | ||
626 | 63 | actionBarStyle.buttons.pressedForegroundColor : | ||
627 | 64 | button.enabled ? | ||
628 | 65 | actionBarStyle.buttons.foregroundColor : | ||
629 | 66 | actionBarStyle.buttons.disabledForegroundColor | ||
630 | 67 | backgroundColor: button.pressed ? | ||
631 | 68 | actionBarStyle.buttons.pressedBackgroundColor : | ||
632 | 69 | button.enabled ? | ||
633 | 70 | actionBarStyle.buttons.backgroundColor : | ||
634 | 71 | actionBarStyle.buttons.disabledBackgroundColor | ||
635 | 72 | } | ||
636 | 73 | action: modelData | ||
637 | 74 | activeFocusOnTab: false | ||
638 | 75 | } | ||
639 | 76 | divider.visible: false | ||
640 | 77 | } | ||
641 | 78 | |||
642 | 79 | Rectangle { | ||
643 | 80 | color: actionBarStyle.backgroundColor | ||
644 | 81 | id: listViewContainer | ||
645 | 82 | anchors.fill: parent | ||
646 | 83 | |||
647 | 84 | property var visibleActions: getVisibleActions(styledItem.actions) | ||
648 | 85 | function getVisibleActions(actions) { | ||
649 | 86 | var visibleActionList = []; | ||
650 | 87 | for (var i = 0; i < actions.length; i++) { | ||
651 | 88 | var action = actions[i]; | ||
652 | 89 | if (action && action.hasOwnProperty("visible") && action.visible) { | ||
653 | 90 | visibleActionList.push(action); | ||
654 | 91 | } | ||
655 | 92 | } | ||
656 | 93 | return visibleActionList; | ||
657 | 94 | } | ||
658 | 95 | |||
659 | 96 | ListView { | ||
660 | 97 | id: actionsListView | ||
661 | 98 | objectName: "actions_listview" | ||
662 | 99 | anchors { | ||
663 | 100 | right: parent.right | ||
664 | 101 | top: parent.top | ||
665 | 102 | bottom: parent.bottom | ||
666 | 103 | rightMargin: scrollButtons.width | ||
667 | 104 | } | ||
668 | 105 | displayMarginBeginning: scrollButtons.width | ||
669 | 106 | displayMarginEnd: scrollButtons.width | ||
670 | 107 | leftMargin: -scrollButtons.width | ||
671 | 108 | rightMargin: -scrollButtons.width | ||
672 | 109 | width: listViewContainer.width - 2*scrollButtons.width | ||
673 | 110 | layoutDirection: Qt.RightToLeft | ||
674 | 111 | |||
675 | 112 | orientation: ListView.Horizontal | ||
676 | 113 | boundsBehavior: Flickable.StopAtBounds | ||
677 | 114 | delegate: styledItem.delegate | ||
678 | 115 | model: listViewContainer.visibleActions | ||
679 | 116 | |||
680 | 117 | // This gives the correct behavior when scrollButtons.width is | ||
681 | 118 | // larger/smaller/equal compared to the width of the delegate. | ||
682 | 119 | onCurrentIndexChanged: positionViewAtIndex(currentIndex, ListView.Contain) | ||
683 | 120 | |||
684 | 121 | SmoothedAnimation { | ||
685 | 122 | objectName: "actions_scroll_animation" | ||
686 | 123 | id: contentXAnim | ||
687 | 124 | target: actionsListView | ||
688 | 125 | property: "contentX" | ||
689 | 126 | duration: UbuntuAnimation.FastDuration | ||
690 | 127 | } | ||
691 | 128 | |||
692 | 129 | // direction == 1 to show more icons on the left | ||
693 | 130 | // direction == -1 to show more icons on the right | ||
694 | 131 | function scroll(direction) { | ||
695 | 132 | if (contentXAnim.running) contentXAnim.stop(); | ||
696 | 133 | var newContentX = actionsListView.contentX - (actionsListView.width * direction); | ||
697 | 134 | contentXAnim.from = actionsListView.contentX; | ||
698 | 135 | // make sure we don't overshoot bounds | ||
699 | 136 | contentXAnim.to = MathUtils.clamp( | ||
700 | 137 | newContentX, | ||
701 | 138 | originX + scrollButtons.width, | ||
702 | 139 | actionsListView.originX + actionsListView.contentWidth | ||
703 | 140 | - actionsListView.width - scrollButtons.width); | ||
704 | 141 | contentXAnim.start(); | ||
705 | 142 | } | ||
706 | 143 | } | ||
707 | 144 | |||
708 | 145 | Component { | ||
709 | 146 | id: scrollButtonComponent | ||
710 | 147 | AbstractButton { | ||
711 | 148 | id: scrollButton | ||
712 | 149 | width: actionBarStyle.scrollButtons.width | ||
713 | 150 | enabled: opacity === 1.0 | ||
714 | 151 | onClicked: actionsListView.scroll(scrollDirection) | ||
715 | 152 | opacity: buttonOpacity | ||
716 | 153 | objectName: buttonName | ||
717 | 154 | Behavior on opacity { | ||
718 | 155 | UbuntuNumberAnimation { | ||
719 | 156 | duration: actionBarStyle.scrollButtons.fadeDuration | ||
720 | 157 | } | ||
721 | 158 | } | ||
722 | 159 | Rectangle { | ||
723 | 160 | anchors.fill: parent | ||
724 | 161 | color: scrollButton.pressed ? actionBarStyle.scrollButtons.pressedBackgroundColor | ||
725 | 162 | : actionBarStyle.scrollButtons.backgroundColor | ||
726 | 163 | } | ||
727 | 164 | Icon { | ||
728 | 165 | // FIXME: Use new theme icon from | ||
729 | 166 | // https://code.launchpad.net/~tiheum/ubuntu-themes/toolkit-arrows/+merge/298609 | ||
730 | 167 | // after it lands in overlay and archive. | ||
731 | 168 | anchors.centerIn: parent | ||
732 | 169 | width: units.gu(1) | ||
733 | 170 | height: units.gu(1) | ||
734 | 171 | rotation: iconRotation | ||
735 | 172 | name: "chevron" | ||
736 | 173 | color: scrollButton.pressed ? actionBarStyle.scrollButtons.pressedForegroundColor | ||
737 | 174 | : actionBarStyle.scrollButtons.foregroundColor | ||
738 | 175 | } | ||
739 | 176 | } | ||
740 | 177 | } | ||
741 | 178 | Loader { | ||
742 | 179 | anchors { | ||
743 | 180 | left: parent.left | ||
744 | 181 | top: parent.top | ||
745 | 182 | bottom: parent.bottom | ||
746 | 183 | } | ||
747 | 184 | sourceComponent: scrollButtonComponent | ||
748 | 185 | property int iconRotation: 180 | ||
749 | 186 | property real buttonOpacity: actionsListView.atXBeginning ? 0.0 : 1.0 | ||
750 | 187 | property int scrollDirection: 1 | ||
751 | 188 | property string buttonName: "leading_scroll_button" | ||
752 | 189 | } | ||
753 | 190 | Loader { | ||
754 | 191 | anchors { | ||
755 | 192 | right: parent.right | ||
756 | 193 | top: parent.top | ||
757 | 194 | bottom: parent.bottom | ||
758 | 195 | } | ||
759 | 196 | sourceComponent: scrollButtonComponent | ||
760 | 197 | property int iconRotation: 0 | ||
761 | 198 | property real buttonOpacity: actionsListView.atXEnd ? 0.0 : 1.0 | ||
762 | 199 | property int scrollDirection: -1 | ||
763 | 200 | property string buttonName: "trailing_scroll_button" | ||
764 | 201 | } | ||
765 | 202 | } | ||
766 | 203 | } | ||
767 | 0 | 204 | ||
768 | === modified file 'src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro' | |||
769 | --- src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro 2016-04-21 11:34:55 +0000 | |||
770 | +++ src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro 2016-08-31 08:57:26 +0000 | |||
771 | @@ -103,6 +103,7 @@ | |||
772 | 103 | 1.3/ProgressionVisualStyle.qml \ | 103 | 1.3/ProgressionVisualStyle.qml \ |
773 | 104 | 1.3/PullToRefreshStyle.qml \ | 104 | 1.3/PullToRefreshStyle.qml \ |
774 | 105 | 1.3/ScrollbarStyle.qml \ | 105 | 1.3/ScrollbarStyle.qml \ |
775 | 106 | 1.3/ScrollingActionBarStyle.qml \ | ||
776 | 106 | 1.3/SectionsStyle.qml \ | 107 | 1.3/SectionsStyle.qml \ |
777 | 107 | 1.3/SheetForegroundStyle.qml \ | 108 | 1.3/SheetForegroundStyle.qml \ |
778 | 108 | 1.3/SliderStyle.qml \ | 109 | 1.3/SliderStyle.qml \ |
779 | 109 | 110 | ||
780 | === modified file 'src/Ubuntu/Components/Themes/Ambiance/qmldir' | |||
781 | --- src/Ubuntu/Components/Themes/Ambiance/qmldir 2016-02-19 11:18:51 +0000 | |||
782 | +++ src/Ubuntu/Components/Themes/Ambiance/qmldir 2016-08-31 08:57:26 +0000 | |||
783 | @@ -59,6 +59,7 @@ | |||
784 | 59 | #version 1.3 | 59 | #version 1.3 |
785 | 60 | AmbianceNormal 1.3 ./1.3/AmbianceNormal.qml | 60 | AmbianceNormal 1.3 ./1.3/AmbianceNormal.qml |
786 | 61 | ActionBarStyle 1.3 ./1.3/ActionBarStyle.qml | 61 | ActionBarStyle 1.3 ./1.3/ActionBarStyle.qml |
787 | 62 | ScrollingActionBarStyle 1.3 ./1.3/ScrollingActionBarStyle.qml | ||
788 | 62 | MainViewStyle 1.3 ./1.3/MainViewStyle.qml | 63 | MainViewStyle 1.3 ./1.3/MainViewStyle.qml |
789 | 63 | ListItemOptionSelector 1.3 ./1.3/ListItemOptionSelector.qml | 64 | ListItemOptionSelector 1.3 ./1.3/ListItemOptionSelector.qml |
790 | 64 | OptionSelectorStyle 1.3 ./1.3/OptionSelectorStyle.qml | 65 | OptionSelectorStyle 1.3 ./1.3/OptionSelectorStyle.qml |
791 | 65 | 66 | ||
792 | === modified file 'src/Ubuntu/Components/qmldir' | |||
793 | --- src/Ubuntu/Components/qmldir 2016-07-29 13:21:05 +0000 | |||
794 | +++ src/Ubuntu/Components/qmldir 2016-08-31 08:57:26 +0000 | |||
795 | @@ -96,7 +96,6 @@ | |||
796 | 96 | ################################################# | 96 | ################################################# |
797 | 97 | #version 1.3 | 97 | #version 1.3 |
798 | 98 | ActionBar 1.3 1.3/ActionBar.qml | 98 | ActionBar 1.3 1.3/ActionBar.qml |
799 | 99 | ActionList 1.3 1.3/ActionList.qml | ||
800 | 100 | AdaptivePageLayout 1.3 1.3/AdaptivePageLayout.qml | 99 | AdaptivePageLayout 1.3 1.3/AdaptivePageLayout.qml |
801 | 101 | PageColumnsLayout 1.3 1.3/PageColumnsLayout.qml | 100 | PageColumnsLayout 1.3 1.3/PageColumnsLayout.qml |
802 | 102 | PageColumn 1.3 1.3/PageColumn.qml | 101 | PageColumn 1.3 1.3/PageColumn.qml |
803 | 103 | 102 | ||
804 | === modified file 'src/Ubuntu/Test/UbuntuTestCase13.qml' | |||
805 | --- src/Ubuntu/Test/UbuntuTestCase13.qml 2016-03-15 13:17:53 +0000 | |||
806 | +++ src/Ubuntu/Test/UbuntuTestCase13.qml 2016-08-31 08:57:26 +0000 | |||
807 | @@ -15,7 +15,7 @@ | |||
808 | 15 | */ | 15 | */ |
809 | 16 | 16 | ||
810 | 17 | import QtQuick 2.4 | 17 | import QtQuick 2.4 |
812 | 18 | import QtTest 1.0 | 18 | import QtTest 1.1 |
813 | 19 | import Ubuntu.Components 1.3 | 19 | import Ubuntu.Components 1.3 |
814 | 20 | 20 | ||
815 | 21 | /*! | 21 | /*! |
816 | 22 | 22 | ||
817 | === modified file 'src/Ubuntu/UbuntuMetrics/applicationmonitor.cpp' | |||
818 | --- src/Ubuntu/UbuntuMetrics/applicationmonitor.cpp 2016-08-06 00:54:30 +0000 | |||
819 | +++ src/Ubuntu/UbuntuMetrics/applicationmonitor.cpp 2016-08-31 08:57:26 +0000 | |||
820 | @@ -567,7 +567,9 @@ | |||
821 | 567 | event.generic.id = id; | 567 | event.generic.id = id; |
822 | 568 | // We don't bother fixing up non null-terminated string, just potential | 568 | // We don't bother fixing up non null-terminated string, just potential |
823 | 569 | // overflows. | 569 | // overflows. |
825 | 570 | event.generic.stringSize = qMin(size, UMGenericEvent::maxStringSize); | 570 | // Note: GCC5 comoiler/linker cannot find UMGenericEvent::maxStringSize |
826 | 571 | // if used in qMin(); force type to satisfy it | ||
827 | 572 | event.generic.stringSize = qMin(size, quint32(UMGenericEvent::maxStringSize)); | ||
828 | 571 | memcpy(event.generic.string, string, event.generic.stringSize); | 573 | memcpy(event.generic.string, string, event.generic.stringSize); |
829 | 572 | d->m_loggingThread->push(&event); | 574 | d->m_loggingThread->push(&event); |
830 | 573 | return true; | 575 | return true; |
831 | 574 | 576 | ||
832 | === modified file 'src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro' | |||
833 | --- src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro 2016-08-04 17:25:09 +0000 | |||
834 | +++ src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro 2016-08-31 08:57:26 +0000 | |||
835 | @@ -44,7 +44,15 @@ | |||
836 | 44 | mousetouchadaptor_p.h \ | 44 | mousetouchadaptor_p.h \ |
837 | 45 | mousetouchadaptor_p_p.h \ | 45 | mousetouchadaptor_p_p.h \ |
838 | 46 | propertychange_p.h \ | 46 | propertychange_p.h \ |
840 | 47 | ubuntutoolkitmodule.h | 47 | ubuntutoolkitmodule.h \ |
841 | 48 | splitview_p.h \ | ||
842 | 49 | splitview_p_p.h \ | ||
843 | 50 | privates/splitviewhandler_p_p.h \ | ||
844 | 51 | menu_p_p.h \ | ||
845 | 52 | menubar_p_p.h \ | ||
846 | 53 | menu_p.h \ | ||
847 | 54 | menubar_p.h \ | ||
848 | 55 | menugroup_p.h | ||
849 | 48 | 56 | ||
850 | 49 | SOURCES += \ | 57 | SOURCES += \ |
851 | 50 | colorutils.cpp \ | 58 | colorutils.cpp \ |
852 | @@ -52,7 +60,13 @@ | |||
853 | 52 | asyncloader.cpp \ | 60 | asyncloader.cpp \ |
854 | 53 | mousetouchadaptor.cpp \ | 61 | mousetouchadaptor.cpp \ |
855 | 54 | propertychange.cpp \ | 62 | propertychange.cpp \ |
857 | 55 | ubuntutoolkitmodule.cpp | 63 | ubuntutoolkitmodule.cpp \ |
858 | 64 | splitview.cpp \ | ||
859 | 65 | privates/splitviewhandler.cpp \ | ||
860 | 66 | splitviewlayout.cpp \ | ||
861 | 67 | menu.cpp \ | ||
862 | 68 | menubar.cpp \ | ||
863 | 69 | menugroup.cpp | ||
864 | 56 | 70 | ||
865 | 57 | HEADERS += \ | 71 | HEADERS += \ |
866 | 58 | uctheme_p.h \ | 72 | uctheme_p.h \ |
867 | @@ -149,7 +163,9 @@ | |||
868 | 149 | privates/appheaderbase_p.h \ | 163 | privates/appheaderbase_p.h \ |
869 | 150 | label_p.h \ | 164 | label_p.h \ |
870 | 151 | ucbottomedgeregion_p_p.h \ | 165 | ucbottomedgeregion_p_p.h \ |
872 | 152 | privates/ucscrollbarutils_p.h | 166 | privates/ucscrollbarutils_p.h \ |
873 | 167 | actionlist_p.h \ | ||
874 | 168 | exclusivegroup_p.h | ||
875 | 153 | 169 | ||
876 | 154 | SOURCES += \ | 170 | SOURCES += \ |
877 | 155 | uctheme.cpp \ | 171 | uctheme.cpp \ |
878 | @@ -226,7 +242,9 @@ | |||
879 | 226 | privates/ucpagewrapper.cpp \ | 242 | privates/ucpagewrapper.cpp \ |
880 | 227 | privates/ucpagewrapperincubator.cpp \ | 243 | privates/ucpagewrapperincubator.cpp \ |
881 | 228 | privates/appheaderbase.cpp \ | 244 | privates/appheaderbase.cpp \ |
883 | 229 | privates/ucscrollbarutils.cpp | 245 | privates/ucscrollbarutils.cpp \ |
884 | 246 | actionlist.cpp \ | ||
885 | 247 | exclusivegroup.cpp | ||
886 | 230 | 248 | ||
887 | 231 | # adapters | 249 | # adapters |
888 | 232 | SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp | 250 | SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp |
889 | 233 | 251 | ||
890 | === added file 'src/Ubuntu/UbuntuToolkit/actionlist.cpp' | |||
891 | --- src/Ubuntu/UbuntuToolkit/actionlist.cpp 1970-01-01 00:00:00 +0000 | |||
892 | +++ src/Ubuntu/UbuntuToolkit/actionlist.cpp 2016-08-31 08:57:26 +0000 | |||
893 | @@ -0,0 +1,158 @@ | |||
894 | 1 | /* | ||
895 | 2 | * Copyright 2016 Canonical Ltd. | ||
896 | 3 | * | ||
897 | 4 | * This program is free software; you can redistribute it and/or modify | ||
898 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
899 | 6 | * the Free Software Foundation; version 3. | ||
900 | 7 | * | ||
901 | 8 | * This program is distributed in the hope that it will be useful, | ||
902 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
903 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
904 | 11 | * GNU Lesser General Public License for more details. | ||
905 | 12 | * | ||
906 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
907 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
908 | 15 | */ | ||
909 | 16 | |||
910 | 17 | #include "actionlist_p.h" | ||
911 | 18 | #include "ucaction_p.h" | ||
912 | 19 | |||
913 | 20 | UT_NAMESPACE_BEGIN | ||
914 | 21 | |||
915 | 22 | /*! | ||
916 | 23 | * \qmltype ActionList | ||
917 | 24 | * \inqmlmodule Ubuntu.Components | ||
918 | 25 | * \ingroup ubuntu | ||
919 | 26 | * \brief List of \l Action items | ||
920 | 27 | * An ActionList provies a way of grouping actions together. | ||
921 | 28 | * \qml | ||
922 | 29 | * ActionList { | ||
923 | 30 | * Action { | ||
924 | 31 | * id: action1 | ||
925 | 32 | * } | ||
926 | 33 | * Action { | ||
927 | 34 | * id: action2 | ||
928 | 35 | * } | ||
929 | 36 | * } | ||
930 | 37 | * \endqml | ||
931 | 38 | */ | ||
932 | 39 | /*! | ||
933 | 40 | * \qmlsignal ActionList::added(Action action) | ||
934 | 41 | * \since Ubuntu.Components 1.3 | ||
935 | 42 | * Signal called when an action is added to the list | ||
936 | 43 | */ | ||
937 | 44 | /*! | ||
938 | 45 | * \qmlsignal ActionList::removed(Action action) | ||
939 | 46 | * \since Ubuntu.Components 1.3 | ||
940 | 47 | * Signal called when an action is removed from the list | ||
941 | 48 | */ | ||
942 | 49 | ActionList::ActionList(QObject *parent) | ||
943 | 50 | : QObject(parent) | ||
944 | 51 | { | ||
945 | 52 | } | ||
946 | 53 | |||
947 | 54 | /*! | ||
948 | 55 | * \qmlmethod ActionList::addAction(Action action) | ||
949 | 56 | * \since Ubuntu.Components 1.3 | ||
950 | 57 | * Adds an Action to the list programatically. | ||
951 | 58 | * \qml | ||
952 | 59 | * Item { | ||
953 | 60 | * Instantiator { | ||
954 | 61 | * model: 4 | ||
955 | 62 | * onObjectAdded: actionList.addAction(object) | ||
956 | 63 | * onObjectRemoved: actionList.removeAction(object) | ||
957 | 64 | * | ||
958 | 65 | * Action {} | ||
959 | 66 | * } | ||
960 | 67 | * | ||
961 | 68 | * ActionList { | ||
962 | 69 | * id: actionList | ||
963 | 70 | * } | ||
964 | 71 | * } | ||
965 | 72 | * \endqml | ||
966 | 73 | * \sa ActionList::removeAction | ||
967 | 74 | */ | ||
968 | 75 | void ActionList::addAction(UCAction *action) | ||
969 | 76 | { | ||
970 | 77 | if (m_actions.contains(action)) { | ||
971 | 78 | return; | ||
972 | 79 | } | ||
973 | 80 | m_actions.append(action); | ||
974 | 81 | Q_EMIT added(action); | ||
975 | 82 | } | ||
976 | 83 | |||
977 | 84 | /*! | ||
978 | 85 | * \qmlmethod ActionList::removeAction(Action action) | ||
979 | 86 | * \since Ubuntu.Components 1.3 | ||
980 | 87 | * Removes an action from the list programatically. | ||
981 | 88 | * \sa ActionList::addAction | ||
982 | 89 | */ | ||
983 | 90 | void ActionList::removeAction(UCAction *action) | ||
984 | 91 | { | ||
985 | 92 | if (!action) { | ||
986 | 93 | return; | ||
987 | 94 | } | ||
988 | 95 | if (m_actions.removeOne(action)) { | ||
989 | 96 | Q_EMIT removed(action); | ||
990 | 97 | } | ||
991 | 98 | } | ||
992 | 99 | |||
993 | 100 | /*! | ||
994 | 101 | * \qmlproperty list<Action> ActionList::actions | ||
995 | 102 | * \default | ||
996 | 103 | * List of Actions in this ActionList | ||
997 | 104 | * Note that when you set this property, the children of the ActionList will be ignored, | ||
998 | 105 | * so do not set the list and define children. | ||
999 | 106 | * | ||
1000 | 107 | * The advantage of setting actions over using the children is that the same | ||
1001 | 108 | * \l Action items can be used in several sets of actions. | ||
1002 | 109 | */ | ||
1003 | 110 | QQmlListProperty<UCAction> ActionList::actions() | ||
1004 | 111 | { | ||
1005 | 112 | return QQmlListProperty<UCAction>(this, 0, | ||
1006 | 113 | ActionList::append, | ||
1007 | 114 | ActionList::count, | ||
1008 | 115 | ActionList::at, | ||
1009 | 116 | ActionList::clear); | ||
1010 | 117 | } | ||
1011 | 118 | |||
1012 | 119 | const QList<UCAction*> &ActionList::list() const | ||
1013 | 120 | { | ||
1014 | 121 | return m_actions; | ||
1015 | 122 | } | ||
1016 | 123 | |||
1017 | 124 | void ActionList::append(QQmlListProperty<UCAction> *list, UCAction *action) | ||
1018 | 125 | { | ||
1019 | 126 | ActionList *actionList = qobject_cast<ActionList*>(list->object); | ||
1020 | 127 | if (actionList) { | ||
1021 | 128 | actionList->addAction(action); | ||
1022 | 129 | } | ||
1023 | 130 | } | ||
1024 | 131 | |||
1025 | 132 | void ActionList::clear(QQmlListProperty<UCAction> *list) | ||
1026 | 133 | { | ||
1027 | 134 | ActionList *actionList = qobject_cast<ActionList*>(list->object); | ||
1028 | 135 | if (actionList) { | ||
1029 | 136 | actionList->m_actions.clear(); | ||
1030 | 137 | } | ||
1031 | 138 | } | ||
1032 | 139 | |||
1033 | 140 | UCAction* ActionList::at(QQmlListProperty<UCAction> *list, int index) | ||
1034 | 141 | { | ||
1035 | 142 | ActionList *actionList = qobject_cast<ActionList*>(list->object); | ||
1036 | 143 | if (actionList) { | ||
1037 | 144 | return actionList->m_actions.value(index, nullptr); | ||
1038 | 145 | } | ||
1039 | 146 | return Q_NULLPTR; | ||
1040 | 147 | } | ||
1041 | 148 | |||
1042 | 149 | int ActionList::count(QQmlListProperty<UCAction> *list) | ||
1043 | 150 | { | ||
1044 | 151 | ActionList *actionList = qobject_cast<ActionList*>(list->object); | ||
1045 | 152 | if (actionList) { | ||
1046 | 153 | return actionList->m_actions.count(); | ||
1047 | 154 | } | ||
1048 | 155 | return 0; | ||
1049 | 156 | } | ||
1050 | 157 | |||
1051 | 158 | UT_NAMESPACE_END | ||
1052 | 0 | 159 | ||
1053 | === added file 'src/Ubuntu/UbuntuToolkit/actionlist_p.h' | |||
1054 | --- src/Ubuntu/UbuntuToolkit/actionlist_p.h 1970-01-01 00:00:00 +0000 | |||
1055 | +++ src/Ubuntu/UbuntuToolkit/actionlist_p.h 2016-08-31 08:57:26 +0000 | |||
1056 | @@ -0,0 +1,58 @@ | |||
1057 | 1 | /* | ||
1058 | 2 | * Copyright 2016 Canonical Ltd. | ||
1059 | 3 | * | ||
1060 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1061 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
1062 | 6 | * the Free Software Foundation; version 3. | ||
1063 | 7 | * | ||
1064 | 8 | * This program is distributed in the hope that it will be useful, | ||
1065 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1066 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1067 | 11 | * GNU Lesser General Public License for more details. | ||
1068 | 12 | * | ||
1069 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
1070 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1071 | 15 | */ | ||
1072 | 16 | |||
1073 | 17 | #ifndef ACTIONLIST_H | ||
1074 | 18 | #define ACTIONLIST_H | ||
1075 | 19 | |||
1076 | 20 | #include <QObject> | ||
1077 | 21 | #include <QtQml/QQmlListProperty> | ||
1078 | 22 | #include "ubuntutoolkitglobal.h" | ||
1079 | 23 | |||
1080 | 24 | UT_NAMESPACE_BEGIN | ||
1081 | 25 | |||
1082 | 26 | class UCAction; | ||
1083 | 27 | class UBUNTUTOOLKIT_EXPORT ActionList : public QObject | ||
1084 | 28 | { | ||
1085 | 29 | Q_OBJECT | ||
1086 | 30 | Q_PROPERTY(QQmlListProperty<UT_PREPEND_NAMESPACE(UCAction)> actions READ actions) | ||
1087 | 31 | Q_CLASSINFO("DefaultProperty", "actions") | ||
1088 | 32 | public: | ||
1089 | 33 | explicit ActionList(QObject *parent = 0); | ||
1090 | 34 | |||
1091 | 35 | QQmlListProperty<UCAction> actions(); | ||
1092 | 36 | |||
1093 | 37 | const QList<UCAction*> &list() const; | ||
1094 | 38 | |||
1095 | 39 | public Q_SLOTS: | ||
1096 | 40 | void addAction(UT_PREPEND_NAMESPACE(UCAction) *action); | ||
1097 | 41 | void removeAction(UT_PREPEND_NAMESPACE(UCAction) *action); | ||
1098 | 42 | |||
1099 | 43 | Q_SIGNALS: | ||
1100 | 44 | void added(UCAction *action); | ||
1101 | 45 | void removed(UCAction *action); | ||
1102 | 46 | |||
1103 | 47 | protected: | ||
1104 | 48 | QList<UCAction*> m_actions; | ||
1105 | 49 | |||
1106 | 50 | static void append(QQmlListProperty<UCAction> *list, UCAction *action); | ||
1107 | 51 | static void clear(QQmlListProperty<UCAction> *list); | ||
1108 | 52 | static UCAction* at(QQmlListProperty<UCAction> *list, int index); | ||
1109 | 53 | static int count(QQmlListProperty<UCAction> *list); | ||
1110 | 54 | }; | ||
1111 | 55 | |||
1112 | 56 | UT_NAMESPACE_END | ||
1113 | 57 | |||
1114 | 58 | #endif // ACTIONLIST_H | ||
1115 | 0 | 59 | ||
1116 | === added file 'src/Ubuntu/UbuntuToolkit/exclusivegroup.cpp' | |||
1117 | --- src/Ubuntu/UbuntuToolkit/exclusivegroup.cpp 1970-01-01 00:00:00 +0000 | |||
1118 | +++ src/Ubuntu/UbuntuToolkit/exclusivegroup.cpp 2016-08-31 08:57:26 +0000 | |||
1119 | @@ -0,0 +1,168 @@ | |||
1120 | 1 | /* | ||
1121 | 2 | * Copyright 2016 Canonical Ltd. | ||
1122 | 3 | * | ||
1123 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1124 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
1125 | 6 | * the Free Software Foundation; version 3. | ||
1126 | 7 | * | ||
1127 | 8 | * This program is distributed in the hope that it will be useful, | ||
1128 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1129 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1130 | 11 | * GNU Lesser General Public License for more details. | ||
1131 | 12 | * | ||
1132 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
1133 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1134 | 15 | * | ||
1135 | 16 | */ | ||
1136 | 17 | |||
1137 | 18 | #include "exclusivegroup_p.h" | ||
1138 | 19 | #include "ucaction_p.h" | ||
1139 | 20 | |||
1140 | 21 | #include <QSignalMapper> | ||
1141 | 22 | |||
1142 | 23 | #define CHECKED_PROPERTY "checked" | ||
1143 | 24 | |||
1144 | 25 | UT_NAMESPACE_BEGIN | ||
1145 | 26 | |||
1146 | 27 | static const char *checkableSignals[] = { | ||
1147 | 28 | "toggled(bool)", | ||
1148 | 29 | 0 | ||
1149 | 30 | }; | ||
1150 | 31 | |||
1151 | 32 | static bool isChecked(const QObject *o) | ||
1152 | 33 | { | ||
1153 | 34 | if (!o) return false; | ||
1154 | 35 | QVariant checkedVariant = o->property(CHECKED_PROPERTY); | ||
1155 | 36 | return checkedVariant.isValid() && checkedVariant.toBool(); | ||
1156 | 37 | } | ||
1157 | 38 | |||
1158 | 39 | /*! | ||
1159 | 40 | * \qmltype ExclusiveGroup | ||
1160 | 41 | * \inqmlmodule Ubuntu.Components | ||
1161 | 42 | * \since Ubuntu.Components 1.3 | ||
1162 | 43 | * \ingroup ubuntu | ||
1163 | 44 | * \inherits ActionList | ||
1164 | 45 | * \brief ExclusiveGroup provides a way to declare several checkable controls as mutually exclusive. | ||
1165 | 46 | * | ||
1166 | 47 | * The ExclusiveGroup will only allow a single object to have it's checkable property set to "true" | ||
1167 | 48 | * at any one time. The exclusive group accepts child Actions, but objects other than Actions can be | ||
1168 | 49 | * used by using the \l bindCheckable function as long as they support one of the required signals, | ||
1169 | 50 | * and a "checked" property. | ||
1170 | 51 | * \qml | ||
1171 | 52 | * ExclusiveGroup { | ||
1172 | 53 | * Action { | ||
1173 | 54 | * parameterType: Action.Bool | ||
1174 | 55 | * state: true | ||
1175 | 56 | * } | ||
1176 | 57 | * Action { | ||
1177 | 58 | * parameterType: Action.Bool | ||
1178 | 59 | * state: false | ||
1179 | 60 | * } | ||
1180 | 61 | * } | ||
1181 | 62 | * \endqml | ||
1182 | 63 | */ | ||
1183 | 64 | ExclusiveGroup::ExclusiveGroup(QObject *parent) | ||
1184 | 65 | : ActionList(parent) | ||
1185 | 66 | , m_signalMapper(new QSignalMapper(this)) | ||
1186 | 67 | , m_entranceGuard(false) | ||
1187 | 68 | { | ||
1188 | 69 | connect(this, &ActionList::added, this, &ExclusiveGroup::onActionAdded); | ||
1189 | 70 | connect(this, &ActionList::removed, this, &ExclusiveGroup::onActionRemoved); | ||
1190 | 71 | |||
1191 | 72 | int index = m_signalMapper->metaObject()->indexOfMethod("map()"); | ||
1192 | 73 | m_updateCurrentMethod = m_signalMapper->metaObject()->method(index); | ||
1193 | 74 | connect(m_signalMapper, static_cast<void(QSignalMapper::*)(QObject *)>(&QSignalMapper::mapped), this, [this](QObject *object) { | ||
1194 | 75 | if (isChecked(object)) { | ||
1195 | 76 | setCurrent(object); | ||
1196 | 77 | } | ||
1197 | 78 | }); | ||
1198 | 79 | } | ||
1199 | 80 | |||
1200 | 81 | void ExclusiveGroup::onActionAdded(UCAction *action) | ||
1201 | 82 | { | ||
1202 | 83 | action->setExclusiveGroup(this); | ||
1203 | 84 | } | ||
1204 | 85 | |||
1205 | 86 | void ExclusiveGroup::onActionRemoved(UCAction *action) | ||
1206 | 87 | { | ||
1207 | 88 | action->setExclusiveGroup(nullptr); | ||
1208 | 89 | } | ||
1209 | 90 | |||
1210 | 91 | /*! | ||
1211 | 92 | * \qmlproperty Action ExclusiveGroup::current | ||
1212 | 93 | * Returns the currently checked action | ||
1213 | 94 | */ | ||
1214 | 95 | void ExclusiveGroup::setCurrent(QObject *object) | ||
1215 | 96 | { | ||
1216 | 97 | if (m_current == object) | ||
1217 | 98 | return; | ||
1218 | 99 | |||
1219 | 100 | if (m_current) | ||
1220 | 101 | m_current->setProperty(CHECKED_PROPERTY, QVariant(false)); | ||
1221 | 102 | m_current = object; | ||
1222 | 103 | if (m_current) | ||
1223 | 104 | m_current->setProperty(CHECKED_PROPERTY, QVariant(true)); | ||
1224 | 105 | Q_EMIT currentChanged(); | ||
1225 | 106 | } | ||
1226 | 107 | |||
1227 | 108 | QObject *ExclusiveGroup::current() const | ||
1228 | 109 | { | ||
1229 | 110 | return m_current.data(); | ||
1230 | 111 | } | ||
1231 | 112 | |||
1232 | 113 | /*! | ||
1233 | 114 | * \qmlmethod void ExclusiveGroup::bindCheckable(object object) | ||
1234 | 115 | * Explicitly bind an objects checkability to this exclusive group. | ||
1235 | 116 | * \note This only works with objects which support the following signals signals: | ||
1236 | 117 | * \list | ||
1237 | 118 | * \li \b toggled(bool) | ||
1238 | 119 | * \endlist | ||
1239 | 120 | * \qml | ||
1240 | 121 | * Item { | ||
1241 | 122 | * ExclusiveGroup { | ||
1242 | 123 | * id: exclusiveGroup | ||
1243 | 124 | * } | ||
1244 | 125 | * Instantiator { | ||
1245 | 126 | * model: 4 | ||
1246 | 127 | * onObjectAdded: exclusiveGroup.bindCheckable(object) | ||
1247 | 128 | * onObjectRemoved: exclusiveGroup.unbindCheckable(object) | ||
1248 | 129 | * | ||
1249 | 130 | * Action { | ||
1250 | 131 | * checkable: true | ||
1251 | 132 | * } | ||
1252 | 133 | * } | ||
1253 | 134 | * } | ||
1254 | 135 | * \endqml | ||
1255 | 136 | * \sa ExclusiveGroup::unbindCheckable | ||
1256 | 137 | */ | ||
1257 | 138 | void ExclusiveGroup::bindCheckable(QObject *object) | ||
1258 | 139 | { | ||
1259 | 140 | for (const char **signalName = checkableSignals; *signalName; signalName++) { | ||
1260 | 141 | int signalIndex = object->metaObject()->indexOfSignal(*signalName); | ||
1261 | 142 | if (signalIndex != -1) { | ||
1262 | 143 | QMetaMethod signalMethod = object->metaObject()->method(signalIndex); | ||
1263 | 144 | connect(object, signalMethod, m_signalMapper, m_updateCurrentMethod, Qt::UniqueConnection); | ||
1264 | 145 | m_signalMapper->setMapping(object, object); | ||
1265 | 146 | connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unbindCheckable(QObject*)), Qt::UniqueConnection); | ||
1266 | 147 | if (!m_current && isChecked(object)) | ||
1267 | 148 | setCurrent(object); | ||
1268 | 149 | break; | ||
1269 | 150 | } | ||
1270 | 151 | } | ||
1271 | 152 | } | ||
1272 | 153 | |||
1273 | 154 | /*! | ||
1274 | 155 | * \qmlmethod void ExclusiveGroup::unbindCheckable(object object) | ||
1275 | 156 | * Explicitly unbind an objects checkability from this exclusive group. | ||
1276 | 157 | * \sa ExclusiveGroup::bindCheckable | ||
1277 | 158 | */ | ||
1278 | 159 | void ExclusiveGroup::unbindCheckable(QObject *object) | ||
1279 | 160 | { | ||
1280 | 161 | if (m_current == object) | ||
1281 | 162 | setCurrent(0); | ||
1282 | 163 | |||
1283 | 164 | disconnect(object, 0, m_signalMapper, 0); | ||
1284 | 165 | disconnect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unbindCheckable(QObject*))); | ||
1285 | 166 | } | ||
1286 | 167 | |||
1287 | 168 | UT_NAMESPACE_END | ||
1288 | 0 | 169 | ||
1289 | === added file 'src/Ubuntu/UbuntuToolkit/exclusivegroup_p.h' | |||
1290 | --- src/Ubuntu/UbuntuToolkit/exclusivegroup_p.h 1970-01-01 00:00:00 +0000 | |||
1291 | +++ src/Ubuntu/UbuntuToolkit/exclusivegroup_p.h 2016-08-31 08:57:26 +0000 | |||
1292 | @@ -0,0 +1,62 @@ | |||
1293 | 1 | /* | ||
1294 | 2 | * Copyright 2016 Canonical Ltd. | ||
1295 | 3 | * | ||
1296 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1297 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
1298 | 6 | * the Free Software Foundation; version 3. | ||
1299 | 7 | * | ||
1300 | 8 | * This program is distributed in the hope that it will be useful, | ||
1301 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1302 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1303 | 11 | * GNU Lesser General Public License for more details. | ||
1304 | 12 | * | ||
1305 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
1306 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1307 | 15 | * | ||
1308 | 16 | */ | ||
1309 | 17 | |||
1310 | 18 | #ifndef EXCLUSIVEGROUP_H | ||
1311 | 19 | #define EXCLUSIVEGROUP_H | ||
1312 | 20 | |||
1313 | 21 | #include "actionlist_p.h" | ||
1314 | 22 | #include "ubuntutoolkitglobal.h" | ||
1315 | 23 | |||
1316 | 24 | #include <QMetaMethod> | ||
1317 | 25 | #include <QPointer> | ||
1318 | 26 | |||
1319 | 27 | class QSignalMapper; | ||
1320 | 28 | |||
1321 | 29 | UT_NAMESPACE_BEGIN | ||
1322 | 30 | |||
1323 | 31 | class UBUNTUTOOLKIT_EXPORT ExclusiveGroup : public ActionList | ||
1324 | 32 | { | ||
1325 | 33 | Q_OBJECT | ||
1326 | 34 | Q_PROPERTY(QObject* current READ current NOTIFY currentChanged) | ||
1327 | 35 | |||
1328 | 36 | public: | ||
1329 | 37 | explicit ExclusiveGroup(QObject *parent = 0); | ||
1330 | 38 | |||
1331 | 39 | QObject* current() const; | ||
1332 | 40 | |||
1333 | 41 | Q_INVOKABLE void bindCheckable(QObject* object); | ||
1334 | 42 | Q_INVOKABLE void unbindCheckable(QObject* object); | ||
1335 | 43 | |||
1336 | 44 | Q_SIGNALS: | ||
1337 | 45 | void currentChanged(); | ||
1338 | 46 | |||
1339 | 47 | protected Q_SLOTS: | ||
1340 | 48 | void onActionAdded(UCAction* action); | ||
1341 | 49 | void onActionRemoved(UCAction* action); | ||
1342 | 50 | |||
1343 | 51 | private: | ||
1344 | 52 | void setCurrent(QObject* action); | ||
1345 | 53 | |||
1346 | 54 | QSignalMapper* m_signalMapper; | ||
1347 | 55 | QPointer<QObject> m_current; | ||
1348 | 56 | QMetaMethod m_updateCurrentMethod; | ||
1349 | 57 | bool m_entranceGuard; | ||
1350 | 58 | }; | ||
1351 | 59 | |||
1352 | 60 | UT_NAMESPACE_END | ||
1353 | 61 | |||
1354 | 62 | #endif // EXCLUSIVEGROUP_H | ||
1355 | 0 | 63 | ||
1356 | === added file 'src/Ubuntu/UbuntuToolkit/menu.cpp' | |||
1357 | --- src/Ubuntu/UbuntuToolkit/menu.cpp 1970-01-01 00:00:00 +0000 | |||
1358 | +++ src/Ubuntu/UbuntuToolkit/menu.cpp 2016-08-31 08:57:26 +0000 | |||
1359 | @@ -0,0 +1,671 @@ | |||
1360 | 1 | /* | ||
1361 | 2 | * Copyright 2016 Canonical Ltd. | ||
1362 | 3 | * | ||
1363 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1364 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
1365 | 6 | * the Free Software Foundation; version 3. | ||
1366 | 7 | * | ||
1367 | 8 | * This program is distributed in the hope that it will be useful, | ||
1368 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1369 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1370 | 11 | * GNU Lesser General Public License for more details. | ||
1371 | 12 | * | ||
1372 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
1373 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1374 | 15 | */ | ||
1375 | 16 | |||
1376 | 17 | #include "menu_p.h" | ||
1377 | 18 | #include "menu_p_p.h" | ||
1378 | 19 | #include "menubar_p.h" | ||
1379 | 20 | #include "actionlist_p.h" | ||
1380 | 21 | #include "menugroup_p.h" | ||
1381 | 22 | |||
1382 | 23 | // Qt | ||
1383 | 24 | #include <QPointer> | ||
1384 | 25 | #include <QQuickItem> | ||
1385 | 26 | #include <QLoggingCategory> | ||
1386 | 27 | #include <QtGui/qpa/qplatformtheme.h> | ||
1387 | 28 | #include <QtGui/qpa/qplatformmenu.h> | ||
1388 | 29 | #include <private/qguiapplication_p.h> | ||
1389 | 30 | #include <private/qquickitem_p.h> | ||
1390 | 31 | |||
1391 | 32 | #include <functional> | ||
1392 | 33 | |||
1393 | 34 | Q_LOGGING_CATEGORY(ucMenu, "ubuntu.components.Menu", QtMsgType::QtWarningMsg) | ||
1394 | 35 | |||
1395 | 36 | UT_NAMESPACE_BEGIN | ||
1396 | 37 | |||
1397 | 38 | namespace { | ||
1398 | 39 | |||
1399 | 40 | QWindow* findWindowForObject(QObject* object) | ||
1400 | 41 | { | ||
1401 | 42 | QObject* window = object; | ||
1402 | 43 | while (window && !window->isWindowType()) { | ||
1403 | 44 | window = window->parent(); | ||
1404 | 45 | if (QQuickItem* item = qobject_cast<QQuickItem*>(window)) { | ||
1405 | 46 | window = item->window(); | ||
1406 | 47 | } | ||
1407 | 48 | } | ||
1408 | 49 | return qobject_cast<QWindow*>(window); | ||
1409 | 50 | } | ||
1410 | 51 | |||
1411 | 52 | // recursively get the all the object from the menu group which are not lists or groups. | ||
1412 | 53 | QObjectList getActionsFromMenuGroup(MenuGroup* menuGroup) { | ||
1413 | 54 | |||
1414 | 55 | QObjectList objectList; | ||
1415 | 56 | |||
1416 | 57 | Q_FOREACH(QObject* data, menuGroup->list()) { | ||
1417 | 58 | |||
1418 | 59 | if (auto actionList = qobject_cast<ActionList*>(data)) { | ||
1419 | 60 | Q_FOREACH(UCAction* action, actionList->list()) { | ||
1420 | 61 | objectList << action; | ||
1421 | 62 | } | ||
1422 | 63 | } else if (auto subMenuGroup = qobject_cast<MenuGroup*>(data)) { | ||
1423 | 64 | objectList << getActionsFromMenuGroup(subMenuGroup); | ||
1424 | 65 | } else { | ||
1425 | 66 | objectList << data; | ||
1426 | 67 | } | ||
1427 | 68 | } | ||
1428 | 69 | return objectList; | ||
1429 | 70 | } | ||
1430 | 71 | |||
1431 | 72 | // recursively get the first object from the menu group which is not a list or a group. | ||
1432 | 73 | QObject* getFirstObject(MenuGroup* menuGroup) { | ||
1433 | 74 | |||
1434 | 75 | Q_FOREACH(QObject* data, menuGroup->list()) { | ||
1435 | 76 | |||
1436 | 77 | if (auto subMenuGroup = qobject_cast<MenuGroup*>(data)) { | ||
1437 | 78 | QObject* object = getFirstObject(subMenuGroup); | ||
1438 | 79 | if (object) { return object; } | ||
1439 | 80 | } else if (auto actionList = qobject_cast<ActionList*>(data)) { | ||
1440 | 81 | return actionList->list().count() > 0 ? actionList->list()[0] : 0; | ||
1441 | 82 | } else { | ||
1442 | 83 | return data; | ||
1443 | 84 | } | ||
1444 | 85 | } | ||
1445 | 86 | return Q_NULLPTR; | ||
1446 | 87 | } | ||
1447 | 88 | |||
1448 | 89 | } | ||
1449 | 90 | |||
1450 | 91 | MenuPrivate::MenuPrivate(Menu *qq) | ||
1451 | 92 | : q_ptr(qq) | ||
1452 | 93 | , m_platformMenu(QGuiApplicationPrivate::platformTheme()->createPlatformMenu()) | ||
1453 | 94 | { | ||
1454 | 95 | } | ||
1455 | 96 | |||
1456 | 97 | MenuPrivate::~MenuPrivate() | ||
1457 | 98 | { | ||
1458 | 99 | qDeleteAll(m_platformItems); | ||
1459 | 100 | m_platformItems.clear(); | ||
1460 | 101 | |||
1461 | 102 | delete m_platformMenu; | ||
1462 | 103 | m_platformMenu = Q_NULLPTR; | ||
1463 | 104 | } | ||
1464 | 105 | |||
1465 | 106 | void MenuPrivate::insertObject(int index, QObject *o) | ||
1466 | 107 | { | ||
1467 | 108 | Q_Q(Menu); | ||
1468 | 109 | if (!o) return; | ||
1469 | 110 | qCDebug(ucMenu).nospace() << "Menu::insertObject(index="<< index << ", object=" << o << ")"; | ||
1470 | 111 | |||
1471 | 112 | if (!m_platformMenu) { | ||
1472 | 113 | m_data.insert(m_data.count() > index ? index : m_data.count(), o); | ||
1473 | 114 | return; | ||
1474 | 115 | } | ||
1475 | 116 | |||
1476 | 117 | // If the menus contains lists or groups, we need to alter the insertion index to account for them. | ||
1477 | 118 | int actualIndex = 0; | ||
1478 | 119 | bool insertSeparator = false; | ||
1479 | 120 | for (int i = 0; i < index && i < m_data.count(); i++) { | ||
1480 | 121 | QObject* data = m_data[i]; | ||
1481 | 122 | |||
1482 | 123 | int dataObjectCount = 0; | ||
1483 | 124 | if (auto menuGroup = qobject_cast<MenuGroup*>(data)) { | ||
1484 | 125 | dataObjectCount = getActionsFromMenuGroup(menuGroup).count(); | ||
1485 | 126 | } else if (auto list = qobject_cast<ActionList*>(data)) { | ||
1486 | 127 | dataObjectCount = list->list().count(); | ||
1487 | 128 | } else { | ||
1488 | 129 | dataObjectCount = 1; | ||
1489 | 130 | } | ||
1490 | 131 | actualIndex += dataObjectCount; | ||
1491 | 132 | // insert a separator before the new item if there are previous items. | ||
1492 | 133 | insertSeparator |= dataObjectCount > 0; | ||
1493 | 134 | |||
1494 | 135 | // account for item separators if it's not the last data item. | ||
1495 | 136 | actualIndex += dataObjectCount > 0 && (i+1 < index && i+1 < m_data.count()) ? 1: 0; | ||
1496 | 137 | } | ||
1497 | 138 | |||
1498 | 139 | // need to make sure the item after the insertion index has a separator | ||
1499 | 140 | if (index < m_data.count()) { | ||
1500 | 141 | QObject* data = m_data.at(index); | ||
1501 | 142 | QObject* objectToSeparate(Q_NULLPTR); | ||
1502 | 143 | |||
1503 | 144 | if (auto menuGroup = qobject_cast<MenuGroup*>(data)) { | ||
1504 | 145 | objectToSeparate = getFirstObject(menuGroup); | ||
1505 | 146 | } else if (auto actionList = qobject_cast<ActionList*>(data)) { | ||
1506 | 147 | objectToSeparate = actionList->list().count() > 0 ? actionList->list()[0] : 0; | ||
1507 | 148 | } else { | ||
1508 | 149 | objectToSeparate = data; | ||
1509 | 150 | } | ||
1510 | 151 | |||
1511 | 152 | if (objectToSeparate && m_platformItems.contains(objectToSeparate)) { | ||
1512 | 153 | m_platformItems.value(objectToSeparate)->setSeparator(); | ||
1513 | 154 | } | ||
1514 | 155 | } | ||
1515 | 156 | |||
1516 | 157 | m_data.insert(m_data.count() > index ? index : m_data.count(), o); | ||
1517 | 158 | |||
1518 | 159 | // if an object changes, we need to remove and re-add it. | ||
1519 | 160 | std::function<void()> refreshObject = [o, this]() { | ||
1520 | 161 | int index = m_data.indexOf(o); | ||
1521 | 162 | if (index >= 0) { | ||
1522 | 163 | removeObject(o); | ||
1523 | 164 | insertObject(index, o); | ||
1524 | 165 | } | ||
1525 | 166 | }; | ||
1526 | 167 | |||
1527 | 168 | // Get All the menu item objects | ||
1528 | 169 | QObjectList objects; | ||
1529 | 170 | if (auto menuGroup = qobject_cast<MenuGroup*>(o)) { | ||
1530 | 171 | Q_FOREACH(QObject* menuGroupObject, getActionsFromMenuGroup(menuGroup)) { | ||
1531 | 172 | objects << menuGroupObject; | ||
1532 | 173 | } | ||
1533 | 174 | // connect to content changes | ||
1534 | 175 | QObject::connect(menuGroup, &MenuGroup::changed, q, refreshObject); | ||
1535 | 176 | } else if (auto actionList = qobject_cast<ActionList*>(o)) { | ||
1536 | 177 | Q_FOREACH(UCAction* action, actionList->list()) { | ||
1537 | 178 | objects << action; | ||
1538 | 179 | } | ||
1539 | 180 | // connect to content changes | ||
1540 | 181 | QObject::connect(actionList, &ActionList::added, q, refreshObject); | ||
1541 | 182 | QObject::connect(actionList, &ActionList::removed, q, refreshObject); | ||
1542 | 183 | } else { | ||
1543 | 184 | objects << o; | ||
1544 | 185 | } | ||
1545 | 186 | |||
1546 | 187 | Q_FOREACH(QObject* platformObject, objects) { | ||
1547 | 188 | // add to platform | ||
1548 | 189 | auto platformWrapper = new PlatformItemWrapper(platformObject, q); | ||
1549 | 190 | platformWrapper->insert(actualIndex++, insertSeparator); | ||
1550 | 191 | if (platformWrapper->hasSeparator()) { // we also inserted an separator, need to increment for next position. | ||
1551 | 192 | actualIndex++; | ||
1552 | 193 | } | ||
1553 | 194 | insertSeparator = false; | ||
1554 | 195 | m_platformItems[platformObject] = platformWrapper; | ||
1555 | 196 | // map the inserted item with the object which sources the platformItem info. | ||
1556 | 197 | if (!m_dataPlatformObjectMap.contains(o, platformObject)) { | ||
1557 | 198 | m_dataPlatformObjectMap.insertMulti(o, platformObject); | ||
1558 | 199 | } | ||
1559 | 200 | |||
1560 | 201 | QObject::connect(platformObject, &QObject::destroyed, q, [o, this](QObject* platformObject) { | ||
1561 | 202 | m_dataPlatformObjectMap.remove(o, platformObject); | ||
1562 | 203 | |||
1563 | 204 | if (m_platformItems.contains(platformObject)) { | ||
1564 | 205 | PlatformItemWrapper* wrapper = m_platformItems.take(platformObject); | ||
1565 | 206 | wrapper->remove(); | ||
1566 | 207 | delete wrapper; | ||
1567 | 208 | } | ||
1568 | 209 | }); | ||
1569 | 210 | } | ||
1570 | 211 | } | ||
1571 | 212 | |||
1572 | 213 | void MenuPrivate::removeObject(QObject *o) | ||
1573 | 214 | { | ||
1574 | 215 | Q_Q(Menu); | ||
1575 | 216 | m_data.removeOne(o); | ||
1576 | 217 | qCDebug(ucMenu).nospace() << "Menu::removeObject(" << o << ")"; | ||
1577 | 218 | |||
1578 | 219 | if (m_platformMenu) { | ||
1579 | 220 | if (auto menuGroup = qobject_cast<MenuGroup*>(o)) { | ||
1580 | 221 | // disconnect from content changes | ||
1581 | 222 | QObject::disconnect(menuGroup, &MenuGroup::changed, q, 0); | ||
1582 | 223 | } else if (ActionList* actionList = qobject_cast<ActionList*>(o)) { | ||
1583 | 224 | // disconnect from content changes | ||
1584 | 225 | QObject::disconnect(actionList, &ActionList::added, q, 0); | ||
1585 | 226 | QObject::disconnect(actionList, &ActionList::removed, q, 0); | ||
1586 | 227 | } | ||
1587 | 228 | |||
1588 | 229 | QList<QObject*> platformObjects = m_dataPlatformObjectMap.values(o); | ||
1589 | 230 | m_dataPlatformObjectMap.remove(o); | ||
1590 | 231 | |||
1591 | 232 | Q_FOREACH(QObject* platformObject, platformObjects) { | ||
1592 | 233 | // remove from platform. | ||
1593 | 234 | if (m_platformItems.contains(platformObject)) { | ||
1594 | 235 | PlatformItemWrapper* wrapper = m_platformItems.take(platformObject); | ||
1595 | 236 | wrapper->remove(); | ||
1596 | 237 | delete wrapper; | ||
1597 | 238 | } | ||
1598 | 239 | } | ||
1599 | 240 | } | ||
1600 | 241 | } | ||
1601 | 242 | |||
1602 | 243 | void MenuPrivate::_q_updateEnabled() | ||
1603 | 244 | { | ||
1604 | 245 | Q_Q(Menu); | ||
1605 | 246 | |||
1606 | 247 | bool isEnabled = q->isEnabled(); | ||
1607 | 248 | if (m_platformMenu) { m_platformMenu->setEnabled(isEnabled); } | ||
1608 | 249 | } | ||
1609 | 250 | |||
1610 | 251 | void MenuPrivate::_q_updateText() | ||
1611 | 252 | { | ||
1612 | 253 | Q_Q(Menu); | ||
1613 | 254 | |||
1614 | 255 | QString text = q->text(); | ||
1615 | 256 | if (m_platformMenu) { m_platformMenu->setText(text); } | ||
1616 | 257 | } | ||
1617 | 258 | |||
1618 | 259 | void MenuPrivate::_q_updateIcon() | ||
1619 | 260 | { | ||
1620 | 261 | Q_Q(Menu); | ||
1621 | 262 | |||
1622 | 263 | QIcon icon; | ||
1623 | 264 | if (!q->iconSource().isEmpty()) { | ||
1624 | 265 | icon = QIcon(q->iconSource().path()); | ||
1625 | 266 | } else if (!q->iconName().isEmpty()) { | ||
1626 | 267 | icon = QIcon::fromTheme(q->iconName()); | ||
1627 | 268 | } | ||
1628 | 269 | |||
1629 | 270 | if (m_platformMenu) { m_platformMenu->setIcon(icon); } | ||
1630 | 271 | } | ||
1631 | 272 | |||
1632 | 273 | void MenuPrivate::_q_updateVisible() | ||
1633 | 274 | { | ||
1634 | 275 | Q_Q(Menu); | ||
1635 | 276 | |||
1636 | 277 | bool visible = q->visible(); | ||
1637 | 278 | if (m_platformMenu) { m_platformMenu->setVisible(visible); } | ||
1638 | 279 | } | ||
1639 | 280 | |||
1640 | 281 | void MenuPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o) | ||
1641 | 282 | { | ||
1642 | 283 | Menu *q = qobject_cast<Menu *>(prop->object); | ||
1643 | 284 | q->appendObject(o); | ||
1644 | 285 | } | ||
1645 | 286 | |||
1646 | 287 | int MenuPrivate::data_count(QQmlListProperty<QObject> *prop) | ||
1647 | 288 | { | ||
1648 | 289 | MenuPrivate *p = static_cast<MenuPrivate *>(prop->data); | ||
1649 | 290 | return p->m_data.count(); | ||
1650 | 291 | } | ||
1651 | 292 | |||
1652 | 293 | QObject *MenuPrivate::data_at(QQmlListProperty<QObject> *prop, int index) | ||
1653 | 294 | { | ||
1654 | 295 | MenuPrivate *p = static_cast<MenuPrivate *>(prop->data); | ||
1655 | 296 | return p->m_data.value(index, Q_NULLPTR); | ||
1656 | 297 | } | ||
1657 | 298 | |||
1658 | 299 | void MenuPrivate::data_clear(QQmlListProperty<QObject> *prop) | ||
1659 | 300 | { | ||
1660 | 301 | MenuPrivate *p = static_cast<MenuPrivate *>(prop->data); | ||
1661 | 302 | p->m_data.clear(); | ||
1662 | 303 | } | ||
1663 | 304 | |||
1664 | 305 | /*! | ||
1665 | 306 | * \qmltype Menu | ||
1666 | 307 | * \inqmlmodule Ubuntu.Components | ||
1667 | 308 | * \ingroup ubuntu | ||
1668 | 309 | * \brief Menu defines a context menu or submenu structure of a MenuBar | ||
1669 | 310 | * | ||
1670 | 311 | * Example usage: | ||
1671 | 312 | * \qml | ||
1672 | 313 | * import QtQuick 2.4 | ||
1673 | 314 | * import Ubuntu.Components 1.3 | ||
1674 | 315 | * Menu { | ||
1675 | 316 | * text: "&File" | ||
1676 | 317 | * | ||
1677 | 318 | * MenuGroup { | ||
1678 | 319 | * Action { | ||
1679 | 320 | * text: "&New" | ||
1680 | 321 | * shortcut: "Ctrl+N" | ||
1681 | 322 | * } | ||
1682 | 323 | * | ||
1683 | 324 | * Action { | ||
1684 | 325 | * text: "&Open" | ||
1685 | 326 | * shortcut: "Ctrl+O" | ||
1686 | 327 | * } | ||
1687 | 328 | * } | ||
1688 | 329 | * | ||
1689 | 330 | * Menu { | ||
1690 | 331 | * text: "Recent Files" | ||
1691 | 332 | * | ||
1692 | 333 | * ActionList { | ||
1693 | 334 | * Action { text: "1.txt" } | ||
1694 | 335 | * Action { text: "2.txt" } | ||
1695 | 336 | * Action { text: "3.txt" } | ||
1696 | 337 | * } | ||
1697 | 338 | * } | ||
1698 | 339 | * | ||
1699 | 340 | * Action { | ||
1700 | 341 | * action: Action { | ||
1701 | 342 | * text: "E&xit" | ||
1702 | 343 | * shortcut: "Ctrl+X" | ||
1703 | 344 | * } | ||
1704 | 345 | * } | ||
1705 | 346 | * } | ||
1706 | 347 | * \endqml | ||
1707 | 348 | */ | ||
1708 | 349 | Menu::Menu(QObject *parent) | ||
1709 | 350 | : UCAction(parent) | ||
1710 | 351 | , d_ptr(new MenuPrivate(this)) | ||
1711 | 352 | { | ||
1712 | 353 | Q_D(Menu); | ||
1713 | 354 | |||
1714 | 355 | connect(this, SIGNAL(enabledChanged()), this, SLOT(_q_updateEnabled())); | ||
1715 | 356 | connect(this, SIGNAL(textChanged()), this, SLOT(_q_updateText())); | ||
1716 | 357 | connect(this, SIGNAL(iconNameChanged()), this, SLOT(_q_updateIcon())); | ||
1717 | 358 | connect(this, SIGNAL(iconSourceChanged()), this, SLOT(_q_updateIcon())); | ||
1718 | 359 | connect(this, SIGNAL(visibleChanged()), this, SLOT(_q_updateVisible())); | ||
1719 | 360 | } | ||
1720 | 361 | |||
1721 | 362 | Menu::~Menu() | ||
1722 | 363 | { | ||
1723 | 364 | } | ||
1724 | 365 | |||
1725 | 366 | /*! | ||
1726 | 367 | * \qmlproperty list<Object> Menu::data | ||
1727 | 368 | * \default | ||
1728 | 369 | * List of objects representing menu items within the menu. | ||
1729 | 370 | * | ||
1730 | 371 | * Currently supports Menu, Action, AcionList & MenuGroup objects. | ||
1731 | 372 | * \note Item object which do not support platformItem will not be exported for native menus. | ||
1732 | 373 | */ | ||
1733 | 374 | QQmlListProperty<QObject> Menu::data() | ||
1734 | 375 | { | ||
1735 | 376 | Q_D(Menu); | ||
1736 | 377 | return QQmlListProperty<QObject>(this, d, | ||
1737 | 378 | &MenuPrivate::data_append, | ||
1738 | 379 | &MenuPrivate::data_count, | ||
1739 | 380 | &MenuPrivate::data_at, | ||
1740 | 381 | &MenuPrivate::data_clear); | ||
1741 | 382 | } | ||
1742 | 383 | |||
1743 | 384 | /*! | ||
1744 | 385 | * \qmlmethod Menu::appendObject(object o) | ||
1745 | 386 | * Add a object tto the menu | ||
1746 | 387 | */ | ||
1747 | 388 | void Menu::appendObject(QObject *o) | ||
1748 | 389 | { | ||
1749 | 390 | Q_D(Menu); | ||
1750 | 391 | |||
1751 | 392 | insertObject(d->m_data.count(), o); | ||
1752 | 393 | } | ||
1753 | 394 | |||
1754 | 395 | /*! | ||
1755 | 396 | * \qmlmethod Menu::insertObject(int index, object o) | ||
1756 | 397 | * Inserts an item at the index in the menu. | ||
1757 | 398 | * | ||
1758 | 399 | * Currently supports Menu, Action, AcionList & MenuGroup objects. | ||
1759 | 400 | * \note Item object which do not support platformItem will not be exported for native menus. | ||
1760 | 401 | */ | ||
1761 | 402 | void Menu::insertObject(int index, QObject *o) | ||
1762 | 403 | { | ||
1763 | 404 | Q_D(Menu); | ||
1764 | 405 | d->insertObject(index, o); | ||
1765 | 406 | } | ||
1766 | 407 | |||
1767 | 408 | /*! | ||
1768 | 409 | * \qmlmethod Menu::removeObject(object o) | ||
1769 | 410 | * Removes the item from the menu. | ||
1770 | 411 | */ | ||
1771 | 412 | void Menu::removeObject(QObject *o) | ||
1772 | 413 | { | ||
1773 | 414 | Q_D(Menu); | ||
1774 | 415 | qCDebug(ucMenu) << "Menu::removeObject" << o; | ||
1775 | 416 | |||
1776 | 417 | d->removeObject(o); | ||
1777 | 418 | } | ||
1778 | 419 | |||
1779 | 420 | QPlatformMenu* Menu::platformMenu() const | ||
1780 | 421 | { | ||
1781 | 422 | Q_D(const Menu); | ||
1782 | 423 | return d->m_platformMenu; | ||
1783 | 424 | } | ||
1784 | 425 | |||
1785 | 426 | /*! | ||
1786 | 427 | * \qmlmethod Menu::show(point point) | ||
1787 | 428 | * Show the menu popup at the given point | ||
1788 | 429 | */ | ||
1789 | 430 | void Menu::show(const QPoint &point) | ||
1790 | 431 | { | ||
1791 | 432 | Q_D(Menu); | ||
1792 | 433 | qCDebug(ucMenu, "Menu::popup(%s, point(%d,%d))", qPrintable(text()), point.x(), point.y()); | ||
1793 | 434 | |||
1794 | 435 | if (d->m_platformMenu) { | ||
1795 | 436 | d->m_platformMenu->showPopup(findWindowForObject(this), QRect(point, QSize()), Q_NULLPTR); | ||
1796 | 437 | } | ||
1797 | 438 | } | ||
1798 | 439 | |||
1799 | 440 | /*! | ||
1800 | 441 | * \qmlmethod Menu::dismiss() | ||
1801 | 442 | * Dismiss and destroy the menu popup. | ||
1802 | 443 | */ | ||
1803 | 444 | void Menu::dismiss() | ||
1804 | 445 | { | ||
1805 | 446 | Q_D(Menu); | ||
1806 | 447 | qCDebug(ucMenu, "Menu::dismiss(%s)", qPrintable(text())); | ||
1807 | 448 | |||
1808 | 449 | if (d->m_platformMenu) { | ||
1809 | 450 | d->m_platformMenu->dismiss(); | ||
1810 | 451 | } | ||
1811 | 452 | } | ||
1812 | 453 | |||
1813 | 454 | |||
1814 | 455 | PlatformItemWrapper::PlatformItemWrapper(QObject *target, Menu* menu) | ||
1815 | 456 | : QObject(menu) | ||
1816 | 457 | , m_target(target) | ||
1817 | 458 | , m_menu(menu) | ||
1818 | 459 | , m_platformItem(menu->platformMenu() ? menu->platformMenu()->createMenuItem() : Q_NULLPTR) | ||
1819 | 460 | , m_platformItemSeparator(Q_NULLPTR) | ||
1820 | 461 | , m_inserted(false) | ||
1821 | 462 | { | ||
1822 | 463 | if (Menu* menu = qobject_cast<Menu*>(m_target)) { | ||
1823 | 464 | if (m_platformItem) { | ||
1824 | 465 | m_platformItem->setMenu(menu->platformMenu()); | ||
1825 | 466 | } | ||
1826 | 467 | |||
1827 | 468 | connect(menu, &Menu::visibleChanged, this, &PlatformItemWrapper::updateVisible); | ||
1828 | 469 | connect(menu, &Menu::textChanged, this, &PlatformItemWrapper::updateText); | ||
1829 | 470 | connect(menu, &Menu::enabledChanged, this, &PlatformItemWrapper::updateEnabled); | ||
1830 | 471 | connect(menu, &Menu::iconSourceChanged, this, &PlatformItemWrapper::updateIcon); | ||
1831 | 472 | connect(menu, &Menu::iconNameChanged, this, &PlatformItemWrapper::updateIcon); | ||
1832 | 473 | |||
1833 | 474 | } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) { | ||
1834 | 475 | |||
1835 | 476 | connect(action, &UCAction::visibleChanged, this, &PlatformItemWrapper::updateVisible); | ||
1836 | 477 | connect(action, &UCAction::textChanged, this, &PlatformItemWrapper::updateText); | ||
1837 | 478 | connect(action, &UCAction::enabledChanged, this, &PlatformItemWrapper::updateEnabled); | ||
1838 | 479 | connect(action, &UCAction::iconSourceChanged, this, &PlatformItemWrapper::updateIcon); | ||
1839 | 480 | connect(action, &UCAction::iconNameChanged, this, &PlatformItemWrapper::updateIcon); | ||
1840 | 481 | connect(action, &UCAction::shortcutChanged, this, &PlatformItemWrapper::updateShortcut); | ||
1841 | 482 | connect(action, &UCAction::checkableChanged, this, &PlatformItemWrapper::updateCheck); | ||
1842 | 483 | connect(action, &UCAction::toggled, this, &PlatformItemWrapper::updateCheck); | ||
1843 | 484 | |||
1844 | 485 | if (m_platformItem) { | ||
1845 | 486 | // Connect to activate (with inversion for checkables) | ||
1846 | 487 | connect(m_platformItem, &QPlatformMenuItem::activated, action, [action]() { | ||
1847 | 488 | action->trigger(); | ||
1848 | 489 | }); | ||
1849 | 490 | } | ||
1850 | 491 | |||
1851 | 492 | } | ||
1852 | 493 | syncPlatformItem(); | ||
1853 | 494 | } | ||
1854 | 495 | |||
1855 | 496 | PlatformItemWrapper::~PlatformItemWrapper() | ||
1856 | 497 | { | ||
1857 | 498 | if (m_inserted && m_menu && m_menu->platformMenu()) { | ||
1858 | 499 | m_menu->platformMenu()->removeMenuItem(m_platformItem); | ||
1859 | 500 | if (m_platformItemSeparator) { | ||
1860 | 501 | m_menu->platformMenu()->removeMenuItem(m_platformItemSeparator); | ||
1861 | 502 | delete m_platformItemSeparator; | ||
1862 | 503 | } | ||
1863 | 504 | } | ||
1864 | 505 | delete m_platformItem; | ||
1865 | 506 | } | ||
1866 | 507 | |||
1867 | 508 | void PlatformItemWrapper::insert(int index, bool withSeparator) | ||
1868 | 509 | { | ||
1869 | 510 | if (m_inserted) return; | ||
1870 | 511 | qCDebug(ucMenu).nospace() << " PlatformItemWrapper::insert(menu=" << m_menu | ||
1871 | 512 | << ", index=" << index | ||
1872 | 513 | << ", object=" << m_target << ")"; | ||
1873 | 514 | |||
1874 | 515 | auto platformMenu = m_menu->platformMenu(); | ||
1875 | 516 | if (!platformMenu) return; | ||
1876 | 517 | if (!m_platformItem) return; | ||
1877 | 518 | |||
1878 | 519 | QPlatformMenuItem* before = platformMenu->menuItemAt(index); | ||
1879 | 520 | platformMenu->insertMenuItem(m_platformItem, before); | ||
1880 | 521 | m_inserted = true; | ||
1881 | 522 | |||
1882 | 523 | if (withSeparator) setSeparator(); | ||
1883 | 524 | } | ||
1884 | 525 | |||
1885 | 526 | void PlatformItemWrapper::remove() | ||
1886 | 527 | { | ||
1887 | 528 | if (!m_inserted) return; | ||
1888 | 529 | qCDebug(ucMenu).nospace() << " PlatformItemWrapper::remove(menu=" << m_menu | ||
1889 | 530 | << ", object=" << m_target << ")"; | ||
1890 | 531 | |||
1891 | 532 | auto platformMenu = m_menu->platformMenu(); | ||
1892 | 533 | if (!platformMenu) return; | ||
1893 | 534 | if (!m_platformItem) return; | ||
1894 | 535 | |||
1895 | 536 | platformMenu->removeMenuItem(m_platformItem); | ||
1896 | 537 | m_inserted = false; | ||
1897 | 538 | |||
1898 | 539 | if (m_platformItemSeparator) { | ||
1899 | 540 | qCDebug(ucMenu).nospace() << " PlatformItemWrapper::removeSeparator(menu=" << m_menu | ||
1900 | 541 | << ", object=" << m_target << ")"; | ||
1901 | 542 | platformMenu->removeMenuItem(m_platformItemSeparator); | ||
1902 | 543 | delete m_platformItemSeparator; | ||
1903 | 544 | m_platformItemSeparator = Q_NULLPTR; | ||
1904 | 545 | } | ||
1905 | 546 | } | ||
1906 | 547 | |||
1907 | 548 | void PlatformItemWrapper::setSeparator() | ||
1908 | 549 | { | ||
1909 | 550 | // already created | ||
1910 | 551 | if (m_platformItemSeparator) return; | ||
1911 | 552 | // not inserted yet. | ||
1912 | 553 | if (!m_inserted) return; | ||
1913 | 554 | |||
1914 | 555 | auto platformMenu = m_menu->platformMenu(); | ||
1915 | 556 | if (!platformMenu) return; | ||
1916 | 557 | |||
1917 | 558 | // insert separator before? | ||
1918 | 559 | m_platformItemSeparator = platformMenu->createMenuItem(); | ||
1919 | 560 | if (m_platformItemSeparator) { | ||
1920 | 561 | qCDebug(ucMenu).nospace() << " PlatformItemWrapper::setSeparator(menu=" << m_menu | ||
1921 | 562 | << ", object=" << m_target << ")"; | ||
1922 | 563 | |||
1923 | 564 | m_platformItemSeparator->setIsSeparator(true); | ||
1924 | 565 | platformMenu->insertMenuItem(m_platformItemSeparator, m_platformItem); | ||
1925 | 566 | } | ||
1926 | 567 | } | ||
1927 | 568 | |||
1928 | 569 | void PlatformItemWrapper::updateVisible() | ||
1929 | 570 | { | ||
1930 | 571 | if (Menu* menu = qobject_cast<Menu*>(m_target)) { | ||
1931 | 572 | if (m_platformItem) m_platformItem->setVisible(menu->visible()); | ||
1932 | 573 | if (menu->platformMenu()) menu->platformMenu()->setVisible(menu->visible()); | ||
1933 | 574 | } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) { | ||
1934 | 575 | if (m_platformItem) m_platformItem->setVisible(action->visible()); | ||
1935 | 576 | } | ||
1936 | 577 | } | ||
1937 | 578 | |||
1938 | 579 | void PlatformItemWrapper::updateEnabled() | ||
1939 | 580 | { | ||
1940 | 581 | if (Menu* menu = qobject_cast<Menu*>(m_target)) { | ||
1941 | 582 | if (m_platformItem) m_platformItem->setEnabled(menu->isEnabled()); | ||
1942 | 583 | if (menu->platformMenu()) menu->platformMenu()->setEnabled(menu->isEnabled()); | ||
1943 | 584 | } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) { | ||
1944 | 585 | if (m_platformItem) m_platformItem->setEnabled(action->isEnabled()); | ||
1945 | 586 | } | ||
1946 | 587 | } | ||
1947 | 588 | |||
1948 | 589 | void PlatformItemWrapper::updateText() | ||
1949 | 590 | { | ||
1950 | 591 | if (Menu* menu = qobject_cast<Menu*>(m_target)) { | ||
1951 | 592 | if (m_platformItem) m_platformItem->setText(menu->text()); | ||
1952 | 593 | if (menu->platformMenu()) menu->platformMenu()->setText(menu->text()); | ||
1953 | 594 | } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) { | ||
1954 | 595 | if (m_platformItem) m_platformItem->setText(action->text()); | ||
1955 | 596 | } | ||
1956 | 597 | } | ||
1957 | 598 | |||
1958 | 599 | void PlatformItemWrapper::updateIcon() | ||
1959 | 600 | { | ||
1960 | 601 | QIcon icon; | ||
1961 | 602 | if (Menu* menu = qobject_cast<Menu*>(m_target)) { | ||
1962 | 603 | |||
1963 | 604 | if (!menu->iconSource().isEmpty()) { | ||
1964 | 605 | icon = QIcon(menu->iconSource().path()); | ||
1965 | 606 | } else if (!menu->iconName().isEmpty()) { | ||
1966 | 607 | icon = QIcon::fromTheme(menu->iconName()); | ||
1967 | 608 | } | ||
1968 | 609 | if (menu->platformMenu()) menu->platformMenu()->setIcon(icon); | ||
1969 | 610 | |||
1970 | 611 | } else if (UCAction* action = qobject_cast<UCAction*>(m_target)) { | ||
1971 | 612 | |||
1972 | 613 | if (!action->iconSource().isEmpty()) { | ||
1973 | 614 | icon = QIcon(action->iconSource().path()); | ||
1974 | 615 | } else if (!action->iconName().isEmpty()) { | ||
1975 | 616 | icon = QIcon::fromTheme(action->iconName()); | ||
1976 | 617 | } | ||
1977 | 618 | } | ||
1978 | 619 | |||
1979 | 620 | if (m_platformItem) { m_platformItem->setIcon(icon); } | ||
1980 | 621 | } | ||
1981 | 622 | |||
1982 | 623 | |||
1983 | 624 | inline QKeySequence sequenceFromVariant(const QVariant& variant) | ||
1984 | 625 | { | ||
1985 | 626 | if (variant.type() == QVariant::Int) { | ||
1986 | 627 | return static_cast<QKeySequence::StandardKey>(variant.toInt()); | ||
1987 | 628 | } | ||
1988 | 629 | if (variant.type() == QVariant::String) { | ||
1989 | 630 | return QKeySequence::fromString(variant.toString()); | ||
1990 | 631 | } | ||
1991 | 632 | return QKeySequence(); | ||
1992 | 633 | } | ||
1993 | 634 | |||
1994 | 635 | void PlatformItemWrapper::updateShortcut() | ||
1995 | 636 | { | ||
1996 | 637 | if (!m_platformItem) return; | ||
1997 | 638 | |||
1998 | 639 | if (UCAction* action = qobject_cast<UCAction*>(m_target)) { | ||
1999 | 640 | m_platformItem->setShortcut(sequenceFromVariant(action->shortcut())); | ||
2000 | 641 | } | ||
2001 | 642 | } | ||
2002 | 643 | |||
2003 | 644 | void PlatformItemWrapper::updateCheck() | ||
2004 | 645 | { | ||
2005 | 646 | if (!m_platformItem) return; | ||
2006 | 647 | |||
2007 | 648 | if (UCAction* action = qobject_cast<UCAction*>(m_target)) { | ||
2008 | 649 | bool checkable = action->isCheckable(); | ||
2009 | 650 | m_platformItem->setCheckable(checkable); | ||
2010 | 651 | m_platformItem->setChecked(checkable && action->isChecked()); | ||
2011 | 652 | } | ||
2012 | 653 | } | ||
2013 | 654 | |||
2014 | 655 | void PlatformItemWrapper::syncPlatformItem() | ||
2015 | 656 | { | ||
2016 | 657 | updateVisible(); | ||
2017 | 658 | updateEnabled(); | ||
2018 | 659 | updateText(); | ||
2019 | 660 | updateIcon(); | ||
2020 | 661 | updateShortcut(); | ||
2021 | 662 | updateCheck(); | ||
2022 | 663 | |||
2023 | 664 | if (m_menu->platformMenu() && m_platformItem) { | ||
2024 | 665 | m_menu->platformMenu()->syncMenuItem(m_platformItem); | ||
2025 | 666 | } | ||
2026 | 667 | } | ||
2027 | 668 | |||
2028 | 669 | UT_NAMESPACE_END | ||
2029 | 670 | |||
2030 | 671 | #include "moc_menu_p.cpp" | ||
2031 | 0 | 672 | ||
2032 | === added file 'src/Ubuntu/UbuntuToolkit/menu_p.h' | |||
2033 | --- src/Ubuntu/UbuntuToolkit/menu_p.h 1970-01-01 00:00:00 +0000 | |||
2034 | +++ src/Ubuntu/UbuntuToolkit/menu_p.h 2016-08-31 08:57:26 +0000 | |||
2035 | @@ -0,0 +1,75 @@ | |||
2036 | 1 | /* | ||
2037 | 2 | * Copyright 2016 Canonical Ltd. | ||
2038 | 3 | * | ||
2039 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2040 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
2041 | 6 | * the Free Software Foundation; version 3. | ||
2042 | 7 | * | ||
2043 | 8 | * This program is distributed in the hope that it will be useful, | ||
2044 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2045 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2046 | 11 | * GNU Lesser General Public License for more details. | ||
2047 | 12 | * | ||
2048 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
2049 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2050 | 15 | * | ||
2051 | 16 | */ | ||
2052 | 17 | |||
2053 | 18 | #ifndef MENU_P_H | ||
2054 | 19 | #define MENU_P_H | ||
2055 | 20 | |||
2056 | 21 | #include <QQmlListProperty> | ||
2057 | 22 | #include <QLoggingCategory> | ||
2058 | 23 | #include <QPointer> | ||
2059 | 24 | #include <ubuntutoolkitglobal.h> | ||
2060 | 25 | |||
2061 | 26 | #include "ucaction_p.h" | ||
2062 | 27 | |||
2063 | 28 | Q_DECLARE_LOGGING_CATEGORY(ucMenu); | ||
2064 | 29 | |||
2065 | 30 | class QPlatformMenu; | ||
2066 | 31 | class QPlatformMenuItem; | ||
2067 | 32 | class QQuickItem; | ||
2068 | 33 | |||
2069 | 34 | UT_NAMESPACE_BEGIN | ||
2070 | 35 | |||
2071 | 36 | class MenuPrivate; | ||
2072 | 37 | class MenuBar; | ||
2073 | 38 | class UCAction; | ||
2074 | 39 | class UBUNTUTOOLKIT_EXPORT Menu : public UCAction | ||
2075 | 40 | { | ||
2076 | 41 | Q_OBJECT | ||
2077 | 42 | |||
2078 | 43 | Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL) | ||
2079 | 44 | Q_CLASSINFO("DefaultProperty", "data") | ||
2080 | 45 | |||
2081 | 46 | public: | ||
2082 | 47 | explicit Menu(QObject *parent = 0); | ||
2083 | 48 | ~Menu(); | ||
2084 | 49 | |||
2085 | 50 | QQmlListProperty<QObject> data(); | ||
2086 | 51 | |||
2087 | 52 | Q_INVOKABLE void appendObject(QObject* obj); | ||
2088 | 53 | Q_INVOKABLE void insertObject(int index, QObject* obj); | ||
2089 | 54 | Q_INVOKABLE void removeObject(QObject* obj); | ||
2090 | 55 | |||
2091 | 56 | QPlatformMenu *platformMenu() const; | ||
2092 | 57 | |||
2093 | 58 | public Q_SLOTS: | ||
2094 | 59 | void show(const QPoint& pt); | ||
2095 | 60 | void dismiss(); | ||
2096 | 61 | |||
2097 | 62 | private: | ||
2098 | 63 | Q_DISABLE_COPY(Menu) | ||
2099 | 64 | Q_DECLARE_PRIVATE(Menu) | ||
2100 | 65 | QScopedPointer<MenuPrivate> d_ptr; | ||
2101 | 66 | |||
2102 | 67 | Q_PRIVATE_SLOT(d_func(), void _q_updateEnabled()) | ||
2103 | 68 | Q_PRIVATE_SLOT(d_func(), void _q_updateText()) | ||
2104 | 69 | Q_PRIVATE_SLOT(d_func(), void _q_updateIcon()) | ||
2105 | 70 | Q_PRIVATE_SLOT(d_func(), void _q_updateVisible()) | ||
2106 | 71 | }; | ||
2107 | 72 | |||
2108 | 73 | UT_NAMESPACE_END | ||
2109 | 74 | |||
2110 | 75 | #endif // MENU_P_H | ||
2111 | 0 | 76 | ||
2112 | === added file 'src/Ubuntu/UbuntuToolkit/menu_p_p.h' | |||
2113 | --- src/Ubuntu/UbuntuToolkit/menu_p_p.h 1970-01-01 00:00:00 +0000 | |||
2114 | +++ src/Ubuntu/UbuntuToolkit/menu_p_p.h 2016-08-31 08:57:26 +0000 | |||
2115 | @@ -0,0 +1,95 @@ | |||
2116 | 1 | /* | ||
2117 | 2 | * Copyright 2016 Canonical Ltd. | ||
2118 | 3 | * | ||
2119 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2120 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
2121 | 6 | * the Free Software Foundation; version 3. | ||
2122 | 7 | * | ||
2123 | 8 | * This program is distributed in the hope that it will be useful, | ||
2124 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2125 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2126 | 11 | * GNU Lesser General Public License for more details. | ||
2127 | 12 | * | ||
2128 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
2129 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2130 | 15 | * | ||
2131 | 16 | */ | ||
2132 | 17 | |||
2133 | 18 | #ifndef MENU_P_P_H | ||
2134 | 19 | #define MENU_P_P_H | ||
2135 | 20 | |||
2136 | 21 | #include "menu_p.h" | ||
2137 | 22 | #include <ubuntutoolkitglobal.h> | ||
2138 | 23 | |||
2139 | 24 | class QObject; | ||
2140 | 25 | class QQmlComponent; | ||
2141 | 26 | |||
2142 | 27 | UT_NAMESPACE_BEGIN | ||
2143 | 28 | |||
2144 | 29 | class UCAction; | ||
2145 | 30 | class Menu; | ||
2146 | 31 | class PlatformItemWrapper; | ||
2147 | 32 | |||
2148 | 33 | class MenuPrivate | ||
2149 | 34 | { | ||
2150 | 35 | Q_DECLARE_PUBLIC(Menu) | ||
2151 | 36 | public: | ||
2152 | 37 | MenuPrivate(Menu *qq); | ||
2153 | 38 | virtual ~MenuPrivate(); | ||
2154 | 39 | |||
2155 | 40 | void insertObject(int index, QObject *obj); | ||
2156 | 41 | void removeObject(QObject *obj); | ||
2157 | 42 | |||
2158 | 43 | void _q_updateEnabled(); | ||
2159 | 44 | void _q_updateText(); | ||
2160 | 45 | void _q_updateIcon(); | ||
2161 | 46 | void _q_updateVisible(); | ||
2162 | 47 | |||
2163 | 48 | static void data_append(QQmlListProperty<QObject> *prop, QObject *o); | ||
2164 | 49 | static int data_count(QQmlListProperty<QObject> *prop); | ||
2165 | 50 | static QObject *data_at(QQmlListProperty<QObject> *prop, int index); | ||
2166 | 51 | static void data_clear(QQmlListProperty<QObject> *prop); | ||
2167 | 52 | |||
2168 | 53 | Menu* q_ptr; | ||
2169 | 54 | QPlatformMenu* m_platformMenu; | ||
2170 | 55 | UCAction* m_action; | ||
2171 | 56 | |||
2172 | 57 | QHash<QObject*, PlatformItemWrapper*> m_platformItems; | ||
2173 | 58 | QMultiHash<QObject*, QObject*> m_dataPlatformObjectMap; | ||
2174 | 59 | QVector<QObject*> m_data; | ||
2175 | 60 | }; | ||
2176 | 61 | |||
2177 | 62 | class PlatformItemWrapper : public QObject | ||
2178 | 63 | { | ||
2179 | 64 | Q_OBJECT | ||
2180 | 65 | public: | ||
2181 | 66 | PlatformItemWrapper(QObject *target, Menu* menu); | ||
2182 | 67 | ~PlatformItemWrapper(); | ||
2183 | 68 | |||
2184 | 69 | void insert(int index, bool withSeparator); | ||
2185 | 70 | void remove(); | ||
2186 | 71 | void setSeparator(); | ||
2187 | 72 | |||
2188 | 73 | bool hasSeparator() const { return m_platformItemSeparator != Q_NULLPTR; } | ||
2189 | 74 | |||
2190 | 75 | public Q_SLOTS: | ||
2191 | 76 | void updateVisible(); | ||
2192 | 77 | void updateEnabled(); | ||
2193 | 78 | void updateText(); | ||
2194 | 79 | void updateIcon(); | ||
2195 | 80 | void updateShortcut(); | ||
2196 | 81 | void updateCheck(); | ||
2197 | 82 | |||
2198 | 83 | private: | ||
2199 | 84 | void syncPlatformItem(); | ||
2200 | 85 | |||
2201 | 86 | QObject* m_target; | ||
2202 | 87 | QPointer<Menu> m_menu; | ||
2203 | 88 | QPlatformMenuItem* m_platformItem; | ||
2204 | 89 | QPlatformMenuItem* m_platformItemSeparator; | ||
2205 | 90 | bool m_inserted; | ||
2206 | 91 | }; | ||
2207 | 92 | |||
2208 | 93 | UT_NAMESPACE_END | ||
2209 | 94 | |||
2210 | 95 | #endif // MENU_P_P_H | ||
2211 | 0 | 96 | ||
2212 | === added file 'src/Ubuntu/UbuntuToolkit/menubar.cpp' | |||
2213 | --- src/Ubuntu/UbuntuToolkit/menubar.cpp 1970-01-01 00:00:00 +0000 | |||
2214 | +++ src/Ubuntu/UbuntuToolkit/menubar.cpp 2016-08-31 08:57:26 +0000 | |||
2215 | @@ -0,0 +1,340 @@ | |||
2216 | 1 | /* | ||
2217 | 2 | * Copyright 2016 Canonical Ltd. | ||
2218 | 3 | * | ||
2219 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2220 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
2221 | 6 | * the Free Software Foundation; version 3. | ||
2222 | 7 | * | ||
2223 | 8 | * This program is distributed in the hope that it will be useful, | ||
2224 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2225 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2226 | 11 | * GNU Lesser General Public License for more details. | ||
2227 | 12 | * | ||
2228 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
2229 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2230 | 15 | * | ||
2231 | 16 | */ | ||
2232 | 17 | |||
2233 | 18 | #include "menubar_p.h" | ||
2234 | 19 | #include "menubar_p_p.h" | ||
2235 | 20 | |||
2236 | 21 | // Qt | ||
2237 | 22 | #include <QQuickItem> | ||
2238 | 23 | #include <QQuickWindow> | ||
2239 | 24 | #include <QLoggingCategory> | ||
2240 | 25 | #include <private/qguiapplication_p.h> | ||
2241 | 26 | #include <QtGui/qpa/qplatformtheme.h> | ||
2242 | 27 | #include <QtGui/qpa/qplatformmenu.h> | ||
2243 | 28 | |||
2244 | 29 | UT_NAMESPACE_BEGIN | ||
2245 | 30 | |||
2246 | 31 | MenuBarPrivate::MenuBarPrivate(MenuBar *qq) | ||
2247 | 32 | : q_ptr(qq) | ||
2248 | 33 | { | ||
2249 | 34 | m_platformBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar(); | ||
2250 | 35 | } | ||
2251 | 36 | |||
2252 | 37 | MenuBarPrivate::~MenuBarPrivate() | ||
2253 | 38 | { | ||
2254 | 39 | qDeleteAll(m_platformMenus); | ||
2255 | 40 | m_platformMenus.clear(); | ||
2256 | 41 | |||
2257 | 42 | delete m_platformBar; | ||
2258 | 43 | m_platformBar = Q_NULLPTR; | ||
2259 | 44 | } | ||
2260 | 45 | |||
2261 | 46 | void MenuBarPrivate::insertMenu(int index, Menu* menu) | ||
2262 | 47 | { | ||
2263 | 48 | Q_Q(MenuBar); | ||
2264 | 49 | Menu* prevMenu = m_menus.count() > index ? m_menus[index] : Q_NULLPTR; | ||
2265 | 50 | |||
2266 | 51 | m_menus.insert(index, menu); | ||
2267 | 52 | |||
2268 | 53 | // add to platform | ||
2269 | 54 | if (m_platformBar && menu->platformMenu()) { | ||
2270 | 55 | auto platformWrapper = new PlatformMenuWrapper(menu, q); | ||
2271 | 56 | platformWrapper->insert(prevMenu ? prevMenu->platformMenu() : Q_NULLPTR); | ||
2272 | 57 | m_platformMenus[menu] = platformWrapper; | ||
2273 | 58 | |||
2274 | 59 | QObject::connect(menu, &QObject::destroyed, q, [this](QObject* object) { | ||
2275 | 60 | if (m_platformMenus.contains(object)) { | ||
2276 | 61 | PlatformMenuWrapper* wrapper = m_platformMenus.take(object); | ||
2277 | 62 | wrapper->remove(); | ||
2278 | 63 | delete wrapper; | ||
2279 | 64 | } | ||
2280 | 65 | }); | ||
2281 | 66 | } | ||
2282 | 67 | } | ||
2283 | 68 | |||
2284 | 69 | void MenuBarPrivate::removeMenu(Menu *menu) | ||
2285 | 70 | { | ||
2286 | 71 | m_menus.removeOne(menu); | ||
2287 | 72 | |||
2288 | 73 | if (m_platformBar) { | ||
2289 | 74 | if (m_platformMenus.contains(menu)) { | ||
2290 | 75 | PlatformMenuWrapper* wrapper = m_platformMenus.take(menu); | ||
2291 | 76 | wrapper->remove(); | ||
2292 | 77 | delete wrapper; | ||
2293 | 78 | } | ||
2294 | 79 | } | ||
2295 | 80 | } | ||
2296 | 81 | |||
2297 | 82 | void MenuBarPrivate::menu_append(QQmlListProperty<Menu> *prop, Menu *o) | ||
2298 | 83 | { | ||
2299 | 84 | MenuBarPrivate *q = static_cast<MenuBarPrivate *>(prop->data); | ||
2300 | 85 | // menubar is the menus parent | ||
2301 | 86 | o->setParent(prop->object); | ||
2302 | 87 | q->insertMenu(q->m_menus.count(), o); | ||
2303 | 88 | } | ||
2304 | 89 | |||
2305 | 90 | int MenuBarPrivate::menu_count(QQmlListProperty<Menu> *prop) | ||
2306 | 91 | { | ||
2307 | 92 | MenuBarPrivate *p = static_cast<MenuBarPrivate *>(prop->data); | ||
2308 | 93 | return p->m_menus.count(); | ||
2309 | 94 | } | ||
2310 | 95 | |||
2311 | 96 | Menu *MenuBarPrivate::menu_at(QQmlListProperty<Menu> *prop, int index) | ||
2312 | 97 | { | ||
2313 | 98 | MenuBarPrivate *p = static_cast<MenuBarPrivate *>(prop->data); | ||
2314 | 99 | return p->m_menus.value(index); | ||
2315 | 100 | } | ||
2316 | 101 | |||
2317 | 102 | void MenuBarPrivate::menu_clear(QQmlListProperty<Menu> *prop) | ||
2318 | 103 | { | ||
2319 | 104 | MenuBarPrivate *p = static_cast<MenuBarPrivate *>(prop->data); | ||
2320 | 105 | p->m_menus.clear(); | ||
2321 | 106 | } | ||
2322 | 107 | |||
2323 | 108 | /*! | ||
2324 | 109 | * \qmltype MenuBar | ||
2325 | 110 | * \inqmlmodule Ubuntu.Components 1.3 | ||
2326 | 111 | * \ingroup ubuntu | ||
2327 | 112 | * \brief MenuBar defines an application menu bar structure | ||
2328 | 113 | * | ||
2329 | 114 | * Example usage: | ||
2330 | 115 | * \qml | ||
2331 | 116 | * import QtQuick 2.4 | ||
2332 | 117 | * import Ubuntu.Components 1.3 | ||
2333 | 118 | * MainView { | ||
2334 | 119 | * MenuBar { | ||
2335 | 120 | * Menu { | ||
2336 | 121 | * text: "_File" | ||
2337 | 122 | * | ||
2338 | 123 | * MenuItem { | ||
2339 | 124 | * text: "_New" | ||
2340 | 125 | * shortcut: "Ctrl+N" | ||
2341 | 126 | * } | ||
2342 | 127 | * | ||
2343 | 128 | * MenuItem { | ||
2344 | 129 | * text: "_Open" | ||
2345 | 130 | * shortcut: "Ctrl+O" | ||
2346 | 131 | * } | ||
2347 | 132 | * | ||
2348 | 133 | * MenuSeparator {} | ||
2349 | 134 | * | ||
2350 | 135 | * MenuItem { | ||
2351 | 136 | * action: exitAction | ||
2352 | 137 | * } | ||
2353 | 138 | * } | ||
2354 | 139 | * | ||
2355 | 140 | * Menu { | ||
2356 | 141 | * text: "_Edit" | ||
2357 | 142 | * | ||
2358 | 143 | * MenuItem { | ||
2359 | 144 | * text: "_Undo" | ||
2360 | 145 | * iconSource: "image://theme/undo" | ||
2361 | 146 | * } | ||
2362 | 147 | * } | ||
2363 | 148 | * Menu { | ||
2364 | 149 | * text: "_Window" | ||
2365 | 150 | * | ||
2366 | 151 | * MenuItem { | ||
2367 | 152 | * text: "Fullscreen" | ||
2368 | 153 | * checkable: true | ||
2369 | 154 | * checked: false | ||
2370 | 155 | * } | ||
2371 | 156 | * } | ||
2372 | 157 | * } | ||
2373 | 158 | * Action { | ||
2374 | 159 | * id: boundAction | ||
2375 | 160 | * text: "E_xit" | ||
2376 | 161 | * onTriggered: { | ||
2377 | 162 | * Qt.quit(); | ||
2378 | 163 | * } | ||
2379 | 164 | * } | ||
2380 | 165 | * } | ||
2381 | 166 | * \endqml | ||
2382 | 167 | */ | ||
2383 | 168 | MenuBar::MenuBar(QObject *parent) | ||
2384 | 169 | : QObject(parent) | ||
2385 | 170 | , d_ptr(new MenuBarPrivate(this)) | ||
2386 | 171 | { | ||
2387 | 172 | } | ||
2388 | 173 | |||
2389 | 174 | MenuBar::~MenuBar() | ||
2390 | 175 | { | ||
2391 | 176 | } | ||
2392 | 177 | |||
2393 | 178 | /*! | ||
2394 | 179 | * \qmlmethod void MenuBar::appendMenu(Menu menu) | ||
2395 | 180 | * Append a Menu to the MenuBar | ||
2396 | 181 | */ | ||
2397 | 182 | void MenuBar::appendMenu(Menu *menu) | ||
2398 | 183 | { | ||
2399 | 184 | Q_D(MenuBar); | ||
2400 | 185 | insertMenu(d->m_menus.count(), menu); | ||
2401 | 186 | } | ||
2402 | 187 | |||
2403 | 188 | /*! | ||
2404 | 189 | * \qmlmethod void MenuBar::insertMenu(int index, Menu menu) | ||
2405 | 190 | * Insert a Menu to the MenuBar at the specified position | ||
2406 | 191 | */ | ||
2407 | 192 | void MenuBar::insertMenu(int index, Menu *menu) | ||
2408 | 193 | { | ||
2409 | 194 | Q_D(MenuBar); | ||
2410 | 195 | if (!menu) return; | ||
2411 | 196 | |||
2412 | 197 | d->insertMenu(index, menu); | ||
2413 | 198 | Q_EMIT menusChanged(); | ||
2414 | 199 | } | ||
2415 | 200 | |||
2416 | 201 | /*! | ||
2417 | 202 | * \qmlmethod void MenuBar::removeMenu(Menu menu) | ||
2418 | 203 | * Remove a Menu from the MenuBar | ||
2419 | 204 | */ | ||
2420 | 205 | void MenuBar::removeMenu(Menu *menu) | ||
2421 | 206 | { | ||
2422 | 207 | Q_D(MenuBar); | ||
2423 | 208 | if (!menu) return; | ||
2424 | 209 | |||
2425 | 210 | d->removeMenu(menu); | ||
2426 | 211 | Q_EMIT menusChanged(); | ||
2427 | 212 | } | ||
2428 | 213 | /*! | ||
2429 | 214 | * \qmlproperty list<Menu> MenuBar::menus | ||
2430 | 215 | * \default | ||
2431 | 216 | * List of Menus in this MenuBar. | ||
2432 | 217 | */ | ||
2433 | 218 | QQmlListProperty<Menu> MenuBar::menus() | ||
2434 | 219 | { | ||
2435 | 220 | Q_D(MenuBar); | ||
2436 | 221 | return QQmlListProperty<Menu>(this, d, | ||
2437 | 222 | &MenuBarPrivate::menu_append, | ||
2438 | 223 | &MenuBarPrivate::menu_count, | ||
2439 | 224 | &MenuBarPrivate::menu_at, | ||
2440 | 225 | &MenuBarPrivate::menu_clear); | ||
2441 | 226 | } | ||
2442 | 227 | |||
2443 | 228 | QPlatformMenuBar *MenuBar::platformMenuBar() const | ||
2444 | 229 | { | ||
2445 | 230 | Q_D(const MenuBar); | ||
2446 | 231 | return d->m_platformBar; | ||
2447 | 232 | } | ||
2448 | 233 | |||
2449 | 234 | void MenuBar::classBegin() | ||
2450 | 235 | { | ||
2451 | 236 | } | ||
2452 | 237 | |||
2453 | 238 | void MenuBar::componentComplete() | ||
2454 | 239 | { | ||
2455 | 240 | Q_D(MenuBar); | ||
2456 | 241 | |||
2457 | 242 | auto parentItem = qobject_cast<QQuickItem*>(parent()); | ||
2458 | 243 | if (parentItem && d->m_platformBar) { | ||
2459 | 244 | d->m_platformBar->handleReparent(parentItem->window()); | ||
2460 | 245 | } | ||
2461 | 246 | } | ||
2462 | 247 | |||
2463 | 248 | |||
2464 | 249 | PlatformMenuWrapper::PlatformMenuWrapper(Menu *target, MenuBar* bar) | ||
2465 | 250 | : QObject(bar) | ||
2466 | 251 | , m_bar(bar) | ||
2467 | 252 | , m_target(target) | ||
2468 | 253 | , m_inserted(false) | ||
2469 | 254 | { | ||
2470 | 255 | connect(m_target, &Menu::visibleChanged, this, &PlatformMenuWrapper::updateVisible); | ||
2471 | 256 | connect(m_target, &Menu::textChanged, this, &PlatformMenuWrapper::updateText); | ||
2472 | 257 | connect(m_target, &Menu::enabledChanged, this, &PlatformMenuWrapper::updateEnabled); | ||
2473 | 258 | connect(m_target, &Menu::iconSourceChanged, this, &PlatformMenuWrapper::updateIcon); | ||
2474 | 259 | connect(m_target, &Menu::iconNameChanged, this, &PlatformMenuWrapper::updateIcon); | ||
2475 | 260 | |||
2476 | 261 | syncPlatformMenu(); | ||
2477 | 262 | } | ||
2478 | 263 | |||
2479 | 264 | PlatformMenuWrapper::~PlatformMenuWrapper() | ||
2480 | 265 | { | ||
2481 | 266 | if (m_inserted && m_bar && m_bar->platformMenuBar()) { | ||
2482 | 267 | if (m_target && m_target->platformMenu()) { | ||
2483 | 268 | m_bar->platformMenuBar()->removeMenu(m_target->platformMenu()); | ||
2484 | 269 | } | ||
2485 | 270 | } | ||
2486 | 271 | } | ||
2487 | 272 | |||
2488 | 273 | void PlatformMenuWrapper::insert(QPlatformMenu *before) | ||
2489 | 274 | { | ||
2490 | 275 | if (m_inserted) return; | ||
2491 | 276 | qCDebug(ucMenu).nospace() << " PlatformMenuWrapper::insert(bar=" << m_bar | ||
2492 | 277 | << ", before=" << before | ||
2493 | 278 | << ", menu=" << m_target << ")"; | ||
2494 | 279 | |||
2495 | 280 | auto platformBar = m_bar->platformMenuBar(); | ||
2496 | 281 | if (!platformBar) return; | ||
2497 | 282 | auto platformMenu = m_target->platformMenu(); | ||
2498 | 283 | if (!platformMenu) return; | ||
2499 | 284 | |||
2500 | 285 | platformBar->insertMenu(platformMenu, before); | ||
2501 | 286 | m_inserted = true; | ||
2502 | 287 | } | ||
2503 | 288 | |||
2504 | 289 | void PlatformMenuWrapper::remove() | ||
2505 | 290 | { | ||
2506 | 291 | if (!m_inserted) return; | ||
2507 | 292 | qCDebug(ucMenu).nospace() << " PlatformMenuWrapper::remove(bar=" << m_bar | ||
2508 | 293 | << ", menu=" << m_target << ")"; | ||
2509 | 294 | |||
2510 | 295 | auto platformBar = m_bar->platformMenuBar(); | ||
2511 | 296 | if (!platformBar) return; | ||
2512 | 297 | auto platformMenu = m_target->platformMenu(); | ||
2513 | 298 | if (!platformMenu) return; | ||
2514 | 299 | |||
2515 | 300 | platformBar->removeMenu(platformMenu); | ||
2516 | 301 | m_inserted = false; | ||
2517 | 302 | } | ||
2518 | 303 | |||
2519 | 304 | void PlatformMenuWrapper::updateVisible() | ||
2520 | 305 | { | ||
2521 | 306 | if (m_target->platformMenu()) m_target->platformMenu()->setVisible(m_target->visible()); | ||
2522 | 307 | } | ||
2523 | 308 | |||
2524 | 309 | void PlatformMenuWrapper::updateEnabled() | ||
2525 | 310 | { | ||
2526 | 311 | if (m_target->platformMenu()) m_target->platformMenu()->setEnabled(m_target->isEnabled()); | ||
2527 | 312 | } | ||
2528 | 313 | |||
2529 | 314 | void PlatformMenuWrapper::updateText() | ||
2530 | 315 | { | ||
2531 | 316 | if (m_target->platformMenu()) m_target->platformMenu()->setText(m_target->text()); | ||
2532 | 317 | } | ||
2533 | 318 | |||
2534 | 319 | void PlatformMenuWrapper::updateIcon() | ||
2535 | 320 | { | ||
2536 | 321 | QIcon icon; | ||
2537 | 322 | if (!m_target->iconSource().isEmpty()) { | ||
2538 | 323 | icon = QIcon(m_target->iconSource().path()); | ||
2539 | 324 | } else if (!m_target->iconName().isEmpty()) { | ||
2540 | 325 | icon = QIcon::fromTheme(m_target->iconName()); | ||
2541 | 326 | } | ||
2542 | 327 | if (m_target->platformMenu()) m_target->platformMenu()->setIcon(icon); | ||
2543 | 328 | } | ||
2544 | 329 | |||
2545 | 330 | void PlatformMenuWrapper::syncPlatformMenu() | ||
2546 | 331 | { | ||
2547 | 332 | updateVisible(); | ||
2548 | 333 | updateEnabled(); | ||
2549 | 334 | updateText(); | ||
2550 | 335 | updateIcon(); | ||
2551 | 336 | } | ||
2552 | 337 | |||
2553 | 338 | UT_NAMESPACE_END | ||
2554 | 339 | |||
2555 | 340 | #include "moc_menubar_p.cpp" | ||
2556 | 0 | 341 | ||
2557 | === added file 'src/Ubuntu/UbuntuToolkit/menubar_p.h' | |||
2558 | --- src/Ubuntu/UbuntuToolkit/menubar_p.h 1970-01-01 00:00:00 +0000 | |||
2559 | +++ src/Ubuntu/UbuntuToolkit/menubar_p.h 2016-08-31 08:57:26 +0000 | |||
2560 | @@ -0,0 +1,65 @@ | |||
2561 | 1 | /* | ||
2562 | 2 | * Copyright 2016 Canonical Ltd. | ||
2563 | 3 | * | ||
2564 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2565 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
2566 | 6 | * the Free Software Foundation; version 3. | ||
2567 | 7 | * | ||
2568 | 8 | * This program is distributed in the hope that it will be useful, | ||
2569 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2570 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2571 | 11 | * GNU Lesser General Public License for more details. | ||
2572 | 12 | * | ||
2573 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
2574 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2575 | 15 | * | ||
2576 | 16 | */ | ||
2577 | 17 | |||
2578 | 18 | #ifndef MENUBAR_P_H | ||
2579 | 19 | #define MENUBAR_P_H | ||
2580 | 20 | |||
2581 | 21 | #include "menu_p.h" | ||
2582 | 22 | #include <ubuntutoolkitglobal.h> | ||
2583 | 23 | |||
2584 | 24 | #include <QQmlParserStatus> | ||
2585 | 25 | |||
2586 | 26 | class QPlatformMenuBar; | ||
2587 | 27 | |||
2588 | 28 | UT_NAMESPACE_BEGIN | ||
2589 | 29 | |||
2590 | 30 | class MenuBarPrivate; | ||
2591 | 31 | class UBUNTUTOOLKIT_EXPORT MenuBar : public QObject, public QQmlParserStatus | ||
2592 | 32 | { | ||
2593 | 33 | Q_OBJECT | ||
2594 | 34 | Q_INTERFACES(QQmlParserStatus) | ||
2595 | 35 | |||
2596 | 36 | Q_PROPERTY(QQmlListProperty<UT_PREPEND_NAMESPACE(Menu)> menus READ menus NOTIFY menusChanged FINAL) | ||
2597 | 37 | Q_CLASSINFO("DefaultProperty", "menus") | ||
2598 | 38 | |||
2599 | 39 | public: | ||
2600 | 40 | explicit MenuBar(QObject *parent = 0); | ||
2601 | 41 | ~MenuBar(); | ||
2602 | 42 | |||
2603 | 43 | Q_INVOKABLE void appendMenu(Menu *menu); | ||
2604 | 44 | Q_INVOKABLE void insertMenu(int index, Menu *menu); | ||
2605 | 45 | Q_INVOKABLE void removeMenu(Menu *menu); | ||
2606 | 46 | |||
2607 | 47 | QQmlListProperty<Menu> menus(); | ||
2608 | 48 | |||
2609 | 49 | QPlatformMenuBar *platformMenuBar() const; | ||
2610 | 50 | |||
2611 | 51 | void classBegin() Q_DECL_OVERRIDE; | ||
2612 | 52 | void componentComplete() Q_DECL_OVERRIDE; | ||
2613 | 53 | |||
2614 | 54 | Q_SIGNALS: | ||
2615 | 55 | void menusChanged(); | ||
2616 | 56 | |||
2617 | 57 | private: | ||
2618 | 58 | Q_DISABLE_COPY(MenuBar) | ||
2619 | 59 | Q_DECLARE_PRIVATE(MenuBar) | ||
2620 | 60 | QScopedPointer<MenuBarPrivate> d_ptr; | ||
2621 | 61 | }; | ||
2622 | 62 | |||
2623 | 63 | UT_NAMESPACE_END | ||
2624 | 64 | |||
2625 | 65 | #endif // MENUBAR_P_H | ||
2626 | 0 | 66 | ||
2627 | === added file 'src/Ubuntu/UbuntuToolkit/menubar_p_p.h' | |||
2628 | --- src/Ubuntu/UbuntuToolkit/menubar_p_p.h 1970-01-01 00:00:00 +0000 | |||
2629 | +++ src/Ubuntu/UbuntuToolkit/menubar_p_p.h 2016-08-31 08:57:26 +0000 | |||
2630 | @@ -0,0 +1,78 @@ | |||
2631 | 1 | /* | ||
2632 | 2 | * Copyright 2016 Canonical Ltd. | ||
2633 | 3 | * | ||
2634 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2635 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
2636 | 6 | * the Free Software Foundation; version 3. | ||
2637 | 7 | * | ||
2638 | 8 | * This program is distributed in the hope that it will be useful, | ||
2639 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2640 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2641 | 11 | * GNU Lesser General Public License for more details. | ||
2642 | 12 | * | ||
2643 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
2644 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2645 | 15 | * | ||
2646 | 16 | */ | ||
2647 | 17 | |||
2648 | 18 | #ifndef MENUBAR_P_P_H | ||
2649 | 19 | #define MENUBAR_P_P_H | ||
2650 | 20 | |||
2651 | 21 | #include "menubar_p.h" | ||
2652 | 22 | #include <ubuntutoolkitglobal.h> | ||
2653 | 23 | |||
2654 | 24 | class QPlatformMenuBar; | ||
2655 | 25 | |||
2656 | 26 | UT_NAMESPACE_BEGIN | ||
2657 | 27 | |||
2658 | 28 | class PlatformMenuWrapper; | ||
2659 | 29 | |||
2660 | 30 | class MenuBarPrivate | ||
2661 | 31 | { | ||
2662 | 32 | Q_DECLARE_PUBLIC(MenuBar) | ||
2663 | 33 | public: | ||
2664 | 34 | MenuBarPrivate(MenuBar *qq); | ||
2665 | 35 | ~MenuBarPrivate(); | ||
2666 | 36 | |||
2667 | 37 | void insertMenu(int index, Menu *menu); | ||
2668 | 38 | void removeMenu(Menu *menu); | ||
2669 | 39 | |||
2670 | 40 | static void menu_append(QQmlListProperty<Menu> *prop, Menu *o); | ||
2671 | 41 | static int menu_count(QQmlListProperty<Menu> *prop); | ||
2672 | 42 | static Menu *menu_at(QQmlListProperty<Menu> *prop, int index); | ||
2673 | 43 | static void menu_clear(QQmlListProperty<Menu> *prop); | ||
2674 | 44 | |||
2675 | 45 | MenuBar* q_ptr; | ||
2676 | 46 | QPlatformMenuBar* m_platformBar; | ||
2677 | 47 | QVector<Menu*> m_menus; | ||
2678 | 48 | QHash<QObject*, PlatformMenuWrapper*> m_platformMenus; | ||
2679 | 49 | }; | ||
2680 | 50 | |||
2681 | 51 | class PlatformMenuWrapper : public QObject | ||
2682 | 52 | { | ||
2683 | 53 | Q_OBJECT | ||
2684 | 54 | public: | ||
2685 | 55 | PlatformMenuWrapper(Menu *target, MenuBar *bar); | ||
2686 | 56 | ~PlatformMenuWrapper(); | ||
2687 | 57 | |||
2688 | 58 | void insert(QPlatformMenu *before); | ||
2689 | 59 | void remove(); | ||
2690 | 60 | |||
2691 | 61 | public Q_SLOTS: | ||
2692 | 62 | void updateVisible(); | ||
2693 | 63 | void updateEnabled(); | ||
2694 | 64 | void updateText(); | ||
2695 | 65 | void updateIcon(); | ||
2696 | 66 | |||
2697 | 67 | private: | ||
2698 | 68 | void syncPlatformMenu(); | ||
2699 | 69 | |||
2700 | 70 | QPointer<MenuBar> m_bar; | ||
2701 | 71 | QPointer<Menu> m_target; | ||
2702 | 72 | bool m_inserted; | ||
2703 | 73 | }; | ||
2704 | 74 | |||
2705 | 75 | UT_NAMESPACE_END | ||
2706 | 76 | |||
2707 | 77 | #endif // MENUBAR_P_P_H | ||
2708 | 78 | |||
2709 | 0 | 79 | ||
2710 | === added file 'src/Ubuntu/UbuntuToolkit/menugroup.cpp' | |||
2711 | --- src/Ubuntu/UbuntuToolkit/menugroup.cpp 1970-01-01 00:00:00 +0000 | |||
2712 | +++ src/Ubuntu/UbuntuToolkit/menugroup.cpp 2016-08-31 08:57:26 +0000 | |||
2713 | @@ -0,0 +1,164 @@ | |||
2714 | 1 | /* | ||
2715 | 2 | * Copyright 2016 Canonical Ltd. | ||
2716 | 3 | * | ||
2717 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2718 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
2719 | 6 | * the Free Software Foundation; version 3. | ||
2720 | 7 | * | ||
2721 | 8 | * This program is distributed in the hope that it will be useful, | ||
2722 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2723 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2724 | 11 | * GNU Lesser General Public License for more details. | ||
2725 | 12 | * | ||
2726 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
2727 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2728 | 15 | */ | ||
2729 | 16 | |||
2730 | 17 | #include "menugroup_p.h" | ||
2731 | 18 | #include "actionlist_p.h" | ||
2732 | 19 | #include "ucaction_p.h" | ||
2733 | 20 | |||
2734 | 21 | UT_NAMESPACE_BEGIN | ||
2735 | 22 | |||
2736 | 23 | /*! | ||
2737 | 24 | * \qmltype MenuGroup | ||
2738 | 25 | * \inqmlmodule Ubuntu.Components | ||
2739 | 26 | * \ingroup ubuntu | ||
2740 | 27 | * \brief Logical list of items for a menu. | ||
2741 | 28 | * | ||
2742 | 29 | * Example usage: | ||
2743 | 30 | * \qml | ||
2744 | 31 | * import QtQuick 2.4 | ||
2745 | 32 | * import Ubuntu.Components 1.3 | ||
2746 | 33 | * Menu { | ||
2747 | 34 | * text: "Edit" | ||
2748 | 35 | * | ||
2749 | 36 | * MenuGroup { | ||
2750 | 37 | * Action { text: "Undo" } | ||
2751 | 38 | * Action { text: "Redo" } | ||
2752 | 39 | * } | ||
2753 | 40 | * | ||
2754 | 41 | * MenuGroup { | ||
2755 | 42 | * Action { text: "Cut" } | ||
2756 | 43 | * ActionList { | ||
2757 | 44 | * Action { text: "Copy" } | ||
2758 | 45 | * Action { text: "Paste" } | ||
2759 | 46 | * } | ||
2760 | 47 | * } | ||
2761 | 48 | * | ||
2762 | 49 | * MenuGroup { | ||
2763 | 50 | * Action { text: "Select All" } | ||
2764 | 51 | * } | ||
2765 | 52 | * } | ||
2766 | 53 | * \endqml | ||
2767 | 54 | */ | ||
2768 | 55 | /*! | ||
2769 | 56 | * \qmlsignal MenuGroup::added(Object action) | ||
2770 | 57 | * Signal called when a action is added to the list | ||
2771 | 58 | */ | ||
2772 | 59 | |||
2773 | 60 | /*! | ||
2774 | 61 | * \qmlsignal MenuGroup::removed(Object action) | ||
2775 | 62 | * Signal called when a action is removed from the list | ||
2776 | 63 | */ | ||
2777 | 64 | /*! | ||
2778 | 65 | * \qmlsignal MenuGroup::changed() | ||
2779 | 66 | * Signal called when the contents of the group change, | ||
2780 | 67 | * including child content changes (eg. \l ActionList child add/remove) | ||
2781 | 68 | */ | ||
2782 | 69 | MenuGroup::MenuGroup(QObject *parent) | ||
2783 | 70 | : QObject(parent) | ||
2784 | 71 | { | ||
2785 | 72 | } | ||
2786 | 73 | |||
2787 | 74 | /*! | ||
2788 | 75 | * \qmlmethod MenuGroup::addObject(Object object) | ||
2789 | 76 | * Adds an Object to the list programatically. | ||
2790 | 77 | */ | ||
2791 | 78 | void MenuGroup::addObject(QObject *object) | ||
2792 | 79 | { | ||
2793 | 80 | if (m_data.contains(object)) { | ||
2794 | 81 | return; | ||
2795 | 82 | } | ||
2796 | 83 | m_data.push_back(object); | ||
2797 | 84 | |||
2798 | 85 | if (auto childGroup = qobject_cast<MenuGroup*>(object)) { | ||
2799 | 86 | connect(childGroup, &MenuGroup::changed, this, &MenuGroup::changed); | ||
2800 | 87 | } else if (auto actionList = qobject_cast<ActionList*>(object)) { | ||
2801 | 88 | connect(actionList, &ActionList::added, this, &MenuGroup::changed); | ||
2802 | 89 | connect(actionList, &ActionList::removed, this, &MenuGroup::changed); | ||
2803 | 90 | } | ||
2804 | 91 | |||
2805 | 92 | Q_EMIT added(object); | ||
2806 | 93 | Q_EMIT changed(); | ||
2807 | 94 | } | ||
2808 | 95 | |||
2809 | 96 | /*! | ||
2810 | 97 | * \qmlmethod MenuGroup::removeObject(Object object) | ||
2811 | 98 | * Removes an object from the list programatically. | ||
2812 | 99 | */ | ||
2813 | 100 | void MenuGroup::removeObject(QObject *object) | ||
2814 | 101 | { | ||
2815 | 102 | if (!object) { | ||
2816 | 103 | return; | ||
2817 | 104 | } | ||
2818 | 105 | if (m_data.removeOne(object)) { | ||
2819 | 106 | disconnect(object, 0, this, 0); | ||
2820 | 107 | Q_EMIT removed(object); | ||
2821 | 108 | Q_EMIT changed(); | ||
2822 | 109 | } | ||
2823 | 110 | } | ||
2824 | 111 | |||
2825 | 112 | /*! | ||
2826 | 113 | |||
2827 | 114 | * \qmlproperty list<Object> MenuGroup::data | ||
2828 | 115 | * \default | ||
2829 | 116 | * List of Objects in this MenuGroup | ||
2830 | 117 | * Note that when you set this property, the children of the MenuGroup will be ignored, | ||
2831 | 118 | * so do not set the list and define children. | ||
2832 | 119 | */ | ||
2833 | 120 | QQmlListProperty<QObject> MenuGroup::data() | ||
2834 | 121 | { | ||
2835 | 122 | return QQmlListProperty<QObject>(this, 0, MenuGroup::append, MenuGroup::count, MenuGroup::at, MenuGroup::clear); | ||
2836 | 123 | } | ||
2837 | 124 | |||
2838 | 125 | const QVector<QObject*> &MenuGroup::list() const | ||
2839 | 126 | { | ||
2840 | 127 | return m_data; | ||
2841 | 128 | } | ||
2842 | 129 | |||
2843 | 130 | void MenuGroup::append(QQmlListProperty<QObject> *list, QObject *object) | ||
2844 | 131 | { | ||
2845 | 132 | MenuGroup *menuGroup = qobject_cast<MenuGroup*>(list->object); | ||
2846 | 133 | if (menuGroup) { | ||
2847 | 134 | menuGroup->addObject(object); | ||
2848 | 135 | } | ||
2849 | 136 | } | ||
2850 | 137 | |||
2851 | 138 | int MenuGroup::count(QQmlListProperty<QObject> *list) | ||
2852 | 139 | { | ||
2853 | 140 | MenuGroup *menuGroup = qobject_cast<MenuGroup*>(list->object); | ||
2854 | 141 | if (menuGroup) { | ||
2855 | 142 | return menuGroup->m_data.count(); | ||
2856 | 143 | } | ||
2857 | 144 | return 0; | ||
2858 | 145 | } | ||
2859 | 146 | |||
2860 | 147 | QObject* MenuGroup::at(QQmlListProperty<QObject> *list, int index) | ||
2861 | 148 | { | ||
2862 | 149 | MenuGroup *menuGroup = qobject_cast<MenuGroup*>(list->object); | ||
2863 | 150 | if (menuGroup && index >=0 && menuGroup->m_data.count() > index) { | ||
2864 | 151 | return menuGroup->m_data[index]; | ||
2865 | 152 | } | ||
2866 | 153 | return Q_NULLPTR; | ||
2867 | 154 | } | ||
2868 | 155 | |||
2869 | 156 | void MenuGroup::clear(QQmlListProperty<QObject> *list) | ||
2870 | 157 | { | ||
2871 | 158 | MenuGroup *menuGroup = qobject_cast<MenuGroup*>(list->object); | ||
2872 | 159 | if (menuGroup) { | ||
2873 | 160 | menuGroup->m_data.clear(); | ||
2874 | 161 | } | ||
2875 | 162 | } | ||
2876 | 163 | |||
2877 | 164 | UT_NAMESPACE_END | ||
2878 | 0 | 165 | ||
2879 | === added file 'src/Ubuntu/UbuntuToolkit/menugroup_p.h' | |||
2880 | --- src/Ubuntu/UbuntuToolkit/menugroup_p.h 1970-01-01 00:00:00 +0000 | |||
2881 | +++ src/Ubuntu/UbuntuToolkit/menugroup_p.h 2016-08-31 08:57:26 +0000 | |||
2882 | @@ -0,0 +1,60 @@ | |||
2883 | 1 | /* | ||
2884 | 2 | * Copyright 2016 Canonical Ltd. | ||
2885 | 3 | * | ||
2886 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2887 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
2888 | 6 | * the Free Software Foundation; version 3. | ||
2889 | 7 | * | ||
2890 | 8 | * This program is distributed in the hope that it will be useful, | ||
2891 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2892 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2893 | 11 | * GNU Lesser General Public License for more details. | ||
2894 | 12 | * | ||
2895 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
2896 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2897 | 15 | */ | ||
2898 | 16 | |||
2899 | 17 | #ifndef MENUGROUP_P_H | ||
2900 | 18 | #define MENUGROUP_P_H | ||
2901 | 19 | |||
2902 | 20 | #include <ubuntutoolkitglobal.h> | ||
2903 | 21 | |||
2904 | 22 | #include <QObject> | ||
2905 | 23 | #include <QVector> | ||
2906 | 24 | #include <QQmlListProperty> | ||
2907 | 25 | |||
2908 | 26 | UT_NAMESPACE_BEGIN | ||
2909 | 27 | |||
2910 | 28 | class MenuGroup : public QObject | ||
2911 | 29 | { | ||
2912 | 30 | Q_OBJECT | ||
2913 | 31 | Q_PROPERTY(QQmlListProperty<QObject> data READ data) | ||
2914 | 32 | Q_CLASSINFO("DefaultProperty", "data") | ||
2915 | 33 | public: | ||
2916 | 34 | explicit MenuGroup(QObject *parent = 0); | ||
2917 | 35 | |||
2918 | 36 | QQmlListProperty<QObject> data(); | ||
2919 | 37 | |||
2920 | 38 | const QVector<QObject*> &list() const; | ||
2921 | 39 | |||
2922 | 40 | public Q_SLOTS: | ||
2923 | 41 | void addObject(QObject *object); | ||
2924 | 42 | void removeObject(QObject *object); | ||
2925 | 43 | |||
2926 | 44 | Q_SIGNALS: | ||
2927 | 45 | void added(QObject *object); | ||
2928 | 46 | void removed(QObject *object); | ||
2929 | 47 | void changed(); | ||
2930 | 48 | |||
2931 | 49 | protected: | ||
2932 | 50 | QVector<QObject*> m_data; | ||
2933 | 51 | |||
2934 | 52 | static void append(QQmlListProperty<QObject> *list, QObject *action); | ||
2935 | 53 | static int count(QQmlListProperty<QObject> *list); | ||
2936 | 54 | static QObject* at(QQmlListProperty<QObject> *list, int); | ||
2937 | 55 | static void clear(QQmlListProperty<QObject> *list); | ||
2938 | 56 | }; | ||
2939 | 57 | |||
2940 | 58 | UT_NAMESPACE_END | ||
2941 | 59 | |||
2942 | 60 | #endif // MENUGROUP_P_H | ||
2943 | 0 | 61 | ||
2944 | === added file 'src/Ubuntu/UbuntuToolkit/privates/splitviewhandler.cpp' | |||
2945 | --- src/Ubuntu/UbuntuToolkit/privates/splitviewhandler.cpp 1970-01-01 00:00:00 +0000 | |||
2946 | +++ src/Ubuntu/UbuntuToolkit/privates/splitviewhandler.cpp 2016-08-31 08:57:26 +0000 | |||
2947 | @@ -0,0 +1,137 @@ | |||
2948 | 1 | /* | ||
2949 | 2 | * Copyright 2016 Canonical Ltd. | ||
2950 | 3 | * | ||
2951 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2952 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
2953 | 6 | * the Free Software Foundation; version 3. | ||
2954 | 7 | * | ||
2955 | 8 | * This program is distributed in the hope that it will be useful, | ||
2956 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2957 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2958 | 11 | * GNU Lesser General Public License for more details. | ||
2959 | 12 | * | ||
2960 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
2961 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2962 | 15 | * | ||
2963 | 16 | * Author: Zsombor Egri <zsombor.egri@canonical.com> | ||
2964 | 17 | */ | ||
2965 | 18 | |||
2966 | 19 | #include "splitviewhandler_p_p.h" | ||
2967 | 20 | #include <QtQuick/private/qquickanchors_p.h> | ||
2968 | 21 | #include <QtQuick/private/qquickitem_p.h> | ||
2969 | 22 | #include <QtQuick/private/qquickevents_p_p.h> | ||
2970 | 23 | #include <QtQml/QQmlEngine> | ||
2971 | 24 | #include <QtQml/QQmlInfo> | ||
2972 | 25 | #include <splitview_p_p.h> | ||
2973 | 26 | |||
2974 | 27 | UT_NAMESPACE_BEGIN | ||
2975 | 28 | |||
2976 | 29 | SplitViewHandler::SplitViewHandler(QQuickItem *parent) | ||
2977 | 30 | : QQuickMouseArea(parent) | ||
2978 | 31 | { | ||
2979 | 32 | // for testing purposes | ||
2980 | 33 | setObjectName("resize_handle"); | ||
2981 | 34 | setFlag(ItemHasContents); | ||
2982 | 35 | setHoverEnabled(true); | ||
2983 | 36 | setAcceptedButtons(Qt::LeftButton); | ||
2984 | 37 | |||
2985 | 38 | setCursorShape(Qt::SplitHCursor); | ||
2986 | 39 | setParentItem(parent); | ||
2987 | 40 | |||
2988 | 41 | // attach the handler to the parent's rigth edge | ||
2989 | 42 | QQuickItemPrivate *dParent = QQuickItemPrivate::get(parentItem()); | ||
2990 | 43 | QQuickAnchors *anchors = QQuickItemPrivate::get(this)->anchors(); | ||
2991 | 44 | anchors->setTop(dParent->top()); | ||
2992 | 45 | anchors->setBottom(dParent->bottom()); | ||
2993 | 46 | anchors->setLeft(dParent->right()); | ||
2994 | 47 | |||
2995 | 48 | // capture mouse events | ||
2996 | 49 | connect(this, SIGNAL(pressed(QQuickMouseEvent*)), this, SLOT(onPressed(QQuickMouseEvent*))); | ||
2997 | 50 | connect(this, &SplitViewHandler::released, this, &SplitViewHandler::onReleased); | ||
2998 | 51 | connect(this, &SplitViewHandler::positionChanged, this, &SplitViewHandler::onPositionChanged); | ||
2999 | 52 | } | ||
3000 | 53 | |||
3001 | 54 | SplitViewHandler::~SplitViewHandler() | ||
3002 | 55 | { | ||
3003 | 56 | if (spacing) { | ||
3004 | 57 | disconnect(*spacing); | ||
3005 | 58 | } | ||
3006 | 59 | delete spacing; | ||
3007 | 60 | } | ||
3008 | 61 | |||
3009 | 62 | void SplitViewHandler::connectToView(SplitView *view) | ||
3010 | 63 | { | ||
3011 | 64 | this->view = view; | ||
3012 | 65 | // grab the context of the parent | ||
3013 | 66 | QQmlEngine::setContextForObject(this, qmlContext(view)); | ||
3014 | 67 | |||
3015 | 68 | // bind SplitView spacing, use it to specify the resize handle | ||
3016 | 69 | auto resizer = [view, this]() { | ||
3017 | 70 | setWidth(view->spacing()); | ||
3018 | 71 | }; | ||
3019 | 72 | spacing = new QMetaObject::Connection; | ||
3020 | 73 | *spacing = connect(view, &SplitView::spacingChanged, resizer); | ||
3021 | 74 | setWidth(view->spacing()); | ||
3022 | 75 | |||
3023 | 76 | // connect to receive handle delegate | ||
3024 | 77 | connect(view, &SplitView::handleDelegateChanged, | ||
3025 | 78 | this, &SplitViewHandler::onDelegateChanged); | ||
3026 | 79 | |||
3027 | 80 | onDelegateChanged(); | ||
3028 | 81 | } | ||
3029 | 82 | |||
3030 | 83 | void SplitViewHandler::onPressed(QQuickMouseEvent *event) | ||
3031 | 84 | { | ||
3032 | 85 | prevPos = QPointF(event->x(), event->y()); | ||
3033 | 86 | } | ||
3034 | 87 | |||
3035 | 88 | void SplitViewHandler::onReleased(QQuickMouseEvent *event) | ||
3036 | 89 | { | ||
3037 | 90 | Q_UNUSED(event); | ||
3038 | 91 | prevPos = QPointF(); | ||
3039 | 92 | } | ||
3040 | 93 | |||
3041 | 94 | void SplitViewHandler::onPositionChanged(QQuickMouseEvent *event) | ||
3042 | 95 | { | ||
3043 | 96 | if (!pressed()) { | ||
3044 | 97 | return; | ||
3045 | 98 | } | ||
3046 | 99 | qreal dx = event->x() - prevPos.x(); | ||
3047 | 100 | SplitViewAttached *attached = SplitViewAttached::get(parentItem()); | ||
3048 | 101 | if (attached) { | ||
3049 | 102 | attached->resize(dx); | ||
3050 | 103 | } | ||
3051 | 104 | } | ||
3052 | 105 | |||
3053 | 106 | void SplitViewHandler::onDelegateChanged() | ||
3054 | 107 | { | ||
3055 | 108 | static bool warningShown = false; | ||
3056 | 109 | // the child is an instance of the delegate | ||
3057 | 110 | QList<QQuickItem*> children = childItems(); | ||
3058 | 111 | qDeleteAll(children); | ||
3059 | 112 | |||
3060 | 113 | // and set the new delegate - if any | ||
3061 | 114 | if (SplitViewPrivate::get(view)->handleDelegate) { | ||
3062 | 115 | QQmlContext *context = new QQmlContext(qmlContext(this), this); | ||
3063 | 116 | context->setContextProperty("handle", QVariant::fromValue(this)); | ||
3064 | 117 | QObject *object = SplitViewPrivate::get(view)->handleDelegate->beginCreate(context); | ||
3065 | 118 | if (object) { | ||
3066 | 119 | QQuickItem *item = qobject_cast<QQuickItem*>(object); | ||
3067 | 120 | if (!item) { | ||
3068 | 121 | if (!warningShown) { | ||
3069 | 122 | qmlInfo(view) << "handle delegate not an Item"; | ||
3070 | 123 | warningShown = true; | ||
3071 | 124 | } | ||
3072 | 125 | SplitViewPrivate::get(view)->handleDelegate->completeCreate(); | ||
3073 | 126 | delete object; | ||
3074 | 127 | } else { | ||
3075 | 128 | warningShown = false; | ||
3076 | 129 | QQml_setParent_noEvent(item, this); | ||
3077 | 130 | item->setParentItem(this); | ||
3078 | 131 | SplitViewPrivate::get(view)->handleDelegate->completeCreate(); | ||
3079 | 132 | } | ||
3080 | 133 | } | ||
3081 | 134 | } | ||
3082 | 135 | } | ||
3083 | 136 | |||
3084 | 137 | UT_NAMESPACE_END | ||
3085 | 0 | 138 | ||
3086 | === added file 'src/Ubuntu/UbuntuToolkit/privates/splitviewhandler_p_p.h' | |||
3087 | --- src/Ubuntu/UbuntuToolkit/privates/splitviewhandler_p_p.h 1970-01-01 00:00:00 +0000 | |||
3088 | +++ src/Ubuntu/UbuntuToolkit/privates/splitviewhandler_p_p.h 2016-08-31 08:57:26 +0000 | |||
3089 | @@ -0,0 +1,52 @@ | |||
3090 | 1 | /* | ||
3091 | 2 | * Copyright 2016 Canonical Ltd. | ||
3092 | 3 | * | ||
3093 | 4 | * This program is free software; you can redistribute it and/or modify | ||
3094 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
3095 | 6 | * the Free Software Foundation; version 3. | ||
3096 | 7 | * | ||
3097 | 8 | * This program is distributed in the hope that it will be useful, | ||
3098 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3099 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3100 | 11 | * GNU Lesser General Public License for more details. | ||
3101 | 12 | * | ||
3102 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
3103 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3104 | 15 | * | ||
3105 | 16 | * Author: Zsombor Egri <zsombor.egri@canonical.com> | ||
3106 | 17 | */ | ||
3107 | 18 | |||
3108 | 19 | #ifndef SPLITVIEWHANDLER_H | ||
3109 | 20 | #define SPLITVIEWHANDLER_H | ||
3110 | 21 | |||
3111 | 22 | #include <QtQuick/QQuickItem> | ||
3112 | 23 | #include <QtCore/QPointer> | ||
3113 | 24 | #include <QtQuick/private/qquickmousearea_p.h> | ||
3114 | 25 | #include <ubuntutoolkitglobal.h> | ||
3115 | 26 | |||
3116 | 27 | UT_NAMESPACE_BEGIN | ||
3117 | 28 | |||
3118 | 29 | class SplitView; | ||
3119 | 30 | class SplitViewHandler : public QQuickMouseArea | ||
3120 | 31 | { | ||
3121 | 32 | Q_OBJECT | ||
3122 | 33 | public: | ||
3123 | 34 | explicit SplitViewHandler(QQuickItem *parent = 0); | ||
3124 | 35 | ~SplitViewHandler(); | ||
3125 | 36 | void connectToView(SplitView *view); | ||
3126 | 37 | |||
3127 | 38 | protected: | ||
3128 | 39 | QPointF prevPos; | ||
3129 | 40 | QPointer<SplitView> view; | ||
3130 | 41 | QMetaObject::Connection *spacing{nullptr}; | ||
3131 | 42 | |||
3132 | 43 | private Q_SLOTS: | ||
3133 | 44 | void onPressed(QQuickMouseEvent *event); | ||
3134 | 45 | void onReleased(QQuickMouseEvent *event); | ||
3135 | 46 | void onPositionChanged(QQuickMouseEvent *event); | ||
3136 | 47 | void onDelegateChanged(); | ||
3137 | 48 | }; | ||
3138 | 49 | |||
3139 | 50 | UT_NAMESPACE_END | ||
3140 | 51 | |||
3141 | 52 | #endif // SPLITVIEWHANDLER_H | ||
3142 | 0 | 53 | ||
3143 | === modified file 'src/Ubuntu/UbuntuToolkit/quickutils.cpp' | |||
3144 | --- src/Ubuntu/UbuntuToolkit/quickutils.cpp 2016-07-07 07:21:48 +0000 | |||
3145 | +++ src/Ubuntu/UbuntuToolkit/quickutils.cpp 2016-08-31 08:57:26 +0000 | |||
3146 | @@ -36,6 +36,7 @@ | |||
3147 | 36 | 36 | ||
3148 | 37 | QuickUtils::QuickUtils(QObject *parent) : | 37 | QuickUtils::QuickUtils(QObject *parent) : |
3149 | 38 | QObject(parent), | 38 | QObject(parent), |
3150 | 39 | m_rootWindow(0), | ||
3151 | 39 | m_rootView(0), | 40 | m_rootView(0), |
3152 | 40 | m_mouseAttached(false), | 41 | m_mouseAttached(false), |
3153 | 41 | m_keyboardAttached(false) | 42 | m_keyboardAttached(false) |
3154 | @@ -86,7 +87,7 @@ | |||
3155 | 86 | // make sure we have the m_rootView updated | 87 | // make sure we have the m_rootView updated |
3156 | 87 | lookupQuickView(); | 88 | lookupQuickView(); |
3157 | 88 | if (!object) { | 89 | if (!object) { |
3159 | 89 | return (m_rootView) ? m_rootView->rootObject() : 0; | 90 | return m_rootView ? m_rootView->rootObject() : (m_rootWindow ? m_rootWindow->contentItem() : 0); |
3160 | 90 | } | 91 | } |
3161 | 91 | 92 | ||
3162 | 92 | QQuickItem *item = qobject_cast<QQuickItem*>(object); | 93 | QQuickItem *item = qobject_cast<QQuickItem*>(object); |
3163 | @@ -175,9 +176,10 @@ | |||
3164 | 175 | */ | 176 | */ |
3165 | 176 | void QuickUtils::lookupQuickView() | 177 | void QuickUtils::lookupQuickView() |
3166 | 177 | { | 178 | { |
3168 | 178 | if (m_rootView) | 179 | if (m_rootWindow) |
3169 | 179 | return; | 180 | return; |
3170 | 180 | Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) { | 181 | Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) { |
3171 | 182 | m_rootWindow = qobject_cast<QQuickWindow*>(w); | ||
3172 | 181 | m_rootView = qobject_cast<QQuickView*>(w); | 183 | m_rootView = qobject_cast<QQuickView*>(w); |
3173 | 182 | if (m_rootView) { | 184 | if (m_rootView) { |
3174 | 183 | // connect in case we get the root object changed | 185 | // connect in case we get the root object changed |
3175 | 184 | 186 | ||
3176 | === modified file 'src/Ubuntu/UbuntuToolkit/quickutils_p.h' | |||
3177 | --- src/Ubuntu/UbuntuToolkit/quickutils_p.h 2016-07-07 07:21:48 +0000 | |||
3178 | +++ src/Ubuntu/UbuntuToolkit/quickutils_p.h 2016-08-31 08:57:26 +0000 | |||
3179 | @@ -85,6 +85,7 @@ | |||
3180 | 85 | 85 | ||
3181 | 86 | private: | 86 | private: |
3182 | 87 | explicit QuickUtils(QObject *parent = 0); | 87 | explicit QuickUtils(QObject *parent = 0); |
3183 | 88 | QPointer<QQuickWindow> m_rootWindow; | ||
3184 | 88 | QPointer<QQuickView> m_rootView; | 89 | QPointer<QQuickView> m_rootView; |
3185 | 89 | QStringList m_omitIM; | 90 | QStringList m_omitIM; |
3186 | 90 | bool m_mouseAttached; | 91 | bool m_mouseAttached; |
3187 | 91 | 92 | ||
3188 | === added file 'src/Ubuntu/UbuntuToolkit/splitview.cpp' | |||
3189 | --- src/Ubuntu/UbuntuToolkit/splitview.cpp 1970-01-01 00:00:00 +0000 | |||
3190 | +++ src/Ubuntu/UbuntuToolkit/splitview.cpp 2016-08-31 08:57:26 +0000 | |||
3191 | @@ -0,0 +1,675 @@ | |||
3192 | 1 | /* | ||
3193 | 2 | * Copyright 2016 Canonical Ltd. | ||
3194 | 3 | * | ||
3195 | 4 | * This program is free software; you can redistribute it and/or modify | ||
3196 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
3197 | 6 | * the Free Software Foundation; version 3. | ||
3198 | 7 | * | ||
3199 | 8 | * This program is distributed in the hope that it will be useful, | ||
3200 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3201 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3202 | 11 | * GNU Lesser General Public License for more details. | ||
3203 | 12 | * | ||
3204 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
3205 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3206 | 15 | * | ||
3207 | 16 | * Author: Zsombor Egri <zsombor.egri@canonical.com> | ||
3208 | 17 | */ | ||
3209 | 18 | |||
3210 | 19 | #include <QtQuick/private/qquickitem_p.h> | ||
3211 | 20 | #include <QtQuick/private/qquickanchors_p.h> | ||
3212 | 21 | #include <QtQml/QQmlInfo> | ||
3213 | 22 | |||
3214 | 23 | #include "splitview_p.h" | ||
3215 | 24 | #include "splitview_p_p.h" | ||
3216 | 25 | #include "ucunits_p.h" | ||
3217 | 26 | #include "ucpagetreenode_p.h" | ||
3218 | 27 | |||
3219 | 28 | #include "privates/splitviewhandler_p_p.h" | ||
3220 | 29 | |||
3221 | 30 | #define DEFAULT_SPACING_DP 4 | ||
3222 | 31 | |||
3223 | 32 | UT_NAMESPACE_BEGIN | ||
3224 | 33 | |||
3225 | 34 | /*! | ||
3226 | 35 | * \qmltype SplitView | ||
3227 | 36 | * \inqmlmodule Ubuntu.Components.Labs 1.0 | ||
3228 | 37 | * \inherits QQuickBasePositioner | ||
3229 | 38 | * \ingroup ubuntu-labs | ||
3230 | 39 | * \brief A view component with a flexible layout configuration setup. | ||
3231 | 40 | * | ||
3232 | 41 | * The component arranges the declared child elements horizontally based on an active | ||
3233 | 42 | * column configuration layout. Child elements are considered to be views, and each view | ||
3234 | 43 | * is identified with a column index, specified by the SplitView.column attached property. | ||
3235 | 44 | * Views should not have width declared, because the width of each view is specified | ||
3236 | 45 | * by the active layout's configuration (ViewColumn) and will overwrite the value | ||
3237 | 46 | * specified by the view. On the other hand they should have a height specified, or | ||
3238 | 47 | * they can be anchored to the top and bottom of the view. SplitView being a positioner, | ||
3239 | 48 | * remember not to anchor horizontal anchor lines or anchor fill the columns. | ||
3240 | 49 | * | ||
3241 | 50 | * In order for a SplitView to show some content it must have at least one active layout | ||
3242 | 51 | * present. Views which are not configured by the active layout will be hidden. Hidden | ||
3243 | 52 | * views may be resized, therefore if the content is size sensitive (i.e. the amount | ||
3244 | 53 | * shown differs depending on the space available), make sure the content of your view | ||
3245 | 54 | * does take this into account. | ||
3246 | 55 | * \code | ||
3247 | 56 | * import QtQuick 2.4 | ||
3248 | 57 | * import Ubuntu.Components 1.3 | ||
3249 | 58 | * import Ubuntu.Components.Labs 1.0 | ||
3250 | 59 | * | ||
3251 | 60 | * MainView { | ||
3252 | 61 | * id: main | ||
3253 | 62 | * width: units.gu(300) | ||
3254 | 63 | * height: units.gu(80) | ||
3255 | 64 | * SplitView { | ||
3256 | 65 | * anchors.fill: parent | ||
3257 | 66 | * layouts: [ | ||
3258 | 67 | * SplitViewLayout { | ||
3259 | 68 | * when: main.width < units.gu(80) | ||
3260 | 69 | * ViewColumn { | ||
3261 | 70 | * fillWidth: true | ||
3262 | 71 | * } | ||
3263 | 72 | * }, | ||
3264 | 73 | * SplitViewLayout { | ||
3265 | 74 | * when: main.width >= units.gu(80) | ||
3266 | 75 | * ViewColumn { | ||
3267 | 76 | * minimumWidth: units.gu(30) | ||
3268 | 77 | * maximumWidth: units.gu(100) | ||
3269 | 78 | * preferredWidth: units.gu(40) | ||
3270 | 79 | * } | ||
3271 | 80 | * ViewColumn { | ||
3272 | 81 | * minimumWidth: units.gu(40) | ||
3273 | 82 | * fillWidth: true | ||
3274 | 83 | * } | ||
3275 | 84 | * } | ||
3276 | 85 | * ] | ||
3277 | 86 | * } | ||
3278 | 87 | * | ||
3279 | 88 | * Page { | ||
3280 | 89 | * id: column1 | ||
3281 | 90 | * height: parent.height | ||
3282 | 91 | * } | ||
3283 | 92 | * Page { | ||
3284 | 93 | * id: column2 | ||
3285 | 94 | * height: parent.height | ||
3286 | 95 | * } | ||
3287 | 96 | * } | ||
3288 | 97 | * \endcode | ||
3289 | 98 | * | ||
3290 | 99 | * The SplitView can be used with a Repeater in case the content of the view columns | ||
3291 | 100 | * doesn't need to be preserved between layout changes. The example above with a | ||
3292 | 101 | * Repeater would look as follows: | ||
3293 | 102 | * \code | ||
3294 | 103 | * import QtQuick 2.4 | ||
3295 | 104 | * import Ubuntu.Components 1.3 | ||
3296 | 105 | * import Ubuntu.Components.Labs 1.0 | ||
3297 | 106 | * | ||
3298 | 107 | * MainView { | ||
3299 | 108 | * id: main | ||
3300 | 109 | * width: units.gu(300) | ||
3301 | 110 | * height: units.gu(80) | ||
3302 | 111 | * SplitView { | ||
3303 | 112 | * id: view | ||
3304 | 113 | * anchors.fill: parent | ||
3305 | 114 | * layouts: [ | ||
3306 | 115 | * SplitViewLayout { | ||
3307 | 116 | * when: main.width < units.gu(80) | ||
3308 | 117 | * ViewColumn { | ||
3309 | 118 | * fillWidth: true | ||
3310 | 119 | * } | ||
3311 | 120 | * }, | ||
3312 | 121 | * SplitViewLayout { | ||
3313 | 122 | * when: main.width >= units.gu(80) | ||
3314 | 123 | * ViewColumn { | ||
3315 | 124 | * minimumWidth: units.gu(30) | ||
3316 | 125 | * maximumWidth: units.gu(100) | ||
3317 | 126 | * preferredWidth: units.gu(40) | ||
3318 | 127 | * } | ||
3319 | 128 | * ViewColumn { | ||
3320 | 129 | * minimumWidth: units.gu(40) | ||
3321 | 130 | * fillWidth: true | ||
3322 | 131 | * } | ||
3323 | 132 | * } | ||
3324 | 133 | * ] | ||
3325 | 134 | * } | ||
3326 | 135 | * | ||
3327 | 136 | * Repeater { | ||
3328 | 137 | * model: view.activeLayout.columns | ||
3329 | 138 | * Page { | ||
3330 | 139 | * height: parent.height | ||
3331 | 140 | * } | ||
3332 | 141 | * } | ||
3333 | 142 | * } | ||
3334 | 143 | * \endcode | ||
3335 | 144 | * | ||
3336 | 145 | * \section2 Resizing | ||
3337 | 146 | * SplitView provides the ability to resize view columns. Each column has an attached | ||
3338 | 147 | * handle which provides the ability to resize the columns using a mouse or touch. | ||
3339 | 148 | * Columns can be resized if the spacing property is set and the column configurations | ||
3340 | 149 | * allow that (see \l spacing property). | ||
3341 | 150 | * | ||
3342 | 151 | * \section2 Attached properties | ||
3343 | 152 | * SplitView provides a set of attached properties to each column view. Views can in | ||
3344 | 153 | * this way have access to various values of the SplitView and configurations. | ||
3345 | 154 | */ | ||
3346 | 155 | |||
3347 | 156 | /*! | ||
3348 | 157 | * \qmlproperty real SplitView::spacing | ||
3349 | 158 | * Spacing between view columns. A value bigger than 0 enables resizing of columns with | ||
3350 | 159 | * a \l{ViewColumn::minimumWidth}{minimumWidth} lower than \l {ViewColumn::maximumWidth}{maximumWidth}. | ||
3351 | 160 | * If spacing is 0 the columns cannot be resized. | ||
3352 | 161 | * Defaults to 4 device pixels. | ||
3353 | 162 | */ | ||
3354 | 163 | void SplitView::setSpacing2(qreal spacing, bool reset) | ||
3355 | 164 | { | ||
3356 | 165 | Q_D(SplitView); | ||
3357 | 166 | if (reset && d->defaultSpacing) { | ||
3358 | 167 | QObject::disconnect(*d->defaultSpacing); | ||
3359 | 168 | delete d->defaultSpacing; | ||
3360 | 169 | d->defaultSpacing = Q_NULLPTR; | ||
3361 | 170 | } | ||
3362 | 171 | if (qFuzzyCompare(this->spacing(), spacing)) { | ||
3363 | 172 | return; | ||
3364 | 173 | } | ||
3365 | 174 | static_cast<QQuickBasePositioner*>(this)->setSpacing(spacing); | ||
3366 | 175 | } | ||
3367 | 176 | |||
3368 | 177 | /****************************************************************************** | ||
3369 | 178 | * SplitViewAttached | ||
3370 | 179 | */ | ||
3371 | 180 | SplitViewAttached::SplitViewAttached(QObject *parent) | ||
3372 | 181 | : QObject(*(new SplitViewAttachedPrivate), parent) | ||
3373 | 182 | { | ||
3374 | 183 | } | ||
3375 | 184 | |||
3376 | 185 | SplitViewAttached *SplitViewAttached::get(QQuickItem *item) | ||
3377 | 186 | { | ||
3378 | 187 | SplitViewAttached *attached = static_cast<SplitViewAttached*>( | ||
3379 | 188 | qmlAttachedPropertiesObject<SplitView>(item, false)); | ||
3380 | 189 | return attached; | ||
3381 | 190 | } | ||
3382 | 191 | |||
3383 | 192 | ViewColumn *SplitViewAttachedPrivate::getConfig(QQuickItem *attachee) | ||
3384 | 193 | { | ||
3385 | 194 | SplitViewAttached *attached = SplitViewAttached::get(attachee); | ||
3386 | 195 | if (!attached) { | ||
3387 | 196 | return nullptr; | ||
3388 | 197 | } | ||
3389 | 198 | return get(attached)->config(); | ||
3390 | 199 | } | ||
3391 | 200 | |||
3392 | 201 | void SplitViewAttachedPrivate::configure(SplitView *view, int column) | ||
3393 | 202 | { | ||
3394 | 203 | this->column = column; | ||
3395 | 204 | splitView = view; | ||
3396 | 205 | Q_EMIT q_func()->columnChanged(); | ||
3397 | 206 | } | ||
3398 | 207 | |||
3399 | 208 | void SplitViewAttached::resize(qreal delta) | ||
3400 | 209 | { | ||
3401 | 210 | Q_D(SplitViewAttached); | ||
3402 | 211 | ViewColumn *config = d->config(); | ||
3403 | 212 | if (config) { | ||
3404 | 213 | config->resize(delta); | ||
3405 | 214 | } | ||
3406 | 215 | } | ||
3407 | 216 | |||
3408 | 217 | /*! | ||
3409 | 218 | * \qmlattachedproperty ViewColumn SplitView::columnConfig | ||
3410 | 219 | * The attached property holds the active layout's column configuration data. | ||
3411 | 220 | * The value is null if there is no active configuration value provided for | ||
3412 | 221 | * the column. | ||
3413 | 222 | */ | ||
3414 | 223 | UT_PREPEND_NAMESPACE(ViewColumn*) SplitViewAttachedPrivate::config() | ||
3415 | 224 | { | ||
3416 | 225 | if (!splitView || column < 0) { | ||
3417 | 226 | return nullptr; | ||
3418 | 227 | } | ||
3419 | 228 | SplitViewPrivate *d = SplitViewPrivate::get(splitView); | ||
3420 | 229 | if (!d->activeLayout) { | ||
3421 | 230 | return nullptr; | ||
3422 | 231 | } | ||
3423 | 232 | if (SplitViewLayoutPrivate::get(d->activeLayout)->columnData.size() <= column) { | ||
3424 | 233 | return nullptr; | ||
3425 | 234 | } | ||
3426 | 235 | return SplitViewLayoutPrivate::get(d->activeLayout)->columnData[column]; | ||
3427 | 236 | } | ||
3428 | 237 | |||
3429 | 238 | /*! | ||
3430 | 239 | * \qmlattachedproperty SplitView SplitView::view | ||
3431 | 240 | * Contains the SplitView instance of the column. | ||
3432 | 241 | */ | ||
3433 | 242 | |||
3434 | 243 | /*! | ||
3435 | 244 | * \qmlattachedproperty int SplitView::column | ||
3436 | 245 | * The property holds the column index the view is configured to. | ||
3437 | 246 | */ | ||
3438 | 247 | |||
3439 | 248 | /****************************************************************************** | ||
3440 | 249 | * SplitView | ||
3441 | 250 | */ | ||
3442 | 251 | SplitViewPrivate::SplitViewPrivate(SplitView *qq) | ||
3443 | 252 | : q_ptr(qq) | ||
3444 | 253 | { | ||
3445 | 254 | } | ||
3446 | 255 | |||
3447 | 256 | SplitViewPrivate::~SplitViewPrivate() | ||
3448 | 257 | { | ||
3449 | 258 | } | ||
3450 | 259 | |||
3451 | 260 | UT_PREPEND_NAMESPACE(SplitViewAttached) *SplitView::qmlAttachedProperties(QObject *owner) | ||
3452 | 261 | { | ||
3453 | 262 | return new SplitViewAttached(owner); | ||
3454 | 263 | } | ||
3455 | 264 | |||
3456 | 265 | // layouts property | ||
3457 | 266 | /*! | ||
3458 | 267 | * \qmlproperty list<SplitViewLayout> SplitView::layouts | ||
3459 | 268 | * The property holds the layout configurations declared for the given SplitView. | ||
3460 | 269 | * \sa SplitViewLayout | ||
3461 | 270 | */ | ||
3462 | 271 | void SplitViewPrivate::layout_Append(QQmlListProperty<SplitViewLayout> *list, SplitViewLayout* layout) | ||
3463 | 272 | { | ||
3464 | 273 | SplitView *view = static_cast<SplitView*>(list->object); | ||
3465 | 274 | SplitViewPrivate *d = SplitViewPrivate::get(view); | ||
3466 | 275 | d->columnLatouts.append(layout); | ||
3467 | 276 | // parent layout to view | ||
3468 | 277 | layout->setParent(view); | ||
3469 | 278 | // capture layout activation | ||
3470 | 279 | QObject::connect(layout, SIGNAL(whenChanged()), view, SLOT(changeLayout()), Qt::DirectConnection); | ||
3471 | 280 | Q_EMIT view->layoutsChanged(); | ||
3472 | 281 | } | ||
3473 | 282 | int SplitViewPrivate::layout_Count(QQmlListProperty<SplitViewLayout> *list) | ||
3474 | 283 | { | ||
3475 | 284 | SplitView *view = static_cast<SplitView*>(list->object); | ||
3476 | 285 | SplitViewPrivate *d = SplitViewPrivate::get(view); | ||
3477 | 286 | return d->columnLatouts.size(); | ||
3478 | 287 | } | ||
3479 | 288 | SplitViewLayout *SplitViewPrivate::layout_At(QQmlListProperty<SplitViewLayout> *list, int index) | ||
3480 | 289 | { | ||
3481 | 290 | SplitView *view = static_cast<SplitView*>(list->object); | ||
3482 | 291 | SplitViewPrivate *d = SplitViewPrivate::get(view); | ||
3483 | 292 | return d->columnLatouts.at(index); | ||
3484 | 293 | } | ||
3485 | 294 | void SplitViewPrivate::layout_Clear(QQmlListProperty<SplitViewLayout> *list) | ||
3486 | 295 | { | ||
3487 | 296 | SplitView *view = static_cast<SplitView*>(list->object); | ||
3488 | 297 | SplitViewPrivate *d = SplitViewPrivate::get(view); | ||
3489 | 298 | for (SplitViewLayout *layout : d->columnLatouts) { | ||
3490 | 299 | // disconnect layout activation | ||
3491 | 300 | QObject::disconnect(layout, SIGNAL(whenChanged()), view, SLOT(changeLayout())); | ||
3492 | 301 | delete layout; | ||
3493 | 302 | } | ||
3494 | 303 | d->columnLatouts.clear(); | ||
3495 | 304 | d->activeLayout = nullptr; | ||
3496 | 305 | Q_EMIT view->layoutsChanged(); | ||
3497 | 306 | } | ||
3498 | 307 | QQmlListProperty<SplitViewLayout> SplitViewPrivate::layouts() | ||
3499 | 308 | { | ||
3500 | 309 | Q_Q(SplitView); | ||
3501 | 310 | return QQmlListProperty<SplitViewLayout>(q, (void*)&columnLatouts, | ||
3502 | 311 | &layout_Append, | ||
3503 | 312 | &layout_Count, | ||
3504 | 313 | &layout_At, | ||
3505 | 314 | &layout_Clear); | ||
3506 | 315 | } | ||
3507 | 316 | |||
3508 | 317 | /*! | ||
3509 | 318 | * \qmlproperty SplitViewLayout SplitView::activeLayout | ||
3510 | 319 | * \readonly | ||
3511 | 320 | * The property holds the active SplitViewLayout instance, or null is no layout | ||
3512 | 321 | * is active. | ||
3513 | 322 | */ | ||
3514 | 323 | UT_PREPEND_NAMESPACE(SplitViewLayout) *SplitViewPrivate::getActiveLayout() | ||
3515 | 324 | { | ||
3516 | 325 | return activeLayout; | ||
3517 | 326 | } | ||
3518 | 327 | |||
3519 | 328 | // invoked when one of the SplitViewLayouts emits whenChanged() | ||
3520 | 329 | void SplitViewPrivate::changeLayout() | ||
3521 | 330 | { | ||
3522 | 331 | // go through layouts and check who's the active one | ||
3523 | 332 | SplitViewLayout *newActive = nullptr; | ||
3524 | 333 | for (SplitViewLayout *layout : columnLatouts) { | ||
3525 | 334 | if (SplitViewLayoutPrivate::get(layout)->when) { | ||
3526 | 335 | newActive = layout; | ||
3527 | 336 | break; | ||
3528 | 337 | } | ||
3529 | 338 | } | ||
3530 | 339 | if (newActive == activeLayout) { | ||
3531 | 340 | return; | ||
3532 | 341 | } | ||
3533 | 342 | |||
3534 | 343 | // Q: should we reset the sizes of the previous layout? | ||
3535 | 344 | // at least it feels right to preserve the last state of the layout... | ||
3536 | 345 | activeLayout = newActive; | ||
3537 | 346 | |||
3538 | 347 | Q_EMIT q_func()->activeLayoutChanged(); | ||
3539 | 348 | |||
3540 | 349 | updateLayout(); | ||
3541 | 350 | if (q_func()->sender()) { | ||
3542 | 351 | // was called by a whenChanged() signal invocation | ||
3543 | 352 | recalculateWidths(RecalculateAll); | ||
3544 | 353 | } | ||
3545 | 354 | } | ||
3546 | 355 | |||
3547 | 356 | void SplitViewPrivate::updateLayout() | ||
3548 | 357 | { | ||
3549 | 358 | Q_Q(SplitView); | ||
3550 | 359 | for (QQuickItem *child : q->childItems()) { | ||
3551 | 360 | bool visible = true; | ||
3552 | 361 | ViewColumn *columnConfig = SplitViewAttachedPrivate::getConfig(child); | ||
3553 | 362 | if (!columnConfig) { | ||
3554 | 363 | // no configuration for the column, hide it | ||
3555 | 364 | visible = false; | ||
3556 | 365 | } else { | ||
3557 | 366 | ViewColumnPrivate *config = ViewColumnPrivate::get(columnConfig); | ||
3558 | 367 | visible = activeLayout | ||
3559 | 368 | && (config->column < SplitViewLayoutPrivate::get(activeLayout)->columnData.size()); | ||
3560 | 369 | } | ||
3561 | 370 | dirty = dirty | (child->isVisible() != visible); | ||
3562 | 371 | child->setVisible(visible); | ||
3563 | 372 | } | ||
3564 | 373 | } | ||
3565 | 374 | |||
3566 | 375 | void SplitViewPrivate::recalculateWidths(RelayoutOperation operation) | ||
3567 | 376 | { | ||
3568 | 377 | if (!activeLayout || (!QQuickItemPrivate::get(q_func())->componentComplete && !dirty)) { | ||
3569 | 378 | return; | ||
3570 | 379 | } | ||
3571 | 380 | Q_Q(SplitView); | ||
3572 | 381 | |||
3573 | 382 | // remove the spacing from the width | ||
3574 | 383 | qreal fillWidth = q->width() - q->spacing() * (SplitViewLayoutPrivate::get(activeLayout)->columnData.size() - 1); | ||
3575 | 384 | // stack of columns with fillWidth true | ||
3576 | 385 | QList<QQuickItem*> fillStack; | ||
3577 | 386 | |||
3578 | 387 | for (QQuickItem *child : q->childItems()) { | ||
3579 | 388 | ViewColumn *columnConfig = SplitViewAttachedPrivate::getConfig(child); | ||
3580 | 389 | if (!columnConfig) { | ||
3581 | 390 | continue; | ||
3582 | 391 | } | ||
3583 | 392 | ViewColumnPrivate *config = ViewColumnPrivate::get(columnConfig); | ||
3584 | 393 | |||
3585 | 394 | if (config->fillWidth && !config->resized) { | ||
3586 | 395 | // add to the fillWidth stack | ||
3587 | 396 | if (operation & CalculateFillWidth) { | ||
3588 | 397 | fillStack << child; | ||
3589 | 398 | } | ||
3590 | 399 | } else { | ||
3591 | 400 | if (operation & SetPreferredSize) { | ||
3592 | 401 | child->setWidth(config->preferredWidth); | ||
3593 | 402 | } | ||
3594 | 403 | if (operation & CalculateFillWidth) { | ||
3595 | 404 | fillWidth -= config->preferredWidth; | ||
3596 | 405 | } | ||
3597 | 406 | } | ||
3598 | 407 | } | ||
3599 | 408 | |||
3600 | 409 | // split the width between the stacked fillWidth columns | ||
3601 | 410 | if (fillStack.size() && (operation & CalculateFillWidth)) { | ||
3602 | 411 | fillWidth /= fillStack.size(); | ||
3603 | 412 | for (QQuickItem *child : fillStack) { | ||
3604 | 413 | // even though the column is fillWidth, it may have min and max specified; | ||
3605 | 414 | // check if the size can be applied | ||
3606 | 415 | ViewColumnPrivate *config = ViewColumnPrivate::get(SplitViewAttachedPrivate::getConfig(child)); | ||
3607 | 416 | config->setPreferredWidth(fillWidth, false); | ||
3608 | 417 | // update preferredWidth so it can be used in case of resize | ||
3609 | 418 | child->setWidth(config->preferredWidth); | ||
3610 | 419 | } | ||
3611 | 420 | } | ||
3612 | 421 | dirty = false; | ||
3613 | 422 | } | ||
3614 | 423 | |||
3615 | 424 | /*! | ||
3616 | 425 | * \qmlproperty Component SplitView::handleDelegate | ||
3617 | 426 | * The property holds the delegate to be shown for the column resizing handle. | ||
3618 | 427 | * The delegate is for pure visual, mouse and touch handling is provided by the | ||
3619 | 428 | * SplitView component itself. The component provides a context property called | ||
3620 | 429 | * \e handle which embeds the visuals. This can be used to anchor the visuals | ||
3621 | 430 | * to the resize handle. The thickness of the handle is driven by the \l spacing | ||
3622 | 431 | * property. | ||
3623 | 432 | * \code | ||
3624 | 433 | * import QtQuick 2.4 | ||
3625 | 434 | * import Ubuntu.Components 1.3 | ||
3626 | 435 | * import Ubuntu.Components.Labs 1.0 | ||
3627 | 436 | * | ||
3628 | 437 | * MainView { | ||
3629 | 438 | * id: main | ||
3630 | 439 | * width: units.gu(300) | ||
3631 | 440 | * height: units.gu(80) | ||
3632 | 441 | * | ||
3633 | 442 | * SplitView { | ||
3634 | 443 | * anchors.fill: parent | ||
3635 | 444 | * handleDelegate: Rectangle { | ||
3636 | 445 | * anchors { | ||
3637 | 446 | * fill: parent | ||
3638 | 447 | * leftMargin: units.dp(2) | ||
3639 | 448 | * rightMargin: units.dp(2) | ||
3640 | 449 | * topMargin: handle.height / 2 - units.gu(3) | ||
3641 | 450 | * bottomMargin: handle.height / 2 - units.gu(3) | ||
3642 | 451 | * } | ||
3643 | 452 | * color: UbuntuColors.graphite | ||
3644 | 453 | * scale: handle.containsMouse || handle.pressed ? 1.6 : 1.0 | ||
3645 | 454 | * Behavior on scale { UbuntuNumberAnimation {} } | ||
3646 | 455 | * } | ||
3647 | 456 | * layouts: [ | ||
3648 | 457 | * SplitViewLayout { | ||
3649 | 458 | * when: main.width < units.gu(80) | ||
3650 | 459 | * ViewColumn { | ||
3651 | 460 | * fillWidth: true | ||
3652 | 461 | * } | ||
3653 | 462 | * }, | ||
3654 | 463 | * SplitViewLayout { | ||
3655 | 464 | * when: main.width >= units.gu(80) | ||
3656 | 465 | * ViewColumn { | ||
3657 | 466 | * minimumWidth: units.gu(30) | ||
3658 | 467 | * maximumWidth: units.gu(100) | ||
3659 | 468 | * preferredWidth: units.gu(40) | ||
3660 | 469 | * } | ||
3661 | 470 | * ViewColumn { | ||
3662 | 471 | * minimumWidth: units.gu(40) | ||
3663 | 472 | * fillWidth: true | ||
3664 | 473 | * } | ||
3665 | 474 | * } | ||
3666 | 475 | * ] | ||
3667 | 476 | * } | ||
3668 | 477 | * | ||
3669 | 478 | * Page { | ||
3670 | 479 | * id: column1 | ||
3671 | 480 | * height: parent.height | ||
3672 | 481 | * } | ||
3673 | 482 | * Page { | ||
3674 | 483 | * id: column2 | ||
3675 | 484 | * height: parent.height | ||
3676 | 485 | * } | ||
3677 | 486 | * } | ||
3678 | 487 | * \endcode | ||
3679 | 488 | */ | ||
3680 | 489 | |||
3681 | 490 | SplitView::SplitView(QQuickItem *parent) | ||
3682 | 491 | : QQuickBasePositioner(Horizontal, parent) | ||
3683 | 492 | , d_ptr(new SplitViewPrivate(this)) | ||
3684 | 493 | { | ||
3685 | 494 | Q_D(SplitView); | ||
3686 | 495 | d->init(); | ||
3687 | 496 | } | ||
3688 | 497 | |||
3689 | 498 | SplitView::SplitView(SplitViewPrivate &dd, QQuickItem *parent) | ||
3690 | 499 | : QQuickBasePositioner(Vertical, parent) | ||
3691 | 500 | , d_ptr(&dd) | ||
3692 | 501 | { | ||
3693 | 502 | Q_D(SplitView); | ||
3694 | 503 | d->init(); | ||
3695 | 504 | } | ||
3696 | 505 | |||
3697 | 506 | SplitView::~SplitView() | ||
3698 | 507 | { | ||
3699 | 508 | Q_D(SplitView); | ||
3700 | 509 | delete d; | ||
3701 | 510 | } | ||
3702 | 511 | |||
3703 | 512 | void SplitViewPrivate::init() | ||
3704 | 513 | { | ||
3705 | 514 | Q_Q(SplitView); | ||
3706 | 515 | auto spacingHandle = [q]() { | ||
3707 | 516 | q->setSpacing2(UCUnits::instance(q)->dp(DEFAULT_SPACING_DP), false); | ||
3708 | 517 | }; | ||
3709 | 518 | defaultSpacing = new QMetaObject::Connection; | ||
3710 | 519 | *defaultSpacing = QObject::connect(UCUnits::instance(q), &UCUnits::gridUnitChanged, spacingHandle); | ||
3711 | 520 | |||
3712 | 521 | // connect the spacingChanged signals | ||
3713 | 522 | QObject::connect(q, SIGNAL(spacingChanged()), q, SIGNAL(spacingChanged2())); | ||
3714 | 523 | |||
3715 | 524 | // set the defaults | ||
3716 | 525 | q->setSpacing2(UCUnits::instance(q)->dp(DEFAULT_SPACING_DP), false); | ||
3717 | 526 | } | ||
3718 | 527 | |||
3719 | 528 | void SplitView::doPositioning(QSizeF *contentSize) | ||
3720 | 529 | { | ||
3721 | 530 | // Inspired from QtQuick QQuickRow code | ||
3722 | 531 | // FIXME: revisit the code once we move to Qt 5.6 as there were more properties added to positioner | ||
3723 | 532 | |||
3724 | 533 | // calculate the layout before we go into the positioning | ||
3725 | 534 | d_func()->recalculateWidths(SplitViewPrivate::RecalculateAll); | ||
3726 | 535 | |||
3727 | 536 | //Precondition: All items in the positioned list have a valid item pointer and should be positioned | ||
3728 | 537 | QQuickItemPrivate *d = QQuickItemPrivate::get(this); | ||
3729 | 538 | qreal hoffset = 0; | ||
3730 | 539 | |||
3731 | 540 | QList<qreal> hoffsets; | ||
3732 | 541 | for (int ii = 0; ii < positionedItems.count(); ++ii) { | ||
3733 | 542 | PositionedItem &child = positionedItems[ii]; | ||
3734 | 543 | |||
3735 | 544 | if (!d->effectiveLayoutMirror) { | ||
3736 | 545 | positionItemX(hoffset, &child); | ||
3737 | 546 | } else { | ||
3738 | 547 | hoffsets << hoffset; | ||
3739 | 548 | } | ||
3740 | 549 | |||
3741 | 550 | contentSize->setHeight(qMax(contentSize->height(), child.item->height())); | ||
3742 | 551 | |||
3743 | 552 | hoffset += child.item->width(); | ||
3744 | 553 | hoffset += spacing(); | ||
3745 | 554 | } | ||
3746 | 555 | |||
3747 | 556 | if (hoffset != 0) { //If we positioned any items, undo the extra spacing from the last item | ||
3748 | 557 | hoffset -= spacing(); | ||
3749 | 558 | } | ||
3750 | 559 | contentSize->setWidth(hoffset); | ||
3751 | 560 | |||
3752 | 561 | if (!d->effectiveLayoutMirror) { | ||
3753 | 562 | return; | ||
3754 | 563 | } | ||
3755 | 564 | |||
3756 | 565 | //Right to Left layout | ||
3757 | 566 | qreal end = 0; | ||
3758 | 567 | if (!widthValid()) { | ||
3759 | 568 | end = contentSize->width(); | ||
3760 | 569 | } else { | ||
3761 | 570 | end = width(); | ||
3762 | 571 | } | ||
3763 | 572 | |||
3764 | 573 | int acc = 0; | ||
3765 | 574 | for (int ii = 0; ii < positionedItems.count(); ++ii) { | ||
3766 | 575 | PositionedItem &child = positionedItems[ii]; | ||
3767 | 576 | hoffset = end - hoffsets[acc++] - child.item->width(); | ||
3768 | 577 | positionItemX(hoffset, &child); | ||
3769 | 578 | } | ||
3770 | 579 | } | ||
3771 | 580 | |||
3772 | 581 | void SplitView::reportConflictingAnchors() | ||
3773 | 582 | { | ||
3774 | 583 | // Inspired from QtQuick QQuickColumn code | ||
3775 | 584 | bool anchorConflict = false; | ||
3776 | 585 | for (int ii = 0; ii < positionedItems.count(); ++ii) { | ||
3777 | 586 | const PositionedItem &child = positionedItems.at(ii); | ||
3778 | 587 | if (child.item) { | ||
3779 | 588 | QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors; | ||
3780 | 589 | if (anchors) { | ||
3781 | 590 | // can we patch out the anchors (Page?) | ||
3782 | 591 | if (qobject_cast<UCPageTreeNode*>(child.item)) { | ||
3783 | 592 | // unset left anchor | ||
3784 | 593 | anchors->resetLeft(); | ||
3785 | 594 | } | ||
3786 | 595 | QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors(); | ||
3787 | 596 | if (usedAnchors & QQuickAnchors::LeftAnchor || | ||
3788 | 597 | usedAnchors & QQuickAnchors::RightAnchor || | ||
3789 | 598 | usedAnchors & QQuickAnchors::HCenterAnchor || | ||
3790 | 599 | anchors->fill() || anchors->centerIn()) { | ||
3791 | 600 | anchorConflict = true; | ||
3792 | 601 | break; | ||
3793 | 602 | } | ||
3794 | 603 | } | ||
3795 | 604 | } | ||
3796 | 605 | } | ||
3797 | 606 | if (anchorConflict) { | ||
3798 | 607 | qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside SplitView." | ||
3799 | 608 | << " SplitView will not function."; | ||
3800 | 609 | } | ||
3801 | 610 | } | ||
3802 | 611 | |||
3803 | 612 | void SplitView::componentComplete() | ||
3804 | 613 | { | ||
3805 | 614 | Q_D(SplitView); | ||
3806 | 615 | d->changeLayout(); | ||
3807 | 616 | QQuickBasePositioner::componentComplete(); | ||
3808 | 617 | } | ||
3809 | 618 | |||
3810 | 619 | void SplitView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) | ||
3811 | 620 | { | ||
3812 | 621 | QQuickBasePositioner::geometryChanged(newGeometry, oldGeometry); | ||
3813 | 622 | // if we have fillWidths, recalculate those! | ||
3814 | 623 | // call this on horizontal resize, vertical one will do its job | ||
3815 | 624 | if (newGeometry.width() != oldGeometry.width()) { | ||
3816 | 625 | Q_D(SplitView); | ||
3817 | 626 | d->recalculateWidths(SplitViewPrivate::CalculateFillWidth); | ||
3818 | 627 | } | ||
3819 | 628 | } | ||
3820 | 629 | |||
3821 | 630 | void SplitView::itemChange(ItemChange change, const ItemChangeData &data) | ||
3822 | 631 | { | ||
3823 | 632 | QQuickBasePositioner::itemChange(change, data); | ||
3824 | 633 | // we must exclude Repeater | ||
3825 | 634 | switch (change) { | ||
3826 | 635 | case ItemChildAddedChange: | ||
3827 | 636 | if (data.item && !data.item->inherits("QQuickRepeater")) { | ||
3828 | 637 | // attach properties and configure | ||
3829 | 638 | SplitViewAttached *attached = static_cast<SplitViewAttached*>( | ||
3830 | 639 | qmlAttachedPropertiesObject<SplitView>(data.item, true)); | ||
3831 | 640 | |||
3832 | 641 | Q_D(SplitView); | ||
3833 | 642 | SplitViewAttachedPrivate::get(attached)->configure(this, d->viewCount++); | ||
3834 | 643 | |||
3835 | 644 | // attach the split handler to it | ||
3836 | 645 | SplitViewHandler *handler = new SplitViewHandler(data.item); | ||
3837 | 646 | handler->connectToView(this); | ||
3838 | 647 | } | ||
3839 | 648 | break; | ||
3840 | 649 | case ItemChildRemovedChange: | ||
3841 | 650 | if (data.item && !data.item->inherits("QQuickRepeater")) { | ||
3842 | 651 | Q_D(SplitView); | ||
3843 | 652 | d->viewCount--; | ||
3844 | 653 | } | ||
3845 | 654 | break; | ||
3846 | 655 | default: // ommit the rest | ||
3847 | 656 | break; | ||
3848 | 657 | } | ||
3849 | 658 | } | ||
3850 | 659 | |||
3851 | 660 | /****************************************************************** | ||
3852 | 661 | * properties | ||
3853 | 662 | */ | ||
3854 | 663 | |||
3855 | 664 | void SplitViewPrivate::setHandle(QQmlComponent *delegate) | ||
3856 | 665 | { | ||
3857 | 666 | if (handleDelegate == delegate) { | ||
3858 | 667 | return; | ||
3859 | 668 | } | ||
3860 | 669 | handleDelegate = delegate; | ||
3861 | 670 | Q_EMIT q_func()->handleDelegateChanged(); | ||
3862 | 671 | } | ||
3863 | 672 | |||
3864 | 673 | UT_NAMESPACE_END | ||
3865 | 674 | |||
3866 | 675 | #include "moc_splitview_p.cpp" | ||
3867 | 0 | 676 | ||
3868 | === added file 'src/Ubuntu/UbuntuToolkit/splitview_p.h' | |||
3869 | --- src/Ubuntu/UbuntuToolkit/splitview_p.h 1970-01-01 00:00:00 +0000 | |||
3870 | +++ src/Ubuntu/UbuntuToolkit/splitview_p.h 2016-08-31 08:57:26 +0000 | |||
3871 | @@ -0,0 +1,160 @@ | |||
3872 | 1 | /* | ||
3873 | 2 | * Copyright 2016 Canonical Ltd. | ||
3874 | 3 | * | ||
3875 | 4 | * This program is free software; you can redistribute it and/or modify | ||
3876 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
3877 | 6 | * the Free Software Foundation; version 3. | ||
3878 | 7 | * | ||
3879 | 8 | * This program is distributed in the hope that it will be useful, | ||
3880 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3881 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3882 | 11 | * GNU Lesser General Public License for more details. | ||
3883 | 12 | * | ||
3884 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
3885 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3886 | 15 | * | ||
3887 | 16 | * Author: Zsombor Egri <zsombor.egri@canonical.com> | ||
3888 | 17 | */ | ||
3889 | 18 | |||
3890 | 19 | #ifndef SPLITVIEW_P_H | ||
3891 | 20 | #define SPLITVIEW_P_H | ||
3892 | 21 | |||
3893 | 22 | #include <QtQuick/private/qquickpositioners_p.h> | ||
3894 | 23 | |||
3895 | 24 | #include "ubuntutoolkitglobal.h" | ||
3896 | 25 | |||
3897 | 26 | UT_NAMESPACE_BEGIN | ||
3898 | 27 | |||
3899 | 28 | class ViewColumnPrivate; | ||
3900 | 29 | class ViewColumn : public QObject, public QQmlParserStatus | ||
3901 | 30 | { | ||
3902 | 31 | Q_OBJECT | ||
3903 | 32 | Q_INTERFACES(QQmlParserStatus) | ||
3904 | 33 | Q_PRIVATE_PROPERTY(ViewColumn::d_func(), bool fillWidth MEMBER fillWidth WRITE setFillWidth NOTIFY fillWidthChanged) | ||
3905 | 34 | Q_PRIVATE_PROPERTY(ViewColumn::d_func(), qreal minimumWidth MEMBER minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged) | ||
3906 | 35 | Q_PRIVATE_PROPERTY(ViewColumn::d_func(), qreal maximumWidth MEMBER maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged) | ||
3907 | 36 | Q_PRIVATE_PROPERTY(ViewColumn::d_func(), qreal preferredWidth MEMBER preferredWidth WRITE setPreferredWidth NOTIFY preferredWidthChanged) | ||
3908 | 37 | public: | ||
3909 | 38 | explicit ViewColumn(QObject *parent = 0); | ||
3910 | 39 | |||
3911 | 40 | bool resize(qreal delta); | ||
3912 | 41 | |||
3913 | 42 | Q_SIGNALS: | ||
3914 | 43 | void minimumWidthChanged(); | ||
3915 | 44 | void maximumWidthChanged(); | ||
3916 | 45 | void preferredWidthChanged(); | ||
3917 | 46 | void fillWidthChanged(); | ||
3918 | 47 | |||
3919 | 48 | protected: | ||
3920 | 49 | // from QQmlParserStatus | ||
3921 | 50 | void classBegin() override {} | ||
3922 | 51 | void componentComplete() override; | ||
3923 | 52 | private: | ||
3924 | 53 | Q_DECLARE_PRIVATE(ViewColumn) | ||
3925 | 54 | }; | ||
3926 | 55 | |||
3927 | 56 | class SplitViewLayoutPrivate; | ||
3928 | 57 | class SplitViewLayout : public QObject | ||
3929 | 58 | { | ||
3930 | 59 | Q_OBJECT | ||
3931 | 60 | |||
3932 | 61 | Q_PRIVATE_PROPERTY(SplitViewLayout::d_func(), bool when MEMBER when NOTIFY whenChanged) | ||
3933 | 62 | #ifdef Q_QDOC | ||
3934 | 63 | Q_PRIVATE_PROPERTY(SplitViewLayout::d_func(), QQmlListProperty<ViewColumn> columns READ columns NOTIFY columnsChanged DESIGNABLE false) | ||
3935 | 64 | #else | ||
3936 | 65 | Q_PRIVATE_PROPERTY(SplitViewLayout::d_func(), QQmlListProperty<UT_PREPEND_NAMESPACE(ViewColumn)> columns READ columns NOTIFY columnsChanged DESIGNABLE false) | ||
3937 | 66 | #endif | ||
3938 | 67 | Q_CLASSINFO("DefaultProperty", "columns") | ||
3939 | 68 | public: | ||
3940 | 69 | explicit SplitViewLayout(QObject *parent = 0); | ||
3941 | 70 | |||
3942 | 71 | Q_SIGNALS: | ||
3943 | 72 | void whenChanged(); | ||
3944 | 73 | void columnsChanged(); | ||
3945 | 74 | |||
3946 | 75 | private: | ||
3947 | 76 | Q_DECLARE_PRIVATE(SplitViewLayout) | ||
3948 | 77 | }; | ||
3949 | 78 | |||
3950 | 79 | class SplitView; | ||
3951 | 80 | class SplitViewAttachedPrivate; | ||
3952 | 81 | class SplitViewAttached : public QObject | ||
3953 | 82 | { | ||
3954 | 83 | Q_OBJECT | ||
3955 | 84 | Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), int column READ getColumn NOTIFY columnChanged) | ||
3956 | 85 | #ifdef Q_QDOC | ||
3957 | 86 | Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), SplitView* view READ view) | ||
3958 | 87 | Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), ViewColumn* columnConfig READ config NOTIFY columnChanged) | ||
3959 | 88 | #else | ||
3960 | 89 | Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), UT_PREPEND_NAMESPACE(SplitView*) view READ view) | ||
3961 | 90 | Q_PRIVATE_PROPERTY(SplitViewAttached::d_func(), UT_PREPEND_NAMESPACE(ViewColumn*) columnConfig READ config NOTIFY columnChanged) | ||
3962 | 91 | #endif | ||
3963 | 92 | public: | ||
3964 | 93 | explicit SplitViewAttached(QObject *parent = 0); | ||
3965 | 94 | |||
3966 | 95 | static SplitViewAttached *get(QQuickItem *item); | ||
3967 | 96 | |||
3968 | 97 | void resize(qreal delta); | ||
3969 | 98 | |||
3970 | 99 | Q_SIGNALS: | ||
3971 | 100 | void columnChanged(); | ||
3972 | 101 | |||
3973 | 102 | private: | ||
3974 | 103 | Q_DECLARE_PRIVATE(SplitViewAttached) | ||
3975 | 104 | }; | ||
3976 | 105 | |||
3977 | 106 | class SplitViewPrivate; | ||
3978 | 107 | class SplitView : public QQuickBasePositioner | ||
3979 | 108 | { | ||
3980 | 109 | Q_OBJECT | ||
3981 | 110 | #ifdef Q_QDOC | ||
3982 | 111 | Q_PRIVATE_PROPERTY(SplitView::d_func(), QQmlListProperty<SplitViewLayout> layouts READ layouts NOTIFY layoutsChanged DESIGNABLE false) | ||
3983 | 112 | Q_PRIVATE_PROPERTY(SplitView::d_func(), SplitViewLayout *activeLayout READ getActiveLayout NOTIFY activeLayoutChanged) | ||
3984 | 113 | #else | ||
3985 | 114 | Q_PRIVATE_PROPERTY(SplitView::d_func(), QQmlListProperty<UT_PREPEND_NAMESPACE(SplitViewLayout)> layouts READ layouts NOTIFY layoutsChanged DESIGNABLE false) | ||
3986 | 115 | Q_PRIVATE_PROPERTY(SplitView::d_func(), UT_PREPEND_NAMESPACE(SplitViewLayout) *activeLayout READ getActiveLayout NOTIFY activeLayoutChanged) | ||
3987 | 116 | #endif | ||
3988 | 117 | Q_PRIVATE_PROPERTY(SplitView::d_func(), QQmlComponent *handleDelegate MEMBER handleDelegate WRITE setHandle NOTIFY handleDelegateChanged) | ||
3989 | 118 | // overrides | ||
3990 | 119 | Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing2 NOTIFY spacingChanged2) | ||
3991 | 120 | public: | ||
3992 | 121 | explicit SplitView(QQuickItem *parent = 0); | ||
3993 | 122 | |||
3994 | 123 | static UT_PREPEND_NAMESPACE(SplitViewAttached) *qmlAttachedProperties(QObject*); | ||
3995 | 124 | |||
3996 | 125 | Q_SIGNALS: | ||
3997 | 126 | void layoutsChanged(); | ||
3998 | 127 | void activeLayoutChanged(); | ||
3999 | 128 | void handleDelegateChanged(); | ||
4000 | 129 | void spacingChanged2(); | ||
4001 | 130 | |||
4002 | 131 | protected: | ||
4003 | 132 | SplitView(SplitViewPrivate &, QQuickItem *); | ||
4004 | 133 | ~SplitView(); | ||
4005 | 134 | |||
4006 | 135 | // property setters | ||
4007 | 136 | void setSpacing2(qreal spacing, bool reset = true); | ||
4008 | 137 | |||
4009 | 138 | // from QQuickBasePositioner | ||
4010 | 139 | void doPositioning(QSizeF *contentSize) override; | ||
4011 | 140 | void reportConflictingAnchors() override; | ||
4012 | 141 | |||
4013 | 142 | // overrides | ||
4014 | 143 | void componentComplete() override; | ||
4015 | 144 | void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; | ||
4016 | 145 | void itemChange(ItemChange, const ItemChangeData &) override; | ||
4017 | 146 | private: | ||
4018 | 147 | // QQuickBasePositionerPrivate is not an exported API, therefore we cannot derive from it | ||
4019 | 148 | SplitViewPrivate* const d_ptr; | ||
4020 | 149 | Q_DECLARE_PRIVATE_D(d_ptr, SplitView) | ||
4021 | 150 | Q_PRIVATE_SLOT(d_func(), void changeLayout()) | ||
4022 | 151 | }; | ||
4023 | 152 | |||
4024 | 153 | UT_NAMESPACE_END | ||
4025 | 154 | |||
4026 | 155 | QML_DECLARE_TYPE(UT_PREPEND_NAMESPACE(ViewColumn)) | ||
4027 | 156 | QML_DECLARE_TYPE(UT_PREPEND_NAMESPACE(SplitViewLayout)) | ||
4028 | 157 | QML_DECLARE_TYPE(UT_PREPEND_NAMESPACE(SplitView)) | ||
4029 | 158 | QML_DECLARE_TYPEINFO(UT_PREPEND_NAMESPACE(SplitView), QML_HAS_ATTACHED_PROPERTIES) | ||
4030 | 159 | |||
4031 | 160 | #endif // SPLITVIEW_P_H | ||
4032 | 0 | 161 | ||
4033 | === added file 'src/Ubuntu/UbuntuToolkit/splitview_p_p.h' | |||
4034 | --- src/Ubuntu/UbuntuToolkit/splitview_p_p.h 1970-01-01 00:00:00 +0000 | |||
4035 | +++ src/Ubuntu/UbuntuToolkit/splitview_p_p.h 2016-08-31 08:57:26 +0000 | |||
4036 | @@ -0,0 +1,154 @@ | |||
4037 | 1 | /* | ||
4038 | 2 | * Copyright 2016 Canonical Ltd. | ||
4039 | 3 | * | ||
4040 | 4 | * This program is free software; you can redistribute it and/or modify | ||
4041 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
4042 | 6 | * the Free Software Foundation; version 3. | ||
4043 | 7 | * | ||
4044 | 8 | * This program is distributed in the hope that it will be useful, | ||
4045 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
4046 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
4047 | 11 | * GNU Lesser General Public License for more details. | ||
4048 | 12 | * | ||
4049 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
4050 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
4051 | 15 | * | ||
4052 | 16 | * Author: Zsombor Egri <zsombor.egri@canonical.com> | ||
4053 | 17 | */ | ||
4054 | 18 | |||
4055 | 19 | #ifndef SPLITVIEW_P_P_H | ||
4056 | 20 | #define SPLITVIEW_P_P_H | ||
4057 | 21 | |||
4058 | 22 | #include "splitview_p.h" | ||
4059 | 23 | #include <QtCore/private/qobject_p.h> | ||
4060 | 24 | |||
4061 | 25 | UT_NAMESPACE_BEGIN | ||
4062 | 26 | |||
4063 | 27 | class ViewColumnPrivate : public QObjectPrivate | ||
4064 | 28 | { | ||
4065 | 29 | Q_DECLARE_PUBLIC(ViewColumn) | ||
4066 | 30 | |||
4067 | 31 | public: | ||
4068 | 32 | ViewColumnPrivate() {} | ||
4069 | 33 | |||
4070 | 34 | static ViewColumnPrivate *get(ViewColumn *q) | ||
4071 | 35 | { | ||
4072 | 36 | return q ? q->d_func() : nullptr; | ||
4073 | 37 | } | ||
4074 | 38 | |||
4075 | 39 | void setMinimumWidth(qreal width); | ||
4076 | 40 | void setMaximumWidth(qreal width); | ||
4077 | 41 | void setPreferredWidth(qreal width, bool notify = true); | ||
4078 | 42 | void setFillWidth(bool fill); | ||
4079 | 43 | |||
4080 | 44 | void recalculateLayoutContent(); | ||
4081 | 45 | |||
4082 | 46 | qreal minimumWidth{0.0}; | ||
4083 | 47 | qreal maximumWidth{std::numeric_limits<qreal>::max()}; | ||
4084 | 48 | qreal preferredWidth{0.0}; | ||
4085 | 49 | int column{-1}; | ||
4086 | 50 | bool fillWidth{false}; | ||
4087 | 51 | bool resized{false}; | ||
4088 | 52 | bool completed{false}; | ||
4089 | 53 | }; | ||
4090 | 54 | |||
4091 | 55 | class SplitViewLayoutPrivate : public QObjectPrivate | ||
4092 | 56 | { | ||
4093 | 57 | Q_DECLARE_PUBLIC(SplitViewLayout) | ||
4094 | 58 | public: | ||
4095 | 59 | SplitViewLayoutPrivate() {} | ||
4096 | 60 | static SplitViewLayoutPrivate *get(SplitViewLayout *q) | ||
4097 | 61 | { | ||
4098 | 62 | return q->d_func(); | ||
4099 | 63 | } | ||
4100 | 64 | |||
4101 | 65 | QQmlListProperty<UT_PREPEND_NAMESPACE(ViewColumn)> columns(); | ||
4102 | 66 | |||
4103 | 67 | QList<ViewColumn*> columnData; | ||
4104 | 68 | bool when{false}; | ||
4105 | 69 | |||
4106 | 70 | private: | ||
4107 | 71 | static void columns_Append(QQmlListProperty<ViewColumn> *, ViewColumn*); | ||
4108 | 72 | static int columns_Count(QQmlListProperty<ViewColumn> *); | ||
4109 | 73 | static ViewColumn *columns_At(QQmlListProperty<ViewColumn> *, int); | ||
4110 | 74 | static void columns_Clear(QQmlListProperty<ViewColumn> *); | ||
4111 | 75 | }; | ||
4112 | 76 | |||
4113 | 77 | class SplitViewAttachedPrivate : public QObjectPrivate | ||
4114 | 78 | { | ||
4115 | 79 | Q_DECLARE_PUBLIC(SplitViewAttached) | ||
4116 | 80 | public: | ||
4117 | 81 | SplitViewAttachedPrivate() {} | ||
4118 | 82 | |||
4119 | 83 | static SplitViewAttachedPrivate *get(SplitViewAttached *q) | ||
4120 | 84 | { | ||
4121 | 85 | return q->d_func(); | ||
4122 | 86 | } | ||
4123 | 87 | static ViewColumn *getConfig(QQuickItem *attachee); | ||
4124 | 88 | |||
4125 | 89 | UT_PREPEND_NAMESPACE(SplitView*) view() const | ||
4126 | 90 | { | ||
4127 | 91 | return splitView; | ||
4128 | 92 | } | ||
4129 | 93 | int getColumn() const | ||
4130 | 94 | { | ||
4131 | 95 | return column; | ||
4132 | 96 | } | ||
4133 | 97 | void configure(SplitView *view, int column); | ||
4134 | 98 | UT_PREPEND_NAMESPACE(ViewColumn*) config(); | ||
4135 | 99 | |||
4136 | 100 | SplitView *splitView{nullptr}; | ||
4137 | 101 | int column{-1}; | ||
4138 | 102 | }; | ||
4139 | 103 | |||
4140 | 104 | class SplitViewPrivate | ||
4141 | 105 | { | ||
4142 | 106 | SplitView *const q_ptr{nullptr}; | ||
4143 | 107 | Q_DECLARE_PUBLIC(SplitView) | ||
4144 | 108 | |||
4145 | 109 | public: | ||
4146 | 110 | enum RelayoutOperation { | ||
4147 | 111 | SetPreferredSize = 0x01, | ||
4148 | 112 | CalculateFillWidth = 0x02, | ||
4149 | 113 | RecalculateAll = 0xFF | ||
4150 | 114 | }; | ||
4151 | 115 | |||
4152 | 116 | SplitViewPrivate(SplitView *qq); | ||
4153 | 117 | virtual ~SplitViewPrivate(); | ||
4154 | 118 | void init(); | ||
4155 | 119 | |||
4156 | 120 | static SplitViewPrivate *get(SplitView *q) | ||
4157 | 121 | { | ||
4158 | 122 | return q->d_func(); | ||
4159 | 123 | } | ||
4160 | 124 | |||
4161 | 125 | QQmlListProperty<QObject> data(); | ||
4162 | 126 | QQmlListProperty<UT_PREPEND_NAMESPACE(SplitViewLayout)> layouts(); | ||
4163 | 127 | UT_PREPEND_NAMESPACE(SplitViewLayout) *getActiveLayout(); | ||
4164 | 128 | |||
4165 | 129 | void updateLayout(); | ||
4166 | 130 | void recalculateWidths(RelayoutOperation operation); | ||
4167 | 131 | void setHandle(QQmlComponent *delegate); | ||
4168 | 132 | |||
4169 | 133 | // private slots | ||
4170 | 134 | void changeLayout(); | ||
4171 | 135 | |||
4172 | 136 | // members | ||
4173 | 137 | QList<SplitViewLayout*> columnLatouts; | ||
4174 | 138 | SplitViewLayout* activeLayout{nullptr}; | ||
4175 | 139 | QQmlComponent *handleDelegate{nullptr}; | ||
4176 | 140 | QMetaObject::Connection *defaultSpacing{nullptr}; | ||
4177 | 141 | int viewCount{0}; | ||
4178 | 142 | bool dirty{false}; | ||
4179 | 143 | |||
4180 | 144 | private: | ||
4181 | 145 | static void layout_Append(QQmlListProperty<SplitViewLayout> *, SplitViewLayout*); | ||
4182 | 146 | static int layout_Count(QQmlListProperty<SplitViewLayout> *); | ||
4183 | 147 | static SplitViewLayout *layout_At(QQmlListProperty<SplitViewLayout> *, int); | ||
4184 | 148 | static void layout_Clear(QQmlListProperty<SplitViewLayout> *); | ||
4185 | 149 | }; | ||
4186 | 150 | |||
4187 | 151 | UT_NAMESPACE_END | ||
4188 | 152 | |||
4189 | 153 | #endif // SPLITVIEW_P_P_H | ||
4190 | 154 | |||
4191 | 0 | 155 | ||
4192 | === added file 'src/Ubuntu/UbuntuToolkit/splitviewlayout.cpp' | |||
4193 | --- src/Ubuntu/UbuntuToolkit/splitviewlayout.cpp 1970-01-01 00:00:00 +0000 | |||
4194 | +++ src/Ubuntu/UbuntuToolkit/splitviewlayout.cpp 2016-08-31 08:57:26 +0000 | |||
4195 | @@ -0,0 +1,252 @@ | |||
4196 | 1 | /* Copyright 2016 Canonical Ltd. | ||
4197 | 2 | * | ||
4198 | 3 | * This program is free software; you can redistribute it and/or modify | ||
4199 | 4 | * it under the terms of the GNU Lesser General Public License as published by | ||
4200 | 5 | * the Free Software Foundation; version 3. | ||
4201 | 6 | * | ||
4202 | 7 | * This program is distributed in the hope that it will be useful, | ||
4203 | 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
4204 | 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
4205 | 10 | * GNU Lesser General Public License for more details. | ||
4206 | 11 | * | ||
4207 | 12 | * You should have received a copy of the GNU Lesser General Public License | ||
4208 | 13 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
4209 | 14 | * | ||
4210 | 15 | * Author: Zsombor Egri <zsombor.egri@canonical.com> | ||
4211 | 16 | */ | ||
4212 | 17 | |||
4213 | 18 | #include <QtQuick/private/qquickitem_p.h> | ||
4214 | 19 | #include <QtQuick/private/qquickanchors_p.h> | ||
4215 | 20 | #include <QtQml/QQmlInfo> | ||
4216 | 21 | |||
4217 | 22 | #include "splitview_p.h" | ||
4218 | 23 | #include "splitview_p_p.h" | ||
4219 | 24 | #include "ucmathutils_p.h" | ||
4220 | 25 | |||
4221 | 26 | UT_NAMESPACE_BEGIN | ||
4222 | 27 | |||
4223 | 28 | /****************************************************************************** | ||
4224 | 29 | * ViewColumn configuration object | ||
4225 | 30 | */ | ||
4226 | 31 | /*! | ||
4227 | 32 | * \qmltype ViewColumn | ||
4228 | 33 | * \inmodule Ubuntu.Components.Labs | ||
4229 | 34 | * \ingroup ubuntu-labs | ||
4230 | 35 | * \brief View column metrics configuration for SplitView. | ||
4231 | 36 | * | ||
4232 | 37 | * The component provides width metrics configuration for SplitView layout | ||
4233 | 38 | * columns. The values are applied on columns by an active SplitViewLayout. | ||
4234 | 39 | * On resizing, the values are preserved for the entire lifetime of the | ||
4235 | 40 | * component, even when the active layout is changed into an other one. | ||
4236 | 41 | * When changed back, the previous values will be used. | ||
4237 | 42 | */ | ||
4238 | 43 | ViewColumn::ViewColumn(QObject *parent) | ||
4239 | 44 | : QObject(*(new ViewColumnPrivate), parent) | ||
4240 | 45 | { | ||
4241 | 46 | } | ||
4242 | 47 | |||
4243 | 48 | void ViewColumn::componentComplete() | ||
4244 | 49 | { | ||
4245 | 50 | // check preferredWidth, its value may need fixing | ||
4246 | 51 | Q_D(ViewColumn); | ||
4247 | 52 | d->setPreferredWidth(d->preferredWidth); | ||
4248 | 53 | d->completed = true; | ||
4249 | 54 | } | ||
4250 | 55 | |||
4251 | 56 | void ViewColumnPrivate::recalculateLayoutContent() | ||
4252 | 57 | { | ||
4253 | 58 | SplitViewLayout *layout = qobject_cast<SplitViewLayout*>(parent); | ||
4254 | 59 | if (!layout) { | ||
4255 | 60 | qFatal("ViewColumn declared outside of SplitViewLayout"); | ||
4256 | 61 | } | ||
4257 | 62 | SplitView *view = qobject_cast<SplitView*>(SplitViewLayoutPrivate::get(layout)->parent); | ||
4258 | 63 | if (!view) { | ||
4259 | 64 | qFatal("SplitViewLayout not used in any SplitView"); | ||
4260 | 65 | } | ||
4261 | 66 | |||
4262 | 67 | SplitViewPrivate *dView = SplitViewPrivate::get(view); | ||
4263 | 68 | if (dView->activeLayout == layout) { | ||
4264 | 69 | dView->recalculateWidths(SplitViewPrivate::RecalculateAll); | ||
4265 | 70 | } | ||
4266 | 71 | } | ||
4267 | 72 | |||
4268 | 73 | /*! | ||
4269 | 74 | * \qmlproperty real ViewColumn::minimumWidth | ||
4270 | 75 | * Specifies the minimum width of the column. The number must be a positive value | ||
4271 | 76 | * and less or equal than the maximumWidth value. | ||
4272 | 77 | */ | ||
4273 | 78 | void ViewColumnPrivate::setMinimumWidth(qreal width) | ||
4274 | 79 | { | ||
4275 | 80 | if (qFuzzyCompare(minimumWidth, width)) { | ||
4276 | 81 | return; | ||
4277 | 82 | } | ||
4278 | 83 | if (width < 0.0) { | ||
4279 | 84 | qmlInfo(q_func()) << "minimumWidth cannot be a negative value"; | ||
4280 | 85 | return; | ||
4281 | 86 | } | ||
4282 | 87 | if (width > maximumWidth) { | ||
4283 | 88 | qmlInfo(q_func()) << "minimumWidth is greater than maximumWidth"; | ||
4284 | 89 | return; | ||
4285 | 90 | } | ||
4286 | 91 | minimumWidth = width; | ||
4287 | 92 | Q_EMIT q_func()->minimumWidthChanged(); | ||
4288 | 93 | // clamp preferredWidth if needed | ||
4289 | 94 | setPreferredWidth(preferredWidth); | ||
4290 | 95 | recalculateLayoutContent(); | ||
4291 | 96 | } | ||
4292 | 97 | |||
4293 | 98 | /*! | ||
4294 | 99 | * \qmlproperty real ViewColumn::maximumWidth | ||
4295 | 100 | * Specifies the maximum width of the column. The number must be a positive value | ||
4296 | 101 | * and bigger than the minimumWidth value. | ||
4297 | 102 | */ | ||
4298 | 103 | void ViewColumnPrivate::setMaximumWidth(qreal width) | ||
4299 | 104 | { | ||
4300 | 105 | if (qFuzzyCompare(maximumWidth, width)) { | ||
4301 | 106 | return; | ||
4302 | 107 | } | ||
4303 | 108 | if (width < 0.0) { | ||
4304 | 109 | qmlInfo(q_func()) << "maximumWidth cannot be a negative value"; | ||
4305 | 110 | return; | ||
4306 | 111 | } | ||
4307 | 112 | if (width < minimumWidth) { | ||
4308 | 113 | qmlInfo(q_func()) << "maximumWidth is smaller than minimumWidth"; | ||
4309 | 114 | return; | ||
4310 | 115 | } | ||
4311 | 116 | maximumWidth = width; | ||
4312 | 117 | Q_EMIT q_func()->maximumWidthChanged(); | ||
4313 | 118 | setPreferredWidth(preferredWidth); | ||
4314 | 119 | recalculateLayoutContent(); | ||
4315 | 120 | } | ||
4316 | 121 | |||
4317 | 122 | /*! | ||
4318 | 123 | * \qmlproperty real ViewColumn::preferredWidth | ||
4319 | 124 | * The property holds the preferred width of the column. The value must be situated | ||
4320 | 125 | * in between minimumWidth and maximumWidth. In case fillWidth is set, the value will | ||
4321 | 126 | * hold the actual width of the column, but setting its value will not affect the | ||
4322 | 127 | * width of the column. | ||
4323 | 128 | */ | ||
4324 | 129 | void ViewColumnPrivate::setPreferredWidth(qreal width, bool notify) | ||
4325 | 130 | { | ||
4326 | 131 | // clamp | ||
4327 | 132 | width = UCMathUtils::clamp(width, minimumWidth, maximumWidth); | ||
4328 | 133 | if (qFuzzyCompare(preferredWidth, width)) { | ||
4329 | 134 | return; | ||
4330 | 135 | } | ||
4331 | 136 | preferredWidth = width; | ||
4332 | 137 | if (notify) { | ||
4333 | 138 | Q_EMIT q_func()->preferredWidthChanged(); | ||
4334 | 139 | recalculateLayoutContent(); | ||
4335 | 140 | } | ||
4336 | 141 | } | ||
4337 | 142 | |||
4338 | 143 | /*! | ||
4339 | 144 | * \qmlproperty bool ViewColumn::fillWidth | ||
4340 | 145 | * If set, the column width will take the space available after all the other | ||
4341 | 146 | * columns with non-fill width are configured. This means that if there is more | ||
4342 | 147 | * than one column configured to fill width, the reminder width is split evenly | ||
4343 | 148 | * between these columns. If all columns are configured to fill width, the colum | ||
4344 | 149 | * widths will be split evenly between all the columns. | ||
4345 | 150 | * \note When a column configured with fillWidth is resized, the properties will | ||
4346 | 151 | * not be altered, but the fillWidth wioll no longer be taken into account. Instead, | ||
4347 | 152 | * the preferredWidth will drive the width of that column from that point on. | ||
4348 | 153 | */ | ||
4349 | 154 | void ViewColumnPrivate::setFillWidth(bool fill) | ||
4350 | 155 | { | ||
4351 | 156 | if (fill == fillWidth) { | ||
4352 | 157 | return; | ||
4353 | 158 | } | ||
4354 | 159 | fillWidth = fill; | ||
4355 | 160 | Q_EMIT q_func()->fillWidthChanged(); | ||
4356 | 161 | recalculateLayoutContent(); | ||
4357 | 162 | } | ||
4358 | 163 | |||
4359 | 164 | bool ViewColumn::resize(qreal delta) | ||
4360 | 165 | { | ||
4361 | 166 | Q_D(ViewColumn); | ||
4362 | 167 | // apply limits | ||
4363 | 168 | qreal newWidth = d->preferredWidth + delta; | ||
4364 | 169 | // clamp | ||
4365 | 170 | newWidth = UCMathUtils::clamp(newWidth, d->minimumWidth, d->maximumWidth); | ||
4366 | 171 | if (newWidth != d->preferredWidth) { | ||
4367 | 172 | d->resized = true; | ||
4368 | 173 | d->setPreferredWidth(newWidth); | ||
4369 | 174 | return true; | ||
4370 | 175 | } | ||
4371 | 176 | return false; | ||
4372 | 177 | } | ||
4373 | 178 | |||
4374 | 179 | /****************************************************************************** | ||
4375 | 180 | * SplitViewLayout layouts configuration | ||
4376 | 181 | */ | ||
4377 | 182 | /*! | ||
4378 | 183 | * \qmltype SplitViewLayout | ||
4379 | 184 | * \inmodule Ubuntu.Components.Labs | ||
4380 | 185 | * \ingroup ubuntu-labs | ||
4381 | 186 | * \brief Layout configuration for SplitView. | ||
4382 | 187 | * | ||
4383 | 188 | * SplitViewLayout defines a layout configuration and the condition when the layout is | ||
4384 | 189 | * expected to be applied. In case multiple layout conditions evaluate to true, the first | ||
4385 | 190 | * one in the list will be activated. | ||
4386 | 191 | */ | ||
4387 | 192 | SplitViewLayout::SplitViewLayout(QObject *parent) | ||
4388 | 193 | : QObject(*(new SplitViewLayoutPrivate), parent) | ||
4389 | 194 | { | ||
4390 | 195 | } | ||
4391 | 196 | |||
4392 | 197 | void SplitViewLayoutPrivate::columns_Append(QQmlListProperty<ViewColumn> *list, ViewColumn* data) | ||
4393 | 198 | { | ||
4394 | 199 | SplitViewLayout *layout = static_cast<SplitViewLayout*>(list->object); | ||
4395 | 200 | SplitViewLayoutPrivate *d = SplitViewLayoutPrivate::get(layout); | ||
4396 | 201 | ViewColumnPrivate::get(data)->column = d->columnData.size(); | ||
4397 | 202 | // make sure ViewColumn is parented to the layout definition | ||
4398 | 203 | data->setParent(layout); | ||
4399 | 204 | d->columnData.append(data); | ||
4400 | 205 | Q_EMIT layout->columnsChanged(); | ||
4401 | 206 | } | ||
4402 | 207 | int SplitViewLayoutPrivate::columns_Count(QQmlListProperty<ViewColumn> *list) | ||
4403 | 208 | { | ||
4404 | 209 | SplitViewLayout *layout = static_cast<SplitViewLayout*>(list->object); | ||
4405 | 210 | SplitViewLayoutPrivate *d = SplitViewLayoutPrivate::get(layout); | ||
4406 | 211 | return d->columnData.size(); | ||
4407 | 212 | } | ||
4408 | 213 | ViewColumn *SplitViewLayoutPrivate::columns_At(QQmlListProperty<ViewColumn> *list, int index) | ||
4409 | 214 | { | ||
4410 | 215 | SplitViewLayout *layout = static_cast<SplitViewLayout*>(list->object); | ||
4411 | 216 | SplitViewLayoutPrivate *d = SplitViewLayoutPrivate::get(layout); | ||
4412 | 217 | return d->columnData.at(index); | ||
4413 | 218 | } | ||
4414 | 219 | void SplitViewLayoutPrivate::columns_Clear(QQmlListProperty<ViewColumn> *list) | ||
4415 | 220 | { | ||
4416 | 221 | SplitViewLayout *layout = static_cast<SplitViewLayout*>(list->object); | ||
4417 | 222 | SplitViewLayoutPrivate *d = SplitViewLayoutPrivate::get(layout); | ||
4418 | 223 | qDeleteAll(d->columnData); | ||
4419 | 224 | d->columnData.clear(); | ||
4420 | 225 | Q_EMIT layout->columnsChanged(); | ||
4421 | 226 | } | ||
4422 | 227 | |||
4423 | 228 | /*! | ||
4424 | 229 | * \qmlproperty list<ViewColumn> SplitViewLayout::columns | ||
4425 | 230 | * \default | ||
4426 | 231 | * The property holds the column configurations for the layout. If the view has more | ||
4427 | 232 | * columns than the configuration specifies, the extra columns will be hidden (their | ||
4428 | 233 | * visible property will be set to false!). Also, the hidden column sizes may change, | ||
4429 | 234 | * therefore size-sensitive content must be aware of this. | ||
4430 | 235 | */ | ||
4431 | 236 | QQmlListProperty<UT_PREPEND_NAMESPACE(ViewColumn)> SplitViewLayoutPrivate::columns() | ||
4432 | 237 | { | ||
4433 | 238 | Q_Q(SplitViewLayout); | ||
4434 | 239 | return QQmlListProperty<UT_PREPEND_NAMESPACE(ViewColumn)>(q, &columnData, | ||
4435 | 240 | &columns_Append, | ||
4436 | 241 | &columns_Count, | ||
4437 | 242 | &columns_At, | ||
4438 | 243 | &columns_Clear); | ||
4439 | 244 | } | ||
4440 | 245 | |||
4441 | 246 | /*! | ||
4442 | 247 | * \qmlproperty bool SplitViewLayout::when | ||
4443 | 248 | * Specifies the condition when to apply the layout. Usually holds a binding which | ||
4444 | 249 | * evaluates to true or false to activate the layout. | ||
4445 | 250 | */ | ||
4446 | 251 | |||
4447 | 252 | UT_NAMESPACE_END | ||
4448 | 0 | 253 | ||
4449 | === modified file 'src/Ubuntu/UbuntuToolkit/ubuntutoolkitmodule.cpp' | |||
4450 | --- src/Ubuntu/UbuntuToolkit/ubuntutoolkitmodule.cpp 2016-08-06 00:55:32 +0000 | |||
4451 | +++ src/Ubuntu/UbuntuToolkit/ubuntutoolkitmodule.cpp 2016-08-31 08:57:26 +0000 | |||
4452 | @@ -89,6 +89,13 @@ | |||
4453 | 89 | #include <privates/ucpagewrapper_p.h> | 89 | #include <privates/ucpagewrapper_p.h> |
4454 | 90 | #include <privates/appheaderbase_p.h> | 90 | #include <privates/appheaderbase_p.h> |
4455 | 91 | #include <privates/ucscrollbarutils_p.h> | 91 | #include <privates/ucscrollbarutils_p.h> |
4456 | 92 | #include <actionlist_p.h> | ||
4457 | 93 | #include <exclusivegroup_p.h> | ||
4458 | 94 | #include <menu_p.h> | ||
4459 | 95 | #include <menubar_p.h> | ||
4460 | 96 | #include <menugroup_p.h> | ||
4461 | 97 | |||
4462 | 98 | #include <splitview_p.h> | ||
4463 | 92 | 99 | ||
4464 | 93 | // styles | 100 | // styles |
4465 | 94 | #include <ucbottomedgestyle_p.h> | 101 | #include <ucbottomedgestyle_p.h> |
4466 | @@ -374,6 +381,8 @@ | |||
4467 | 374 | qmlRegisterType<UCPageTreeNode>(uri, 1, 3, "PageTreeNode"); | 381 | qmlRegisterType<UCPageTreeNode>(uri, 1, 3, "PageTreeNode"); |
4468 | 375 | qmlRegisterType<UCPopupContext>(uri, 1, 3, "PopupContext"); | 382 | qmlRegisterType<UCPopupContext>(uri, 1, 3, "PopupContext"); |
4469 | 376 | qmlRegisterType<UCMainViewBase>(uri, 1, 3, "MainViewBase"); | 383 | qmlRegisterType<UCMainViewBase>(uri, 1, 3, "MainViewBase"); |
4470 | 384 | qmlRegisterType<ActionList>(uri, 1, 3, "ActionList"); | ||
4471 | 385 | qmlRegisterType<ExclusiveGroup>(uri, 1, 3, "ExclusiveGroup"); | ||
4472 | 377 | } | 386 | } |
4473 | 378 | 387 | ||
4474 | 379 | void UbuntuToolkitModule::undefineModule() | 388 | void UbuntuToolkitModule::undefineModule() |
4475 | @@ -404,15 +413,20 @@ | |||
4476 | 404 | */ | 413 | */ |
4477 | 405 | void UbuntuLabsModule::initializeModule(QQmlEngine *engine, QQmlExtensionPlugin *plugin) | 414 | void UbuntuLabsModule::initializeModule(QQmlEngine *engine, QQmlExtensionPlugin *plugin) |
4478 | 406 | { | 415 | { |
4479 | 407 | Q_UNUSED(engine); | ||
4480 | 408 | Q_UNUSED(plugin); | 416 | Q_UNUSED(plugin); |
4481 | 417 | |||
4482 | 418 | // qmlplugindump requires that quickutils is initialized. | ||
4483 | 419 | QuickUtils::instance(engine); | ||
4484 | 409 | } | 420 | } |
4485 | 410 | 421 | ||
4486 | 411 | void UbuntuLabsModule::defineModule(const char *uri) | 422 | void UbuntuLabsModule::defineModule(const char *uri) |
4487 | 412 | { | 423 | { |
4491 | 413 | Q_UNUSED(uri); | 424 | qmlRegisterType<SplitView>(uri, 1, 0, "SplitView"); |
4492 | 414 | // a fake component so we can have the module types file created | 425 | qmlRegisterType<SplitViewLayout>(uri, 1, 0, "SplitViewLayout"); |
4493 | 415 | qmlRegisterType<QObject>(uri, 1, 0, "ZiObject"); | 426 | qmlRegisterType<ViewColumn>(uri, 1, 0, "ViewColumn"); |
4494 | 427 | qmlRegisterType<Menu>(uri, 1, 0, "Menu"); | ||
4495 | 428 | qmlRegisterType<MenuBar>(uri, 1, 0, "MenuBar"); | ||
4496 | 429 | qmlRegisterType<MenuGroup>(uri, 1, 0, "MenuGroup"); | ||
4497 | 416 | } | 430 | } |
4498 | 417 | 431 | ||
4499 | 418 | void UbuntuLabsModule::undefineModule() | 432 | void UbuntuLabsModule::undefineModule() |
4500 | 419 | 433 | ||
4501 | === modified file 'src/Ubuntu/UbuntuToolkit/ucaction.cpp' | |||
4502 | --- src/Ubuntu/UbuntuToolkit/ucaction.cpp 2016-07-07 07:21:48 +0000 | |||
4503 | +++ src/Ubuntu/UbuntuToolkit/ucaction.cpp 2016-08-31 08:57:26 +0000 | |||
4504 | @@ -17,6 +17,7 @@ | |||
4505 | 17 | #include "ucaction_p.h" | 17 | #include "ucaction_p.h" |
4506 | 18 | #include "quickutils_p.h" | 18 | #include "quickutils_p.h" |
4507 | 19 | #include "ucactioncontext_p.h" | 19 | #include "ucactioncontext_p.h" |
4508 | 20 | #include "exclusivegroup_p.h" | ||
4509 | 20 | 21 | ||
4510 | 21 | #include <QtDebug> | 22 | #include <QtDebug> |
4511 | 22 | #include <QtQml/QQmlInfo> | 23 | #include <QtQml/QQmlInfo> |
4512 | @@ -149,6 +150,18 @@ | |||
4513 | 149 | * text: "&Call" | 150 | * text: "&Call" |
4514 | 150 | * } | 151 | * } |
4515 | 151 | * \endqml | 152 | * \endqml |
4516 | 153 | * | ||
4517 | 154 | * \section2 Checkable property | ||
4518 | 155 | * Since Ubuntu.Components 1.3 Action supports the checkable/checked properties. | ||
4519 | 156 | * \qml | ||
4520 | 157 | * Button { | ||
4521 | 158 | * action: Action { | ||
4522 | 159 | * checkable: true | ||
4523 | 160 | * checked: false | ||
4524 | 161 | * } | ||
4525 | 162 | * color: action.checked ? UbuntuColor.green : UbuntuColor.red | ||
4526 | 163 | * } | ||
4527 | 164 | * \endqml | ||
4528 | 152 | */ | 165 | */ |
4529 | 153 | 166 | ||
4530 | 154 | /*! | 167 | /*! |
4531 | @@ -160,6 +173,14 @@ | |||
4532 | 160 | */ | 173 | */ |
4533 | 161 | 174 | ||
4534 | 162 | /*! | 175 | /*! |
4535 | 176 | * \qmlsignal Action::toggled(bool value) | ||
4536 | 177 | * Signal called when the action's checked property changes. | ||
4537 | 178 | * \note The toggled signal should be used for checkable actions rather than the | ||
4538 | 179 | * triggered signal. | ||
4539 | 180 | * \sa Action::checkable, Action::checked, ExclusiveGroup | ||
4540 | 181 | */ | ||
4541 | 182 | |||
4542 | 183 | /*! | ||
4543 | 163 | * \qmlproperty string Action::description | 184 | * \qmlproperty string Action::description |
4544 | 164 | * User visible secondary description for the action. Description is more verbose | 185 | * User visible secondary description for the action. Description is more verbose |
4545 | 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. |
4546 | @@ -250,51 +271,17 @@ | |||
4547 | 250 | * \endqml | 271 | * \endqml |
4548 | 251 | */ | 272 | */ |
4549 | 252 | 273 | ||
4550 | 253 | /*! | ||
4551 | 254 | * \qmlproperty enum Action::parameterType | ||
4552 | 255 | * Type of the parameter passed to \l trigger and \l triggered. | ||
4553 | 256 | * Type is an enumeration: | ||
4554 | 257 | * \list | ||
4555 | 258 | * \li \b Action.None: No paramater. (default) | ||
4556 | 259 | * \li \b Action.String: String parameter. | ||
4557 | 260 | * \li \b Action.Integer: Integer parameter. | ||
4558 | 261 | * \li \b Action.Bool: Boolean parameter. | ||
4559 | 262 | * \li \b Action.Real: Single precision floating point parameter. | ||
4560 | 263 | * \li \b Action.Object: The parameter is an object. | ||
4561 | 264 | * \endlist | ||
4562 | 265 | * \qml | ||
4563 | 266 | * Action { | ||
4564 | 267 | * id: action | ||
4565 | 268 | * parameterType: Action.String | ||
4566 | 269 | * onTriggered: { | ||
4567 | 270 | * // value arguments now contain strings | ||
4568 | 271 | * console.log(value); | ||
4569 | 272 | * } | ||
4570 | 273 | * Component.onCompleted: action.trigger("Hello World") | ||
4571 | 274 | * } | ||
4572 | 275 | * \endqml | ||
4573 | 276 | */ | ||
4574 | 277 | |||
4575 | 278 | /*! | ||
4576 | 279 | * \qmlproperty bool Action::enabled | ||
4577 | 280 | * If set to false the action can not be triggered. Components visualizing the | ||
4578 | 281 | * action migth either hide the action or make it insensitive. However visibility | ||
4579 | 282 | * can be controlled separately using the \l visible property. | ||
4580 | 283 | */ | ||
4581 | 284 | |||
4582 | 285 | /*! | ||
4583 | 286 | * \qmlproperty bool Action::visible | ||
4584 | 287 | * Specifies whether the action is visible to the user. Defaults to true. | ||
4585 | 288 | */ | ||
4586 | 289 | |||
4587 | 290 | UCAction::UCAction(QObject *parent) | 274 | UCAction::UCAction(QObject *parent) |
4588 | 291 | : QObject(parent) | 275 | : QObject(parent) |
4589 | 276 | , m_exclusiveGroup(Q_NULLPTR) | ||
4590 | 292 | , m_itemHint(Q_NULLPTR) | 277 | , m_itemHint(Q_NULLPTR) |
4591 | 293 | , m_parameterType(None) | 278 | , m_parameterType(None) |
4592 | 294 | , m_factoryIconSource(true) | 279 | , m_factoryIconSource(true) |
4593 | 295 | , m_enabled(true) | 280 | , m_enabled(true) |
4594 | 296 | , m_visible(true) | 281 | , m_visible(true) |
4595 | 297 | , m_published(false) | 282 | , m_published(false) |
4596 | 283 | , m_checkable(false) | ||
4597 | 284 | , m_checked(false) | ||
4598 | 298 | { | 285 | { |
4599 | 299 | generateName(); | 286 | generateName(); |
4600 | 300 | // FIXME: we need QInputDeviceInfo to detect the keyboard attechment | 287 | // FIXME: we need QInputDeviceInfo to detect the keyboard attechment |
4601 | @@ -436,6 +423,163 @@ | |||
4602 | 436 | Q_EMIT shortcutChanged(); | 423 | Q_EMIT shortcutChanged(); |
4603 | 437 | } | 424 | } |
4604 | 438 | 425 | ||
4605 | 426 | /*! | ||
4606 | 427 | * \qmlproperty bool Action::visible | ||
4607 | 428 | * Specifies whether the action is visible to the user. Defaults to true. | ||
4608 | 429 | */ | ||
4609 | 430 | void UCAction::setVisible(bool visible) | ||
4610 | 431 | { | ||
4611 | 432 | if (m_visible == visible) { | ||
4612 | 433 | return; | ||
4613 | 434 | } | ||
4614 | 435 | m_visible = visible; | ||
4615 | 436 | Q_EMIT visibleChanged(); | ||
4616 | 437 | } | ||
4617 | 438 | |||
4618 | 439 | /*! | ||
4619 | 440 | * \qmlproperty bool Action::enabled | ||
4620 | 441 | * If set to false the action can not be triggered. Components visualizing the | ||
4621 | 442 | * action migth either hide the action or make it insensitive. However visibility | ||
4622 | 443 | * can be controlled separately using the \l visible property. | ||
4623 | 444 | */ | ||
4624 | 445 | void UCAction::setEnabled(bool enabled) | ||
4625 | 446 | { | ||
4626 | 447 | if (m_enabled == enabled) { | ||
4627 | 448 | return; | ||
4628 | 449 | } | ||
4629 | 450 | m_enabled = enabled; | ||
4630 | 451 | Q_EMIT enabledChanged(); | ||
4631 | 452 | |||
4632 | 453 | } | ||
4633 | 454 | |||
4634 | 455 | /*! | ||
4635 | 456 | * \qmlproperty enum Action::parameterType | ||
4636 | 457 | * Type of the parameter passed to \l trigger and \l triggered. | ||
4637 | 458 | * Type is an enumeration: | ||
4638 | 459 | * \list | ||
4639 | 460 | * \li \b Action.None: No paramater. (default) | ||
4640 | 461 | * \li \b Action.String: String parameter. | ||
4641 | 462 | * \li \b Action.Integer: Integer parameter. | ||
4642 | 463 | * \li \b Action.Bool: Boolean parameter. | ||
4643 | 464 | * \li \b Action.Real: Single precision floating point parameter. | ||
4644 | 465 | * \li \b Action.Object: The parameter is an object. | ||
4645 | 466 | * \endlist | ||
4646 | 467 | * \qml | ||
4647 | 468 | * Action { | ||
4648 | 469 | * id: action | ||
4649 | 470 | * parameterType: Action.String | ||
4650 | 471 | * onTriggered: { | ||
4651 | 472 | * // value arguments now contain strings | ||
4652 | 473 | * console.log(value); | ||
4653 | 474 | * } | ||
4654 | 475 | * Component.onCompleted: action.trigger("Hello World") | ||
4655 | 476 | * } | ||
4656 | 477 | * \endqml | ||
4657 | 478 | */ | ||
4658 | 479 | void UCAction::setParameterType(UCAction::Type type) | ||
4659 | 480 | { | ||
4660 | 481 | if (m_parameterType == type) { | ||
4661 | 482 | return; | ||
4662 | 483 | } | ||
4663 | 484 | m_parameterType = type; | ||
4664 | 485 | Q_EMIT parameterTypeChanged(); | ||
4665 | 486 | } | ||
4666 | 487 | |||
4667 | 488 | /*! | ||
4668 | 489 | * \qmlproperty bool Action::checkable | ||
4669 | 490 | * \since Ubuntu.Components 1.3 | ||
4670 | 491 | * Whether the action can be checked. Defaults to false. | ||
4671 | 492 | * \sa Action::checked, Action::toggled, ExclusiveGroup | ||
4672 | 493 | */ | ||
4673 | 494 | void UCAction::setCheckable(bool checkable) | ||
4674 | 495 | { | ||
4675 | 496 | if (m_checkable == checkable) { | ||
4676 | 497 | return; | ||
4677 | 498 | } | ||
4678 | 499 | m_checkable = checkable; | ||
4679 | 500 | Q_EMIT checkableChanged(); | ||
4680 | 501 | |||
4681 | 502 | // If the Action is already checked, assert the check state. | ||
4682 | 503 | if (m_checked) | ||
4683 | 504 | Q_EMIT toggled(m_checkable); | ||
4684 | 505 | } | ||
4685 | 506 | |||
4686 | 507 | /*! | ||
4687 | 508 | * \qmlproperty bool Action::checked | ||
4688 | 509 | * \since Ubuntu.Components 1.3 | ||
4689 | 510 | * If the action is checkable, this property reflects its checked state. Defaults to false. | ||
4690 | 511 | * Its value is also false while checkable is false. | ||
4691 | 512 | * \sa Action::checkable, Action::toggled, ExclusiveGroup | ||
4692 | 513 | */ | ||
4693 | 514 | void UCAction::setChecked(bool checked) | ||
4694 | 515 | { | ||
4695 | 516 | if (m_checked == checked) { | ||
4696 | 517 | return; | ||
4697 | 518 | } | ||
4698 | 519 | m_checked = checked; | ||
4699 | 520 | |||
4700 | 521 | if (m_checkable) { | ||
4701 | 522 | Q_EMIT toggled(checked); | ||
4702 | 523 | } | ||
4703 | 524 | } | ||
4704 | 525 | |||
4705 | 526 | /*! | ||
4706 | 527 | * \qmlproperty ExclusiveGroup Action::exclusiveGroup | ||
4707 | 528 | * \since Ubuntu.Components 1.3 | ||
4708 | 529 | * The \l ExclusiveGroup associated with this action. | ||
4709 | 530 | * An exclusive group allows the \l checked property to belinked to other actions, | ||
4710 | 531 | * as in radio controls. | ||
4711 | 532 | * \qml | ||
4712 | 533 | * Column { | ||
4713 | 534 | * ExclusiveGroup { | ||
4714 | 535 | * Action { | ||
4715 | 536 | * id: action1 | ||
4716 | 537 | * checkable: true | ||
4717 | 538 | * checked: true | ||
4718 | 539 | * } | ||
4719 | 540 | * Action { | ||
4720 | 541 | * id: action2 | ||
4721 | 542 | * checkable: true | ||
4722 | 543 | * } | ||
4723 | 544 | * Action { | ||
4724 | 545 | * id: action3 | ||
4725 | 546 | * checkable: true | ||
4726 | 547 | * } | ||
4727 | 548 | * } | ||
4728 | 549 | * | ||
4729 | 550 | * Button { | ||
4730 | 551 | * action: action1 | ||
4731 | 552 | * color: action.checked ? UbuntuColor.green : UbuntuColor.red | ||
4732 | 553 | * } | ||
4733 | 554 | * Button { | ||
4734 | 555 | * action: action2 | ||
4735 | 556 | * color: action.checked ? UbuntuColor.green : UbuntuColor.red | ||
4736 | 557 | * } | ||
4737 | 558 | * Button { | ||
4738 | 559 | * action: action3 | ||
4739 | 560 | * color: action.checked ? UbuntuColor.green : UbuntuColor.grey | ||
4740 | 561 | * } | ||
4741 | 562 | * } | ||
4742 | 563 | * \endqml | ||
4743 | 564 | */ | ||
4744 | 565 | void UCAction::setExclusiveGroup(ExclusiveGroup *exclusiveGroup) | ||
4745 | 566 | { | ||
4746 | 567 | if (m_exclusiveGroup == exclusiveGroup) { | ||
4747 | 568 | return; | ||
4748 | 569 | } | ||
4749 | 570 | |||
4750 | 571 | if (m_exclusiveGroup) { | ||
4751 | 572 | m_exclusiveGroup->unbindCheckable(this); | ||
4752 | 573 | } | ||
4753 | 574 | |||
4754 | 575 | m_exclusiveGroup = exclusiveGroup; | ||
4755 | 576 | |||
4756 | 577 | if (m_exclusiveGroup) { | ||
4757 | 578 | m_exclusiveGroup->bindCheckable(this); | ||
4758 | 579 | } | ||
4759 | 580 | Q_EMIT exclusiveGroupChanged(); | ||
4760 | 581 | } | ||
4761 | 582 | |||
4762 | 439 | bool UCAction::event(QEvent *event) | 583 | bool UCAction::event(QEvent *event) |
4763 | 440 | { | 584 | { |
4764 | 441 | if (event->type() != QEvent::Shortcut) | 585 | if (event->type() != QEvent::Shortcut) |
4765 | @@ -475,6 +619,11 @@ | |||
4766 | 475 | if (!m_enabled) { | 619 | if (!m_enabled) { |
4767 | 476 | return; | 620 | return; |
4768 | 477 | } | 621 | } |
4769 | 622 | |||
4770 | 623 | if (m_checkable && !(m_checked && m_exclusiveGroup)) { | ||
4771 | 624 | setChecked(!m_checked); | ||
4772 | 625 | } | ||
4773 | 626 | |||
4774 | 478 | if (!isValidType(value.type())) { | 627 | if (!isValidType(value.type())) { |
4775 | 479 | Q_EMIT triggered(QVariant()); | 628 | Q_EMIT triggered(QVariant()); |
4776 | 480 | } else { | 629 | } else { |
4777 | 481 | 630 | ||
4778 | === modified file 'src/Ubuntu/UbuntuToolkit/ucaction_p.h' | |||
4779 | --- src/Ubuntu/UbuntuToolkit/ucaction_p.h 2016-07-07 07:21:48 +0000 | |||
4780 | +++ src/Ubuntu/UbuntuToolkit/ucaction_p.h 2016-08-31 08:57:26 +0000 | |||
4781 | @@ -53,7 +53,7 @@ | |||
4782 | 53 | } | 53 | } |
4783 | 54 | } | 54 | } |
4784 | 55 | 55 | ||
4786 | 56 | class UCActionAttached; | 56 | class ExclusiveGroup; |
4787 | 57 | class UBUNTUTOOLKIT_EXPORT UCAction : public QObject | 57 | class UBUNTUTOOLKIT_EXPORT UCAction : public QObject |
4788 | 58 | { | 58 | { |
4789 | 59 | Q_OBJECT | 59 | Q_OBJECT |
4790 | @@ -62,19 +62,23 @@ | |||
4791 | 62 | Q_ENUMS(Type) | 62 | Q_ENUMS(Type) |
4792 | 63 | Q_PROPERTY(QString name MEMBER m_name WRITE setName NOTIFY nameChanged) | 63 | Q_PROPERTY(QString name MEMBER m_name WRITE setName NOTIFY nameChanged) |
4793 | 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) |
4795 | 65 | Q_PROPERTY(QString iconName MEMBER m_iconName WRITE setIconName NOTIFY iconNameChanged) | 65 | Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged) |
4796 | 66 | Q_PROPERTY(QString description MEMBER m_description NOTIFY descriptionChanged) | 66 | Q_PROPERTY(QString description MEMBER m_description NOTIFY descriptionChanged) |
4797 | 67 | Q_PROPERTY(QString keywords MEMBER m_keywords NOTIFY keywordsChanged) | 67 | Q_PROPERTY(QString keywords MEMBER m_keywords NOTIFY keywordsChanged) |
4800 | 68 | Q_PROPERTY(bool enabled MEMBER m_enabled NOTIFY enabledChanged) | 68 | Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) |
4801 | 69 | Q_PROPERTY(Type parameterType MEMBER m_parameterType NOTIFY parameterTypeChanged) | 69 | Q_PROPERTY(Type parameterType READ parameterType WRITE setParameterType NOTIFY parameterTypeChanged) |
4802 | 70 | |||
4803 | 71 | Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged REVISION 1) | ||
4804 | 72 | Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY toggled REVISION 1) | ||
4805 | 73 | Q_PROPERTY(ExclusiveGroup* exclusiveGroup READ exclusiveGroup WRITE setExclusiveGroup NOTIFY exclusiveGroupChanged REVISION 1) | ||
4806 | 70 | 74 | ||
4807 | 71 | // Toolkit Actions API | 75 | // Toolkit Actions API |
4810 | 72 | Q_PROPERTY(QUrl iconSource MEMBER m_iconSource WRITE setIconSource NOTIFY iconSourceChanged) | 76 | Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource NOTIFY iconSourceChanged) |
4811 | 73 | Q_PROPERTY(bool visible MEMBER m_visible NOTIFY visibleChanged) | 77 | Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged) |
4812 | 74 | Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint) | 78 | Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint) |
4813 | 75 | 79 | ||
4814 | 76 | // QtQuickControls.Action | 80 | // QtQuickControls.Action |
4816 | 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) |
4817 | 78 | public: | 82 | public: |
4818 | 79 | enum Type { | 83 | enum Type { |
4819 | 80 | None, | 84 | None, |
4820 | @@ -108,11 +112,26 @@ | |||
4821 | 108 | QString text(); | 112 | QString text(); |
4822 | 109 | void setText(const QString &text); | 113 | void setText(const QString &text); |
4823 | 110 | void resetText(); | 114 | void resetText(); |
4824 | 115 | QString iconName() const { return m_iconName; } | ||
4825 | 111 | void setIconName(const QString &name); | 116 | void setIconName(const QString &name); |
4826 | 117 | QUrl iconSource() const { return m_iconSource; } | ||
4827 | 112 | void setIconSource(const QUrl &url); | 118 | void setIconSource(const QUrl &url); |
4828 | 113 | void setItemHint(QQmlComponent *); | 119 | void setItemHint(QQmlComponent *); |
4829 | 120 | QVariant shortcut() const { return m_shortcut; } | ||
4830 | 114 | void setShortcut(const QVariant&); | 121 | void setShortcut(const QVariant&); |
4831 | 115 | void resetShortcut(); | 122 | void resetShortcut(); |
4832 | 123 | bool visible() const { return m_visible; } | ||
4833 | 124 | void setVisible(bool visible); | ||
4834 | 125 | void setEnabled(bool enabled); | ||
4835 | 126 | void setParameterType(Type type); | ||
4836 | 127 | Type parameterType() const { return m_parameterType; } | ||
4837 | 128 | void setCheckable(bool checkable); | ||
4838 | 129 | bool isCheckable() const { return m_checkable; } | ||
4839 | 130 | void setChecked(bool checked); | ||
4840 | 131 | bool isChecked() const { return m_checkable && m_checked; } | ||
4841 | 132 | |||
4842 | 133 | ExclusiveGroup *exclusiveGroup() const { return m_exclusiveGroup; } | ||
4843 | 134 | void setExclusiveGroup(ExclusiveGroup *exclusiveGroup); | ||
4844 | 116 | 135 | ||
4845 | 117 | Q_SIGNALS: | 136 | Q_SIGNALS: |
4846 | 118 | void nameChanged(); | 137 | void nameChanged(); |
4847 | @@ -125,13 +144,18 @@ | |||
4848 | 125 | void iconSourceChanged(); | 144 | void iconSourceChanged(); |
4849 | 126 | void visibleChanged(); | 145 | void visibleChanged(); |
4850 | 127 | void shortcutChanged(); | 146 | void shortcutChanged(); |
4851 | 147 | Q_REVISION(1) void checkableChanged(); | ||
4852 | 148 | Q_REVISION(1) void exclusiveGroupChanged(); | ||
4853 | 149 | |||
4854 | 128 | void triggered(const QVariant &value); | 150 | void triggered(const QVariant &value); |
4855 | 151 | Q_REVISION(1) void toggled(bool value); | ||
4856 | 129 | 152 | ||
4857 | 130 | public Q_SLOTS: | 153 | public Q_SLOTS: |
4858 | 131 | void trigger(const QVariant &value = QVariant()); | 154 | void trigger(const QVariant &value = QVariant()); |
4859 | 132 | 155 | ||
4860 | 133 | private: | 156 | private: |
4861 | 134 | QPODVector<QQuickItem*, 4> m_owningItems; | 157 | QPODVector<QQuickItem*, 4> m_owningItems; |
4862 | 158 | ExclusiveGroup *m_exclusiveGroup; | ||
4863 | 135 | QString m_name; | 159 | QString m_name; |
4864 | 136 | QString m_text; | 160 | QString m_text; |
4865 | 137 | QString m_iconName; | 161 | QString m_iconName; |
4866 | @@ -146,6 +170,8 @@ | |||
4867 | 146 | bool m_enabled:1; | 170 | bool m_enabled:1; |
4868 | 147 | bool m_visible:1; | 171 | bool m_visible:1; |
4869 | 148 | bool m_published:1; | 172 | bool m_published:1; |
4870 | 173 | bool m_checkable:1; | ||
4871 | 174 | bool m_checked:1; | ||
4872 | 149 | 175 | ||
4873 | 150 | friend class UCActionContext; | 176 | friend class UCActionContext; |
4874 | 151 | friend class UCActionItem; | 177 | friend class UCActionItem; |
4875 | 152 | 178 | ||
4876 | === modified file 'src/Ubuntu/UbuntuToolkit/uclistitem.cpp' | |||
4877 | --- src/Ubuntu/UbuntuToolkit/uclistitem.cpp 2016-07-14 07:41:06 +0000 | |||
4878 | +++ src/Ubuntu/UbuntuToolkit/uclistitem.cpp 2016-08-31 08:57:26 +0000 | |||
4879 | @@ -537,7 +537,7 @@ | |||
4880 | 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. |
4881 | 538 | * \qml | 538 | * \qml |
4882 | 539 | * import QtQuick 2.4 | 539 | * import QtQuick 2.4 |
4884 | 540 | * import Ubuntu.Components 1.2 | 540 | * import Ubuntu.Components 1.3 |
4885 | 541 | * | 541 | * |
4886 | 542 | * MainView { | 542 | * MainView { |
4887 | 543 | * width: units.gu(40) | 543 | * width: units.gu(40) |
4888 | @@ -572,20 +572,29 @@ | |||
4889 | 572 | * onClicked: console.log("clicked on ListItem with trailingActions set") | 572 | * onClicked: console.log("clicked on ListItem with trailingActions set") |
4890 | 573 | * } | 573 | * } |
4891 | 574 | * ListItem { | 574 | * ListItem { |
4894 | 575 | * Label { | 575 | * // shall specify the height when Using ListItemLayout inside ListItem |
4895 | 576 | * text: "onClicked implemented" | 576 | * height: clickImplementedLayout.height + (divider.visible ? divider.height : 0) |
4896 | 577 | * ListItemLayout { | ||
4897 | 578 | * id: clickImplementedLayout | ||
4898 | 579 | * title.text: "onClicked implemented" | ||
4899 | 577 | * } | 580 | * } |
4900 | 578 | * onClicked: console.log("clicked on ListItem with onClicked implemented") | 581 | * onClicked: console.log("clicked on ListItem with onClicked implemented") |
4901 | 579 | * } | 582 | * } |
4902 | 580 | * ListItem { | 583 | * ListItem { |
4905 | 581 | * Label { | 584 | * // shall specify the height when Using ListItemLayout inside ListItem |
4906 | 582 | * text: "onPressAndHold implemented" | 585 | * height: pressHoldLayout.height + (divider.visible ? divider.height : 0) |
4907 | 586 | * ListItemLayout { | ||
4908 | 587 | * id: pressHoldLayout | ||
4909 | 588 | * title.text: "onPressAndHold implemented" | ||
4910 | 583 | * } | 589 | * } |
4911 | 584 | * onPressAndHold: console.log("long-pressed on ListItem with onPressAndHold implemented") | 590 | * onPressAndHold: console.log("long-pressed on ListItem with onPressAndHold implemented") |
4912 | 585 | * } | 591 | * } |
4913 | 586 | * ListItem { | 592 | * ListItem { |
4916 | 587 | * Label { | 593 | * // shall specify the height when Using ListItemLayout inside ListItem |
4917 | 588 | * text: "No highlight" | 594 | * height: noHighlightLayout.height + (divider.visible ? divider.height : 0) |
4918 | 595 | * ListItemLayout { | ||
4919 | 596 | * id: noHighlightLayout | ||
4920 | 597 | * title.text: "No highlight" | ||
4921 | 589 | * } | 598 | * } |
4922 | 590 | * } | 599 | * } |
4923 | 591 | * } | 600 | * } |
4924 | @@ -671,7 +680,7 @@ | |||
4925 | 671 | * to the view itself. | 680 | * to the view itself. |
4926 | 672 | * \qml | 681 | * \qml |
4927 | 673 | * import QtQuick 2.4 | 682 | * import QtQuick 2.4 |
4929 | 674 | * import Ubuntu.Components 1.2 | 683 | * import Ubuntu.Components 1.3 |
4930 | 675 | * | 684 | * |
4931 | 676 | * Flickable { | 685 | * Flickable { |
4932 | 677 | * width: units.gu(40) | 686 | * width: units.gu(40) |
4933 | @@ -735,7 +744,7 @@ | |||
4934 | 735 | * Example of live drag implementation: | 744 | * Example of live drag implementation: |
4935 | 736 | * \qml | 745 | * \qml |
4936 | 737 | * import QtQuick 2.4 | 746 | * import QtQuick 2.4 |
4938 | 738 | * import Ubuntu.Components 1.2 | 747 | * import Ubuntu.Components 1.3 |
4939 | 739 | * | 748 | * |
4940 | 740 | * ListView { | 749 | * ListView { |
4941 | 741 | * model: ListModel { | 750 | * model: ListModel { |
4942 | @@ -746,8 +755,11 @@ | |||
4943 | 746 | * } | 755 | * } |
4944 | 747 | * } | 756 | * } |
4945 | 748 | * delegate: ListItem { | 757 | * delegate: ListItem { |
4948 | 749 | * Label { | 758 | * // shall specify the height when Using ListItemLayout inside ListItem |
4949 | 750 | * text: modelData | 759 | * height: modelLayout.height + (divider.visible ? divider.height : 0) |
4950 | 760 | * ListItemLayout { | ||
4951 | 761 | * id: modelLayout | ||
4952 | 762 | * title.text: modelData | ||
4953 | 751 | * } | 763 | * } |
4954 | 752 | * color: dragMode ? "lightblue" : "lightgray" | 764 | * color: dragMode ? "lightblue" : "lightgray" |
4955 | 753 | * onPressAndHold: ListView.view.ViewItems.dragMode = | 765 | * onPressAndHold: ListView.view.ViewItems.dragMode = |
4956 | @@ -769,7 +781,7 @@ | |||
4957 | 769 | * Example of drag'n'drop implementation: | 781 | * Example of drag'n'drop implementation: |
4958 | 770 | * \qml | 782 | * \qml |
4959 | 771 | * import QtQuick 2.4 | 783 | * import QtQuick 2.4 |
4961 | 772 | * import Ubuntu.Components 1.2 | 784 | * import Ubuntu.Components 1.3 |
4962 | 773 | * | 785 | * |
4963 | 774 | * ListView { | 786 | * ListView { |
4964 | 775 | * model: ListModel { | 787 | * model: ListModel { |
4965 | @@ -780,8 +792,11 @@ | |||
4966 | 780 | * } | 792 | * } |
4967 | 781 | * } | 793 | * } |
4968 | 782 | * delegate: ListItem { | 794 | * delegate: ListItem { |
4971 | 783 | * Label { | 795 | * // shall specify the height when Using ListItemLayout inside ListItem |
4972 | 784 | * text: modelData | 796 | * height: modelLayout.height + (divider.visible ? divider.height : 0) |
4973 | 797 | * ListItemLayout { | ||
4974 | 798 | * id: modelLayout | ||
4975 | 799 | * title.text: modelData | ||
4976 | 785 | * } | 800 | * } |
4977 | 786 | * color: dragMode ? "lightblue" : "lightgray" | 801 | * color: dragMode ? "lightblue" : "lightgray" |
4978 | 787 | * onPressAndHold: ListView.view.ViewItems.dragMode = | 802 | * onPressAndHold: ListView.view.ViewItems.dragMode = |
4979 | @@ -815,13 +830,16 @@ | |||
4980 | 815 | * can still be implemented with these kind of lists as well. | 830 | * can still be implemented with these kind of lists as well. |
4981 | 816 | * \qml | 831 | * \qml |
4982 | 817 | * import QtQuick 2.4 | 832 | * import QtQuick 2.4 |
4984 | 818 | * import Ubuntu.Components 1.2 | 833 | * import Ubuntu.Components 1.3 |
4985 | 819 | * | 834 | * |
4986 | 820 | * ListView { | 835 | * ListView { |
4987 | 821 | * model: ["plum", "peach", "pomegrenade", "pear", "banana"] | 836 | * model: ["plum", "peach", "pomegrenade", "pear", "banana"] |
4988 | 822 | * delegate: ListItem { | 837 | * delegate: ListItem { |
4991 | 823 | * Label { | 838 | * // shall specify the height when Using ListItemLayout inside ListItem |
4992 | 824 | * text: modelData | 839 | * height: modelLayout.height + (divider.visible ? divider.height : 0) |
4993 | 840 | * ListItemLayout { | ||
4994 | 841 | * id: modelLayout | ||
4995 | 842 | * title.text: modelData | ||
4996 | 825 | * } | 843 | * } |
4997 | 826 | * color: dragMode ? "lightblue" : "lightgray" | 844 | * color: dragMode ? "lightblue" : "lightgray" |
4998 | 827 | * onPressAndHold: ListView.view.ViewItems.dragMode = | 845 | * onPressAndHold: ListView.view.ViewItems.dragMode = |
4999 | @@ -849,14 +867,17 @@ | |||
5000 | 849 | * \l ViewItems::dragUpdated signal handler. | 867 | * \l ViewItems::dragUpdated signal handler. |
The diff has been truncated for viewing.