Merge ~osomon/oxide:autofill-profiles-management into oxide:master

Proposed by Olivier Tilloy
Status: Needs review
Proposed branch: ~osomon/oxide:autofill-profiles-management
Merge into: oxide:master
Prerequisite: ~osomon/oxide:autofill
Diff against target: 1095 lines (+773/-7)
15 files modified
qt/core/browser/oxide_qt_web_context.cc (+144/-1)
qt/core/browser/oxide_qt_web_context.h (+13/-1)
qt/core/glue/oxide_qt_web_context_proxy.h (+8/-0)
qt/core/glue/oxide_qt_web_context_proxy_client.h (+3/-1)
qt/qmlplugin/oxide.qmltypes (+32/-0)
qt/qmlplugin/oxide_qml_plugin.cc (+4/-0)
qt/quick/CMakeLists.txt (+2/-1)
qt/quick/api/oxideqquickautofillprofiles.cc (+193/-0)
qt/quick/api/oxideqquickautofillprofiles.h (+68/-0)
qt/quick/api/oxideqquickautofillprofiles_p.h (+80/-0)
qt/quick/api/oxideqquickwebcontext.cc (+21/-2)
qt/quick/api/oxideqquickwebcontext.h (+4/-0)
qt/quick/api/oxideqquickwebcontext_p.h (+7/-1)
qt/tests/qmltests/api/tst_WebContext_autofillProfiles.qml (+141/-0)
qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml (+53/-0)
Reviewer Review Type Date Requested Status
Oxide Developers Pending
Review via email: mp+319257@code.launchpad.net

Commit message

New API on WebContext for autofill profiles management.

To post a comment you must log in.
2861ed9... by Olivier Tilloy

Ensure that the autofill profiles have been loaded before accessing them.

f4c0d6a... by Olivier Tilloy

Reduce the height of the autofill entries.

ef4fb16... by Olivier Tilloy

Preview autofill entry under mouse cursor.

f943678... by Olivier Tilloy

Highlight currently selected suggestion.

06c7bad... by Olivier Tilloy

Simplify focus handling.

818af21... by Olivier Tilloy

Fix FTBFS.

c60a7e8... by Olivier Tilloy

Handle validation when no suggestion is selected.

daa6b3b... by Olivier Tilloy

Add a unit test for autofill popup destruction.

5859240... by Olivier Tilloy

Ensure unit tests are locale-independent.

1c3531f... by Olivier Tilloy

Fix build errors when rebased on latest master.

67d903b... by Olivier Tilloy

Always use an InMemoryPrefStore.

Persisting the value of OxideQQuickWebContext::autofillEnabled would be
inconsistent with every other setting exposed by the API
(eg, we don't persist popupBlockerEnabled or doNotTrackEnabled).

a508ed9... by Olivier Tilloy

Move CreateAutofillPopup to WebContentsClient.

d9ff4e9... by Olivier Tilloy

Bump version for new WebContext API to 1.23.

bfac2c5... by Olivier Tilloy

Drop default case as there's already a branch for every value.

8d05925... by Olivier Tilloy

Do not modify oxide::ContentClient to access the application locale.

Instead, expose the application locale as a new method on BrowserPlatformIntegration.

d613e81... by Olivier Tilloy

Marked a private helper private.

e6dde29... by Olivier Tilloy

Ensure that autofill works in incognito mode, as expected.

559bd23... by Olivier Tilloy

Add tests for autofill in incognito webviews.

cb4b1d5... by Olivier Tilloy

Make WebAutofillPopupHost::Init not return anything, for consistency.

d4ec246... by Olivier Tilloy

Remove redundant std::move().

9b8a3c0... by Olivier Tilloy

Rename methods to start with an uppercase letter, for consistency with newly-written code.

7b47f20... by Olivier Tilloy

Take timeout into account.

75307e9... by Olivier Tilloy

Do not depend on the omnibox component in release builds.

f85f34f... by Olivier Tilloy

Rename files for consistency with newly-added code.

ea88035... by Olivier Tilloy

Remove unused references to gfx::NativeView (always null) in AutofillPopupController.

0c5a23f... by Olivier Tilloy

Remove unused method.

867131f... by Olivier Tilloy

Make ownership of AutofillPopupController explicit.

becd872... by Olivier Tilloy

Updated test.

3f0f3aa... by Olivier Tilloy

Fork WebDataServiceWrapper to remove bits that oxide doesn't need.

2283d7f... by Olivier Tilloy

New FilteredPrefStore class that stores all preferences in memory except for a selected set which are persisted on disk.

370bace... by Olivier Tilloy

Updated oxide.qmltypes.

Unmerged commits

370bace... by Olivier Tilloy

Updated oxide.qmltypes.

becd872... by Olivier Tilloy

Updated test.

2861ed9... by Olivier Tilloy

Ensure that the autofill profiles have been loaded before accessing them.

1925106... by Olivier Tilloy

New API on WebContext for autofill profiles management.

2283d7f... by Olivier Tilloy

New FilteredPrefStore class that stores all preferences in memory except for a selected set which are persisted on disk.

3f0f3aa... by Olivier Tilloy

Fork WebDataServiceWrapper to remove bits that oxide doesn't need.

867131f... by Olivier Tilloy

Make ownership of AutofillPopupController explicit.

0c5a23f... by Olivier Tilloy

Remove unused method.

ea88035... by Olivier Tilloy

Remove unused references to gfx::NativeView (always null) in AutofillPopupController.

f85f34f... by Olivier Tilloy

Rename files for consistency with newly-added code.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/qt/core/browser/oxide_qt_web_context.cc b/qt/core/browser/oxide_qt_web_context.cc
2index fc1492f..678ec86 100644
3--- a/qt/core/browser/oxide_qt_web_context.cc
4+++ b/qt/core/browser/oxide_qt_web_context.cc
5@@ -20,7 +20,6 @@
6 #include <vector>
7
8 #include <QDateTime>
9-#include <QDebug>
10 #include <QMetaMethod>
11 #include <QNetworkCookie>
12 #include <QObject>
13@@ -30,10 +29,13 @@
14
15 #include "base/auto_reset.h"
16 #include "base/files/file_path.h"
17+#include "base/guid.h"
18 #include "base/logging.h"
19 #include "base/strings/string_util.h"
20+#include "base/strings/utf_string_conversions.h"
21 #include "base/synchronization/lock.h"
22 #include "base/threading/thread_task_runner_handle.h"
23+#include "components/autofill/core/browser/personal_data_manager.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/cookie_store_factory.h"
26 #include "content/public/browser/resource_request_info.h"
27@@ -59,6 +61,7 @@
28 #include "shared/browser/oxide_user_agent_settings.h"
29 #include "shared/browser/oxide_user_script_master.h"
30 #include "shared/browser/permissions/oxide_temporary_saved_permission_context.h"
31+#include "shared/browser/personal_data_manager_factory.h"
32
33 #include "oxide_qt_browser_startup.h"
34
35@@ -85,6 +88,28 @@ int GetNextCookieRequestId() {
36 return id++;
37 }
38
39+const char kAutofillOrigin[] = "oxide autofill";
40+
41+void PopulateAutofillProfileFromVariant(autofill::AutofillProfile* profile,
42+ const QVariantMap& map) {
43+#define SET_PROFILE_FIELD(field, key) \
44+ profile->SetRawInfo(autofill::field, base::UTF8ToUTF16( \
45+ map.value(QStringLiteral(key)).toString().toStdString()))
46+ SET_PROFILE_FIELD(NAME_FIRST, "firstName");
47+ SET_PROFILE_FIELD(NAME_MIDDLE, "middleName");
48+ SET_PROFILE_FIELD(NAME_LAST, "lastName");
49+ SET_PROFILE_FIELD(NAME_FULL, "fullName");
50+ SET_PROFILE_FIELD(COMPANY_NAME, "companyName");
51+ SET_PROFILE_FIELD(ADDRESS_HOME_STREET_ADDRESS, "address");
52+ SET_PROFILE_FIELD(ADDRESS_HOME_CITY, "city");
53+ SET_PROFILE_FIELD(ADDRESS_HOME_STATE, "state");
54+ SET_PROFILE_FIELD(ADDRESS_HOME_ZIP, "zip");
55+ SET_PROFILE_FIELD(ADDRESS_HOME_COUNTRY, "country");
56+ SET_PROFILE_FIELD(PHONE_HOME_WHOLE_NUMBER, "phone");
57+ SET_PROFILE_FIELD(EMAIL_ADDRESS, "email");
58+#undef SET_PROFILE_FIELD
59+}
60+
61 }
62
63 class WebContext::BrowserContextDelegate
64@@ -453,7 +478,13 @@ WebContext::WebContext(WebContextProxyClient* client,
65 WebContext::~WebContext() {
66 if (context_.get()) {
67 context_->SetDelegate(nullptr);
68+
69 MediaCaptureDevicesContext::Get(context_.get())->set_client(nullptr);
70+
71+ autofill::PersonalDataManager* manager =
72+ PersonalDataManagerFactory::GetForContext(context_.get());
73+ DCHECK(manager);
74+ manager->RemoveObserver(this);
75 }
76 }
77
78@@ -538,6 +569,12 @@ BrowserContext* WebContext::GetContext() {
79
80 UpdateUserScripts();
81
82+ autofill::PersonalDataManager* manager =
83+ PersonalDataManagerFactory::GetForContext(context_.get());
84+ DCHECK(manager);
85+ manager->AddObserver(this);
86+ client_->AutofillProfilesChanged();
87+
88 return context_.get();
89 }
90
91@@ -1001,6 +1038,10 @@ void WebContext::DefaultVideoDeviceChanged() {
92 client_->DefaultVideoCaptureDeviceChanged();
93 }
94
95+void WebContext::OnPersonalDataChanged() {
96+ client_->AutofillProfilesChanged();
97+}
98+
99 bool WebContext::doNotTrack() const {
100 if (IsInitialized()) {
101 return UserAgentSettings::Get(context_.get())->GetDoNotTrack();
102@@ -1033,5 +1074,107 @@ void WebContext::setAutofillEnabled(bool enabled) {
103 }
104 }
105
106+bool WebContext::autofillProfilesLoaded() const {
107+ if (!IsInitialized()) {
108+ return false;
109+ }
110+
111+ autofill::PersonalDataManager* manager =
112+ PersonalDataManagerFactory::GetForContext(context_.get());
113+ DCHECK(manager);
114+ return manager->IsDataLoaded();
115+}
116+
117+QStringList WebContext::getAutofillProfiles() const {
118+ if (!autofillProfilesLoaded()) {
119+ return QStringList();
120+ }
121+
122+ autofill::PersonalDataManager* manager =
123+ PersonalDataManagerFactory::GetForContext(context_.get());
124+ QStringList rv;
125+ for (auto profile : manager->GetProfiles()) {
126+ rv.append(QString::fromStdString(profile->guid()));
127+ }
128+ return rv;
129+}
130+
131+QVariant WebContext::getAutofillProfile(const QString& guid) const {
132+ if (!autofillProfilesLoaded()) {
133+ return QVariant();
134+ }
135+
136+ autofill::PersonalDataManager* manager =
137+ PersonalDataManagerFactory::GetForContext(context_.get());
138+ autofill::AutofillProfile* profile =
139+ manager->GetProfileByGUID(guid.toStdString());
140+ if (!profile) {
141+ return QVariant();
142+ }
143+
144+ QVariantMap rv;
145+ const std::string& locale = manager->app_locale();
146+ rv[QStringLiteral("guid")] = QString::fromStdString(profile->guid());
147+ rv[QStringLiteral("origin")] = QString::fromStdString(profile->origin());
148+#define GET_PROFILE_FIELD(key, field) \
149+ rv[QStringLiteral(key)] = QString::fromStdString(base::UTF16ToUTF8( \
150+ profile->GetInfo(autofill::AutofillType(autofill::field), locale)))
151+ GET_PROFILE_FIELD("firstName", NAME_FIRST);
152+ GET_PROFILE_FIELD("middleName", NAME_MIDDLE);
153+ GET_PROFILE_FIELD("lastName", NAME_LAST);
154+ GET_PROFILE_FIELD("fullName", NAME_FULL);
155+ GET_PROFILE_FIELD("companyName", COMPANY_NAME);
156+ GET_PROFILE_FIELD("address", ADDRESS_HOME_STREET_ADDRESS);
157+ GET_PROFILE_FIELD("city", ADDRESS_HOME_CITY);
158+ GET_PROFILE_FIELD("state", ADDRESS_HOME_STATE);
159+ GET_PROFILE_FIELD("zip", ADDRESS_HOME_ZIP);
160+ GET_PROFILE_FIELD("country", ADDRESS_HOME_COUNTRY);
161+ GET_PROFILE_FIELD("phone", PHONE_HOME_WHOLE_NUMBER);
162+ GET_PROFILE_FIELD("email", EMAIL_ADDRESS);
163+#undef GET_PROFILE_FIELD
164+ return rv;
165+}
166+
167+void WebContext::addAutofillProfile(const QVariant& profile) {
168+ if (!autofillProfilesLoaded()) {
169+ return;
170+ }
171+
172+ autofill::PersonalDataManager* manager =
173+ PersonalDataManagerFactory::GetForContext(context_.get());
174+ autofill::AutofillProfile ap(base::GenerateGUID(), kAutofillOrigin);
175+ PopulateAutofillProfileFromVariant(&ap, profile.toMap());
176+ manager->AddProfile(ap);
177+}
178+
179+void WebContext::removeAutofillProfile(const QString& guid) {
180+ if (!autofillProfilesLoaded()) {
181+ return;
182+ }
183+
184+ autofill::PersonalDataManager* manager =
185+ PersonalDataManagerFactory::GetForContext(context_.get());
186+ manager->RemoveByGUID(guid.toStdString());
187+}
188+
189+void WebContext::updateAutofillProfile(const QVariant& profile) {
190+ if (!autofillProfilesLoaded()) {
191+ return;
192+ }
193+
194+ QVariantMap map = profile.toMap();
195+ if (!map.contains(QStringLiteral("guid"))) {
196+ return;
197+ }
198+
199+ autofill::PersonalDataManager* manager =
200+ PersonalDataManagerFactory::GetForContext(context_.get());
201+ autofill::AutofillProfile ap(
202+ map.value(QStringLiteral("guid")).toString().toStdString(),
203+ map.value(QStringLiteral("origin")).toString().toStdString());
204+ PopulateAutofillProfileFromVariant(&ap, profile.toMap());
205+ manager->UpdateProfile(ap);
206+}
207+
208 } // namespace qt
209 } // namespace oxide
210diff --git a/qt/core/browser/oxide_qt_web_context.h b/qt/core/browser/oxide_qt_web_context.h
211index 1dd4134..ef5817c 100644
212--- a/qt/core/browser/oxide_qt_web_context.h
213+++ b/qt/core/browser/oxide_qt_web_context.h
214@@ -29,6 +29,7 @@
215 #include "base/macros.h"
216 #include "base/memory/ref_counted.h"
217 #include "base/memory/weak_ptr.h"
218+#include "components/autofill/core/browser/personal_data_manager_observer.h"
219 #include "net/cookies/canonical_cookie.h"
220
221 #include "qt/core/glue/oxide_qt_web_context_proxy.h"
222@@ -67,7 +68,8 @@ class WebContextGetter : public base::RefCountedThreadSafe<WebContextGetter> {
223 };
224
225 class WebContext : public WebContextProxy,
226- public oxide::MediaCaptureDevicesContextClient {
227+ public oxide::MediaCaptureDevicesContextClient,
228+ public autofill::PersonalDataManagerObserver {
229 public:
230 WebContext(WebContextProxyClient* client, QObject* handle);
231 ~WebContext();
232@@ -147,10 +149,20 @@ class WebContext : public WebContextProxy,
233 bool autofillEnabled() const override;
234 void setAutofillEnabled(bool enabled) override;
235
236+ bool autofillProfilesLoaded() const override;
237+ QStringList getAutofillProfiles() const override;
238+ QVariant getAutofillProfile(const QString& guid) const override;
239+ void addAutofillProfile(const QVariant& profile) override;
240+ void removeAutofillProfile(const QString& guid) override;
241+ void updateAutofillProfile(const QVariant& profile) override;
242+
243 // oxide::MediaCaptureDevicesContextClient implementation
244 void DefaultAudioDeviceChanged() override;
245 void DefaultVideoDeviceChanged() override;
246
247+ // autofill::PersonalDataManagerObserver implementation
248+ void OnPersonalDataChanged() override;
249+
250 WebContextProxyClient* client_;
251
252 BrowserContext::UniquePtr context_;
253diff --git a/qt/core/glue/oxide_qt_web_context_proxy.h b/qt/core/glue/oxide_qt_web_context_proxy.h
254index 49f0180..59b9b6b 100644
255--- a/qt/core/glue/oxide_qt_web_context_proxy.h
256+++ b/qt/core/glue/oxide_qt_web_context_proxy.h
257@@ -23,6 +23,7 @@
258 #include <QStringList>
259 #include <QtGlobal>
260 #include <QUrl>
261+#include <QVariant>
262 #include <QWeakPointer>
263
264 #include "qt/core/api/oxideqglobal.h"
265@@ -140,6 +141,13 @@ class OXIDE_QTCORE_EXPORT WebContextProxy : public ProxyBase<WebContext> {
266
267 virtual bool autofillEnabled() const = 0;
268 virtual void setAutofillEnabled(bool enabled) = 0;
269+
270+ virtual bool autofillProfilesLoaded() const = 0;
271+ virtual QStringList getAutofillProfiles() const = 0;
272+ virtual QVariant getAutofillProfile(const QString& guid) const = 0;
273+ virtual void addAutofillProfile(const QVariant& profile) = 0;
274+ virtual void removeAutofillProfile(const QString& guid) = 0;
275+ virtual void updateAutofillProfile(const QVariant& profile) = 0;
276 };
277
278 } // namespace qt
279diff --git a/qt/core/glue/oxide_qt_web_context_proxy_client.h b/qt/core/glue/oxide_qt_web_context_proxy_client.h
280index a449c60..9c710d9 100644
281--- a/qt/core/glue/oxide_qt_web_context_proxy_client.h
282+++ b/qt/core/glue/oxide_qt_web_context_proxy_client.h
283@@ -1,5 +1,5 @@
284 // vim:expandtab:shiftwidth=2:tabstop=2:
285-// Copyright (C) 2013-2015 Canonical Ltd.
286+// Copyright (C) 2013-2017 Canonical Ltd.
287
288 // This library is free software; you can redistribute it and/or
289 // modify it under the terms of the GNU Lesser General Public
290@@ -51,6 +51,8 @@ class WebContextProxyClient {
291
292 virtual void DefaultVideoCaptureDeviceChanged() = 0;
293
294+ virtual void AutofillProfilesChanged() = 0;
295+
296 class IOClient {
297 public:
298 virtual ~IOClient() {}
299diff --git a/qt/qmlplugin/oxide.qmltypes b/qt/qmlplugin/oxide.qmltypes
300index 1d7d164..2adbde8 100644
301--- a/qt/qmlplugin/oxide.qmltypes
302+++ b/qt/qmlplugin/oxide.qmltypes
303@@ -186,6 +186,31 @@ Module {
304 Method { name: "deny" }
305 }
306 Component {
307+ name: "OxideQQuickAutofillProfiles"
308+ prototype: "QAbstractListModel"
309+ exports: ["AutofillProfiles 1.22"]
310+ isCreatable: false
311+ exportMetaObjectRevisions: [0]
312+ Property { name: "ready"; type: "bool"; isReadonly: true }
313+ Method {
314+ name: "get"
315+ type: "QVariant"
316+ Parameter { name: "guid"; type: "string" }
317+ }
318+ Method {
319+ name: "add"
320+ Parameter { name: "profile"; type: "QVariant" }
321+ }
322+ Method {
323+ name: "remove"
324+ Parameter { name: "guid"; type: "string" }
325+ }
326+ Method {
327+ name: "update"
328+ Parameter { name: "profile"; type: "QVariant" }
329+ }
330+ }
331+ Component {
332 name: "OxideQQuickCookieManager"
333 prototype: "QObject"
334 exports: ["CookieManager 1.0", "CookieManager 1.3"]
335@@ -477,6 +502,13 @@ Module {
336 Property { name: "userAgentOverrides"; revision: 3; type: "QVariantList" }
337 Property { name: "doNotTrackEnabled"; revision: 3; type: "bool" }
338 Property { name: "autofillEnabled"; revision: 4; type: "bool" }
339+ Property {
340+ name: "autofillProfiles"
341+ revision: 4
342+ type: "OxideQQuickAutofillProfiles"
343+ isReadonly: true
344+ isPointer: true
345+ }
346 Signal { name: "devtoolsBindIpChanged" }
347 Signal { name: "hostMappingRulesChanged"; revision: 1 }
348 Signal { name: "allowedExtraUrlSchemesChanged"; revision: 1 }
349diff --git a/qt/qmlplugin/oxide_qml_plugin.cc b/qt/qmlplugin/oxide_qml_plugin.cc
350index cf2e41c..749d66f 100644
351--- a/qt/qmlplugin/oxide_qml_plugin.cc
352+++ b/qt/qmlplugin/oxide_qml_plugin.cc
353@@ -34,6 +34,7 @@
354 #include "qt/core/api/oxideqsecuritystatus.h"
355 #include "qt/core/api/oxideqsslcertificate.h"
356 #include "qt/core/api/oxideqwebpreferences.h"
357+#include "qt/quick/api/oxideqquickautofillprofiles.h"
358 #include "qt/quick/api/oxideqquickcookiemanager_p.h"
359 #include "qt/quick/api/oxideqquickglobal_p.h"
360 #include "qt/quick/api/oxideqquicklocationbarcontroller.h"
361@@ -217,6 +218,9 @@ class OxideQmlPlugin : public QQmlExtensionPlugin {
362 "NavigationHistory is accessed via WebView.navigationHistory");
363
364 qmlRegisterType<OxideQQuickWebContext, 4>(uri, 1, 22, "WebContext");
365+ qmlRegisterUncreatableType<OxideQQuickAutofillProfiles>(
366+ uri, 1, 22, "AutofillProfiles",
367+ "AutofillProfiles is accessed via WebContext.autofillProfiles");
368 }
369 };
370
371diff --git a/qt/quick/CMakeLists.txt b/qt/quick/CMakeLists.txt
372index 3737b68..416a7ce 100644
373--- a/qt/quick/CMakeLists.txt
374+++ b/qt/quick/CMakeLists.txt
375@@ -1,6 +1,6 @@
376 # vim:expandtab:shiftwidth=2:tabstop=2:
377
378-# Copyright (C) 2014-2016 Canonical Ltd.
379+# Copyright (C) 2014-2017 Canonical Ltd.
380
381 # This library is free software; you can redistribute it and/or
382 # modify it under the terms of the GNU Lesser General Public
383@@ -20,6 +20,7 @@ qt5_wrap_cpp(MOC_EXTRA
384 api/oxideqquickwebcontextdelegateworker_p_p.h)
385
386 set(OXIDE_QUICKLIB_SRCS
387+ api/oxideqquickautofillprofiles.cc
388 api/oxideqquickcookiemanager.cc
389 api/oxideqquickglobal.cc
390 api/oxideqquicklocationbarcontroller.cc
391diff --git a/qt/quick/api/oxideqquickautofillprofiles.cc b/qt/quick/api/oxideqquickautofillprofiles.cc
392new file mode 100644
393index 0000000..835984c
394--- /dev/null
395+++ b/qt/quick/api/oxideqquickautofillprofiles.cc
396@@ -0,0 +1,193 @@
397+// vim:expandtab:shiftwidth=2:tabstop=2:
398+// Copyright (C) 2017 Canonical Ltd.
399+
400+// This library is free software; you can redistribute it and/or
401+// modify it under the terms of the GNU Lesser General Public
402+// License as published by the Free Software Foundation; either
403+// version 2.1 of the License, or (at your option) any later version.
404+
405+// This library is distributed in the hope that it will be useful,
406+// but WITHOUT ANY WARRANTY; without even the implied warranty of
407+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
408+// Lesser General Public License for more details.
409+
410+// You should have received a copy of the GNU Lesser General Public
411+// License along with this library; if not, write to the Free Software
412+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
413+
414+#include "oxideqquickautofillprofiles.h"
415+#include "oxideqquickautofillprofiles_p.h"
416+
417+#include <QString>
418+
419+#include "qt/core/glue/oxide_qt_web_context_proxy.h"
420+
421+OxideQQuickAutofillProfilesPrivate::OxideQQuickAutofillProfilesPrivate(
422+ OxideQQuickAutofillProfiles* q)
423+ : q_ptr(q),
424+ model_items_need_rebuilding_(true) {}
425+
426+void OxideQQuickAutofillProfilesPrivate::ensureModelItemsAreBuilt() {
427+ if (!model_items_need_rebuilding_) {
428+ return;
429+ }
430+
431+ Q_ASSERT(model_items_.isEmpty());
432+ model_items_need_rebuilding_ = false;
433+
434+ QStringList guids = web_context_proxy_->getAutofillProfiles();
435+ for (const auto& guid : guids) {
436+ model_items_.append(web_context_proxy_->getAutofillProfile(guid));
437+ }
438+}
439+
440+void OxideQQuickAutofillProfilesPrivate::AutofillProfilesChanged() {
441+ Q_Q(OxideQQuickAutofillProfiles);
442+
443+ model_items_need_rebuilding_ = false;
444+ q->beginResetModel();
445+ model_items_need_rebuilding_ = true;
446+ model_items_.clear();
447+ q->endResetModel();
448+
449+ Q_EMIT q->readyChanged();
450+}
451+
452+OxideQQuickAutofillProfilesPrivate
453+ ::~OxideQQuickAutofillProfilesPrivate() = default;
454+
455+// static
456+OxideQQuickAutofillProfilesPrivate* OxideQQuickAutofillProfilesPrivate::get(
457+ OxideQQuickAutofillProfiles* q) {
458+ return q->d_func();
459+}
460+
461+// static
462+std::unique_ptr<OxideQQuickAutofillProfiles>
463+OxideQQuickAutofillProfilesPrivate::Create() {
464+ return std::unique_ptr<OxideQQuickAutofillProfiles>(
465+ new OxideQQuickAutofillProfiles());
466+}
467+
468+void OxideQQuickAutofillProfilesPrivate::SetWebContextProxy(
469+ oxide::qt::WebContextProxy* proxy) {
470+ web_context_proxy_ = proxy;
471+}
472+
473+OxideQQuickAutofillProfiles::OxideQQuickAutofillProfiles()
474+ : d_ptr(new OxideQQuickAutofillProfilesPrivate(this)) {}
475+
476+bool OxideQQuickAutofillProfiles::ready() const {
477+ Q_D(const OxideQQuickAutofillProfiles);
478+
479+ return d->web_context_proxy_->autofillProfilesLoaded();
480+}
481+
482+QHash<int, QByteArray> OxideQQuickAutofillProfiles::roleNames() const {
483+ static QHash<int, QByteArray> roles;
484+ if (roles.isEmpty()) {
485+ roles[OxideQQuickAutofillProfilesPrivate::Guid] = "guid";
486+ roles[OxideQQuickAutofillProfilesPrivate::Origin] = "origin";
487+ roles[OxideQQuickAutofillProfilesPrivate::FirstName] = "firstName";
488+ roles[OxideQQuickAutofillProfilesPrivate::MiddleName] = "middleName";
489+ roles[OxideQQuickAutofillProfilesPrivate::LastName] = "lastName";
490+ roles[OxideQQuickAutofillProfilesPrivate::FullName] = "fullName";
491+ roles[OxideQQuickAutofillProfilesPrivate::CompanyName] = "companyName";
492+ roles[OxideQQuickAutofillProfilesPrivate::Address] = "address";
493+ roles[OxideQQuickAutofillProfilesPrivate::City] = "city";
494+ roles[OxideQQuickAutofillProfilesPrivate::State] = "state";
495+ roles[OxideQQuickAutofillProfilesPrivate::Zip] = "zip";
496+ roles[OxideQQuickAutofillProfilesPrivate::Country] = "country";
497+ roles[OxideQQuickAutofillProfilesPrivate::Phone] = "phone";
498+ roles[OxideQQuickAutofillProfilesPrivate::Email] = "email";
499+ }
500+ return roles;
501+}
502+
503+int OxideQQuickAutofillProfiles::rowCount(const QModelIndex& parent) const {
504+ Q_UNUSED(parent);
505+ Q_D(const OxideQQuickAutofillProfiles);
506+
507+ const_cast<OxideQQuickAutofillProfiles*>(this)
508+ ->d_func()->ensureModelItemsAreBuilt();
509+
510+ return d->model_items_.size();
511+}
512+
513+QVariant OxideQQuickAutofillProfiles::data(const QModelIndex& index,
514+ int role) const {
515+ Q_D(const OxideQQuickAutofillProfiles);
516+
517+ const_cast<OxideQQuickAutofillProfiles*>(this)
518+ ->d_func()->ensureModelItemsAreBuilt();
519+
520+ if (!index.isValid()) {
521+ return QVariant();
522+ }
523+
524+ int row = index.row();
525+ if ((row < 0) || (row >= d->model_items_.size())) {
526+ return QVariant();
527+ }
528+
529+ const QVariantMap& item = d->model_items_[row].toMap();
530+
531+ switch (role) {
532+ case OxideQQuickAutofillProfilesPrivate::Guid:
533+ return item.value(QStringLiteral("guid"));
534+ case OxideQQuickAutofillProfilesPrivate::Origin:
535+ return item.value(QStringLiteral("origin"));
536+ case OxideQQuickAutofillProfilesPrivate::FirstName:
537+ return item.value(QStringLiteral("firstName"));
538+ case OxideQQuickAutofillProfilesPrivate::MiddleName:
539+ return item.value(QStringLiteral("middleName"));
540+ case OxideQQuickAutofillProfilesPrivate::LastName:
541+ return item.value(QStringLiteral("lastName"));
542+ case OxideQQuickAutofillProfilesPrivate::FullName:
543+ return item.value(QStringLiteral("fullName"));
544+ case OxideQQuickAutofillProfilesPrivate::CompanyName:
545+ return item.value(QStringLiteral("companyName"));
546+ case OxideQQuickAutofillProfilesPrivate::Address:
547+ return item.value(QStringLiteral("address"));
548+ case OxideQQuickAutofillProfilesPrivate::City:
549+ return item.value(QStringLiteral("city"));
550+ case OxideQQuickAutofillProfilesPrivate::State:
551+ return item.value(QStringLiteral("state"));
552+ case OxideQQuickAutofillProfilesPrivate::Zip:
553+ return item.value(QStringLiteral("zip"));
554+ case OxideQQuickAutofillProfilesPrivate::Country:
555+ return item.value(QStringLiteral("country"));
556+ case OxideQQuickAutofillProfilesPrivate::Phone:
557+ return item.value(QStringLiteral("phone"));
558+ case OxideQQuickAutofillProfilesPrivate::Email:
559+ return item.value(QStringLiteral("email"));
560+ default:
561+ return QVariant();
562+ }
563+}
564+
565+OxideQQuickAutofillProfiles::~OxideQQuickAutofillProfiles() = default;
566+
567+QVariant OxideQQuickAutofillProfiles::get(const QString& guid) const {
568+ Q_D(const OxideQQuickAutofillProfiles);
569+
570+ return d->web_context_proxy_->getAutofillProfile(guid);
571+}
572+
573+void OxideQQuickAutofillProfiles::add(const QVariant& profile) {
574+ Q_D(OxideQQuickAutofillProfiles);
575+
576+ d->web_context_proxy_->addAutofillProfile(profile);
577+}
578+
579+void OxideQQuickAutofillProfiles::remove(const QString& guid) {
580+ Q_D(OxideQQuickAutofillProfiles);
581+
582+ d->web_context_proxy_->removeAutofillProfile(guid);
583+}
584+
585+void OxideQQuickAutofillProfiles::update(const QVariant& profile) {
586+ Q_D(OxideQQuickAutofillProfiles);
587+
588+ d->web_context_proxy_->updateAutofillProfile(profile);
589+}
590diff --git a/qt/quick/api/oxideqquickautofillprofiles.h b/qt/quick/api/oxideqquickautofillprofiles.h
591new file mode 100644
592index 0000000..7022037
593--- /dev/null
594+++ b/qt/quick/api/oxideqquickautofillprofiles.h
595@@ -0,0 +1,68 @@
596+// vim:expandtab:shiftwidth=2:tabstop=2:
597+// Copyright (C) 2017 Canonical Ltd.
598+
599+// This library is free software; you can redistribute it and/or
600+// modify it under the terms of the GNU Lesser General Public
601+// License as published by the Free Software Foundation; either
602+// version 2.1 of the License, or (at your option) any later version.
603+
604+// This library is distributed in the hope that it will be useful,
605+// but WITHOUT ANY WARRANTY; without even the implied warranty of
606+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
607+// Lesser General Public License for more details.
608+
609+// You should have received a copy of the GNU Lesser General Public
610+// License along with this library; if not, write to the Free Software
611+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
612+
613+#ifndef OXIDE_QTQUICK_AUTOFILL_PROFILES
614+#define OXIDE_QTQUICK_AUTOFILL_PROFILES
615+
616+#include <QtCore/QAbstractListModel>
617+#include <QtCore/QScopedPointer>
618+#include <QtCore/QVariant>
619+#include <QtQml/QtQml>
620+
621+#include <OxideQtQuick/oxideqquickglobal.h>
622+
623+class QString;
624+
625+class OxideQQuickAutofillProfilesPrivate;
626+
627+class OXIDE_QTQUICK_EXPORT OxideQQuickAutofillProfiles
628+ : public QAbstractListModel {
629+ Q_OBJECT
630+
631+ Q_PROPERTY(bool ready READ ready NOTIFY readyChanged)
632+
633+ Q_DECLARE_PRIVATE(OxideQQuickAutofillProfiles)
634+ Q_DISABLE_COPY(OxideQQuickAutofillProfiles)
635+
636+ public:
637+ ~OxideQQuickAutofillProfiles() Q_DECL_OVERRIDE;
638+
639+ bool ready() const;
640+
641+ public Q_SLOTS:
642+ QVariant get(const QString& guid) const;
643+ void add(const QVariant& profile);
644+ void remove(const QString& guid);
645+ void update(const QVariant& profile);
646+
647+ Q_SIGNALS:
648+ void readyChanged();
649+
650+ private:
651+ OxideQQuickAutofillProfiles();
652+
653+ // reimplemented from QAbstractListModel
654+ QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
655+ int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
656+ QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE;
657+
658+ QScopedPointer<OxideQQuickAutofillProfilesPrivate> d_ptr;
659+};
660+
661+QML_DECLARE_TYPE(OxideQQuickAutofillProfiles)
662+
663+#endif // OXIDE_QTQUICK_AUTOFILL_PROFILES
664diff --git a/qt/quick/api/oxideqquickautofillprofiles_p.h b/qt/quick/api/oxideqquickautofillprofiles_p.h
665new file mode 100644
666index 0000000..d47b60b
667--- /dev/null
668+++ b/qt/quick/api/oxideqquickautofillprofiles_p.h
669@@ -0,0 +1,80 @@
670+// vim:expandtab:shiftwidth=2:tabstop=2:
671+// Copyright (C) 2017 Canonical Ltd.
672+
673+// This library is free software; you can redistribute it and/or
674+// modify it under the terms of the GNU Lesser General Public
675+// License as published by the Free Software Foundation; either
676+// version 2.1 of the License, or (at your option) any later version.
677+
678+// This library is distributed in the hope that it will be useful,
679+// but WITHOUT ANY WARRANTY; without even the implied warranty of
680+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
681+// Lesser General Public License for more details.
682+
683+// You should have received a copy of the GNU Lesser General Public
684+// License along with this library; if not, write to the Free Software
685+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
686+
687+#ifndef _OXIDE_QT_QUICK_API_AUTOFILL_PROFILES_P_H_
688+#define _OXIDE_QT_QUICK_API_AUTOFILL_PROFILES_P_H_
689+
690+#include <memory>
691+
692+#include <QtGlobal>
693+#include <QVariantList>
694+
695+namespace oxide {
696+namespace qt {
697+class WebContextProxy;
698+}
699+}
700+
701+class OxideQQuickAutofillProfiles;
702+
703+class OxideQQuickAutofillProfilesPrivate {
704+ Q_DECLARE_PUBLIC(OxideQQuickAutofillProfiles)
705+ Q_DISABLE_COPY(OxideQQuickAutofillProfilesPrivate)
706+
707+ public:
708+ ~OxideQQuickAutofillProfilesPrivate();
709+
710+ static OxideQQuickAutofillProfilesPrivate* get(
711+ OxideQQuickAutofillProfiles* q);
712+
713+ static std::unique_ptr<OxideQQuickAutofillProfiles> Create();
714+
715+ void SetWebContextProxy(oxide::qt::WebContextProxy* proxy);
716+
717+ void AutofillProfilesChanged();
718+
719+ private:
720+ OxideQQuickAutofillProfilesPrivate(OxideQQuickAutofillProfiles* q);
721+
722+ void ensureModelItemsAreBuilt();
723+
724+ enum Roles {
725+ Guid = Qt::UserRole + 1,
726+ Origin,
727+ FirstName,
728+ MiddleName,
729+ LastName,
730+ FullName,
731+ CompanyName,
732+ Address,
733+ City,
734+ State,
735+ Zip,
736+ Country,
737+ Phone,
738+ Email
739+ };
740+
741+ OxideQQuickAutofillProfiles* q_ptr;
742+
743+ oxide::qt::WebContextProxy* web_context_proxy_;
744+
745+ bool model_items_need_rebuilding_;
746+ QVariantList model_items_;
747+};
748+
749+#endif // _OXIDE_QT_QUICK_API_AUTOFILL_PROFILES_P_H_
750diff --git a/qt/quick/api/oxideqquickwebcontext.cc b/qt/quick/api/oxideqquickwebcontext.cc
751index 1946af0..92b99ee 100644
752--- a/qt/quick/api/oxideqquickwebcontext.cc
753+++ b/qt/quick/api/oxideqquickwebcontext.cc
754@@ -1,5 +1,5 @@
755 // vim:expandtab:shiftwidth=2:tabstop=2:
756-// Copyright (C) 2013-2016 Canonical Ltd.
757+// Copyright (C) 2013-2017 Canonical Ltd.
758
759 // This library is free software; you can redistribute it and/or
760 // modify it under the terms of the GNU Lesser General Public
761@@ -35,6 +35,8 @@
762 #include "qt/core/glue/oxide_qt_web_context_proxy.h"
763 #include "qt/quick/oxide_qquick_init.h"
764
765+#include "oxideqquickautofillprofiles.h"
766+#include "oxideqquickautofillprofiles_p.h"
767 #include "oxideqquickcookiemanager_p.h"
768 #include "oxideqquickuserscript.h"
769 #include "oxideqquickuserscript_p.h"
770@@ -213,7 +215,11 @@ OxideQQuickWebContextPrivate::OxideQQuickWebContextPrivate(
771 proxy_(WebContextProxy::create(this, q)),
772 constructed_(false),
773 io_(new oxide::qquick::WebContextIODelegate()),
774- cookie_manager_(nullptr) {}
775+ cookie_manager_(nullptr),
776+ autofill_profiles_(OxideQQuickAutofillProfilesPrivate::Create()) {
777+ OxideQQuickAutofillProfilesPrivate::get(autofill_profiles_.get())
778+ ->SetWebContextProxy(proxy_.data());
779+}
780
781 void OxideQQuickWebContextPrivate::userScriptUpdated() {
782 proxy_->updateUserScripts();
783@@ -391,6 +397,13 @@ void OxideQQuickWebContextPrivate::DefaultVideoCaptureDeviceChanged() {
784 emit q->defaultVideoCaptureDeviceIdChanged();
785 }
786
787+void OxideQQuickWebContextPrivate::AutofillProfilesChanged() {
788+ Q_Q(OxideQQuickWebContext);
789+
790+ OxideQQuickAutofillProfilesPrivate::get(autofill_profiles_.get())
791+ ->AutofillProfilesChanged();
792+}
793+
794 OxideQQuickWebContextPrivate::~OxideQQuickWebContextPrivate() {}
795
796 void OxideQQuickWebContextPrivate::delegateWorkerDestroyed(
797@@ -1592,4 +1605,10 @@ void OxideQQuickWebContext::setAutofillEnabled(bool enabled) {
798 emit autofillEnabledChanged();
799 }
800
801+OxideQQuickAutofillProfiles* OxideQQuickWebContext::autofillProfiles() const {
802+ Q_D(const OxideQQuickWebContext);
803+
804+ return d->autofill_profiles_.get();
805+}
806+
807 #include "moc_oxideqquickwebcontext.cpp"
808diff --git a/qt/quick/api/oxideqquickwebcontext.h b/qt/quick/api/oxideqquickwebcontext.h
809index f8ca6fa..85c1773 100644
810--- a/qt/quick/api/oxideqquickwebcontext.h
811+++ b/qt/quick/api/oxideqquickwebcontext.h
812@@ -30,6 +30,7 @@
813
814 #include <OxideQtQuick/oxideqquickglobal.h>
815
816+class OxideQQuickAutofillProfiles;
817 class OxideQQuickCookieManager;
818 class OxideQQuickWebContextDelegateWorker;
819 class OxideQQuickUserScript;
820@@ -78,6 +79,7 @@ class OXIDE_QTQUICK_EXPORT OxideQQuickWebContext : public QObject,
821 Q_PROPERTY(bool doNotTrackEnabled READ doNotTrack WRITE setDoNotTrack NOTIFY doNotTrackEnabledChanged REVISION 3)
822
823 Q_PROPERTY(bool autofillEnabled READ autofillEnabled WRITE setAutofillEnabled NOTIFY autofillEnabledChanged REVISION 4)
824+ Q_PROPERTY(OxideQQuickAutofillProfiles* autofillProfiles READ autofillProfiles CONSTANT REVISION 4)
825
826 Q_ENUMS(CookiePolicy)
827 Q_ENUMS(SessionCookieMode)
828@@ -178,6 +180,8 @@ class OXIDE_QTQUICK_EXPORT OxideQQuickWebContext : public QObject,
829 bool autofillEnabled() const;
830 void setAutofillEnabled(bool enabled);
831
832+ OxideQQuickAutofillProfiles* autofillProfiles() const;
833+
834 Q_SIGNALS:
835 void productChanged();
836 void userAgentChanged();
837diff --git a/qt/quick/api/oxideqquickwebcontext_p.h b/qt/quick/api/oxideqquickwebcontext_p.h
838index 262e132..4e9f34a 100644
839--- a/qt/quick/api/oxideqquickwebcontext_p.h
840+++ b/qt/quick/api/oxideqquickwebcontext_p.h
841@@ -1,5 +1,5 @@
842 // vim:expandtab:shiftwidth=2:tabstop=2:
843-// Copyright (C) 2013-2016 Canonical Ltd.
844+// Copyright (C) 2013-2017 Canonical Ltd.
845
846 // This library is free software; you can redistribute it and/or
847 // modify it under the terms of the GNU Lesser General Public
848@@ -25,10 +25,13 @@
849 #include <QStringList>
850 #include <QtGlobal>
851
852+#include <memory>
853+
854 #include "qt/core/glue/oxide_qt_web_context_proxy_client.h"
855
856 #include "qt/quick/api/oxideqquickwebcontext.h"
857
858+class OxideQQuickAutofillProfiles;
859 class OxideQQuickWebContextDelegateWorker;
860 class OxideQQuickUserScript;
861
862@@ -108,6 +111,7 @@ class Q_DECL_EXPORT OxideQQuickWebContextPrivate
863 QNetworkAccessManager* GetCustomNetworkAccessManager() override;
864 void DefaultAudioCaptureDeviceChanged() override;
865 void DefaultVideoCaptureDeviceChanged() override;
866+ void AutofillProfilesChanged() override;
867
868 OxideQQuickWebContext* q_ptr;
869
870@@ -125,6 +129,8 @@ class Q_DECL_EXPORT OxideQQuickWebContextPrivate
871
872 QStringList allowed_extra_url_schemes_;
873
874+ std::unique_ptr<OxideQQuickAutofillProfiles> autofill_profiles_;
875+
876 Q_DISABLE_COPY(OxideQQuickWebContextPrivate);
877 };
878
879diff --git a/qt/tests/qmltests/api/tst_WebContext_autofillProfiles.qml b/qt/tests/qmltests/api/tst_WebContext_autofillProfiles.qml
880new file mode 100644
881index 0000000..3c38ec2
882--- /dev/null
883+++ b/qt/tests/qmltests/api/tst_WebContext_autofillProfiles.qml
884@@ -0,0 +1,141 @@
885+import QtQuick 2.0
886+import QtTest 1.0
887+import com.canonical.Oxide 1.22
888+import Oxide.testsupport 1.0
889+import Ubuntu.Components 1.3
890+
891+TestWebView {
892+ id: webView
893+
894+ ListView {
895+ id: listView
896+ anchors.fill: parent
897+ model: SortFilterModel {
898+ model: webView.context ? webView.context.autofillProfiles: null
899+ sort.property: "fullName"
900+ }
901+ delegate: Item {
902+ objectName: "profile_delegate_%1".arg(index)
903+ readonly property string guid: model.guid
904+ readonly property string fullName: model.fullName
905+ }
906+ }
907+
908+ TestCase {
909+ name: "WebContext_autofillProfiles"
910+ when: windowShown
911+
912+ function makeProfile(firstName, lastName, companyName, address,
913+ city, zip, country, phone, email) {
914+ var profile = new Object;
915+ profile.firstName = firstName;
916+ profile.lastName = lastName;
917+ profile.companyName = companyName;
918+ profile.address = address;
919+ profile.city = city;
920+ profile.zip = zip;
921+ profile.country = country;
922+ profile.phone = phone;
923+ profile.email = email;
924+ return profile;
925+ }
926+
927+ function compareProfile(profile, fullName, firstName, lastName, companyName,
928+ address, city, zip, phone, email) {
929+ compare(profile.fullName, fullName);
930+ compare(profile.firstName, firstName);
931+ compare(profile.lastName, lastName);
932+ compare(profile.companyName, companyName);
933+ compare(profile.address, address);
934+ compare(profile.city, city);
935+ compare(profile.zip, zip);
936+ compare(profile.phone, phone);
937+ compare(profile.email, email);
938+ }
939+
940+ function getDelegate(index) {
941+ return TestSupport.findItemInScene(listView,
942+ "profile_delegate_%1".arg(index));
943+ }
944+
945+ function initTestCase() {
946+ webView.context.autofillEnabled = true;
947+ tryCompare(webView.context.autofillProfiles, "ready", true);
948+ }
949+
950+ function init() {
951+ compare(listView.count, 0);
952+ }
953+
954+ function test_WebContext_autofillProfiles_get_nonexistent_profile() {
955+ compare(webView.context.autofillProfiles.get("I-DONT-EXIST"), undefined);
956+ }
957+
958+ function test_WebContext_autofillProfiles_add_and_remove_profiles() {
959+ var p1 = makeProfile("John", "Lennon", "Apple Records",
960+ "Beaconsfield Road", "Liverpool", "L25 6DA",
961+ "England", "+440151234567", "john@thebeatles.com");
962+ webView.context.autofillProfiles.add(p1);
963+ tryCompare(listView, "count", 1);
964+ compare(getDelegate(0).fullName, "John Lennon");
965+
966+ var p2 = makeProfile("John", "Doe", "", "Park Avenue", "NYC", "NY 10016",
967+ "USA", "", "john.doe@nospam.org");
968+ webView.context.autofillProfiles.add(p2);
969+ tryCompare(listView, "count", 2);
970+ verify(TestUtils.waitFor(function() {
971+ return (getDelegate(0).fullName == "John Doe"); }));
972+ compare(getDelegate(1).fullName, "John Lennon");
973+
974+ var guid0 = getDelegate(0).guid;
975+ var guid1 = getDelegate(1).guid;
976+ compareProfile(webView.context.autofillProfiles.get(guid0),
977+ "John Doe", "John", "Doe", "", "Park Avenue", "NYC",
978+ "NY 10016", "", "john.doe@nospam.org");
979+ compareProfile(webView.context.autofillProfiles.get(guid1),
980+ "John Lennon", "John", "Lennon", "Apple Records",
981+ "Beaconsfield Road", "Liverpool", "L25 6DA",
982+ "+440151234567", "john@thebeatles.com");
983+
984+ webView.context.autofillProfiles.remove("I-DONT-EXIST");
985+ compare(listView.count, 2);
986+
987+ webView.context.autofillProfiles.remove(guid1);
988+ tryCompare(listView, "count", 1);
989+ webView.context.autofillProfiles.remove(guid0);
990+ tryCompare(listView, "count", 0);
991+ }
992+
993+ function test_WebContext_autofillProfiles_update_profile() {
994+ var p = makeProfile("John", "Lennon", "Apple Records",
995+ "Beaconsfield Road", "Liverpool", "L25 6DA",
996+ "England", "+440151234567", "john@thebeatles.com");
997+ webView.context.autofillProfiles.add(p);
998+ tryCompare(listView, "count", 1);
999+ var delegate = getDelegate(0);
1000+ compare(delegate.fullName, "John Lennon");
1001+ var guid = delegate.guid;
1002+
1003+ // Try updating without specifying the GUID, nothing should happen
1004+ p.firstName = "Paul";
1005+ compare(p.guid, undefined);
1006+ webView.context.autofillProfiles.update(p);
1007+ compare(webView.context.autofillProfiles.get(guid).firstName, "John");
1008+
1009+ // Try updating with an invalid GUID, nothing should happen
1010+ p.guid = "I-DONT-EXIST";
1011+ webView.context.autofillProfiles.update(p);
1012+ compare(webView.context.autofillProfiles.get(guid).firstName, "John");
1013+
1014+ // Update the profile with its GUID
1015+ p.lastName = "McCartney";
1016+ p.guid = guid;
1017+ webView.context.autofillProfiles.update(p);
1018+ verify(TestUtils.waitFor(function() {
1019+ return (getDelegate(0).fullName == "Paul McCartney"); }));
1020+
1021+ webView.context.autofillProfiles.remove(guid);
1022+ tryCompare(listView, "count", 0);
1023+ }
1024+ }
1025+}
1026diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml
1027index 8001673..e1954b0 100644
1028--- a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml
1029+++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml
1030@@ -14,6 +14,21 @@ UbuntuTestWebView {
1031
1032 focus: true
1033
1034+ Component {
1035+ id: profilesViewFactory
1036+
1037+ ListView {
1038+ anchors.fill: parent
1039+ model: SortFilterModel {
1040+ model: webView.context ? webView.context.autofillProfiles: null
1041+ }
1042+ delegate: Item {
1043+ objectName: "profile_delegate_%1".arg(index)
1044+ readonly property string guid: model.guid
1045+ }
1046+ }
1047+ }
1048+
1049 TestCase {
1050 name: "WebViewAutofillPopup_autofill_profiles"
1051 when: windowShown
1052@@ -224,5 +239,43 @@ UbuntuTestWebView {
1053 tryCompare(popup, "count", 1);
1054 compare(getSuggestion(0).label, "Beaconsfield Road");
1055 }
1056+
1057+ function test_use_profile_added_from_settings() {
1058+ // Add a new profile
1059+ tryCompare(webView.context.autofillProfiles, "ready", true);
1060+ var profile = new Object;
1061+ profile.firstName = "Paul";
1062+ profile.lastName = "McCartney";
1063+ profile.address = "Penny Lane";
1064+ profile.city = "Liverpool";
1065+ profile.zip = "L18 1DE";
1066+ profile.email = "paul@thebeatles.com";
1067+ webView.context.autofillProfiles.add(profile);
1068+
1069+ typeStringInField("p", "firstname");
1070+ var popup = getAutofillPopup();
1071+ compare(popup.count, 1);
1072+ compare(getSuggestion(0).value, "Paul");
1073+ var item = getSuggestion(0);
1074+ mouseClick(item);
1075+ verify(waitForAutofillPopupToClose());
1076+ compare_field_value("firstname", "Paul");
1077+ compare_field_value("lastname", "McCartney");
1078+ compare_field_value("email", "paul@thebeatles.com");
1079+ compare_field_value("zipcode", "L18 1DE");
1080+ compare_field_value("city", "Liverpool");
1081+ compare_field_value("street", "Penny Lane");
1082+
1083+ // Remove the profile
1084+ var profilesView = profilesViewFactory.createObject(webView);
1085+ profilesView.model.filter.property = "firstName";
1086+ profilesView.model.filter.pattern = /^Paul$/;
1087+ tryCompare(profilesView, "count", 1);
1088+ var delegate = TestSupport.findItemInScene(profilesView,
1089+ "profile_delegate_0");
1090+ webView.context.autofillProfiles.remove(delegate.guid);
1091+ tryCompare(profilesView, "count", 0);
1092+ profilesView.destroy();
1093+ }
1094 }
1095 }

Subscribers

People subscribed via source and target branches