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