1/*
2    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3    Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19*/
20
21#include "config.h"
22#include "qgraphicswebview.h"
23
24#if !defined(QT_NO_GRAPHICSVIEW)
25
26#include "qwebframe.h"
27#include "qwebframe_p.h"
28#include "qwebpage.h"
29#include "qwebpage_p.h"
30#include "PageClientQt.h"
31#include "FrameView.h"
32#include "GraphicsContext.h"
33#include "IntRect.h"
34#include "TiledBackingStore.h"
35#include <QtCore/qmetaobject.h>
36#include <QtCore/qsharedpointer.h>
37#include <QtCore/qtimer.h>
38#include <QtGui/qapplication.h>
39#include <QtGui/qgraphicsscene.h>
40#include <QtGui/qgraphicssceneevent.h>
41#include <QtGui/qgraphicsview.h>
42#include <QtGui/qpixmapcache.h>
43#include <QtGui/qscrollbar.h>
44#include <QtGui/qstyleoption.h>
45#include <QtGui/qinputcontext.h>
46#if defined(Q_WS_X11)
47#include <QX11Info>
48#endif
49#include <Settings.h>
50
51using namespace WebCore;
52
53class QGraphicsWebViewPrivate {
54public:
55    QGraphicsWebViewPrivate(QGraphicsWebView* parent)
56        : q(parent)
57        , page(0)
58        , resizesToContents(false)
59        , renderHints(QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform) {}
60
61    virtual ~QGraphicsWebViewPrivate();
62
63    void syncLayers();
64
65    void updateResizesToContentsForPage();
66
67    void detachCurrentPage();
68
69    void _q_doLoadFinished(bool success);
70    void _q_contentsSizeChanged(const QSize&);
71    void _q_scaleChanged();
72
73    void _q_pageDestroyed();
74
75    QGraphicsWebView* q;
76    QWebPage* page;
77    bool resizesToContents;
78    QPainter::RenderHints renderHints;
79
80    QGraphicsItemOverlay* overlay() const
81    {
82        if (!page || !page->d->client)
83            return 0;
84        return pageClient()->overlay;
85    }
86
87    PageClientQGraphicsWidget* pageClient() const
88    {
89        return static_cast<WebCore::PageClientQGraphicsWidget*> (page->d->client.get());
90    }
91};
92
93QGraphicsWebViewPrivate::~QGraphicsWebViewPrivate()
94{
95    detachCurrentPage();
96}
97
98void QGraphicsWebViewPrivate::syncLayers()
99{
100#if USE(ACCELERATED_COMPOSITING)
101    pageClient()->syncLayers();
102#endif
103}
104
105void QGraphicsWebViewPrivate::_q_doLoadFinished(bool success)
106{
107    // If the page had no title, still make sure it gets the signal
108    if (q->title().isEmpty())
109        emit q->urlChanged(q->url());
110
111    emit q->loadFinished(success);
112}
113
114void QGraphicsWebViewPrivate::_q_pageDestroyed()
115{
116    page = 0;
117    q->setPage(0);
118}
119
120void QGraphicsWebViewPrivate::updateResizesToContentsForPage()
121{
122    ASSERT(page);
123    pageClient()->viewResizesToContents = resizesToContents;
124    if (resizesToContents) {
125        // resizes to contents mode requires preferred contents size to be set
126        if (!page->preferredContentsSize().isValid())
127            page->setPreferredContentsSize(QSize(960, 800));
128
129        QObject::connect(page->mainFrame(), SIGNAL(contentsSizeChanged(QSize)),
130            q, SLOT(_q_contentsSizeChanged(const QSize&)), Qt::UniqueConnection);
131    } else {
132        QObject::disconnect(page->mainFrame(), SIGNAL(contentsSizeChanged(QSize)),
133                         q, SLOT(_q_contentsSizeChanged(const QSize&)));
134    }
135    page->d->page->mainFrame()->view()->setPaintsEntireContents(resizesToContents);
136    page->d->page->mainFrame()->view()->setDelegatesScrolling(resizesToContents);
137}
138
139void QGraphicsWebViewPrivate::_q_contentsSizeChanged(const QSize& size)
140{
141    if (!resizesToContents)
142        return;
143    q->setGeometry(QRectF(q->geometry().topLeft(), size));
144}
145
146void QGraphicsWebViewPrivate::_q_scaleChanged()
147{
148#if ENABLE(TILED_BACKING_STORE)
149    if (!page)
150        return;
151    pageClient()->updateTiledBackingStoreScale();
152#endif
153}
154
155/*!
156    \class QGraphicsWebView
157    \brief The QGraphicsWebView class allows Web content to be added to a GraphicsView.
158    \since 4.6
159
160    An instance of this class renders Web content from a URL or supplied as data, using
161    features of the QtWebKit module.
162
163    If the width and height of the item are not set, they will default to 800 and 600,
164    respectively. If the Web page contents is larger than that, scrollbars will be shown
165    if not disabled explicitly.
166
167    \section1 Browser Features
168
169    Many of the functions, signals and properties provided by QWebView are also available
170    for this item, making it simple to adapt existing code to use QGraphicsWebView instead
171    of QWebView.
172
173    The item uses a QWebPage object to perform the rendering of Web content, and this can
174    be obtained with the page() function, enabling the document itself to be accessed and
175    modified.
176
177    As with QWebView, the item records the browsing history using a QWebHistory object,
178    accessible using the history() function. The QWebSettings object that defines the
179    configuration of the browser can be obtained with the settings() function, enabling
180    features like plugin support to be customized for each item.
181
182    \sa QWebView, QGraphicsTextItem
183*/
184
185/*!
186    \fn void QGraphicsWebView::titleChanged(const QString &title)
187
188    This signal is emitted whenever the \a title of the main frame changes.
189
190    \sa title()
191*/
192
193/*!
194    \fn void QGraphicsWebView::urlChanged(const QUrl &url)
195
196    This signal is emitted when the \a url of the view changes.
197
198    \sa url(), load()
199*/
200
201/*!
202    \fn void QGraphicsWebView::iconChanged()
203
204    This signal is emitted whenever the icon of the page is loaded or changes.
205
206    In order for icons to be loaded, you will need to set an icon database path
207    using QWebSettings::setIconDatabasePath().
208
209    \sa icon(), QWebSettings::setIconDatabasePath()
210*/
211
212/*!
213    \fn void QGraphicsWebView::loadStarted()
214
215    This signal is emitted when a new load of the page is started.
216
217    \sa loadProgress(), loadFinished()
218*/
219
220/*!
221    \fn void QGraphicsWebView::loadFinished(bool ok)
222
223    This signal is emitted when a load of the page is finished.
224    \a ok will indicate whether the load was successful or any error occurred.
225
226    \sa loadStarted()
227*/
228
229/*!
230    Constructs an empty QGraphicsWebView with parent \a parent.
231
232    \sa load()
233*/
234QGraphicsWebView::QGraphicsWebView(QGraphicsItem* parent)
235    : QGraphicsWidget(parent)
236    , d(new QGraphicsWebViewPrivate(this))
237{
238    setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
239    setAcceptDrops(true);
240    setAcceptHoverEvents(true);
241    setAcceptTouchEvents(true);
242    setFocusPolicy(Qt::StrongFocus);
243    setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
244#if ENABLE(TILED_BACKING_STORE)
245    QObject::connect(this, SIGNAL(scaleChanged()), this, SLOT(_q_scaleChanged()));
246#endif
247}
248
249/*!
250    Destroys the item.
251*/
252QGraphicsWebView::~QGraphicsWebView()
253{
254    delete d;
255}
256
257/*!
258    Returns a pointer to the underlying web page.
259
260    \sa setPage()
261*/
262QWebPage* QGraphicsWebView::page() const
263{
264    if (!d->page) {
265        QGraphicsWebView* that = const_cast<QGraphicsWebView*>(this);
266        QWebPage* page = new QWebPage(that);
267
268        // Default to not having a background, in the case
269        // the page doesn't provide one.
270        QPalette palette = QApplication::palette();
271        palette.setBrush(QPalette::Base, QColor::fromRgbF(0, 0, 0, 0));
272        page->setPalette(palette);
273
274        that->setPage(page);
275    }
276
277    return d->page;
278}
279
280/*! \reimp
281*/
282void QGraphicsWebView::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget*)
283{
284    QPainter::RenderHints oldHints = painter->renderHints();
285    painter->setRenderHints(oldHints | d->renderHints);
286#if ENABLE(TILED_BACKING_STORE)
287    if (WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(page()->mainFrame())->tiledBackingStore()) {
288        // FIXME: We should set the backing store viewport earlier than in paint
289        backingStore->adjustVisibleRect();
290        // QWebFrame::render is a public API, bypass it for tiled rendering so behavior does not need to change.
291        WebCore::GraphicsContext context(painter);
292        page()->mainFrame()->d->renderFromTiledBackingStore(&context, option->exposedRect.toAlignedRect());
293        painter->setRenderHints(oldHints);
294        return;
295    }
296#endif
297#if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
298    page()->mainFrame()->render(painter, d->overlay() ? QWebFrame::ContentsLayer : QWebFrame::AllLayers, option->exposedRect.toAlignedRect());
299#else
300    page()->mainFrame()->render(painter, QWebFrame::AllLayers, option->exposedRect.toRect());
301#endif
302    painter->setRenderHints(oldHints);
303}
304
305/*! \reimp
306*/
307bool QGraphicsWebView::sceneEvent(QEvent* event)
308{
309    // Re-implemented in order to allows fixing event-related bugs in patch releases.
310
311    if (d->page && (event->type() == QEvent::TouchBegin
312                || event->type() == QEvent::TouchEnd
313                || event->type() == QEvent::TouchUpdate)) {
314        d->page->event(event);
315
316        // Always return true so that we'll receive also TouchUpdate and TouchEnd events
317        return true;
318    }
319
320    return QGraphicsWidget::sceneEvent(event);
321}
322
323/*! \reimp
324*/
325QVariant QGraphicsWebView::itemChange(GraphicsItemChange change, const QVariant& value)
326{
327    switch (change) {
328    // Differently from QWebView, it is interesting to QGraphicsWebView to handle
329    // post mouse cursor change notifications. Reason: 'ItemCursorChange' is sent
330    // as the first action in QGraphicsItem::setCursor implementation, and at that
331    // item widget's cursor has not been effectively changed yet.
332    // After cursor is properly set (at 'ItemCursorHasChanged' emission time), we
333    // fire 'CursorChange'.
334    case ItemCursorChange:
335        return value;
336    case ItemCursorHasChanged: {
337            QEvent event(QEvent::CursorChange);
338            QApplication::sendEvent(this, &event);
339            return value;
340        }
341    default:
342        break;
343    }
344
345    return QGraphicsWidget::itemChange(change, value);
346}
347
348/*! \reimp
349*/
350QSizeF QGraphicsWebView::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
351{
352    if (which == Qt::PreferredSize)
353        return QSizeF(800, 600); // ###
354    return QGraphicsWidget::sizeHint(which, constraint);
355}
356
357/*! \reimp
358*/
359QVariant QGraphicsWebView::inputMethodQuery(Qt::InputMethodQuery query) const
360{
361    if (d->page)
362        return d->page->inputMethodQuery(query);
363    return QVariant();
364}
365
366/*!
367    \property QGraphicsWebView::renderHints
368    \since 4.8
369    \brief the default render hints for the view
370
371    These hints are used to initialize QPainter before painting the Web page.
372
373    QPainter::TextAntialiasing and QPainter::SmoothPixmapTransform are enabled by default and will be
374    used to render the item in addition of what has been set on the painter given by QGraphicsScene.
375
376    \note This property is not available on Symbian. However, the getter and
377    setter functions can still be used directly.
378
379    \sa QPainter::renderHints()
380*/
381
382/*!
383    \since 4.8
384    Returns the render hints used by the view to render content.
385
386    \sa QPainter::renderHints()
387*/
388QPainter::RenderHints QGraphicsWebView::renderHints() const
389{
390    return d->renderHints;
391}
392
393/*!
394    \since 4.8
395    Sets the render hints used by the view to the specified \a hints.
396
397    \sa QPainter::setRenderHints()
398*/
399void QGraphicsWebView::setRenderHints(QPainter::RenderHints hints)
400{
401    if (hints == d->renderHints)
402        return;
403    d->renderHints = hints;
404    update();
405}
406
407/*!
408    \since 4.8
409    If \a enabled is true, enables the specified render \a hint; otherwise
410    disables it.
411
412    \sa renderHints, QPainter::renderHints()
413*/
414void QGraphicsWebView::setRenderHint(QPainter::RenderHint hint, bool enabled)
415{
416    QPainter::RenderHints oldHints = d->renderHints;
417    if (enabled)
418        d->renderHints |= hint;
419    else
420        d->renderHints &= ~hint;
421    if (oldHints != d->renderHints)
422        update();
423}
424
425/*! \reimp
426*/
427bool QGraphicsWebView::event(QEvent* event)
428{
429    // Re-implemented in order to allows fixing event-related bugs in patch releases.
430
431    if (d->page) {
432        if (event->type() == QEvent::PaletteChange)
433            d->page->setPalette(palette());
434#ifndef QT_NO_CONTEXTMENU
435        if (event->type() == QEvent::GraphicsSceneContextMenu) {
436            if (!isEnabled())
437                return false;
438
439            QGraphicsSceneContextMenuEvent* ev = static_cast<QGraphicsSceneContextMenuEvent*>(event);
440            QContextMenuEvent fakeEvent(QContextMenuEvent::Reason(ev->reason()), ev->pos().toPoint());
441            if (d->page->swallowContextMenuEvent(&fakeEvent)) {
442                event->accept();
443                return true;
444            }
445            d->page->updatePositionDependentActions(fakeEvent.pos());
446        } else
447#endif // QT_NO_CONTEXTMENU
448        {
449#ifndef QT_NO_CURSOR
450            if (event->type() == QEvent::CursorChange) {
451                // An unsetCursor will set the cursor to Qt::ArrowCursor.
452                // Thus this cursor change might be a QWidget::unsetCursor()
453                // If this is not the case and it came from WebCore, the
454                // QWebPageClient already has set its cursor internally
455                // to Qt::ArrowCursor, so updating the cursor is always
456                // right, as it falls back to the last cursor set by
457                // WebCore.
458                // FIXME: Add a QEvent::CursorUnset or similar to Qt.
459                if (cursor().shape() == Qt::ArrowCursor)
460                    d->page->d->client->resetCursor();
461            }
462#endif
463        }
464    }
465    return QGraphicsWidget::event(event);
466}
467
468void QGraphicsWebViewPrivate::detachCurrentPage()
469{
470    if (!page)
471        return;
472
473    page->d->view.clear();
474    page->d->client = 0;
475
476    // if the page was created by us, we own it and need to
477    // destroy it as well.
478
479    if (page->parent() == q)
480        delete page;
481    else
482        page->disconnect(q);
483
484    page = 0;
485}
486
487/*!
488    Makes \a page the new web page of the web graphicsitem.
489
490    The parent QObject of the provided page remains the owner
491    of the object. If the current document is a child of the web
492    view, it will be deleted.
493
494    \sa page()
495*/
496void QGraphicsWebView::setPage(QWebPage* page)
497{
498    if (d->page == page)
499        return;
500
501    d->detachCurrentPage();
502    d->page = page;
503
504    if (!d->page)
505        return;
506
507    d->page->d->client = new PageClientQGraphicsWidget(this, page); // set the page client
508
509    if (d->overlay())
510        d->overlay()->prepareGraphicsItemGeometryChange();
511
512    QSize size = geometry().size().toSize();
513    page->setViewportSize(size);
514
515    if (d->resizesToContents)
516        d->updateResizesToContentsForPage();
517
518    QWebFrame* mainFrame = d->page->mainFrame();
519
520    connect(mainFrame, SIGNAL(titleChanged(QString)),
521            this, SIGNAL(titleChanged(QString)));
522    connect(mainFrame, SIGNAL(iconChanged()),
523            this, SIGNAL(iconChanged()));
524    connect(mainFrame, SIGNAL(urlChanged(QUrl)),
525            this, SIGNAL(urlChanged(QUrl)));
526    connect(d->page, SIGNAL(loadStarted()),
527            this, SIGNAL(loadStarted()));
528    connect(d->page, SIGNAL(loadProgress(int)),
529            this, SIGNAL(loadProgress(int)));
530    connect(d->page, SIGNAL(loadFinished(bool)),
531            this, SLOT(_q_doLoadFinished(bool)));
532    connect(d->page, SIGNAL(statusBarMessage(QString)),
533            this, SIGNAL(statusBarMessage(QString)));
534    connect(d->page, SIGNAL(linkClicked(QUrl)),
535            this, SIGNAL(linkClicked(QUrl)));
536    connect(d->page, SIGNAL(destroyed()),
537            this, SLOT(_q_pageDestroyed()));
538#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN))
539    connect(d->page, SIGNAL(microFocusChanged()),
540            this, SLOT(updateMicroFocus()));
541#endif
542}
543
544/*!
545    \property QGraphicsWebView::url
546    \brief the url of the web page currently viewed
547
548    Setting this property clears the view and loads the URL.
549
550    By default, this property contains an empty, invalid URL.
551
552    \sa load(), urlChanged()
553*/
554
555void QGraphicsWebView::setUrl(const QUrl &url)
556{
557    page()->mainFrame()->setUrl(url);
558}
559
560QUrl QGraphicsWebView::url() const
561{
562    if (d->page)
563        return d->page->mainFrame()->url();
564
565    return QUrl();
566}
567
568/*!
569    \property QGraphicsWebView::title
570    \brief the title of the web page currently viewed
571
572    By default, this property contains an empty string.
573
574    \sa titleChanged()
575*/
576QString QGraphicsWebView::title() const
577{
578    if (d->page)
579        return d->page->mainFrame()->title();
580
581    return QString();
582}
583
584/*!
585    \property QGraphicsWebView::icon
586    \brief the icon associated with the web page currently viewed
587
588    By default, this property contains a null icon.
589
590    \sa iconChanged(), QWebSettings::iconForUrl()
591*/
592QIcon QGraphicsWebView::icon() const
593{
594    if (d->page)
595        return d->page->mainFrame()->icon();
596
597    return QIcon();
598}
599
600/*!
601    \property QGraphicsWebView::zoomFactor
602    \brief the zoom factor for the view
603*/
604
605void QGraphicsWebView::setZoomFactor(qreal factor)
606{
607    if (factor == page()->mainFrame()->zoomFactor())
608        return;
609
610    page()->mainFrame()->setZoomFactor(factor);
611}
612
613qreal QGraphicsWebView::zoomFactor() const
614{
615    return page()->mainFrame()->zoomFactor();
616}
617
618/*! \reimp
619*/
620void QGraphicsWebView::updateGeometry()
621{
622    if (d->overlay())
623        d->overlay()->prepareGraphicsItemGeometryChange();
624
625    QGraphicsWidget::updateGeometry();
626
627    if (!d->page)
628        return;
629
630    QSize size = geometry().size().toSize();
631    d->page->setViewportSize(size);
632}
633
634/*! \reimp
635*/
636void QGraphicsWebView::setGeometry(const QRectF& rect)
637{
638    QGraphicsWidget::setGeometry(rect);
639
640    if (d->overlay())
641        d->overlay()->prepareGraphicsItemGeometryChange();
642
643    if (!d->page)
644        return;
645
646    // NOTE: call geometry() as setGeometry ensures that
647    // the geometry is within legal bounds (minimumSize, maximumSize)
648    QSize size = geometry().size().toSize();
649    d->page->setViewportSize(size);
650}
651
652/*!
653    Convenience slot that stops loading the document.
654
655    \sa reload(), loadFinished()
656*/
657void QGraphicsWebView::stop()
658{
659    if (d->page)
660        d->page->triggerAction(QWebPage::Stop);
661}
662
663/*!
664    Convenience slot that loads the previous document in the list of documents
665    built by navigating links. Does nothing if there is no previous document.
666
667    \sa forward()
668*/
669void QGraphicsWebView::back()
670{
671    if (d->page)
672        d->page->triggerAction(QWebPage::Back);
673}
674
675/*!
676    Convenience slot that loads the next document in the list of documents
677    built by navigating links. Does nothing if there is no next document.
678
679    \sa back()
680*/
681void QGraphicsWebView::forward()
682{
683    if (d->page)
684        d->page->triggerAction(QWebPage::Forward);
685}
686
687/*!
688    Reloads the current document.
689
690    \sa stop(), loadStarted()
691*/
692void QGraphicsWebView::reload()
693{
694    if (d->page)
695        d->page->triggerAction(QWebPage::Reload);
696}
697
698/*!
699    Loads the specified \a url and displays it.
700
701    \note The view remains the same until enough data has arrived to display the new \a url.
702
703    \sa setUrl(), url(), urlChanged()
704*/
705void QGraphicsWebView::load(const QUrl& url)
706{
707    page()->mainFrame()->load(url);
708}
709
710/*!
711    \fn void QGraphicsWebView::load(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, const QByteArray &body)
712
713    Loads a network request, \a request, using the method specified in \a operation.
714
715    \a body is optional and is only used for POST operations.
716
717    \note The view remains the same until enough data has arrived to display the new url.
718
719    \sa url(), urlChanged()
720*/
721
722void QGraphicsWebView::load(const QNetworkRequest& request,
723                    QNetworkAccessManager::Operation operation,
724                    const QByteArray& body)
725{
726    page()->mainFrame()->load(request, operation, body);
727}
728
729/*!
730    Sets the content of the web view to the specified \a html.
731
732    External objects such as stylesheets or images referenced in the HTML
733    document are located relative to \a baseUrl.
734
735    The \a html is loaded immediately; external objects are loaded asynchronously.
736
737    When using this method, WebKit assumes that external resources such as
738    JavaScript programs or style sheets are encoded in UTF-8 unless otherwise
739    specified. For example, the encoding of an external script can be specified
740    through the charset attribute of the HTML script tag. Alternatively, the
741    encoding can also be specified by the web server.
742
743    This is a convenience function equivalent to setContent(html, "text/html", baseUrl).
744
745    \warning This function works only for HTML, for other mime types (i.e. XHTML, SVG)
746    setContent() should be used instead.
747
748    \sa load(), setContent(), QWebFrame::toHtml(), QWebFrame::setContent()
749*/
750void QGraphicsWebView::setHtml(const QString& html, const QUrl& baseUrl)
751{
752    page()->mainFrame()->setHtml(html, baseUrl);
753}
754
755/*!
756    Sets the content of the web graphicsitem to the specified content \a data. If the \a mimeType argument
757    is empty it is currently assumed that the content is HTML but in future versions we may introduce
758    auto-detection.
759
760    External objects referenced in the content are located relative to \a baseUrl.
761
762    The \a data is loaded immediately; external objects are loaded asynchronously.
763
764    \sa load(), setHtml(), QWebFrame::toHtml()
765*/
766void QGraphicsWebView::setContent(const QByteArray& data, const QString& mimeType, const QUrl& baseUrl)
767{
768    page()->mainFrame()->setContent(data, mimeType, baseUrl);
769}
770
771/*!
772    Returns a pointer to the view's history of navigated web pages.
773
774    It is equivalent to
775
776    \snippet webkitsnippets/qtwebkit_qwebview_snippet.cpp 0
777*/
778QWebHistory* QGraphicsWebView::history() const
779{
780    return page()->history();
781}
782
783/*!
784    \property QGraphicsWebView::modified
785    \brief whether the document was modified by the user
786
787    Parts of HTML documents can be editable for example through the
788    \c{contenteditable} attribute on HTML elements.
789
790    By default, this property is false.
791*/
792bool QGraphicsWebView::isModified() const
793{
794    if (d->page)
795        return d->page->isModified();
796    return false;
797}
798
799/*!
800    Returns a pointer to the view/page specific settings object.
801
802    It is equivalent to
803
804    \snippet webkitsnippets/qtwebkit_qwebview_snippet.cpp 1
805
806    \sa QWebSettings::globalSettings()
807*/
808QWebSettings* QGraphicsWebView::settings() const
809{
810    return page()->settings();
811}
812
813/*!
814    Returns a pointer to a QAction that encapsulates the specified web action \a action.
815*/
816QAction *QGraphicsWebView::pageAction(QWebPage::WebAction action) const
817{
818#ifdef QT_NO_ACTION
819    Q_UNUSED(action)
820    return 0;
821#else
822    return page()->action(action);
823#endif
824}
825
826/*!
827    Triggers the specified \a action. If it is a checkable action the specified
828    \a checked state is assumed.
829
830    \sa pageAction()
831*/
832void QGraphicsWebView::triggerPageAction(QWebPage::WebAction action, bool checked)
833{
834    page()->triggerAction(action, checked);
835}
836
837/*!
838    Finds the specified string, \a subString, in the page, using the given \a options.
839
840    If the HighlightAllOccurrences flag is passed, the function will highlight all occurrences
841    that exist in the page. All subsequent calls will extend the highlight, rather than
842    replace it, with occurrences of the new string.
843
844    If the HighlightAllOccurrences flag is not passed, the function will select an occurrence
845    and all subsequent calls will replace the current occurrence with the next one.
846
847    To clear the selection, just pass an empty string.
848
849    Returns true if \a subString was found; otherwise returns false.
850
851    \sa QWebPage::selectedText(), QWebPage::selectionChanged()
852*/
853bool QGraphicsWebView::findText(const QString &subString, QWebPage::FindFlags options)
854{
855    if (d->page)
856        return d->page->findText(subString, options);
857    return false;
858}
859
860/*!
861    \property QGraphicsWebView::resizesToContents
862    \brief whether the size of the QGraphicsWebView and its viewport changes to match the contents size
863    \since 4.7
864
865    If this property is set, the QGraphicsWebView will automatically change its
866    size to match the size of the main frame contents. As a result the top level frame
867    will never have scrollbars. It will also make CSS fixed positioning to behave like absolute positioning
868    with elements positioned relative to the document instead of the viewport.
869
870    This property should be used in conjunction with the QWebPage::preferredContentsSize property.
871    If not explicitly set, the preferredContentsSize is automatically set to a reasonable value.
872
873    \sa QWebPage::setPreferredContentsSize()
874*/
875void QGraphicsWebView::setResizesToContents(bool enabled)
876{
877    if (d->resizesToContents == enabled)
878        return;
879    d->resizesToContents = enabled;
880    if (d->page)
881        d->updateResizesToContentsForPage();
882}
883
884bool QGraphicsWebView::resizesToContents() const
885{
886    return d->resizesToContents;
887}
888
889/*!
890    \property QGraphicsWebView::tiledBackingStoreFrozen
891    \brief whether the tiled backing store updates its contents
892    \since 4.7
893
894    If the tiled backing store is enabled using QWebSettings::TiledBackingStoreEnabled attribute, this property
895    can be used to disable backing store updates temporarily. This can be useful for example for running
896    a smooth animation that changes the scale of the QGraphicsWebView.
897
898    When the backing store is unfrozen, its contents will be automatically updated to match the current
899    state of the document. If the QGraphicsWebView scale was changed, the backing store is also
900    re-rendered using the new scale.
901
902    If the tiled backing store is not enabled, this property does nothing.
903
904    \sa QWebSettings::TiledBackingStoreEnabled
905    \sa QGraphicsObject::scale
906*/
907bool QGraphicsWebView::isTiledBackingStoreFrozen() const
908{
909#if ENABLE(TILED_BACKING_STORE)
910    WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(page()->mainFrame())->tiledBackingStore();
911    if (!backingStore)
912        return false;
913    return backingStore->contentsFrozen();
914#else
915    return false;
916#endif
917}
918
919void QGraphicsWebView::setTiledBackingStoreFrozen(bool frozen)
920{
921#if ENABLE(TILED_BACKING_STORE)
922    WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(page()->mainFrame())->tiledBackingStore();
923    if (!backingStore)
924        return;
925    backingStore->setContentsFrozen(frozen);
926#else
927    UNUSED_PARAM(frozen);
928#endif
929}
930
931/*! \reimp
932*/
933void QGraphicsWebView::hoverMoveEvent(QGraphicsSceneHoverEvent* ev)
934{
935    if (d->page) {
936        const bool accepted = ev->isAccepted();
937        QMouseEvent me = QMouseEvent(QEvent::MouseMove,
938                ev->pos().toPoint(), Qt::NoButton,
939                Qt::NoButton, Qt::NoModifier);
940        d->page->event(&me);
941        ev->setAccepted(accepted);
942    }
943
944    if (!ev->isAccepted())
945        QGraphicsItem::hoverMoveEvent(ev);
946}
947
948/*! \reimp
949*/
950void QGraphicsWebView::hoverLeaveEvent(QGraphicsSceneHoverEvent* ev)
951{
952    Q_UNUSED(ev);
953}
954
955/*! \reimp
956*/
957void QGraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* ev)
958{
959    if (d->page) {
960        const bool accepted = ev->isAccepted();
961        d->page->event(ev);
962        ev->setAccepted(accepted);
963    }
964
965    if (!ev->isAccepted())
966        QGraphicsItem::mouseMoveEvent(ev);
967}
968
969/*! \reimp
970*/
971void QGraphicsWebView::mousePressEvent(QGraphicsSceneMouseEvent* ev)
972{
973    if (d->page) {
974        const bool accepted = ev->isAccepted();
975        d->page->event(ev);
976        ev->setAccepted(accepted);
977    }
978
979    if (!ev->isAccepted())
980        QGraphicsItem::mousePressEvent(ev);
981}
982
983/*! \reimp
984*/
985void QGraphicsWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent* ev)
986{
987    if (d->page) {
988        const bool accepted = ev->isAccepted();
989        d->page->event(ev);
990        ev->setAccepted(accepted);
991    }
992
993    if (!ev->isAccepted())
994        QGraphicsItem::mouseReleaseEvent(ev);
995}
996
997/*! \reimp
998*/
999void QGraphicsWebView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* ev)
1000{
1001    if (d->page) {
1002        const bool accepted = ev->isAccepted();
1003        d->page->event(ev);
1004        ev->setAccepted(accepted);
1005    }
1006
1007    if (!ev->isAccepted())
1008        QGraphicsItem::mouseDoubleClickEvent(ev);
1009}
1010
1011/*! \reimp
1012*/
1013void QGraphicsWebView::keyPressEvent(QKeyEvent* ev)
1014{
1015    if (d->page)
1016        d->page->event(ev);
1017
1018    if (!ev->isAccepted())
1019        QGraphicsItem::keyPressEvent(ev);
1020}
1021
1022/*! \reimp
1023*/
1024void QGraphicsWebView::keyReleaseEvent(QKeyEvent* ev)
1025{
1026    if (d->page)
1027        d->page->event(ev);
1028
1029    if (!ev->isAccepted())
1030        QGraphicsItem::keyReleaseEvent(ev);
1031}
1032
1033/*! \reimp
1034*/
1035void QGraphicsWebView::focusInEvent(QFocusEvent* ev)
1036{
1037    if (d->page)
1038        d->page->event(ev);
1039    else
1040        QGraphicsItem::focusInEvent(ev);
1041}
1042
1043/*! \reimp
1044*/
1045void QGraphicsWebView::focusOutEvent(QFocusEvent* ev)
1046{
1047    if (d->page)
1048        d->page->event(ev);
1049    else
1050        QGraphicsItem::focusOutEvent(ev);
1051}
1052
1053/*! \reimp
1054*/
1055bool QGraphicsWebView::focusNextPrevChild(bool next)
1056{
1057    if (d->page)
1058        return d->page->focusNextPrevChild(next);
1059
1060    return QGraphicsWidget::focusNextPrevChild(next);
1061}
1062
1063/*! \reimp
1064*/
1065void QGraphicsWebView::dragEnterEvent(QGraphicsSceneDragDropEvent* ev)
1066{
1067#ifndef QT_NO_DRAGANDDROP
1068    if (d->page)
1069        d->page->event(ev);
1070#else
1071    Q_UNUSED(ev);
1072#endif
1073}
1074
1075/*! \reimp
1076*/
1077void QGraphicsWebView::dragLeaveEvent(QGraphicsSceneDragDropEvent* ev)
1078{
1079#ifndef QT_NO_DRAGANDDROP
1080    if (d->page) {
1081        const bool accepted = ev->isAccepted();
1082        d->page->event(ev);
1083        ev->setAccepted(accepted);
1084    }
1085
1086    if (!ev->isAccepted())
1087        QGraphicsWidget::dragLeaveEvent(ev);
1088#else
1089    Q_UNUSED(ev);
1090#endif
1091}
1092
1093/*! \reimp
1094*/
1095void QGraphicsWebView::dragMoveEvent(QGraphicsSceneDragDropEvent* ev)
1096{
1097#ifndef QT_NO_DRAGANDDROP
1098    if (d->page) {
1099        const bool accepted = ev->isAccepted();
1100        d->page->event(ev);
1101        ev->setAccepted(accepted);
1102    }
1103
1104    if (!ev->isAccepted())
1105        QGraphicsWidget::dragMoveEvent(ev);
1106#else
1107    Q_UNUSED(ev);
1108#endif
1109}
1110
1111/*! \reimp
1112*/
1113void QGraphicsWebView::dropEvent(QGraphicsSceneDragDropEvent* ev)
1114{
1115#ifndef QT_NO_DRAGANDDROP
1116    if (d->page) {
1117        const bool accepted = ev->isAccepted();
1118        d->page->event(ev);
1119        ev->setAccepted(accepted);
1120    }
1121
1122    if (!ev->isAccepted())
1123        QGraphicsWidget::dropEvent(ev);
1124#else
1125    Q_UNUSED(ev);
1126#endif
1127}
1128
1129#ifndef QT_NO_CONTEXTMENU
1130/*! \reimp
1131*/
1132void QGraphicsWebView::contextMenuEvent(QGraphicsSceneContextMenuEvent* ev)
1133{
1134    if (d->page) {
1135        const bool accepted = ev->isAccepted();
1136        d->page->event(ev);
1137        ev->setAccepted(accepted);
1138    }
1139}
1140#endif // QT_NO_CONTEXTMENU
1141
1142#ifndef QT_NO_WHEELEVENT
1143/*! \reimp
1144*/
1145void QGraphicsWebView::wheelEvent(QGraphicsSceneWheelEvent* ev)
1146{
1147    if (d->page) {
1148        const bool accepted = ev->isAccepted();
1149        d->page->event(ev);
1150        ev->setAccepted(accepted);
1151    }
1152
1153    if (!ev->isAccepted())
1154        QGraphicsItem::wheelEvent(ev);
1155}
1156#endif // QT_NO_WHEELEVENT
1157
1158/*! \reimp
1159*/
1160void QGraphicsWebView::inputMethodEvent(QInputMethodEvent* ev)
1161{
1162    if (d->page)
1163        d->page->event(ev);
1164
1165    if (!ev->isAccepted())
1166        QGraphicsItem::inputMethodEvent(ev);
1167}
1168
1169/*!
1170    \fn void QGraphicsWebView::statusBarMessage(const QString& text)
1171
1172    This signal is emitted when the statusbar \a text is changed by the page.
1173*/
1174
1175/*!
1176    \fn void QGraphicsWebView::loadProgress(int progress)
1177
1178    This signal is emitted every time an element in the web page
1179    completes loading and the overall loading progress advances.
1180
1181    This signal tracks the progress of all child frames.
1182
1183    The current value is provided by \a progress and scales from 0 to 100,
1184    which is the default range of QProgressBar.
1185
1186    \sa loadStarted(), loadFinished()
1187*/
1188
1189/*!
1190    \fn void QGraphicsWebView::linkClicked(const QUrl &url)
1191
1192    This signal is emitted whenever the user clicks on a link and the page's linkDelegationPolicy
1193    property is set to delegate the link handling for the specified \a url.
1194
1195    \sa QWebPage::linkDelegationPolicy()
1196*/
1197
1198#endif // QT_NO_GRAPHICSVIEW
1199
1200#include "moc_qgraphicswebview.cpp"
1201