2
* Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Library General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Library General Public License for more details.
14
* You should have received a copy of the GNU Library General Public License
15
* along with this program; see the file COPYING.LIB. If not, write to
16
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
* Boston, MA 02110-1301, USA.
22
#include "QtDialogRunner.h"
24
#include "WKRetainPtr.h"
25
#include "WKStringQt.h"
26
#include "qquickwebview_p_p.h"
27
#include "qwebpermissionrequest_p.h"
28
#include <QtQml/QQmlComponent>
29
#include <QtQml/QQmlContext>
30
#include <QtQml/QQmlEngine>
31
#include <QtQuick/QQuickItem>
32
#include <wtf/PassOwnPtr.h>
36
QtDialogRunner::QtDialogRunner(QQuickWebView* webView)
39
, m_wasAccepted(false)
43
QtDialogRunner::~QtDialogRunner()
47
// All dialogs need a way to support the state of the
48
// dialog being done/finished/dismissed. This is handled
49
// in the dialog base context.
50
class DialogContextBase : public QObject {
61
// Allows clients to call dismiss() directly, while also
62
// being able to hook up signals to automatically also
63
// dismiss the dialog since it's a slot.
75
// We store the dismissed state so that run() can check to see if a
76
// dialog has already been dismissed before spinning an event loop.
78
friend void QtDialogRunner::run();
81
class DialogContextObject : public DialogContextBase {
83
Q_PROPERTY(QString message READ message CONSTANT)
84
Q_PROPERTY(QString defaultValue READ defaultValue CONSTANT)
87
DialogContextObject(const QString& message, const QString& defaultValue = QString())
90
, m_defaultValue(defaultValue)
92
connect(this, SIGNAL(accepted(QString)), SLOT(dismiss()));
93
connect(this, SIGNAL(rejected()), SLOT(dismiss()));
95
QString message() const { return m_message; }
96
QString defaultValue() const { return m_defaultValue; }
99
void accept(const QString& result = QString()) { emit accepted(result); }
100
void reject() { emit rejected(); }
103
void accepted(const QString& result);
108
QString m_defaultValue;
111
class BaseAuthenticationContextObject : public DialogContextBase {
113
Q_PROPERTY(QString hostname READ hostname CONSTANT)
114
Q_PROPERTY(QString prefilledUsername READ prefilledUsername CONSTANT)
117
BaseAuthenticationContextObject(const QString& hostname, const QString& prefilledUsername)
118
: DialogContextBase()
119
, m_hostname(hostname)
120
, m_prefilledUsername(prefilledUsername)
122
connect(this, SIGNAL(accepted(QString, QString)), SLOT(dismiss()));
123
connect(this, SIGNAL(rejected()), SLOT(dismiss()));
126
QString hostname() const { return m_hostname; }
127
QString prefilledUsername() const { return m_prefilledUsername; }
130
void accept(const QString& username, const QString& password) { emit accepted(username, password); }
131
void reject() { emit rejected(); }
134
void accepted(const QString& username, const QString& password);
139
QString m_prefilledUsername;
142
class HttpAuthenticationDialogContextObject : public BaseAuthenticationContextObject {
144
Q_PROPERTY(QString realm READ realm CONSTANT)
147
HttpAuthenticationDialogContextObject(const QString& hostname, const QString& realm, const QString& prefilledUsername)
148
: BaseAuthenticationContextObject(hostname, prefilledUsername)
153
QString realm() const { return m_realm; }
159
class ProxyAuthenticationDialogContextObject : public BaseAuthenticationContextObject {
161
Q_PROPERTY(quint16 port READ port CONSTANT)
164
ProxyAuthenticationDialogContextObject(const QString& hostname, quint16 port, const QString& prefilledUsername)
165
: BaseAuthenticationContextObject(hostname, prefilledUsername)
170
quint16 port() const { return m_port; }
176
class CertificateVerificationDialogContextObject : public DialogContextBase {
178
Q_PROPERTY(QString hostname READ hostname CONSTANT)
181
CertificateVerificationDialogContextObject(const QString& hostname)
182
: DialogContextBase()
183
, m_hostname(hostname)
185
connect(this, SIGNAL(accepted()), SLOT(dismiss()));
186
connect(this, SIGNAL(rejected()), SLOT(dismiss()));
189
QString hostname() const { return m_hostname; }
192
void accept() { emit accepted(); }
193
void reject() { emit rejected(); }
203
class FilePickerContextObject : public DialogContextBase {
205
Q_PROPERTY(QStringList fileList READ fileList CONSTANT)
206
Q_PROPERTY(bool allowMultipleFiles READ allowMultipleFiles CONSTANT)
209
FilePickerContextObject(const QStringList& selectedFiles, bool allowMultiple)
210
: DialogContextBase()
211
, m_allowMultiple(allowMultiple)
212
, m_fileList(selectedFiles)
214
connect(this, SIGNAL(fileSelected(QStringList)), SLOT(dismiss()));
215
connect(this, SIGNAL(rejected()), SLOT(dismiss()));
218
QStringList fileList() const { return m_fileList; }
219
bool allowMultipleFiles() const { return m_allowMultiple;}
222
void reject() { emit rejected();}
223
void accept(const QVariant& path)
225
QStringList filesPath = path.toStringList();
227
if (filesPath.isEmpty()) {
232
// For single file upload, send only the first element if there are more than one file paths
233
if (!m_allowMultiple && filesPath.count() > 1)
234
filesPath = QStringList(filesPath.at(0));
235
emit fileSelected(filesPath);
240
void fileSelected(const QStringList&);
243
bool m_allowMultiple;
244
QStringList m_fileList;
247
class DatabaseQuotaDialogContextObject : public DialogContextBase {
249
Q_PROPERTY(QString databaseName READ databaseName CONSTANT)
250
Q_PROPERTY(QString displayName READ displayName CONSTANT)
251
Q_PROPERTY(quint64 currentQuota READ currentQuota CONSTANT)
252
Q_PROPERTY(quint64 currentOriginUsage READ currentOriginUsage CONSTANT)
253
Q_PROPERTY(quint64 currentDatabaseUsage READ currentDatabaseUsage CONSTANT)
254
Q_PROPERTY(quint64 expectedUsage READ expectedUsage CONSTANT)
255
Q_PROPERTY(QtWebSecurityOrigin* origin READ securityOrigin CONSTANT)
258
DatabaseQuotaDialogContextObject(const QString& databaseName, const QString& displayName, WKSecurityOriginRef securityOrigin, quint64 currentQuota, quint64 currentOriginUsage, quint64 currentDatabaseUsage, quint64 expectedUsage)
259
: DialogContextBase()
260
, m_databaseName(databaseName)
261
, m_displayName(displayName)
262
, m_currentQuota(currentQuota)
263
, m_currentOriginUsage(currentOriginUsage)
264
, m_currentDatabaseUsage(currentDatabaseUsage)
265
, m_expectedUsage(expectedUsage)
267
WKRetainPtr<WKStringRef> scheme = adoptWK(WKSecurityOriginCopyProtocol(securityOrigin));
268
WKRetainPtr<WKStringRef> host = adoptWK(WKSecurityOriginCopyHost(securityOrigin));
270
m_securityOrigin.setScheme(WKStringCopyQString(scheme.get()));
271
m_securityOrigin.setHost(WKStringCopyQString(host.get()));
272
m_securityOrigin.setPort(static_cast<int>(WKSecurityOriginGetPort(securityOrigin)));
274
connect(this, SIGNAL(accepted(quint64)), SLOT(dismiss()));
275
connect(this, SIGNAL(rejected()), SLOT(dismiss()));
278
QString databaseName() const { return m_databaseName; }
279
QString displayName() const { return m_displayName; }
280
quint64 currentQuota() const { return m_currentQuota; }
281
quint64 currentOriginUsage() const { return m_currentOriginUsage; }
282
quint64 currentDatabaseUsage() const { return m_currentDatabaseUsage; }
283
quint64 expectedUsage() const { return m_expectedUsage; }
284
QtWebSecurityOrigin* securityOrigin() { return &m_securityOrigin; }
287
void accept(quint64 size) { emit accepted(size); }
288
void reject() { emit rejected(); }
291
void accepted(quint64 size);
295
QString m_databaseName;
296
QString m_displayName;
297
quint64 m_currentQuota;
298
quint64 m_currentOriginUsage;
299
quint64 m_currentDatabaseUsage;
300
quint64 m_expectedUsage;
301
QtWebSecurityOrigin m_securityOrigin;
304
void QtDialogRunner::run()
306
DialogContextBase* context = static_cast<DialogContextBase*>(m_dialogContext->contextObject());
308
// We may have already been dismissed as part of Component.onCompleted()
309
if (context->m_dismissed)
312
connect(context, SIGNAL(dismissed()), SLOT(quit()));
313
exec(); // Spin the event loop
316
bool QtDialogRunner::initForAlert(const QString& message)
318
QQmlComponent* component = m_webView->experimental()->alertDialog();
322
DialogContextObject* contextObject = new DialogContextObject(message);
324
return createDialog(component, contextObject);
327
bool QtDialogRunner::initForConfirm(const QString& message)
329
QQmlComponent* component = m_webView->experimental()->confirmDialog();
333
DialogContextObject* contextObject = new DialogContextObject(message);
334
connect(contextObject, SIGNAL(accepted(QString)), SLOT(onAccepted()));
336
return createDialog(component, contextObject);
339
bool QtDialogRunner::initForPrompt(const QString& message, const QString& defaultValue)
341
QQmlComponent* component = m_webView->experimental()->promptDialog();
345
DialogContextObject* contextObject = new DialogContextObject(message, defaultValue);
346
connect(contextObject, SIGNAL(accepted(QString)), SLOT(onAccepted(QString)));
348
return createDialog(component, contextObject);
351
bool QtDialogRunner::initForAuthentication(const QString& hostname, const QString& realm, const QString& prefilledUsername)
353
QQmlComponent* component = m_webView->experimental()->authenticationDialog();
357
HttpAuthenticationDialogContextObject* contextObject = new HttpAuthenticationDialogContextObject(hostname, realm, prefilledUsername);
358
connect(contextObject, SIGNAL(accepted(QString, QString)), SLOT(onAuthenticationAccepted(QString, QString)));
360
return createDialog(component, contextObject);
363
bool QtDialogRunner::initForProxyAuthentication(const QString& hostname, uint16_t port, const QString& prefilledUsername)
365
QQmlComponent* component = m_webView->experimental()->proxyAuthenticationDialog();
369
ProxyAuthenticationDialogContextObject* contextObject = new ProxyAuthenticationDialogContextObject(hostname, port, prefilledUsername);
370
connect(contextObject, SIGNAL(accepted(QString, QString)), SLOT(onAuthenticationAccepted(QString, QString)));
372
return createDialog(component, contextObject);
375
bool QtDialogRunner::initForCertificateVerification(const QString& hostname)
377
QQmlComponent* component = m_webView->experimental()->certificateVerificationDialog();
381
CertificateVerificationDialogContextObject* contextObject = new CertificateVerificationDialogContextObject(hostname);
382
connect(contextObject, SIGNAL(accepted()), SLOT(onAccepted()));
384
return createDialog(component, contextObject);
387
bool QtDialogRunner::initForFilePicker(const QStringList& selectedFiles, bool allowMultiple)
389
QQmlComponent* component = m_webView->experimental()->filePicker();
393
FilePickerContextObject* contextObject = new FilePickerContextObject(selectedFiles, allowMultiple);
394
connect(contextObject, SIGNAL(fileSelected(QStringList)), SLOT(onFileSelected(QStringList)));
396
return createDialog(component, contextObject);
399
bool QtDialogRunner::initForDatabaseQuotaDialog(const QString& databaseName, const QString& displayName, WKSecurityOriginRef securityOrigin, quint64 currentQuota, quint64 currentOriginUsage, quint64 currentDatabaseUsage, quint64 expectedUsage)
401
QQmlComponent* component = m_webView->experimental()->databaseQuotaDialog();
405
DatabaseQuotaDialogContextObject* contextObject = new DatabaseQuotaDialogContextObject(databaseName, displayName, securityOrigin, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage);
406
connect(contextObject, SIGNAL(accepted(quint64)), SLOT(onDatabaseQuotaAccepted(quint64)));
408
return createDialog(component, contextObject);
411
bool QtDialogRunner::createDialog(QQmlComponent* component, QObject* contextObject)
413
QQmlContext* baseContext = component->creationContext();
415
baseContext = QQmlEngine::contextForObject(m_webView);
416
m_dialogContext = adoptPtr(new QQmlContext(baseContext));
418
// This makes both "message" and "model.message" work for the dialog,
419
// just like QtQuick's ListView delegates.
420
contextObject->setParent(m_dialogContext.get());
421
m_dialogContext->setContextProperty(QLatin1String("model"), contextObject);
422
m_dialogContext->setContextObject(contextObject);
424
QObject* object = component->beginCreate(m_dialogContext.get());
426
m_dialogContext.clear();
430
m_dialog = adoptPtr(qobject_cast<QQuickItem*>(object));
432
m_dialogContext.clear();
437
QQuickWebViewPrivate::get(m_webView)->addAttachedPropertyTo(m_dialog.get());
438
m_dialog->setParentItem(m_webView);
440
// Only fully create the component once we've set both a parent
441
// and the needed context and attached properties, so that dialogs
442
// can do useful stuff in their Component.onCompleted() method.
443
component->completeCreate();
445
// FIXME: As part of completeCreate, the bindings of the item will be
446
// evaluated, but for some reason doing mapToItem/mapFromItem in a
447
// binding will not work as expected, even if we at binding evaluation
448
// time have the parent and all the way up to the root QML item.
449
// As a workaround you can set whichever property you need in
450
// Component.onCompleted, even to a binding using Qt.bind().
455
void QtDialogRunner::onAccepted(const QString& result)
457
m_wasAccepted = true;
461
void QtDialogRunner::onAuthenticationAccepted(const QString& username, const QString& password)
463
m_username = username;
464
m_password = password;
467
void QtDialogRunner::onFileSelected(const QStringList& filePaths)
469
m_wasAccepted = true;
470
m_filepaths = filePaths;
473
void QtDialogRunner::onDatabaseQuotaAccepted(quint64 quota)
475
m_wasAccepted = true;
476
m_databaseQuota = quota;
479
} // namespace WebKit
481
#include "QtDialogRunner.moc"
482
#include "moc_QtDialogRunner.cpp"