Home | History | Annotate | Download | only in declarative
      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>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 */
    531 QDeclarativeListProperty<QObject> QDeclarativeWebView::javaScriptWindowObjects()
    532 {
    533     return QDeclarativeListProperty<QObject>(this, d, &QDeclarativeWebViewPrivate::windowObjectsAppend);
    534 }
    535 
    536 QDeclarativeWebViewAttached* QDeclarativeWebView::qmlAttachedProperties(QObject* o)
    537 {
    538     return new QDeclarativeWebViewAttached(o);
    539 }
    540 
    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 
    554 bool QDeclarativeWebView::renderingEnabled() const
    555 {
    556     return d->rendering;
    557 }
    558 
    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 */
    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 */
    617 int QDeclarativeWebView::pressGrabTime() const
    618 {
    619     return d->view->pressTime;
    620 }
    621 
    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 */
    635 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 */
    644 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 */
    653 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 */
    662 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 */
    674 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 */
    683 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 */
    694 void QDeclarativeWebView::setStatusText(const QString& text)
    695 {
    696     d->statusText = text;
    697     emit statusTextChanged();
    698 }
    699 
    700 void QDeclarativeWebView::windowObjectCleared()
    701 {
    702     d->updateWindowObjects();
    703 }
    704 
    705 QString QDeclarativeWebView::statusText() const
    706 {
    707     return d->statusText;
    708 }
    709 
    710 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 */
    757 QDeclarativeWebSettings* QDeclarativeWebView::settingsObject() const
    758 {
    759     d->settings.s = page()->settings();
    760     return &d->settings;
    761 }
    762 
    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 
    815 void QDeclarativeWebView::load(const QNetworkRequest& request, QNetworkAccessManager::Operation operation, const QByteArray& body)
    816 {
    817     page()->mainFrame()->load(request, operation, body);
    818 }
    819 
    820 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 */
    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 
    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 
    864 QWebHistory* QDeclarativeWebView::history() const
    865 {
    866     return page()->history();
    867 }
    868 
    869 QWebSettings* QDeclarativeWebView::settings() const
    870 {
    871     return page()->settings();
    872 }
    873 
    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 */
    926 QDeclarativeComponent* QDeclarativeWebView::newWindowComponent() const
    927 {
    928     return d->newWindowComponent;
    929 }
    930 
    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 */
    947 QDeclarativeItem* QDeclarativeWebView::newWindowParent() const
    948 {
    949     return d->newWindowParent;
    950 }
    951 
    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 
    965 QSize QDeclarativeWebView::contentsSize() const
    966 {
    967     return page()->mainFrame()->contentsSize() * contentsScale();
    968 }
    969 
    970 qreal QDeclarativeWebView::contentsScale() const
    971 {
    972     return d->view->scale();
    973 }
    974 
    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 
    991 QColor QDeclarativeWebView::backgroundColor() const
    992 {
    993     return d->view->palette().base().color();
    994 }
    995 
    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 */
   1013 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 */
   1036 QDeclarativeWebPage::QDeclarativeWebPage(QDeclarativeWebView* parent) :
   1037     QWebPage(parent)
   1038 {
   1039 }
   1040 
   1041 QDeclarativeWebPage::~QDeclarativeWebPage()
   1042 {
   1043 }
   1044 
   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 
   1061 void QDeclarativeWebPage::javaScriptAlert(QWebFrame* originatingFrame, const QString& msg)
   1062 {
   1063     Q_UNUSED(originatingFrame)
   1064     emit viewItem()->alert(msg);
   1065 }
   1066 
   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 
   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 
   1086 QDeclarativeWebView* QDeclarativeWebPage::viewItem()
   1087 {
   1088     return static_cast<QDeclarativeWebView*>(parent());
   1089 }
   1090 
   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