2011-03-10 Alexis Menard <alexis.menard@openbossa.org>
[WebKit-https.git] / Source / 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 "qwebelement.h"
35 #include "qwebframe.h"
36 #include "qwebpage.h"
37 #include "qwebsettings.h"
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     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
110 void GraphicsWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
111 {
112     QGraphicsWebView::mouseReleaseEvent(event);
113     pressTimer.stop();
114     parent->setKeepMouseGrab(false);
115     ungrabMouse();
116 }
117
118 void 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
125 void GraphicsWebView::timerEvent(QTimerEvent* event)
126 {
127     if (event->timerId() == pressTimer.timerId()) {
128         pressTimer.stop();
129         grabMouse();
130         parent->setKeepMouseGrab(true);
131     }
132 }
133
134 void 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
144 bool 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
248 QDeclarativeWebView::QDeclarativeWebView(QDeclarativeItem *parent) : QDeclarativeItem(parent)
249 {
250     init();
251 }
252
253 QDeclarativeWebView::~QDeclarativeWebView()
254 {
255     delete d;
256 }
257
258 void 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     if (!preferredWidth())
279         setPreferredWidth(d->view->preferredWidth());
280     if (!preferredHeight())
281         setPreferredHeight(d->view->preferredHeight());
282     connect(d->view, SIGNAL(geometryChanged()), this, SLOT(updateDeclarativeWebViewSize()));
283     connect(d->view, SIGNAL(doubleClick(int, int)), this, SIGNAL(doubleClick(int, int)));
284     connect(d->view, SIGNAL(scaleChanged()), this, SIGNAL(contentsScaleChanged()));
285 }
286
287 void QDeclarativeWebView::componentComplete()
288 {
289     QDeclarativeItem::componentComplete();
290     page()->setNetworkAccessManager(qmlEngine(this)->networkAccessManager());
291
292     switch (d->pending) {
293     case QDeclarativeWebViewPrivate::PendingUrl:
294         setUrl(d->pendingUrl);
295         break;
296     case QDeclarativeWebViewPrivate::PendingHtml:
297         setHtml(d->pendingString, d->pendingUrl);
298         break;
299     case QDeclarativeWebViewPrivate::PendingContent:
300         setContent(d->pendingData, d->pendingString, d->pendingUrl);
301         break;
302     default:
303         break;
304     }
305     d->pending = QDeclarativeWebViewPrivate::PendingNone;
306     d->updateWindowObjects();
307 }
308
309 QDeclarativeWebView::Status QDeclarativeWebView::status() const
310 {
311     return d->status;
312 }
313
314
315 /*!
316     \qmlproperty real WebView::progress
317     This property holds the progress of loading the current URL, from 0 to 1.
318
319     If you just want to know when progress gets to 1, use
320     WebView::onLoadFinished() or WebView::onLoadFailed() instead.
321 */
322 qreal QDeclarativeWebView::progress() const
323 {
324     return d->progress;
325 }
326
327 void QDeclarativeWebView::doLoadStarted()
328 {
329     if (!d->url.isEmpty()) {
330         d->status = Loading;
331         emit statusChanged(d->status);
332     }
333     emit loadStarted();
334 }
335
336 void QDeclarativeWebView::doLoadProgress(int p)
337 {
338     if (d->progress == p / 100.0)
339         return;
340     d->progress = p / 100.0;
341     emit progressChanged();
342 }
343
344 void QDeclarativeWebView::pageUrlChanged()
345 {
346     updateContentsSize();
347
348     if ((d->url.isEmpty() && page()->mainFrame()->url() != QUrl(QLatin1String("about:blank")))
349         || (d->url != page()->mainFrame()->url() && !page()->mainFrame()->url().isEmpty()))
350     {
351         d->url = page()->mainFrame()->url();
352         if (d->url == QUrl(QLatin1String("about:blank")))
353             d->url = QUrl();
354         emit urlChanged();
355     }
356 }
357
358 void QDeclarativeWebView::doLoadFinished(bool ok)
359 {
360     if (ok) {
361         d->status = d->url.isEmpty() ? Null : Ready;
362         emit loadFinished();
363     } else {
364         d->status = Error;
365         emit loadFailed();
366     }
367     emit statusChanged(d->status);
368 }
369
370 /*!
371     \qmlproperty url WebView::url
372     This property holds the URL to the page displayed in this item. It can be set,
373     but also can change spontaneously (eg. because of network redirection).
374
375     If the url is empty, the page is blank.
376
377     The url is always absolute (QML will resolve relative URL strings in the context
378     of the containing QML document).
379 */
380 QUrl QDeclarativeWebView::url() const
381 {
382     return d->url;
383 }
384
385 void QDeclarativeWebView::setUrl(const QUrl& url)
386 {
387     if (url == d->url)
388         return;
389
390     if (isComponentComplete()) {
391         d->url = url;
392         updateContentsSize();
393         QUrl seturl = url;
394         if (seturl.isEmpty())
395             seturl = QUrl(QLatin1String("about:blank"));
396
397         Q_ASSERT(!seturl.isRelative());
398
399         page()->mainFrame()->load(seturl);
400
401         emit urlChanged();
402     } else {
403         d->pending = d->PendingUrl;
404         d->pendingUrl = url;
405     }
406 }
407
408 /*!
409     \qmlproperty int WebView::preferredWidth
410     This property holds the ideal width for displaying the current URL.
411 */
412 int QDeclarativeWebView::preferredWidth() const
413 {
414     return d->preferredwidth;
415 }
416
417 void QDeclarativeWebView::setPreferredWidth(int width)
418 {
419     if (d->preferredwidth == width)
420         return;
421     d->preferredwidth = width;
422     updateContentsSize();
423     emit preferredWidthChanged();
424 }
425
426 /*!
427     \qmlproperty int WebView::preferredHeight
428     This property holds the ideal height for displaying the current URL.
429     This only affects the area zoomed by heuristicZoom().
430 */
431 int QDeclarativeWebView::preferredHeight() const
432 {
433     return d->preferredheight;
434 }
435
436 void QDeclarativeWebView::setPreferredHeight(int height)
437 {
438     if (d->preferredheight == height)
439         return;
440     d->preferredheight = height;
441     updateContentsSize();
442     emit preferredHeightChanged();
443 }
444
445 /*!
446     \qmlmethod bool WebView::evaluateJavaScript(string scriptSource)
447
448     Evaluates the \a scriptSource JavaScript inside the context of the
449     main web frame, and returns the result of the last executed statement.
450
451     Note that this JavaScript does \e not have any access to QML objects
452     except as made available as windowObjects.
453 */
454 QVariant QDeclarativeWebView::evaluateJavaScript(const QString& scriptSource)
455 {
456     return this->page()->mainFrame()->evaluateJavaScript(scriptSource);
457 }
458
459 void QDeclarativeWebView::updateDeclarativeWebViewSize()
460 {
461     QSizeF size = d->view->geometry().size() * contentsScale();
462     setImplicitWidth(size.width());
463     setImplicitHeight(size.height());
464 }
465
466 void QDeclarativeWebView::initialLayout()
467 {
468     // nothing useful to do at this point
469 }
470
471 void QDeclarativeWebView::updateContentsSize()
472 {
473     if (page()) {
474         page()->setPreferredContentsSize(QSize(
475             d->preferredwidth>0 ? d->preferredwidth : width(),
476             d->preferredheight>0 ? d->preferredheight : height()));
477     }
478 }
479
480 void QDeclarativeWebView::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
481 {
482     QWebPage* webPage = page();
483     if (newGeometry.size() != oldGeometry.size() && webPage) {
484         QSize contentSize = webPage->preferredContentsSize();
485         if (widthValid())
486             contentSize.setWidth(width());
487         if (heightValid())
488             contentSize.setHeight(height());
489         if (contentSize != webPage->preferredContentsSize())
490             webPage->setPreferredContentsSize(contentSize);
491     }
492     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
493 }
494
495 /*!
496     \qmlproperty list<object> WebView::javaScriptWindowObjects
497
498     A list of QML objects to expose to the web page.
499
500     Each object will be added as a property of the web frame's window object.  The
501     property name is controlled by the value of \c WebView.windowObjectName
502     attached property.
503
504     Exposing QML objects to a web page allows JavaScript executing in the web
505     page itself to communicate with QML, by reading and writing properties and
506     by calling methods of the exposed QML objects.
507
508     This example shows how to call into a QML method using a window object.
509
510     \qml
511     WebView {
512         javaScriptWindowObjects: QtObject {
513             WebView.windowObjectName: "qml"
514
515             function qmlCall() {
516                 console.log("This call is in QML!");
517             }
518         }
519
520         html: "<script>console.log(\"This is in WebKit!\"); window.qml.qmlCall();</script>"
521     }
522     \endqml
523
524     The output of the example will be:
525     \code
526     This is in WebKit!
527     This call is in QML!
528     \endcode
529
530     If Javascript is not enabled for the page, then this property does nothing.
531 */
532 QDeclarativeListProperty<QObject> QDeclarativeWebView::javaScriptWindowObjects()
533 {
534     return QDeclarativeListProperty<QObject>(this, d, &QDeclarativeWebViewPrivate::windowObjectsAppend);
535 }
536
537 QDeclarativeWebViewAttached* QDeclarativeWebView::qmlAttachedProperties(QObject* o)
538 {
539     return new QDeclarativeWebViewAttached(o);
540 }
541
542 void QDeclarativeWebViewPrivate::updateWindowObjects()
543 {
544     if (!q->isComponentCompletePublic() || !q->page())
545         return;
546
547     for (int i = 0; i < windowObjects.count(); ++i) {
548         QObject* object = windowObjects.at(i);
549         QDeclarativeWebViewAttached* attached = static_cast<QDeclarativeWebViewAttached *>(qmlAttachedPropertiesObject<QDeclarativeWebView>(object));
550         if (attached && !attached->windowObjectName().isEmpty())
551             q->page()->mainFrame()->addToJavaScriptWindowObject(attached->windowObjectName(), object);
552     }
553 }
554
555 bool QDeclarativeWebView::renderingEnabled() const
556 {
557     return d->rendering;
558 }
559
560 void QDeclarativeWebView::setRenderingEnabled(bool enabled)
561 {
562     if (d->rendering == enabled)
563         return;
564     d->rendering = enabled;
565     emit renderingEnabledChanged();
566     d->view->setTiledBackingStoreFrozen(!enabled);
567 }
568
569 /*!
570     \qmlsignal WebView::onDoubleClick(int clickx, int clicky)
571
572     The WebView does not pass double-click events to the web engine, but rather
573     emits this signals.
574 */
575
576 /*!
577     \qmlmethod bool WebView::heuristicZoom(int clickX, int clickY, real maxzoom)
578
579     Finds a zoom that:
580     \list
581     \i shows a whole item
582     \i includes (\a clickX, \a clickY)
583     \i fits into the preferredWidth and preferredHeight
584     \i zooms by no more than \a maxZoom
585     \i is more than 10% above the current zoom
586     \endlist
587
588     If such a zoom exists, emits zoomTo(zoom,centerX,centerY) and returns true; otherwise,
589     no signal is emitted and returns false.
590 */
591 bool QDeclarativeWebView::heuristicZoom(int clickX, int clickY, qreal maxZoom)
592 {
593     if (contentsScale() >= maxZoom / scale())
594         return false;
595     qreal ozf = contentsScale();
596     QRect showArea = elementAreaAt(clickX, clickY, d->preferredwidth / maxZoom, d->preferredheight / maxZoom);
597     qreal z = qMin(qreal(d->preferredwidth) / showArea.width(), qreal(d->preferredheight) / showArea.height());
598     if (z > maxZoom / scale())
599         z = maxZoom / scale();
600     if (z / ozf > 1.2) {
601         QRectF r(showArea.left() * z, showArea.top() * z, showArea.width() * z, showArea.height() * z);
602         emit zoomTo(z, r.x() + r.width() / 2, r.y() + r.height() / 2);
603         return true;
604     }
605     return false;
606 }
607
608 /*!
609     \qmlproperty int WebView::pressGrabTime
610
611     The number of milliseconds the user must press before the WebView
612     starts passing move events through to the Web engine (rather than
613     letting other QML elements such as a Flickable take them).
614
615     Defaults to 400ms. Set to 0 to always grab and pass move events to
616     the Web engine.
617 */
618 int QDeclarativeWebView::pressGrabTime() const
619 {
620     return d->view->pressTime;
621 }
622
623 void QDeclarativeWebView::setPressGrabTime(int millis)
624 {
625     if (d->view->pressTime == millis)
626         return;
627     d->view->pressTime = millis;
628     emit pressGrabTimeChanged();
629 }
630
631 #ifndef QT_NO_ACTION
632 /*!
633     \qmlproperty action WebView::back
634     This property holds the action for causing the previous URL in the history to be displayed.
635 */
636 QAction* QDeclarativeWebView::backAction() const
637 {
638     return page()->action(QWebPage::Back);
639 }
640
641 /*!
642     \qmlproperty action WebView::forward
643     This property holds the action for causing the next URL in the history to be displayed.
644 */
645 QAction* QDeclarativeWebView::forwardAction() const
646 {
647     return page()->action(QWebPage::Forward);
648 }
649
650 /*!
651     \qmlproperty action WebView::reload
652     This property holds the action for reloading with the current URL
653 */
654 QAction* QDeclarativeWebView::reloadAction() const
655 {
656     return page()->action(QWebPage::Reload);
657 }
658
659 /*!
660     \qmlproperty action WebView::stop
661     This property holds the action for stopping loading with the current URL
662 */
663 QAction* QDeclarativeWebView::stopAction() const
664 {
665     return page()->action(QWebPage::Stop);
666 }
667 #endif // QT_NO_ACTION
668
669 /*!
670     \qmlproperty string WebView::title
671     This property holds the title of the web page currently viewed
672
673     By default, this property contains an empty string.
674 */
675 QString QDeclarativeWebView::title() const
676 {
677     return page()->mainFrame()->title();
678 }
679
680 /*!
681     \qmlproperty pixmap WebView::icon
682     This property holds the icon associated with the web page currently viewed
683 */
684 QPixmap QDeclarativeWebView::icon() const
685 {
686     return page()->mainFrame()->icon().pixmap(QSize(256, 256));
687 }
688
689 /*!
690     \qmlproperty string WebView::statusText
691
692     This property is the current status suggested by the current web page. In a web browser,
693     such status is often shown in some kind of status bar.
694 */
695 void QDeclarativeWebView::setStatusText(const QString& text)
696 {
697     d->statusText = text;
698     emit statusTextChanged();
699 }
700
701 void QDeclarativeWebView::windowObjectCleared()
702 {
703     d->updateWindowObjects();
704 }
705
706 QString QDeclarativeWebView::statusText() const
707 {
708     return d->statusText;
709 }
710
711 QWebPage* QDeclarativeWebView::page() const
712 {
713     return d->view->page();
714 }
715
716 // The QObject interface to settings().
717 /*!
718     \qmlproperty string WebView::settings.standardFontFamily
719     \qmlproperty string WebView::settings.fixedFontFamily
720     \qmlproperty string WebView::settings.serifFontFamily
721     \qmlproperty string WebView::settings.sansSerifFontFamily
722     \qmlproperty string WebView::settings.cursiveFontFamily
723     \qmlproperty string WebView::settings.fantasyFontFamily
724
725     \qmlproperty int WebView::settings.minimumFontSize
726     \qmlproperty int WebView::settings.minimumLogicalFontSize
727     \qmlproperty int WebView::settings.defaultFontSize
728     \qmlproperty int WebView::settings.defaultFixedFontSize
729
730     \qmlproperty bool WebView::settings.autoLoadImages
731     \qmlproperty bool WebView::settings.javascriptEnabled
732     \qmlproperty bool WebView::settings.javaEnabled
733     \qmlproperty bool WebView::settings.pluginsEnabled
734     \qmlproperty bool WebView::settings.privateBrowsingEnabled
735     \qmlproperty bool WebView::settings.javascriptCanOpenWindows
736     \qmlproperty bool WebView::settings.javascriptCanAccessClipboard
737     \qmlproperty bool WebView::settings.developerExtrasEnabled
738     \qmlproperty bool WebView::settings.linksIncludedInFocusChain
739     \qmlproperty bool WebView::settings.zoomTextOnly
740     \qmlproperty bool WebView::settings.printElementBackgrounds
741     \qmlproperty bool WebView::settings.offlineStorageDatabaseEnabled
742     \qmlproperty bool WebView::settings.offlineWebApplicationCacheEnabled
743     \qmlproperty bool WebView::settings.localStorageDatabaseEnabled
744     \qmlproperty bool WebView::settings.localContentCanAccessRemoteUrls
745
746     These properties give access to the settings controlling the web view.
747
748     See QWebSettings for details of these properties.
749
750     \qml
751     WebView {
752         settings.pluginsEnabled: true
753         settings.standardFontFamily: "Arial"
754         // ...
755     }
756     \endqml
757 */
758 QDeclarativeWebSettings* QDeclarativeWebView::settingsObject() const
759 {
760     d->settings.s = page()->settings();
761     return &d->settings;
762 }
763
764 void QDeclarativeWebView::setPage(QWebPage* page)
765 {
766     if (d->view->page() == page)
767         return;
768
769     d->view->setPage(page);
770     updateContentsSize();
771     page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
772     page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
773     connect(page->mainFrame(), SIGNAL(urlChanged(QUrl)), this, SLOT(pageUrlChanged()));
774     connect(page->mainFrame(), SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged(QString)));
775     connect(page->mainFrame(), SIGNAL(titleChanged(QString)), this, SIGNAL(iconChanged()));
776     connect(page->mainFrame(), SIGNAL(iconChanged()), this, SIGNAL(iconChanged()));
777     connect(page->mainFrame(), SIGNAL(initialLayoutCompleted()), this, SLOT(initialLayout()));
778     connect(page->mainFrame(), SIGNAL(contentsSizeChanged(QSize)), this, SIGNAL(contentsSizeChanged(QSize)));
779
780     connect(page, SIGNAL(loadStarted()), this, SLOT(doLoadStarted()));
781     connect(page, SIGNAL(loadProgress(int)), this, SLOT(doLoadProgress(int)));
782     connect(page, SIGNAL(loadFinished(bool)), this, SLOT(doLoadFinished(bool)));
783     connect(page, SIGNAL(statusBarMessage(QString)), this, SLOT(setStatusText(QString)));
784
785     connect(page->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(windowObjectCleared()));
786
787     page->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, true);
788
789 }
790
791 /*!
792     \qmlsignal WebView::onLoadStarted()
793
794     This handler is called when the web engine begins loading
795     a page. Later, WebView::onLoadFinished() or WebView::onLoadFailed()
796     will be emitted.
797 */
798
799 /*!
800     \qmlsignal WebView::onLoadFinished()
801
802     This handler is called when the web engine \e successfully
803     finishes loading a page, including any component content
804     (WebView::onLoadFailed() will be emitted otherwise).
805
806     \sa progress
807 */
808
809 /*!
810     \qmlsignal WebView::onLoadFailed()
811
812     This handler is called when the web engine fails loading
813     a page or any component content
814     (WebView::onLoadFinished() will be emitted on success).
815 */
816
817 void QDeclarativeWebView::load(const QNetworkRequest& request, QNetworkAccessManager::Operation operation, const QByteArray& body)
818 {
819     page()->mainFrame()->load(request, operation, body);
820 }
821
822 QString QDeclarativeWebView::html() const
823 {
824     return page()->mainFrame()->toHtml();
825 }
826
827 /*!
828     \qmlproperty string WebView::html
829     This property holds HTML text set directly
830
831     The html property can be set as a string.
832
833     \qml
834     WebView {
835         html: "<p>This is <b>HTML</b>."
836     }
837     \endqml
838 */
839 void QDeclarativeWebView::setHtml(const QString& html, const QUrl& baseUrl)
840 {
841     updateContentsSize();
842     if (isComponentComplete())
843         page()->mainFrame()->setHtml(html, baseUrl);
844     else {
845         d->pending = d->PendingHtml;
846         d->pendingUrl = baseUrl;
847         d->pendingString = html;
848     }
849     emit htmlChanged();
850 }
851
852 void QDeclarativeWebView::setContent(const QByteArray& data, const QString& mimeType, const QUrl& baseUrl)
853 {
854     updateContentsSize();
855
856     if (isComponentComplete())
857         page()->mainFrame()->setContent(data, mimeType, qmlContext(this)->resolvedUrl(baseUrl));
858     else {
859         d->pending = d->PendingContent;
860         d->pendingUrl = baseUrl;
861         d->pendingString = mimeType;
862         d->pendingData = data;
863     }
864 }
865
866 QWebHistory* QDeclarativeWebView::history() const
867 {
868     return page()->history();
869 }
870
871 QWebSettings* QDeclarativeWebView::settings() const
872 {
873     return page()->settings();
874 }
875
876 QDeclarativeWebView* QDeclarativeWebView::createWindow(QWebPage::WebWindowType type)
877 {
878     switch (type) {
879     case QWebPage::WebBrowserWindow: {
880         if (!d->newWindowComponent && d->newWindowParent)
881             qWarning("WebView::newWindowComponent not set - WebView::newWindowParent ignored");
882         else if (d->newWindowComponent && !d->newWindowParent)
883             qWarning("WebView::newWindowParent not set - WebView::newWindowComponent ignored");
884         else if (d->newWindowComponent && d->newWindowParent) {
885             QDeclarativeWebView* webview = 0;
886             QDeclarativeContext* windowContext = new QDeclarativeContext(qmlContext(this));
887
888             QObject* newObject = d->newWindowComponent->create(windowContext);
889             if (newObject) {
890                 windowContext->setParent(newObject);
891                 QDeclarativeItem* item = qobject_cast<QDeclarativeItem *>(newObject);
892                 if (!item)
893                     delete newObject;
894                 else {
895                     webview = item->findChild<QDeclarativeWebView*>();
896                     if (!webview)
897                         delete item;
898                     else {
899                         newObject->setParent(d->newWindowParent);
900                         static_cast<QGraphicsObject*>(item)->setParentItem(d->newWindowParent);
901                     }
902                 }
903             } else
904                 delete windowContext;
905
906             return webview;
907         }
908     }
909     break;
910     case QWebPage::WebModalDialog: {
911         // Not supported
912     }
913     }
914     return 0;
915 }
916
917 /*!
918     \qmlproperty component WebView::newWindowComponent
919
920     This property holds the component to use for new windows.
921     The component must have a WebView somewhere in its structure.
922
923     When the web engine requests a new window, it will be an instance of
924     this component.
925
926     The parent of the new window is set by newWindowParent. It must be set.
927 */
928 QDeclarativeComponent* QDeclarativeWebView::newWindowComponent() const
929 {
930     return d->newWindowComponent;
931 }
932
933 void QDeclarativeWebView::setNewWindowComponent(QDeclarativeComponent* newWindow)
934 {
935     if (newWindow == d->newWindowComponent)
936         return;
937     d->newWindowComponent = newWindow;
938     emit newWindowComponentChanged();
939 }
940
941
942 /*!
943     \qmlproperty item WebView::newWindowParent
944
945     The parent item for new windows.
946
947     \sa newWindowComponent
948 */
949 QDeclarativeItem* QDeclarativeWebView::newWindowParent() const
950 {
951     return d->newWindowParent;
952 }
953
954 void QDeclarativeWebView::setNewWindowParent(QDeclarativeItem* parent)
955 {
956     if (parent == d->newWindowParent)
957         return;
958     if (d->newWindowParent && parent) {
959         QList<QGraphicsItem *> children = d->newWindowParent->childItems();
960         for (int i = 0; i < children.count(); ++i)
961             children.at(i)->setParentItem(parent);
962     }
963     d->newWindowParent = parent;
964     emit newWindowParentChanged();
965 }
966
967 QSize QDeclarativeWebView::contentsSize() const
968 {
969     return page()->mainFrame()->contentsSize() * contentsScale();
970 }
971
972 qreal QDeclarativeWebView::contentsScale() const
973 {
974     return d->view->scale();
975 }
976
977 void QDeclarativeWebView::setContentsScale(qreal scale)
978 {
979     if (scale == d->view->scale())
980         return;
981     d->view->setScale(scale);
982     updateDeclarativeWebViewSize();
983     emit contentsScaleChanged();
984 }
985
986 #if QT_VERSION >= 0x040702
987 /*!
988     \qmlproperty color WebView::backgroundColor
989     \since QtWebKit 1.1
990     This property holds the background color of the view.
991 */
992
993 QColor QDeclarativeWebView::backgroundColor() const
994 {
995     return d->view->palette().base().color();
996 }
997
998 void QDeclarativeWebView::setBackgroundColor(const QColor& color)
999 {
1000     QPalette palette = d->view->palette();
1001     if (palette.base().color() == color)
1002         return;
1003     palette.setBrush(QPalette::Base, color);
1004     d->view->setPalette(palette);
1005     emit backgroundColorChanged();
1006 }
1007 #endif
1008
1009 /*!
1010     Returns the area of the largest element at position (\a x,\a y) that is no larger
1011     than \a maxWidth by \a maxHeight pixels.
1012
1013     May return an area larger in the case when no smaller element is at the position.
1014 */
1015 QRect QDeclarativeWebView::elementAreaAt(int x, int y, int maxWidth, int maxHeight) const
1016 {
1017     QWebHitTestResult hit = page()->mainFrame()->hitTestContent(QPoint(x, y));
1018     QRect hitRect = hit.boundingRect();
1019     QWebElement element = hit.enclosingBlockElement();
1020     if (maxWidth <= 0)
1021         maxWidth = INT_MAX;
1022     if (maxHeight <= 0)
1023         maxHeight = INT_MAX;
1024     while (!element.parent().isNull() && element.geometry().width() <= maxWidth && element.geometry().height() <= maxHeight) {
1025         hitRect = element.geometry();
1026         element = element.parent();
1027     }
1028     return hitRect;
1029 }
1030
1031 /*!
1032     \internal
1033     \class QDeclarativeWebPage
1034     \brief The QDeclarativeWebPage class is a QWebPage that can create QML plugins.
1035
1036     \sa QDeclarativeWebView
1037 */
1038 QDeclarativeWebPage::QDeclarativeWebPage(QDeclarativeWebView* parent) :
1039     QWebPage(parent)
1040 {
1041 }
1042
1043 QDeclarativeWebPage::~QDeclarativeWebPage()
1044 {
1045 }
1046
1047 QString QDeclarativeWebPage::chooseFile(QWebFrame* originatingFrame, const QString& oldFile)
1048 {
1049     // Not supported (it's modal)
1050     Q_UNUSED(originatingFrame)
1051     Q_UNUSED(oldFile)
1052     return oldFile;
1053 }
1054
1055 /*!
1056     \qmlsignal WebView::onAlert(string message)
1057
1058     The handler is called when the web engine sends a JavaScript alert. The \a message is the text
1059     to be displayed in the alert to the user.
1060 */
1061
1062
1063 void QDeclarativeWebPage::javaScriptAlert(QWebFrame* originatingFrame, const QString& msg)
1064 {
1065     Q_UNUSED(originatingFrame)
1066     emit viewItem()->alert(msg);
1067 }
1068
1069 bool QDeclarativeWebPage::javaScriptConfirm(QWebFrame* originatingFrame, const QString& msg)
1070 {
1071     // Not supported (it's modal)
1072     Q_UNUSED(originatingFrame)
1073     Q_UNUSED(msg)
1074     return false;
1075 }
1076
1077 bool QDeclarativeWebPage::javaScriptPrompt(QWebFrame* originatingFrame, const QString& msg, const QString& defaultValue, QString* result)
1078 {
1079     // Not supported (it's modal)
1080     Q_UNUSED(originatingFrame)
1081     Q_UNUSED(msg)
1082     Q_UNUSED(defaultValue)
1083     Q_UNUSED(result)
1084     return false;
1085 }
1086
1087
1088 QDeclarativeWebView* QDeclarativeWebPage::viewItem()
1089 {
1090     return static_cast<QDeclarativeWebView*>(parent());
1091 }
1092
1093 QWebPage* QDeclarativeWebPage::createWindow(WebWindowType type)
1094 {
1095     QDeclarativeWebView* newView = viewItem()->createWindow(type);
1096     if (newView)
1097         return newView->page();
1098     return 0;
1099 }
1100
1101 QT_END_NAMESPACE
1102