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