Merge lp:~osomon/webbrowser-app/lazy-webviews into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Approved by: Michael Sheldon
Approved revision: 695
Merged at revision: 686
Proposed branch: lp:~osomon/webbrowser-app/lazy-webviews
Merge into: lp:webbrowser-app
Diff against target: 1200 lines (+314/-203)
12 files modified
po/webbrowser-app.pot (+17/-13)
src/app/webbrowser/Browser.qml (+98/-41)
src/app/webbrowser/TabPreview.qml (+33/-9)
src/app/webbrowser/TabsView.qml (+11/-7)
src/app/webbrowser/tabs-model.cpp (+36/-36)
src/app/webbrowser/tabs-model.h (+7/-7)
src/app/webbrowser/webbrowser-app.qml (+2/-1)
tests/autopilot/webbrowser_app/emulators/browser.py (+3/-0)
tests/autopilot/webbrowser_app/tests/__init__.py (+6/-0)
tests/autopilot/webbrowser_app/tests/test_session_save_restore.py (+1/-0)
tests/autopilot/webbrowser_app/tests/test_tabs.py (+6/-1)
tests/unittests/tabs-model/tst_TabsModelTests.cpp (+94/-88)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/lazy-webviews
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Michael Sheldon (community) Approve
Review via email: mp+231576@code.launchpad.net

Commit message

Instantiate webviews on demand, only when they really need to be shown.
Show placeholder artwork and text in empty tab previews.

To post a comment you must log in.
688. By Olivier Tilloy

Add placeholder artwork and text for empty tab previews.

689. By Olivier Tilloy

Add missing asset.

Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

The "Open link in new tab" behaviour seems to be broken, the currently focused tab remains visible but unresponsive to interaction (the new tab can be switched to via the "Open tabs" menu and switching back to the original tab restores responsiveness). Other than that it's looking really good!

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
690. By Olivier Tilloy

Fix the "Open [link|image] in new tab" contextual actions to instantiate the requested webview right away.

Revision history for this message
Olivier Tilloy (osomon) wrote :

> The "Open link in new tab" behaviour seems to be broken, the currently focused
> tab remains visible but unresponsive to interaction (the new tab can be
> switched to via the "Open tabs" menu and switching back to the original tab
> restores responsiveness). Other than that it's looking really good!

Good catch, thanks Michael! I keep meaning to write autopilot tests for the contextual actions, but never get around to doing it. I’ll see if I can bump the priority of this task, such tests would have caught this regression. I fixed it with revision 690.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:690
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/1048/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/3869
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/2977/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/247
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/247
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/247/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/247
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/3726
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5116
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5116/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/11849
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/2418/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3261
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3261/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/1048/rebuild

review: Needs Fixing (continuous-integration)
691. By Olivier Tilloy

Ensure the tab previews fill up the available vertical space if there aren’t enough of them to fill it with their default height.

692. By Olivier Tilloy

Fix a harmless warning.

693. By Olivier Tilloy

Update translation template.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
694. By Olivier Tilloy

Fix opening new tabs from the URL dispatcher.
Changed the default behaviour of openUrlInNewTab() to instantiate the corresponding webview by default (can be overridden).

695. By Olivier Tilloy

Update translation template again.

Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

All working very nicely now!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:695
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/1050/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/3898
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/3002/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/249
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/249
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/249/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/249
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/3754
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5145
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5145/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/11896
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/2443/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3287
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3287/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/1050/rebuild

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'po/webbrowser-app.pot'
2--- po/webbrowser-app.pot 2014-08-14 09:15:21 +0000
3+++ po/webbrowser-app.pot 2014-08-21 11:29:14 +0000
4@@ -8,7 +8,7 @@
5 msgstr ""
6 "Project-Id-Version: webbrowser-app\n"
7 "Report-Msgid-Bugs-To: \n"
8-"POT-Creation-Date: 2014-08-14 11:13+0200\n"
9+"POT-Creation-Date: 2014-08-21 13:27+0200\n"
10 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Language-Team: LANGUAGE <LL@li.org>\n"
13@@ -249,30 +249,30 @@
14 msgid "search or enter an address"
15 msgstr ""
16
17-#: src/app/webbrowser/Browser.qml:150
18+#: src/app/webbrowser/Browser.qml:154
19 msgid "Share"
20 msgstr ""
21
22-#: src/app/webbrowser/Browser.qml:164
23+#: src/app/webbrowser/Browser.qml:168
24 msgid "History"
25 msgstr ""
26
27-#: src/app/webbrowser/Browser.qml:170
28+#: src/app/webbrowser/Browser.qml:174
29 msgid "Open tabs"
30 msgstr ""
31
32-#: src/app/webbrowser/Browser.qml:176 src/app/webbrowser/TabsView.qml:55
33+#: src/app/webbrowser/Browser.qml:180 src/app/webbrowser/TabsView.qml:57
34 msgid "New tab"
35 msgstr ""
36
37-#: src/app/webbrowser/ExpandedHistoryView.qml:99
38+#: src/app/webbrowser/ExpandedHistoryView.qml:107
39 #, qt-format
40 msgid "%1 page"
41 msgid_plural "%1 pages"
42 msgstr[0] ""
43 msgstr[1] ""
44
45-#: src/app/webbrowser/ExpandedHistoryView.qml:113
46+#: src/app/webbrowser/ExpandedHistoryView.qml:121
47 msgid "Less"
48 msgstr ""
49
50@@ -284,23 +284,23 @@
51 msgid "Yesterday"
52 msgstr ""
53
54-#: src/app/webbrowser/HistoryView.qml:95 src/app/webbrowser/TabsView.qml:96
55+#: src/app/webbrowser/HistoryView.qml:99 src/app/webbrowser/TabsView.qml:100
56 msgid "Done"
57 msgstr ""
58
59-#: src/app/webbrowser/HistoryView.qml:109
60+#: src/app/webbrowser/HistoryView.qml:113
61 msgid "Clear"
62 msgstr ""
63
64-#: src/app/webbrowser/HistoryView.qml:123
65+#: src/app/webbrowser/HistoryView.qml:127
66 msgid "Delete all history?"
67 msgstr ""
68
69-#: src/app/webbrowser/HistoryView.qml:126
70+#: src/app/webbrowser/HistoryView.qml:130
71 msgid "Yes"
72 msgstr ""
73
74-#: src/app/webbrowser/HistoryView.qml:135
75+#: src/app/webbrowser/HistoryView.qml:139
76 msgid "No"
77 msgstr ""
78
79@@ -320,7 +320,11 @@
80 msgid "see more"
81 msgstr ""
82
83-#: src/app/webbrowser/TabsView.qml:111
84+#: src/app/webbrowser/TabPreview.qml:162
85+msgid "Tap to view"
86+msgstr ""
87+
88+#: src/app/webbrowser/TabsView.qml:115
89 msgid "Add"
90 msgstr ""
91
92
93=== modified file 'src/app/webbrowser/Browser.qml'
94--- src/app/webbrowser/Browser.qml 2014-08-18 13:04:52 +0000
95+++ src/app/webbrowser/Browser.qml 2014-08-21 11:29:14 +0000
96@@ -27,7 +27,7 @@
97 BrowserView {
98 id: browser
99
100- currentWebview: tabsModel.currentWebview
101+ currentWebview: tabsModel.currentTab ? tabsModel.currentTab.webview : null
102
103 property url homepage
104 property QtObject searchEngine
105@@ -53,7 +53,7 @@
106 onTriggered: _bookmarksModel.add(currentWebview.url, currentWebview.title, currentWebview.icon)
107 },
108 Actions.NewTab {
109- onTriggered: openUrlInNewTab("", true)
110+ onTriggered: browser.openUrlInNewTab("", true)
111 },
112 Actions.ClearHistory {
113 onTriggered: _historyModel.clearAll()
114@@ -63,9 +63,9 @@
115 Item {
116 id: previewsContainer
117
118- width: webviewContainer.width
119- height: webviewContainer.height
120- y: webviewContainer.y
121+ width: tabContainer.width
122+ height: tabContainer.height
123+ y: tabContainer.y
124
125 Component {
126 id: previewComponent
127@@ -73,11 +73,15 @@
128 ShaderEffectSource {
129 id: preview
130
131+ property var tab
132+
133 width: parent.width
134 height: parent.height
135
136- onSourceItemChanged: {
137- if (!sourceItem) {
138+ sourceItem: tab ? tab.webview : null
139+
140+ onTabChanged: {
141+ if (!tab) {
142 this.destroy()
143 }
144 }
145@@ -94,7 +98,7 @@
146 visible: !historyViewContainer.visible && !tabsViewContainer.visible
147
148 Item {
149- id: webviewContainer
150+ id: tabContainer
151 anchors {
152 left: parent.left
153 right: parent.right
154@@ -104,7 +108,7 @@
155 }
156
157 ErrorSheet {
158- anchors.fill: webviewContainer
159+ anchors.fill: tabContainer
160 visible: currentWebview ? currentWebview.lastLoadFailed : false
161 url: currentWebview ? currentWebview.url : ""
162 onRefreshClicked: currentWebview.reload()
163@@ -214,7 +218,7 @@
164 horizontalCenter: parent.horizontalCenter
165 }
166 width: chrome.width - units.gu(5)
167- height: enabled ? Math.min(contentHeight, webviewContainer.height - units.gu(2)) : 0
168+ height: enabled ? Math.min(contentHeight, tabContainer.height - units.gu(2)) : 0
169 model: historyMatches
170 onSelected: {
171 browser.currentWebview.url = url
172@@ -235,8 +239,11 @@
173 TabsView {
174 anchors.fill: parent
175 model: tabsModel
176- onNewTabRequested: browser.openUrlInNewTab("", true)
177- onDone: this.destroy()
178+ onNewTabRequested: browser.openUrlInNewTab("", true, false)
179+ onDone: {
180+ tabsModel.currentTab.load()
181+ this.destroy()
182+ }
183 }
184 }
185 }
186@@ -308,14 +315,50 @@
187 }
188
189 Component {
190+ id: tabComponent
191+
192+ FocusScope {
193+ property url initialUrl
194+ property string initialTitle
195+ property var request
196+ readonly property var webview: (children.length == 1) ? children[0] : null
197+ readonly property url url: webview ? webview.url : initialUrl
198+ readonly property string title: webview ? webview.title : initialTitle
199+ readonly property url icon: webview ? webview.icon : ""
200+ property var preview
201+
202+ anchors.fill: parent
203+
204+ function load() {
205+ if (!webview) {
206+ webviewComponent.createObject(this, {"url": initialUrl})
207+ }
208+ }
209+
210+ function unload() {
211+ if (webview) {
212+ webview.destroy()
213+ }
214+ }
215+
216+ Component.onCompleted: {
217+ if (request) {
218+ // Instantiating the webview cannot be delayed because the request
219+ // object is destroyed after exiting the newViewRequested signal handler.
220+ webviewComponent.createObject(this, {"request": request})
221+ }
222+ }
223+ }
224+ }
225+
226+ Component {
227 id: webviewComponent
228
229 WebViewImpl {
230 currentWebview: browser.currentWebview
231
232- property var preview
233-
234 anchors.fill: parent
235+ focus: true
236
237 readonly property bool current: currentWebview === this
238 enabled: current
239@@ -328,7 +371,7 @@
240 contextualActions: ActionList {
241 Actions.OpenLinkInNewTab {
242 enabled: contextualData.href.toString()
243- onTriggered: openUrlInNewTab(contextualData.href, true)
244+ onTriggered: browser.openUrlInNewTab(contextualData.href, true)
245 }
246 Actions.BookmarkLink {
247 enabled: contextualData.href.toString()
248@@ -340,7 +383,7 @@
249 }
250 Actions.OpenImageInNewTab {
251 enabled: contextualData.img.toString()
252- onTriggered: openUrlInNewTab(contextualData.img, true)
253+ onTriggered: browser.openUrlInNewTab(contextualData.img, true)
254 }
255 Actions.CopyImage {
256 enabled: contextualData.img.toString()
257@@ -353,9 +396,9 @@
258 }
259
260 onNewViewRequested: {
261- var webview = webviewComponent.createObject(webviewContainer, {"request": request})
262+ var tab = tabComponent.createObject(tabContainer, {"request": request})
263 var setCurrent = (request.disposition == Oxide.NewViewRequest.DispositionNewForegroundTab)
264- internal.addTab(webview, setCurrent, false)
265+ internal.addTab(tab, setCurrent, false)
266 }
267
268 onLoadingChanged: {
269@@ -402,22 +445,30 @@
270 QtObject {
271 id: internal
272
273- function addTab(webview, setCurrent, focusAddressBar) {
274- var index = tabsModel.add(webview)
275+ function addTab(tab, setCurrent, focusAddressBar) {
276+ var index = tabsModel.add(tab)
277 if (setCurrent) {
278 tabsModel.setCurrent(index)
279 if (focusAddressBar) {
280- chrome.forceActiveFocus()
281- Qt.inputMethod.show() // work around http://pad.lv/1316057
282+ internal.focusAddressBar()
283 }
284 }
285- webview.preview = previewComponent.createObject(previewsContainer, {sourceItem: webview})
286+ tab.preview = previewComponent.createObject(previewsContainer, {tab: tab})
287+ }
288+
289+ function focusAddressBar() {
290+ chrome.forceActiveFocus()
291+ Qt.inputMethod.show() // work around http://pad.lv/1316057
292 }
293 }
294
295- function openUrlInNewTab(url, setCurrent) {
296- var webview = webviewComponent.createObject(webviewContainer, {"url": url})
297- internal.addTab(webview, setCurrent, !url.toString() && (formFactor == "desktop"))
298+ function openUrlInNewTab(url, setCurrent, load) {
299+ load = typeof load !== 'undefined' ? load : true
300+ var tab = tabComponent.createObject(tabContainer, {"initialUrl": url})
301+ internal.addTab(tab, setCurrent, !url.toString() && (formFactor == "desktop"))
302+ if (load) {
303+ tabsModel.currentTab.load()
304+ }
305 }
306
307 SessionStorage {
308@@ -431,9 +482,8 @@
309 }
310 var tabs = []
311 for (var i = 0; i < tabsModel.count; ++i) {
312- var webview = tabsModel.get(i)
313- var tab = serializeWebviewState(webview)
314- tabs.push(tab)
315+ var tab = tabsModel.get(i)
316+ tabs.push(serializeTabState(tab))
317 }
318 store(JSON.stringify({tabs: tabs}))
319 }
320@@ -452,46 +502,53 @@
321 var tabs = state.tabs
322 if (tabs) {
323 for (var i = 0; i < tabs.length; ++i) {
324- var webview = createWebviewFromState(tabs[i])
325- internal.addTab(webview, i == 0, false)
326+ var tab = createTabFromState(tabs[i])
327+ internal.addTab(tab, i == 0, false)
328 }
329 }
330 }
331 }
332
333- // Those two functions are used to save/restore the current state of a webview.
334+ // Those two functions are used to save/restore the current state of a tab.
335 // The current implementation is naive, it only saves/restores the current URL.
336 // In the future, we’ll want to rely on oxide to save and restore a full state
337- // of the webview as a binary blob, which includes navigation history, current
338- // scroll offset and form data. See http://pad.lv/1353143.
339- function serializeWebviewState(webview) {
340+ // of the corresponding webview as a binary blob, which includes navigation
341+ // history, current scroll offset and form data. See http://pad.lv/1353143.
342+ function serializeTabState(tab) {
343 var state = {}
344- state.url = webview.url.toString()
345+ state.url = tab.url.toString()
346+ state.title = tab.title
347 return state
348 }
349
350- function createWebviewFromState(state) {
351- return webviewComponent.createObject(webviewContainer, {"url": state.url})
352+ function createTabFromState(state) {
353+ var properties = {"initialUrl": state.url, "initialTitle": state.title}
354+ return tabComponent.createObject(tabContainer, properties)
355 }
356 }
357 Connections {
358 target: tabsModel
359- onCurrentWebviewChanged: session.save()
360+ onCurrentTabChanged: session.save()
361 onCountChanged: session.save()
362 }
363 Connections {
364 target: browser.currentWebview
365 onUrlChanged: session.save()
366+ onTitleChanged: session.save()
367 }
368 Component.onCompleted: {
369 if (browser.restoreSession) {
370 session.restore()
371 }
372 for (var i in browser.initialUrls) {
373- browser.openUrlInNewTab(browser.initialUrls[i], true)
374+ browser.openUrlInNewTab(browser.initialUrls[i], true, false)
375 }
376 if (tabsModel.count == 0) {
377- browser.openUrlInNewTab(browser.homepage, true)
378+ browser.openUrlInNewTab(browser.homepage, true, false)
379+ }
380+ tabsModel.currentTab.load()
381+ if (!tabsModel.currentTab.url.toString() && (formFactor == "desktop")) {
382+ internal.focusAddressBar()
383 }
384 }
385 }
386
387=== modified file 'src/app/webbrowser/TabPreview.qml'
388--- src/app/webbrowser/TabPreview.qml 2014-08-12 06:04:50 +0000
389+++ src/app/webbrowser/TabPreview.qml 2014-08-21 11:29:14 +0000
390@@ -20,11 +20,11 @@
391 import Ubuntu.Components 1.1
392
393 Column {
394- id: tab
395+ id: tabPreview
396
397 property alias title: label.text
398- property var webview
399- readonly property url url: webview ? webview.url : ""
400+ property var tab
401+ readonly property url url: tab ? tab.url : ""
402
403 signal selected()
404 signal closeRequested()
405@@ -56,7 +56,7 @@
406 name: "close"
407 }
408
409- onTriggered: tab.closeRequested()
410+ onTriggered: tabPreview.closeRequested()
411
412 Rectangle {
413 anchors {
414@@ -122,7 +122,7 @@
415 }
416 width: parent.width / 2
417
418- onClicked: tab.selected()
419+ onClicked: tabPreview.selected()
420 }
421 }
422 }
423@@ -143,15 +143,39 @@
424 width: parent.width
425 height: parent.height - header.height
426
427+ Image {
428+ visible: !previewContainer.visible
429+ source: "assets/tab-artwork.png"
430+ fillMode: Image.PreserveAspectFit
431+ height: Math.min(parent.height / 1.6, units.gu(28))
432+ width: height
433+ anchors {
434+ right: parent.right
435+ rightMargin: -width / 5
436+ bottom: parent.bottom
437+ bottomMargin: -height / 10
438+ }
439+ }
440+
441+ Label {
442+ visible: !previewContainer.visible
443+ text: i18n.tr("Tap to view")
444+ anchors {
445+ centerIn: parent
446+ verticalCenterOffset: units.gu(-2)
447+ }
448+ }
449+
450 Item {
451 id: previewContainer
452+ visible: tabPreview.tab ? tabPreview.tab.webview : false
453 anchors.fill: parent
454 clip: true
455 }
456
457 MouseArea {
458 anchors.fill: parent
459- onClicked: tab.selected()
460+ onClicked: tabPreview.selected()
461 }
462
463 Rectangle {
464@@ -172,15 +196,15 @@
465 }
466
467 Component.onCompleted: {
468- var preview = tab.webview.preview
469+ var preview = tabPreview.tab.preview
470 internal.previewParent = preview.parent
471 preview.parent = previewContainer
472 preview.width = internal.previewParent.width
473 preview.height = internal.previewParent.height
474 }
475 Component.onDestruction: {
476- if (tab.webview) {
477- var preview = tab.webview.preview
478+ if (tabPreview.tab) {
479+ var preview = tabPreview.tab.preview
480 preview.parent = internal.previewParent
481 preview.width = preview.parent.width
482 preview.height = preview.parent.height
483
484=== modified file 'src/app/webbrowser/TabsView.qml'
485--- src/app/webbrowser/TabsView.qml 2014-08-08 17:29:21 +0000
486+++ src/app/webbrowser/TabsView.qml 2014-08-21 11:29:14 +0000
487@@ -43,27 +43,31 @@
488 bottom: toolbar.top
489 }
490
491- spacing: units.gu(-10)
492+ spacing: units.gu(-5)
493
494 boundsBehavior: Flickable.StopAtBounds
495
496 delegate: TabPreview {
497 width: parent.width
498- height: (listview.count == 1) ? listview.height : units.gu(40)
499+ readonly property real minHeight: units.gu(35)
500+ height: (listview.count * minHeight + (listview.count - 1) * listview.spacing) < listview.height ? (listview.height + (1 - listview.count) * listview.spacing) / listview.count : minHeight
501+
502 z: index
503
504 title: model.title ? model.title : (model.url.toString() ? model.url : i18n.tr("New tab"))
505- webview: model.webview
506+ tab: model.tab
507
508 onSelected: {
509+ tab.load()
510+ tab.forceActiveFocus()
511 tabsview.model.setCurrent(index)
512- webview.forceActiveFocus()
513 tabsview.done()
514 }
515 onCloseRequested: {
516- var webview = tabsview.model.remove(index)
517- if (webview) {
518- webview.destroy()
519+ var tab = tabsview.model.remove(index)
520+ if (tab) {
521+ tab.unload()
522+ tab.destroy()
523 }
524 if (tabsview.model.count === 0) {
525 tabsview.newTabRequested()
526
527=== added file 'src/app/webbrowser/assets/tab-artwork.png'
528Binary files src/app/webbrowser/assets/tab-artwork.png 1970-01-01 00:00:00 +0000 and src/app/webbrowser/assets/tab-artwork.png 2014-08-21 11:29:14 +0000 differ
529=== modified file 'src/app/webbrowser/tabs-model.cpp'
530--- src/app/webbrowser/tabs-model.cpp 2014-08-06 13:57:06 +0000
531+++ src/app/webbrowser/tabs-model.cpp 2014-08-21 11:29:14 +0000
532@@ -27,11 +27,11 @@
533 \brief List model that stores the list of currently open tabs.
534
535 TabsModel is a list model that stores the list of currently open tabs.
536- Each tab holds a pointer to a WebView and associated metadata (URL, title,
537+ Each tab holds a pointer to a Tab and associated metadata (URL, title,
538 icon).
539
540- The model doesn’t own the WebView, so it is the responsibility of whoever
541- adds a tab to instantiate the corresponding WebView, and to destroy it after
542+ The model doesn’t own the Tab, so it is the responsibility of whoever
543+ adds a tab to instantiate the corresponding Tab, and to destroy it after
544 it’s removed from the model.
545 */
546 TabsModel::TabsModel(QObject* parent)
547@@ -50,7 +50,7 @@
548 roles[Url] = "url";
549 roles[Title] = "title";
550 roles[Icon] = "icon";
551- roles[WebView] = "webview";
552+ roles[Tab] = "tab";
553 }
554 return roles;
555 }
556@@ -58,7 +58,7 @@
557 int TabsModel::rowCount(const QModelIndex& parent) const
558 {
559 Q_UNUSED(parent);
560- return m_webviews.count();
561+ return m_tabs.count();
562 }
563
564 QVariant TabsModel::data(const QModelIndex& index, int role) const
565@@ -66,61 +66,61 @@
566 if (!index.isValid()) {
567 return QVariant();
568 }
569- QObject* webview = m_webviews.at(index.row());
570+ QObject* tab = m_tabs.at(index.row());
571 switch (role) {
572 case Url:
573- return webview->property("url");
574+ return tab->property("url");
575 case Title:
576- return webview->property("title");
577+ return tab->property("title");
578 case Icon:
579- return webview->property("icon");
580- case WebView:
581- return QVariant::fromValue(webview);
582+ return tab->property("icon");
583+ case Tab:
584+ return QVariant::fromValue(tab);
585 default:
586 return QVariant();
587 }
588 }
589
590-QObject* TabsModel::currentWebview() const
591+QObject* TabsModel::currentTab() const
592 {
593- if (m_webviews.isEmpty()) {
594+ if (m_tabs.isEmpty()) {
595 return 0;
596 }
597- return m_webviews.first();
598+ return m_tabs.first();
599 }
600
601 /*!
602 Add a tab to the model and return the corresponding index in the model.
603
604 It is the responsibility of the caller to instantiate the corresponding
605- WebView beforehand.
606+ Tab beforehand.
607 */
608-int TabsModel::add(QObject* webview)
609+int TabsModel::add(QObject* tab)
610 {
611- if (webview == 0) {
612- qWarning() << "Invalid WebView";
613+ if (tab == 0) {
614+ qWarning() << "Invalid Tab";
615 return -1;
616 }
617- int index = m_webviews.count();
618+ int index = m_tabs.count();
619 beginInsertRows(QModelIndex(), index, index);
620- m_webviews.append(webview);
621- connect(webview, SIGNAL(urlChanged()), SLOT(onUrlChanged()));
622- connect(webview, SIGNAL(titleChanged()), SLOT(onTitleChanged()));
623- connect(webview, SIGNAL(iconChanged()), SLOT(onIconChanged()));
624+ m_tabs.append(tab);
625+ connect(tab, SIGNAL(urlChanged()), SLOT(onUrlChanged()));
626+ connect(tab, SIGNAL(titleChanged()), SLOT(onTitleChanged()));
627+ connect(tab, SIGNAL(iconChanged()), SLOT(onIconChanged()));
628 endInsertRows();
629 Q_EMIT countChanged();
630 if (index == 0) {
631- Q_EMIT currentWebviewChanged();
632+ Q_EMIT currentTabChanged();
633 }
634 return index;
635 }
636
637 /*!
638 Given its index, remove a tab from the model, and return the corresponding
639- WebView.
640+ Tab.
641
642 It is the responsibility of the caller to destroy the corresponding
643- WebView afterwards.
644+ Tab afterwards.
645 */
646 QObject* TabsModel::remove(int index)
647 {
648@@ -128,14 +128,14 @@
649 return 0;
650 }
651 beginRemoveRows(QModelIndex(), index, index);
652- QObject* webview = m_webviews.takeAt(index);
653- webview->disconnect(this);
654+ QObject* tab = m_tabs.takeAt(index);
655+ tab->disconnect(this);
656 endRemoveRows();
657 Q_EMIT countChanged();
658 if (index == 0) {
659- Q_EMIT currentWebviewChanged();
660+ Q_EMIT currentTabChanged();
661 }
662- return webview;
663+ return tab;
664 }
665
666 void TabsModel::setCurrent(int index)
667@@ -147,9 +147,9 @@
668 return;
669 }
670 beginMoveRows(QModelIndex(), index, index, QModelIndex(), 0);
671- m_webviews.prepend(m_webviews.takeAt(index));
672+ m_tabs.prepend(m_tabs.takeAt(index));
673 endMoveRows();
674- Q_EMIT currentWebviewChanged();
675+ Q_EMIT currentTabChanged();
676 }
677
678 QObject* TabsModel::get(int index) const
679@@ -157,21 +157,21 @@
680 if (!checkValidTabIndex(index)) {
681 return 0;
682 }
683- return m_webviews.at(index);
684+ return m_tabs.at(index);
685 }
686
687 bool TabsModel::checkValidTabIndex(int index) const
688 {
689- if ((index < 0) || (index >= m_webviews.count())) {
690+ if ((index < 0) || (index >= m_tabs.count())) {
691 qWarning() << "Invalid tab index:" << index;
692 return false;
693 }
694 return true;
695 }
696
697-void TabsModel::onDataChanged(QObject* webview, int role)
698+void TabsModel::onDataChanged(QObject* tab, int role)
699 {
700- int index = m_webviews.indexOf(webview);
701+ int index = m_tabs.indexOf(tab);
702 if (checkValidTabIndex(index)) {
703 Q_EMIT dataChanged(this->index(index, 0), this->index(index, 0), QVector<int>() << role);
704 }
705
706=== modified file 'src/app/webbrowser/tabs-model.h'
707--- src/app/webbrowser/tabs-model.h 2014-08-06 13:57:06 +0000
708+++ src/app/webbrowser/tabs-model.h 2014-08-21 11:29:14 +0000
709@@ -31,7 +31,7 @@
710
711 Q_ENUMS(Roles)
712
713- Q_PROPERTY(QObject* currentWebview READ currentWebview NOTIFY currentWebviewChanged)
714+ Q_PROPERTY(QObject* currentTab READ currentTab NOTIFY currentTabChanged)
715 Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
716
717 public:
718@@ -42,7 +42,7 @@
719 Url = Qt::UserRole + 1,
720 Title,
721 Icon,
722- WebView
723+ Tab
724 };
725
726 // reimplemented from QAbstractListModel
727@@ -50,15 +50,15 @@
728 int rowCount(const QModelIndex& parent=QModelIndex()) const;
729 QVariant data(const QModelIndex& index, int role) const;
730
731- QObject* currentWebview() const;
732+ QObject* currentTab() const;
733
734- Q_INVOKABLE int add(QObject* webview);
735+ Q_INVOKABLE int add(QObject* tab);
736 Q_INVOKABLE QObject* remove(int index);
737 Q_INVOKABLE void setCurrent(int index);
738 Q_INVOKABLE QObject* get(int index) const;
739
740 Q_SIGNALS:
741- void currentWebviewChanged() const;
742+ void currentTabChanged() const;
743 void countChanged() const;
744
745 private Q_SLOTS:
746@@ -67,10 +67,10 @@
747 void onIconChanged();
748
749 private:
750- QList<QObject*> m_webviews;
751+ QList<QObject*> m_tabs;
752
753 bool checkValidTabIndex(int index) const;
754- void onDataChanged(QObject* webview, int role);
755+ void onDataChanged(QObject* tab, int role);
756 };
757
758 #endif // __TABS_MODEL_H__
759
760=== modified file 'src/app/webbrowser/webbrowser-app.qml'
761--- src/app/webbrowser/webbrowser-app.qml 2014-08-08 13:51:25 +0000
762+++ src/app/webbrowser/webbrowser-app.qml 2014-08-21 11:29:14 +0000
763@@ -65,7 +65,8 @@
764 target: UriHandler
765 onOpened: {
766 for (var i = 0; i < uris.length; ++i) {
767- browser.openUrlInNewTab(uris[i], i == uris.length - 1)
768+ var setCurrent = (i == uris.length - 1)
769+ browser.openUrlInNewTab(uris[i], setCurrent, setCurrent)
770 }
771 }
772 }
773
774=== modified file 'tests/autopilot/webbrowser_app/emulators/browser.py'
775--- tests/autopilot/webbrowser_app/emulators/browser.py 2014-08-08 17:29:21 +0000
776+++ tests/autopilot/webbrowser_app/emulators/browser.py 2014-08-21 11:29:14 +0000
777@@ -119,6 +119,9 @@
778 def get_current_webview(self):
779 return self.select_single("WebViewImpl", current=True)
780
781+ def get_webviews(self):
782+ return self.select_many("WebViewImpl")
783+
784 def get_visible_webviews(self):
785 return self.select_many("WebViewImpl", visible=True)
786
787
788=== modified file 'tests/autopilot/webbrowser_app/tests/__init__.py'
789--- tests/autopilot/webbrowser_app/tests/__init__.py 2014-08-08 17:29:21 +0000
790+++ tests/autopilot/webbrowser_app/tests/__init__.py 2014-08-21 11:29:14 +0000
791@@ -149,16 +149,22 @@
792 self.main_window.get_tabs_view()
793
794 def open_new_tab(self):
795+ count = len(self.main_window.get_webviews())
796 # assumes the tabs view is already open
797 tabs_view = self.main_window.get_tabs_view()
798 add_button = tabs_view.get_add_button()
799 self.pointing_device.click_object(add_button)
800 tabs_view.wait_until_destroyed()
801+ self.assert_number_webviews_eventually(count + 1)
802 self.main_window.get_new_tab_view()
803 if model() == 'Desktop':
804 address_bar = self.main_window.get_chrome().get_address_bar()
805 self.assertThat(address_bar.activeFocus, Eventually(Equals(True)))
806
807+ def assert_number_webviews_eventually(self, count):
808+ self.assertThat(lambda: len(self.main_window.get_webviews()),
809+ Eventually(Equals(count)))
810+
811 def ping_server(self):
812 ping = urllib.request.urlopen(self.base_url + "/ping")
813 self.assertThat(ping.read(), Equals(b"pong"))
814
815=== modified file 'tests/autopilot/webbrowser_app/tests/test_session_save_restore.py'
816--- tests/autopilot/webbrowser_app/tests/test_session_save_restore.py 2014-08-11 06:31:21 +0000
817+++ tests/autopilot/webbrowser_app/tests/test_session_save_restore.py 2014-08-21 11:29:14 +0000
818@@ -52,3 +52,4 @@
819 for i in range(len(paths)):
820 self.assertThat(previews[len(paths) - 1 - i].url,
821 Eventually(Equals(self.base_url + paths[i])))
822+ self.assert_number_webviews_eventually(1)
823
824=== modified file 'tests/autopilot/webbrowser_app/tests/test_tabs.py'
825--- tests/autopilot/webbrowser_app/tests/test_tabs.py 2014-07-25 11:07:31 +0000
826+++ tests/autopilot/webbrowser_app/tests/test_tabs.py 2014-08-21 11:29:14 +0000
827@@ -60,6 +60,7 @@
828 close_button = preview.get_close_button()
829 self.pointing_device.click_object(close_button)
830 tabs_view.wait_until_destroyed()
831+ self.assert_number_webviews_eventually(1)
832 self.main_window.get_new_tab_view()
833 if model() == 'Desktop':
834 address_bar = self.main_window.get_chrome().get_address_bar()
835@@ -76,16 +77,18 @@
836 self.type_in_address_bar(url)
837 self.keyboard.press_and_release("Enter")
838 new_tab_view.wait_until_destroyed()
839+ self.assert_number_webviews_eventually(2)
840 self.open_tabs_view()
841 tabs_view = self.main_window.get_tabs_view()
842 previews = tabs_view.get_ordered_previews()
843 self.assertThat(len(previews), Equals(2))
844- preview = previews[1]
845+ preview = previews[0]
846 close_button = preview.get_close_button()
847 self.pointing_device.click_object(close_button)
848 self.assertThat(lambda: len(tabs_view.get_previews()),
849 Eventually(Equals(1)))
850 preview = tabs_view.get_previews()[0]
851+ self.assert_number_webviews_eventually(1)
852 webview = self.main_window.get_current_webview()
853 self.assertThat(preview.title, Equals(webview.title))
854
855@@ -142,6 +145,7 @@
856 webview = self.main_window.get_current_webview()
857 self.pointing_device.click_object(webview)
858 self.check_current_tab(self.base_url + "/aleaiactaest")
859+ self.assert_number_webviews_eventually(2)
860
861 def test_open_iframe_target_blank_in_new_tab(self):
862 url = self.base_url + "/fulliframewithblanktargetlink"
863@@ -150,6 +154,7 @@
864 webview = self.main_window.get_current_webview()
865 self.pointing_device.click_object(webview)
866 self.check_current_tab(self.base_url + "/aleaiactaest")
867+ self.assert_number_webviews_eventually(2)
868
869 def test_selecting_tab_focuses_webview(self):
870 self.focus_address_bar()
871
872=== modified file 'tests/unittests/tabs-model/tst_TabsModelTests.cpp'
873--- tests/unittests/tabs-model/tst_TabsModelTests.cpp 2014-07-25 11:03:45 +0000
874+++ tests/unittests/tabs-model/tst_TabsModelTests.cpp 2014-08-21 11:29:14 +0000
875@@ -34,7 +34,7 @@
876 private:
877 TabsModel* model;
878
879- QQuickItem* createWebView()
880+ QQuickItem* createTab()
881 {
882 QQmlEngine engine;
883 QQmlComponent component(&engine);
884@@ -55,13 +55,16 @@
885
886 void cleanup()
887 {
888+ while (model->rowCount() > 0) {
889+ delete model->remove(0);
890+ }
891 delete model;
892 }
893
894 void shouldBeInitiallyEmpty()
895 {
896 QCOMPARE(model->rowCount(), 0);
897- QCOMPARE(model->currentWebview(), (QObject*) 0);
898+ QCOMPARE(model->currentTab(), (QObject*) 0);
899 }
900
901 void shouldExposeRoleNames()
902@@ -70,45 +73,45 @@
903 QVERIFY(roleNames.contains("url"));
904 QVERIFY(roleNames.contains("title"));
905 QVERIFY(roleNames.contains("icon"));
906- QVERIFY(roleNames.contains("webview"));
907+ QVERIFY(roleNames.contains("tab"));
908 }
909
910 void shouldNotAllowSettingTheIndexToAnInvalidValue()
911 {
912 model->setCurrent(0);
913- QCOMPARE(model->currentWebview(), (QObject*) 0);
914+ QCOMPARE(model->currentTab(), (QObject*) 0);
915 model->setCurrent(2);
916- QCOMPARE(model->currentWebview(), (QObject*) 0);
917+ QCOMPARE(model->currentTab(), (QObject*) 0);
918 model->setCurrent(-2);
919- QCOMPARE(model->currentWebview(), (QObject*) 0);
920+ QCOMPARE(model->currentTab(), (QObject*) 0);
921 }
922
923- void shouldNotAddNullWebView()
924+ void shouldNotAddNullTab()
925 {
926 QCOMPARE(model->add(0), -1);
927 QCOMPARE(model->rowCount(), 0);
928 }
929
930- void shouldReturnIndexWhenAddingWebView()
931+ void shouldReturnIndexWhenAddingTab()
932 {
933 for(int i = 0; i < 3; ++i) {
934- QCOMPARE(model->add(createWebView()), i);
935+ QCOMPARE(model->add(createTab()), i);
936 }
937 }
938
939- void shouldUpdateCountWhenAddingWebView()
940+ void shouldUpdateCountWhenAddingTab()
941 {
942 QSignalSpy spy(model, SIGNAL(countChanged()));
943- model->add(createWebView());
944+ model->add(createTab());
945 QCOMPARE(spy.count(), 1);
946 QCOMPARE(model->rowCount(), 1);
947 }
948
949- void shouldUpdateCountWhenRemovingWebView()
950+ void shouldUpdateCountWhenRemovingTab()
951 {
952- model->add(createWebView());
953+ model->add(createTab());
954 QSignalSpy spy(model, SIGNAL(countChanged()));
955- model->remove(0);
956+ delete model->remove(0);
957 QCOMPARE(spy.count(), 1);
958 QCOMPARE(model->rowCount(), 0);
959 }
960@@ -120,39 +123,42 @@
961 QCOMPARE(model->remove(-2), (QObject*) 0);
962 }
963
964- void shouldReturnWebViewWhenRemoving()
965+ void shouldReturnTabWhenRemoving()
966 {
967- QQuickItem* webview = createWebView();
968- model->add(webview);
969+ QQuickItem* tab = createTab();
970+ model->add(tab);
971 QObject* removed = model->remove(0);
972- QCOMPARE(removed, webview);
973- }
974-
975- void shouldNotChangeCurrentWebviewWhenAddingUnlessModelWasEmpty()
976- {
977- QSignalSpy spy(model, SIGNAL(currentWebviewChanged()));
978- QQuickItem* webview = createWebView();
979- model->add(webview);
980- QCOMPARE(spy.count(), 1);
981- QCOMPARE(model->currentWebview(), webview);
982- model->add(createWebView());
983- QCOMPARE(spy.count(), 1);
984- QCOMPARE(model->currentWebview(), webview);
985- }
986-
987- void shouldNotDeleteWebViewWhenRemoving()
988- {
989- QQuickItem* webview = createWebView();
990- model->add(webview);
991+ QCOMPARE(removed, tab);
992+ delete removed;
993+ }
994+
995+ void shouldNotChangeCurrentTabWhenAddingUnlessModelWasEmpty()
996+ {
997+ QSignalSpy spy(model, SIGNAL(currentTabChanged()));
998+ QQuickItem* tab = createTab();
999+ model->add(tab);
1000+ QCOMPARE(spy.count(), 1);
1001+ QCOMPARE(model->currentTab(), tab);
1002+ spy.clear();
1003+ model->add(createTab());
1004+ QVERIFY(spy.isEmpty());
1005+ QCOMPARE(model->currentTab(), tab);
1006+ }
1007+
1008+ void shouldNotDeleteTabWhenRemoving()
1009+ {
1010+ QQuickItem* tab = createTab();
1011+ model->add(tab);
1012 model->remove(0);
1013- QCOMPARE(webview->parent(), this);
1014+ QCOMPARE(tab->parent(), this);
1015+ delete tab;
1016 }
1017
1018- void shouldNotifyWhenAddingWebView()
1019+ void shouldNotifyWhenAddingTab()
1020 {
1021 QSignalSpy spy(model, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
1022 for(int i = 0; i < 3; ++i) {
1023- model->add(createWebView());
1024+ model->add(createTab());
1025 QCOMPARE(spy.count(), 1);
1026 QList<QVariant> args = spy.takeFirst();
1027 QCOMPARE(args.at(1).toInt(), i);
1028@@ -160,19 +166,19 @@
1029 }
1030 }
1031
1032- void shouldNotifyWhenRemovingWebView()
1033+ void shouldNotifyWhenRemovingTab()
1034 {
1035 QSignalSpy spy(model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)));
1036 for(int i = 0; i < 5; ++i) {
1037- model->add(createWebView());
1038+ model->add(createTab());
1039 }
1040- model->remove(3);
1041+ delete model->remove(3);
1042 QCOMPARE(spy.count(), 1);
1043 QList<QVariant> args = spy.takeFirst();
1044 QCOMPARE(args.at(1).toInt(), 3);
1045 QCOMPARE(args.at(2).toInt(), 3);
1046 for(int i = 3; i >= 0; --i) {
1047- model->remove(i);
1048+ delete model->remove(i);
1049 QCOMPARE(spy.count(), 1);
1050 args = spy.takeFirst();
1051 QCOMPARE(args.at(1).toInt(), i);
1052@@ -180,14 +186,14 @@
1053 }
1054 }
1055
1056- void shouldNotifyWhenWebViewPropertiesChange()
1057+ void shouldNotifyWhenTabPropertiesChange()
1058 {
1059 qRegisterMetaType<QVector<int> >();
1060 QSignalSpy spy(model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
1061- QQuickItem* webview = createWebView();
1062- model->add(webview);
1063+ QQuickItem* tab = createTab();
1064+ model->add(tab);
1065
1066- QQmlProperty(webview, "url").write(QUrl("http://ubuntu.com"));
1067+ QQmlProperty(tab, "url").write(QUrl("http://ubuntu.com"));
1068 QCOMPARE(spy.count(), 1);
1069 QList<QVariant> args = spy.takeFirst();
1070 QCOMPARE(args.at(0).toModelIndex().row(), 0);
1071@@ -196,7 +202,7 @@
1072 QCOMPARE(roles.size(), 1);
1073 QVERIFY(roles.contains(TabsModel::Url));
1074
1075- QQmlProperty(webview, "title").write(QString("Lorem Ipsum"));
1076+ QQmlProperty(tab, "title").write(QString("Lorem Ipsum"));
1077 QCOMPARE(spy.count(), 1);
1078 args = spy.takeFirst();
1079 QCOMPARE(args.at(0).toModelIndex().row(), 0);
1080@@ -205,7 +211,7 @@
1081 QCOMPARE(roles.size(), 1);
1082 QVERIFY(roles.contains(TabsModel::Title));
1083
1084- QQmlProperty(webview, "icon").write(QUrl("image://webicon/123"));
1085+ QQmlProperty(tab, "icon").write(QUrl("image://webicon/123"));
1086 QCOMPARE(spy.count(), 1);
1087 args = spy.takeFirst();
1088 QCOMPARE(args.at(0).toModelIndex().row(), 0);
1089@@ -215,73 +221,73 @@
1090 QVERIFY(roles.contains(TabsModel::Icon));
1091 }
1092
1093- void shouldUpdateCurrentWebviewWhenSettingCurrent()
1094+ void shouldUpdateCurrentTabWhenSettingCurrent()
1095 {
1096- QQuickItem* webview1 = createWebView();
1097- model->add(webview1);
1098- QSignalSpy spy(model, SIGNAL(currentWebviewChanged()));
1099+ QQuickItem* tab1 = createTab();
1100+ model->add(tab1);
1101+ QSignalSpy spy(model, SIGNAL(currentTabChanged()));
1102 model->setCurrent(0);
1103- QCOMPARE(spy.count(), 0);
1104- QCOMPARE(model->currentWebview(), webview1);
1105- QQuickItem* webview2 = createWebView();
1106- model->add(webview2);
1107+ QVERIFY(spy.isEmpty());
1108+ QCOMPARE(model->currentTab(), tab1);
1109+ QQuickItem* tab2 = createTab();
1110+ model->add(tab2);
1111 model->setCurrent(1);
1112 QCOMPARE(spy.count(), 1);
1113- QCOMPARE(model->currentWebview(), webview2);
1114+ QCOMPARE(model->currentTab(), tab2);
1115 }
1116
1117- void shouldUpdateCurrentWebviewWhenRemoving()
1118+ void shouldUpdateCurrentTabWhenRemoving()
1119 {
1120- QSignalSpy spy(model, SIGNAL(currentWebviewChanged()));
1121+ QSignalSpy spy(model, SIGNAL(currentTabChanged()));
1122
1123- // Adding a webview to an empty model should update the current webview.
1124- // Removing the last webview from the model should update it too.
1125- model->add(createWebView());
1126- model->remove(0);
1127+ // Adding a tab to an empty model should update the current tab.
1128+ // Removing the last tab from the model should update it too.
1129+ model->add(createTab());
1130+ delete model->remove(0);
1131 QCOMPARE(spy.count(), 2);
1132
1133- // When removing a webview after the current one,
1134- // the current webview shouldn’t change.
1135- QQuickItem* webview1 = createWebView();
1136- model->add(webview1);
1137- model->add(createWebView());
1138+ // When removing a tab after the current one,
1139+ // the current tab shouldn’t change.
1140+ QQuickItem* tab1 = createTab();
1141+ model->add(tab1);
1142+ model->add(createTab());
1143 spy.clear();
1144- model->remove(1);
1145- QCOMPARE(model->currentWebview(), webview1);
1146- QCOMPARE(spy.count(), 0);
1147+ delete model->remove(1);
1148+ QCOMPARE(model->currentTab(), tab1);
1149+ QVERIFY(spy.isEmpty());
1150
1151- // When removing the current webview, if there is a webview after it,
1152+ // When removing the current tab, if there is a tab after it,
1153 // it becomes the current one.
1154- QQuickItem* webview2 = createWebView();
1155- model->add(webview2);
1156+ QQuickItem* tab2 = createTab();
1157+ model->add(tab2);
1158 spy.clear();
1159- model->remove(0);
1160+ delete model->remove(0);
1161 QCOMPARE(spy.count(), 1);
1162- QCOMPARE(model->currentWebview(), webview2);
1163+ QCOMPARE(model->currentTab(), tab2);
1164
1165- // When removing the current webview, if it was the last one, the
1166- // current webview should be reset to 0.
1167+ // When removing the current tab, if it was the last one, the
1168+ // current tab should be reset to 0.
1169 spy.clear();
1170- model->remove(0);
1171+ delete model->remove(0);
1172 QCOMPARE(spy.count(), 1);
1173- QCOMPARE(model->currentWebview(), (QObject*) 0);
1174+ QCOMPARE(model->currentTab(), (QObject*) 0);
1175 }
1176
1177 void shouldReturnData()
1178 {
1179- QQuickItem* webview = createWebView();
1180- QQmlProperty(webview, "url").write(QUrl("http://ubuntu.com/"));
1181- QQmlProperty(webview, "title").write(QString("Lorem Ipsum"));
1182- QQmlProperty(webview, "icon").write(QUrl("image://webicon/123"));
1183- model->add(webview);
1184+ QQuickItem* tab = createTab();
1185+ QQmlProperty(tab, "url").write(QUrl("http://ubuntu.com/"));
1186+ QQmlProperty(tab, "title").write(QString("Lorem Ipsum"));
1187+ QQmlProperty(tab, "icon").write(QUrl("image://webicon/123"));
1188+ model->add(tab);
1189 QVERIFY(!model->data(QModelIndex(), TabsModel::Url).isValid());
1190 QVERIFY(!model->data(model->index(-1, 0), TabsModel::Url).isValid());
1191 QVERIFY(!model->data(model->index(3, 0), TabsModel::Url).isValid());
1192 QCOMPARE(model->data(model->index(0, 0), TabsModel::Url).toUrl(), QUrl("http://ubuntu.com/"));
1193 QCOMPARE(model->data(model->index(0, 0), TabsModel::Title).toString(), QString("Lorem Ipsum"));
1194 QCOMPARE(model->data(model->index(0, 0), TabsModel::Icon).toUrl(), QUrl("image://webicon/123"));
1195- QCOMPARE(model->data(model->index(0, 0), TabsModel::WebView).value<QQuickItem*>(), webview);
1196- QVERIFY(!model->data(model->index(0, 0), TabsModel::WebView + 3).isValid());
1197+ QCOMPARE(model->data(model->index(0, 0), TabsModel::Tab).value<QQuickItem*>(), tab);
1198+ QVERIFY(!model->data(model->index(0, 0), TabsModel::Tab + 3).isValid());
1199 }
1200 };
1201

Subscribers

People subscribed via source and target branches

to status/vote changes: