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