qdeclarativewebview.cpp revision 2fc2651226baac27029e38c9d6ef883fa32084db
1/*
2    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3
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.
8
9    This library 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.
13
14    You should have received a copy of the GNU Library General Public License
15    along with this library; 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.
18*/
19
20
21#include "qdeclarativewebview_p.h"
22
23#include <QtCore/QDebug>
24#include <QtCore/QEvent>
25#include <QtCore/QFile>
26#include <QtDeclarative/QDeclarativeContext>
27#include <QtDeclarative/QDeclarativeEngine>
28#include <QtDeclarative/qdeclarative.h>
29#include <QtGui/QApplication>
30#include <QtGui/QGraphicsSceneMouseEvent>
31#include <QtGui/QKeyEvent>
32#include <QtGui/QMouseEvent>
33#include <QtGui/QPen>
34#include "qwebelement.h"
35#include "qwebframe.h"
36#include "qwebpage.h"
37#include "qwebsettings.h"
38
39QT_BEGIN_NAMESPACE
40
41class QDeclarativeWebViewPrivate {
42public:
43    QDeclarativeWebViewPrivate(QDeclarativeWebView* qq)
44      : q(qq)
45      , preferredwidth(0)
46      , preferredheight(0)
47      , progress(1.0)
48      , status(QDeclarativeWebView::Null)
49      , pending(PendingNone)
50      , newWindowComponent(0)
51      , newWindowParent(0)
52      , rendering(true)
53    {
54    }
55
56    QDeclarativeWebView* q;
57
58    QUrl url; // page url might be different if it has not loaded yet
59    GraphicsWebView* view;
60
61    int preferredwidth, preferredheight;
62    qreal progress;
63    QDeclarativeWebView::Status status;
64    QString statusText;
65    enum { PendingNone, PendingUrl, PendingHtml, PendingContent } pending;
66    QUrl pendingUrl;
67    QString pendingString;
68    QByteArray pendingData;
69    mutable QDeclarativeWebSettings settings;
70    QDeclarativeComponent* newWindowComponent;
71    QDeclarativeItem* newWindowParent;
72
73    static void windowObjectsAppend(QDeclarativeListProperty<QObject>* prop, QObject* o)
74    {
75        static_cast<QDeclarativeWebViewPrivate*>(prop->data)->windowObjects.append(o);
76        static_cast<QDeclarativeWebViewPrivate*>(prop->data)->updateWindowObjects();
77    }
78
79    void updateWindowObjects();
80    QObjectList windowObjects;
81
82    bool rendering;
83};
84
85GraphicsWebView::GraphicsWebView(QDeclarativeWebView* parent)
86    : QGraphicsWebView(parent)
87    , parent(parent)
88    , pressTime(400)
89{
90}
91
92void GraphicsWebView::mousePressEvent(QGraphicsSceneMouseEvent* event)
93{
94    pressPoint = event->pos();
95    if (pressTime) {
96        pressTimer.start(pressTime, this);
97        parent->setKeepMouseGrab(false);
98    } else {
99        grabMouse();
100        parent->setKeepMouseGrab(true);
101    }
102    QGraphicsWebView::mousePressEvent(event);
103
104    QWebHitTestResult hit = page()->mainFrame()->hitTestContent(pressPoint.toPoint());
105    if (hit.isContentEditable())
106        parent->forceActiveFocus();
107    setFocus();
108}
109
110void GraphicsWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
111{
112    QGraphicsWebView::mouseReleaseEvent(event);
113    pressTimer.stop();
114    parent->setKeepMouseGrab(false);
115    ungrabMouse();
116}
117
118void GraphicsWebView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
119{
120    QMouseEvent* me = new QMouseEvent(QEvent::MouseButtonDblClick, (event->pos() / parent->contentsScale()).toPoint(), event->button(), event->buttons(), 0);
121    emit doubleClick(event->pos().x(), event->pos().y());
122    delete me;
123}
124
125void GraphicsWebView::timerEvent(QTimerEvent* event)
126{
127    if (event->timerId() == pressTimer.timerId()) {
128        pressTimer.stop();
129        grabMouse();
130        parent->setKeepMouseGrab(true);
131    }
132}
133
134void GraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
135{
136    if (pressTimer.isActive()) {
137        if ((event->pos() - pressPoint).manhattanLength() > QApplication::startDragDistance())
138            pressTimer.stop();
139    }
140    if (parent->keepMouseGrab())
141        QGraphicsWebView::mouseMoveEvent(event);
142}
143
144bool GraphicsWebView::sceneEvent(QEvent *event)
145{
146    bool rv = QGraphicsWebView::sceneEvent(event);
147    if (event->type() == QEvent::UngrabMouse) {
148        pressTimer.stop();
149        parent->setKeepMouseGrab(false);
150    }
151    return rv;
152}
153
154/*!
155    \qmlclass WebView QDeclarativeWebView
156    \ingroup qml-view-elements
157    \since 4.7
158    \brief The WebView item allows you to add Web content to a canvas.
159    \inherits Item
160
161    A WebView renders Web content based on a URL.
162
163    This type is made available by importing the \c QtWebKit module:
164
165    \bold{import QtWebKit 1.0}
166
167    The WebView item includes no scrolling, scaling, toolbars, or other common browser
168    components. These must be implemented around WebView. See the \l{QML Web Browser}
169    example for a demonstration of this.
170
171    The page to be displayed by the item is specified using the \l url property,
172    and this can be changed to fetch and display a new page. While the page loads,
173    the \l progress property is updated to indicate how much of the page has been
174    loaded.
175
176    \section1 Appearance
177
178    If the width and height of the item is not set, they will dynamically adjust
179    to a size appropriate for the content. This width may be large for typical
180    online web pages, typically greater than 800 by 600 pixels.
181
182    If the \l{Item::}{width} or \l{Item::}{height} is explictly set, the rendered Web site will be
183    clipped, not scaled, to fit into the set dimensions.
184
185    If the preferredWidth property is set, the width will be this amount or larger,
186    usually laying out the Web content to fit the preferredWidth.
187
188    The appearance of the content can be controlled to a certain extent by changing
189    the settings.standardFontFamily property and other settings related to fonts.
190
191    The page can be zoomed by calling the heuristicZoom() method, which performs a
192    series of tests to determine whether zoomed content will be displayed in an
193    appropriate way in the space allocated to the item.
194
195    \section1 User Interaction and Navigation
196
197    By default, certain mouse and touch events are delivered to other items in
198    preference to the Web content. For example, when a scrolling view is created
199    by placing a WebView in a Flickable, move events are delivered to the Flickable
200    so that the user can scroll the page. This prevents the user from accidentally
201    selecting text in a Web page instead of scrolling.
202
203    The pressGrabTime property defines the time the user must touch or press a
204    mouse button over the WebView before the Web content will receive the move
205    events it needs to select text and images.
206
207    When this item has keyboard focus, all keyboard input will be sent directly to
208    the Web page within.
209
210    When the navigates by clicking on links, the item records the pages visited
211    in its internal history
212
213    Because this item is designed to be used as a component in a browser, it
214    exposes \l{Action}{actions} for \l back, \l forward, \l reload and \l stop.
215    These can be triggered to change the current page displayed by the item.
216
217    \section1 Example Usage
218
219    \beginfloatright
220    \inlineimage webview.png
221    \endfloat
222
223    The following example displays a scaled down Web page at a fixed size.
224
225    \snippet doc/src/snippets/declarative/webview/webview.qml document
226
227    \clearfloat
228
229    \sa {declarative/modelviews/webview}{WebView example}, {demos/declarative/webbrowser}{Web Browser demo}
230*/
231
232/*!
233    \internal
234    \class QDeclarativeWebView
235    \brief The QDeclarativeWebView class allows you to add web content to a QDeclarativeView.
236
237    A WebView renders web content base on a URL.
238
239    \image webview.png
240
241    The item includes no scrolling, scaling,
242    toolbars, etc., those must be implemented around WebView. See the WebBrowser example
243    for a demonstration of this.
244
245    A QDeclarativeWebView object can be instantiated in Qml using the tag \l WebView.
246*/
247
248QDeclarativeWebView::QDeclarativeWebView(QDeclarativeItem *parent) : QDeclarativeItem(parent)
249{
250    init();
251}
252
253QDeclarativeWebView::~QDeclarativeWebView()
254{
255    delete d;
256}
257
258void QDeclarativeWebView::init()
259{
260    d = new QDeclarativeWebViewPrivate(this);
261
262    if (QWebSettings::iconDatabasePath().isNull() &&
263        QWebSettings::globalSettings()->localStoragePath().isNull() &&
264        QWebSettings::offlineStoragePath().isNull() &&
265        QWebSettings::offlineWebApplicationCachePath().isNull())
266        QWebSettings::enablePersistentStorage();
267
268    setAcceptedMouseButtons(Qt::LeftButton);
269    setFlag(QGraphicsItem::ItemHasNoContents, true);
270    setFlag(QGraphicsItem::ItemIsFocusScope, true);
271    setClip(true);
272
273    d->view = new GraphicsWebView(this);
274    d->view->setResizesToContents(true);
275    d->view->setFocus();
276    QWebPage* wp = new QDeclarativeWebPage(this);
277    setPage(wp);
278    connect(d->view, SIGNAL(geometryChanged()), this, SLOT(updateDeclarativeWebViewSize()));
279    connect(d->view, SIGNAL(doubleClick(int, int)), this, SIGNAL(doubleClick(int, int)));
280    connect(d->view, SIGNAL(scaleChanged()), this, SIGNAL(contentsScaleChanged()));
281}
282
283void QDeclarativeWebView::componentComplete()
284{
285    QDeclarativeItem::componentComplete();
286    page()->setNetworkAccessManager(qmlEngine(this)->networkAccessManager());
287
288    switch (d->pending) {
289    case QDeclarativeWebViewPrivate::PendingUrl:
290        setUrl(d->pendingUrl);
291        break;
292    case QDeclarativeWebViewPrivate::PendingHtml:
293        setHtml(d->pendingString, d->pendingUrl);
294        break;
295    case QDeclarativeWebViewPrivate::PendingContent:
296        setContent(d->pendingData, d->pendingString, d->pendingUrl);
297        break;
298    default:
299        break;
300    }
301    d->pending = QDeclarativeWebViewPrivate::PendingNone;
302    d->updateWindowObjects();
303}
304
305QDeclarativeWebView::Status QDeclarativeWebView::status() const
306{
307    return d->status;
308}
309
310
311/*!
312    \qmlproperty real WebView::progress
313    This property holds the progress of loading the current URL, from 0 to 1.
314
315    If you just want to know when progress gets to 1, use
316    WebView::onLoadFinished() or WebView::onLoadFailed() instead.
317*/
318qreal QDeclarativeWebView::progress() const
319{
320    return d->progress;
321}
322
323void QDeclarativeWebView::doLoadStarted()
324{
325    if (!d->url.isEmpty()) {
326        d->status = Loading;
327        emit statusChanged(d->status);
328    }
329    emit loadStarted();
330}
331
332void QDeclarativeWebView::doLoadProgress(int p)
333{
334    if (d->progress == p / 100.0)
335        return;
336    d->progress = p / 100.0;
337    emit progressChanged();
338}
339
340void QDeclarativeWebView::pageUrlChanged()
341{
342    updateContentsSize();
343
344    if ((d->url.isEmpty() && page()->mainFrame()->url() != QUrl(QLatin1String("about:blank")))
345        || (d->url != page()->mainFrame()->url() && !page()->mainFrame()->url().isEmpty()))
346    {
347        d->url = page()->mainFrame()->url();
348        if (d->url == QUrl(QLatin1String("about:blank")))
349            d->url = QUrl();
350        emit urlChanged();
351    }
352}
353
354void QDeclarativeWebView::doLoadFinished(bool ok)
355{
356    if (ok) {
357        d->status = d->url.isEmpty() ? Null : Ready;
358        emit loadFinished();
359    } else {
360        d->status = Error;
361        emit loadFailed();
362    }
363    emit statusChanged(d->status);
364}
365
366/*!
367    \qmlproperty url WebView::url
368    This property holds the URL to the page displayed in this item. It can be set,
369    but also can change spontaneously (eg. because of network redirection).
370
371    If the url is empty, the page is blank.
372
373    The url is always absolute (QML will resolve relative URL strings in the context
374    of the containing QML document).
375*/
376QUrl QDeclarativeWebView::url() const
377{
378    return d->url;
379}
380
381void QDeclarativeWebView::setUrl(const QUrl& url)
382{
383    if (url == d->url)
384        return;
385
386    if (isComponentComplete()) {
387        d->url = url;
388        updateContentsSize();
389        QUrl seturl = url;
390        if (seturl.isEmpty())
391            seturl = QUrl(QLatin1String("about:blank"));
392
393        Q_ASSERT(!seturl.isRelative());
394
395        page()->mainFrame()->load(seturl);
396
397        emit urlChanged();
398    } else {
399        d->pending = d->PendingUrl;
400        d->pendingUrl = url;
401    }
402}
403
404/*!
405    \qmlproperty int WebView::preferredWidth
406    This property holds the ideal width for displaying the current URL.
407*/
408int QDeclarativeWebView::preferredWidth() const
409{
410    return d->preferredwidth;
411}
412
413void QDeclarativeWebView::setPreferredWidth(int width)
414{
415    if (d->preferredwidth == width)
416        return;
417    d->preferredwidth = width;
418    updateContentsSize();
419    emit preferredWidthChanged();
420}
421
422/*!
423    \qmlproperty int WebView::preferredHeight
424    This property holds the ideal height for displaying the current URL.
425    This only affects the area zoomed by heuristicZoom().
426*/
427int QDeclarativeWebView::preferredHeight() const
428{
429    return d->preferredheight;
430}
431
432void QDeclarativeWebView::setPreferredHeight(int height)
433{
434    if (d->preferredheight == height)
435        return;
436    d->preferredheight = height;
437    updateContentsSize();
438    emit preferredHeightChanged();
439}
440
441/*!
442    \qmlmethod bool WebView::evaluateJavaScript(string scriptSource)
443
444    Evaluates the \a scriptSource JavaScript inside the context of the
445    main web frame, and returns the result of the last executed statement.
446
447    Note that this JavaScript does \e not have any access to QML objects
448    except as made available as windowObjects.
449*/
450QVariant QDeclarativeWebView::evaluateJavaScript(const QString& scriptSource)
451{
452    return this->page()->mainFrame()->evaluateJavaScript(scriptSource);
453}
454
455void QDeclarativeWebView::updateDeclarativeWebViewSize()
456{
457    QSizeF size = d->view->geometry().size() * contentsScale();
458    setImplicitWidth(size.width());
459    setImplicitHeight(size.height());
460}
461
462void QDeclarativeWebView::initialLayout()
463{
464    // nothing useful to do at this point
465}
466
467void QDeclarativeWebView::updateContentsSize()
468{
469    if (page()) {
470        page()->setPreferredContentsSize(QSize(
471            d->preferredwidth>0 ? d->preferredwidth : width(),
472            d->preferredheight>0 ? d->preferredheight : height()));
473    }
474}
475
476void QDeclarativeWebView::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
477{
478    QWebPage* webPage = page();
479    if (newGeometry.size() != oldGeometry.size() && webPage) {
480        QSize contentSize = webPage->preferredContentsSize();
481        if (widthValid())
482            contentSize.setWidth(width());
483        if (heightValid())
484            contentSize.setHeight(height());
485        if (contentSize != webPage->preferredContentsSize())
486            webPage->setPreferredContentsSize(contentSize);
487    }
488    QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
489}
490
491/*!
492    \qmlproperty list<object> WebView::javaScriptWindowObjects
493
494    A list of QML objects to expose to the web page.
495
496    Each object will be added as a property of the web frame's window object.  The
497    property name is controlled by the value of \c WebView.windowObjectName
498    attached property.
499
500    Exposing QML objects to a web page allows JavaScript executing in the web
501    page itself to communicate with QML, by reading and writing properties and
502    by calling methods of the exposed QML objects.
503
504    This example shows how to call into a QML method using a window object.
505
506    \qml
507    WebView {
508        javaScriptWindowObjects: QtObject {
509            WebView.windowObjectName: "qml"
510
511            function qmlCall() {
512                console.log("This call is in QML!");
513            }
514        }
515
516        html: "<script>console.log(\"This is in WebKit!\"); window.qml.qmlCall();</script>"
517    }
518    \endqml
519
520    The output of the example will be:
521    \code
522    This is in WebKit!
523    This call is in QML!
524    \endcode
525
526    If Javascript is not enabled for the page, then this property does nothing.
527*/
528QDeclarativeListProperty<QObject> QDeclarativeWebView::javaScriptWindowObjects()
529{
530    return QDeclarativeListProperty<QObject>(this, d, &QDeclarativeWebViewPrivate::windowObjectsAppend);
531}
532
533QDeclarativeWebViewAttached* QDeclarativeWebView::qmlAttachedProperties(QObject* o)
534{
535    return new QDeclarativeWebViewAttached(o);
536}
537
538void QDeclarativeWebViewPrivate::updateWindowObjects()
539{
540    if (!q->isComponentCompletePublic() || !q->page())
541        return;
542
543    for (int i = 0; i < windowObjects.count(); ++i) {
544        QObject* object = windowObjects.at(i);
545        QDeclarativeWebViewAttached* attached = static_cast<QDeclarativeWebViewAttached *>(qmlAttachedPropertiesObject<QDeclarativeWebView>(object));
546        if (attached && !attached->windowObjectName().isEmpty())
547            q->page()->mainFrame()->addToJavaScriptWindowObject(attached->windowObjectName(), object);
548    }
549}
550
551bool QDeclarativeWebView::renderingEnabled() const
552{
553    return d->rendering;
554}
555
556void QDeclarativeWebView::setRenderingEnabled(bool enabled)
557{
558    if (d->rendering == enabled)
559        return;
560    d->rendering = enabled;
561    emit renderingEnabledChanged();
562    d->view->setTiledBackingStoreFrozen(!enabled);
563}
564
565/*!
566    \qmlsignal WebView::onDoubleClick(int clickx, int clicky)
567
568    The WebView does not pass double-click events to the web engine, but rather
569    emits this signals.
570*/
571
572/*!
573    \qmlmethod bool WebView::heuristicZoom(int clickX, int clickY, real maxzoom)
574
575    Finds a zoom that:
576    \list
577    \i shows a whole item
578    \i includes (\a clickX, \a clickY)
579    \i fits into the preferredWidth and preferredHeight
580    \i zooms by no more than \a maxZoom
581    \i is more than 10% above the current zoom
582    \endlist
583
584    If such a zoom exists, emits zoomTo(zoom,centerX,centerY) and returns true; otherwise,
585    no signal is emitted and returns false.
586*/
587bool QDeclarativeWebView::heuristicZoom(int clickX, int clickY, qreal maxZoom)
588{
589    if (contentsScale() >= maxZoom / scale())
590        return false;
591    qreal ozf = contentsScale();
592    QRect showArea = elementAreaAt(clickX, clickY, d->preferredwidth / maxZoom, d->preferredheight / maxZoom);
593    qreal z = qMin(qreal(d->preferredwidth) / showArea.width(), qreal(d->preferredheight) / showArea.height());
594    if (z > maxZoom / scale())
595        z = maxZoom / scale();
596    if (z / ozf > 1.2) {
597        QRectF r(showArea.left() * z, showArea.top() * z, showArea.width() * z, showArea.height() * z);
598        emit zoomTo(z, r.x() + r.width() / 2, r.y() + r.height() / 2);
599        return true;
600    }
601    return false;
602}
603
604/*!
605    \qmlproperty int WebView::pressGrabTime
606
607    The number of milliseconds the user must press before the WebView
608    starts passing move events through to the Web engine (rather than
609    letting other QML elements such as a Flickable take them).
610
611    Defaults to 400ms. Set to 0 to always grab and pass move events to
612    the Web engine.
613*/
614int QDeclarativeWebView::pressGrabTime() const
615{
616    return d->view->pressTime;
617}
618
619void QDeclarativeWebView::setPressGrabTime(int millis)
620{
621    if (d->view->pressTime == millis)
622        return;
623    d->view->pressTime = millis;
624    emit pressGrabTimeChanged();
625}
626
627#ifndef QT_NO_ACTION
628/*!
629    \qmlproperty action WebView::back
630    This property holds the action for causing the previous URL in the history to be displayed.
631*/
632QAction* QDeclarativeWebView::backAction() const
633{
634    return page()->action(QWebPage::Back);
635}
636
637/*!
638    \qmlproperty action WebView::forward
639    This property holds the action for causing the next URL in the history to be displayed.
640*/
641QAction* QDeclarativeWebView::forwardAction() const
642{
643    return page()->action(QWebPage::Forward);
644}
645
646/*!
647    \qmlproperty action WebView::reload
648    This property holds the action for reloading with the current URL
649*/
650QAction* QDeclarativeWebView::reloadAction() const
651{
652    return page()->action(QWebPage::Reload);
653}
654
655/*!
656    \qmlproperty action WebView::stop
657    This property holds the action for stopping loading with the current URL
658*/
659QAction* QDeclarativeWebView::stopAction() const
660{
661    return page()->action(QWebPage::Stop);
662}
663#endif // QT_NO_ACTION
664
665/*!
666    \qmlproperty string WebView::title
667    This property holds the title of the web page currently viewed
668
669    By default, this property contains an empty string.
670*/
671QString QDeclarativeWebView::title() const
672{
673    return page()->mainFrame()->title();
674}
675
676/*!
677    \qmlproperty pixmap WebView::icon
678    This property holds the icon associated with the web page currently viewed
679*/
680QPixmap QDeclarativeWebView::icon() const
681{
682    return page()->mainFrame()->icon().pixmap(QSize(256, 256));
683}
684
685/*!
686    \qmlproperty string WebView::statusText
687
688    This property is the current status suggested by the current web page. In a web browser,
689    such status is often shown in some kind of status bar.
690*/
691void QDeclarativeWebView::setStatusText(const QString& text)
692{
693    d->statusText = text;
694    emit statusTextChanged();
695}
696
697void QDeclarativeWebView::windowObjectCleared()
698{
699    d->updateWindowObjects();
700}
701
702QString QDeclarativeWebView::statusText() const
703{
704    return d->statusText;
705}
706
707QWebPage* QDeclarativeWebView::page() const
708{
709    return d->view->page();
710}
711
712// The QObject interface to settings().
713/*!
714    \qmlproperty string WebView::settings.standardFontFamily
715    \qmlproperty string WebView::settings.fixedFontFamily
716    \qmlproperty string WebView::settings.serifFontFamily
717    \qmlproperty string WebView::settings.sansSerifFontFamily
718    \qmlproperty string WebView::settings.cursiveFontFamily
719    \qmlproperty string WebView::settings.fantasyFontFamily
720
721    \qmlproperty int WebView::settings.minimumFontSize
722    \qmlproperty int WebView::settings.minimumLogicalFontSize
723    \qmlproperty int WebView::settings.defaultFontSize
724    \qmlproperty int WebView::settings.defaultFixedFontSize
725
726    \qmlproperty bool WebView::settings.autoLoadImages
727    \qmlproperty bool WebView::settings.javascriptEnabled
728    \qmlproperty bool WebView::settings.javaEnabled
729    \qmlproperty bool WebView::settings.pluginsEnabled
730    \qmlproperty bool WebView::settings.privateBrowsingEnabled
731    \qmlproperty bool WebView::settings.javascriptCanOpenWindows
732    \qmlproperty bool WebView::settings.javascriptCanAccessClipboard
733    \qmlproperty bool WebView::settings.developerExtrasEnabled
734    \qmlproperty bool WebView::settings.linksIncludedInFocusChain
735    \qmlproperty bool WebView::settings.zoomTextOnly
736    \qmlproperty bool WebView::settings.printElementBackgrounds
737    \qmlproperty bool WebView::settings.offlineStorageDatabaseEnabled
738    \qmlproperty bool WebView::settings.offlineWebApplicationCacheEnabled
739    \qmlproperty bool WebView::settings.localStorageDatabaseEnabled
740    \qmlproperty bool WebView::settings.localContentCanAccessRemoteUrls
741
742    These properties give access to the settings controlling the web view.
743
744    See QWebSettings for details of these properties.
745
746    \qml
747    WebView {
748        settings.pluginsEnabled: true
749        settings.standardFontFamily: "Arial"
750        // ...
751    }
752    \endqml
753*/
754QDeclarativeWebSettings* QDeclarativeWebView::settingsObject() const
755{
756    d->settings.s = page()->settings();
757    return &d->settings;
758}
759
760void QDeclarativeWebView::setPage(QWebPage* page)
761{
762    if (d->view->page() == page)
763        return;
764
765    d->view->setPage(page);
766    updateContentsSize();
767    page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
768    page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
769    connect(page->mainFrame(), SIGNAL(urlChanged(QUrl)), this, SLOT(pageUrlChanged()));
770    connect(page->mainFrame(), SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged(QString)));
771    connect(page->mainFrame(), SIGNAL(titleChanged(QString)), this, SIGNAL(iconChanged()));
772    connect(page->mainFrame(), SIGNAL(iconChanged()), this, SIGNAL(iconChanged()));
773    connect(page->mainFrame(), SIGNAL(initialLayoutCompleted()), this, SLOT(initialLayout()));
774    connect(page->mainFrame(), SIGNAL(contentsSizeChanged(QSize)), this, SIGNAL(contentsSizeChanged(QSize)));
775
776    connect(page, SIGNAL(loadStarted()), this, SLOT(doLoadStarted()));
777    connect(page, SIGNAL(loadProgress(int)), this, SLOT(doLoadProgress(int)));
778    connect(page, SIGNAL(loadFinished(bool)), this, SLOT(doLoadFinished(bool)));
779    connect(page, SIGNAL(statusBarMessage(QString)), this, SLOT(setStatusText(QString)));
780
781    connect(page->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(windowObjectCleared()));
782
783    page->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, true);
784
785}
786
787/*!
788    \qmlsignal WebView::onLoadStarted()
789
790    This handler is called when the web engine begins loading
791    a page. Later, WebView::onLoadFinished() or WebView::onLoadFailed()
792    will be emitted.
793*/
794
795/*!
796    \qmlsignal WebView::onLoadFinished()
797
798    This handler is called when the web engine \e successfully
799    finishes loading a page, including any component content
800    (WebView::onLoadFailed() will be emitted otherwise).
801
802    \sa progress
803*/
804
805/*!
806    \qmlsignal WebView::onLoadFailed()
807
808    This handler is called when the web engine fails loading
809    a page or any component content
810    (WebView::onLoadFinished() will be emitted on success).
811*/
812
813void QDeclarativeWebView::load(const QNetworkRequest& request, QNetworkAccessManager::Operation operation, const QByteArray& body)
814{
815    page()->mainFrame()->load(request, operation, body);
816}
817
818QString QDeclarativeWebView::html() const
819{
820    return page()->mainFrame()->toHtml();
821}
822
823/*!
824    \qmlproperty string WebView::html
825    This property holds HTML text set directly
826
827    The html property can be set as a string.
828
829    \qml
830    WebView {
831        html: "<p>This is <b>HTML</b>."
832    }
833    \endqml
834*/
835void QDeclarativeWebView::setHtml(const QString& html, const QUrl& baseUrl)
836{
837    updateContentsSize();
838    if (isComponentComplete())
839        page()->mainFrame()->setHtml(html, baseUrl);
840    else {
841        d->pending = d->PendingHtml;
842        d->pendingUrl = baseUrl;
843        d->pendingString = html;
844    }
845    emit htmlChanged();
846}
847
848void QDeclarativeWebView::setContent(const QByteArray& data, const QString& mimeType, const QUrl& baseUrl)
849{
850    updateContentsSize();
851
852    if (isComponentComplete())
853        page()->mainFrame()->setContent(data, mimeType, qmlContext(this)->resolvedUrl(baseUrl));
854    else {
855        d->pending = d->PendingContent;
856        d->pendingUrl = baseUrl;
857        d->pendingString = mimeType;
858        d->pendingData = data;
859    }
860}
861
862QWebHistory* QDeclarativeWebView::history() const
863{
864    return page()->history();
865}
866
867QWebSettings* QDeclarativeWebView::settings() const
868{
869    return page()->settings();
870}
871
872QDeclarativeWebView* QDeclarativeWebView::createWindow(QWebPage::WebWindowType type)
873{
874    switch (type) {
875    case QWebPage::WebBrowserWindow: {
876        if (!d->newWindowComponent && d->newWindowParent)
877            qWarning("WebView::newWindowComponent not set - WebView::newWindowParent ignored");
878        else if (d->newWindowComponent && !d->newWindowParent)
879            qWarning("WebView::newWindowParent not set - WebView::newWindowComponent ignored");
880        else if (d->newWindowComponent && d->newWindowParent) {
881            QDeclarativeWebView* webview = 0;
882            QDeclarativeContext* windowContext = new QDeclarativeContext(qmlContext(this));
883
884            QObject* newObject = d->newWindowComponent->create(windowContext);
885            if (newObject) {
886                windowContext->setParent(newObject);
887                QDeclarativeItem* item = qobject_cast<QDeclarativeItem *>(newObject);
888                if (!item)
889                    delete newObject;
890                else {
891                    webview = item->findChild<QDeclarativeWebView*>();
892                    if (!webview)
893                        delete item;
894                    else {
895                        newObject->setParent(d->newWindowParent);
896                        static_cast<QGraphicsObject*>(item)->setParentItem(d->newWindowParent);
897                    }
898                }
899            } else
900                delete windowContext;
901
902            return webview;
903        }
904    }
905    break;
906    case QWebPage::WebModalDialog: {
907        // Not supported
908    }
909    }
910    return 0;
911}
912
913/*!
914    \qmlproperty component WebView::newWindowComponent
915
916    This property holds the component to use for new windows.
917    The component must have a WebView somewhere in its structure.
918
919    When the web engine requests a new window, it will be an instance of
920    this component.
921
922    The parent of the new window is set by newWindowParent. It must be set.
923*/
924QDeclarativeComponent* QDeclarativeWebView::newWindowComponent() const
925{
926    return d->newWindowComponent;
927}
928
929void QDeclarativeWebView::setNewWindowComponent(QDeclarativeComponent* newWindow)
930{
931    if (newWindow == d->newWindowComponent)
932        return;
933    d->newWindowComponent = newWindow;
934    emit newWindowComponentChanged();
935}
936
937
938/*!
939    \qmlproperty item WebView::newWindowParent
940
941    The parent item for new windows.
942
943    \sa newWindowComponent
944*/
945QDeclarativeItem* QDeclarativeWebView::newWindowParent() const
946{
947    return d->newWindowParent;
948}
949
950void QDeclarativeWebView::setNewWindowParent(QDeclarativeItem* parent)
951{
952    if (parent == d->newWindowParent)
953        return;
954    if (d->newWindowParent && parent) {
955        QList<QGraphicsItem *> children = d->newWindowParent->childItems();
956        for (int i = 0; i < children.count(); ++i)
957            children.at(i)->setParentItem(parent);
958    }
959    d->newWindowParent = parent;
960    emit newWindowParentChanged();
961}
962
963QSize QDeclarativeWebView::contentsSize() const
964{
965    return page()->mainFrame()->contentsSize() * contentsScale();
966}
967
968qreal QDeclarativeWebView::contentsScale() const
969{
970    return d->view->scale();
971}
972
973void QDeclarativeWebView::setContentsScale(qreal scale)
974{
975    if (scale == d->view->scale())
976        return;
977    d->view->setScale(scale);
978    updateDeclarativeWebViewSize();
979    emit contentsScaleChanged();
980}
981
982/*!
983    Returns the area of the largest element at position (\a x,\a y) that is no larger
984    than \a maxWidth by \a maxHeight pixels.
985
986    May return an area larger in the case when no smaller element is at the position.
987*/
988QRect QDeclarativeWebView::elementAreaAt(int x, int y, int maxWidth, int maxHeight) const
989{
990    QWebHitTestResult hit = page()->mainFrame()->hitTestContent(QPoint(x, y));
991    QRect hitRect = hit.boundingRect();
992    QWebElement element = hit.enclosingBlockElement();
993    if (maxWidth <= 0)
994        maxWidth = INT_MAX;
995    if (maxHeight <= 0)
996        maxHeight = INT_MAX;
997    while (!element.parent().isNull() && element.geometry().width() <= maxWidth && element.geometry().height() <= maxHeight) {
998        hitRect = element.geometry();
999        element = element.parent();
1000    }
1001    return hitRect;
1002}
1003
1004/*!
1005    \internal
1006    \class QDeclarativeWebPage
1007    \brief The QDeclarativeWebPage class is a QWebPage that can create QML plugins.
1008
1009    \sa QDeclarativeWebView
1010*/
1011QDeclarativeWebPage::QDeclarativeWebPage(QDeclarativeWebView* parent) :
1012    QWebPage(parent)
1013{
1014}
1015
1016QDeclarativeWebPage::~QDeclarativeWebPage()
1017{
1018}
1019
1020QString QDeclarativeWebPage::chooseFile(QWebFrame* originatingFrame, const QString& oldFile)
1021{
1022    // Not supported (it's modal)
1023    Q_UNUSED(originatingFrame)
1024    Q_UNUSED(oldFile)
1025    return oldFile;
1026}
1027
1028/*!
1029    \qmlsignal WebView::onAlert(string message)
1030
1031    The handler is called when the web engine sends a JavaScript alert. The \a message is the text
1032    to be displayed in the alert to the user.
1033*/
1034
1035
1036void QDeclarativeWebPage::javaScriptAlert(QWebFrame* originatingFrame, const QString& msg)
1037{
1038    Q_UNUSED(originatingFrame)
1039    emit viewItem()->alert(msg);
1040}
1041
1042bool QDeclarativeWebPage::javaScriptConfirm(QWebFrame* originatingFrame, const QString& msg)
1043{
1044    // Not supported (it's modal)
1045    Q_UNUSED(originatingFrame)
1046    Q_UNUSED(msg)
1047    return false;
1048}
1049
1050bool QDeclarativeWebPage::javaScriptPrompt(QWebFrame* originatingFrame, const QString& msg, const QString& defaultValue, QString* result)
1051{
1052    // Not supported (it's modal)
1053    Q_UNUSED(originatingFrame)
1054    Q_UNUSED(msg)
1055    Q_UNUSED(defaultValue)
1056    Q_UNUSED(result)
1057    return false;
1058}
1059
1060
1061QDeclarativeWebView* QDeclarativeWebPage::viewItem()
1062{
1063    return static_cast<QDeclarativeWebView*>(parent());
1064}
1065
1066QWebPage* QDeclarativeWebPage::createWindow(WebWindowType type)
1067{
1068    QDeclarativeWebView* newView = viewItem()->createWindow(type);
1069    if (newView)
1070        return newView->page();
1071    return 0;
1072}
1073
1074QT_END_NAMESPACE
1075
1076