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