• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
QDeclarativeWebViewPrivate(QDeclarativeWebView * qq)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 
windowObjectsAppend(QDeclarativeListProperty<QObject> * prop,QObject * o)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 
GraphicsWebView(QDeclarativeWebView * parent)85 GraphicsWebView::GraphicsWebView(QDeclarativeWebView* parent)
86     : QGraphicsWebView(parent)
87     , parent(parent)
88     , pressTime(400)
89 {
90 }
91 
mousePressEvent(QGraphicsSceneMouseEvent * event)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 
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)110 void GraphicsWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
111 {
112     QGraphicsWebView::mouseReleaseEvent(event);
113     pressTimer.stop();
114     parent->setKeepMouseGrab(false);
115     ungrabMouse();
116 }
117 
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)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 
timerEvent(QTimerEvent * event)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 
mouseMoveEvent(QGraphicsSceneMouseEvent * event)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 
sceneEvent(QEvent * event)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 
QDeclarativeWebView(QDeclarativeItem * parent)248 QDeclarativeWebView::QDeclarativeWebView(QDeclarativeItem *parent) : QDeclarativeItem(parent)
249 {
250     init();
251 }
252 
~QDeclarativeWebView()253 QDeclarativeWebView::~QDeclarativeWebView()
254 {
255     delete d;
256 }
257 
init()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 
componentComplete()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 
status() const309 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 */
progress() const322 qreal QDeclarativeWebView::progress() const
323 {
324     return d->progress;
325 }
326 
doLoadStarted()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 
doLoadProgress(int p)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 
pageUrlChanged()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 
doLoadFinished(bool ok)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 */
url() const380 QUrl QDeclarativeWebView::url() const
381 {
382     return d->url;
383 }
384 
setUrl(const QUrl & url)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 */
preferredWidth() const412 int QDeclarativeWebView::preferredWidth() const
413 {
414     return d->preferredwidth;
415 }
416 
setPreferredWidth(int width)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 */
preferredHeight() const431 int QDeclarativeWebView::preferredHeight() const
432 {
433     return d->preferredheight;
434 }
435 
setPreferredHeight(int height)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 */
evaluateJavaScript(const QString & scriptSource)454 QVariant QDeclarativeWebView::evaluateJavaScript(const QString& scriptSource)
455 {
456     return this->page()->mainFrame()->evaluateJavaScript(scriptSource);
457 }
458 
updateDeclarativeWebViewSize()459 void QDeclarativeWebView::updateDeclarativeWebViewSize()
460 {
461     QSizeF size = d->view->geometry().size() * contentsScale();
462     setImplicitWidth(size.width());
463     setImplicitHeight(size.height());
464 }
465 
initialLayout()466 void QDeclarativeWebView::initialLayout()
467 {
468     // nothing useful to do at this point
469 }
470 
updateContentsSize()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 
geometryChanged(const QRectF & newGeometry,const QRectF & oldGeometry)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>window.qml.qmlCall();</script>"
521     }
522     \endqml
523 
524     The output of the example will be:
525     \code
526     This call is in QML!
527     \endcode
528 
529     If Javascript is not enabled for the page, then this property does nothing.
530 */
javaScriptWindowObjects()531 QDeclarativeListProperty<QObject> QDeclarativeWebView::javaScriptWindowObjects()
532 {
533     return QDeclarativeListProperty<QObject>(this, d, &QDeclarativeWebViewPrivate::windowObjectsAppend);
534 }
535 
qmlAttachedProperties(QObject * o)536 QDeclarativeWebViewAttached* QDeclarativeWebView::qmlAttachedProperties(QObject* o)
537 {
538     return new QDeclarativeWebViewAttached(o);
539 }
540 
updateWindowObjects()541 void QDeclarativeWebViewPrivate::updateWindowObjects()
542 {
543     if (!q->isComponentCompletePublic() || !q->page())
544         return;
545 
546     for (int i = 0; i < windowObjects.count(); ++i) {
547         QObject* object = windowObjects.at(i);
548         QDeclarativeWebViewAttached* attached = static_cast<QDeclarativeWebViewAttached *>(qmlAttachedPropertiesObject<QDeclarativeWebView>(object));
549         if (attached && !attached->windowObjectName().isEmpty())
550             q->page()->mainFrame()->addToJavaScriptWindowObject(attached->windowObjectName(), object);
551     }
552 }
553 
renderingEnabled() const554 bool QDeclarativeWebView::renderingEnabled() const
555 {
556     return d->rendering;
557 }
558 
setRenderingEnabled(bool enabled)559 void QDeclarativeWebView::setRenderingEnabled(bool enabled)
560 {
561     if (d->rendering == enabled)
562         return;
563     d->rendering = enabled;
564     emit renderingEnabledChanged();
565     d->view->setTiledBackingStoreFrozen(!enabled);
566 }
567 
568 /*!
569     \qmlsignal WebView::onDoubleClick(int clickx, int clicky)
570 
571     The WebView does not pass double-click events to the web engine, but rather
572     emits this signals.
573 */
574 
575 /*!
576     \qmlmethod bool WebView::heuristicZoom(int clickX, int clickY, real maxzoom)
577 
578     Finds a zoom that:
579     \list
580     \i shows a whole item
581     \i includes (\a clickX, \a clickY)
582     \i fits into the preferredWidth and preferredHeight
583     \i zooms by no more than \a maxZoom
584     \i is more than 10% above the current zoom
585     \endlist
586 
587     If such a zoom exists, emits zoomTo(zoom,centerX,centerY) and returns true; otherwise,
588     no signal is emitted and returns false.
589 */
heuristicZoom(int clickX,int clickY,qreal maxZoom)590 bool QDeclarativeWebView::heuristicZoom(int clickX, int clickY, qreal maxZoom)
591 {
592     if (contentsScale() >= maxZoom / scale())
593         return false;
594     qreal ozf = contentsScale();
595     QRect showArea = elementAreaAt(clickX, clickY, d->preferredwidth / maxZoom, d->preferredheight / maxZoom);
596     qreal z = qMin(qreal(d->preferredwidth) / showArea.width(), qreal(d->preferredheight) / showArea.height());
597     if (z > maxZoom / scale())
598         z = maxZoom / scale();
599     if (z / ozf > 1.2) {
600         QRectF r(showArea.left() * z, showArea.top() * z, showArea.width() * z, showArea.height() * z);
601         emit zoomTo(z, r.x() + r.width() / 2, r.y() + r.height() / 2);
602         return true;
603     }
604     return false;
605 }
606 
607 /*!
608     \qmlproperty int WebView::pressGrabTime
609 
610     The number of milliseconds the user must press before the WebView
611     starts passing move events through to the Web engine (rather than
612     letting other QML elements such as a Flickable take them).
613 
614     Defaults to 400ms. Set to 0 to always grab and pass move events to
615     the Web engine.
616 */
pressGrabTime() const617 int QDeclarativeWebView::pressGrabTime() const
618 {
619     return d->view->pressTime;
620 }
621 
setPressGrabTime(int millis)622 void QDeclarativeWebView::setPressGrabTime(int millis)
623 {
624     if (d->view->pressTime == millis)
625         return;
626     d->view->pressTime = millis;
627     emit pressGrabTimeChanged();
628 }
629 
630 #ifndef QT_NO_ACTION
631 /*!
632     \qmlproperty action WebView::back
633     This property holds the action for causing the previous URL in the history to be displayed.
634 */
backAction() const635 QAction* QDeclarativeWebView::backAction() const
636 {
637     return page()->action(QWebPage::Back);
638 }
639 
640 /*!
641     \qmlproperty action WebView::forward
642     This property holds the action for causing the next URL in the history to be displayed.
643 */
forwardAction() const644 QAction* QDeclarativeWebView::forwardAction() const
645 {
646     return page()->action(QWebPage::Forward);
647 }
648 
649 /*!
650     \qmlproperty action WebView::reload
651     This property holds the action for reloading with the current URL
652 */
reloadAction() const653 QAction* QDeclarativeWebView::reloadAction() const
654 {
655     return page()->action(QWebPage::Reload);
656 }
657 
658 /*!
659     \qmlproperty action WebView::stop
660     This property holds the action for stopping loading with the current URL
661 */
stopAction() const662 QAction* QDeclarativeWebView::stopAction() const
663 {
664     return page()->action(QWebPage::Stop);
665 }
666 #endif // QT_NO_ACTION
667 
668 /*!
669     \qmlproperty string WebView::title
670     This property holds the title of the web page currently viewed
671 
672     By default, this property contains an empty string.
673 */
title() const674 QString QDeclarativeWebView::title() const
675 {
676     return page()->mainFrame()->title();
677 }
678 
679 /*!
680     \qmlproperty pixmap WebView::icon
681     This property holds the icon associated with the web page currently viewed
682 */
icon() const683 QPixmap QDeclarativeWebView::icon() const
684 {
685     return page()->mainFrame()->icon().pixmap(QSize(256, 256));
686 }
687 
688 /*!
689     \qmlproperty string WebView::statusText
690 
691     This property is the current status suggested by the current web page. In a web browser,
692     such status is often shown in some kind of status bar.
693 */
setStatusText(const QString & text)694 void QDeclarativeWebView::setStatusText(const QString& text)
695 {
696     d->statusText = text;
697     emit statusTextChanged();
698 }
699 
windowObjectCleared()700 void QDeclarativeWebView::windowObjectCleared()
701 {
702     d->updateWindowObjects();
703 }
704 
statusText() const705 QString QDeclarativeWebView::statusText() const
706 {
707     return d->statusText;
708 }
709 
page() const710 QWebPage* QDeclarativeWebView::page() const
711 {
712     return d->view->page();
713 }
714 
715 // The QObject interface to settings().
716 /*!
717     \qmlproperty string WebView::settings.standardFontFamily
718     \qmlproperty string WebView::settings.fixedFontFamily
719     \qmlproperty string WebView::settings.serifFontFamily
720     \qmlproperty string WebView::settings.sansSerifFontFamily
721     \qmlproperty string WebView::settings.cursiveFontFamily
722     \qmlproperty string WebView::settings.fantasyFontFamily
723 
724     \qmlproperty int WebView::settings.minimumFontSize
725     \qmlproperty int WebView::settings.minimumLogicalFontSize
726     \qmlproperty int WebView::settings.defaultFontSize
727     \qmlproperty int WebView::settings.defaultFixedFontSize
728 
729     \qmlproperty bool WebView::settings.autoLoadImages
730     \qmlproperty bool WebView::settings.javascriptEnabled
731     \qmlproperty bool WebView::settings.javaEnabled
732     \qmlproperty bool WebView::settings.pluginsEnabled
733     \qmlproperty bool WebView::settings.privateBrowsingEnabled
734     \qmlproperty bool WebView::settings.javascriptCanOpenWindows
735     \qmlproperty bool WebView::settings.javascriptCanAccessClipboard
736     \qmlproperty bool WebView::settings.developerExtrasEnabled
737     \qmlproperty bool WebView::settings.linksIncludedInFocusChain
738     \qmlproperty bool WebView::settings.zoomTextOnly
739     \qmlproperty bool WebView::settings.printElementBackgrounds
740     \qmlproperty bool WebView::settings.offlineStorageDatabaseEnabled
741     \qmlproperty bool WebView::settings.offlineWebApplicationCacheEnabled
742     \qmlproperty bool WebView::settings.localStorageDatabaseEnabled
743     \qmlproperty bool WebView::settings.localContentCanAccessRemoteUrls
744 
745     These properties give access to the settings controlling the web view.
746 
747     See QWebSettings for details of these properties.
748 
749     \qml
750     WebView {
751         settings.pluginsEnabled: true
752         settings.standardFontFamily: "Arial"
753         // ...
754     }
755     \endqml
756 */
settingsObject() const757 QDeclarativeWebSettings* QDeclarativeWebView::settingsObject() const
758 {
759     d->settings.s = page()->settings();
760     return &d->settings;
761 }
762 
setPage(QWebPage * page)763 void QDeclarativeWebView::setPage(QWebPage* page)
764 {
765     if (d->view->page() == page)
766         return;
767 
768     d->view->setPage(page);
769     updateContentsSize();
770     page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
771     page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
772     connect(page->mainFrame(), SIGNAL(urlChanged(QUrl)), this, SLOT(pageUrlChanged()));
773     connect(page->mainFrame(), SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged(QString)));
774     connect(page->mainFrame(), SIGNAL(iconChanged()), this, SIGNAL(iconChanged()));
775     connect(page->mainFrame(), SIGNAL(initialLayoutCompleted()), this, SLOT(initialLayout()));
776     connect(page->mainFrame(), SIGNAL(contentsSizeChanged(QSize)), this, SIGNAL(contentsSizeChanged(QSize)));
777 
778     connect(page, SIGNAL(loadStarted()), this, SLOT(doLoadStarted()));
779     connect(page, SIGNAL(loadProgress(int)), this, SLOT(doLoadProgress(int)));
780     connect(page, SIGNAL(loadFinished(bool)), this, SLOT(doLoadFinished(bool)));
781     connect(page, SIGNAL(statusBarMessage(QString)), this, SLOT(setStatusText(QString)));
782 
783     connect(page->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(windowObjectCleared()));
784 
785     page->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, true);
786 
787 }
788 
789 /*!
790     \qmlsignal WebView::onLoadStarted()
791 
792     This handler is called when the web engine begins loading
793     a page. Later, WebView::onLoadFinished() or WebView::onLoadFailed()
794     will be emitted.
795 */
796 
797 /*!
798     \qmlsignal WebView::onLoadFinished()
799 
800     This handler is called when the web engine \e successfully
801     finishes loading a page, including any component content
802     (WebView::onLoadFailed() will be emitted otherwise).
803 
804     \sa progress
805 */
806 
807 /*!
808     \qmlsignal WebView::onLoadFailed()
809 
810     This handler is called when the web engine fails loading
811     a page or any component content
812     (WebView::onLoadFinished() will be emitted on success).
813 */
814 
load(const QNetworkRequest & request,QNetworkAccessManager::Operation operation,const QByteArray & body)815 void QDeclarativeWebView::load(const QNetworkRequest& request, QNetworkAccessManager::Operation operation, const QByteArray& body)
816 {
817     page()->mainFrame()->load(request, operation, body);
818 }
819 
html() const820 QString QDeclarativeWebView::html() const
821 {
822     return page()->mainFrame()->toHtml();
823 }
824 
825 /*!
826     \qmlproperty string WebView::html
827     This property holds HTML text set directly
828 
829     The html property can be set as a string.
830 
831     \qml
832     WebView {
833         html: "<p>This is <b>HTML</b>."
834     }
835     \endqml
836 */
setHtml(const QString & html,const QUrl & baseUrl)837 void QDeclarativeWebView::setHtml(const QString& html, const QUrl& baseUrl)
838 {
839     updateContentsSize();
840     if (isComponentComplete())
841         page()->mainFrame()->setHtml(html, baseUrl);
842     else {
843         d->pending = d->PendingHtml;
844         d->pendingUrl = baseUrl;
845         d->pendingString = html;
846     }
847     emit htmlChanged();
848 }
849 
setContent(const QByteArray & data,const QString & mimeType,const QUrl & baseUrl)850 void QDeclarativeWebView::setContent(const QByteArray& data, const QString& mimeType, const QUrl& baseUrl)
851 {
852     updateContentsSize();
853 
854     if (isComponentComplete())
855         page()->mainFrame()->setContent(data, mimeType, qmlContext(this)->resolvedUrl(baseUrl));
856     else {
857         d->pending = d->PendingContent;
858         d->pendingUrl = baseUrl;
859         d->pendingString = mimeType;
860         d->pendingData = data;
861     }
862 }
863 
history() const864 QWebHistory* QDeclarativeWebView::history() const
865 {
866     return page()->history();
867 }
868 
settings() const869 QWebSettings* QDeclarativeWebView::settings() const
870 {
871     return page()->settings();
872 }
873 
createWindow(QWebPage::WebWindowType type)874 QDeclarativeWebView* QDeclarativeWebView::createWindow(QWebPage::WebWindowType type)
875 {
876     switch (type) {
877     case QWebPage::WebBrowserWindow: {
878         if (!d->newWindowComponent && d->newWindowParent)
879             qWarning("WebView::newWindowComponent not set - WebView::newWindowParent ignored");
880         else if (d->newWindowComponent && !d->newWindowParent)
881             qWarning("WebView::newWindowParent not set - WebView::newWindowComponent ignored");
882         else if (d->newWindowComponent && d->newWindowParent) {
883             QDeclarativeWebView* webview = 0;
884             QDeclarativeContext* windowContext = new QDeclarativeContext(qmlContext(this));
885 
886             QObject* newObject = d->newWindowComponent->create(windowContext);
887             if (newObject) {
888                 windowContext->setParent(newObject);
889                 QDeclarativeItem* item = qobject_cast<QDeclarativeItem *>(newObject);
890                 if (!item)
891                     delete newObject;
892                 else {
893                     webview = item->findChild<QDeclarativeWebView*>();
894                     if (!webview)
895                         delete item;
896                     else {
897                         newObject->setParent(d->newWindowParent);
898                         static_cast<QGraphicsObject*>(item)->setParentItem(d->newWindowParent);
899                     }
900                 }
901             } else
902                 delete windowContext;
903 
904             return webview;
905         }
906     }
907     break;
908     case QWebPage::WebModalDialog: {
909         // Not supported
910     }
911     }
912     return 0;
913 }
914 
915 /*!
916     \qmlproperty component WebView::newWindowComponent
917 
918     This property holds the component to use for new windows.
919     The component must have a WebView somewhere in its structure.
920 
921     When the web engine requests a new window, it will be an instance of
922     this component.
923 
924     The parent of the new window is set by newWindowParent. It must be set.
925 */
newWindowComponent() const926 QDeclarativeComponent* QDeclarativeWebView::newWindowComponent() const
927 {
928     return d->newWindowComponent;
929 }
930 
setNewWindowComponent(QDeclarativeComponent * newWindow)931 void QDeclarativeWebView::setNewWindowComponent(QDeclarativeComponent* newWindow)
932 {
933     if (newWindow == d->newWindowComponent)
934         return;
935     d->newWindowComponent = newWindow;
936     emit newWindowComponentChanged();
937 }
938 
939 
940 /*!
941     \qmlproperty item WebView::newWindowParent
942 
943     The parent item for new windows.
944 
945     \sa newWindowComponent
946 */
newWindowParent() const947 QDeclarativeItem* QDeclarativeWebView::newWindowParent() const
948 {
949     return d->newWindowParent;
950 }
951 
setNewWindowParent(QDeclarativeItem * parent)952 void QDeclarativeWebView::setNewWindowParent(QDeclarativeItem* parent)
953 {
954     if (parent == d->newWindowParent)
955         return;
956     if (d->newWindowParent && parent) {
957         QList<QGraphicsItem *> children = d->newWindowParent->childItems();
958         for (int i = 0; i < children.count(); ++i)
959             children.at(i)->setParentItem(parent);
960     }
961     d->newWindowParent = parent;
962     emit newWindowParentChanged();
963 }
964 
contentsSize() const965 QSize QDeclarativeWebView::contentsSize() const
966 {
967     return page()->mainFrame()->contentsSize() * contentsScale();
968 }
969 
contentsScale() const970 qreal QDeclarativeWebView::contentsScale() const
971 {
972     return d->view->scale();
973 }
974 
setContentsScale(qreal scale)975 void QDeclarativeWebView::setContentsScale(qreal scale)
976 {
977     if (scale == d->view->scale())
978         return;
979     d->view->setScale(scale);
980     updateDeclarativeWebViewSize();
981     emit contentsScaleChanged();
982 }
983 
984 #if QT_VERSION >= 0x040703
985 /*!
986     \qmlproperty color WebView::backgroundColor
987     \since QtWebKit 1.1
988     This property holds the background color of the view.
989 */
990 
backgroundColor() const991 QColor QDeclarativeWebView::backgroundColor() const
992 {
993     return d->view->palette().base().color();
994 }
995 
setBackgroundColor(const QColor & color)996 void QDeclarativeWebView::setBackgroundColor(const QColor& color)
997 {
998     QPalette palette = d->view->palette();
999     if (palette.base().color() == color)
1000         return;
1001     palette.setBrush(QPalette::Base, color);
1002     d->view->setPalette(palette);
1003     emit backgroundColorChanged();
1004 }
1005 #endif
1006 
1007 /*!
1008     Returns the area of the largest element at position (\a x,\a y) that is no larger
1009     than \a maxWidth by \a maxHeight pixels.
1010 
1011     May return an area larger in the case when no smaller element is at the position.
1012 */
elementAreaAt(int x,int y,int maxWidth,int maxHeight) const1013 QRect QDeclarativeWebView::elementAreaAt(int x, int y, int maxWidth, int maxHeight) const
1014 {
1015     QWebHitTestResult hit = page()->mainFrame()->hitTestContent(QPoint(x, y));
1016     QRect hitRect = hit.boundingRect();
1017     QWebElement element = hit.enclosingBlockElement();
1018     if (maxWidth <= 0)
1019         maxWidth = INT_MAX;
1020     if (maxHeight <= 0)
1021         maxHeight = INT_MAX;
1022     while (!element.parent().isNull() && element.geometry().width() <= maxWidth && element.geometry().height() <= maxHeight) {
1023         hitRect = element.geometry();
1024         element = element.parent();
1025     }
1026     return hitRect;
1027 }
1028 
1029 /*!
1030     \internal
1031     \class QDeclarativeWebPage
1032     \brief The QDeclarativeWebPage class is a QWebPage that can create QML plugins.
1033 
1034     \sa QDeclarativeWebView
1035 */
QDeclarativeWebPage(QDeclarativeWebView * parent)1036 QDeclarativeWebPage::QDeclarativeWebPage(QDeclarativeWebView* parent) :
1037     QWebPage(parent)
1038 {
1039 }
1040 
~QDeclarativeWebPage()1041 QDeclarativeWebPage::~QDeclarativeWebPage()
1042 {
1043 }
1044 
chooseFile(QWebFrame * originatingFrame,const QString & oldFile)1045 QString QDeclarativeWebPage::chooseFile(QWebFrame* originatingFrame, const QString& oldFile)
1046 {
1047     // Not supported (it's modal)
1048     Q_UNUSED(originatingFrame)
1049     Q_UNUSED(oldFile)
1050     return oldFile;
1051 }
1052 
1053 /*!
1054     \qmlsignal WebView::onAlert(string message)
1055 
1056     The handler is called when the web engine sends a JavaScript alert. The \a message is the text
1057     to be displayed in the alert to the user.
1058 */
1059 
1060 
javaScriptAlert(QWebFrame * originatingFrame,const QString & msg)1061 void QDeclarativeWebPage::javaScriptAlert(QWebFrame* originatingFrame, const QString& msg)
1062 {
1063     Q_UNUSED(originatingFrame)
1064     emit viewItem()->alert(msg);
1065 }
1066 
javaScriptConfirm(QWebFrame * originatingFrame,const QString & msg)1067 bool QDeclarativeWebPage::javaScriptConfirm(QWebFrame* originatingFrame, const QString& msg)
1068 {
1069     // Not supported (it's modal)
1070     Q_UNUSED(originatingFrame)
1071     Q_UNUSED(msg)
1072     return false;
1073 }
1074 
javaScriptPrompt(QWebFrame * originatingFrame,const QString & msg,const QString & defaultValue,QString * result)1075 bool QDeclarativeWebPage::javaScriptPrompt(QWebFrame* originatingFrame, const QString& msg, const QString& defaultValue, QString* result)
1076 {
1077     // Not supported (it's modal)
1078     Q_UNUSED(originatingFrame)
1079     Q_UNUSED(msg)
1080     Q_UNUSED(defaultValue)
1081     Q_UNUSED(result)
1082     return false;
1083 }
1084 
1085 
viewItem()1086 QDeclarativeWebView* QDeclarativeWebPage::viewItem()
1087 {
1088     return static_cast<QDeclarativeWebView*>(parent());
1089 }
1090 
createWindow(WebWindowType type)1091 QWebPage* QDeclarativeWebPage::createWindow(WebWindowType type)
1092 {
1093     QDeclarativeWebView* newView = viewItem()->createWindow(type);
1094     if (newView)
1095         return newView->page();
1096     return 0;
1097 }
1098 
1099 QT_END_NAMESPACE
1100 
1101