Merge ~santoshbit2007/oxide:UITK_FilePicker_Impl into oxide:master

Proposed by Santosh
Status: Needs review
Proposed branch: ~santoshbit2007/oxide:UITK_FilePicker_Impl
Merge into: oxide:master
Diff against target: 2709 lines (+1412/-126)
38 files modified
dev/null (+0/-67)
qt/core/BUILD.gn (+4/-4)
qt/core/browser/file_picker_host.cc (+121/-0)
qt/core/browser/file_picker_host.h (+61/-0)
qt/core/browser/oxide_qt_web_view.cc (+41/-5)
qt/core/browser/oxide_qt_web_view.h (+4/-2)
qt/core/glue/auxiliary_ui_factory.h (+10/-0)
qt/core/glue/file_picker.h (+52/-0)
qt/core/glue/file_picker_client.h (+39/-0)
qt/core/glue/oxide_qt_web_view_proxy_client.h (+0/-5)
qt/quick/CMakeLists.txt (+1/-1)
qt/quick/api/oxideqquickwebview.cc (+15/-13)
qt/quick/api/oxideqquickwebview_p.h (+0/-5)
qt/quick/qquick_legacy_auxiliary_ui_factory.cc (+19/-3)
qt/quick/qquick_legacy_auxiliary_ui_factory.h (+10/-0)
qt/quick/qquick_legacy_file_picker.cc (+182/-0)
qt/quick/qquick_legacy_file_picker.h (+77/-0)
qt/tests/qmltests/ubuntu_ui/tst_WebViewFilePicker.html (+11/-0)
qt/tests/qmltests/ubuntu_ui/tst_WebViewFilePicker.qml (+58/-0)
qt/uitk/lib/CMakeLists.txt (+1/-0)
qt/uitk/lib/resources.qrc (+2/-0)
qt/uitk/lib/resources/FilePickerContentHub.qml (+122/-0)
qt/uitk/lib/resources/FilePickerDialog.qml (+63/-0)
qt/uitk/lib/uitk_auxiliary_ui_factory.cc (+11/-0)
qt/uitk/lib/uitk_auxiliary_ui_factory.h (+6/-0)
qt/uitk/lib/uitk_file_picker.cc (+150/-0)
qt/uitk/lib/uitk_file_picker.h (+80/-0)
shared/BUILD.gn (+4/-2)
shared/browser/file_picker.h (+37/-0)
shared/browser/file_picker_client.h (+39/-0)
shared/browser/file_picker_host.cc (+92/-0)
shared/browser/file_picker_host.h (+69/-0)
shared/browser/oxide_web_view.cc (+12/-8)
shared/browser/oxide_web_view.h (+4/-2)
shared/browser/oxide_web_view_client.cc (+1/-4)
shared/browser/oxide_web_view_client.h (+0/-5)
shared/browser/web_contents_client.cc (+7/-0)
shared/browser/web_contents_client.h (+7/-0)
Reviewer Review Type Date Requested Status
Olivier Tilloy (community) Needs Fixing
Chris Coulson Approve
Review via email: mp+317213@code.launchpad.net

Description of the change

UITK filePicker Implementation which uses content-hub picker dialog.

I had issue with handing testcases for this, as no control over content-hub file selection view.
Suggestion is welcomed.

To post a comment you must log in.
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Thanks for working on this.

First of all, don't be afraid to refactor existing code. It would be nice to refactor the FilePicker layering in a similar way to recent changes I've made to the context menu / popup menu / JS dialogs implementations.

I've left a few comments inline.

In addition to those:

- I don't see where the fallback (legacy / non content-hub) file picker implementation gets loaded.
- Please remove qt::WebViewProxyClient::CreateFilePicker (and the corresponding implementation in qt/quick/api).

I'm probably not the best person to review the content-hub picker implementation.

review: Needs Fixing
Revision history for this message
Santosh (santoshbit2007) wrote :

While running the testcases, I am seeing protobuf issue
-tmpdir /tmp/tmp-oxide-runtestsnIpqZ4 --file tst_WebViewFilePicker.qml'
[New Thread 0x7ffff539f700 (LWP 12033)]
Oxide.Ubuntu is an experimental module - future versions may change in backwards-incompatible ways, and without bumping the module version. Please use with caution

[libprotobuf FATAL ../../third_party/protobuf/src/google/protobuf/stubs/common.cc:78] This program was compiled against version 2.6.1 of the Protocol Buffer runtime library, which is not compatible with the installed version (3.0.0). Contact the program author for an update. If you compiled the program yourself, make sure that your headers are from the same version of Protocol Buffers as your link-time library. (Version verification failed in "/build/mir-sajBv9/mir-0.26.1+16.04.20170209.1/obj-x86_64-linux-gnu/src/protobuf/mir_protobuf.pb.cc".)

Its happens only when content-hub is used.

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Thanks, I've left some more comments.

Also, I've been gradually dropping the "oxide_" and "oxide_qt_" prefixes from filenames, keeping those only for files that implement Chromium interfaces

review: Needs Fixing
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

I think this looks ok (please see 1 comment inline though).

Also, I think I have an alternative idea for how the fallback could work. I'll open another bug for that though.

review: Approve
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Ok, I opened bug 1672707 too

Revision history for this message
Santosh (santoshbit2007) wrote :

Thanks chris, I will check two new child bugs.

Regards
Santosh

On Tue, Mar 14, 2017 at 5:54 PM, Chris Coulson <email address hidden>
wrote:

> Ok, I opened bug 1672707 too
> --
> https://code.launchpad.net/~santoshbit2007/oxide/+git/oxide/+merge/317213
> You are the owner of ~santoshbit2007/oxide:UITK_FilePicker_Impl.
>

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

Just tested with webbrowser-app unconfined on unity7 desktop, and while I’m getting the list of apps correctly displayed, clicking on any of them (including browser itself) does nothing and I’m seeing the following errors in the logs:

void ContentTransfer::setTransfer(com::ubuntu::content::Transfer*) No valid transfer object passed: QObject(0x0)
bool ContentTransfer::start() Transfer can't be started

Also, see two minor comments inline.

review: Needs Fixing
Revision history for this message
Santosh (santoshbit2007) wrote :

Thanks for comments.

I am aware of this issue, I think you are testing legacy webview filepicker and here webbrowser-app filepicker is used, anyway this issue is related with content-hub.
Basically what happens is deb package of source app are not correctly registered in
content-hub with unity7/desktop. Ken VanDine had same saying on this when I had asked.IIRC same issue happens with webbrowser-app without this patch.
I will do double check though.

Best way to validate with unity8/mobile platform and app having UbuntuWebView

I will check other comments.

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

Nope, I am indeed testing the new webview (I have a branch of webbrowser-app that makes use of it). With the legacy webview (and webbrowser-app’s file picker), I am able to select a file from webbrowser-app itself as a source. With your branch, I can’t. It’s gotta work on desktop too, testing on mobile is not enough.

Revision history for this message
Santosh (santoshbit2007) wrote :

I tried to test with some apps(filemanager, gallary) but they doesn't seems to works well with content-hub, although gallery app works only once(needs reboot nexttime) and filepicker works well with that. There is some works going on ken team to fix that

unity7 result are as:

UbuntuWebView + oxidefilepicker
 gallary --> works
 webbrowser-app -- > doesn't ( need to fix in app side, as of now legacy webbrowser-app filepicker has code that shows the webbrowser-app local download page)
 This will not be valid in current case as now filepicker is app independent.

legacy webview + webbrowser-app filepicker : ->
gallary --. works
webbrowser-app --> works

Revision history for this message
Santosh (santoshbit2007) wrote :

Tested on unity8 with gallery app, works fine here

Revision history for this message
Santosh (santoshbit2007) wrote :

rebased on latest oxide

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

Please see my comments inline.

I have tested with a custom branch of webbrowser-app that uses the new Oxide.Ubuntu WebView, on unity7 and unconfined.

The fallback to the file dialog works if qml-module-qtquick-dialogs is installed.

I can confirm that the content-hub dialog works well once with the gallery app as a provider, but it doesn’t work subsequent times.

I disagree that the custom code in webbrowser-app to show the downloads page is not a valid use-case. We can’t afford this kind of regression. Besides, it seems a perfectly valid use case for other apps that may want to provide an integrated content picker, not just webbrowser-app. I’d say we need an additional API that lets embedders provide a custom view for when the app itself is picked as a content provider.

We also might want to consider allowing embedders to override the built-in file picker. Apps might want to use the Oxide.Ubuntu WebView while retaining a tight control of what content can be uploaded.

review: Needs Fixing
Revision history for this message
Santosh (santoshbit2007) wrote :

Thanks olivier for reviews,

I agree with that disagree, may be I created confusion before but I also mean the same.
What I really mean is that "custom code in webbrowser-app to show the downloads" should be
in different place not in the webbrowser-app filepicker. so that when oxide's internal filepicker is used(in this case webbrowser-app filepicker is not used), showing of download page still happens.

Regarding overriding filepicker, Its minor work in term of coding because OxideUbuntuWebview directly drives from OxideQQuickWebView, so all the api exposed by OxideQQuickWebView are also valid for OxideUbuntuWebView, But there is difference in how ui_factroy has been used in both webview. OxideUbuntuWebView supports uitk factory and OxideQQuickWebView uses legacy_aux_factory.
uitk factory doesn't support overriding but legacy_aux_factory supports(as used by webrowser-app right now).
So Its basically design decision and would need to confirm with chris. If agreed I will prefer to take it in seperate patch.

1710134... by Santosh

Review comments addressed

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

See answers inline.

Revision history for this message
Santosh (santoshbit2007) :
48adfba... by Santosh

 test case updated

814695d... by Santosh

 Use compare in place of compare

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

The updates to the test case look ok. I'd still like to see proper testing of the content-hub based picker with mocks of the content-hub D-Bus API, but it looks like you want to implement that in a follow-up branch?

Revision history for this message
Santosh (santoshbit2007) wrote :

Hi Olivier,

Yes, I am planning to work testing part in separate branch, Its not very
straight way I need to do dig down in D-bus usage and also
would need to update oxide testing infrastructure. there was some updates
that content-hub project also plan to add some testing support
capability (not exactly clear what their plan).
Existing branch is already big to handle for me, and I don't to complicate
it further and mess up things, and I also feel review will be easier
in separate branch.

I already filed a bug for testing improvement
https://bugs.launchpad.net/oxide/+bug/1679628
Sure will look into this next.

Regards
Santosh

On Tue, Apr 4, 2017 at 9:43 PM, Olivier Tilloy <<email address hidden>
> wrote:

> The updates to the test case look ok. I'd still like to see proper testing
> of the content-hub based picker with mocks of the content-hub D-Bus API,
> but it looks like you want to implement that in a follow-up branch?
> --
> https://code.launchpad.net/~santoshbit2007/oxide/+git/oxide/+merge/317213
> You are the owner of ~santoshbit2007/oxide:UITK_FilePicker_Impl.
>

Unmerged commits

814695d... by Santosh

 Use compare in place of compare

48adfba... by Santosh

 test case updated

1710134... by Santosh

Review comments addressed

6a80baf... by Santosh

UITK FilePicker implementation

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/qt/core/BUILD.gn b/qt/core/BUILD.gn
2index 4a12427..395e906 100644
3--- a/qt/core/BUILD.gn
4+++ b/qt/core/BUILD.gn
5@@ -199,6 +199,8 @@ source_set("core_sources") {
6 "browser/clipboard/oxide_qt_clipboard.h",
7 "browser/contents_view_impl.cc",
8 "browser/contents_view_impl.h",
9+ "browser/file_picker_host.cc",
10+ "browser/file_picker_host.h",
11 "browser/input/input_method_context_owner_client.h",
12 "browser/input/qt_input_method_context.cc",
13 "browser/input/qt_input_method_context.h",
14@@ -224,8 +226,6 @@ source_set("core_sources") {
15 "browser/oxide_qt_drag_utils.h",
16 "browser/oxide_qt_event_utils.cc",
17 "browser/oxide_qt_event_utils.h",
18- "browser/oxide_qt_file_picker.cc",
19- "browser/oxide_qt_file_picker.h",
20 "browser/oxide_qt_find_controller.cc",
21 "browser/oxide_qt_find_controller.h",
22 "browser/oxide_qt_location_provider.cc",
23@@ -284,6 +284,8 @@ source_set("core_sources") {
24 "glue/contents_view.h",
25 "glue/contents_view_client.h",
26 "glue/edit_capability_flags.h",
27+ "glue/file_picker.h",
28+ "glue/file_picker_client.h",
29 "glue/javascript_dialog.h",
30 "glue/javascript_dialog_client.h",
31 "glue/javascript_dialog_type.h",
32@@ -296,8 +298,6 @@ source_set("core_sources") {
33 "glue/navigation_history.cc",
34 "glue/navigation_history.h",
35 "glue/navigation_history_client.h",
36- "glue/oxide_qt_file_picker_proxy.h",
37- "glue/oxide_qt_file_picker_proxy_client.h",
38 "glue/oxide_qt_init.cc",
39 "glue/oxide_qt_init.h",
40 "glue/oxide_qt_proxy_base.cc",
41diff --git a/qt/core/browser/file_picker_host.cc b/qt/core/browser/file_picker_host.cc
42new file mode 100644
43index 0000000..8a35163
44--- /dev/null
45+++ b/qt/core/browser/file_picker_host.cc
46@@ -0,0 +1,121 @@
47+// vim:expandtab:shiftwidth=2:tabstop=2:
48+// Copyright (C) 2017 Canonical Ltd.
49+
50+// This library is free software; you can redistribute it and/or
51+// modify it under the terms of the GNU Lesser General Public
52+// License as published by the Free Software Foundation; either
53+// version 2.1 of the License, or (at your option) any later version.
54+
55+// This library is distributed in the hope that it will be useful,
56+// but WITHOUT ANY WARRANTY; without even the implied warranty of
57+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
58+// Lesser General Public License for more details.
59+
60+// You should have received a copy of the GNU Lesser General Public
61+// License along with this library; if not, write to the Free Software
62+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
63+
64+#include "file_picker_host.h"
65+
66+#include <vector>
67+
68+#include <QDir>
69+#include <QFileInfo>
70+#include <QString>
71+#include <QStringList>
72+#include <QtGlobal>
73+
74+#include "base/files/file_path.h"
75+#include "base/strings/utf_string_conversions.h"
76+#include "content/public/common/file_chooser_file_info.h"
77+#include "content/public/common/file_chooser_params.h"
78+
79+#include "oxide/shared/browser/file_picker_client.h"
80+
81+#include "qt/core/glue/file_picker.h"
82+
83+namespace oxide {
84+namespace qt {
85+
86+namespace {
87+
88+content::FileChooserFileInfo MakeFileInfo(const QFileInfo& fi) {
89+ content::FileChooserFileInfo info;
90+ info.file_path = base::FilePath(fi.absoluteFilePath().toStdString());
91+ return info;
92+}
93+
94+std::vector<content::FileChooserFileInfo> Enumerate(const QDir& dir) {
95+ std::vector<content::FileChooserFileInfo> enumerated;
96+ QDir::Filters filters =
97+ QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden;
98+ for (const QFileInfo& file : dir.entryInfoList(filters)) {
99+ if (file.isDir()) {
100+ content::FileChooserFileInfo info;
101+ QString directoryPath = file.absoluteFilePath() + QStringLiteral("/.");
102+ info.file_path = base::FilePath(directoryPath.toStdString());
103+ enumerated.push_back(info);
104+ std::vector<content::FileChooserFileInfo> contents =
105+ Enumerate(file.absoluteFilePath());
106+ enumerated.insert(enumerated.end(), contents.begin(), contents.end());
107+ } else {
108+ enumerated.push_back(MakeFileInfo(file));
109+ }
110+ }
111+ return enumerated;
112+}
113+
114+}
115+
116+FilePickerHost::~FilePickerHost() = default;
117+
118+void FilePickerHost::Run() {
119+ picker_->Show();
120+}
121+
122+void FilePickerHost::Hide() {
123+ picker_->Hide();
124+}
125+
126+void FilePickerHost::done(const QFileInfoList& files,
127+ qt::FilePicker::Mode mode) {
128+ std::vector<content::FileChooserFileInfo> selection;
129+ if (mode == qt::FilePicker::UploadFolder) {
130+ if (!files.isEmpty() && files.first().isDir()) {
131+ // XXX: chrome does this asynchronously on a background thread
132+ // (see net::DirectoryLister)
133+ selection = Enumerate(files.first().absoluteFilePath());
134+ }
135+ } else {
136+ for (const QFileInfo& file : files) {
137+ selection.push_back(MakeFileInfo(file));
138+ }
139+ }
140+ content::FileChooserParams::Mode permissions;
141+ switch (mode) {
142+ case qt::FilePicker::Open:
143+ permissions = content::FileChooserParams::Open;
144+ break;
145+ case qt::FilePicker::OpenMultiple:
146+ permissions = content::FileChooserParams::OpenMultiple;
147+ break;
148+ case qt::FilePicker::UploadFolder:
149+ permissions = content::FileChooserParams::UploadFolder;
150+ break;
151+ case qt::FilePicker::Save:
152+ permissions = content::FileChooserParams::Save;
153+ break;
154+ }
155+
156+ client_->Done(selection, permissions);
157+}
158+
159+FilePickerHost::FilePickerHost(oxide::FilePickerClient* client)
160+ : client_(client) {}
161+
162+void FilePickerHost::Init(std::unique_ptr<qt::FilePicker> picker) {
163+ picker_ = std::move(picker);
164+}
165+
166+} // namespace qt
167+} // namespace oxide
168diff --git a/qt/core/browser/file_picker_host.h b/qt/core/browser/file_picker_host.h
169new file mode 100644
170index 0000000..1248cc9
171--- /dev/null
172+++ b/qt/core/browser/file_picker_host.h
173@@ -0,0 +1,61 @@
174+// vim:expandtab:shiftwidth=2:tabstop=2:
175+// Copyright (C) 2017 Canonical Ltd.
176+
177+// This library is free software; you can redistribute it and/or
178+// modify it under the terms of the GNU Lesser General Public
179+// License as published by the Free Software Foundation; either
180+// version 2.1 of the License, or (at your option) any later version.
181+
182+// This library is distributed in the hope that it will be useful,
183+// but WITHOUT ANY WARRANTY; without even the implied warranty of
184+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
185+// Lesser General Public License for more details.
186+
187+// You should have received a copy of the GNU Lesser General Public
188+// License along with this library; if not, write to the Free Software
189+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
190+
191+#ifndef _OXIDE_QT_CORE_BROWSER_FILE_PICKER_HOST_H_
192+#define _OXIDE_QT_CORE_BROWSER_FILE_PICKER_HOST_H_
193+
194+#include <memory>
195+
196+#include "base/macros.h"
197+
198+#include "qt/core/glue/file_picker_client.h"
199+#include "shared/browser/file_picker.h"
200+
201+namespace oxide {
202+
203+class FilePickerClient;
204+
205+namespace qt {
206+
207+class FilePicker;
208+
209+class FilePickerHost : public oxide::FilePicker, public FilePickerClient {
210+ public:
211+ FilePickerHost(oxide::FilePickerClient* client);
212+ ~FilePickerHost() override;
213+
214+ void Init(std::unique_ptr<qt::FilePicker> picker);
215+
216+ private:
217+ // oxide::FilePicker implementation
218+ void Run() override;
219+ void Hide() override;
220+
221+ // FilePickerClient implementation
222+ void done(const QFileInfoList& files, qt::FilePicker::Mode mode) override;
223+
224+ std::unique_ptr<qt::FilePicker> picker_;
225+
226+ oxide::FilePickerClient* client_;
227+
228+ DISALLOW_COPY_AND_ASSIGN(FilePickerHost);
229+};
230+
231+} // namespace qt
232+} // namespace oxide
233+
234+#endif // _OXIDE_QT_CORE_BROWSER_FILE_PICKER_HOST_H_
235diff --git a/qt/core/browser/oxide_qt_file_picker.cc b/qt/core/browser/oxide_qt_file_picker.cc
236deleted file mode 100644
237index 691e1ff..0000000
238--- a/qt/core/browser/oxide_qt_file_picker.cc
239+++ /dev/null
240@@ -1,145 +0,0 @@
241-// vim:expandtab:shiftwidth=2:tabstop=2:
242-// Copyright (C) 2014 Canonical Ltd.
243-
244-// This library is free software; you can redistribute it and/or
245-// modify it under the terms of the GNU Lesser General Public
246-// License as published by the Free Software Foundation; either
247-// version 2.1 of the License, or (at your option) any later version.
248-
249-// This library is distributed in the hope that it will be useful,
250-// but WITHOUT ANY WARRANTY; without even the implied warranty of
251-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
252-// Lesser General Public License for more details.
253-
254-// You should have received a copy of the GNU Lesser General Public
255-// License along with this library; if not, write to the Free Software
256-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
257-
258-#include "oxide_qt_file_picker.h"
259-
260-#include <vector>
261-
262-#include <QDir>
263-#include <QFileInfo>
264-#include <QString>
265-#include <QStringList>
266-#include <QtGlobal>
267-
268-#include "base/files/file_path.h"
269-#include "base/strings/utf_string_conversions.h"
270-#include "content/public/common/file_chooser_file_info.h"
271-#include "content/public/common/file_chooser_params.h"
272-
273-#include "qt/core/glue/oxide_qt_file_picker_proxy.h"
274-
275-namespace oxide {
276-namespace qt {
277-
278-namespace {
279-
280-content::FileChooserFileInfo MakeFileInfo(const QFileInfo& fi) {
281- content::FileChooserFileInfo info;
282- info.file_path = base::FilePath(fi.absoluteFilePath().toStdString());
283- return info;
284-}
285-
286-std::vector<content::FileChooserFileInfo> Enumerate(const QDir& dir) {
287- std::vector<content::FileChooserFileInfo> enumerated;
288- QDir::Filters filters =
289- QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden;
290- Q_FOREACH (const QFileInfo& file, dir.entryInfoList(filters)) {
291- if (file.isDir()) {
292- content::FileChooserFileInfo info;
293- QString directoryPath = file.absoluteFilePath() + QStringLiteral("/.");
294- info.file_path = base::FilePath(directoryPath.toStdString());
295- enumerated.push_back(info);
296- std::vector<content::FileChooserFileInfo> contents =
297- Enumerate(file.absoluteFilePath());
298- enumerated.insert(enumerated.end(), contents.begin(), contents.end());
299- } else {
300- enumerated.push_back(MakeFileInfo(file));
301- }
302- }
303- return enumerated;
304-}
305-
306-}
307-
308-FilePicker::~FilePicker() {}
309-
310-void FilePicker::Run(const content::FileChooserParams& params) {
311- FilePickerProxy::Mode mode;
312- switch (params.mode) {
313- case content::FileChooserParams::Open:
314- mode = FilePickerProxy::Open;
315- break;
316- case content::FileChooserParams::OpenMultiple:
317- mode = FilePickerProxy::OpenMultiple;
318- break;
319- case content::FileChooserParams::UploadFolder:
320- mode = FilePickerProxy::UploadFolder;
321- break;
322- case content::FileChooserParams::Save:
323- mode = FilePickerProxy::Save;
324- break;
325- default:
326- Q_UNREACHABLE();
327- }
328- QString title = QString::fromStdString(base::UTF16ToUTF8(params.title));
329- QFileInfo defaultFileName(QString::fromStdString(params.default_file_name.value()));
330- QStringList acceptTypes;
331- std::vector<base::string16>::const_iterator i;
332- for (i = params.accept_types.begin(); i != params.accept_types.end(); ++i) {
333- acceptTypes << QString::fromStdString(base::UTF16ToUTF8(*i));
334- }
335- proxy_->Show(mode, title, defaultFileName, acceptTypes);
336-}
337-
338-void FilePicker::Hide() {
339- proxy_->Hide();
340-}
341-
342-void FilePicker::done(const QFileInfoList& files,
343- FilePickerProxy::Mode mode) {
344- std::vector<content::FileChooserFileInfo> selection;
345- if (mode == FilePickerProxy::UploadFolder) {
346- if (!files.isEmpty() && files.first().isDir()) {
347- // XXX: chrome does this asynchronously on a background thread
348- // (see net::DirectoryLister)
349- selection = Enumerate(files.first().absoluteFilePath());
350- }
351- } else {
352- Q_FOREACH (const QFileInfo& file, files) {
353- selection.push_back(MakeFileInfo(file));
354- }
355- }
356- content::FileChooserParams::Mode permissions;
357- switch (mode) {
358- case FilePickerProxy::Open:
359- permissions = content::FileChooserParams::Open;
360- break;
361- case FilePickerProxy::OpenMultiple:
362- permissions = content::FileChooserParams::OpenMultiple;
363- break;
364- case FilePickerProxy::UploadFolder:
365- permissions = content::FileChooserParams::UploadFolder;
366- break;
367- case FilePickerProxy::Save:
368- permissions = content::FileChooserParams::Save;
369- break;
370- default:
371- Q_UNREACHABLE();
372- }
373-
374- Done(selection, permissions);
375-}
376-
377-FilePicker::FilePicker(content::RenderFrameHost* rfh)
378- : oxide::FilePicker(rfh) {}
379-
380-void FilePicker::SetProxy(FilePickerProxy* proxy) {
381- proxy_.reset(proxy);
382-}
383-
384-} // namespace qt
385-} // namespace oxide
386diff --git a/qt/core/browser/oxide_qt_file_picker.h b/qt/core/browser/oxide_qt_file_picker.h
387deleted file mode 100644
388index 3141395..0000000
389--- a/qt/core/browser/oxide_qt_file_picker.h
390+++ /dev/null
391@@ -1,59 +0,0 @@
392-// vim:expandtab:shiftwidth=2:tabstop=2:
393-// Copyright (C) 2014 Canonical Ltd.
394-
395-// This library is free software; you can redistribute it and/or
396-// modify it under the terms of the GNU Lesser General Public
397-// License as published by the Free Software Foundation; either
398-// version 2.1 of the License, or (at your option) any later version.
399-
400-// This library is distributed in the hope that it will be useful,
401-// but WITHOUT ANY WARRANTY; without even the implied warranty of
402-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
403-// Lesser General Public License for more details.
404-
405-// You should have received a copy of the GNU Lesser General Public
406-// License along with this library; if not, write to the Free Software
407-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
408-
409-#ifndef _OXIDE_QT_CORE_BROWSER_FILE_PICKER_H_
410-#define _OXIDE_QT_CORE_BROWSER_FILE_PICKER_H_
411-
412-#include <memory>
413-
414-#include "base/macros.h"
415-
416-#include "qt/core/glue/oxide_qt_file_picker_proxy_client.h"
417-#include "shared/browser/oxide_file_picker.h"
418-
419-namespace oxide {
420-namespace qt {
421-
422-class FilePickerProxy;
423-
424-class FilePicker : public oxide::FilePicker,
425- public FilePickerProxyClient {
426- public:
427- FilePicker(content::RenderFrameHost* rfh);
428-
429- void SetProxy(FilePickerProxy* proxy);
430-
431- private:
432- ~FilePicker() override;
433-
434- // oxide::FilePicker implementation
435- void Run(const content::FileChooserParams& params) override;
436- void Hide() override;
437-
438- // FilePickerProxyClient implementation
439- void done(const QFileInfoList& files,
440- FilePickerProxy::Mode mode) override;
441-
442- std::unique_ptr<FilePickerProxy> proxy_;
443-
444- DISALLOW_IMPLICIT_CONSTRUCTORS(FilePicker);
445-};
446-
447-} // namespace qt
448-} // namespace oxide
449-
450-#endif // _OXIDE_QT_CORE_BROWSER_FILE_PICKER_H_
451diff --git a/qt/core/browser/oxide_qt_web_view.cc b/qt/core/browser/oxide_qt_web_view.cc
452index ab4d2d2..5c0fa3d 100644
453--- a/qt/core/browser/oxide_qt_web_view.cc
454+++ b/qt/core/browser/oxide_qt_web_view.cc
455@@ -93,11 +93,11 @@
456 #include "shared/common/oxide_enum_flags.h"
457
458 #include "contents_view_impl.h"
459+#include "file_picker_host.h"
460 #include "javascript_dialog_host.h"
461 #include "menu_item_builder.h"
462 #include "oxide_qt_dpi_utils.h"
463 #include "oxide_qt_event_utils.h"
464-#include "oxide_qt_file_picker.h"
465 #include "oxide_qt_screen_utils.h"
466 #include "oxide_qt_script_message_handler.h"
467 #include "oxide_qt_type_conversions.h"
468@@ -543,10 +543,46 @@ void WebView::FrameMetadataUpdated(const cc::CompositorFrameMetadata& old) {
469 client_->FrameMetadataUpdated(flags);
470 }
471
472-oxide::FilePicker* WebView::CreateFilePicker(content::RenderFrameHost* rfh) {
473- FilePicker* picker = new FilePicker(rfh);
474- picker->SetProxy(client_->CreateFilePicker(picker));
475- return picker;
476+std::unique_ptr<oxide::FilePicker> WebView::CreateFilePicker(
477+ const content::FileChooserParams& params,
478+ oxide::FilePickerClient* client) {
479+ std::unique_ptr<qt::FilePickerHost> host =
480+ base::MakeUnique<qt::FilePickerHost>(client);
481+
482+ qt::FilePicker::Mode mode;
483+ switch (params.mode) {
484+ case content::FileChooserParams::Open:
485+ mode = qt::FilePicker::Open;
486+ break;
487+ case content::FileChooserParams::OpenMultiple:
488+ mode = qt::FilePicker::OpenMultiple;
489+ break;
490+ case content::FileChooserParams::UploadFolder:
491+ mode = qt::FilePicker::UploadFolder;
492+ break;
493+ case content::FileChooserParams::Save:
494+ mode = qt::FilePicker::Save;
495+ break;
496+ }
497+
498+ QString title = QString::fromStdString(base::UTF16ToUTF8(params.title));
499+ QFileInfo default_file_name(
500+ QString::fromStdString(params.default_file_name.value()));
501+
502+ QStringList accept_types;
503+ for (const auto& i : params.accept_types) {
504+ accept_types << QString::fromStdString(base::UTF16ToUTF8(i));
505+ }
506+
507+ std::unique_ptr<qt::FilePicker> picker = aux_ui_factory_->CreateFilePicker(
508+ mode, title, default_file_name, accept_types, host.get());
509+
510+ if (!picker) {
511+ return nullptr;
512+ }
513+
514+ host->Init(std::move(picker));
515+ return std::move(host);
516 }
517
518 void WebView::ContentBlocked() {
519diff --git a/qt/core/browser/oxide_qt_web_view.h b/qt/core/browser/oxide_qt_web_view.h
520index 5da67af..6f8f670 100644
521--- a/qt/core/browser/oxide_qt_web_view.h
522+++ b/qt/core/browser/oxide_qt_web_view.h
523@@ -125,7 +125,9 @@ class WebView : public oxide::WebViewClient,
524 int32_t line_no,
525 const base::string16& source_id) override;
526 void FrameMetadataUpdated(const cc::CompositorFrameMetadata& old) override;
527- oxide::FilePicker* CreateFilePicker(content::RenderFrameHost* rfh) override;
528+ std::unique_ptr<oxide::FilePicker> CreateFilePicker(
529+ const content::FileChooserParams& params,
530+ oxide::FilePickerClient* client) override;
531 void ContentBlocked() override;
532 void PrepareToCloseResponseReceived(bool proceed) override;
533 void CloseRequested() override;
534@@ -286,4 +288,4 @@ class WebView : public oxide::WebViewClient,
535 } // namespace qt
536 } // namespace oxide
537
538-#endif // _OXIDE_QT_CORE_BROWSER_WEB_VIEW_H_
539+#endif // _OXIDE_QT_CORE_BROWSER_WEB_VIEW_H_
540diff --git a/qt/core/glue/auxiliary_ui_factory.h b/qt/core/glue/auxiliary_ui_factory.h
541index 4150b1b..c96f0b1 100644
542--- a/qt/core/glue/auxiliary_ui_factory.h
543+++ b/qt/core/glue/auxiliary_ui_factory.h
544@@ -25,6 +25,7 @@
545
546 #include "qt/core/glue/edit_capability_flags.h"
547 #include "qt/core/glue/menu_item.h"
548+#include "qt/core/glue/file_picker.h"
549
550 QT_BEGIN_NAMESPACE
551 class QString;
552@@ -42,6 +43,8 @@ class TouchEditingMenuClient;
553 class WebContextMenu;
554 class WebContextMenuClient;
555 struct WebContextMenuParams;
556+class FilePickerClient;
557+class FilePicker;
558
559 class AuxiliaryUIFactory {
560 public:
561@@ -65,6 +68,13 @@ class AuxiliaryUIFactory {
562 virtual std::unique_ptr<JavaScriptDialog> CreateBeforeUnloadDialog(
563 const QUrl& origin_url,
564 JavaScriptDialogClient* client) = 0;
565+
566+ virtual std::unique_ptr<FilePicker> CreateFilePicker(
567+ qt::FilePicker::Mode mode,
568+ const QString& title,
569+ const QFileInfo& default_file,
570+ const QStringList& accept_types,
571+ FilePickerClient* client) = 0;
572 };
573
574 } // namespace qt
575diff --git a/qt/core/glue/file_picker.h b/qt/core/glue/file_picker.h
576new file mode 100644
577index 0000000..de44ae6
578--- /dev/null
579+++ b/qt/core/glue/file_picker.h
580@@ -0,0 +1,52 @@
581+// vim:expandtab:shiftwidth=2:tabstop=2:
582+// Copyright (C) 2014-2015 Canonical Ltd.
583+
584+// This library is free software; you can redistribute it and/or
585+// modify it under the terms of the GNU Lesser General Public
586+// License as published by the Free Software Foundation; either
587+// version 2.1 of the License, or (at your option) any later version.
588+
589+// This library is distributed in the hope that it will be useful,
590+// but WITHOUT ANY WARRANTY; without even the implied warranty of
591+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
592+// Lesser General Public License for more details.
593+
594+// You should have received a copy of the GNU Lesser General Public
595+// License along with this library; if not, write to the Free Software
596+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
597+
598+#ifndef _OXIDE_QT_CORE_GLUE_FILE_PICKER_H_
599+#define _OXIDE_QT_CORE_GLUE_FILE_PICKER_H_
600+
601+#include <QtGlobal>
602+
603+QT_BEGIN_NAMESPACE
604+class QFileInfo;
605+class QString;
606+class QStringList;
607+QT_END_NAMESPACE
608+
609+namespace oxide {
610+namespace qt {
611+
612+class FilePicker {
613+ public:
614+
615+ // Matches chromium’s content/public/common/file_chooser_params.h
616+ enum Mode {
617+ Open,
618+ OpenMultiple,
619+ UploadFolder,
620+ Save,
621+ };
622+
623+ virtual ~FilePicker() = default;
624+
625+ virtual void Hide() = 0;
626+ virtual void Show() = 0;
627+};
628+
629+} // namespace qt
630+} // namespace oxide
631+
632+#endif // _OXIDE_QT_CORE_GLUE_FILE_PICKER_H_
633diff --git a/qt/core/glue/file_picker_client.h b/qt/core/glue/file_picker_client.h
634new file mode 100644
635index 0000000..222e266
636--- /dev/null
637+++ b/qt/core/glue/file_picker_client.h
638@@ -0,0 +1,39 @@
639+// vim:expandtab:shiftwidth=2:tabstop=2:
640+// Copyright (C) 2014-2015 Canonical Ltd.
641+
642+// This library is free software; you can redistribute it and/or
643+// modify it under the terms of the GNU Lesser General Public
644+// License as published by the Free Software Foundation; either
645+// version 2.1 of the License, or (at your option) any later version.
646+
647+// This library is distributed in the hope that it will be useful,
648+// but WITHOUT ANY WARRANTY; without even the implied warranty of
649+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
650+// Lesser General Public License for more details.
651+
652+// You should have received a copy of the GNU Lesser General Public
653+// License along with this library; if not, write to the Free Software
654+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
655+
656+#ifndef _OXIDE_QT_CORE_GLUE_FILE_PICKER_CLIENT_H_
657+#define _OXIDE_QT_CORE_GLUE_FILE_PICKER_CLIENT_H_
658+
659+#include <QFileInfoList>
660+
661+#include "file_picker.h"
662+
663+namespace oxide {
664+namespace qt {
665+
666+class FilePickerClient {
667+ public:
668+ virtual ~FilePickerClient() = default;
669+
670+ virtual void done(const QFileInfoList& files,
671+ FilePicker::Mode mode) = 0;
672+};
673+
674+} // namespace qt
675+} // namespace oxide
676+
677+#endif // _OXIDE_QT_CORE_GLUE_FILE_PICKER_CLIENT_H_
678diff --git a/qt/core/glue/oxide_qt_file_picker_proxy.h b/qt/core/glue/oxide_qt_file_picker_proxy.h
679deleted file mode 100644
680index 62d3def..0000000
681--- a/qt/core/glue/oxide_qt_file_picker_proxy.h
682+++ /dev/null
683@@ -1,56 +0,0 @@
684-// vim:expandtab:shiftwidth=2:tabstop=2:
685-// Copyright (C) 2014-2015 Canonical Ltd.
686-
687-// This library is free software; you can redistribute it and/or
688-// modify it under the terms of the GNU Lesser General Public
689-// License as published by the Free Software Foundation; either
690-// version 2.1 of the License, or (at your option) any later version.
691-
692-// This library is distributed in the hope that it will be useful,
693-// but WITHOUT ANY WARRANTY; without even the implied warranty of
694-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
695-// Lesser General Public License for more details.
696-
697-// You should have received a copy of the GNU Lesser General Public
698-// License along with this library; if not, write to the Free Software
699-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
700-
701-#ifndef _OXIDE_QT_CORE_GLUE_FILE_PICKER_PROXY_H_
702-#define _OXIDE_QT_CORE_GLUE_FILE_PICKER_PROXY_H_
703-
704-#include <QtGlobal>
705-
706-QT_BEGIN_NAMESPACE
707-class QFileInfo;
708-class QString;
709-class QStringList;
710-QT_END_NAMESPACE
711-
712-namespace oxide {
713-namespace qt {
714-
715-class FilePickerProxy {
716- public:
717-
718- // Matches chromium’s content/public/common/file_chooser_params.h
719- enum Mode {
720- Open,
721- OpenMultiple,
722- UploadFolder,
723- Save,
724- };
725-
726- virtual ~FilePickerProxy() {}
727-
728- virtual void Show(Mode mode,
729- const QString& title,
730- const QFileInfo& default_fileName,
731- const QStringList& accept_types) = 0;
732-
733- virtual void Hide() = 0;
734-};
735-
736-} // namespace qt
737-} // namespace oxide
738-
739-#endif // _OXIDE_QT_CORE_GLUE_FILE_PICKER_PROXY_H_
740diff --git a/qt/core/glue/oxide_qt_file_picker_proxy_client.h b/qt/core/glue/oxide_qt_file_picker_proxy_client.h
741deleted file mode 100644
742index c1d6812..0000000
743--- a/qt/core/glue/oxide_qt_file_picker_proxy_client.h
744+++ /dev/null
745@@ -1,39 +0,0 @@
746-// vim:expandtab:shiftwidth=2:tabstop=2:
747-// Copyright (C) 2014-2015 Canonical Ltd.
748-
749-// This library is free software; you can redistribute it and/or
750-// modify it under the terms of the GNU Lesser General Public
751-// License as published by the Free Software Foundation; either
752-// version 2.1 of the License, or (at your option) any later version.
753-
754-// This library is distributed in the hope that it will be useful,
755-// but WITHOUT ANY WARRANTY; without even the implied warranty of
756-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
757-// Lesser General Public License for more details.
758-
759-// You should have received a copy of the GNU Lesser General Public
760-// License along with this library; if not, write to the Free Software
761-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
762-
763-#ifndef _OXIDE_QT_CORE_GLUE_FILE_PICKER_PROXY_CLIENT_H_
764-#define _OXIDE_QT_CORE_GLUE_FILE_PICKER_PROXY_CLIENT_H_
765-
766-#include <QFileInfoList>
767-
768-#include "qt/core/glue/oxide_qt_file_picker_proxy.h"
769-
770-namespace oxide {
771-namespace qt {
772-
773-class FilePickerProxyClient {
774- public:
775- virtual ~FilePickerProxyClient() {}
776-
777- virtual void done(const QFileInfoList& files,
778- FilePickerProxy::Mode mode) = 0;
779-};
780-
781-} // namespace qt
782-} // namespace oxide
783-
784-#endif // _OXIDE_QT_CORE_GLUE_FILE_PICKER_PROXY_CLIENT_H_
785diff --git a/qt/core/glue/oxide_qt_web_view_proxy_client.h b/qt/core/glue/oxide_qt_web_view_proxy_client.h
786index 91105f8..21e85f7 100644
787--- a/qt/core/glue/oxide_qt_web_view_proxy_client.h
788+++ b/qt/core/glue/oxide_qt_web_view_proxy_client.h
789@@ -46,8 +46,6 @@ QT_END_NAMESPACE
790 namespace oxide {
791 namespace qt {
792
793-class FilePickerProxy;
794-class FilePickerProxyClient;
795 class LegacyExternalTouchEditingMenuControllerDelegate;
796 class WebFrameProxy;
797
798@@ -68,9 +66,6 @@ class WebViewProxyClient {
799 return nullptr;
800 }
801
802- // XXX: Move to AuxiliaryUIFactory
803- virtual FilePickerProxy* CreateFilePicker(FilePickerProxyClient* client) = 0;
804-
805 virtual void WebProcessStatusChanged() = 0;
806
807 virtual void URLChanged() = 0;
808diff --git a/qt/quick/CMakeLists.txt b/qt/quick/CMakeLists.txt
809index 3737b68..621d2b1 100644
810--- a/qt/quick/CMakeLists.txt
811+++ b/qt/quick/CMakeLists.txt
812@@ -38,7 +38,7 @@ set(OXIDE_QUICKLIB_SRCS
813 contents_view.cc
814 legacy_contents_view.cc
815 oxide_qquick_accelerated_frame_node.cc
816- oxide_qquick_file_picker.cc
817+ qquick_legacy_file_picker.cc
818 oxide_qquick_image_frame_node.cc
819 oxide_qquick_init.cc
820 oxide_qquick_software_frame_node.cc
821diff --git a/qt/quick/api/oxideqquickwebview.cc b/qt/quick/api/oxideqquickwebview.cc
822index 1454418..842d917 100644
823--- a/qt/quick/api/oxideqquickwebview.cc
824+++ b/qt/quick/api/oxideqquickwebview.cc
825@@ -52,7 +52,6 @@
826 #include "qt/core/glue/macros.h"
827 #include "qt/quick/contents_view.h"
828 #include "qt/quick/legacy_contents_view.h"
829-#include "qt/quick/oxide_qquick_file_picker.h"
830 #include "qt/quick/oxide_qquick_init.h"
831 #include "qt/quick/qquick_legacy_auxiliary_ui_factory.h"
832
833@@ -138,7 +137,6 @@ OxideQQuickWebViewPrivate::OxideQQuickWebViewPrivate(
834 navigation_history_(OxideQQuickNavigationHistoryPrivate::Create()),
835 security_status_(OxideQSecurityStatusPrivate::Create()),
836 find_controller_(OxideQFindControllerPrivate::Create()),
837- file_picker_(nullptr),
838 using_old_load_event_signal_(false),
839 construct_props_(new ConstructProps()) {}
840
841@@ -153,13 +151,6 @@ OxideQQuickWebViewPrivate
842 touch_selection_controller_.get());
843 }
844
845-oxide::qt::FilePickerProxy* OxideQQuickWebViewPrivate::CreateFilePicker(
846- oxide::qt::FilePickerProxyClient* client) {
847- Q_Q(OxideQQuickWebView);
848-
849- return new oxide::qquick::FilePicker(q, client);
850-}
851-
852 void OxideQQuickWebViewPrivate::WebProcessStatusChanged() {
853 Q_Q(OxideQQuickWebView);
854
855@@ -1986,17 +1977,28 @@ void OxideQQuickWebView::setBeforeUnloadDialog(
856 QQmlComponent* OxideQQuickWebView::filePicker() const {
857 Q_D(const OxideQQuickWebView);
858
859- return d->file_picker_;
860+ if (!d->legacy_aux_ui_factory_) {
861+ return nullptr;
862+ }
863+
864+ return d->legacy_aux_ui_factory_->file_picker();
865 }
866
867-void OxideQQuickWebView::setFilePicker(QQmlComponent* filePicker) {
868+void OxideQQuickWebView::setFilePicker(QQmlComponent* filepicker) {
869 Q_D(OxideQQuickWebView);
870
871- if (d->file_picker_ == filePicker) {
872+ if (!d->legacy_aux_ui_factory_) {
873+ qWarning() <<
874+ "OxideQQuickWebView: Specifying a filepicker implementation "
875+ "has no effect on this WebView, as it provides a built-in file picker";
876+ return;
877+ }
878+
879+ if (d->legacy_aux_ui_factory_->file_picker() == filepicker) {
880 return;
881 }
882
883- d->file_picker_ = filePicker;
884+ d->legacy_aux_ui_factory_->set_file_picker(filepicker);
885 emit filePickerChanged();
886 }
887
888diff --git a/qt/quick/api/oxideqquickwebview_p.h b/qt/quick/api/oxideqquickwebview_p.h
889index 14930de..a765f84 100644
890--- a/qt/quick/api/oxideqquickwebview_p.h
891+++ b/qt/quick/api/oxideqquickwebview_p.h
892@@ -43,7 +43,6 @@ class OxideQQuickWebContextPrivate;
893 class OxideQQuickWebView;
894
895 QT_BEGIN_NAMESPACE
896-class QQmlComponent;
897 template <typename T> class QQmlListProperty;
898 class QQuickItem;
899 QT_END_NAMESPACE
900@@ -81,8 +80,6 @@ class OXIDE_QTQUICK_EXPORT OxideQQuickWebViewPrivate
901 // oxide::qt::WebViewProxyClient implementation
902 oxide::qt::LegacyExternalTouchEditingMenuControllerDelegate*
903 GetLegacyExternalTouchEditingMenuControllerDelegate() const override;
904- oxide::qt::FilePickerProxy* CreateFilePicker(
905- oxide::qt::FilePickerProxyClient* client) override;
906 void WebProcessStatusChanged() override;
907 void URLChanged() override;
908 void TitleChanged() override;
909@@ -162,8 +159,6 @@ class OXIDE_QTQUICK_EXPORT OxideQQuickWebViewPrivate
910 std::unique_ptr<OxideQQuickTouchSelectionController>
911 touch_selection_controller_;
912
913- QQmlComponent* file_picker_;
914-
915 bool using_old_load_event_signal_;
916
917 struct ConstructProps;
918diff --git a/qt/quick/oxide_qquick_file_picker.cc b/qt/quick/oxide_qquick_file_picker.cc
919deleted file mode 100644
920index ae8eaa5..0000000
921--- a/qt/quick/oxide_qquick_file_picker.cc
922+++ /dev/null
923@@ -1,171 +0,0 @@
924-// vim:expandtab:shiftwidth=2:tabstop=2:
925-// Copyright (C) 2014 Canonical Ltd.
926-
927-// This library is free software; you can redistribute it and/or
928-// modify it under the terms of the GNU Lesser General Public
929-// License as published by the Free Software Foundation; either
930-// version 2.1 of the License, or (at your option) any later version.
931-
932-// This library is distributed in the hope that it will be useful,
933-// but WITHOUT ANY WARRANTY; without even the implied warranty of
934-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
935-// Lesser General Public License for more details.
936-
937-// You should have received a copy of the GNU Lesser General Public
938-// License along with this library; if not, write to the Free Software
939-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
940-
941-#include "oxide_qquick_file_picker.h"
942-
943-#include <QDebug>
944-#include <QObject>
945-#include <QQmlComponent>
946-#include <QQmlContext>
947-#include <QQmlEngine>
948-#include <QQuickItem>
949-
950-#include "qt/core/glue/oxide_qt_file_picker_proxy_client.h"
951-#include "qt/quick/api/oxideqquickwebview.h"
952-#include "qt/quick/api/oxideqquickwebview_p.h"
953-
954-namespace oxide {
955-namespace qquick {
956-
957-class FilePickerContext : public QObject {
958- Q_OBJECT
959- Q_PROPERTY(bool allowMultipleFiles READ allowMultipleFiles CONSTANT FINAL)
960- Q_PROPERTY(bool directory READ directory CONSTANT FINAL)
961- Q_PROPERTY(QString title READ title CONSTANT FINAL)
962- Q_PROPERTY(QString defaultFileName READ defaultFileName CONSTANT FINAL)
963- Q_PROPERTY(QStringList acceptTypes READ acceptTypes CONSTANT FINAL)
964-
965- public:
966- virtual ~FilePickerContext() {}
967- FilePickerContext(oxide::qt::FilePickerProxyClient* client,
968- oxide::qt::FilePickerProxy::Mode mode,
969- const QString& title,
970- const QFileInfo& default_file_name,
971- const QStringList& accept_types);
972-
973- bool allowMultipleFiles() const;
974- bool directory() const;
975- const QString& title() const { return title_; }
976- const QString& defaultFileName() const { return default_file_name_; }
977- const QStringList& acceptTypes() const { return accept_types_; }
978-
979- public Q_SLOTS:
980- void accept(const QVariant& files) const;
981- void reject() const;
982-
983- private:
984- oxide::qt::FilePickerProxyClient* client_;
985- oxide::qt::FilePickerProxy::Mode mode_;
986- QString title_;
987- QString default_file_name_;
988- QStringList accept_types_;
989-};
990-
991-FilePickerContext::FilePickerContext(
992- oxide::qt::FilePickerProxyClient* client,
993- oxide::qt::FilePickerProxy::Mode mode,
994- const QString& title,
995- const QFileInfo& default_file_name,
996- const QStringList& accept_types)
997- : client_(client),
998- mode_(mode),
999- title_(title),
1000- default_file_name_(default_file_name.filePath()),
1001- accept_types_(accept_types) {}
1002-
1003-bool FilePickerContext::allowMultipleFiles() const {
1004- return (mode_ == oxide::qt::FilePickerProxy::OpenMultiple);
1005-}
1006-
1007-bool FilePickerContext::directory() const {
1008- return (mode_ == oxide::qt::FilePickerProxy::UploadFolder);
1009-}
1010-
1011-void FilePickerContext::accept(const QVariant& files) const {
1012- QFileInfoList info;
1013- Q_FOREACH(const QString& file, files.toStringList()) {
1014- if (QFileInfo::exists(file)) {
1015- info.append(QFileInfo(file));
1016- }
1017- }
1018- if ((info.size() > 1) && !allowMultipleFiles()) {
1019- qWarning() <<
1020- "FilePickerContext::accept: This file picker does not allow selecting "
1021- "multiple files";
1022- info.erase(info.begin() + 1, info.end());
1023- }
1024- client_->done(info, mode_);
1025-}
1026-
1027-void FilePickerContext::reject() const {
1028- client_->done(QFileInfoList(), mode_);
1029-}
1030-
1031-FilePicker::~FilePicker() {}
1032-
1033-void FilePicker::Show(Mode mode,
1034- const QString& title,
1035- const QFileInfo& default_fileName,
1036- const QStringList& accept_types) {
1037- if (!view_) {
1038- qWarning() << "FilePicker::Show: Can't show after the view has gone";
1039- client_->done(QFileInfoList(), mode);
1040- return;
1041- }
1042-
1043- FilePickerContext* contextObject =
1044- new FilePickerContext(client_, mode, title, default_fileName, accept_types);
1045- QQmlComponent* component = view_->filePicker();
1046- if (!component) {
1047- qWarning() <<
1048- "FilePicker::Show: Content requested a file picker, but the "
1049- "application hasn't provided one";
1050- delete contextObject;
1051- client_->done(QFileInfoList(), mode);
1052- return;
1053- }
1054-
1055- QQmlContext* baseContext = component->creationContext();
1056- if (!baseContext) {
1057- baseContext = QQmlEngine::contextForObject(view_);
1058- }
1059- context_.reset(new QQmlContext(baseContext));
1060-
1061- context_->setContextProperty(QLatin1String("model"), contextObject);
1062- context_->setContextObject(contextObject);
1063- contextObject->setParent(context_.data());
1064-
1065- item_.reset(qobject_cast<QQuickItem*>(component->beginCreate(context_.data())));
1066- if (!item_) {
1067- qWarning() <<
1068- "FilePicker::Show: Failed to create instance of Qml file picker "
1069- "component";
1070- context_.reset();
1071- client_->done(QFileInfoList(), mode);
1072- return;
1073- }
1074-
1075- OxideQQuickWebViewPrivate::get(view_)->addAttachedPropertyTo(item_.data());
1076- item_->setParentItem(view_);
1077- component->completeCreate();
1078-}
1079-
1080-void FilePicker::Hide() {
1081- if (!item_.isNull()) {
1082- item_->setVisible(false);
1083- }
1084-}
1085-
1086-FilePicker::FilePicker(OxideQQuickWebView* view,
1087- oxide::qt::FilePickerProxyClient* client)
1088- : view_(view),
1089- client_(client) {}
1090-
1091-} // namespace qquick
1092-} // namespace oxide
1093-
1094-#include "oxide_qquick_file_picker.moc"
1095diff --git a/qt/quick/oxide_qquick_file_picker.h b/qt/quick/oxide_qquick_file_picker.h
1096deleted file mode 100644
1097index f988d8f..0000000
1098--- a/qt/quick/oxide_qquick_file_picker.h
1099+++ /dev/null
1100@@ -1,66 +0,0 @@
1101-// vim:expandtab:shiftwidth=2:tabstop=2:
1102-// Copyright (C) 2014 Canonical Ltd.
1103-
1104-// This library is free software; you can redistribute it and/or
1105-// modify it under the terms of the GNU Lesser General Public
1106-// License as published by the Free Software Foundation; either
1107-// version 2.1 of the License, or (at your option) any later version.
1108-
1109-// This library is distributed in the hope that it will be useful,
1110-// but WITHOUT ANY WARRANTY; without even the implied warranty of
1111-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1112-// Lesser General Public License for more details.
1113-
1114-// You should have received a copy of the GNU Lesser General Public
1115-// License along with this library; if not, write to the Free Software
1116-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1117-
1118-#ifndef _OXIDE_QT_QUICK_FILE_PICKER_H_
1119-#define _OXIDE_QT_QUICK_FILE_PICKER_H_
1120-
1121-#include <QPointer>
1122-#include <QScopedPointer>
1123-#include <QtGlobal>
1124-
1125-#include "qt/core/glue/oxide_qt_file_picker_proxy.h"
1126-
1127-class OxideQQuickWebView;
1128-
1129-QT_BEGIN_NAMESPACE
1130-class QQmlContext;
1131-class QQuickItem;
1132-QT_END_NAMESPACE
1133-
1134-namespace oxide {
1135-
1136-namespace qt {
1137-class FilePickerProxyClient;
1138-}
1139-
1140-namespace qquick {
1141-
1142-class FilePicker : public oxide::qt::FilePickerProxy {
1143- public:
1144- FilePicker(OxideQQuickWebView* view,
1145- oxide::qt::FilePickerProxyClient* client);
1146-
1147- private:
1148- ~FilePicker() override;
1149-
1150- // oxide::qt::FilePickerProxy implementation
1151- void Show(Mode mode,
1152- const QString& title,
1153- const QFileInfo& default_filename,
1154- const QStringList& accept_types) override;
1155- void Hide() override;
1156-
1157- QPointer<OxideQQuickWebView> view_;
1158- oxide::qt::FilePickerProxyClient* client_;
1159- QScopedPointer<QQmlContext> context_;
1160- QScopedPointer<QQuickItem> item_;
1161-};
1162-
1163-} // namespace qquick
1164-} // namespace oxide
1165-
1166-#endif // _OXIDE_QT_QUICK_FILE_PICKER_H_
1167diff --git a/qt/quick/qquick_legacy_auxiliary_ui_factory.cc b/qt/quick/qquick_legacy_auxiliary_ui_factory.cc
1168index c0084c2..a85eccb 100644
1169--- a/qt/quick/qquick_legacy_auxiliary_ui_factory.cc
1170+++ b/qt/quick/qquick_legacy_auxiliary_ui_factory.cc
1171@@ -13,7 +13,7 @@
1172
1173 // You should have received a copy of the GNU Lesser General Public
1174 // License along with this library; if not, write to the Free Software
1175-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1176+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1177
1178 #include "qquick_legacy_auxiliary_ui_factory.h"
1179
1180@@ -25,6 +25,7 @@
1181 #include "qquick_legacy_alert_dialog.h"
1182 #include "qquick_legacy_before_unload_dialog.h"
1183 #include "qquick_legacy_confirm_dialog.h"
1184+#include "qquick_legacy_file_picker.h"
1185 #include "qquick_legacy_prompt_dialog.h"
1186 #include "qquick_legacy_web_context_menu.h"
1187
1188@@ -103,10 +104,25 @@ LegacyAuxiliaryUIFactory::CreateBeforeUnloadDialog(
1189 new LegacyBeforeUnloadDialog(item_, before_unload_dialog_, client));
1190 }
1191
1192+std::unique_ptr<qt::FilePicker> LegacyAuxiliaryUIFactory::CreateFilePicker(
1193+ qt::FilePicker::Mode mode,
1194+ const QString& title,
1195+ const QFileInfo& default_file_name,
1196+ const QStringList& accept_types,
1197+ qt::FilePickerClient* client) {
1198+ if (!file_picker_) {
1199+ return nullptr;
1200+ }
1201+
1202+ return std::unique_ptr<qt::FilePicker>(
1203+ new LegacyFilePicker(item_, file_picker_, mode, title, default_file_name,
1204+ accept_types, client));
1205+}
1206+
1207 LegacyAuxiliaryUIFactory::LegacyAuxiliaryUIFactory(QQuickItem* item)
1208 : item_(item) {}
1209
1210 LegacyAuxiliaryUIFactory::~LegacyAuxiliaryUIFactory() = default;
1211
1212-} // namespace qquick
1213-} // namespace oxide
1214+} // namespace qquick
1215+} // namespace oxide
1216diff --git a/qt/quick/qquick_legacy_auxiliary_ui_factory.h b/qt/quick/qquick_legacy_auxiliary_ui_factory.h
1217index a7cec12..08421ed 100644
1218--- a/qt/quick/qquick_legacy_auxiliary_ui_factory.h
1219+++ b/qt/quick/qquick_legacy_auxiliary_ui_factory.h
1220@@ -53,6 +53,9 @@ class LegacyAuxiliaryUIFactory : public qt::AuxiliaryUIFactory {
1221 QQmlComponent* before_unload_dialog() const { return before_unload_dialog_; }
1222 void set_before_unload_dialog(QQmlComponent* c) { before_unload_dialog_ = c; }
1223
1224+ QQmlComponent* file_picker() const { return file_picker_; }
1225+ void set_file_picker(QQmlComponent* c) { file_picker_ = c; }
1226+
1227 private:
1228 // qt::AuxiliaryUIFactory implementation
1229 std::unique_ptr<qt::WebContextMenu> CreateWebContextMenu(
1230@@ -71,6 +74,12 @@ class LegacyAuxiliaryUIFactory : public qt::AuxiliaryUIFactory {
1231 std::unique_ptr<qt::JavaScriptDialog> CreateBeforeUnloadDialog(
1232 const QUrl& origin_url,
1233 qt::JavaScriptDialogClient* client) override;
1234+ std::unique_ptr<qt::FilePicker> CreateFilePicker(
1235+ qt::FilePicker::Mode mode,
1236+ const QString& title,
1237+ const QFileInfo& default_file_name,
1238+ const QStringList& accept_types,
1239+ qt::FilePickerClient* client) override;
1240
1241 QQuickItem* item_;
1242
1243@@ -79,6 +88,7 @@ class LegacyAuxiliaryUIFactory : public qt::AuxiliaryUIFactory {
1244 QPointer<QQmlComponent> confirm_dialog_;
1245 QPointer<QQmlComponent> prompt_dialog_;
1246 QPointer<QQmlComponent> before_unload_dialog_;
1247+ QPointer<QQmlComponent> file_picker_;
1248 };
1249
1250 } // namespace qquick
1251diff --git a/qt/quick/qquick_legacy_file_picker.cc b/qt/quick/qquick_legacy_file_picker.cc
1252new file mode 100644
1253index 0000000..cfe12ba
1254--- /dev/null
1255+++ b/qt/quick/qquick_legacy_file_picker.cc
1256@@ -0,0 +1,182 @@
1257+// vim:expandtab:shiftwidth=2:tabstop=2:
1258+// Copyright (C) 2014 Canonical Ltd.
1259+
1260+// This library is free software; you can redistribute it and/or
1261+// modify it under the terms of the GNU Lesser General Public
1262+// License as published by the Free Software Foundation; either
1263+// version 2.1 of the License, or (at your option) any later version.
1264+
1265+// This library is distributed in the hope that it will be useful,
1266+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1267+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1268+// Lesser General Public License for more details.
1269+
1270+// You should have received a copy of the GNU Lesser General Public
1271+// License along with this library; if not, write to the Free Software
1272+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1273+
1274+#include "qquick_legacy_file_picker.h"
1275+
1276+#include <QDebug>
1277+#include <QFileInfoList>
1278+#include <QObject>
1279+#include <QQmlComponent>
1280+#include <QQmlContext>
1281+#include <QQmlEngine>
1282+#include <QQuickItem>
1283+
1284+#include "qt/core/glue/file_picker_client.h"
1285+#include "qt/quick/api/oxideqquickwebview.h"
1286+#include "qt/quick/api/oxideqquickwebview_p.h"
1287+
1288+namespace oxide {
1289+namespace qquick {
1290+
1291+class FilePickerContext : public QObject {
1292+ Q_OBJECT
1293+ Q_PROPERTY(bool allowMultipleFiles READ allowMultipleFiles CONSTANT FINAL)
1294+ Q_PROPERTY(bool directory READ directory CONSTANT FINAL)
1295+ Q_PROPERTY(QString title READ title CONSTANT FINAL)
1296+ Q_PROPERTY(QString defaultFileName READ defaultFileName CONSTANT FINAL)
1297+ Q_PROPERTY(QStringList acceptTypes READ acceptTypes CONSTANT FINAL)
1298+
1299+ public:
1300+ virtual ~FilePickerContext() {}
1301+ FilePickerContext(oxide::qt::FilePickerClient* client,
1302+ oxide::qt::FilePicker::Mode mode,
1303+ const QString& title,
1304+ const QFileInfo& default_file,
1305+ const QStringList& accept_types);
1306+
1307+ bool allowMultipleFiles() const;
1308+ bool directory() const;
1309+ const QString& title() const { return title_; }
1310+ const QString& defaultFileName() const { return default_file_name_; }
1311+ const QStringList& acceptTypes() const { return accept_types_; }
1312+
1313+ public Q_SLOTS:
1314+ void accept(const QVariant& files) const;
1315+ void reject() const;
1316+
1317+ private:
1318+ oxide::qt::FilePickerClient* client_;
1319+ oxide::qt::FilePicker::Mode mode_;
1320+ QString title_;
1321+ QString default_file_name_;
1322+ QStringList accept_types_;
1323+};
1324+
1325+FilePickerContext::FilePickerContext(oxide::qt::FilePickerClient* client,
1326+ oxide::qt::FilePicker::Mode mode,
1327+ const QString& title,
1328+ const QFileInfo& default_file_name,
1329+ const QStringList& accept_types)
1330+ : client_(client),
1331+ mode_(mode),
1332+ title_(title),
1333+ default_file_name_(default_file_name.filePath()),
1334+ accept_types_(accept_types) {}
1335+
1336+bool FilePickerContext::allowMultipleFiles() const {
1337+ return (mode_ == oxide::qt::FilePicker::OpenMultiple);
1338+}
1339+
1340+bool FilePickerContext::directory() const {
1341+ return (mode_ == oxide::qt::FilePicker::UploadFolder);
1342+}
1343+
1344+void FilePickerContext::accept(const QVariant& files) const {
1345+ QFileInfoList info;
1346+ for (const QString& file : files.toStringList()) {
1347+ if (QFileInfo::exists(file)) {
1348+ info.append(QFileInfo(file));
1349+ }
1350+ }
1351+ if ((info.size() > 1) && !allowMultipleFiles()) {
1352+ qWarning() <<
1353+ "FilePickerContext::accept: This file picker does not allow selecting "
1354+ "multiple files";
1355+ info.erase(info.begin() + 1, info.end());
1356+ }
1357+ client_->done(info, mode_);
1358+}
1359+
1360+void FilePickerContext::reject() const {
1361+ client_->done(QFileInfoList(), mode_);
1362+}
1363+
1364+LegacyFilePicker::~LegacyFilePicker() {}
1365+
1366+void LegacyFilePicker::Show() {
1367+ if (!parent_) {
1368+ qWarning()
1369+ << "LegacyFilePicker::Show: Can't show after the parent has gone";
1370+ client_->done(QFileInfoList(), mode_);
1371+ return;
1372+ }
1373+
1374+ if (!component_) {
1375+ qWarning()
1376+ << "LegacyFilePicker::Show: Content requested a file picker, but the "
1377+ "application hasn't provided one";
1378+ client_->done(QFileInfoList(), mode_);
1379+ return;
1380+ }
1381+
1382+ FilePickerContext* contextObject = new FilePickerContext(
1383+ client_, mode_, title_, default_file_, accept_types_);
1384+
1385+ QQmlContext* baseContext = component_->creationContext();
1386+ if (!baseContext) {
1387+ baseContext = QQmlEngine::contextForObject(parent_);
1388+ }
1389+ context_.reset(new QQmlContext(baseContext));
1390+
1391+ context_->setContextProperty(QLatin1String("model"), contextObject);
1392+ context_->setContextObject(contextObject);
1393+ contextObject->setParent(context_.data());
1394+
1395+ item_.reset(qobject_cast<QQuickItem*>(component_->beginCreate(context_.data())));
1396+ if (!item_) {
1397+ qWarning() <<
1398+ "LegacyFilePicker::Show: Failed to create instance of Qml file picker "
1399+ "component";
1400+ context_.reset();
1401+ client_->done(QFileInfoList(), mode_);
1402+ return;
1403+ }
1404+
1405+ OxideQQuickWebView* web_view = qobject_cast<OxideQQuickWebView*>(parent_);
1406+ if (web_view) {
1407+ OxideQQuickWebViewPrivate::get(web_view)
1408+ ->addAttachedPropertyTo(item_.data());
1409+ }
1410+ item_->setParentItem(parent_);
1411+ component_->completeCreate();
1412+}
1413+
1414+void LegacyFilePicker::Hide() {
1415+ if (!item_.isNull()) {
1416+ item_->setVisible(false);
1417+ }
1418+}
1419+
1420+LegacyFilePicker::LegacyFilePicker(QQuickItem* parent,
1421+ QQmlComponent* component,
1422+ qt::FilePicker::Mode mode,
1423+ const QString& title,
1424+ const QFileInfo& default_file,
1425+ const QStringList& accept_types,
1426+ qt::FilePickerClient* client)
1427+ : parent_(parent),
1428+ component_(component),
1429+ mode_(mode),
1430+ title_(title),
1431+ default_file_(default_file),
1432+ accept_types_(accept_types),
1433+ client_(client) {}
1434+
1435+} // namespace qquick
1436+} // namespace oxide
1437+
1438+#include "qquick_legacy_file_picker.moc"
1439diff --git a/qt/quick/qquick_legacy_file_picker.h b/qt/quick/qquick_legacy_file_picker.h
1440new file mode 100644
1441index 0000000..83bbd5c
1442--- /dev/null
1443+++ b/qt/quick/qquick_legacy_file_picker.h
1444@@ -0,0 +1,77 @@
1445+// vim:expandtab:shiftwidth=2:tabstop=2:
1446+// Copyright (C) 2014 Canonical Ltd.
1447+
1448+// This library is free software; you can redistribute it and/or
1449+// modify it under the terms of the GNU Lesser General Public
1450+// License as published by the Free Software Foundation; either
1451+// version 2.1 of the License, or (at your option) any later version.
1452+
1453+// This library is distributed in the hope that it will be useful,
1454+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1455+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1456+// Lesser General Public License for more details.
1457+
1458+// You should have received a copy of the GNU Lesser General Public
1459+// License along with this library; if not, write to the Free Software
1460+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1461+
1462+#ifndef _OXIDE_QT_QUICK_LEGACY_FILE_PICKER_H_
1463+#define _OXIDE_QT_QUICK_LEGACY_FILE_PICKER_H_
1464+
1465+#include <QFileInfo>
1466+#include <QPointer>
1467+#include <QScopedPointer>
1468+#include <QStringList>
1469+#include <QtGlobal>
1470+
1471+#include "qt/core/glue/file_picker.h"
1472+
1473+class OxideQQuickWebView;
1474+
1475+QT_BEGIN_NAMESPACE
1476+class QQmlContext;
1477+class QQmlComponent;
1478+class QQuickItem;
1479+QT_END_NAMESPACE
1480+
1481+namespace oxide {
1482+
1483+namespace qt {
1484+class FilePickerClient;
1485+}
1486+
1487+namespace qquick {
1488+
1489+class LegacyFilePicker : public qt::FilePicker {
1490+ public:
1491+ LegacyFilePicker(QQuickItem* parent,
1492+ QQmlComponent* component,
1493+ qt::FilePicker::Mode mode,
1494+ const QString& title,
1495+ const QFileInfo& default_file,
1496+ const QStringList& accept_types,
1497+ qt::FilePickerClient* client);
1498+
1499+ private:
1500+ ~LegacyFilePicker() override;
1501+
1502+ // oxide::qt::FilePicker implementation
1503+ void Show() override;
1504+ void Hide() override;
1505+
1506+ QPointer<QQuickItem> parent_;
1507+ QPointer<QQmlComponent> component_;
1508+ oxide::qt::FilePickerClient* client_;
1509+ QScopedPointer<QQmlContext> context_;
1510+ QScopedPointer<QQuickItem> item_;
1511+
1512+ qt::FilePicker::Mode mode_;
1513+ QString title_;
1514+ QFileInfo default_file_;
1515+ QStringList accept_types_;
1516+};
1517+
1518+} // namespace qquick
1519+} // namespace oxide
1520+
1521+#endif // _OXIDE_QT_QUICK_LEGACY_FILE_PICKER_H_
1522diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewFilePicker.html b/qt/tests/qmltests/ubuntu_ui/tst_WebViewFilePicker.html
1523new file mode 100644
1524index 0000000..f0ae7ec
1525--- /dev/null
1526+++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewFilePicker.html
1527@@ -0,0 +1,11 @@
1528+<!DOCTYPE html>
1529+<html>
1530+ <body>
1531+ <input id="input1" type="file">
1532+ <input id="input2" type="file" multiple>
1533+
1534+ <input id="input3" type="file" accept="image/*">
1535+ <input id="input4" type="file" accept="image/*,audio/*,video/*">
1536+ </body>
1537+</html>
1538+
1539diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewFilePicker.qml b/qt/tests/qmltests/ubuntu_ui/tst_WebViewFilePicker.qml
1540new file mode 100644
1541index 0000000..d30f798
1542--- /dev/null
1543+++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewFilePicker.qml
1544@@ -0,0 +1,58 @@
1545+import QtQuick 2.0
1546+import QtTest 1.0
1547+import com.canonical.Oxide 1.19
1548+import Oxide.Ubuntu 1.0
1549+import Oxide.testsupport 1.0
1550+import Ubuntu.Components 1.3
1551+
1552+UbuntuTestWebView {
1553+ id: webView
1554+ width: 800
1555+ height: 600
1556+
1557+ objectName: "webView"
1558+
1559+ TestCase {
1560+ id: test
1561+ name: "WebViewFilePicker"
1562+ when: windowShown
1563+
1564+ function getFilePicker() {
1565+ return TestSupport.findItemInScene(TestWindow.rootItem, "webView_WebFilePicker");
1566+ }
1567+
1568+ function waitForFilePicker() {
1569+ return TestUtils.waitFor(function() { return !!getFilePicker(); });
1570+ }
1571+
1572+ function closeFilePicker() {
1573+ return getFilePicker().accept([]);
1574+ }
1575+
1576+ function test_WebViewFilePicker1_launch_data() {
1577+ return [
1578+ {selector : "#input1", types : "", multiple : false},
1579+ {selector : "#input2", types : "", multiple : true},
1580+ {selector : "#input3", types : "image/*", multiple : false},
1581+ {selector : "#input4", types : "image/*,audio/*,video/*", multiple : false},
1582+ ]
1583+ }
1584+
1585+ // TODO : This just test the launch and close of filepicker since
1586+ // simulating complete file selection in content hub is not possible.
1587+ // So Need to boost the testcase with simulation of content-hub.
1588+ function test_WebViewFilePicker1_launch(data) {
1589+ webView.url = "http://testsuite/tst_WebViewFilePicker.html";
1590+ verify(webView.waitForLoadSucceeded());
1591+ var r = webView.getTestApi().getBoundingClientRectForSelector(data.selector);
1592+ mouseClick(webView, r.x + r.width / 2, r.y + r.height / 2);
1593+ verify(waitForFilePicker());
1594+
1595+ var pickerObject = getFilePicker();
1596+ compare(pickerObject.acceptTypes.toString(), data.types);
1597+ compare(pickerObject.allowMultiple, data.multiple);
1598+
1599+ closeFilePicker();
1600+ }
1601+ }
1602+}
1603diff --git a/qt/uitk/lib/CMakeLists.txt b/qt/uitk/lib/CMakeLists.txt
1604index 9e76ebe..d2e0234 100644
1605--- a/qt/uitk/lib/CMakeLists.txt
1606+++ b/qt/uitk/lib/CMakeLists.txt
1607@@ -27,6 +27,7 @@ set(OXIDE_UITKLIB_SRCS
1608 uitk_javascript_dialog.cc
1609 uitk_touch_editing_menu.cc
1610 uitk_touch_handle_drawable.cc
1611+ uitk_file_picker.cc
1612 uitk_web_context_menu.cc
1613 uitk_web_popup_menu.cc)
1614
1615diff --git a/qt/uitk/lib/resources.qrc b/qt/uitk/lib/resources.qrc
1616index f2cf4ba..333b717 100644
1617--- a/qt/uitk/lib/resources.qrc
1618+++ b/qt/uitk/lib/resources.qrc
1619@@ -9,5 +9,7 @@
1620 <file alias="WebContextMenuMobile.qml">resources/WebContextMenuMobile.qml</file>
1621 <file alias="WebContextMenuDesktop.qml">resources/WebContextMenuDesktop.qml</file>
1622 <file alias="WebPopupMenu.qml">resources/WebPopupMenu.qml</file>
1623+ <file alias="FilePickerDialog.qml">resources/FilePickerDialog.qml</file>
1624+ <file alias="FilePickerContentHub.qml">resources/FilePickerContentHub.qml</file>
1625 </qresource>
1626 </RCC>
1627diff --git a/qt/uitk/lib/resources/FilePickerContentHub.qml b/qt/uitk/lib/resources/FilePickerContentHub.qml
1628new file mode 100644
1629index 0000000..f360d45
1630--- /dev/null
1631+++ b/qt/uitk/lib/resources/FilePickerContentHub.qml
1632@@ -0,0 +1,122 @@
1633+// vim:expandtab:shiftwidth=2:tabstop=2:
1634+// Copyright (C) 2017 Canonical Ltd.
1635+
1636+// This library is free software; you can redistribute it and/or
1637+// modify it under the terms of the GNU Lesser General Public
1638+// License as published by the Free Software Foundation; either
1639+// version 2.1 of the License, or (at your option) any later version.
1640+
1641+// This library is distributed in the hope that it will be useful,
1642+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1643+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1644+// Lesser General Public License for more details.
1645+
1646+// You should have received a copy of the GNU Lesser General Public
1647+// License along with this library; if not, write to the Free Software
1648+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1649+
1650+import QtQuick 2.4
1651+import Ubuntu.Components.Popups 1.3 as Popups
1652+import Ubuntu.Content 1.3
1653+
1654+Popups.PopupBase {
1655+ id: picker
1656+ objectName: parent.objectName ? parent.objectName + "_WebFilePicker" : ""
1657+
1658+ property bool allowMultiple
1659+ property bool directory
1660+ property string title
1661+ property string defaultFileName
1662+ property var acceptTypes
1663+
1664+ property var activeContentTransfer
1665+
1666+ signal accept(var files)
1667+
1668+ Rectangle {
1669+ anchors.fill: parent
1670+
1671+ ContentPeerPicker {
1672+ id: peerPicker
1673+ anchors.fill: parent
1674+ contentType: ContentType.All
1675+ handler: ContentHandler.Source
1676+ headerText: picker.title
1677+ showTitle: true
1678+
1679+ onPeerSelected: {
1680+ if (picker.allowMultiple) {
1681+ peer.selectionType = ContentTransfer.Multiple;
1682+ } else {
1683+ peer.selectionType = ContentTransfer.Single;
1684+ }
1685+
1686+ picker.activeContentTransfer = peer.request();
1687+ transferConnection.target = picker.activeContentTransfer;
1688+ }
1689+
1690+ onCancelPressed: {
1691+ picker.accept([]);
1692+ }
1693+ }
1694+ }
1695+
1696+ Connections {
1697+ id: transferConnection
1698+ target: null
1699+ onStateChanged: {
1700+ if (picker.activeContentTransfer.state === ContentTransfer.Charged) {
1701+ var selectedItems = [];
1702+ for (var i in picker.activeContentTransfer.items) {
1703+ selectedItems.push(String(picker.activeContentTransfer.items[i].url)
1704+ .replace("file://", ""));
1705+ }
1706+ picker.accept(selectedItems);
1707+ }
1708+ }
1709+ }
1710+
1711+ function mimeTypeToContentType(mimeType) {
1712+ if (mimeType.search("image/") === 0) {
1713+ return ContentType.Pictures;
1714+ } else if (mimeType.search("audio/") === 0) {
1715+ return ContentType.Music;
1716+ } else if (mimeType.search("video/") === 0) {
1717+ return ContentType.Videos;
1718+ } else if (mimeType.search("text/x-vcard") === 0
1719+ || mimeType.search("text/vcard") === 0) {
1720+ return ContentType.Contacts;
1721+ } else if (mimeType.search("application/epub[+]zip") === 0
1722+ || mimeType.search("application/vnd\.amazon\.ebook") === 0
1723+ || mimeType.search("application/x-mobipocket-ebook") === 0
1724+ || mimeType.search("application/x-fictionbook+xml") === 0
1725+ || mimeType.search("application/x-ms-reader") === 0) {
1726+ return ContentType.EBooks;
1727+ } else if (mimeType.search("text/") === 0
1728+ || mimeType.search("application/pdf") === 0
1729+ || mimeType.search("application/x-pdf") === 0
1730+ || mimeType.search("application/vnd\.pdf") === 0
1731+ || mimeType.search("application/vnd\.oasis\.opendocument") === 0
1732+ || mimeType.search("application/msword") === 0
1733+ || mimeType.search("application/vnd\.openxmlformats-officedocument\.wordprocessingml\.document") === 0
1734+ || mimeType.search("application/vnd\.openxmlformats-officedocument\.spreadsheetml\.sheet") === 0
1735+ || mimeType.search("application/vnd\.openxmlformats-officedocument\.presentationml\.presentation") === 0
1736+ || mimeType.search("application/vnd\.ms-excel") === 0
1737+ || mimeType.search("application/vnd\.ms-powerpoint") === 0) {
1738+ return ContentType.Documents;
1739+ } else {
1740+ return ContentType.Unknown;
1741+ }
1742+ }
1743+
1744+ Component.onCompleted: {
1745+ var contentType = ContentType.All
1746+ if (picker.acceptTypes.length === 1 && picker.acceptTypes[0].length != 0) {
1747+ contentType = mimeTypeToContentType(acceptTypes[0])
1748+ if (contentType == ContentType.Unknown) {
1749+ contentType = ContentType.All;
1750+ }
1751+ }
1752+ peerPicker.contentType = contentType;
1753+ }
1754+}
1755diff --git a/qt/uitk/lib/resources/FilePickerDialog.qml b/qt/uitk/lib/resources/FilePickerDialog.qml
1756new file mode 100644
1757index 0000000..7d780dc
1758--- /dev/null
1759+++ b/qt/uitk/lib/resources/FilePickerDialog.qml
1760@@ -0,0 +1,63 @@
1761+// vim:expandtab:shiftwidth=2:tabstop=2:
1762+// Copyright (C) 2017 Canonical Ltd.
1763+
1764+// This library is free software; you can redistribute it and/or
1765+// modify it under the terms of the GNU Lesser General Public
1766+// License as published by the Free Software Foundation; either
1767+// version 2.1 of the License, or (at your option) any later version.
1768+
1769+// This library is distributed in the hope that it will be useful,
1770+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1771+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1772+// Lesser General Public License for more details.
1773+
1774+// You should have received a copy of the GNU Lesser General Public
1775+// License along with this library; if not, write to the Free Software
1776+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1777+
1778+import QtQuick 2.4
1779+import QtQuick.Dialogs 1.2
1780+
1781+FileDialog {
1782+ id: filePicker
1783+
1784+ property bool allowMultiple
1785+ property bool directory
1786+ property string defaultFileName
1787+ property var acceptTypes
1788+
1789+ signal accept(var files)
1790+
1791+ function show() {
1792+ filePicker.open();
1793+ }
1794+
1795+ function hide() {
1796+ filePicker.close();
1797+ }
1798+
1799+ selectExisting: true
1800+ selectFolder: directory
1801+ selectMultiple: allowMultiple && !directory
1802+ folder: defaultFileName
1803+ // TODO: Find correct mapping from mimetypes to namefilter.
1804+ // nameFilters does filtering of file based on file extension and
1805+ // no clear mapping available from mimetypes to file extension, so allow
1806+ // all files to avoid any inconsistency as of now.
1807+ nameFilters: ["All files (*)"]
1808+
1809+ sidebarVisible: true
1810+
1811+ onAccepted : {
1812+ var selectedFiles = [];
1813+ for (var i = 0; i < filePicker.fileUrls.length; ++i) {
1814+ selectedFiles.push(filePicker.fileUrls[i].replace("file://", ""));
1815+ }
1816+ filePicker.accept(selectedFiles);
1817+ }
1818+
1819+ onRejected: {
1820+ filePicker.accept([]);
1821+ }
1822+
1823+}
1824diff --git a/qt/uitk/lib/uitk_auxiliary_ui_factory.cc b/qt/uitk/lib/uitk_auxiliary_ui_factory.cc
1825index e6f64fb..7483f28 100644
1826--- a/qt/uitk/lib/uitk_auxiliary_ui_factory.cc
1827+++ b/qt/uitk/lib/uitk_auxiliary_ui_factory.cc
1828@@ -36,6 +36,7 @@
1829 #include "qt/uitk/lib/api/oxideubuntuwebcontextmenuitem_p.h"
1830
1831 #include "uitk_before_unload_dialog.h"
1832+#include "uitk_file_picker.h"
1833 #include "uitk_javascript_dialog.h"
1834 #include "uitk_touch_editing_menu.h"
1835 #include "uitk_web_context_menu.h"
1836@@ -257,6 +258,16 @@ AuxiliaryUIFactory::CreateBeforeUnloadDialog(
1837 return BeforeUnloadDialog::Create(item_, client);
1838 }
1839
1840+std::unique_ptr<qt::FilePicker> AuxiliaryUIFactory::CreateFilePicker(
1841+ qt::FilePicker::Mode mode,
1842+ const QString& title,
1843+ const QFileInfo& default_file,
1844+ const QStringList& accept_types,
1845+ qt::FilePickerClient* client) {
1846+ return FilePicker::Create(item_, mode, title, default_file, accept_types,
1847+ client);
1848+}
1849+
1850 AuxiliaryUIFactory::AuxiliaryUIFactory(QQuickItem* item, Delegate* delegate)
1851 : item_(item),
1852 delegate_(delegate) {
1853diff --git a/qt/uitk/lib/uitk_auxiliary_ui_factory.h b/qt/uitk/lib/uitk_auxiliary_ui_factory.h
1854index 3d169e4..6be5856 100644
1855--- a/qt/uitk/lib/uitk_auxiliary_ui_factory.h
1856+++ b/qt/uitk/lib/uitk_auxiliary_ui_factory.h
1857@@ -68,6 +68,12 @@ class AuxiliaryUIFactory : public qt::AuxiliaryUIFactory {
1858 std::unique_ptr<qt::JavaScriptDialog> CreateBeforeUnloadDialog(
1859 const QUrl& origin_url,
1860 qt::JavaScriptDialogClient* client) override;
1861+ std::unique_ptr<qt::FilePicker> CreateFilePicker(
1862+ qt::FilePicker::Mode mode,
1863+ const QString& title,
1864+ const QFileInfo& defaultFileName,
1865+ const QStringList& acceptTypes,
1866+ qt::FilePickerClient* client) override;
1867
1868 QQuickItem* item_;
1869
1870diff --git a/qt/uitk/lib/uitk_file_picker.cc b/qt/uitk/lib/uitk_file_picker.cc
1871new file mode 100644
1872index 0000000..ef2caa1
1873--- /dev/null
1874+++ b/qt/uitk/lib/uitk_file_picker.cc
1875@@ -0,0 +1,150 @@
1876+// vim:expandtab:shiftwidth=2:tabstop=2:
1877+// Copyright (C) 2017 Canonical Ltd.
1878+
1879+// This library is free software; you can redistribute it and/or
1880+// modify it under the terms of the GNU Lesser General Public
1881+// License as published by the Free Software Foundation; either
1882+// version 2.1 of the License, or (at your option) any later version.
1883+
1884+// This library is distributed in the hope that it will be useful,
1885+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1886+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1887+// Lesser General Public License for more details.
1888+
1889+// You should have received a copy of the GNU Lesser General Public
1890+// License along with this library; if not, write to the Free Software
1891+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1892+
1893+#include "uitk_file_picker.h"
1894+
1895+#include <QDebug>
1896+#include <QLatin1String>
1897+#include <QObject>
1898+#include <QQmlComponent>
1899+#include <QQmlContext>
1900+#include <QQmlEngine>
1901+#include <QQuickItem>
1902+#include <QString>
1903+#include <QStringList>
1904+
1905+#include "qt/core/glue/file_picker_client.h"
1906+
1907+namespace oxide {
1908+
1909+namespace uitk {
1910+
1911+FilePicker::FilePicker(qt::FilePickerClient* client, qt::FilePicker::Mode mode)
1912+ : client_(client), mode_(mode) {}
1913+
1914+FilePicker::~FilePicker() = default;
1915+
1916+std::unique_ptr<FilePicker> FilePicker::Create(QQuickItem* parent,
1917+ qt::FilePicker::Mode mode,
1918+ const QString& title,
1919+ const QFileInfo& default_file,
1920+ const QStringList& accept_types,
1921+ qt::FilePickerClient* client) {
1922+ Q_ASSERT(parent);
1923+ std::unique_ptr<FilePicker> picker(new FilePicker(client, mode));
1924+ if (!picker->Init(parent, mode, title, default_file, accept_types)) {
1925+ return nullptr;
1926+ }
1927+ return picker;
1928+}
1929+
1930+bool FilePicker::Init(QQuickItem* parent,
1931+ qt::FilePicker::Mode mode,
1932+ const QString& title,
1933+ const QFileInfo& default_file,
1934+ const QStringList& accept_types) {
1935+ QQmlEngine* engine = qmlEngine(parent);
1936+ if (!engine) {
1937+ qWarning() << "uitk::FilePicker: Failed to show filepicker - "
1938+ "cannot determine qml engine for parent item";
1939+ return false;
1940+ }
1941+
1942+ bool fallback = false;
1943+ std::unique_ptr<QQmlComponent> component(new QQmlComponent(engine));
1944+ component->loadUrl(QUrl("qrc:///FilePickerContentHub.qml"),
1945+ QQmlComponent::PreferSynchronous);
1946+ if (component->isError()) {
1947+ qDebug() << "uitk::FilePicker: content hub filepicker failed so fallback "
1948+ "to Quick FileDialog";
1949+ component.reset(new QQmlComponent(engine));
1950+ component->loadUrl(QUrl("qrc:///FilePickerDialog.qml"));
1951+ fallback = true;
1952+ }
1953+
1954+ if (component->isError()) {
1955+ qCritical()
1956+ << "uitk::FilePicker: Failed to Initialize filepicker component "
1957+ "because of following error";
1958+ for (const auto& error : component->errors()) {
1959+ qCritical() << error.description();
1960+ }
1961+ return false;
1962+ }
1963+
1964+ Q_ASSERT(component->isReady());
1965+
1966+ QObject* picker = component->beginCreate(engine->rootContext());
1967+
1968+ if (!picker) {
1969+ qCritical() << "uitk::FilePicker: Failed to create File picker instance";
1970+ return false;
1971+ }
1972+
1973+ item_.reset(picker);
1974+
1975+ // Default filepicker based on content hub is QuickItem but fallback file
1976+ // picker may not be QQuickItem, depending upon how QFileDialog is implemented
1977+ // internally
1978+ if (!fallback) {
1979+ QQuickItem* quick_item = qobject_cast<QQuickItem*>(picker);
1980+ if (!quick_item) {
1981+ qCritical()
1982+ << "uitk::FilePicker: File Picker instance is not a QQuickItem";
1983+ return false;
1984+ }
1985+ quick_item->setParentItem(parent);
1986+ }
1987+
1988+ bool multiple = mode == qt::FilePicker::OpenMultiple;
1989+ bool directory = mode == qt::FilePicker::UploadFolder;
1990+ item_->setProperty("allowMultiple", multiple);
1991+ item_->setProperty("directory", directory);
1992+ item_->setProperty("title", title);
1993+ item_->setProperty("defaultFileName", default_file.absoluteFilePath());
1994+ item_->setProperty("acceptTypes", accept_types);
1995+
1996+ component->completeCreate();
1997+
1998+ connect(item_.get(), SIGNAL(accept(const QVariant&)), this,
1999+ SLOT(OnAccept(const QVariant&)));
2000+
2001+ return true;
2002+}
2003+
2004+void FilePicker::OnAccept(const QVariant& files) const {
2005+ QFileInfoList info;
2006+ for (const QString& file : files.toStringList()) {
2007+ if (QFileInfo::exists(file)) {
2008+ info.append(QFileInfo(file));
2009+ }
2010+ }
2011+ client_->done(info, mode_);
2012+}
2013+
2014+void FilePicker::Hide() {
2015+ QMetaObject::invokeMethod(item_.get(), "hide");
2016+}
2017+
2018+void FilePicker::Show() {
2019+ QMetaObject::invokeMethod(item_.get(), "show");
2020+}
2021+
2022+} // uitk
2023+} // oxide
2024+
2025+#include "uitk_file_picker.moc"
2026diff --git a/qt/uitk/lib/uitk_file_picker.h b/qt/uitk/lib/uitk_file_picker.h
2027new file mode 100644
2028index 0000000..c30526c
2029--- /dev/null
2030+++ b/qt/uitk/lib/uitk_file_picker.h
2031@@ -0,0 +1,80 @@
2032+// vim:expandtab:shiftwidth=2:tabstop=2:
2033+// Copyright (C) 2017 Canonical Ltd.
2034+
2035+// This library is free software; you can redistribute it and/or
2036+// modify it under the terms of the GNU Lesser General Public
2037+// License as published by the Free Software Foundation; either
2038+// version 2.1 of the License, or (at your option) any later version.
2039+
2040+// This library is distributed in the hope that it will be useful,
2041+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2042+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2043+// Lesser General Public License for more details.
2044+
2045+// You should have received a copy of the GNU Lesser General Public
2046+// License along with this library; if not, write to the Free Software
2047+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2048+
2049+#ifndef _OXIDE_QT_UITK_LIB_FILE_PICKER_H_
2050+#define _OXIDE_QT_UITK_LIB_FILE_PICKER_H_
2051+
2052+#include <memory>
2053+#include <QObject>
2054+
2055+#include "qt/core/glue/file_picker.h"
2056+
2057+QT_BEGIN_NAMESPACE
2058+class QFileInfo;
2059+class QQuickItem;
2060+class QString;
2061+class QStringList;
2062+QT_END_NAMESPACE
2063+
2064+namespace oxide {
2065+
2066+namespace qt {
2067+class FilePickerClient;
2068+}
2069+
2070+namespace uitk {
2071+
2072+class FilePicker : public QObject, public qt::FilePicker {
2073+ Q_OBJECT
2074+
2075+ public:
2076+ static std::unique_ptr<FilePicker> Create(QQuickItem* item,
2077+ qt::FilePicker::Mode mode,
2078+ const QString& title,
2079+ const QFileInfo& default_file,
2080+ const QStringList& accept_types,
2081+ qt::FilePickerClient* client);
2082+
2083+ ~FilePicker() override;
2084+
2085+ private Q_SLOTS:
2086+ void OnAccept(const QVariant& files) const;
2087+
2088+ private:
2089+ FilePicker(qt::FilePickerClient* client, qt::FilePicker::Mode mode);
2090+
2091+ bool Init(QQuickItem* item,
2092+ qt::FilePicker::Mode mode,
2093+ const QString& title,
2094+ const QFileInfo& default_file,
2095+ const QStringList& accept_types);
2096+
2097+ // oxide::qt::FilePicker implementation
2098+ void Show() override;
2099+ void Hide() override;
2100+
2101+ qt::FilePicker::Mode mode_;
2102+ qt::FilePickerClient* client_;
2103+ std::unique_ptr<QObject> item_;
2104+
2105+ Q_DISABLE_COPY(FilePicker)
2106+};
2107+
2108+} // uitk
2109+} // oxide
2110+
2111+#endif // _OXIDE_QT_UITK_LIB_FILE_PICKER_H_
2112diff --git a/shared/BUILD.gn b/shared/BUILD.gn
2113index 77eaeca..55eabf6 100644
2114--- a/shared/BUILD.gn
2115+++ b/shared/BUILD.gn
2116@@ -299,6 +299,10 @@ component("shared") {
2117 "browser/device/power_save_blocker.h",
2118 "browser/device/power_save_blocker_linux.cc",
2119 "browser/display_form_factor.h",
2120+ "browser/file_picker_host.cc",
2121+ "browser/file_picker_host.h",
2122+ "browser/file_picker.h",
2123+ "browser/file_picker_client.h",
2124 "browser/input/input_method_context.h",
2125 "browser/input/input_method_context_client.cc",
2126 "browser/input/input_method_context_client.h",
2127@@ -361,8 +365,6 @@ component("shared") {
2128 "browser/oxide_event_utils.h",
2129 "browser/oxide_favicon_helper.cc",
2130 "browser/oxide_favicon_helper.h",
2131- "browser/oxide_file_picker.cc",
2132- "browser/oxide_file_picker.h",
2133 "browser/oxide_find_controller.cc",
2134 "browser/oxide_find_controller.h",
2135 "browser/oxide_find_controller_client.h",
2136diff --git a/shared/browser/file_picker.h b/shared/browser/file_picker.h
2137new file mode 100644
2138index 0000000..d0db237
2139--- /dev/null
2140+++ b/shared/browser/file_picker.h
2141@@ -0,0 +1,37 @@
2142+// vim:expandtab:shiftwidth=2:tabstop=2:
2143+// Copyright (C) 2013-2016 Canonical Ltd.
2144+
2145+// This library is free software; you can redistribute it and/or
2146+// modify it under the terms of the GNU Lesser General Public
2147+// License as published by the Free Software Foundation; either
2148+// version 2.1 of the License, or (at your option) any later version.
2149+
2150+// This library is distributed in the hope that it will be useful,
2151+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2152+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2153+// Lesser General Public License for more details.
2154+
2155+// You should have received a copy of the GNU Lesser General Public
2156+// License along with this library; if not, write to the Free Software
2157+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2158+
2159+#ifndef _OXIDE_SHARED_BROWSER_FILE_PICKER_H_
2160+#define _OXIDE_SHARED_BROWSER_FILE_PICKER_H_
2161+
2162+namespace content {
2163+class FileChooserParams;
2164+}
2165+
2166+namespace oxide {
2167+
2168+class FilePicker {
2169+ public:
2170+ virtual ~FilePicker() = default;
2171+
2172+ virtual void Run() = 0;
2173+ virtual void Hide() = 0;
2174+};
2175+
2176+} // oxide
2177+
2178+#endif // _OXIDE_SHARED_BROWSER_FILE_PICKER_H_
2179diff --git a/shared/browser/file_picker_client.h b/shared/browser/file_picker_client.h
2180new file mode 100644
2181index 0000000..f99de98
2182--- /dev/null
2183+++ b/shared/browser/file_picker_client.h
2184@@ -0,0 +1,39 @@
2185+// vim:expandtab:shiftwidth=2:tabstop=2:
2186+// Copyright (C) 2013-2016 Canonical Ltd.
2187+
2188+// This library is free software; you can redistribute it and/or
2189+// modify it under the terms of the GNU Lesser General Public
2190+// License as published by the Free Software Foundation; either
2191+// version 2.1 of the License, or (at your option) any later version.
2192+
2193+// This library is distributed in the hope that it will be useful,
2194+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2195+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2196+// Lesser General Public License for more details.
2197+
2198+// You should have received a copy of the GNU Lesser General Public
2199+// License along with this library; if not, write to the Free Software
2200+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2201+
2202+#ifndef _OXIDE_SHARED_BROWSER_FILE_PICKER_CLIENT_H_
2203+#define _OXIDE_SHARED_BROWSER_FILE_PICKER_CLIENT_H_
2204+
2205+#include <vector>
2206+
2207+namespace content {
2208+struct FileChooserFileInfo;
2209+struct FileChooserParams;
2210+}
2211+
2212+namespace oxide {
2213+
2214+class FilePickerClient {
2215+ public:
2216+ virtual ~FilePickerClient() = default;
2217+ virtual void Done(const std::vector<content::FileChooserFileInfo>& files,
2218+ content::FileChooserParams::Mode permissions) = 0;
2219+};
2220+
2221+} // oxide
2222+
2223+#endif // _OXIDE_SHARED_BROWSER_FILE_PICKER_CLIENT_H_
2224diff --git a/shared/browser/file_picker_host.cc b/shared/browser/file_picker_host.cc
2225new file mode 100644
2226index 0000000..1699d82
2227--- /dev/null
2228+++ b/shared/browser/file_picker_host.cc
2229@@ -0,0 +1,92 @@
2230+// vim:expandtab:shiftwidth=2:tabstop=2:
2231+// Copyright (C) 2014-2015 Canonical Ltd.
2232+
2233+// This library is free software; you can redistribute it and/or
2234+// modify it under the terms of the GNU Lesser General Public
2235+// License as published by the Free Software Foundation; either
2236+// version 2.1 of the License, or (at your option) any later version.
2237+
2238+// This library is distributed in the hope that it will be useful,
2239+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2240+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2241+// Lesser General Public License for more details.
2242+
2243+// You should have received a copy of the GNU Lesser General Public
2244+// License along with this library; if not, write to the Free Software
2245+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2246+
2247+#include "file_picker_host.h"
2248+
2249+#include "content/public/browser/browser_thread.h"
2250+#include "content/public/browser/render_frame_host.h"
2251+#include "content/public/browser/web_contents.h"
2252+#include "content/public/common/file_chooser_file_info.h"
2253+
2254+#include "oxide/shared/browser/file_picker.h"
2255+#include "oxide/shared/browser/web_contents_client.h"
2256+#include "shared/browser/web_contents_helper.h"
2257+
2258+namespace oxide {
2259+
2260+FilePickerHost::FilePickerHost(content::RenderFrameHost* rfh,
2261+ const content::FileChooserParams& params,
2262+ const base::Closure& on_close_cb)
2263+ : content::WebContentsObserver(
2264+ content::WebContents::FromRenderFrameHost(rfh)),
2265+ render_frame_host_(rfh),
2266+ params_(params),
2267+ on_close_cb_(on_close_cb) {
2268+ DCHECK(web_contents());
2269+
2270+ WebContentsHelper* helper =
2271+ WebContentsHelper::FromWebContents(web_contents());
2272+ if (!helper->client()) {
2273+ return;
2274+ }
2275+
2276+ file_picker_ = helper->client()->CreateFilePicker(params_, this);
2277+}
2278+
2279+FilePickerHost::~FilePickerHost() = default;
2280+
2281+void FilePickerHost::Close() {
2282+ if (on_close_cb_.is_null()) {
2283+ return;
2284+ }
2285+
2286+ base::Closure on_close_callback = std::move(on_close_cb_);
2287+
2288+ if (file_picker_) {
2289+ file_picker_->Hide();
2290+ }
2291+ on_close_callback.Run();
2292+}
2293+
2294+void FilePickerHost::RenderFrameDeleted(content::RenderFrameHost* rfh) {
2295+ if (rfh != render_frame_host_) {
2296+ return;
2297+ }
2298+ render_frame_host_ = nullptr;
2299+
2300+ if (file_picker_) {
2301+ file_picker_->Hide();
2302+ }
2303+}
2304+
2305+void FilePickerHost::Done(
2306+ const std::vector<content::FileChooserFileInfo>& files,
2307+ content::FileChooserParams::Mode permissions) {
2308+ render_frame_host_->FilesSelectedInChooser(files, permissions);
2309+ render_frame_host_ = nullptr;
2310+ Close();
2311+}
2312+
2313+void FilePickerHost::Run() {
2314+ if (!file_picker_) {
2315+ return;
2316+ }
2317+
2318+ file_picker_->Run();
2319+}
2320+
2321+} // namespace oxide
2322diff --git a/shared/browser/file_picker_host.h b/shared/browser/file_picker_host.h
2323new file mode 100644
2324index 0000000..9ac304f
2325--- /dev/null
2326+++ b/shared/browser/file_picker_host.h
2327@@ -0,0 +1,69 @@
2328+// vim:expandtab:shiftwidth=2:tabstop=2:
2329+// Copyright (C) 2017 Canonical Ltd.
2330+
2331+// This library is free software; you can redistribute it and/or
2332+// modify it under the terms of the GNU Lesser General Public
2333+// License as published by the Free Software Foundation; either
2334+// version 2.1 of the License, or (at your option) any later version.
2335+
2336+// This library is distributed in the hope that it will be useful,
2337+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2338+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2339+// Lesser General Public License for more details.
2340+
2341+// You should have received a copy of the GNU Lesser General Public
2342+// License along with this library; if not, write to the Free Software
2343+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2344+
2345+#ifndef _OXIDE_SHARED_BROWSER_FILE_PICKER_HOST_H_
2346+#define _OXIDE_SHARED_BROWSER_FILE_PICKER_HOST_H_
2347+
2348+#include <memory>
2349+#include <vector>
2350+
2351+#include "base/callback.h"
2352+#include "base/macros.h"
2353+#include "content/public/browser/web_contents_observer.h"
2354+#include "content/public/common/file_chooser_params.h"
2355+
2356+#include "shared/browser/file_picker_client.h"
2357+
2358+namespace content {
2359+class RenderFrameHost;
2360+}
2361+
2362+namespace oxide {
2363+class FilePicker;
2364+
2365+class FilePickerHost : public FilePickerClient,
2366+ public content::WebContentsObserver {
2367+ public:
2368+ FilePickerHost(content::RenderFrameHost* rfh,
2369+ const content::FileChooserParams& params,
2370+ const base::Closure& on_close_cb);
2371+ ~FilePickerHost() override;
2372+
2373+ void Run();
2374+
2375+ private:
2376+ void Close();
2377+
2378+ // oxide::FilePickerClient Implemntation
2379+ void Done(const std::vector<content::FileChooserFileInfo>& files,
2380+ content::FileChooserParams::Mode permissions) override;
2381+
2382+ // content::WebContentsObserver implementation
2383+ void RenderFrameDeleted(content::RenderFrameHost* rfh) override;
2384+
2385+ content::RenderFrameHost* render_frame_host_;
2386+ content::FileChooserParams params_;
2387+ base::Closure on_close_cb_;
2388+
2389+ std::unique_ptr<FilePicker> file_picker_;
2390+
2391+ DISALLOW_COPY_AND_ASSIGN(FilePickerHost);
2392+};
2393+
2394+} // namespace oxide
2395+
2396+#endif // _OXIDE_SHARED_BROWSER_FILE_PICKER_HOST_H_
2397diff --git a/shared/browser/oxide_file_picker.cc b/shared/browser/oxide_file_picker.cc
2398deleted file mode 100644
2399index 1bb4d77..0000000
2400--- a/shared/browser/oxide_file_picker.cc
2401+++ /dev/null
2402@@ -1,57 +0,0 @@
2403-// vim:expandtab:shiftwidth=2:tabstop=2:
2404-// Copyright (C) 2014-2015 Canonical Ltd.
2405-
2406-// This library is free software; you can redistribute it and/or
2407-// modify it under the terms of the GNU Lesser General Public
2408-// License as published by the Free Software Foundation; either
2409-// version 2.1 of the License, or (at your option) any later version.
2410-
2411-// This library is distributed in the hope that it will be useful,
2412-// but WITHOUT ANY WARRANTY; without even the implied warranty of
2413-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2414-// Lesser General Public License for more details.
2415-
2416-// You should have received a copy of the GNU Lesser General Public
2417-// License along with this library; if not, write to the Free Software
2418-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2419-
2420-#include "oxide_file_picker.h"
2421-
2422-#include "base/logging.h"
2423-#include "content/public/browser/browser_thread.h"
2424-#include "content/public/browser/render_frame_host.h"
2425-#include "content/public/browser/web_contents.h"
2426-#include "content/public/common/file_chooser_file_info.h"
2427-
2428-namespace oxide {
2429-
2430-FilePicker::FilePicker(content::RenderFrameHost* rfh)
2431- : content::WebContentsObserver(content::WebContents::FromRenderFrameHost(rfh)),
2432- render_frame_host_(rfh) {}
2433-
2434-FilePicker::~FilePicker() {
2435- DCHECK(!render_frame_host_);
2436-}
2437-
2438-void FilePicker::RenderFrameDeleted(content::RenderFrameHost* rfh) {
2439- if (rfh != render_frame_host_) {
2440- return;
2441- }
2442- render_frame_host_ = nullptr;
2443- Hide();
2444- content::BrowserThread::DeleteSoon(
2445- content::BrowserThread::UI, FROM_HERE, this);
2446-}
2447-
2448-void FilePicker::Hide() {}
2449-
2450-void FilePicker::Done(const std::vector<content::FileChooserFileInfo>& files,
2451- content::FileChooserParams::Mode permissions) {
2452- render_frame_host_->FilesSelectedInChooser(files, permissions);
2453- render_frame_host_ = nullptr;
2454- Hide();
2455- content::BrowserThread::DeleteSoon(
2456- content::BrowserThread::UI, FROM_HERE, this);
2457-}
2458-
2459-} // namespace oxide
2460diff --git a/shared/browser/oxide_file_picker.h b/shared/browser/oxide_file_picker.h
2461deleted file mode 100644
2462index b0136c6..0000000
2463--- a/shared/browser/oxide_file_picker.h
2464+++ /dev/null
2465@@ -1,67 +0,0 @@
2466-// vim:expandtab:shiftwidth=2:tabstop=2:
2467-// Copyright (C) 2014 Canonical Ltd.
2468-
2469-// This library is free software; you can redistribute it and/or
2470-// modify it under the terms of the GNU Lesser General Public
2471-// License as published by the Free Software Foundation; either
2472-// version 2.1 of the License, or (at your option) any later version.
2473-
2474-// This library is distributed in the hope that it will be useful,
2475-// but WITHOUT ANY WARRANTY; without even the implied warranty of
2476-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2477-// Lesser General Public License for more details.
2478-
2479-// You should have received a copy of the GNU Lesser General Public
2480-// License along with this library; if not, write to the Free Software
2481-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2482-
2483-#ifndef _OXIDE_SHARED_BROWSER_FILE_PICKER_H_
2484-#define _OXIDE_SHARED_BROWSER_FILE_PICKER_H_
2485-
2486-#include <vector>
2487-
2488-#include "base/macros.h"
2489-#include "content/public/browser/web_contents_observer.h"
2490-#include "content/public/common/file_chooser_params.h"
2491-
2492-#include "shared/common/oxide_shared_export.h"
2493-
2494-namespace base {
2495-template <typename T> class DeleteHelper;
2496-}
2497-
2498-namespace content {
2499-class RenderFrameHost;
2500-struct FileChooserFileInfo;
2501-struct FileChooserParams;
2502-}
2503-
2504-namespace oxide {
2505-
2506-class OXIDE_SHARED_EXPORT FilePicker : public content::WebContentsObserver {
2507- public:
2508- virtual void Run(const content::FileChooserParams& params) = 0;
2509-
2510- void Done(const std::vector<content::FileChooserFileInfo>& files,
2511- content::FileChooserParams::Mode permissions);
2512-
2513- protected:
2514- friend class base::DeleteHelper<FilePicker>;
2515-
2516- FilePicker(content::RenderFrameHost* rfh);
2517- virtual ~FilePicker();
2518-
2519- private:
2520- virtual void Hide();
2521-
2522- // content::WebContentsObserver implementation
2523- void RenderFrameDeleted(content::RenderFrameHost* rfh) override;
2524-
2525- content::RenderFrameHost* render_frame_host_;
2526-
2527- DISALLOW_COPY_AND_ASSIGN(FilePicker);
2528-};
2529-
2530-} // namespace oxide
2531-
2532-#endif // _OXIDE_SHARED_BROWSER_FILE_PICKER_H_
2533diff --git a/shared/browser/oxide_web_view.cc b/shared/browser/oxide_web_view.cc
2534index ac0dbaa..457f83a 100644
2535--- a/shared/browser/oxide_web_view.cc
2536+++ b/shared/browser/oxide_web_view.cc
2537@@ -80,7 +80,7 @@
2538 #include "oxide_content_browser_client.h"
2539 #include "oxide_event_utils.h"
2540 #include "oxide_favicon_helper.h"
2541-#include "oxide_file_picker.h"
2542+#include "file_picker_host.h"
2543 #include "oxide_find_controller.h"
2544 #include "oxide_fullscreen_helper.h"
2545 #include "oxide_render_widget_host_view.h"
2546@@ -611,14 +611,18 @@ content::JavaScriptDialogManager* WebView::GetJavaScriptDialogManager(
2547
2548 void WebView::RunFileChooser(content::RenderFrameHost* render_frame_host,
2549 const content::FileChooserParams& params) {
2550- FilePicker* file_picker = client_->CreateFilePicker(render_frame_host);
2551- if (!file_picker) {
2552- std::vector<content::FileChooserFileInfo> empty;
2553- render_frame_host->FilesSelectedInChooser(empty, params.mode);
2554- return;
2555- }
2556+ active_file_picker_ = base::MakeUnique<FilePickerHost>(
2557+ render_frame_host, params,
2558+ base::Bind(&WebView::DidCloseFileChooser, base::Unretained(this)));
2559+
2560+ active_file_picker_->Run();
2561+}
2562+
2563+void WebView::DidCloseFileChooser() {
2564+ DCHECK(active_file_picker_);
2565
2566- file_picker->Run(params);
2567+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
2568+ FROM_HERE, active_file_picker_.release());
2569 }
2570
2571 bool WebView::EmbedsFullscreenWidget() const {
2572diff --git a/shared/browser/oxide_web_view.h b/shared/browser/oxide_web_view.h
2573index 6d37384..8b78226 100644
2574--- a/shared/browser/oxide_web_view.h
2575+++ b/shared/browser/oxide_web_view.h
2576@@ -63,7 +63,7 @@ namespace oxide {
2577
2578 class BrowserContext;
2579 class CompositorFrameData;
2580-class FilePicker;
2581+class FilePickerHost;
2582 class JavaScriptDialogFactory;
2583 class RenderWidgetHostView;
2584 class WebContentsClient;
2585@@ -207,6 +207,8 @@ class OXIDE_SHARED_EXPORT WebView : public ScriptMessageTarget,
2586 const cc::CompositorFrameMetadata& metadata);
2587 void EditingCapabilitiesChanged();
2588
2589+ void DidCloseFileChooser();
2590+
2591 // ScriptMessageTarget implementation
2592 virtual size_t GetScriptMessageHandlerCount() const override;
2593 virtual const ScriptMessageHandler* GetScriptMessageHandlerAt(
2594@@ -328,7 +330,7 @@ class OXIDE_SHARED_EXPORT WebView : public ScriptMessageTarget,
2595
2596 WebContentsUniquePtr web_contents_;
2597
2598- base::WeakPtr<FilePicker> active_file_picker_;
2599+ std::unique_ptr<FilePickerHost> active_file_picker_;
2600
2601 ContentType blocked_content_;
2602
2603diff --git a/shared/browser/oxide_web_view_client.cc b/shared/browser/oxide_web_view_client.cc
2604index 50aeb59..8d67986 100644
2605--- a/shared/browser/oxide_web_view_client.cc
2606+++ b/shared/browser/oxide_web_view_client.cc
2607@@ -17,6 +17,7 @@
2608
2609 #include "oxide_web_view_client.h"
2610
2611+
2612 namespace oxide {
2613
2614 WebViewClient::~WebViewClient() {}
2615@@ -61,10 +62,6 @@ bool WebViewClient::AddMessageToConsole(int32_t level,
2616 void WebViewClient::FrameMetadataUpdated(
2617 const cc::CompositorFrameMetadata& old) {}
2618
2619-FilePicker* WebViewClient::CreateFilePicker(content::RenderFrameHost* rfh) {
2620- return nullptr;
2621-}
2622-
2623 void WebViewClient::ContentBlocked() {}
2624
2625 void WebViewClient::PrepareToCloseResponseReceived(bool proceed) {}
2626diff --git a/shared/browser/oxide_web_view_client.h b/shared/browser/oxide_web_view_client.h
2627index c27641e..83c0728 100644
2628--- a/shared/browser/oxide_web_view_client.h
2629+++ b/shared/browser/oxide_web_view_client.h
2630@@ -35,14 +35,12 @@ class CompositorFrameMetadata;
2631
2632 namespace content {
2633 struct ContextMenuParams;
2634-class RenderFrameHost;
2635 class WebContents;
2636 }
2637
2638 namespace oxide {
2639
2640 class CertificateError;
2641-class FilePicker;
2642 class WebView;
2643
2644 // A class for customizing the behaviour of WebView
2645@@ -90,9 +88,6 @@ class OXIDE_SHARED_EXPORT WebViewClient : public ScriptMessageTarget {
2646 // TODO(chrisccoulson): Get rid of |old| and replace with |changed_flags|
2647 virtual void FrameMetadataUpdated(const cc::CompositorFrameMetadata& old);
2648
2649- // XXX(chrisccoulson): WebView currently just proxies straight to this -
2650- // should this get its own interface?
2651- virtual FilePicker* CreateFilePicker(content::RenderFrameHost* rfh);
2652
2653 // TODO(chrisccoulson): Rename to BlockedContentChanged or something
2654 // TODO(chrisccoulson): Move content tracking to a separate class with its
2655diff --git a/shared/browser/web_contents_client.cc b/shared/browser/web_contents_client.cc
2656index ccc9ae4..de8a840 100644
2657--- a/shared/browser/web_contents_client.cc
2658+++ b/shared/browser/web_contents_client.cc
2659@@ -22,6 +22,7 @@
2660 #include "shared/browser/touch_selection/touch_editing_menu_controller.h"
2661
2662 #include "web_contents_helper.h"
2663+#include "shared/browser/file_picker.h"
2664
2665 namespace oxide {
2666
2667@@ -90,4 +91,10 @@ std::unique_ptr<TouchEditingMenu> WebContentsClient::CreateTouchEditingMenu(
2668 return nullptr;
2669 }
2670
2671+std::unique_ptr<FilePicker> WebContentsClient::CreateFilePicker(
2672+ const content::FileChooserParams& params,
2673+ FilePickerClient* client) {
2674+ return nullptr;
2675+}
2676+
2677 } // namespace oxide
2678diff --git a/shared/browser/web_contents_client.h b/shared/browser/web_contents_client.h
2679index a303858..b6c674f 100644
2680--- a/shared/browser/web_contents_client.h
2681+++ b/shared/browser/web_contents_client.h
2682@@ -34,6 +34,7 @@ class GURL;
2683
2684 namespace content {
2685 struct ContextMenuParams;
2686+struct FileChooserParams;
2687 class WebContents;
2688 }
2689
2690@@ -43,6 +44,8 @@ class Rect;
2691
2692 namespace oxide {
2693
2694+class FilePicker;
2695+class FilePickerClient;
2696 class ResourceDispatcherHostLoginDelegate;
2697 class TouchEditingMenu;
2698 class TouchEditingMenuClient;
2699@@ -95,6 +98,10 @@ class OXIDE_SHARED_EXPORT WebContentsClient {
2700 virtual std::unique_ptr<TouchEditingMenu> CreateTouchEditingMenu(
2701 blink::WebContextMenuData::EditFlags edit_flags,
2702 TouchEditingMenuClient* client);
2703+
2704+ virtual std::unique_ptr<FilePicker> CreateFilePicker(
2705+ const content::FileChooserParams& params,
2706+ FilePickerClient* client);
2707 };
2708
2709 } // namespace oxide

Subscribers

People subscribed via source and target branches

to all changes: