Merge lp:webbrowser-app/staging into lp:webbrowser-app
- staging
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1560 |
Proposed branch: | lp:webbrowser-app/staging |
Merge into: | lp:webbrowser-app |
Diff against target: |
2840 lines (+1499/-148) 63 files modified
.bzrignore (+0/-2) debian/control (+7/-2) debian/rules (+1/-1) snapcraft.yaml (+8/-16) src/Ubuntu/Web/ua-overrides-desktop.js.in (+9/-0) src/Ubuntu/Web/ua-overrides-mobile.js.in (+3/-0) src/app/ChromeBase.qml (+1/-0) src/app/webbrowser/Browser.qml (+158/-29) src/app/webbrowser/BrowserTab.qml (+19/-2) src/app/webbrowser/CMakeLists.txt (+2/-0) src/app/webbrowser/Chrome.qml (+12/-2) src/app/webbrowser/ContextMenuMobile.qml (+10/-2) src/app/webbrowser/Suggestions.qml (+1/-1) src/app/webbrowser/TabComponent.qml (+33/-15) src/app/webbrowser/TabItem.qml (+2/-2) src/app/webbrowser/TabsBar.qml (+112/-15) src/app/webbrowser/TabsList.qml (+2/-2) src/app/webbrowser/drag-helper.cpp (+203/-0) src/app/webbrowser/drag-helper.h (+91/-0) src/app/webbrowser/reparenter.cpp (+124/-0) src/app/webbrowser/reparenter.h (+46/-0) src/app/webbrowser/webbrowser-app.cpp (+6/-0) src/app/webbrowser/webbrowser-app.qml (+33/-3) src/app/webcontainer/ContextMenuMobile.qml (+10/-2) src/app/webcontainer/WebappWebview.qml (+5/-4) tests/autopilot/webbrowser_app/emulators/browser.py (+7/-1) tests/autopilot/webbrowser_app/tests/__init__.py (+40/-7) tests/autopilot/webbrowser_app/tests/test_downloads.py (+62/-10) tests/autopilot/webbrowser_app/tests/test_history.py (+30/-4) tests/autopilot/webbrowser_app/tests/test_multiple_windows.py (+222/-0) tests/autopilot/webbrowser_app/tests/test_new_tab_view.py (+10/-0) tests/unittests/bookmarks-folder-model/CMakeLists.txt (+1/-1) tests/unittests/bookmarks-folderlist-model/CMakeLists.txt (+1/-1) tests/unittests/bookmarks-model/CMakeLists.txt (+1/-1) tests/unittests/container-url-patterns/CMakeLists.txt (+1/-1) tests/unittests/cookie-store/CMakeLists.txt (+1/-1) tests/unittests/domain-utils/CMakeLists.txt (+1/-1) tests/unittests/downloads-model/CMakeLists.txt (+1/-1) tests/unittests/favicon-fetcher/CMakeLists.txt (+1/-1) tests/unittests/history-domain-model/CMakeLists.txt (+1/-1) tests/unittests/history-domainlist-model/CMakeLists.txt (+1/-1) tests/unittests/history-lastvisitdatelist-model/CMakeLists.txt (+1/-1) tests/unittests/history-model/CMakeLists.txt (+1/-1) tests/unittests/intent-filter/CMakeLists.txt (+1/-1) tests/unittests/limit-proxy-model/CMakeLists.txt (+1/-1) tests/unittests/meminfo/CMakeLists.txt (+1/-1) tests/unittests/oxide-cookie-helper/CMakeLists.txt (+1/-1) tests/unittests/qml/CMakeLists.txt (+2/-0) tests/unittests/qml/ReparenterFakeContainer.qml (+40/-0) tests/unittests/qml/ReparenterFakeTab.qml (+37/-0) tests/unittests/qml/tst_BrowserTab.qml (+3/-2) tests/unittests/qml/tst_QmlTests.cpp (+7/-0) tests/unittests/qml/tst_Reparenter.qml (+114/-0) tests/unittests/qml/tst_TabsBar.qml (+2/-0) tests/unittests/qml/tst_UbuntuWebView02.qml (+1/-0) tests/unittests/search-engine/CMakeLists.txt (+1/-1) tests/unittests/session-storage/CMakeLists.txt (+1/-1) tests/unittests/session-utils/CMakeLists.txt (+1/-1) tests/unittests/single-instance-manager/CMakeLists.txt (+1/-1) tests/unittests/tabs-model/CMakeLists.txt (+1/-1) tests/unittests/text-search-filter-model/CMakeLists.txt (+1/-1) tests/unittests/webapp-container-color-helper/CMakeLists.txt (+1/-1) tests/unittests/webapp-container-hook/CMakeLists.txt (+1/-1) |
To merge this branch: | bzr merge lp:webbrowser-app/staging |
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
system-apps-ci-bot | continuous-integration | Needs Fixing | |
Ubuntu Phablet Team | Pending | ||
Review via email:
|
Commit message
TEST - DO NOT MERGE!
Description of the change

system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
- 1575. By Andrew Hayzen
-
* Add qtdeclarative5-
ubuntu- content1 and qtdeclarative5- ubuntu- download- manager0. 1 as depends as they are in main and then fixes issues with saving images
* Enable autopilot TestDownloads on desktop as depends are now met

system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1575
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 1576. By Olivier Tilloy
-
Use the ubuntu-app-platform content interface.
- 1577. By Olivier Tilloy
-
Update version number in snapcraft.yaml.

system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1576
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/

system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1577
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1578. By Olivier Tilloy
-
Desktop UA override for google docs.

system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1578
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1579. By Andrew Hayzen
-
Add Drag and drop support of tabs between windows on non-mir clients.
- 1580. By Olivier Tilloy
-
Merge the latest changes from trunk.

system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1580
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 1581. By Andrew Hayzen
-
* Improve styling for drag handle to match design
* Add extra properties to DragHelper to allow for changing border size and handle size etc - 1582. By Andrew Hayzen
-
Ensure X position is set correctly when dragging is stopped.

system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1582
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2016-10-06 10:16:41 +0000 |
3 | +++ .bzrignore 2016-11-30 14:23:08 +0000 |
4 | @@ -56,5 +56,3 @@ |
5 | coverage-xml.cmake |
6 | coverage.* |
7 | coveragereport/ |
8 | -tst_*Tests.xml |
9 | -tst_*Test.xml |
10 | |
11 | === modified file 'debian/control' |
12 | --- debian/control 2016-08-29 16:34:14 +0000 |
13 | +++ debian/control 2016-11-30 14:23:08 +0000 |
14 | @@ -45,7 +45,7 @@ |
15 | Depends: ${misc:Depends}, |
16 | ${shlibs:Depends}, |
17 | fonts-liberation, |
18 | - liboxideqt-qmlplugin (>= 1.15), |
19 | + liboxideqt-qmlplugin (>= 1.17), |
20 | libqt5sql5-sqlite, |
21 | qml-module-qt-labs-folderlistmodel, |
22 | qml-module-qt-labs-settings, |
23 | @@ -53,6 +53,8 @@ |
24 | qml-module-qtquick-layouts, |
25 | qml-module-qtquick-window2 (>= 5.3), |
26 | qml-module-ubuntu-web (= ${binary:Version}), |
27 | + qtdeclarative5-ubuntu-content1, |
28 | + qtdeclarative5-ubuntu-download-manager0.1, |
29 | qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3), |
30 | qtdeclarative5-unity-action-plugin, |
31 | Replaces: webbrowser-app-assets, |
32 | @@ -70,12 +72,14 @@ |
33 | Depends: ${misc:Depends}, |
34 | ${shlibs:Depends}, |
35 | fonts-liberation, |
36 | - liboxideqt-qmlplugin (>= 1.8), |
37 | + liboxideqt-qmlplugin (>= 1.17), |
38 | libqt5sql5-sqlite, |
39 | qml-module-qtquick2 (>= 5.4), |
40 | qml-module-qtquick-window2 (>= 5.3), |
41 | qml-module-ubuntu-onlineaccounts, |
42 | qml-module-ubuntu-web (= ${binary:Version}), |
43 | + qtdeclarative5-ubuntu-content1, |
44 | + qtdeclarative5-ubuntu-download-manager0.1, |
45 | qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3), |
46 | qtdeclarative5-unity-action-plugin, |
47 | unity-webapps-qml, |
48 | @@ -164,6 +168,7 @@ |
49 | Multi-Arch: foreign |
50 | Depends: ${misc:Depends}, |
51 | autopilot-qt5, |
52 | + content-hub-testability, |
53 | python3-autopilot, |
54 | python3-fixtures, |
55 | python3-psutil, |
56 | |
57 | === modified file 'debian/rules' |
58 | --- debian/rules 2016-10-13 20:07:10 +0000 |
59 | +++ debian/rules 2016-11-30 14:23:08 +0000 |
60 | @@ -44,5 +44,5 @@ |
61 | |
62 | override_dh_auto_test: |
63 | mkdir -p $(BUILDHOME) |
64 | - HOME=$(BUILDHOME) dh_auto_test |
65 | + HOME=$(BUILDHOME) dh_auto_test -- ARGS+=-VV |
66 | |
67 | |
68 | === added directory 'snap/ubuntu-app-platform' |
69 | === modified file 'snapcraft.yaml' |
70 | --- snapcraft.yaml 2016-10-07 14:42:55 +0000 |
71 | +++ snapcraft.yaml 2016-11-30 14:23:08 +0000 |
72 | @@ -1,5 +1,5 @@ |
73 | name: webbrowser-app |
74 | -version: 0.23+16.10.20160928-0ubuntu1 |
75 | +version: 20161117-staging |
76 | summary: Ubuntu web browser |
77 | description: A lightweight web browser tailored for Ubuntu, based on the Oxide browser engine and using the Ubuntu UI components. |
78 | confinement: strict |
79 | @@ -13,6 +13,7 @@ |
80 | - network |
81 | - network-bind |
82 | - opengl |
83 | + - platform |
84 | - pulseaudio |
85 | - screen-inhibit-control |
86 | - unity7 |
87 | @@ -21,6 +22,11 @@ |
88 | browser-sandbox: |
89 | interface: browser-support |
90 | allow-sandbox: true |
91 | + platform: |
92 | + content: ubuntu-app-platform1 |
93 | + default-provider: ubuntu-app-platform |
94 | + interface: content |
95 | + target: ubuntu-app-platform |
96 | |
97 | parts: |
98 | webbrowser-app: |
99 | @@ -43,21 +49,7 @@ |
100 | - xvfb |
101 | stage-packages: |
102 | - fonts-liberation |
103 | - - liboxideqt-qmlplugin |
104 | - - libqt5sql5-sqlite |
105 | - - mir-graphics-drivers-desktop |
106 | - - qml-module-qt-labs-folderlistmodel |
107 | - - qml-module-qt-labs-settings |
108 | - - qml-module-qtquick2 |
109 | - - qml-module-qtquick-layouts |
110 | - - qml-module-qtquick-window2 |
111 | - - qml-module-ubuntu-components |
112 | - - qml-module-ubuntu-thumbnailer0.1 |
113 | - - qtdeclarative5-ubuntu-content1 |
114 | - - qtdeclarative5-ubuntu-download-manager0.1 |
115 | - - qtdeclarative5-unity-action-plugin |
116 | - - qtubuntu-desktop |
117 | - after: [desktop-qt5] |
118 | + after: [desktop-ubuntu-app-platform] |
119 | |
120 | launcher: |
121 | plugin: dump |
122 | |
123 | === modified file 'src/Ubuntu/Web/ua-overrides-desktop.js.in' |
124 | --- src/Ubuntu/Web/ua-overrides-desktop.js.in 2016-10-14 14:37:23 +0000 |
125 | +++ src/Ubuntu/Web/ua-overrides-desktop.js.in 2016-11-30 14:23:08 +0000 |
126 | @@ -33,4 +33,13 @@ |
127 | |
128 | // Google recaptcha (https://launchpad.net/bugs/1599146) |
129 | ["^https:\/\/www\.google\.com\/recaptcha\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"], |
130 | + |
131 | + // ESPN websites (https://launchpad.net/bugs/1637285) |
132 | + ["^https?:\/\/(.+\.)?espn(fc)?\.co(m|\.uk)\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"], |
133 | + |
134 | + // meet.jit.si (https://launchpad.net/bugs/1635971) |
135 | + ["^https:\/\/meet\.jit\.si\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"], |
136 | + |
137 | + // Google docs (https://launchpad.net/bugs/1643386) |
138 | + ["^https:\/\/(docs|drive)\.google\.com\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"], |
139 | ]; |
140 | |
141 | === modified file 'src/Ubuntu/Web/ua-overrides-mobile.js.in' |
142 | --- src/Ubuntu/Web/ua-overrides-mobile.js.in 2016-10-14 14:37:23 +0000 |
143 | +++ src/Ubuntu/Web/ua-overrides-mobile.js.in 2016-11-30 14:23:08 +0000 |
144 | @@ -35,4 +35,7 @@ |
145 | |
146 | // Google recaptcha (https://launchpad.net/bugs/1599146) |
147 | ["^https:\/\/www\.google\.com\/recaptcha\/", "Mozilla/5.0 (Linux; Ubuntu @UBUNTU_VERSION@ like Android 4.4;) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"], |
148 | + |
149 | + // meet.jit.si (https://launchpad.net/bugs/1635971) |
150 | + ["^https:\/\/meet\.jit\.si\/", "Mozilla/5.0 (Linux; Ubuntu @UBUNTU_VERSION@ like Android 5.0;) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"], |
151 | ]; |
152 | |
153 | === modified file 'src/app/ChromeBase.qml' |
154 | --- src/app/ChromeBase.qml 2016-09-28 07:51:22 +0000 |
155 | +++ src/app/ChromeBase.qml 2016-11-30 14:23:08 +0000 |
156 | @@ -62,6 +62,7 @@ |
157 | right: parent.right |
158 | bottom: parent.bottom |
159 | } |
160 | + objectName: "chromeProgressBar" |
161 | |
162 | z: 2 |
163 | } |
164 | |
165 | === modified file 'src/app/webbrowser/Browser.qml' |
166 | --- src/app/webbrowser/Browser.qml 2016-10-11 16:16:40 +0000 |
167 | +++ src/app/webbrowser/Browser.qml 2016-11-30 14:23:08 +0000 |
168 | @@ -19,10 +19,10 @@ |
169 | import QtQuick 2.4 |
170 | import QtQuick.Window 2.2 |
171 | import Qt.labs.settings 1.0 |
172 | -import Ubuntu.Web 0.2 |
173 | import com.canonical.Oxide 1.15 as Oxide |
174 | import Ubuntu.Components 1.3 |
175 | import Ubuntu.Components.Popups 1.3 |
176 | +import Ubuntu.Web 0.2 |
177 | import Unity.InputInfo 0.1 |
178 | import webbrowserapp.private 0.1 |
179 | import webbrowsercommon.private 0.1 |
180 | @@ -46,6 +46,8 @@ |
181 | |
182 | property var tabsModel: TabsModel {} |
183 | |
184 | + property BrowserWindow thisWindow |
185 | + |
186 | function serializeTabState(tab) { |
187 | var state = {} |
188 | state.uniqueId = tab.uniqueId |
189 | @@ -66,10 +68,25 @@ |
190 | } |
191 | |
192 | function createTab(properties) { |
193 | - return tabComponent.createObject(tabContainer, properties) |
194 | + return internal.createTabHelper(properties) |
195 | + } |
196 | + |
197 | + function bindExistingTab(tab) { |
198 | + Reparenter.reparent(tab, tabContainer); |
199 | + |
200 | + var properties = internal.buildContextProperties(); |
201 | + |
202 | + for (var prop in properties) { |
203 | + tab[prop] = properties[prop]; |
204 | + } |
205 | + |
206 | + // Ensure that we have switched to the tab |
207 | + // otherwise chrome position can break |
208 | + internal.switchToTab(tabsModel.count - 1, true); |
209 | } |
210 | |
211 | signal newWindowRequested(bool incognito) |
212 | + signal newWindowFromTab(var tab, var callback) |
213 | signal openLinkInWindowRequested(url url, bool incognito) |
214 | |
215 | Connections { |
216 | @@ -167,6 +184,10 @@ |
217 | top: parent.top |
218 | } |
219 | height: parent.height - osk.height - bottomEdgeBar.height |
220 | + // disable when newTabView is shown otherwise webview can capture drag events |
221 | + // do not use visible otherwise when a new tab is opened the locationBarController.offset |
222 | + // doesn't get updated, causing the Chrome to disappear |
223 | + enabled: !newTabViewLoader.active |
224 | |
225 | focus: !errorSheetLoader.focus && |
226 | !invalidCertificateErrorSheetLoader.focus && |
227 | @@ -465,6 +486,8 @@ |
228 | showTabsBar: browser.wide |
229 | showFaviconInAddressBar: !browser.wide |
230 | |
231 | + thisWindow: browser.thisWindow |
232 | + |
233 | availableHeight: tabContainer.height - height - y |
234 | |
235 | touchEnabled: internal.hasTouchScreen |
236 | @@ -498,7 +521,8 @@ |
237 | |
238 | onSwitchToTab: internal.switchToTab(index, true) |
239 | onRequestNewTab: internal.openUrlInNewTab("", makeCurrent, true, index) |
240 | - onTabClosed: internal.closeTab(index) |
241 | + onRequestNewWindowFromTab: browser.newWindowFromTab(tab, callback) |
242 | + onTabClosed: internal.closeTab(index, moving) |
243 | |
244 | onFindInPageModeChanged: { |
245 | if (!chrome.findInPageMode) internal.resetFocus() |
246 | @@ -570,7 +594,7 @@ |
247 | |
248 | Keys.onDownPressed: { |
249 | if (suggestionsList.count) suggestionsList.focus = true |
250 | - else if (newTabViewLoader.status == Loader.Ready) { |
251 | + else if (!incognito && (newTabViewLoader.status == Loader.Ready)) { |
252 | newTabViewLoader.forceActiveFocus() |
253 | } |
254 | } |
255 | @@ -977,7 +1001,7 @@ |
256 | |
257 | function openUrlInNewTab(url, setCurrent, load, index) { |
258 | load = typeof load !== 'undefined' ? load : true |
259 | - var tab = tabComponent.createObject(tabContainer, {"initialUrl": url}) |
260 | + var tab = internal.createTabHelper({"initialUrl": url}) |
261 | addTab(tab, setCurrent, index) |
262 | if (load) { |
263 | tab.load() |
264 | @@ -996,8 +1020,36 @@ |
265 | } |
266 | } |
267 | |
268 | - function closeTab(index) { |
269 | + function buildContextProperties(properties) { |
270 | + if (properties === undefined) { |
271 | + properties = {}; |
272 | + } |
273 | + |
274 | + properties["bottomEdgeHandle"] = bottomEdgeHandle; |
275 | + properties["browser"] = browser; |
276 | + properties["chrome"] = chrome; |
277 | + properties["chromeController"] = chromeController; |
278 | + properties["contentHandlerLoader"] = contentHandlerLoader; |
279 | + properties["downloadDialogLoader"] = downloadDialogLoader; |
280 | + properties["downloadsViewLoader"] = downloadsViewLoader; |
281 | + properties["filePickerLoader"] = filePickerLoader; |
282 | + properties["internal"] = internal; |
283 | + properties["recentView"] = recentView; |
284 | + properties["tabsModel"] = tabsModel; |
285 | + |
286 | + return properties; |
287 | + } |
288 | + |
289 | + function createTabHelper(properties) { |
290 | + return Reparenter.createObject(tabComponent, tabContainer, internal.buildContextProperties(properties)); |
291 | + } |
292 | + |
293 | + function closeTab(index, moving) { |
294 | + moving = moving === undefined ? false : moving; |
295 | + |
296 | var tab = tabsModel.get(index) |
297 | + tabsModel.remove(index) |
298 | + |
299 | if (tab) { |
300 | if (!incognito && tab.url.toString().length > 0) { |
301 | closedTabHistory.push({ |
302 | @@ -1005,9 +1057,12 @@ |
303 | index: index |
304 | }) |
305 | } |
306 | - tab.close() |
307 | + |
308 | + // When moving a tab between windows don't close the tab as it has been moved |
309 | + if (!moving) { |
310 | + tab.close() |
311 | + } |
312 | } |
313 | - tabsModel.remove(index) |
314 | if (tabsModel.currentTab) { |
315 | tabsModel.currentTab.load() |
316 | } |
317 | @@ -1163,60 +1218,60 @@ |
318 | // Ctrl+Tab or Ctrl+PageDown: cycle through open tabs |
319 | Shortcut { |
320 | sequence: StandardKey.NextChild |
321 | - enabled: tabContainer.visible || recentView.visible |
322 | + enabled: contentsContainer.visible || recentView.visible |
323 | onActivated: internal.switchToNextTab() |
324 | } |
325 | Shortcut { |
326 | sequence: "Ctrl+PgDown" |
327 | - enabled: tabContainer.visible || recentView.visible |
328 | + enabled: contentsContainer.visible || recentView.visible |
329 | onActivated: internal.switchToNextTab() |
330 | } |
331 | |
332 | // Ctrl+Shift+Tab or Ctrl+PageUp: cycle through open tabs in reverse order |
333 | Shortcut { |
334 | sequence: StandardKey.PreviousChild |
335 | - enabled: tabContainer.visible || recentView.visible |
336 | + enabled: contentsContainer.visible || recentView.visible |
337 | onActivated: internal.switchToPreviousTab() |
338 | } |
339 | Shortcut { |
340 | sequence: "Ctrl+Shift+Tab" |
341 | - enabled: tabContainer.visible || recentView.visible |
342 | + enabled: contentsContainer.visible || recentView.visible |
343 | onActivated: internal.switchToPreviousTab() |
344 | } |
345 | Shortcut { |
346 | sequence: "Ctrl+PgUp" |
347 | - enabled: tabContainer.visible || recentView.visible |
348 | + enabled: contentsContainer.visible || recentView.visible |
349 | onActivated: internal.switchToPreviousTab() |
350 | } |
351 | |
352 | // Ctrl+W or Ctrl+F4: Close the current tab |
353 | Shortcut { |
354 | sequence: StandardKey.Close |
355 | - enabled: tabContainer.visible || recentView.visible |
356 | + enabled: contentsContainer.visible || recentView.visible |
357 | onActivated: internal.closeCurrentTab() |
358 | } |
359 | Shortcut { |
360 | sequence: "Ctrl+F4" |
361 | - enabled: tabContainer.visible || recentView.visible |
362 | + enabled: contentsContainer.visible || recentView.visible |
363 | onActivated: internal.closeCurrentTab() |
364 | } |
365 | |
366 | // Ctrl+Shift+W or Ctrl+Shift+T: Undo close tab |
367 | Shortcut { |
368 | sequence: "Ctrl+Shift+W" |
369 | - enabled: tabContainer.visible || recentView.visible |
370 | + enabled: contentsContainer.visible || recentView.visible |
371 | onActivated: internal.undoCloseTab() |
372 | } |
373 | Shortcut { |
374 | sequence: "Ctrl+Shift+T" |
375 | - enabled: tabContainer.visible || recentView.visible |
376 | + enabled: contentsContainer.visible || recentView.visible |
377 | onActivated: internal.undoCloseTab() |
378 | } |
379 | |
380 | // Ctrl+T: Open a new Tab |
381 | Shortcut { |
382 | sequence: StandardKey.AddTab |
383 | - enabled: tabContainer.visible || recentView.visible || |
384 | + enabled: contentsContainer.visible || recentView.visible || |
385 | bookmarksViewLoader.active || historyViewLoader.active |
386 | onActivated: { |
387 | internal.openUrlInNewTab("", true) |
388 | @@ -1229,24 +1284,24 @@ |
389 | // F6 or Ctrl+L or Alt+D: Select the content in the address bar |
390 | Shortcut { |
391 | sequence: "F6" |
392 | - enabled: tabContainer.visible |
393 | + enabled: contentsContainer.visible |
394 | onActivated: internal.focusAddressBar(true) |
395 | } |
396 | Shortcut { |
397 | sequence: "Ctrl+L" |
398 | - enabled: tabContainer.visible |
399 | + enabled: contentsContainer.visible |
400 | onActivated: internal.focusAddressBar(true) |
401 | } |
402 | Shortcut { |
403 | sequence: "Alt+D" |
404 | - enabled: tabContainer.visible |
405 | + enabled: contentsContainer.visible |
406 | onActivated: internal.focusAddressBar(true) |
407 | } |
408 | |
409 | // Ctrl+D: Toggle bookmarked state on current Tab |
410 | Shortcut { |
411 | sequence: "Ctrl+D" |
412 | - enabled: tabContainer.visible |
413 | + enabled: contentsContainer.visible |
414 | onActivated: { |
415 | if (internal.currentBookmarkOptionsDialog) { |
416 | internal.currentBookmarkOptionsDialog.hide() |
417 | @@ -1263,47 +1318,47 @@ |
418 | // Ctrl+H: Show History |
419 | Shortcut { |
420 | sequence: "Ctrl+H" |
421 | - enabled: tabContainer.visible |
422 | + enabled: contentsContainer.visible |
423 | onActivated: historyViewLoader.active = true |
424 | } |
425 | |
426 | // Ctrl+Shift+O: Show Bookmarks |
427 | Shortcut { |
428 | sequence: "Ctrl+Shift+O" |
429 | - enabled: tabContainer.visible |
430 | + enabled: contentsContainer.visible |
431 | onActivated: bookmarksViewLoader.active = true |
432 | } |
433 | |
434 | // Alt+← or Backspace: Goes to the previous page in history |
435 | Shortcut { |
436 | sequence: StandardKey.Back |
437 | - enabled: tabContainer.visible |
438 | + enabled: contentsContainer.visible |
439 | onActivated: internal.historyGoBack() |
440 | } |
441 | |
442 | // Alt+→ or Shift+Backspace: Goes to the next page in history |
443 | Shortcut { |
444 | sequence: StandardKey.Forward |
445 | - enabled: tabContainer.visible |
446 | + enabled: contentsContainer.visible |
447 | onActivated: internal.historyGoForward() |
448 | } |
449 | |
450 | // F5 or Ctrl+R: Reload current Tab |
451 | Shortcut { |
452 | sequence: StandardKey.Refresh |
453 | - enabled: tabContainer.visible |
454 | + enabled: contentsContainer.visible |
455 | onActivated: if (currentWebview) currentWebview.reload() |
456 | } |
457 | Shortcut { |
458 | sequence: "F5" |
459 | - enabled: tabContainer.visible |
460 | + enabled: contentsContainer.visible |
461 | onActivated: if (currentWebview) currentWebview.reload() |
462 | } |
463 | |
464 | // Ctrl+F: Find in Page |
465 | Shortcut { |
466 | sequence: StandardKey.Find |
467 | - enabled: tabContainer.visible && !newTabViewLoader.active |
468 | + enabled: contentsContainer.visible && !newTabViewLoader.active |
469 | onActivated: chrome.findInPageMode = true |
470 | } |
471 | |
472 | @@ -1400,4 +1455,78 @@ |
473 | source: "ContentPickerDialog.qml" |
474 | asynchronous: true |
475 | } |
476 | + |
477 | + DropArea { |
478 | + id: dropArea |
479 | + anchors { |
480 | + fill: parent |
481 | + } |
482 | + keys: ["webbrowser/tab-" + (incognito ? "incognito" : "public")] |
483 | + |
484 | + readonly property real heightThreshold: chrome.tabsBarHeight |
485 | + |
486 | + onDropped: { |
487 | + // IgnoreAction - no DropArea accepted so New Window |
488 | + // MoveAction - DropArea accept but different window |
489 | + // CopyAction - DropArea accept but same window |
490 | + |
491 | + if (drag.y > heightThreshold) { |
492 | + // Dropped in bottom area, creating new window |
493 | + drop.accept(Qt.IgnoreAction); |
494 | + } else if (drag.source.tabWindow === thisWindow) { |
495 | + // Dropped in same window |
496 | + drop.accept(Qt.CopyAction); |
497 | + } else { |
498 | + // Dropped in new window, moving tab |
499 | + |
500 | + thisWindow.addExistingTab(drag.source.tab); |
501 | + thisWindow.tabsModel.currentIndex = window.tabsModel.count - 1; |
502 | + thisWindow.show(); |
503 | + thisWindow.requestActivate(); |
504 | + |
505 | + thisWindow.tabsModel.currentTab.load(); |
506 | + |
507 | + drop.accept(Qt.MoveAction); |
508 | + } |
509 | + } |
510 | + onEntered: { |
511 | + thisWindow.raise() |
512 | + thisWindow.requestActivate(); |
513 | + } |
514 | + onPositionChanged: { |
515 | + if (drag.source.tabWindow === thisWindow && drag.y < heightThreshold) { |
516 | + // tab drag is within same window and in chrome |
517 | + // so reorder tabs by setting tabDelegate x position |
518 | + drag.source.x = drag.x - (drag.source.width / 2); |
519 | + } |
520 | + } |
521 | + |
522 | + Rectangle { |
523 | + anchors { |
524 | + left: parent.left |
525 | + right: parent.right |
526 | + top: parent.top |
527 | + } |
528 | + color: "#FFF" |
529 | + height: dropArea.heightThreshold |
530 | + opacity: { |
531 | + // Only hide the white shade when this is the active window |
532 | + // and there is no drag being performed or the drag event is |
533 | + // over the tabs bar |
534 | + if (thisWindow.active && !DragHelper.dragging) { |
535 | + 0 |
536 | + } else if (dropArea.containsDrag && dropArea.drag.y <= dropArea.heightThreshold) { |
537 | + 0 |
538 | + } else { |
539 | + 0.6 |
540 | + } |
541 | + } |
542 | + |
543 | + Behavior on opacity { |
544 | + NumberAnimation { |
545 | + |
546 | + } |
547 | + } |
548 | + } |
549 | + } |
550 | } |
551 | |
552 | === modified file 'src/app/webbrowser/BrowserTab.qml' |
553 | --- src/app/webbrowser/BrowserTab.qml 2016-10-07 11:47:05 +0000 |
554 | +++ src/app/webbrowser/BrowserTab.qml 2016-11-30 14:23:08 +0000 |
555 | @@ -98,6 +98,17 @@ |
556 | } |
557 | } |
558 | |
559 | + function loadExisting(existingTab) { |
560 | + if (!webview && !internal.incubator) { |
561 | + // Reparent the webview and any other vars |
562 | + existingTab.webview.parent = webviewContainer; |
563 | + existingTab.webview.tab = tab; |
564 | + |
565 | + // Set the webview into this window |
566 | + webviewContainer.webview = existingTab.webview; |
567 | + } |
568 | + } |
569 | + |
570 | function unload() { |
571 | if (webview) { |
572 | initialUrl = webview.url |
573 | @@ -118,11 +129,17 @@ |
574 | } |
575 | } |
576 | |
577 | - function close() { |
578 | + function close(reparentDestroy) { |
579 | var _url = url |
580 | unload() |
581 | if (_url.toString()) PreviewManager.checkDelete(_url) |
582 | - destroy() |
583 | + |
584 | + if (reparentDestroy || reparentDestroy === undefined) { |
585 | + // Destroys context and object |
586 | + Reparenter.destroyContextAndObject(tab); |
587 | + } else { |
588 | + destroy(); |
589 | + } |
590 | } |
591 | |
592 | QtObject { |
593 | |
594 | === modified file 'src/app/webbrowser/CMakeLists.txt' |
595 | --- src/app/webbrowser/CMakeLists.txt 2015-12-10 09:06:06 +0000 |
596 | +++ src/app/webbrowser/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
597 | @@ -33,7 +33,9 @@ |
598 | |
599 | set(WEBBROWSER_APP_SRC |
600 | cache-deleter.cpp |
601 | + drag-helper.cpp |
602 | file-operations.cpp |
603 | + reparenter.cpp |
604 | searchengine.cpp |
605 | webbrowser-app.cpp |
606 | ) |
607 | |
608 | === modified file 'src/app/webbrowser/Chrome.qml' |
609 | --- src/app/webbrowser/Chrome.qml 2016-10-10 17:00:52 +0000 |
610 | +++ src/app/webbrowser/Chrome.qml 2016-11-30 14:23:08 +0000 |
611 | @@ -42,10 +42,13 @@ |
612 | property alias availableHeight: navigationBar.availableHeight |
613 | readonly property alias bookmarkTogglePlaceHolder: navigationBar.bookmarkTogglePlaceHolder |
614 | property bool touchEnabled: true |
615 | + readonly property real tabsBarHeight: tabsBar.height + content.anchors.topMargin |
616 | + property BrowserWindow thisWindow |
617 | |
618 | signal switchToTab(int index) |
619 | signal requestNewTab(int index, bool makeCurrent) |
620 | - signal tabClosed(int index) |
621 | + signal requestNewWindowFromTab(var tab, var callback) |
622 | + signal tabClosed(int index, bool moving) |
623 | |
624 | backgroundColor: incognito ? UbuntuColors.darkGrey : "#ffffff" |
625 | |
626 | @@ -75,6 +78,7 @@ |
627 | "model": Qt.binding(function () {return chrome.tabsModel}), |
628 | "incognito": Qt.binding(function () {return chrome.incognito}), |
629 | "fgColor": Qt.binding(function () {return navigationBar.fgColor}), |
630 | + "thisWindow": Qt.binding(function () {return chrome.thisWindow}), |
631 | "touchEnabled": Qt.binding(function () {return chrome.touchEnabled}) |
632 | }) |
633 | } |
634 | @@ -84,7 +88,8 @@ |
635 | |
636 | onSwitchToTab: chrome.switchToTab(index) |
637 | onRequestNewTab: chrome.requestNewTab(index, makeCurrent) |
638 | - onTabClosed: chrome.tabClosed(index) |
639 | + onRequestNewWindowFromTab: chrome.requestNewWindowFromTab(tab, callback) |
640 | + onTabClosed: chrome.tabClosed(index, moving) |
641 | } |
642 | asynchronous: true |
643 | |
644 | @@ -130,4 +135,9 @@ |
645 | } |
646 | |
647 | loadProgress: (loading && webview) ? webview.loadProgress : 0 |
648 | + |
649 | + // If the webview changes the use the loading state of the new webview |
650 | + // otherwise opening a new tab/window while another webview was loading |
651 | + // can cause a progress bar to be left behind at zero percent pad.lv/1638337 |
652 | + onWebviewChanged: loading = webview ? webview.loading : false |
653 | } |
654 | |
655 | === modified file 'src/app/webbrowser/ContextMenuMobile.qml' |
656 | --- src/app/webbrowser/ContextMenuMobile.qml 2016-09-19 12:08:03 +0000 |
657 | +++ src/app/webbrowser/ContextMenuMobile.qml 2016-11-30 14:23:08 +0000 |
658 | @@ -23,6 +23,8 @@ |
659 | import com.canonical.Oxide 1.8 as Oxide |
660 | |
661 | Popups.Dialog { |
662 | + id: contextMenu |
663 | + |
664 | property QtObject contextModel: model |
665 | property ActionList actions: null |
666 | |
667 | @@ -119,7 +121,7 @@ |
668 | } |
669 | } |
670 | |
671 | - onTriggered: contextModel.close() |
672 | + onTriggered: contextMenu.hide() |
673 | } |
674 | } |
675 | |
676 | @@ -138,7 +140,13 @@ |
677 | fontSize: "x-small" |
678 | text: i18n.tr("Cancel") |
679 | } |
680 | - onTriggered: contextModel.close() |
681 | + onTriggered: contextMenu.hide() |
682 | + } |
683 | + |
684 | + onVisibleChanged: { |
685 | + if (!visible) { |
686 | + contextModel.close() |
687 | + } |
688 | } |
689 | |
690 | // adjust default dialog visuals to custom requirements for the context menu |
691 | |
692 | === modified file 'src/app/webbrowser/Suggestions.qml' |
693 | --- src/app/webbrowser/Suggestions.qml 2015-08-24 16:51:47 +0000 |
694 | +++ src/app/webbrowser/Suggestions.qml 2016-11-30 14:23:08 +0000 |
695 | @@ -75,7 +75,7 @@ |
696 | title: selected ? modelData.title : Highlight.highlightTerms(modelData.title, searchTerms) |
697 | subtitle: modelData.displayUrl ? (selected ? modelData.url : |
698 | Highlight.highlightTerms(modelData.url, searchTerms)) : "" |
699 | - icon: modelData.icon |
700 | + icon: modelData.icon || "" |
701 | selected: suggestionsList.activeFocus && ListView.isCurrentItem |
702 | |
703 | onActivated: suggestions.activated(modelData.url) |
704 | |
705 | === modified file 'src/app/webbrowser/TabComponent.qml' |
706 | --- src/app/webbrowser/TabComponent.qml 2016-10-11 16:17:11 +0000 |
707 | +++ src/app/webbrowser/TabComponent.qml 2016-11-30 14:23:08 +0000 |
708 | @@ -34,10 +34,22 @@ |
709 | |
710 | BrowserTab { |
711 | anchors.fill: parent |
712 | - incognito: browser.incognito |
713 | - current: tabsModel && tabsModel.currentTab === this |
714 | + incognito: browser ? browser.incognito : false |
715 | + current: browser ? browser.tabsModel && browser.tabsModel.currentTab === this : false |
716 | focus: current |
717 | |
718 | + property var bottomEdgeHandle |
719 | + property var browser |
720 | + property var chrome |
721 | + property var chromeController |
722 | + property var contentHandlerLoader |
723 | + property var downloadDialogLoader |
724 | + property var downloadsViewLoader |
725 | + property var filePickerLoader |
726 | + property var internal |
727 | + property var recentView |
728 | + property var tabsModel |
729 | + |
730 | Item { |
731 | id: contextualMenuTarget |
732 | visible: false |
733 | @@ -49,18 +61,18 @@ |
734 | property BrowserTab tab |
735 | readonly property bool current: tab.current |
736 | |
737 | - currentWebview: browser.currentWebview |
738 | - filePicker: filePickerLoader.item |
739 | + currentWebview: browser ? browser.currentWebview : null |
740 | + filePicker: filePickerLoader ? filePickerLoader.item : null |
741 | |
742 | anchors.fill: parent |
743 | |
744 | focus: true |
745 | |
746 | - enabled: current && !bottomEdgeHandle.dragging && !recentView.visible && tabContainer.focus |
747 | + enabled: current && !bottomEdgeHandle.dragging && !recentView.visible && parent.focus |
748 | |
749 | locationBarController { |
750 | - height: chrome.height |
751 | - mode: chromeController.defaultMode |
752 | + height: chrome ? chrome.height : 0 |
753 | + mode: chromeController ? chromeController.defaultMode : null |
754 | } |
755 | |
756 | //experimental.preferences.developerExtrasEnabled: developerExtrasEnabled |
757 | @@ -115,7 +127,7 @@ |
758 | } |
759 | Actions.Share { |
760 | objectName: "ShareContextualAction" |
761 | - enabled: (contentHandlerLoader.status == Loader.Ready) && contextModel && |
762 | + enabled: (contentHandlerLoader && contentHandlerLoader.status == Loader.Ready) && contextModel && |
763 | (contextModel.linkUrl.toString() || contextModel.selectionText) |
764 | onTriggered: { |
765 | if (contextModel.linkUrl.toString()) { |
766 | @@ -135,9 +147,10 @@ |
767 | Actions.CopyImage { |
768 | objectName: "CopyImageContextualAction" |
769 | enabled: contextModel && |
770 | - (contextModel.mediaType === Oxide.WebView.MediaTypeImage) && |
771 | - contextModel.srcUrl.toString() |
772 | - onTriggered: Clipboard.push(["text/plain", contextModel.srcUrl.toString()]) |
773 | + ((contextModel.mediaType === Oxide.WebView.MediaTypeImage) || |
774 | + (contextModel.mediaType === Oxide.WebView.MediaTypeCanvas)) && |
775 | + contextModel.hasImageContents |
776 | + onTriggered: contextModel.copyImage() |
777 | } |
778 | Actions.SaveImage { |
779 | objectName: "SaveImageContextualAction" |
780 | @@ -237,10 +250,10 @@ |
781 | Component.onCompleted: webviewimpl.contextMenuOnCompleted(this) |
782 | } |
783 | } |
784 | - contextMenu: browser.wide ? contextMenuWideComponent : contextMenuNarrowComponent |
785 | + contextMenu: browser && browser.wide ? contextMenuWideComponent : contextMenuNarrowComponent |
786 | |
787 | onNewViewRequested: { |
788 | - var tab = tabComponent.createObject(tabContainer, {"request": request}) |
789 | + var tab = browser.createTab({"request": request}) |
790 | var setCurrent = (request.disposition == Oxide.NewViewRequest.DispositionNewForegroundTab) |
791 | internal.addTab(tab, setCurrent) |
792 | if (setCurrent) tabContainer.forceActiveFocus() |
793 | @@ -256,9 +269,14 @@ |
794 | break |
795 | } |
796 | } |
797 | + |
798 | + // tab.close() destroys the context so add new tab before destroy if required |
799 | + if (tabsModel.count === 0) { |
800 | + internal.openUrlInNewTab("", true, true) |
801 | + } |
802 | + |
803 | tab.close() |
804 | - } |
805 | - if (tabsModel.count === 0) { |
806 | + } else if (tabsModel.count === 0) { |
807 | internal.openUrlInNewTab("", true, true) |
808 | } |
809 | } |
810 | |
811 | === modified file 'src/app/webbrowser/TabItem.qml' |
812 | --- src/app/webbrowser/TabItem.qml 2016-10-10 09:13:53 +0000 |
813 | +++ src/app/webbrowser/TabItem.qml 2016-11-30 14:23:08 +0000 |
814 | @@ -39,7 +39,7 @@ |
815 | property color fgColor: Theme.palette.normal.baseText |
816 | |
817 | property bool touchEnabled: true |
818 | - |
819 | + |
820 | readonly property bool showCloseIcon: closeIcon.x > units.gu(1) + tabItem.width / 2 |
821 | |
822 | signal selected() |
823 | @@ -64,7 +64,7 @@ |
824 | verticalCenter: parent.verticalCenter |
825 | } |
826 | shouldCache: !incognito |
827 | - |
828 | + |
829 | // Scale width and height of favicon when tabWidth becomes small |
830 | height: width |
831 | width: Math.min(units.dp(16), Math.min(tabItem.width - anchors.leftMargin * 2, tabItem.height)) |
832 | |
833 | === modified file 'src/app/webbrowser/TabsBar.qml' |
834 | --- src/app/webbrowser/TabsBar.qml 2016-10-05 11:03:05 +0000 |
835 | +++ src/app/webbrowser/TabsBar.qml 2016-11-30 14:23:08 +0000 |
836 | @@ -19,6 +19,10 @@ |
837 | import QtQuick 2.4 |
838 | import Ubuntu.Components 1.3 |
839 | import Ubuntu.Components.Popups 1.3 |
840 | + |
841 | +import webbrowserapp.private 0.1 |
842 | + |
843 | +import "." |
844 | import ".." |
845 | |
846 | Item { |
847 | @@ -26,19 +30,21 @@ |
848 | |
849 | property alias model: repeater.model |
850 | |
851 | + property BrowserWindow thisWindow |
852 | + |
853 | property real minTabWidth: 0 //units.gu(6) |
854 | property real maxTabWidth: units.gu(20) |
855 | property real tabWidth: model ? Math.max(Math.min(tabsContainer.maxWidth / model.count, maxTabWidth), minTabWidth) : 0 |
856 | |
857 | // Minimum size of the larger tab |
858 | readonly property real minActiveTabWidth: units.gu(10) |
859 | - |
860 | + |
861 | // When there is a larger tab, calc the smaller tab size |
862 | readonly property real nonActiveTabWidth: (tabsContainer.maxWidth - minActiveTabWidth) / Math.max(model.count - 1, 1) |
863 | |
864 | // The size of the right margin of the tab |
865 | readonly property real rightMargin: units.dp(1) |
866 | - |
867 | + |
868 | // Whether there will be one larger tab or not |
869 | readonly property bool unevenTabWidth: tabWidth + rightMargin < minActiveTabWidth |
870 | |
871 | @@ -50,7 +56,8 @@ |
872 | |
873 | signal switchToTab(int index) |
874 | signal requestNewTab(int index, bool makeCurrent) |
875 | - signal tabClosed(int index) |
876 | + signal requestNewWindowFromTab(var tab, var callback) |
877 | + signal tabClosed(int index, bool moving) |
878 | |
879 | MouseArea { |
880 | anchors.fill: parent |
881 | @@ -110,9 +117,18 @@ |
882 | onTriggered: menu.tab.reload() |
883 | } |
884 | Action { |
885 | + objectName: "tab_action_move_to_new_window" |
886 | + text: i18n.tr("Move to New Window") |
887 | + onTriggered: { |
888 | + // callback function only removes from model |
889 | + // and not destroy as webview is in new window |
890 | + root.requestNewWindowFromTab(menu.tab, function() { root.tabClosed(menu.targetIndex, true); }); |
891 | + } |
892 | + } |
893 | + Action { |
894 | objectName: "tab_action_close_tab" |
895 | text: i18n.tr("Close Tab") |
896 | - onTriggered: root.tabClosed(menu.targetIndex) |
897 | + onTriggered: root.tabClosed(menu.targetIndex, false) |
898 | } |
899 | } |
900 | } |
901 | @@ -130,6 +146,10 @@ |
902 | width: tabWidth * root.model.count |
903 | readonly property real maxWidth: root.width - newTabButton.width - units.gu(2) |
904 | |
905 | + readonly property int maxYDiff: height / 4 |
906 | + |
907 | + function sign(number) { return number / Math.abs(number); } |
908 | + |
909 | Repeater { |
910 | id: repeater |
911 | |
912 | @@ -140,26 +160,32 @@ |
913 | objectName: "tabDelegate" |
914 | |
915 | readonly property int tabIndex: index |
916 | + readonly property var tab: root.model.get(index) |
917 | + readonly property BrowserWindow tabWindow: root.thisWindow |
918 | |
919 | - anchors.top: tabsContainer.top |
920 | - |
921 | + property real rightMargin: units.dp(1) |
922 | width: getSize(index) |
923 | height: tabsContainer.height |
924 | + y: tabsContainer.y // don't use anchor otherwise drag doesn't work |
925 | |
926 | acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton |
927 | readonly property bool dragging: drag.active |
928 | drag { |
929 | target: (pressedButtons === Qt.LeftButton) ? tabDelegate : null |
930 | - axis: Drag.XAxis |
931 | + // FIXME: disable drag and drop on mir pad.lv/1627013 |
932 | + axis: __platformName != "ubuntumirclient" ? Drag.XAndYAxis : Drag.XAxis |
933 | minimumX: 0 |
934 | maximumX: root.width - tabDelegate.width |
935 | filterChildren: true |
936 | } |
937 | |
938 | TabItem { |
939 | - anchors.fill: parent |
940 | - |
941 | active: tabIndex === root.model.currentIndex |
942 | + anchors { |
943 | + left: parent.left |
944 | + right: parent.right |
945 | + } |
946 | + height: tabsContainer.height |
947 | hoverable: true |
948 | incognito: root.incognito |
949 | title: model.title ? model.title : (model.url.toString() ? model.url : i18n.tr("New tab")) |
950 | @@ -170,7 +196,11 @@ |
951 | |
952 | rightMargin: root.rightMargin |
953 | |
954 | - onClosed: root.tabClosed(index) |
955 | + // Keep the visual tabitem within maxYDiff of starting point when |
956 | + // dragging vertically so that it doesn't cover other elements |
957 | + y: Math.abs(parent.y) > tabsContainer.maxYDiff ? (tabsContainer.sign(parent.y) * tabsContainer.maxYDiff) - parent.y : 0 |
958 | + |
959 | + onClosed: root.tabClosed(index, false) |
960 | onSelected: root.switchToTab(index) |
961 | onContextMenu: PopupUtils.open(contextualOptionsComponent, tabDelegate, {"targetIndex": index}) |
962 | } |
963 | @@ -180,15 +210,82 @@ |
964 | property: "reordering" |
965 | value: dragging |
966 | } |
967 | - |
968 | + |
969 | Behavior on width { NumberAnimation { duration: 250 } } |
970 | |
971 | Binding on x { |
972 | - when: !dragging |
973 | + when: !dragging && !DragHelper.dragging |
974 | value: getLeftX(index) |
975 | } |
976 | |
977 | - Behavior on x { NumberAnimation { duration: 250 } } |
978 | + Behavior on x { |
979 | + NumberAnimation { |
980 | + duration: 250 |
981 | + } |
982 | + } |
983 | + |
984 | + NumberAnimation { |
985 | + id: resetVerticalAnimation |
986 | + target: tabDelegate |
987 | + duration: 250 |
988 | + property: "y" |
989 | + to: 0 |
990 | + } |
991 | + |
992 | + onPositionChanged: { |
993 | + // FIXME: disable drag and drop on mir pad.lv/1627013 |
994 | + if (Math.abs(y) > height && __platformName != "ubuntumirclient") { |
995 | + // Reset visual position of tab delegate |
996 | + resetVerticalAnimation.start(); |
997 | + |
998 | + if (mouse.buttons === Qt.LeftButton) { |
999 | + // Generate tab preview for drag handle |
1000 | + DragHelper.expectedAction = Qt.IgnoreAction | Qt.CopyAction | Qt.MoveAction |
1001 | + DragHelper.mimeType = "webbrowser/tab-" + (root.incognito ? "incognito" : "public") |
1002 | + DragHelper.previewBorderWidth = units.gu(1) |
1003 | + DragHelper.previewSize = Qt.size(units.gu(35), units.gu(22.5)) |
1004 | + DragHelper.previewTopCrop = chrome.height |
1005 | + DragHelper.previewUrl = PreviewManager.previewPathFromUrl(tab.url) |
1006 | + DragHelper.source = tabDelegate |
1007 | + |
1008 | + var dropAction = DragHelper.execDrag(tab.url); |
1009 | + |
1010 | + // IgnoreAction - no DropArea accepted so New Window |
1011 | + // MoveAction - DropArea accept but different window |
1012 | + // CopyAction - DropArea accept but same window |
1013 | + |
1014 | + if (dropAction === Qt.MoveAction) { |
1015 | + // Moved into another window |
1016 | + |
1017 | + // drag.active does not become false when |
1018 | + // closing the tab so set reordering back |
1019 | + repeater.reordering = false; |
1020 | + |
1021 | + // Just remove from model and do not destory |
1022 | + // as webview is used in other window |
1023 | + root.tabClosed(index, true); |
1024 | + } else if (dropAction === Qt.CopyAction) { |
1025 | + // Moved into the same window |
1026 | + |
1027 | + // So no action |
1028 | + } else if (dropAction === Qt.IgnoreAction) { |
1029 | + // Moved outside of any window |
1030 | + |
1031 | + // drag.active does not become false when |
1032 | + // closing the tab so set reordering back |
1033 | + repeater.reordering = false; |
1034 | + |
1035 | + // callback function only removes from model |
1036 | + // and not destroy as webview is in new window |
1037 | + root.requestNewWindowFromTab(tab, function() { root.tabClosed(index, true); }) |
1038 | + } else { |
1039 | + // Unknown state |
1040 | + console.debug("Unknown drop action:", dropAction); |
1041 | + } |
1042 | + } |
1043 | + } |
1044 | + } |
1045 | + onReleased: resetVerticalAnimation.start(); |
1046 | |
1047 | function getLeftX(index) { |
1048 | if (unevenTabWidth) { |
1049 | @@ -204,7 +301,7 @@ |
1050 | return index * (tabWidth + rightMargin) |
1051 | } |
1052 | } |
1053 | - |
1054 | + |
1055 | function getSize(index) { |
1056 | if (unevenTabWidth) { |
1057 | // Uneven tabs so use large or small depending which index |
1058 | @@ -217,7 +314,7 @@ |
1059 | return tabWidth + rightMargin |
1060 | } |
1061 | } |
1062 | - |
1063 | + |
1064 | onXChanged: { |
1065 | if (!dragging) return |
1066 | |
1067 | |
1068 | === modified file 'src/app/webbrowser/TabsList.qml' |
1069 | --- src/app/webbrowser/TabsList.qml 2016-02-25 14:54:54 +0000 |
1070 | +++ src/app/webbrowser/TabsList.qml 2016-11-30 14:23:08 +0000 |
1071 | @@ -109,14 +109,14 @@ |
1072 | incognito: tabslist.incognito |
1073 | tab: model.tab |
1074 | showContent: ((index > 0) && (delegate.y > flickable.contentY)) || |
1075 | - !(tab.webview && tab.webview.visible) |
1076 | + !(tab && tab.webview && tab.webview.visible) |
1077 | |
1078 | Binding { |
1079 | // Change the height of the location bar controller |
1080 | // for the first webview only, and only while the tabs |
1081 | // list view is visible. |
1082 | when: tabslist.visible && (index == 0) |
1083 | - target: tab.webview ? tab.webview.locationBarController : null |
1084 | + target: tab && tab.webview ? tab.webview.locationBarController : null |
1085 | property: "height" |
1086 | value: invisibleTabChrome.height |
1087 | } |
1088 | |
1089 | === added file 'src/app/webbrowser/drag-helper.cpp' |
1090 | --- src/app/webbrowser/drag-helper.cpp 1970-01-01 00:00:00 +0000 |
1091 | +++ src/app/webbrowser/drag-helper.cpp 2016-11-30 14:23:08 +0000 |
1092 | @@ -0,0 +1,203 @@ |
1093 | +/* |
1094 | + * Copyright 2016 Canonical Ltd. |
1095 | + * |
1096 | + * This file is part of webbrowser-app. |
1097 | + * |
1098 | + * webbrowser-app is free software; you can redistribute it and/or modify |
1099 | + * it under the terms of the GNU General Public License as published by |
1100 | + * the Free Software Foundation; version 3. |
1101 | + * |
1102 | + * webbrowser-app is distributed in the hope that it will be useful, |
1103 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1104 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1105 | + * GNU General Public License for more details. |
1106 | + * |
1107 | + * You should have received a copy of the GNU General Public License |
1108 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1109 | + */ |
1110 | + |
1111 | +#include "drag-helper.h" |
1112 | + |
1113 | +#include <QtCore/QMimeData> |
1114 | +#include <QtCore/QPoint> |
1115 | +#include <QtCore/QSize> |
1116 | +#include <QtCore/QString> |
1117 | +#include <QtGui/QDrag> |
1118 | +#include <QtGui/QDropEvent> |
1119 | +#include <QtGui/QPainter> |
1120 | +#include <QtGui/QPen> |
1121 | +#include <QtGui/QPixmap> |
1122 | +#include <QtQuick/QQuickItem> |
1123 | + |
1124 | +DragHelper::DragHelper() |
1125 | + : QObject(), |
1126 | + m_active(false), |
1127 | + m_dragging(false), |
1128 | + m_expected_action(Qt::IgnoreAction), |
1129 | + m_mime_type(QStringLiteral("webbrowser/tab")), |
1130 | + m_preview_border_width(8), |
1131 | + m_preview_size(QSizeF(200, 150)), |
1132 | + m_preview_top_crop(0), |
1133 | + m_preview_url(""), |
1134 | + m_source(Q_NULLPTR) |
1135 | +{ |
1136 | + |
1137 | +} |
1138 | + |
1139 | +QPixmap DragHelper::drawPixmapWithBorder(QPixmap pixmap, int borderWidth, QColor color) |
1140 | +{ |
1141 | + // Create a transparent pixmap to draw to |
1142 | + QPixmap output(pixmap.width() + borderWidth * 2, pixmap.height() + borderWidth * 2); |
1143 | + output.fill(QColor(0, 0, 0, 0)); |
1144 | + |
1145 | + // Draw the pixmap with space around the edge for a border |
1146 | + QPainter borderPainter(&output); |
1147 | + borderPainter.setRenderHint(QPainter::Antialiasing); |
1148 | + borderPainter.drawPixmap(borderWidth, borderWidth, pixmap); |
1149 | + |
1150 | + // Define a pen to use for the border |
1151 | + QPen borderPen; |
1152 | + borderPen.setColor(color); |
1153 | + borderPen.setJoinStyle(Qt::MiterJoin); |
1154 | + borderPen.setStyle(Qt::SolidLine); |
1155 | + borderPen.setWidth(borderWidth); |
1156 | + |
1157 | + // Set the pen and draw the border |
1158 | + borderPainter.setPen(borderPen); |
1159 | + borderPainter.drawRect(borderWidth / 2, borderWidth / 2, |
1160 | + output.width() - borderWidth, output.height() - borderWidth); |
1161 | + |
1162 | + return output; |
1163 | +} |
1164 | + |
1165 | +Qt::DropAction DragHelper::execDrag(QString tabId) |
1166 | +{ |
1167 | + QDrag *drag = new QDrag(m_source); |
1168 | + |
1169 | + // Create a mimedata object to use for the drag |
1170 | + QMimeData *mimeData = new QMimeData; |
1171 | + mimeData->setData(mimeType(), tabId.toLatin1()); |
1172 | + |
1173 | + // Get a bordered pixmap of the previewUrl |
1174 | + QSize size = previewSize().toSize(); |
1175 | + |
1176 | + QPixmap pixmap = drawPixmapWithBorder(getPreviewUrlAsPixmap(size.width(), size.height()), |
1177 | + previewBorderWidth(), QColor(205, 205, 205, 255 * 0.6)); // #cdcdcd |
1178 | + |
1179 | + // Setup the drag and then execute it |
1180 | + drag->setHotSpot(QPoint(size.width() * 0.1, size.height() * 0.1)); |
1181 | + drag->setMimeData(mimeData); |
1182 | + drag->setPixmap(pixmap); |
1183 | + |
1184 | + setDragging(true); |
1185 | + |
1186 | + Qt::DropAction action = drag->exec(expectedAction()); |
1187 | + |
1188 | + setDragging(false); |
1189 | + |
1190 | + return action; |
1191 | +} |
1192 | + |
1193 | +QPixmap DragHelper::getPreviewUrlAsPixmap(int width, int height) |
1194 | +{ |
1195 | + QSize pixmapSize(width, height); |
1196 | + QPixmap pixmap(previewUrl()); |
1197 | + |
1198 | + if (pixmap.isNull()) { |
1199 | + // If loading pixmap failed, draw a white rectangle |
1200 | + pixmap = QPixmap(pixmapSize); |
1201 | + QPainter painter(&pixmap); |
1202 | + painter.eraseRect(0, 0, pixmapSize.width(), pixmapSize.height()); |
1203 | + painter.fillRect(0, 0, pixmapSize.width(), pixmapSize.height(), QColor(255, 255, 255, 255)); |
1204 | + } else { |
1205 | + // Crop transparent part off the top of the image |
1206 | + pixmap = pixmap.copy(0, previewTopCrop(), pixmap.width(), pixmap.height() - previewTopCrop()); |
1207 | + |
1208 | + // Scale image to fit the expected size |
1209 | + pixmap = pixmap.scaled(pixmapSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); |
1210 | + } |
1211 | + |
1212 | + return pixmap; |
1213 | +} |
1214 | + |
1215 | +void DragHelper::setActive(bool active) |
1216 | +{ |
1217 | + if (m_active != active) { |
1218 | + m_active = active; |
1219 | + |
1220 | + Q_EMIT activeChanged(); |
1221 | + } |
1222 | +} |
1223 | + |
1224 | +void DragHelper::setDragging(bool dragging) |
1225 | +{ |
1226 | + if (m_dragging != dragging) { |
1227 | + m_dragging = dragging; |
1228 | + |
1229 | + Q_EMIT draggingChanged(); |
1230 | + } |
1231 | +} |
1232 | + |
1233 | +void DragHelper::setExpectedAction(Qt::DropAction expectedAction) |
1234 | +{ |
1235 | + if (m_expected_action != expectedAction) { |
1236 | + m_expected_action = expectedAction; |
1237 | + |
1238 | + Q_EMIT expectedActionChanged(); |
1239 | + } |
1240 | +} |
1241 | + |
1242 | +void DragHelper::setMimeType(QString mimeType) |
1243 | +{ |
1244 | + if (m_mime_type != mimeType) { |
1245 | + m_mime_type = mimeType; |
1246 | + |
1247 | + Q_EMIT mimeTypeChanged(); |
1248 | + } |
1249 | +} |
1250 | + |
1251 | +void DragHelper::setPreviewBorderWidth(int previewBorderWidth) |
1252 | +{ |
1253 | + if (m_preview_border_width != previewBorderWidth) { |
1254 | + m_preview_border_width = previewBorderWidth; |
1255 | + |
1256 | + Q_EMIT previewBorderWidthChanged(); |
1257 | + } |
1258 | +} |
1259 | + |
1260 | +void DragHelper::setPreviewSize(QSizeF previewSize) |
1261 | +{ |
1262 | + if (m_preview_size != previewSize) { |
1263 | + m_preview_size = previewSize; |
1264 | + |
1265 | + Q_EMIT previewSizeChanged(); |
1266 | + } |
1267 | +} |
1268 | + |
1269 | +void DragHelper::setPreviewTopCrop(int previewTopCrop) |
1270 | +{ |
1271 | + if (m_preview_top_crop != previewTopCrop) { |
1272 | + m_preview_top_crop = previewTopCrop; |
1273 | + |
1274 | + Q_EMIT previewTopCropChanged(); |
1275 | + } |
1276 | +} |
1277 | + |
1278 | +void DragHelper::setPreviewUrl(QString previewUrl) |
1279 | +{ |
1280 | + if (m_preview_url != previewUrl) { |
1281 | + m_preview_url = previewUrl; |
1282 | + |
1283 | + Q_EMIT previewUrlChanged(); |
1284 | + } |
1285 | +} |
1286 | + |
1287 | +void DragHelper::setSource(QQuickItem *source) |
1288 | +{ |
1289 | + if (m_source != source) { |
1290 | + m_source = source; |
1291 | + |
1292 | + Q_EMIT sourceChanged(); |
1293 | + } |
1294 | +} |
1295 | + |
1296 | |
1297 | === added file 'src/app/webbrowser/drag-helper.h' |
1298 | --- src/app/webbrowser/drag-helper.h 1970-01-01 00:00:00 +0000 |
1299 | +++ src/app/webbrowser/drag-helper.h 2016-11-30 14:23:08 +0000 |
1300 | @@ -0,0 +1,91 @@ |
1301 | +/* |
1302 | + * Copyright 2016 Canonical Ltd. |
1303 | + * |
1304 | + * This file is part of webbrowser-app. |
1305 | + * |
1306 | + * webbrowser-app is free software; you can redistribute it and/or modify |
1307 | + * it under the terms of the GNU General Public License as published by |
1308 | + * the Free Software Foundation; version 3. |
1309 | + * |
1310 | + * webbrowser-app is distributed in the hope that it will be useful, |
1311 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1312 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1313 | + * GNU General Public License for more details. |
1314 | + * |
1315 | + * You should have received a copy of the GNU General Public License |
1316 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1317 | + */ |
1318 | + |
1319 | +#ifndef __DRAGHELPER_H__ |
1320 | +#define __DRAGHELPER_H__ |
1321 | + |
1322 | +#include <QtCore/QSizeF> |
1323 | +#include <QtCore/QObject> |
1324 | +#include <QtCore/QString> |
1325 | +#include <QtGui/QColor> |
1326 | +#include <QtGui/QMouseEvent> |
1327 | + |
1328 | +class QQuickItem; |
1329 | + |
1330 | +class DragHelper : public QObject |
1331 | +{ |
1332 | + Q_OBJECT |
1333 | + |
1334 | + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) |
1335 | + Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) |
1336 | + Q_PROPERTY(Qt::DropAction expectedAction READ expectedAction WRITE setExpectedAction NOTIFY expectedActionChanged) |
1337 | + Q_PROPERTY(QString mimeType READ mimeType WRITE setMimeType NOTIFY mimeTypeChanged) |
1338 | + Q_PROPERTY(int previewBorderWidth READ previewBorderWidth WRITE setPreviewBorderWidth NOTIFY previewBorderWidthChanged) |
1339 | + Q_PROPERTY(QSizeF previewSize READ previewSize WRITE setPreviewSize NOTIFY previewSizeChanged) |
1340 | + Q_PROPERTY(int previewTopCrop READ previewTopCrop WRITE setPreviewTopCrop NOTIFY previewTopCropChanged) |
1341 | + Q_PROPERTY(QString previewUrl READ previewUrl WRITE setPreviewUrl NOTIFY previewUrlChanged) |
1342 | + Q_PROPERTY(QQuickItem* source READ source WRITE setSource NOTIFY sourceChanged) |
1343 | +public: |
1344 | + DragHelper(); |
1345 | + bool active() { return m_active; } |
1346 | + bool dragging() { return m_dragging; } |
1347 | + Qt::DropAction expectedAction() { return m_expected_action; } |
1348 | + QString mimeType() { return m_mime_type; } |
1349 | + int previewBorderWidth() { return m_preview_border_width; } |
1350 | + QSizeF previewSize() { return m_preview_size; } |
1351 | + int previewTopCrop() { return m_preview_top_crop; } |
1352 | + QString previewUrl() { return m_preview_url; } |
1353 | + QQuickItem *source() { return m_source; } |
1354 | +signals: |
1355 | + void activeChanged(); |
1356 | + void draggingChanged(); |
1357 | + void expectedActionChanged(); |
1358 | + void mimeTypeChanged(); |
1359 | + void previewBorderWidthChanged(); |
1360 | + void previewSizeChanged(); |
1361 | + void previewTopCropChanged(); |
1362 | + void previewUrlChanged(); |
1363 | + void sourceChanged(); |
1364 | +public slots: |
1365 | + Q_INVOKABLE Qt::DropAction execDrag(QString tabId); |
1366 | + void setActive(bool active); |
1367 | + void setExpectedAction(Qt::DropAction expectedAction); |
1368 | + void setMimeType(QString mimeType); |
1369 | + void setPreviewBorderWidth(int previewBorderWidth); |
1370 | + void setPreviewSize(QSizeF previewSize); |
1371 | + void setPreviewTopCrop(int previewTopCrop); |
1372 | + void setPreviewUrl(QString previewUrl); |
1373 | + void setSource(QQuickItem *source); |
1374 | +private: |
1375 | + QPixmap drawPixmapWithBorder(QPixmap pixmap, int borderWidth, QColor color); |
1376 | + QPixmap getPreviewUrlAsPixmap(int width, int height); |
1377 | + void setDragging(bool dragging); |
1378 | + |
1379 | + bool m_active; |
1380 | + bool m_dragging; |
1381 | + Qt::DropAction m_expected_action; |
1382 | + QString m_mime_type; |
1383 | + int m_preview_border_width; |
1384 | + QSizeF m_preview_size; |
1385 | + int m_preview_top_crop; |
1386 | + QString m_preview_url; |
1387 | + QQuickItem *m_source; |
1388 | +}; |
1389 | + |
1390 | +#endif // __DRAGHELPER_H__ |
1391 | + |
1392 | |
1393 | === added file 'src/app/webbrowser/reparenter.cpp' |
1394 | --- src/app/webbrowser/reparenter.cpp 1970-01-01 00:00:00 +0000 |
1395 | +++ src/app/webbrowser/reparenter.cpp 2016-11-30 14:23:08 +0000 |
1396 | @@ -0,0 +1,124 @@ |
1397 | +/* |
1398 | + * Copyright 2016 Canonical Ltd. |
1399 | + * |
1400 | + * This file is part of webbrowser-app. |
1401 | + * |
1402 | + * webbrowser-app is free software; you can redistribute it and/or modify |
1403 | + * it under the terms of the GNU General Public License as published by |
1404 | + * the Free Software Foundation; version 3. |
1405 | + * |
1406 | + * webbrowser-app is distributed in the hope that it will be useful, |
1407 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1408 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1409 | + * GNU General Public License for more details. |
1410 | + * |
1411 | + * You should have received a copy of the GNU General Public License |
1412 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1413 | + */ |
1414 | + |
1415 | +#include "reparenter.h" |
1416 | + |
1417 | +#include <QtCore/QPointer> |
1418 | +#include <QtCore/QVariantMap> |
1419 | +#include <QtQml> |
1420 | +#include <QtQml/QQmlComponent> |
1421 | +#include <QtQml/QQmlContext> |
1422 | +#include <QtQml/QQmlEngine> |
1423 | +#include <QtQml/QQmlProperty> |
1424 | +#include <QtQuick/QQuickItem> |
1425 | + |
1426 | +Reparenter::Reparenter() |
1427 | +{ |
1428 | +} |
1429 | + |
1430 | +// Upon deconstruction ensure that all created contexts are destroyed |
1431 | +Reparenter::~Reparenter() |
1432 | +{ |
1433 | + QMap<QPointer<QQmlContext>, QPointer<QObject>>::iterator i; |
1434 | + |
1435 | + for (i = m_contexts.begin(); i != m_contexts.end(); ++i) { |
1436 | + QPointer<QQmlContext> context = i.key(); |
1437 | + QPointer<QObject> obj = i.value(); |
1438 | + |
1439 | + // If there is valid object then delete |
1440 | + if (obj) { |
1441 | + delete obj; |
1442 | + } |
1443 | + |
1444 | + // If there is a valid context then delete |
1445 | + if (context) { |
1446 | + delete context; |
1447 | + } |
1448 | + } |
1449 | + |
1450 | + m_contexts.clear(); // ensure contexts are removed |
1451 | +} |
1452 | + |
1453 | +// Create an object of the given component with the context given |
1454 | +// if no context is given then the context is the instance of this class |
1455 | +// this method is required so that a custom context can be created, so that |
1456 | +// when tabs are moved between Windows and the window is destroyed, its context |
1457 | +// it not also destroyed |
1458 | +QObject *Reparenter::createObject(QQmlComponent *comp, QQuickItem *parent, QVariantMap properties, QQuickItem *contextItem) |
1459 | +{ |
1460 | + // Make context for the object |
1461 | + QPointer<QQmlContext> context; |
1462 | + |
1463 | + if (contextItem == Q_NULLPTR) { |
1464 | + // Build context from parent |
1465 | + context = new QQmlContext(qmlEngine(parent)->rootContext()); |
1466 | + context->setContextObject(parent); |
1467 | + } else { |
1468 | + context = new QQmlContext(QQmlEngine::contextForObject(contextItem)); |
1469 | + context->setContextObject(contextItem); |
1470 | + } |
1471 | + |
1472 | + // Make component |
1473 | + QPointer<QObject> obj = comp->beginCreate(context); |
1474 | + |
1475 | + // Set visual and actual parent |
1476 | + reparent(qobject_cast<QQuickItem *>(obj), parent); |
1477 | + |
1478 | + // Load properties into object |
1479 | + for (QString key : properties.keys()) { |
1480 | + QQmlProperty::write(obj, key, properties.value(key)); |
1481 | + } |
1482 | + |
1483 | + // Add to store |
1484 | + m_contexts.insert(context, obj); |
1485 | + |
1486 | + comp->completeCreate(); |
1487 | + |
1488 | + return obj; |
1489 | +} |
1490 | + |
1491 | +// Contexts that have been created by us, must be destroyed by us |
1492 | +// so this helper method destroys the context and object |
1493 | +void Reparenter::destroyContextAndObject(QQuickItem *item) |
1494 | +{ |
1495 | + // Get context for object |
1496 | + QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext(); |
1497 | + |
1498 | + // Remove from store |
1499 | + int removed = m_contexts.remove(context); |
1500 | + |
1501 | + // Disconnect everything |
1502 | + item->disconnect(); |
1503 | + |
1504 | + // Delete context if it was removed from our store |
1505 | + if (removed > 0) { |
1506 | + context->deleteLater(); |
1507 | + } |
1508 | + |
1509 | + // Delete the object |
1510 | + item->deleteLater(); |
1511 | +} |
1512 | + |
1513 | +// Reparent the actual objects parent and its visual parent |
1514 | +void Reparenter::reparent(QQuickItem *obj, QQuickItem *newParent) |
1515 | +{ |
1516 | + // Set object and visual parent |
1517 | + obj->setParent(newParent); |
1518 | + obj->setParentItem(newParent); |
1519 | +} |
1520 | + |
1521 | |
1522 | === added file 'src/app/webbrowser/reparenter.h' |
1523 | --- src/app/webbrowser/reparenter.h 1970-01-01 00:00:00 +0000 |
1524 | +++ src/app/webbrowser/reparenter.h 2016-11-30 14:23:08 +0000 |
1525 | @@ -0,0 +1,46 @@ |
1526 | +/* |
1527 | + * Copyright 2016 Canonical Ltd. |
1528 | + * |
1529 | + * This file is part of webbrowser-app. |
1530 | + * |
1531 | + * webbrowser-app is free software; you can redistribute it and/or modify |
1532 | + * it under the terms of the GNU General Public License as published by |
1533 | + * the Free Software Foundation; version 3. |
1534 | + * |
1535 | + * webbrowser-app is distributed in the hope that it will be useful, |
1536 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1537 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1538 | + * GNU General Public License for more details. |
1539 | + * |
1540 | + * You should have received a copy of the GNU General Public License |
1541 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1542 | + */ |
1543 | + |
1544 | +#ifndef __REPARENTER_H__ |
1545 | +#define __REPARENTER_H__ |
1546 | + |
1547 | +#include <QtCore/QMap> |
1548 | +#include <QtCore/QObject> |
1549 | +#include <QtCore/QPointer> |
1550 | +#include <QtCore/QVariantMap> |
1551 | +#include <QtQml/QQmlComponent> |
1552 | +#include <QtQml/QQmlContext> |
1553 | +#include <QtQuick/QQuickItem> |
1554 | + |
1555 | +class Reparenter : public QObject |
1556 | +{ |
1557 | + Q_OBJECT |
1558 | + |
1559 | +public: |
1560 | + Reparenter(); |
1561 | + ~Reparenter(); |
1562 | + |
1563 | + Q_INVOKABLE QObject *createObject(QQmlComponent *comp, QQuickItem *parent, QVariantMap properties={}, QQuickItem *contextItem=Q_NULLPTR); |
1564 | + Q_INVOKABLE void destroyContextAndObject(QQuickItem *item); |
1565 | + Q_INVOKABLE void reparent(QQuickItem *obj, QQuickItem *newParent); |
1566 | +private: |
1567 | + QMap<QPointer<QQmlContext>, QPointer<QObject>> m_contexts; |
1568 | +}; |
1569 | + |
1570 | +#endif // __REPARENTER_H__ |
1571 | + |
1572 | |
1573 | === modified file 'src/app/webbrowser/webbrowser-app.cpp' |
1574 | --- src/app/webbrowser/webbrowser-app.cpp 2016-08-18 16:29:35 +0000 |
1575 | +++ src/app/webbrowser/webbrowser-app.cpp 2016-11-30 14:23:08 +0000 |
1576 | @@ -21,11 +21,13 @@ |
1577 | #include "cache-deleter.h" |
1578 | #include "config.h" |
1579 | #include "downloads-model.h" |
1580 | +#include "drag-helper.h" |
1581 | #include "file-operations.h" |
1582 | #include "history-domainlist-model.h" |
1583 | #include "history-lastvisitdatelist-model.h" |
1584 | #include "history-model.h" |
1585 | #include "limit-proxy-model.h" |
1586 | +#include "reparenter.h" |
1587 | #include "searchengine.h" |
1588 | #include "text-search-filter-model.h" |
1589 | #include "tabs-model.h" |
1590 | @@ -60,6 +62,8 @@ |
1591 | MAKE_SINGLETON_FACTORY(BookmarksModel) |
1592 | MAKE_SINGLETON_FACTORY(HistoryModel) |
1593 | MAKE_SINGLETON_FACTORY(DownloadsModel) |
1594 | +MAKE_SINGLETON_FACTORY(Reparenter) |
1595 | +MAKE_SINGLETON_FACTORY(DragHelper) |
1596 | |
1597 | bool WebbrowserApp::initialize() |
1598 | { |
1599 | @@ -76,6 +80,8 @@ |
1600 | qmlRegisterSingletonType<CacheDeleter>(uri, 0, 1, "CacheDeleter", CacheDeleter_singleton_factory); |
1601 | qmlRegisterSingletonType<DownloadsModel>(uri, 0, 1, "DownloadsModel", DownloadsModel_singleton_factory); |
1602 | qmlRegisterType<TextSearchFilterModel>(uri, 0, 1, "TextSearchFilterModel"); |
1603 | + qmlRegisterSingletonType<DragHelper>(uri, 0, 1, "DragHelper", DragHelper_singleton_factory); |
1604 | + qmlRegisterSingletonType<Reparenter>(uri, 0, 1, "Reparenter", Reparenter_singleton_factory); |
1605 | |
1606 | if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml", QStringLiteral("webbrowser-app"))) { |
1607 | QStringList searchEnginesSearchPaths; |
1608 | |
1609 | === modified file 'src/app/webbrowser/webbrowser-app.qml' |
1610 | --- src/app/webbrowser/webbrowser-app.qml 2016-10-10 17:00:52 +0000 |
1611 | +++ src/app/webbrowser/webbrowser-app.qml 2016-11-30 14:23:08 +0000 |
1612 | @@ -92,7 +92,7 @@ |
1613 | readonly property var tabsModel: browser.tabsModel |
1614 | |
1615 | currentWebview: browser.currentWebview |
1616 | - |
1617 | + |
1618 | title: { |
1619 | if (browser.title) { |
1620 | // TRANSLATORS: %1 refers to the current page’s title |
1621 | @@ -119,6 +119,7 @@ |
1622 | session.clear() |
1623 | } |
1624 | } |
1625 | + |
1626 | if (incognito && (allWindows.length > 1)) { |
1627 | // If the last incognito window is being closed, |
1628 | // prune incognito entries from the downloads model |
1629 | @@ -133,6 +134,7 @@ |
1630 | DownloadsModel.pruneIncognitoDownloads() |
1631 | } |
1632 | } |
1633 | + |
1634 | destroy() |
1635 | } |
1636 | |
1637 | @@ -181,7 +183,27 @@ |
1638 | Browser { |
1639 | id: browser |
1640 | anchors.fill: parent |
1641 | + thisWindow: window |
1642 | settings: webbrowserapp.settings |
1643 | + onNewWindowFromTab: { |
1644 | + var window = windowFactory.createObject( |
1645 | + null, |
1646 | + { |
1647 | + "incognito": tab.incognito, |
1648 | + "height": parent.height, |
1649 | + "width": parent.width, |
1650 | + } |
1651 | + ); |
1652 | + |
1653 | + window.addExistingTab(tab); |
1654 | + window.tabsModel.currentIndex = window.tabsModel.count - 1; |
1655 | + window.show(); |
1656 | + window.requestActivate(); |
1657 | + |
1658 | + window.tabsModel.currentTab.load(); |
1659 | + |
1660 | + callback(); |
1661 | + } |
1662 | onNewWindowRequested: { |
1663 | var window = windowFactory.createObject( |
1664 | null, |
1665 | @@ -261,10 +283,18 @@ |
1666 | } |
1667 | |
1668 | function addTab(url) { |
1669 | - var tab = browser.createTab({"initialUrl": url}) |
1670 | + var tab = browser.createTab({"initialUrl": url || ""}) |
1671 | tabsModel.add(tab) |
1672 | return tab |
1673 | } |
1674 | + |
1675 | + function addExistingTab(tab) { |
1676 | + tabsModel.add(tab); |
1677 | + |
1678 | + browser.bindExistingTab(tab); |
1679 | + |
1680 | + return tab; |
1681 | + } |
1682 | } |
1683 | } |
1684 | |
1685 | @@ -438,7 +468,7 @@ |
1686 | for (var w in allWindows) { |
1687 | var candidate = getCandidate(allWindows[w].tabsModel) |
1688 | if (candidate) { |
1689 | - if (browser.incognito) { |
1690 | + if (allWindows[w].incognito) { |
1691 | console.warn("Unloading a background incognito tab to free up some memory") |
1692 | } else { |
1693 | console.warn("Unloading background tab (%1) to free up some memory".arg(candidate.url)) |
1694 | |
1695 | === modified file 'src/app/webcontainer/ContextMenuMobile.qml' |
1696 | --- src/app/webcontainer/ContextMenuMobile.qml 2016-09-19 12:08:03 +0000 |
1697 | +++ src/app/webcontainer/ContextMenuMobile.qml 2016-11-30 14:23:08 +0000 |
1698 | @@ -23,6 +23,8 @@ |
1699 | import com.canonical.Oxide 1.8 as Oxide |
1700 | |
1701 | Popups.Dialog { |
1702 | + id: contextMenu |
1703 | + |
1704 | property QtObject contextModel: model |
1705 | property ActionList actions: null |
1706 | |
1707 | @@ -121,7 +123,7 @@ |
1708 | } |
1709 | } |
1710 | |
1711 | - onTriggered: contextModel.close() |
1712 | + onTriggered: contextMenu.hide() |
1713 | } |
1714 | } |
1715 | |
1716 | @@ -140,7 +142,13 @@ |
1717 | fontSize: "x-small" |
1718 | text: i18n.tr("Cancel") |
1719 | } |
1720 | - onTriggered: contextModel.close() |
1721 | + onTriggered: contextMenu.hide() |
1722 | + } |
1723 | + |
1724 | + onVisibleChanged: { |
1725 | + if (!visible) { |
1726 | + contextModel.close() |
1727 | + } |
1728 | } |
1729 | |
1730 | // adjust default dialog visuals to custom requirements for the context menu |
1731 | |
1732 | === modified file 'src/app/webcontainer/WebappWebview.qml' |
1733 | --- src/app/webcontainer/WebappWebview.qml 2016-03-16 15:17:34 +0000 |
1734 | +++ src/app/webcontainer/WebappWebview.qml 2016-11-30 14:23:08 +0000 |
1735 | @@ -17,7 +17,7 @@ |
1736 | */ |
1737 | |
1738 | import QtQuick 2.4 |
1739 | -import com.canonical.Oxide 1.8 as Oxide |
1740 | +import com.canonical.Oxide 1.15 as Oxide |
1741 | import Ubuntu.Components 1.3 |
1742 | import Ubuntu.Components.Popups 1.3 |
1743 | import Ubuntu.Web 0.2 |
1744 | @@ -64,9 +64,10 @@ |
1745 | } |
1746 | Actions.CopyImage { |
1747 | enabled: contextModel && |
1748 | - (contextModel.mediaType === Oxide.WebView.MediaTypeImage) && |
1749 | - contextModel.srcUrl.toString() |
1750 | - onTriggered: Clipboard.push(["text/plain", contextModel.srcUrl.toString()]) |
1751 | + ((contextModel.mediaType === Oxide.WebView.MediaTypeImage) || |
1752 | + (contextModel.mediaType === Oxide.WebView.MediaTypeCanvas)) && |
1753 | + contextModel.hasImageContents |
1754 | + onTriggered: contextModel.copyImage() |
1755 | objectName: "CopyImageContextualAction" |
1756 | } |
1757 | Actions.SaveImage { |
1758 | |
1759 | === modified file 'tests/autopilot/webbrowser_app/emulators/browser.py' |
1760 | --- tests/autopilot/webbrowser_app/emulators/browser.py 2016-10-13 14:36:24 +0000 |
1761 | +++ tests/autopilot/webbrowser_app/emulators/browser.py 2016-11-30 14:23:08 +0000 |
1762 | @@ -316,6 +316,10 @@ |
1763 | return self.select_single("ChromeButton", |
1764 | objectName="findPreviousButton") |
1765 | |
1766 | + def get_progress_bar(self): |
1767 | + return self.select_single("ProgressBar", |
1768 | + objectName="chromeProgressBar") |
1769 | + |
1770 | |
1771 | class AddressBar(uitk.UbuntuUIToolkitCustomProxyObjectBase): |
1772 | |
1773 | @@ -522,7 +526,9 @@ |
1774 | |
1775 | class DownloadsPage(BrowserPage): |
1776 | |
1777 | - pass |
1778 | + def get_download_entries(self): |
1779 | + return sorted(self.select_many("DownloadDelegate"), |
1780 | + key=lambda item: item.globalRect.y) |
1781 | |
1782 | |
1783 | class HistoryView(uitk.UbuntuUIToolkitCustomProxyObjectBase): |
1784 | |
1785 | === modified file 'tests/autopilot/webbrowser_app/tests/__init__.py' |
1786 | --- tests/autopilot/webbrowser_app/tests/__init__.py 2016-09-20 21:56:25 +0000 |
1787 | +++ tests/autopilot/webbrowser_app/tests/__init__.py 2016-11-30 14:23:08 +0000 |
1788 | @@ -216,23 +216,29 @@ |
1789 | self.pointing_device.click_object(bookmarks_action) |
1790 | return self.main_window.get_bookmarks_view() |
1791 | |
1792 | - def open_history(self): |
1793 | - chrome = self.main_window.chrome |
1794 | + def open_history(self, window=None): |
1795 | + if window is None: |
1796 | + window = self.main_window |
1797 | + |
1798 | + chrome = window.chrome |
1799 | drawer_button = chrome.get_drawer_button() |
1800 | self.pointing_device.click_object(drawer_button) |
1801 | chrome.get_drawer() |
1802 | history_action = chrome.get_drawer_action("history") |
1803 | self.pointing_device.click_object(history_action) |
1804 | - return self.main_window.get_history_view() |
1805 | - |
1806 | - def open_downloads(self): |
1807 | - chrome = self.main_window.chrome |
1808 | + return window.get_history_view() |
1809 | + |
1810 | + def open_downloads(self, window=None): |
1811 | + if window is None: |
1812 | + window = self.main_window |
1813 | + |
1814 | + chrome = window.chrome |
1815 | drawer_button = chrome.get_drawer_button() |
1816 | self.pointing_device.click_object(drawer_button) |
1817 | chrome.get_drawer() |
1818 | downloads_action = chrome.get_drawer_action("downloads") |
1819 | self.pointing_device.click_object(downloads_action) |
1820 | - return self.main_window.get_downloads_page() |
1821 | + return window.get_downloads_page() |
1822 | |
1823 | def assert_number_webviews_eventually(self, count): |
1824 | self.assertThat(lambda: len(self.main_window.get_webviews()), |
1825 | @@ -256,6 +262,33 @@ |
1826 | os.kill(child.pid, signal) |
1827 | break |
1828 | |
1829 | + def switch_to_unfocused_window(self, target_window, |
1830 | + expected_number_unfocused_windows=1): |
1831 | + try: |
1832 | + windows = [ |
1833 | + window for window in self.process_manager.get_open_windows() |
1834 | + if window.application.desktop_file == |
1835 | + "webbrowser-app.desktop" and |
1836 | + not window.is_focused |
1837 | + ] |
1838 | + |
1839 | + self.assertThat(len(windows), |
1840 | + Equals(expected_number_unfocused_windows)) |
1841 | + |
1842 | + # Cycle through possible windows until target gets focus |
1843 | + for window in windows: |
1844 | + window.set_focus() |
1845 | + self.assertThat(lambda: window.is_focused, |
1846 | + Eventually(Equals(True))) |
1847 | + |
1848 | + if target_window.activeFocus: |
1849 | + break |
1850 | + except (RuntimeError, ImportError): |
1851 | + # Fallback to clicking on the window |
1852 | + self.pointing_device.click_object(target_window) |
1853 | + |
1854 | + self.assertThat(target_window.activeFocus, Eventually(Equals(True))) |
1855 | + |
1856 | |
1857 | class StartOpenRemotePageTestCaseBase(BrowserTestCaseBase): |
1858 | |
1859 | |
1860 | === modified file 'tests/autopilot/webbrowser_app/tests/test_downloads.py' |
1861 | --- tests/autopilot/webbrowser_app/tests/test_downloads.py 2015-12-15 16:02:16 +0000 |
1862 | +++ tests/autopilot/webbrowser_app/tests/test_downloads.py 2016-11-30 14:23:08 +0000 |
1863 | @@ -21,11 +21,12 @@ |
1864 | |
1865 | from testtools.matchers import Equals |
1866 | |
1867 | +import ubuntuuitoolkit as uitk |
1868 | + |
1869 | +import subprocess |
1870 | import testtools |
1871 | |
1872 | |
1873 | -@testtools.skipIf(model() == "Desktop", "Don't run on desktop, as " |
1874 | - "dependencies aren't guaranteed") |
1875 | class TestDownloads(StartOpenRemotePageTestCaseBase): |
1876 | |
1877 | def test_open_close_downloads_page(self): |
1878 | @@ -60,6 +61,65 @@ |
1879 | self.assertThat(options_dialog.visible, Eventually(Equals(True))) |
1880 | self.main_window.click_cancel_download_button() |
1881 | |
1882 | + def test_download(self): |
1883 | + self.main_window.go_to_url(self.base_url + "/downloadpdf") |
1884 | + options_dialog = self.main_window.get_download_options_dialog() |
1885 | + self.assertThat(options_dialog.visible, Eventually(Equals(True))) |
1886 | + self.main_window.click_download_file_button() |
1887 | + downloads_page = self.main_window.get_downloads_page() |
1888 | + self.assertThat(downloads_page.visible, Eventually(Equals(True))) |
1889 | + |
1890 | + @testtools.skipIf(model() != "Desktop", |
1891 | + "Desktop only due to switch_to_unfocused_window") |
1892 | + def test_private_download(self): |
1893 | + self.open_new_private_window() |
1894 | + |
1895 | + public_window = self.app.get_windows(incognito=False)[0] |
1896 | + private_window = self.app.get_windows(incognito=True)[0] |
1897 | + pdf_download_url = self.base_url + "/downloadpdf" |
1898 | + |
1899 | + # Download pdf in private window |
1900 | + private_window.go_to_url(pdf_download_url) |
1901 | + options_dialog = private_window.get_download_options_dialog() |
1902 | + self.assertThat(options_dialog.visible, Eventually(Equals(True))) |
1903 | + private_window.click_download_file_button() |
1904 | + |
1905 | + # Open downloads page in private window |
1906 | + private_downloads_page = private_window.get_downloads_page() |
1907 | + private_downloads_page.visible.wait_for(True) |
1908 | + |
1909 | + # Check that there is one url in the private downloads window |
1910 | + entries = private_downloads_page.get_download_entries() |
1911 | + self.assertThat(len(entries), Equals(1)) |
1912 | + self.assertThat(entries[0].url, Equals(pdf_download_url)) |
1913 | + self.assertThat(entries[0].incognito, Equals(True)) |
1914 | + |
1915 | + # Focus public window |
1916 | + self.switch_to_unfocused_window(public_window) |
1917 | + |
1918 | + # Open downloads page in public window |
1919 | + public_downloads_page = self.open_downloads(public_window) |
1920 | + public_downloads_page.visible.wait_for(True) |
1921 | + |
1922 | + # Check that there are no entries in the public downloads window |
1923 | + entries = public_downloads_page.get_download_entries() |
1924 | + self.assertThat(len(entries), Equals(0)) |
1925 | + |
1926 | + |
1927 | +class TestDownloadsWithContentHubTestability(StartOpenRemotePageTestCaseBase): |
1928 | + def setUp(self): |
1929 | + # Run content-hub-peer-hook-wrapper which ensures that |
1930 | + # content-hub-testability has been register for the ContentPeersModel |
1931 | + |
1932 | + # Find arch path of content-hub-peer-hook-wrapper |
1933 | + path = ("/usr/lib/%s/content-hub/content-hub-peer-hook-wrapper" % |
1934 | + uitk.base.get_host_multiarch()) |
1935 | + |
1936 | + return_code = subprocess.check_call([path]) |
1937 | + self.assertThat(return_code, Equals(0)) |
1938 | + |
1939 | + super(TestDownloadsWithContentHubTestability, self).setUp() |
1940 | + |
1941 | def test_picker(self): |
1942 | self.main_window.go_to_url(self.base_url + "/downloadpdf") |
1943 | options_dialog = self.main_window.get_download_options_dialog() |
1944 | @@ -67,11 +127,3 @@ |
1945 | self.main_window.click_choose_app_button() |
1946 | picker = self.main_window.get_peer_picker() |
1947 | self.assertThat(picker.visible, Eventually(Equals(True))) |
1948 | - |
1949 | - def test_download(self): |
1950 | - self.main_window.go_to_url(self.base_url + "/downloadpdf") |
1951 | - options_dialog = self.main_window.get_download_options_dialog() |
1952 | - self.assertThat(options_dialog.visible, Eventually(Equals(True))) |
1953 | - self.main_window.click_download_file_button() |
1954 | - downloads_page = self.main_window.get_downloads_page() |
1955 | - self.assertThat(downloads_page.visible, Eventually(Equals(True))) |
1956 | |
1957 | === modified file 'tests/autopilot/webbrowser_app/tests/test_history.py' |
1958 | --- tests/autopilot/webbrowser_app/tests/test_history.py 2016-10-06 21:07:50 +0000 |
1959 | +++ tests/autopilot/webbrowser_app/tests/test_history.py 2016-11-30 14:23:08 +0000 |
1960 | @@ -18,15 +18,21 @@ |
1961 | |
1962 | from testtools.matchers import EndsWith, Equals, StartsWith |
1963 | from autopilot.matchers import Eventually |
1964 | +from autopilot.platform import model |
1965 | |
1966 | from webbrowser_app.tests import StartOpenRemotePageTestCaseBase |
1967 | |
1968 | +import testtools |
1969 | + |
1970 | |
1971 | class TestHistory(StartOpenRemotePageTestCaseBase): |
1972 | |
1973 | - def expect_history_entries(self, ordered_urls): |
1974 | - history = self.main_window.get_history_view() |
1975 | - if self.main_window.wide: |
1976 | + def expect_history_entries(self, ordered_urls, window=None): |
1977 | + if window is None: |
1978 | + window = self.main_window |
1979 | + |
1980 | + history = window.get_history_view() |
1981 | + if window.wide: |
1982 | self.assertThat(lambda: len(history.get_entries()), |
1983 | Eventually(Equals(len(ordered_urls)))) |
1984 | entries = history.get_entries() |
1985 | @@ -34,7 +40,7 @@ |
1986 | self.assertThat(lambda: len(history.get_domain_entries()), |
1987 | Eventually(Equals(1))) |
1988 | self.pointing_device.click_object(history.get_domain_entries()[0]) |
1989 | - expanded_history = self.main_window.get_expanded_history_view() |
1990 | + expanded_history = window.get_expanded_history_view() |
1991 | self.assertThat(lambda: len(expanded_history.get_entries()), |
1992 | Eventually(Equals(len(ordered_urls)))) |
1993 | entries = expanded_history.get_entries() |
1994 | @@ -125,6 +131,26 @@ |
1995 | self.open_history() |
1996 | self.expect_history_entries([pushed, url, self.url]) |
1997 | |
1998 | + @testtools.skipIf(model() != "Desktop", |
1999 | + "Desktop only due to switch_to_unfocused_window") |
2000 | + def test_private_window_no_history(self): |
2001 | + self.open_new_private_window() |
2002 | + |
2003 | + public_window = self.app.get_windows(incognito=False)[0] |
2004 | + private_window = self.app.get_windows(incognito=True)[0] |
2005 | + |
2006 | + # Open link in private window |
2007 | + url = self.base_url + "/test2" |
2008 | + private_window.go_to_url(url) |
2009 | + private_window.wait_until_page_loaded(url) |
2010 | + |
2011 | + # Focus public window |
2012 | + self.switch_to_unfocused_window(public_window) |
2013 | + |
2014 | + # Check link is not in history of public window |
2015 | + self.open_history(window=public_window) |
2016 | + self.expect_history_entries([self.url], window=public_window) |
2017 | + |
2018 | def test_title_correct_redirect_header(self): |
2019 | # Regression test for https://launchpad.net/bugs/1603835 |
2020 | url_redirect = self.base_url + "/redirect-no-title-header" |
2021 | |
2022 | === modified file 'tests/autopilot/webbrowser_app/tests/test_multiple_windows.py' |
2023 | --- tests/autopilot/webbrowser_app/tests/test_multiple_windows.py 2016-09-20 21:56:25 +0000 |
2024 | +++ tests/autopilot/webbrowser_app/tests/test_multiple_windows.py 2016-11-30 14:23:08 +0000 |
2025 | @@ -14,7 +14,9 @@ |
2026 | # You should have received a copy of the GNU General Public License |
2027 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2028 | |
2029 | +from autopilot.matchers import Eventually |
2030 | from testtools.matchers import Equals |
2031 | +from time import sleep |
2032 | |
2033 | from webbrowser_app.tests import StartOpenRemotePageTestCaseBase |
2034 | |
2035 | @@ -38,3 +40,223 @@ |
2036 | self.assertThat(len(windows), Equals(2)) |
2037 | self.assertThat(len(self.app.get_windows(incognito=False)), Equals(1)) |
2038 | self.assertThat(len(self.app.get_windows(incognito=True)), Equals(1)) |
2039 | + |
2040 | + def test_open_new_window_progress_bar_hidden(self): |
2041 | + # Regression test for pad.lv/1638337 |
2042 | + url = self.base_url + "/test2" |
2043 | + self.main_window.go_to_url(url) |
2044 | + self.main_window.wait_until_page_loaded(url) |
2045 | + |
2046 | + self.assertThat(self.main_window.chrome.get_progress_bar().visible, |
2047 | + Eventually(Equals(False))) |
2048 | + |
2049 | + # Open a new window |
2050 | + self.open_new_window() |
2051 | + windows = self.app.get_windows() |
2052 | + self.assertThat(len(windows), Equals(2)) |
2053 | + |
2054 | + # Check that progress bar is hidden |
2055 | + for window in windows: |
2056 | + self.assertThat(window.chrome.get_progress_bar().visible, |
2057 | + Eventually(Equals(False))) |
2058 | + |
2059 | + |
2060 | +class TestMultipleWindowsDrag(StartOpenRemotePageTestCaseBase): |
2061 | + def setUp(self): |
2062 | + super(TestMultipleWindowsDrag, self).setUp() |
2063 | + |
2064 | + if not self.main_window.wide: |
2065 | + self.skipTest("Only on wide form factors") |
2066 | + |
2067 | + def drag_tab(self, tab, x2, y2): |
2068 | + x1, y1 = self.get_object_center(tab) |
2069 | + |
2070 | + self.pointing_device.move(x1, y1) |
2071 | + self.pointing_device.press() |
2072 | + |
2073 | + # Drag tab downwards first to ensure we activate tab dragging |
2074 | + for i in range(100): |
2075 | + self.pointing_device.move(x1, y1 + i) |
2076 | + |
2077 | + # Move to destination and release |
2078 | + # pause at each point so we can what is happening |
2079 | + sleep(0.25) |
2080 | + self.pointing_device.move(x2, y2) |
2081 | + sleep(0.25) |
2082 | + self.pointing_device.release() |
2083 | + sleep(0.25) |
2084 | + |
2085 | + def get_object_center(self, obj): |
2086 | + x1, y1, width, height = obj.globalRect |
2087 | + x1 += width // 2 |
2088 | + y1 += height // 2 |
2089 | + |
2090 | + return x1, y1 |
2091 | + |
2092 | + def get_tab_delegate(self, window, tabIndex): |
2093 | + return window.chrome.get_tabs_bar().get_tab(tabIndex) |
2094 | + |
2095 | + def test_drag_tab_tabbar_nothing(self): |
2096 | + '''test that dragging a tab out and in of tabbar is same''' |
2097 | + window = self.app.get_windows()[0] |
2098 | + |
2099 | + # Drag tab down and then back into tab bar |
2100 | + tab = self.get_tab_delegate(window, 0) |
2101 | + x2, y2 = self.get_object_center(tab) |
2102 | + |
2103 | + self.drag_tab(tab, x2, y2) |
2104 | + |
2105 | + # Check we still have 1 window and 1 tab |
2106 | + windows = self.app.get_windows() |
2107 | + self.assertThat(len(windows), Equals(1)) |
2108 | + self.assertThat(lambda: len(windows[0].get_webviews()), |
2109 | + Eventually(Equals(1))) |
2110 | + |
2111 | + def test_drag_tab_bottom_new_window(self): |
2112 | + '''test with two tabs dragging one to the bottom opens a new window''' |
2113 | + window = self.app.get_windows()[0] |
2114 | + |
2115 | + # Open a new tab and check we have two |
2116 | + self.open_new_tab() |
2117 | + self.assertThat(lambda: len(window.get_webviews()), |
2118 | + Eventually(Equals(2))) |
2119 | + |
2120 | + # Drag new tab to bottom part of window |
2121 | + tab = self.get_tab_delegate(window, 1) |
2122 | + x2, y2 = self.get_object_center(window) |
2123 | + |
2124 | + self.drag_tab(tab, x2, y2) |
2125 | + |
2126 | + # Check that a new window has been opened |
2127 | + windows = self.app.get_windows() |
2128 | + self.assertThat(len(windows), Equals(2)) |
2129 | + self.assertThat(lambda: len(windows[0].get_webviews()), |
2130 | + Eventually(Equals(1))) |
2131 | + self.assertThat(lambda: len(windows[1].get_webviews()), |
2132 | + Eventually(Equals(1))) |
2133 | + |
2134 | + def test_drag_tab_outside_new_window(self): |
2135 | + '''test with two tabs dragging one to the bottom opens a new window''' |
2136 | + window = self.app.get_windows()[0] |
2137 | + |
2138 | + # Open a new tab and check we have two |
2139 | + self.open_new_tab() |
2140 | + self.assertThat(lambda: len(window.get_webviews()), |
2141 | + Eventually(Equals(2))) |
2142 | + |
2143 | + # Drag new tab outside of window |
2144 | + tab = self.get_tab_delegate(window, 1) |
2145 | + x2, y2, width, height = window.globalRect |
2146 | + |
2147 | + if x2 > 20: |
2148 | + x2 -= 20 |
2149 | + else: |
2150 | + x2 += width + 20 |
2151 | + |
2152 | + self.drag_tab(tab, x2, y2) |
2153 | + |
2154 | + # Check that a new window has been opened |
2155 | + windows = self.app.get_windows() |
2156 | + self.assertThat(len(windows), Equals(2)) |
2157 | + self.assertThat(lambda: len(windows[0].get_webviews()), |
2158 | + Eventually(Equals(1))) |
2159 | + self.assertThat(lambda: len(windows[1].get_webviews()), |
2160 | + Eventually(Equals(1))) |
2161 | + |
2162 | + def test_drag_tab_between_windows_move(self): |
2163 | + '''test that dragging a tab from one window to another''' |
2164 | + # Open a new tab and window |
2165 | + self.open_new_tab() |
2166 | + self.open_new_window() |
2167 | + |
2168 | + windows = self.app.get_windows() |
2169 | + self.assertThat(len(windows), Equals(2)) |
2170 | + self.assertThat(lambda: len(windows[0].get_webviews()), |
2171 | + Eventually(Equals(2))) |
2172 | + self.assertThat(lambda: len(windows[1].get_webviews()), |
2173 | + Eventually(Equals(1))) |
2174 | + |
2175 | + # Focus window 0 |
2176 | + self.switch_to_unfocused_window(windows[0]) |
2177 | + |
2178 | + # Move tab into window 1 |
2179 | + tab = self.get_tab_delegate(windows[0], 1) |
2180 | + x2, y2 = self.get_object_center(windows[1].chrome.get_tabs_bar()) |
2181 | + |
2182 | + self.drag_tab(tab, x2, y2) |
2183 | + |
2184 | + # Check there are two windows and two tabs open in the second window |
2185 | + windows = self.app.get_windows() |
2186 | + self.assertThat(len(windows), Equals(2)) |
2187 | + self.assertThat(lambda: len(windows[0].get_webviews()), |
2188 | + Eventually(Equals(1))) |
2189 | + self.assertThat(lambda: len(windows[1].get_webviews()), |
2190 | + Eventually(Equals(2))) |
2191 | + |
2192 | + def test_drag_tab_between_windows_move_and_close_window(self): |
2193 | + '''test that dragging tab from one window to another closes original''' |
2194 | + self.open_new_window() |
2195 | + windows = self.app.get_windows() |
2196 | + self.assertThat(len(windows), Equals(2)) |
2197 | + |
2198 | + # Focus window 0 |
2199 | + self.switch_to_unfocused_window(windows[0]) |
2200 | + |
2201 | + # Move tab into window 1 |
2202 | + tab = self.get_tab_delegate(windows[0], 0) |
2203 | + x2, y2 = self.get_object_center(windows[1].chrome.get_tabs_bar()) |
2204 | + |
2205 | + self.drag_tab(tab, x2, y2) |
2206 | + |
2207 | + # Check there are two tabs open in the single remaining window |
2208 | + windows = self.app.get_windows() |
2209 | + self.assertThat(len(windows), Equals(1)) |
2210 | + self.assertThat(lambda: len(windows[0].get_webviews()), |
2211 | + Eventually(Equals(2))) |
2212 | + |
2213 | + def test_drag_public_tab_into_private_window(self): |
2214 | + '''test that you cannot drag a public tab into private window''' |
2215 | + # Open private window, check there are two windows |
2216 | + self.open_new_private_window() |
2217 | + windows = self.app.get_windows() |
2218 | + self.assertThat(len(windows), Equals(2)) |
2219 | + |
2220 | + public_window = self.app.get_windows(incognito=False)[0] |
2221 | + private_window = self.app.get_windows(incognito=True)[0] |
2222 | + |
2223 | + # Focus public window |
2224 | + self.switch_to_unfocused_window(public_window) |
2225 | + |
2226 | + # Move tab into private window |
2227 | + tab = self.get_tab_delegate(public_window, 0) |
2228 | + x2, y2 = self.get_object_center(private_window) |
2229 | + |
2230 | + self.drag_tab(tab, x2, y2) |
2231 | + |
2232 | + # Check there are two windows, one of public and one private |
2233 | + windows = self.app.get_windows() |
2234 | + self.assertThat(len(windows), Equals(2)) |
2235 | + self.assertThat(len(self.app.get_windows(incognito=False)), Equals(1)) |
2236 | + self.assertThat(len(self.app.get_windows(incognito=True)), Equals(1)) |
2237 | + |
2238 | + def test_drag_private_tab_into_public_window(self): |
2239 | + '''test that you cannot drag a private tab into public window''' |
2240 | + # Open private window, check there are two windows |
2241 | + self.open_new_private_window() |
2242 | + windows = self.app.get_windows() |
2243 | + self.assertThat(len(windows), Equals(2)) |
2244 | + |
2245 | + public_window = self.app.get_windows(incognito=False)[0] |
2246 | + private_window = self.app.get_windows(incognito=True)[0] |
2247 | + |
2248 | + # Move tab into public window |
2249 | + tab = self.get_tab_delegate(private_window, 0) |
2250 | + x2, y2 = self.get_object_center(public_window) |
2251 | + |
2252 | + self.drag_tab(tab, x2, y2) |
2253 | + |
2254 | + # Check there are two windows, one of public and one private |
2255 | + windows = self.app.get_windows() |
2256 | + self.assertThat(len(windows), Equals(2)) |
2257 | + self.assertThat(len(self.app.get_windows(incognito=False)), Equals(1)) |
2258 | + self.assertThat(len(self.app.get_windows(incognito=True)), Equals(1)) |
2259 | |
2260 | === modified file 'tests/autopilot/webbrowser_app/tests/test_new_tab_view.py' |
2261 | --- tests/autopilot/webbrowser_app/tests/test_new_tab_view.py 2016-10-11 11:25:23 +0000 |
2262 | +++ tests/autopilot/webbrowser_app/tests/test_new_tab_view.py 2016-11-30 14:23:08 +0000 |
2263 | @@ -466,3 +466,13 @@ |
2264 | self.assertThat(lambda: len(view.get_bookmarks_list()), |
2265 | Eventually(Equals(2))) |
2266 | self.assertThat(view.get_bookmarks_list()[0].title, Equals(title)) |
2267 | + |
2268 | + |
2269 | +class TestNewTabViewPrivate(StartOpenRemotePageTestCaseBase): |
2270 | + def test_private_window_uses_private_tab_view(self): |
2271 | + self.open_new_private_window() |
2272 | + |
2273 | + private_window = self.app.get_windows(incognito=True)[0] |
2274 | + |
2275 | + self.assertThat(private_window.get_new_private_tab_view().visible, |
2276 | + Eventually(Equals(True))) |
2277 | |
2278 | === modified file 'tests/unittests/bookmarks-folder-model/CMakeLists.txt' |
2279 | --- tests/unittests/bookmarks-folder-model/CMakeLists.txt 2015-07-03 16:18:43 +0000 |
2280 | +++ tests/unittests/bookmarks-folder-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2281 | @@ -10,4 +10,4 @@ |
2282 | Qt5::Test |
2283 | webbrowser-app-models |
2284 | ) |
2285 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2286 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2287 | |
2288 | === modified file 'tests/unittests/bookmarks-folderlist-model/CMakeLists.txt' |
2289 | --- tests/unittests/bookmarks-folderlist-model/CMakeLists.txt 2015-07-03 16:18:43 +0000 |
2290 | +++ tests/unittests/bookmarks-folderlist-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2291 | @@ -10,4 +10,4 @@ |
2292 | Qt5::Test |
2293 | webbrowser-app-models |
2294 | ) |
2295 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2296 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2297 | |
2298 | === modified file 'tests/unittests/bookmarks-model/CMakeLists.txt' |
2299 | --- tests/unittests/bookmarks-model/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2300 | +++ tests/unittests/bookmarks-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2301 | @@ -10,4 +10,4 @@ |
2302 | Qt5::Test |
2303 | webbrowser-app-models |
2304 | ) |
2305 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2306 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2307 | |
2308 | === modified file 'tests/unittests/container-url-patterns/CMakeLists.txt' |
2309 | --- tests/unittests/container-url-patterns/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2310 | +++ tests/unittests/container-url-patterns/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2311 | @@ -11,4 +11,4 @@ |
2312 | Qt5::Core |
2313 | Qt5::Test |
2314 | ) |
2315 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2316 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2317 | |
2318 | === modified file 'tests/unittests/cookie-store/CMakeLists.txt' |
2319 | --- tests/unittests/cookie-store/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2320 | +++ tests/unittests/cookie-store/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2321 | @@ -17,4 +17,4 @@ |
2322 | Qt5::Sql |
2323 | Qt5::Test |
2324 | ) |
2325 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2326 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2327 | |
2328 | === modified file 'tests/unittests/domain-utils/CMakeLists.txt' |
2329 | --- tests/unittests/domain-utils/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2330 | +++ tests/unittests/domain-utils/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2331 | @@ -7,4 +7,4 @@ |
2332 | Qt5::Core |
2333 | Qt5::Test |
2334 | ) |
2335 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2336 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2337 | |
2338 | === modified file 'tests/unittests/downloads-model/CMakeLists.txt' |
2339 | --- tests/unittests/downloads-model/CMakeLists.txt 2015-12-11 13:38:52 +0000 |
2340 | +++ tests/unittests/downloads-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2341 | @@ -10,4 +10,4 @@ |
2342 | Qt5::Test |
2343 | webbrowser-app-models |
2344 | ) |
2345 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2346 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2347 | |
2348 | === modified file 'tests/unittests/favicon-fetcher/CMakeLists.txt' |
2349 | --- tests/unittests/favicon-fetcher/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2350 | +++ tests/unittests/favicon-fetcher/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2351 | @@ -15,5 +15,5 @@ |
2352 | Qt5::Network |
2353 | Qt5::Test |
2354 | ) |
2355 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2356 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2357 | set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal") |
2358 | |
2359 | === modified file 'tests/unittests/history-domain-model/CMakeLists.txt' |
2360 | --- tests/unittests/history-domain-model/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2361 | +++ tests/unittests/history-domain-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2362 | @@ -10,4 +10,4 @@ |
2363 | Qt5::Test |
2364 | webbrowser-app-models |
2365 | ) |
2366 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2367 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2368 | |
2369 | === modified file 'tests/unittests/history-domainlist-model/CMakeLists.txt' |
2370 | --- tests/unittests/history-domainlist-model/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2371 | +++ tests/unittests/history-domainlist-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2372 | @@ -10,4 +10,4 @@ |
2373 | Qt5::Test |
2374 | webbrowser-app-models |
2375 | ) |
2376 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2377 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2378 | |
2379 | === modified file 'tests/unittests/history-lastvisitdatelist-model/CMakeLists.txt' |
2380 | --- tests/unittests/history-lastvisitdatelist-model/CMakeLists.txt 2015-07-29 00:25:59 +0000 |
2381 | +++ tests/unittests/history-lastvisitdatelist-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2382 | @@ -8,4 +8,4 @@ |
2383 | Qt5::Sql |
2384 | Qt5::Test |
2385 | ) |
2386 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2387 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2388 | |
2389 | === modified file 'tests/unittests/history-model/CMakeLists.txt' |
2390 | --- tests/unittests/history-model/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2391 | +++ tests/unittests/history-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2392 | @@ -10,4 +10,4 @@ |
2393 | Qt5::Test |
2394 | webbrowser-app-models |
2395 | ) |
2396 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2397 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2398 | |
2399 | === modified file 'tests/unittests/intent-filter/CMakeLists.txt' |
2400 | --- tests/unittests/intent-filter/CMakeLists.txt 2015-07-20 14:20:37 +0000 |
2401 | +++ tests/unittests/intent-filter/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2402 | @@ -14,4 +14,4 @@ |
2403 | Qt5::Qml |
2404 | Qt5::Test |
2405 | ) |
2406 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2407 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2408 | |
2409 | === modified file 'tests/unittests/limit-proxy-model/CMakeLists.txt' |
2410 | --- tests/unittests/limit-proxy-model/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2411 | +++ tests/unittests/limit-proxy-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2412 | @@ -10,4 +10,4 @@ |
2413 | Qt5::Test |
2414 | webbrowser-app-models |
2415 | ) |
2416 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2417 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2418 | |
2419 | === modified file 'tests/unittests/meminfo/CMakeLists.txt' |
2420 | --- tests/unittests/meminfo/CMakeLists.txt 2016-02-09 13:02:16 +0000 |
2421 | +++ tests/unittests/meminfo/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2422 | @@ -11,5 +11,5 @@ |
2423 | Qt5::Core |
2424 | Qt5::Test |
2425 | ) |
2426 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2427 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2428 | set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal") |
2429 | |
2430 | === modified file 'tests/unittests/oxide-cookie-helper/CMakeLists.txt' |
2431 | --- tests/unittests/oxide-cookie-helper/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2432 | +++ tests/unittests/oxide-cookie-helper/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2433 | @@ -13,4 +13,4 @@ |
2434 | Qt5::Network |
2435 | Qt5::Test |
2436 | ) |
2437 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2438 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2439 | |
2440 | === modified file 'tests/unittests/qml/CMakeLists.txt' |
2441 | --- tests/unittests/qml/CMakeLists.txt 2016-08-24 18:17:55 +0000 |
2442 | +++ tests/unittests/qml/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2443 | @@ -18,12 +18,14 @@ |
2444 | ${webbrowser-app_SOURCE_DIR}/bookmarks-model.cpp |
2445 | ${webbrowser-app_SOURCE_DIR}/bookmarks-folder-model.cpp |
2446 | ${webbrowser-app_SOURCE_DIR}/bookmarks-folderlist-model.cpp |
2447 | + ${webbrowser-app_SOURCE_DIR}/drag-helper.cpp |
2448 | ${webbrowser-app_SOURCE_DIR}/file-operations.cpp |
2449 | ${webbrowser-app_SOURCE_DIR}/history-domain-model.cpp |
2450 | ${webbrowser-app_SOURCE_DIR}/history-domainlist-model.cpp |
2451 | ${webbrowser-app_SOURCE_DIR}/history-model.cpp |
2452 | ${webbrowser-app_SOURCE_DIR}/history-lastvisitdatelist-model.cpp |
2453 | ${webbrowser-app_SOURCE_DIR}/limit-proxy-model.cpp |
2454 | + ${webbrowser-app_SOURCE_DIR}/reparenter.cpp |
2455 | ${webbrowser-app_SOURCE_DIR}/searchengine.cpp |
2456 | ${webbrowser-app_SOURCE_DIR}/tabs-model.cpp |
2457 | ${webbrowser-app_SOURCE_DIR}/text-search-filter-model.cpp |
2458 | |
2459 | === added file 'tests/unittests/qml/ReparenterFakeContainer.qml' |
2460 | --- tests/unittests/qml/ReparenterFakeContainer.qml 1970-01-01 00:00:00 +0000 |
2461 | +++ tests/unittests/qml/ReparenterFakeContainer.qml 2016-11-30 14:23:08 +0000 |
2462 | @@ -0,0 +1,40 @@ |
2463 | +/* |
2464 | + * Copyright 2016 Canonical Ltd. |
2465 | + * |
2466 | + * This file is part of webbrowser-app. |
2467 | + * |
2468 | + * webbrowser-app is free software; you can redistribute it and/or modify |
2469 | + * it under the terms of the GNU General Public License as published by |
2470 | + * the Free Software Foundation; version 3. |
2471 | + * |
2472 | + * webbrowser-app is distributed in the hope that it will be useful, |
2473 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2474 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2475 | + * GNU General Public License for more details. |
2476 | + * |
2477 | + * You should have received a copy of the GNU General Public License |
2478 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2479 | + */ |
2480 | +import QtQuick 2.4 |
2481 | + |
2482 | +Item { |
2483 | + id: containerLeft |
2484 | + anchors { |
2485 | + bottom: parent.bottom |
2486 | + left: parent.left |
2487 | + right: parent.horizontalCenter |
2488 | + top: parent.top |
2489 | + } |
2490 | + |
2491 | + property var root |
2492 | + |
2493 | + function makeTab() { |
2494 | + var component = Qt.createComponent(Qt.resolvedUrl("ReparenterFakeTab.qml")) |
2495 | + return component.createObject(containerLeft, {}) |
2496 | + } |
2497 | + |
2498 | + function makeTabHelper() { |
2499 | + var component = Qt.createComponent(Qt.resolvedUrl("ReparenterFakeTab.qml")) |
2500 | + return root.builder(component, containerLeft) |
2501 | + } |
2502 | +} |
2503 | |
2504 | === added file 'tests/unittests/qml/ReparenterFakeTab.qml' |
2505 | --- tests/unittests/qml/ReparenterFakeTab.qml 1970-01-01 00:00:00 +0000 |
2506 | +++ tests/unittests/qml/ReparenterFakeTab.qml 2016-11-30 14:23:08 +0000 |
2507 | @@ -0,0 +1,37 @@ |
2508 | +/* |
2509 | + * Copyright 2016 Canonical Ltd. |
2510 | + * |
2511 | + * This file is part of webbrowser-app. |
2512 | + * |
2513 | + * webbrowser-app is free software; you can redistribute it and/or modify |
2514 | + * it under the terms of the GNU General Public License as published by |
2515 | + * the Free Software Foundation; version 3. |
2516 | + * |
2517 | + * webbrowser-app is distributed in the hope that it will be useful, |
2518 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2519 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2520 | + * GNU General Public License for more details. |
2521 | + * |
2522 | + * You should have received a copy of the GNU General Public License |
2523 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2524 | + */ |
2525 | +import QtQuick 2.4 |
2526 | + |
2527 | +Item { |
2528 | + anchors { |
2529 | + fill: parent |
2530 | + } |
2531 | + |
2532 | + readonly property MouseArea mouseArea: mouseAreaObj |
2533 | + |
2534 | + MouseArea { |
2535 | + id: mouseAreaObj |
2536 | + anchors { |
2537 | + fill: parent |
2538 | + } |
2539 | + |
2540 | + property int clickCount: 0 |
2541 | + |
2542 | + onClicked: clickCount++ |
2543 | + } |
2544 | +} |
2545 | |
2546 | === modified file 'tests/unittests/qml/tst_BrowserTab.qml' |
2547 | --- tests/unittests/qml/tst_BrowserTab.qml 2016-08-18 17:10:32 +0000 |
2548 | +++ tests/unittests/qml/tst_BrowserTab.qml 2016-11-30 14:23:08 +0000 |
2549 | @@ -44,6 +44,8 @@ |
2550 | property int reloaded: 0 |
2551 | property bool loadingState: false |
2552 | function reload() { reloaded++ } |
2553 | + |
2554 | + signal loadEvent() |
2555 | } |
2556 | readonly property bool webviewPresent: webview |
2557 | } |
2558 | @@ -163,9 +165,8 @@ |
2559 | tab.current = false |
2560 | tryCompare(previewSavedSpy, "count", 1) |
2561 | verify(FileOperations.exists(path)) |
2562 | - tab.close() |
2563 | + tab.close(false) |
2564 | verify(!FileOperations.exists(path)) |
2565 | - |
2566 | tab.destroy() |
2567 | } |
2568 | } |
2569 | |
2570 | === modified file 'tests/unittests/qml/tst_QmlTests.cpp' |
2571 | --- tests/unittests/qml/tst_QmlTests.cpp 2016-02-11 08:26:47 +0000 |
2572 | +++ tests/unittests/qml/tst_QmlTests.cpp 2016-11-30 14:23:08 +0000 |
2573 | @@ -21,12 +21,14 @@ |
2574 | #include <QtCore/QObject> |
2575 | #include <QtCore/QString> |
2576 | #include <QtCore/QTemporaryDir> |
2577 | +#include <QtQml/QQmlEngine> |
2578 | #include <QtQml/QtQml> |
2579 | #include <QtQuickTest/QtQuickTest> |
2580 | |
2581 | // local |
2582 | #include "bookmarks-model.h" |
2583 | #include "bookmarks-folderlist-model.h" |
2584 | +#include "drag-helper.h" |
2585 | #include "favicon-fetcher.h" |
2586 | #include "file-operations.h" |
2587 | #include "history-domain-model.h" |
2588 | @@ -34,6 +36,7 @@ |
2589 | #include "history-model.h" |
2590 | #include "history-lastvisitdatelist-model.h" |
2591 | #include "limit-proxy-model.h" |
2592 | +#include "reparenter.h" |
2593 | #include "searchengine.h" |
2594 | #include "tabs-model.h" |
2595 | #include "text-search-filter-model.h" |
2596 | @@ -165,6 +168,8 @@ |
2597 | MAKE_SINGLETON_FACTORY(BookmarksModel) |
2598 | MAKE_SINGLETON_FACTORY(HistoryModelMock) |
2599 | MAKE_SINGLETON_FACTORY(TestContext) |
2600 | +MAKE_SINGLETON_FACTORY(Reparenter) |
2601 | +MAKE_SINGLETON_FACTORY(DragHelper) |
2602 | |
2603 | int main(int argc, char** argv) |
2604 | { |
2605 | @@ -183,6 +188,8 @@ |
2606 | qmlRegisterType<LimitProxyModel>(browserUri, 0, 1, "LimitProxyModel"); |
2607 | qmlRegisterType<TextSearchFilterModel>(browserUri, 0, 1, "TextSearchFilterModel"); |
2608 | qmlRegisterSingletonType<FileOperations>(browserUri, 0, 1, "FileOperations", FileOperations_singleton_factory); |
2609 | + qmlRegisterSingletonType<DragHelper>(browserUri, 0, 1, "DragHelper", DragHelper_singleton_factory); |
2610 | + qmlRegisterSingletonType<Reparenter>(browserUri, 0, 1, "Reparenter", Reparenter_singleton_factory); |
2611 | |
2612 | const char* testUri = "webbrowsertest.private"; |
2613 | qmlRegisterSingletonType<TestContext>(testUri, 0, 1, "TestContext", TestContext_singleton_factory); |
2614 | |
2615 | === added file 'tests/unittests/qml/tst_Reparenter.qml' |
2616 | --- tests/unittests/qml/tst_Reparenter.qml 1970-01-01 00:00:00 +0000 |
2617 | +++ tests/unittests/qml/tst_Reparenter.qml 2016-11-30 14:23:08 +0000 |
2618 | @@ -0,0 +1,114 @@ |
2619 | +/* |
2620 | + * Copyright 2016 Canonical Ltd. |
2621 | + * |
2622 | + * This file is part of webbrowser-app. |
2623 | + * |
2624 | + * webbrowser-app is free software; you can redistribute it and/or modify |
2625 | + * it under the terms of the GNU General Public License as published by |
2626 | + * the Free Software Foundation; version 3. |
2627 | + * |
2628 | + * webbrowser-app is distributed in the hope that it will be useful, |
2629 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2630 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2631 | + * GNU General Public License for more details. |
2632 | + * |
2633 | + * You should have received a copy of the GNU General Public License |
2634 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2635 | + */ |
2636 | +import QtQuick 2.4 |
2637 | +import QtTest 1.0 |
2638 | +import webbrowserapp.private 0.1 |
2639 | + |
2640 | +Item { |
2641 | + id: root |
2642 | + height: 100 |
2643 | + width: 100 |
2644 | + |
2645 | + property Item containerLeft |
2646 | + |
2647 | + Item { |
2648 | + id: containerRight |
2649 | + anchors { |
2650 | + bottom: parent.bottom |
2651 | + left: parent.horizontalCenter |
2652 | + right: parent.right |
2653 | + top: parent.top |
2654 | + } |
2655 | + } |
2656 | + |
2657 | + function addExisting(container, tab) { |
2658 | + tab.parent = container |
2659 | + } |
2660 | + |
2661 | + function addExistingHelper(container, tab) { |
2662 | + Reparenter.reparent(tab, container, {}); |
2663 | + } |
2664 | + |
2665 | + function builder(component, container) { |
2666 | + return Reparenter.createObject(component, container) |
2667 | + } |
2668 | + |
2669 | + TestCase { |
2670 | + name: "Reparenter" |
2671 | + when: windowShown |
2672 | + |
2673 | + function init() { |
2674 | + var component = Qt.createComponent(Qt.resolvedUrl("ReparenterFakeContainer.qml")) |
2675 | + containerLeft = component.createObject(root, {}) |
2676 | + containerLeft.root = root |
2677 | + } |
2678 | + |
2679 | + function cleanup() { |
2680 | + containerRight.children = null |
2681 | + } |
2682 | + |
2683 | + function test_reparenter_cpp() { |
2684 | + var tab = containerLeft.makeTabHelper() |
2685 | + |
2686 | + // Click on tab ensure it has been clicked |
2687 | + mouseClick(root, 25, 50, Qt.LeftButton) |
2688 | + compare(tab.mouseArea.clickCount, 1) |
2689 | + |
2690 | + // Move tab |
2691 | + addExistingHelper(containerRight, tab) |
2692 | + |
2693 | + // Click on tab ensure it has been clicked |
2694 | + mouseClick(root, 75, 50, Qt.LeftButton) |
2695 | + compare(tab.mouseArea.clickCount, 2) |
2696 | + |
2697 | + // Destroy context |
2698 | + containerLeft.destroy() |
2699 | + |
2700 | + // Click on tab ensure it has been clicked |
2701 | + mouseClick(root, 75, 50, Qt.LeftButton) |
2702 | + compare(tab.mouseArea.clickCount, 3) |
2703 | + |
2704 | + // Destroy object and check children have gone |
2705 | + Reparenter.destroyContextAndObject(tab) |
2706 | + tryCompare(tab, "mouseArea", undefined) |
2707 | + } |
2708 | + |
2709 | + function test_reparenter_qml_expect_fail() { |
2710 | + var tab = containerLeft.makeTab() |
2711 | + |
2712 | + // Click on tab ensure it has been clicked |
2713 | + mouseClick(root, 25, 50, Qt.LeftButton) |
2714 | + compare(tab.mouseArea.clickCount, 1) |
2715 | + |
2716 | + // Move tab |
2717 | + addExisting(containerRight, tab) |
2718 | + |
2719 | + // Click on tab ensure it has been clicked |
2720 | + mouseClick(root, 75, 50, Qt.LeftButton) |
2721 | + compare(tab.mouseArea.clickCount, 2) |
2722 | + |
2723 | + // Destroy context |
2724 | + containerLeft.destroy() |
2725 | + |
2726 | + // Attempt to click on tab find that children of tab have been |
2727 | + // destroyed as the context has gone |
2728 | + mouseClick(root, 75, 50, Qt.LeftButton) |
2729 | + tryCompare(tab, "mouseArea", undefined) |
2730 | + } |
2731 | + } |
2732 | +} |
2733 | |
2734 | === modified file 'tests/unittests/qml/tst_TabsBar.qml' |
2735 | --- tests/unittests/qml/tst_TabsBar.qml 2016-10-04 11:33:37 +0000 |
2736 | +++ tests/unittests/qml/tst_TabsBar.qml 2016-11-30 14:23:08 +0000 |
2737 | @@ -28,6 +28,8 @@ |
2738 | height: 200 |
2739 | signal reload(string url) |
2740 | |
2741 | + readonly property string __platformName: "MOCKED_PLATFORM_NAME" |
2742 | + |
2743 | TabsModel { |
2744 | id: tabsModel |
2745 | } |
2746 | |
2747 | === modified file 'tests/unittests/qml/tst_UbuntuWebView02.qml' |
2748 | --- tests/unittests/qml/tst_UbuntuWebView02.qml 2016-09-19 13:17:54 +0000 |
2749 | +++ tests/unittests/qml/tst_UbuntuWebView02.qml 2016-11-30 14:23:08 +0000 |
2750 | @@ -95,6 +95,7 @@ |
2751 | function test_no_contextual_actions() { |
2752 | loadHtmlWithHyperlink() |
2753 | rightClickWebview() |
2754 | + wait(500) |
2755 | compare(waitFor(getContextMenu), null) |
2756 | } |
2757 | |
2758 | |
2759 | === modified file 'tests/unittests/search-engine/CMakeLists.txt' |
2760 | --- tests/unittests/search-engine/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2761 | +++ tests/unittests/search-engine/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2762 | @@ -11,4 +11,4 @@ |
2763 | Qt5::Core |
2764 | Qt5::Test |
2765 | ) |
2766 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2767 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2768 | |
2769 | === modified file 'tests/unittests/session-storage/CMakeLists.txt' |
2770 | --- tests/unittests/session-storage/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2771 | +++ tests/unittests/session-storage/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2772 | @@ -11,4 +11,4 @@ |
2773 | Qt5::Core |
2774 | Qt5::Test |
2775 | ) |
2776 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2777 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2778 | |
2779 | === modified file 'tests/unittests/session-utils/CMakeLists.txt' |
2780 | --- tests/unittests/session-utils/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2781 | +++ tests/unittests/session-utils/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2782 | @@ -11,4 +11,4 @@ |
2783 | Qt5::Core |
2784 | Qt5::Test |
2785 | ) |
2786 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2787 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2788 | |
2789 | === modified file 'tests/unittests/single-instance-manager/CMakeLists.txt' |
2790 | --- tests/unittests/single-instance-manager/CMakeLists.txt 2016-01-18 14:45:12 +0000 |
2791 | +++ tests/unittests/single-instance-manager/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2792 | @@ -13,5 +13,5 @@ |
2793 | Qt5::Network |
2794 | Qt5::Test |
2795 | ) |
2796 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2797 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2798 | set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal") |
2799 | |
2800 | === modified file 'tests/unittests/tabs-model/CMakeLists.txt' |
2801 | --- tests/unittests/tabs-model/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2802 | +++ tests/unittests/tabs-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2803 | @@ -14,5 +14,5 @@ |
2804 | Qt5::Test |
2805 | webbrowser-app-models |
2806 | ) |
2807 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2808 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2809 | set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal") |
2810 | |
2811 | === modified file 'tests/unittests/text-search-filter-model/CMakeLists.txt' |
2812 | --- tests/unittests/text-search-filter-model/CMakeLists.txt 2015-08-19 13:16:06 +0000 |
2813 | +++ tests/unittests/text-search-filter-model/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2814 | @@ -10,4 +10,4 @@ |
2815 | Qt5::Test |
2816 | webbrowser-app-models |
2817 | ) |
2818 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2819 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2820 | |
2821 | === modified file 'tests/unittests/webapp-container-color-helper/CMakeLists.txt' |
2822 | --- tests/unittests/webapp-container-color-helper/CMakeLists.txt 2016-04-04 17:14:01 +0000 |
2823 | +++ tests/unittests/webapp-container-color-helper/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2824 | @@ -13,5 +13,5 @@ |
2825 | Qt5::Gui |
2826 | Qt5::Test |
2827 | ) |
2828 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2829 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
2830 | set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal") |
2831 | |
2832 | === modified file 'tests/unittests/webapp-container-hook/CMakeLists.txt' |
2833 | --- tests/unittests/webapp-container-hook/CMakeLists.txt 2015-06-22 10:29:20 +0000 |
2834 | +++ tests/unittests/webapp-container-hook/CMakeLists.txt 2016-11-30 14:23:08 +0000 |
2835 | @@ -13,4 +13,4 @@ |
2836 | Qt5::Core |
2837 | Qt5::Test |
2838 | ) |
2839 | -add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
2840 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) |
FAILED: Continuous integration, rev:1574 /jenkins. canonical. com/system- apps/job/ lp-webbrowser- app-ci/ 722/ /jenkins. canonical. com/system- apps/job/ build/1931/ console /jenkins. canonical. com/system- apps/job/ build-0- fetch/1932 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 1771 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 1771/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 1771/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= zesty/1771 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= zesty/1771/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 1771 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 1771/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1771/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= zesty/1771 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= zesty/1771/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 1771 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 1771/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 1771/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= zesty/1771 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= zesty/1771/ artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- apps/job/ lp-webbrowser- app-ci/ 722/rebuild
https:/