Merge lp:~michael-sheldon/webbrowser-app/file-upload into lp:webbrowser-app
- file-upload
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Olivier Tilloy |
Approved revision: | 455 |
Merged at revision: | 493 |
Proposed branch: | lp:~michael-sheldon/webbrowser-app/file-upload |
Merge into: | lp:webbrowser-app |
Diff against target: |
501 lines (+352/-26) 9 files modified
debian/control (+3/-1) po/webbrowser-app.pot (+11/-3) src/app/ContentPickerDialog.qml (+98/-0) src/app/FilePickerDialog.qml (+44/-0) src/app/WebViewImpl.qml (+6/-0) src/app/browserapplication.cpp (+1/-20) src/app/browserapplication.h (+5/-2) tests/autopilot/webbrowser_app/tests/http_server.py (+18/-0) tests/autopilot/webbrowser_app/tests/test_content_pick.py (+166/-0) |
To merge this branch: | bzr merge lp:~michael-sheldon/webbrowser-app/file-upload |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Tilloy | Approve | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Ken VanDine | Needs Fixing | ||
Review via email: mp+212605@code.launchpad.net |
Commit message
Add support for file upload via content-hub
Description of the change
Adds support for file upload via content-hub.
Michael Sheldon (michael-sheldon) wrote : | # |
Ken VanDine (ken-vandine) wrote : | # |
I only reviewed the packaging changes, just one nitpick. In debian/control, please keep the package lists for depends sorted alphabetically.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:425
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:426
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:427
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
Testing on my desktop, and I don’t have any app registered in the content hub, so the picker shows up empty, and I’m seeing the following two errors on the console:
file://
file://
That’s a corner case of course, but it would be nice if it could be handled gracefully (ideally some message to the user, which would be something to discuss with design, but even without that, at least make the code robust enough to not spit out errors when the list of handlers is empty).
Olivier Tilloy (osomon) wrote : | # |
When clicking on the cancel button of the picker, I get this error:
file://
you will need to s/dismiss(
Olivier Tilloy (osomon) wrote : | # |
34 + * Copyright 2013 Canonical Ltd.
This should probably be 2014
Olivier Tilloy (osomon) wrote : | # |
Can you update the license header of tests/autopilot
Olivier Tilloy (osomon) wrote : | # |
A style nitpick: I usually do not end lines with semi-colons for javascript code in QML files.
For consistency, would you mind doing that too in src/app/
Olivier Tilloy (osomon) wrote : | # |
135 + Loader {
136 + id: peerModelLoader
137 + active: false
138 + sourceComponent: ContentPeerModel {
139 + contentType: ContentType.All
140 + handler: ContentHandler.
141 + }
142 + }
Does this need to be a separate component? I don’t see it reused anywhere else, maybe the customPeerModel
Michael Sheldon (michael-sheldon) wrote : | # |
The Loader is separate because the ContentPickerDialog and gets destroyed when the dialog is closed, keeping it separate allows us to avoid having to requery the content-hub for peers every time the dialog is displayed (which is less of an issue now the dbus speed problems are resolved, but could become important again when there are a lot of peers).
(The ContentPeerPicker component will create a model itself when a custom model isn't provided, so most apps don't need to worry about this sort of thing).
Michael Sheldon (michael-sheldon) wrote : | # |
file://
Should be fixed now.
file://
This one appears to have been introduced on the content-hub side when using a custom loader, so I'll fix that in a content-hub MR.
Displaying messages when no peers are found should probably also happen in the content-hub (the main ContentPeerPicker element comes from content-hub, ContentPickerDialog is just a wrapper around it to make it usable within the browser).
Michael Sheldon (michael-sheldon) wrote : | # |
Just so you're aware, there'll also be a few warnings about height bindings from the ContentTransferHint when a transfer is in progress. This is due to the ContentTransferHint being a dialog which is then being embedded in another dialog (the ContentPickerDi
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:430
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Sheldon (michael-sheldon) wrote : | # |
> file://
> gnu/qt5/
> property 'count' of undefined
This is now fixed in https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:434
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
> The Loader is separate because the ContentPickerDialog and gets destroyed when
> the dialog is closed, keeping it separate allows us to avoid having to requery
> the content-hub for peers every time the dialog is displayed (which is less of
> an issue now the dbus speed problems are resolved, but could become important
> again when there are a lot of peers).
>
> (The ContentPeerPicker component will create a model itself when a custom
> model isn't provided, so most apps don't need to worry about this sort of
> thing).
That makes sense, thanks for explaining. Would you mind adding a comment in the Loader instance to explain that? It’s not immediately obvious from a quick peak at the code, I wouldn’t want this optimization to disappear in a future refactoring.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:435
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
I’m seeing an issue that I can reliably reproduce:
- open a page that has an input="file" widget (I’m using http://
- choose the gallery app, select a picture, then click "Pick", you’re back to the browser and the picture has been selected in the input widget
- click the button again to e.g. pick another picture
- choose the gallery app
Expected result: the gallery app opens and I can pick a picture
Current result: I get a small dialog with a spinner that never goes away (if however in the meantime I went to the dash and manually closed the gallery app, then the issue cannot be observed)
Michael Sheldon (michael-sheldon) wrote : | # |
> I’m seeing an issue that I can reliably reproduce:
>
> - open a page that has an input="file" widget (I’m using
> http://
> pick content
> - choose the gallery app, select a picture, then click "Pick", you’re back to
> the browser and the picture has been selected in the input widget
> - click the button again to e.g. pick another picture
> - choose the gallery app
>
> Expected result: the gallery app opens and I can pick a picture
> Current result: I get a small dialog with a spinner that never goes away (if
> however in the meantime I went to the dash and manually closed the gallery
> app, then the issue cannot be observed)
It looks like most of the content-hub stuff is happening normally and the gallery goes in to picker mode but then just isn't brought to the foreground, I'll check with Ken what should be happening here (that functionality all lies within the content-
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:436
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
183 + html = '<form action="upload" method="post" enctype=
The "=" should be "+=" here.
Olivier Tilloy (osomon) wrote : | # |
For the insensitivity workaround, instead of a timer, how about something like that:
Connections {
target: Qt.application
if ((Qt.applicatio
}
}
}
(you would need to initialize selectedItems to null for this to work)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:437
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:439
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:440
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Bill Filler (bfiller) wrote : | # |
I was thinking about the file picker functionality on the desktop. Assuming we'll want it to operate correctly for webapps on the desktop. We probably don't want the content-hub/peer picker being launched on the desktop, but rather showing the standard File Chooser component so that the user can choose any file of their liking to upload.
What do you guys think?
Olivier Tilloy (osomon) wrote : | # |
> I was thinking about the file picker functionality on the desktop. Assuming
> we'll want it to operate correctly for webapps on the desktop. We probably
> don't want the content-hub/peer picker being launched on the desktop, but
> rather showing the standard File Chooser component so that the user can choose
> any file of their liking to upload.
>
> What do you guys think?
In a non-unity8 world, I think that’s the desired behaviour indeed.
Note that there’s no such thing as a standard file chooser in QML, one would have to implement one (or expose to QML a standard QFileDialog). We would also need a way to determine which dialog to use (the form factor would work as a temporary solution, but as soon as we have unity8 on the desktop it won’t work anymore).
Olivier Tilloy (osomon) wrote : | # |
So much for my outdated knowledge of the standard QML components… Here comes the FileDialog component, to the rescue: http://
Bill Filler (bfiller) wrote : | # |
regarding the focus issue with content-hub, this appears to be a shell bug, filed here:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:441
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:442
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:442
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Sheldon (michael-sheldon) wrote : | # |
The last couple of commits provide a slightly more standard file upload dialog when being used on the desktop, however this is currently using the QML file dialog implementation. If we want to use the more common QWidgets based file picker we'd need change the browser from being a QGuiApplication to being a QApplication (and add a dependency on libqt5widgets5), what are people's thoughts on this?
Olivier Tilloy (osomon) wrote : | # |
297 +#include <QApplication>
Can you make that <QtWidgets/
Olivier Tilloy (osomon) wrote : | # |
There’s a trivial conflict in debian/control when merging in the latest trunk, can you please fix it?
While at it, you can bump the required version of liboxideqt-
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:443
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
I might be wrong, but I don’t think a build dependency on qtdeclarative5-
Likewise, I don’t think the runtime dependencies that were added to qtdeclarative5-
Olivier Tilloy (osomon) wrote : | # |
76 + signal dismissed();
extraneous trailing semi-colon here ^
184 + model.accept(
there’s a mix of tabs and space on this line, breaking the alignment of the code
Olivier Tilloy (osomon) wrote : | # |
176 + title: i18n.tr("Please choose a file")
Since a new string has been added, the translation template has to be updated. Just run `make webbrowser-app.pot` to regenerate it in your working copy, and commit the changes.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:446
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
20 + qtdeclarative5-
I believe this one is not needed either (for the same reason mentioned above), please remove.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:450
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:451
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
Looks good to me now. Nice job!
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:451
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
I just realized that qtdeclarative5-
My suggestion is to simply remove the dependency from debian/control: since it’s only loaded dynamically at run time and only on devices where the content hub is guaranteed to be installed, it won’t make a difference.
Olivier Tilloy (osomon) wrote : | # |
(for the above to work the ContentPeerModel needs to be moved from WebViewImpl to ContentPickerDi
Olivier Tilloy (osomon) wrote : | # |
Looks good now, thanks Michael!
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2014-04-03 14:20:39 +0000 |
3 | +++ debian/control 2014-04-11 13:15:58 +0000 |
4 | @@ -31,7 +31,8 @@ |
5 | Multi-Arch: foreign |
6 | Depends: ${misc:Depends}, |
7 | ${shlibs:Depends}, |
8 | - liboxideqt-qmlplugin (>= 1.0.0~bzr452), |
9 | + liboxideqt-qmlplugin (>= 1.0.0~bzr490), |
10 | + qtdeclarative5-dialogs-plugin, |
11 | qtdeclarative5-qtquick2-plugin, |
12 | qtdeclarative5-ubuntu-ui-extras-browser-plugin (= ${binary:Version}), |
13 | qtdeclarative5-ubuntu-ui-toolkit-plugin, |
14 | @@ -93,6 +94,7 @@ |
15 | libautopilot-qt (>= 1.4), |
16 | libqt5test5, |
17 | ubuntu-ui-toolkit-autopilot, |
18 | + unity8-autopilot, |
19 | webbrowser-app (>= ${binary:Version}), |
20 | Description: Ubuntu web browser autopilot tests |
21 | A lightweight web browser tailored for Ubuntu, based on the Webkit rendering |
22 | |
23 | === modified file 'po/webbrowser-app.pot' |
24 | --- po/webbrowser-app.pot 2014-03-26 10:00:18 +0000 |
25 | +++ po/webbrowser-app.pot 2014-04-11 13:15:58 +0000 |
26 | @@ -8,7 +8,7 @@ |
27 | msgstr "" |
28 | "Project-Id-Version: webbrowser-app\n" |
29 | "Report-Msgid-Bugs-To: \n" |
30 | -"POT-Creation-Date: 2014-03-26 10:59+0100\n" |
31 | +"POT-Creation-Date: 2014-04-10 16:28+0100\n" |
32 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
33 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
34 | "Language-Team: LANGUAGE <LL@li.org>\n" |
35 | @@ -116,6 +116,10 @@ |
36 | msgid "Refresh page" |
37 | msgstr "" |
38 | |
39 | +#: src/app/FilePickerDialog.qml:26 |
40 | +msgid "Please choose a file" |
41 | +msgstr "" |
42 | + |
43 | #: src/app/PermissionRequest.qml:28 |
44 | msgid "Permission Request" |
45 | msgstr "" |
46 | @@ -288,13 +292,13 @@ |
47 | |
48 | #. TRANSLATORS: %1 refers to the current page’s title |
49 | #: src/app/webbrowser/webbrowser-app.qml:35 |
50 | -#: src/app/webcontainer/webapp-container.qml:44 |
51 | +#: src/app/webcontainer/webapp-container.qml:45 |
52 | #, qt-format |
53 | msgid "%1 - Ubuntu Web Browser" |
54 | msgstr "" |
55 | |
56 | #: src/app/webbrowser/webbrowser-app.qml:37 |
57 | -#: src/app/webcontainer/webapp-container.qml:46 |
58 | +#: src/app/webcontainer/webapp-container.qml:47 |
59 | msgid "Ubuntu Web Browser" |
60 | msgstr "" |
61 | |
62 | @@ -313,3 +317,7 @@ |
63 | #: src/app/webcontainer/AccountsView.qml:38 |
64 | msgid "Select an account" |
65 | msgstr "" |
66 | + |
67 | +#: src/app/webcontainer/WebViewImplWebkit.qml:63 |
68 | +msgid "This page wants to know your device’s location." |
69 | +msgstr "" |
70 | |
71 | === added file 'src/app/ContentPickerDialog.qml' |
72 | --- src/app/ContentPickerDialog.qml 1970-01-01 00:00:00 +0000 |
73 | +++ src/app/ContentPickerDialog.qml 2014-04-11 13:15:58 +0000 |
74 | @@ -0,0 +1,98 @@ |
75 | +/* |
76 | + * Copyright 2014 Canonical Ltd. |
77 | + * |
78 | + * This file is part of webbrowser-app. |
79 | + * |
80 | + * webbrowser-app is free software; you can redistribute it and/or modify |
81 | + * it under the terms of the GNU General Public License as published by |
82 | + * the Free Software Foundation; version 3. |
83 | + * |
84 | + * webbrowser-app is distributed in the hope that it will be useful, |
85 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
86 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
87 | + * GNU General Public License for more details. |
88 | + * |
89 | + * You should have received a copy of the GNU General Public License |
90 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
91 | + */ |
92 | + |
93 | +import QtQuick 2.0 |
94 | +import Ubuntu.Components 0.1 |
95 | +import Ubuntu.Components.Popups 0.1 as Popups |
96 | +import Ubuntu.Content 0.1 |
97 | + |
98 | +Component { |
99 | + Popups.PopupBase { |
100 | + id: picker |
101 | + property var activeTransfer |
102 | + property var selectedItems |
103 | + |
104 | + Rectangle { |
105 | + anchors.fill: parent |
106 | + |
107 | + ContentTransferHint { |
108 | + anchors.fill: parent |
109 | + activeTransfer: picker.activeTransfer |
110 | + } |
111 | + |
112 | + ContentPeerPicker { |
113 | + id: peerPicker |
114 | + anchors.fill: parent |
115 | + visible: true |
116 | + contentType: ContentType.All |
117 | + handler: ContentHandler.Source |
118 | + |
119 | + onPeerSelected: { |
120 | + if (model.allowMultipleFiles) { |
121 | + peer.selectionType = ContentTransfer.Multiple |
122 | + } else { |
123 | + peer.selectionType = ContentTransfer.Single |
124 | + } |
125 | + picker.activeTransfer = peer.request() |
126 | + stateChangeConnection.target = picker.activeTransfer |
127 | + } |
128 | + |
129 | + onCancelPressed: { |
130 | + webview.focus = true |
131 | + model.reject() |
132 | + } |
133 | + } |
134 | + } |
135 | + |
136 | + Connections { |
137 | + id: stateChangeConnection |
138 | + onStateChanged: { |
139 | + if (picker.activeTransfer.state === ContentTransfer.Charged) { |
140 | + selectedItems = [] |
141 | + for(var i in picker.activeTransfer.items) { |
142 | + selectedItems.push(String(picker.activeTransfer.items[i].url).replace("file://", "")) |
143 | + } |
144 | + acceptTimer.running = true |
145 | + } |
146 | + } |
147 | + } |
148 | + |
149 | + // FIXME: Work around for browser becoming insensitive to touch events |
150 | + // if the dialog is dismissed while the application is inactive. |
151 | + // Just listening for changes to Qt.application.active doesn't appear |
152 | + // to be enough to resolve this, so it seems that something else needs |
153 | + // to be happening first. As such there's a potential for a race |
154 | + // condition here, although as yet no problem has been encountered. |
155 | + Timer { |
156 | + id: acceptTimer |
157 | + interval: 100 |
158 | + repeat: true |
159 | + onTriggered: { |
160 | + if(Qt.application.active) { |
161 | + webview.focus = true |
162 | + model.accept(selectedItems) |
163 | + } |
164 | + } |
165 | + } |
166 | + |
167 | + Component.onCompleted: { |
168 | + show() |
169 | + } |
170 | + |
171 | + } |
172 | +} |
173 | |
174 | === added file 'src/app/FilePickerDialog.qml' |
175 | --- src/app/FilePickerDialog.qml 1970-01-01 00:00:00 +0000 |
176 | +++ src/app/FilePickerDialog.qml 2014-04-11 13:15:58 +0000 |
177 | @@ -0,0 +1,44 @@ |
178 | +/* |
179 | + * Copyright 2014 Canonical Ltd. |
180 | + * |
181 | + * This file is part of webbrowser-app. |
182 | + * |
183 | + * webbrowser-app is free software; you can redistribute it and/or modify |
184 | + * it under the terms of the GNU General Public License as published by |
185 | + * the Free Software Foundation; version 3. |
186 | + * |
187 | + * webbrowser-app is distributed in the hope that it will be useful, |
188 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
189 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
190 | + * GNU General Public License for more details. |
191 | + * |
192 | + * You should have received a copy of the GNU General Public License |
193 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
194 | + */ |
195 | + |
196 | +import QtQuick 2.0 |
197 | +import QtQuick.Dialogs 1.0 |
198 | +import Ubuntu.Components.Popups 0.1 as Popups |
199 | + |
200 | +Component { |
201 | + Popups.Dialog { |
202 | + FileDialog { |
203 | + id: fileDialog |
204 | + title: i18n.tr("Please choose a file") |
205 | + selectMultiple: model.allowMultipleFiles |
206 | + |
207 | + onAccepted: { |
208 | + var selectedFiles = [] |
209 | + for(var i in fileDialog.fileUrls) { |
210 | + selectedFiles.push(fileDialog.fileUrls[i].replace("file://", "")) |
211 | + } |
212 | + model.accept(selectedFiles) |
213 | + } |
214 | + |
215 | + onRejected: { |
216 | + model.reject() |
217 | + } |
218 | + Component.onCompleted: visible = true |
219 | + } |
220 | + } |
221 | +} |
222 | |
223 | === modified file 'src/app/WebViewImpl.qml' |
224 | --- src/app/WebViewImpl.qml 2014-04-02 14:33:31 +0000 |
225 | +++ src/app/WebViewImpl.qml 2014-04-11 13:15:58 +0000 |
226 | @@ -35,6 +35,12 @@ |
227 | confirmDialog: ConfirmDialog {} |
228 | promptDialog: PromptDialog {} |
229 | beforeUnloadDialog: BeforeUnloadDialog {} |
230 | + filePicker: filePickerLoader.item |
231 | + |
232 | + Loader { |
233 | + id: filePickerLoader |
234 | + source: formFactor == "desktop" ? "FilePickerDialog.qml" : "ContentPickerDialog.qml" |
235 | + } |
236 | |
237 | /*selectionActions: ActionList { |
238 | Actions.Copy { |
239 | |
240 | === modified file 'src/app/browserapplication.cpp' |
241 | --- src/app/browserapplication.cpp 2014-04-02 15:15:27 +0000 |
242 | +++ src/app/browserapplication.cpp 2014-04-11 13:15:58 +0000 |
243 | @@ -32,7 +32,7 @@ |
244 | #include "webbrowser-window.h" |
245 | |
246 | BrowserApplication::BrowserApplication(int& argc, char** argv) |
247 | - : QGuiApplication(argc, argv) |
248 | + : QApplication(argc, argv) |
249 | , m_engine(0) |
250 | , m_window(0) |
251 | , m_component(0) |
252 | @@ -40,25 +40,6 @@ |
253 | { |
254 | m_arguments = arguments(); |
255 | m_arguments.removeFirst(); |
256 | - |
257 | - // The testability driver is only loaded by QApplication but not by |
258 | - // QGuiApplication (see https://codereview.qt-project.org/#change,66513). |
259 | - // Let’s load the testability driver on our own. |
260 | - if (m_arguments.contains(QLatin1String("-testability")) || |
261 | - qgetenv("QT_LOAD_TESTABILITY") == "1") { |
262 | - QLibrary testLib(QLatin1String("qttestability")); |
263 | - if (testLib.load()) { |
264 | - typedef void (*TasInitialize)(void); |
265 | - TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); |
266 | - if (initFunction) { |
267 | - initFunction(); |
268 | - } else { |
269 | - qCritical("Library qttestability resolve failed!"); |
270 | - } |
271 | - } else { |
272 | - qCritical("Library qttestability load failed!"); |
273 | - } |
274 | - } |
275 | } |
276 | |
277 | BrowserApplication::~BrowserApplication() |
278 | |
279 | === modified file 'src/app/browserapplication.h' |
280 | --- src/app/browserapplication.h 2014-03-27 17:35:54 +0000 |
281 | +++ src/app/browserapplication.h 2014-04-11 13:15:58 +0000 |
282 | @@ -24,14 +24,17 @@ |
283 | #include <QtCore/QString> |
284 | #include <QtCore/QStringList> |
285 | #include <QtCore/QUrl> |
286 | -#include <QtGui/QGuiApplication> |
287 | +#include <QtWidgets/QApplication> |
288 | |
289 | class QQmlComponent; |
290 | class QQmlEngine; |
291 | class QQuickWindow; |
292 | class WebBrowserWindow; |
293 | |
294 | -class BrowserApplication : public QGuiApplication |
295 | +// We want the browser to be QApplication based rather than QGuiApplication |
296 | +// to provide a widget based file picker on the desktop, rather than the |
297 | +// QML fall back picker. |
298 | +class BrowserApplication : public QApplication |
299 | { |
300 | Q_OBJECT |
301 | |
302 | |
303 | === modified file 'tests/autopilot/webbrowser_app/tests/http_server.py' |
304 | --- tests/autopilot/webbrowser_app/tests/http_server.py 2014-02-25 13:05:27 +0000 |
305 | +++ tests/autopilot/webbrowser_app/tests/http_server.py 2014-04-11 13:15:58 +0000 |
306 | @@ -83,6 +83,24 @@ |
307 | html += 'src="/blanktargetlink" />' |
308 | html += '</body></html>' |
309 | self.send_html(html) |
310 | + elif self.path == "/uploadform": |
311 | + # craft a page that accepts clicks anywhere inside its window |
312 | + # and on a click opens up the content picker. |
313 | + # It also pops up an alert with the new content of the file |
314 | + # upload field when it changes |
315 | + self.send_response(200) |
316 | + html = '<html><body style="margin: 0">' |
317 | + html += '<form action="upload" method="post" ' |
318 | + html += 'enctype="multipart/form-data">' |
319 | + html += '<input type="file" name="file" id="file" ' |
320 | + html += 'onchange="alert(this.value)"><br>' |
321 | + html += '<input type="submit" name="submit" value="Submit">' |
322 | + html += '</form>' |
323 | + html += '<a href="javascript:' |
324 | + html += 'document.getElementById(\'file\').click()">' |
325 | + html += '<div style="height: 100%"></div></a>' |
326 | + html += '</body></html>' |
327 | + self.send_html(html) |
328 | else: |
329 | self.send_error(404) |
330 | |
331 | |
332 | === added file 'tests/autopilot/webbrowser_app/tests/test_content_pick.py' |
333 | --- tests/autopilot/webbrowser_app/tests/test_content_pick.py 1970-01-01 00:00:00 +0000 |
334 | +++ tests/autopilot/webbrowser_app/tests/test_content_pick.py 2014-04-11 13:15:58 +0000 |
335 | @@ -0,0 +1,166 @@ |
336 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
337 | +# |
338 | +# Copyright 2014 Canonical |
339 | +# |
340 | +# This program is free software: you can redistribute it and/or modify it |
341 | +# under the terms of the GNU General Public License version 3, as published |
342 | +# by the Free Software Foundation. |
343 | +# |
344 | +# This program is distributed in the hope that it will be useful, |
345 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
346 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
347 | +# GNU General Public License for more details. |
348 | +# |
349 | +# You should have received a copy of the GNU General Public License |
350 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
351 | + |
352 | +from __future__ import absolute_import |
353 | + |
354 | +from autopilot.introspection import get_proxy_object_for_existing_process |
355 | +from autopilot.matchers import Eventually |
356 | +from testtools.matchers import Equals, NotEquals |
357 | +from testtools import skip |
358 | +from webbrowser_app.tests import StartOpenRemotePageTestCaseBase |
359 | +from unity8 import process_helpers as helpers |
360 | +from ubuntuuitoolkit import emulators as toolkit_emulators |
361 | +import os |
362 | +import subprocess |
363 | + |
364 | + |
365 | +@skip("Will not work until bug #1218971 is solved") |
366 | +class TestContentPick(StartOpenRemotePageTestCaseBase): |
367 | + |
368 | + """Tests that content picking dialog show up.""" |
369 | + |
370 | + def test_pick_image(self): |
371 | + url = self.base_url + "/uploadform" |
372 | + self.go_to_url(url) |
373 | + self.assert_page_eventually_loaded(url) |
374 | + webview = self.main_window.get_current_webview() |
375 | + self.pointing_device.click_object(webview) |
376 | + |
377 | + dialog = self.app.wait_select_single("ContentPickerDialog") |
378 | + self.assertThat(dialog.visible, Equals(True)) |
379 | + |
380 | + |
381 | +#@skipIf(model() == 'Desktop', "Phablet only") |
382 | +@skip("Currently unable to fetch dynamically created dialogs (bug #1218971)") |
383 | +class TestContentPickerIntegration(StartOpenRemotePageTestCaseBase): |
384 | + |
385 | + """Tests that the gallery app is brought up to choose image content""" |
386 | + |
387 | + def tearDown(self): |
388 | + os.system("pkill gallery-app") |
389 | + os.system("pkill webbrowser-app") |
390 | + super(StartOpenRemotePageTestCaseBase, self).tearDown() |
391 | + |
392 | + def get_unity8_proxy_object(self): |
393 | + pid = helpers._get_unity_pid() |
394 | + return get_proxy_object_for_existing_process(pid) |
395 | + |
396 | + def get_current_focused_appid(self, unity8): |
397 | + return unity8.select_single("Shell").currentFocusedAppId |
398 | + |
399 | + def set_testability_environment_variable(self): |
400 | + """Makes sure every app opened in the environment loads the |
401 | + testability driver.""" |
402 | + |
403 | + subprocess.check_call([ |
404 | + "/sbin/initctl", |
405 | + "set-env", |
406 | + "QT_LOAD_TESTABILITY=1" |
407 | + ]) |
408 | + |
409 | + def get_app_pid(self, app): |
410 | + """Return the PID of the named app, or -1 if it's not |
411 | + running""" |
412 | + |
413 | + try: |
414 | + return int(subprocess.check_output(["pidof", app]).strip()) |
415 | + except subprocess.CalledProcessError: |
416 | + return -1 |
417 | + |
418 | + def wait_app_focused(self, name): |
419 | + """Wait until the app with the specified name is the |
420 | + currently focused one""" |
421 | + |
422 | + unity8 = self.get_unity8_proxy_object() |
423 | + self.assertThat( |
424 | + lambda: self.get_current_focused_appid(unity8), |
425 | + Eventually(Equals(name)) |
426 | + ) |
427 | + |
428 | + def test_image_picker_is_gallery(self): |
429 | + """ Tests that the gallery shows up when we are picking |
430 | + images """ |
431 | + |
432 | + # Go to a page where clicking anywhere equals clicking on the |
433 | + # file selection button of an upload form |
434 | + url = self.base_url + "/uploadform" |
435 | + self.go_to_url(url) |
436 | + self.assert_page_eventually_loaded(url) |
437 | + webview = self.main_window.get_current_webview() |
438 | + self.pointing_device.click_object(webview) |
439 | + |
440 | + # Verify that such a click brings up the gallery to select images |
441 | + self.wait_app_focused("gallery-app") |
442 | + |
443 | + def test_image_picker_pick_image(self): |
444 | + """ Tests that the we can select an image in the gallery and |
445 | + control will return to the browser with the choosen image |
446 | + picked.""" |
447 | + |
448 | + # First run the previous test to bring up the content picker |
449 | + self.set_testability_environment_variable() |
450 | + self.test_image_picker_is_gallery() |
451 | + |
452 | + # Now wait until the gallery-app process is up. |
453 | + # NOTE: this will not work unless run on a device where unity8 runs in |
454 | + # testability mode. To manually restart unity8 in this mode run from a |
455 | + # python shell: |
456 | + # from unity8 import process_helpers as p |
457 | + # p.restart_unity_with_testability() |
458 | + self.assertThat(lambda: self.get_app_pid("gallery-app"), |
459 | + Eventually(NotEquals(-1))) |
460 | + |
461 | + gallery = get_proxy_object_for_existing_process( |
462 | + self.get_app_pid("gallery-app"), |
463 | + emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase |
464 | + ) |
465 | + |
466 | + # Wait for the gallery UI to completely display |
467 | + view = gallery.wait_select_single("QQuickView") |
468 | + self.assertThat(view.visible, Eventually(Equals(True))) |
469 | + |
470 | + # Select the first picture on the picker by clicking on it |
471 | + # NOTE: this is currently failing if there is anything except two |
472 | + # pictures in the gallery (at least on a Maguro device), so I'm |
473 | + # putting a temporary stop to the test here so that it won't break |
474 | + # in Jenkins |
475 | + return |
476 | + |
477 | + grid = gallery.wait_select_single("MediaGrid") |
478 | + photo = grid.select_many("OrganicItemInteraction")[0] |
479 | + self.pointing_device.click_object(photo) |
480 | + self.assertThat(photo.isSelected, Eventually(Equals(True))) |
481 | + |
482 | + # Now the "Pick" button will be enabled and we click on it |
483 | + button = gallery.select_single("Button", objectName="pickButton") |
484 | + self.assertThat(button.enabled, Eventually(Equals(True))) |
485 | + self.pointing_device.click_object(button) |
486 | + |
487 | + # The gallery should close and focus returned to the browser |
488 | + self.wait_app_focused("webbrowser-app") |
489 | + |
490 | + # Verify that an image has actually been selected |
491 | + dialog = self.app.wait_select_single("ContentPickerDialog") |
492 | + self.assertThat(dialog.visible, Equals(True)) |
493 | + preview = dialog.wait_select_single("QQuickImage", |
494 | + objectName="mediaPreview") |
495 | + self.assertThat(preview.source, Eventually(NotEquals(""))) |
496 | + |
497 | + # Verify that now we can click the "OK" button and it closes the dialog |
498 | + button = dialog.wait_select_single("Button", objectName="ok") |
499 | + self.assertThat(button.enabled, Eventually(Equals(True))) |
500 | + self.pointing_device.click_object(button) |
501 | + self.assertThat(dialog.visible, Eventually(Equals(False))) |
Are there any related MPs required for this MP to build/function as expected? Please list.
* No
Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes)
* Yes
Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator?
* Yes
Did you successfully run all tests found in your component's Test Plan (https:/ /wiki.ubuntu. com/Process/ Merges/ TestPlan/ webbrowser- app) on device or emulator?
* Yes
If you changed the UI, was the change specified/approved by design?
* Added dialog containing a ContentPeerPicker (specified in https:/ /docs.google. com/a/canonical .com/document/ d/1trse15NokU8I J5lm3BnUi7oMNTC kUnYNHeAHZdtzFo Q)
If you changed the packaging (debian), did you subscribe a core-dev to this MP?
* Added qtdeclarative5- ubuntu- content0. 1 to dependencies, subscribed: ken-vandine