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#include "config.h"
21#include "qwebinspector.h"
22
23#include "Element.h"
24#include "InspectorController.h"
25#include "qwebelement.h"
26#include "qwebinspector_p.h"
27#include "qwebpage_p.h"
28
29#include <QResizeEvent>
30
31/*!
32    \class QWebInspector
33    \since 4.6
34    \inmodule QtWebKit
35    \brief The QWebInspector class allows the placement and control of a
36    QWebPage's inspector.
37    The inspector can display a page's hierarchy, its loading statistics and
38    the current state of its individual elements. It is mostly used by web
39    developers.
40
41    The QWebPage to be inspected must be specified using the setPage() method.
42
43    A typical use of QWebInspector follows:
44
45    \snippet webkitsnippets/qtwebkit_qwebinspector_snippet.cpp 0
46
47    A QWebInspector can be made visible either programmatically using
48    setVisible(), or by the user through the attached QWebPage's context
49    menu.
50
51    \note A QWebInspector will display a blank widget if either:
52    \list
53        \o page() is null
54        \o QWebSettings::DeveloperExtrasEnabled is false
55    \endlist
56
57    \section1 Resources
58
59    This class acts mostly as a container and a controller for the inspector.
60    Most of the resources needed by the inspector are owned by the associated
61    QWebPage and are allocated the first time that:
62    \list
63        \o an element is inspected
64        \o the QWebInspector is shown.
65    \endlist
66
67    \section1 Inspector configuration persistence
68
69    The inspector allows the user to configure some options through its
70    user interface (e.g. the resource tracking "Always enable" option).
71    These settings will be persisted automatically by QtWebKit only if
72    your application previously called QCoreApplication::setOrganizationName()
73    and QCoreApplication::setApplicationName().
74    See QSettings's default constructor documentation for an explanation
75    of why this is necessary.
76*/
77
78/*!
79    Constructs an unbound QWebInspector with \a parent as its parent.
80*/
81QWebInspector::QWebInspector(QWidget* parent)
82    : QWidget(parent)
83    , d(new QWebInspectorPrivate(this))
84{
85}
86
87/*!
88    Destroys the inspector.
89*/
90QWebInspector::~QWebInspector()
91{
92    // Remove association principally to prevent deleting a child frontend
93    setPage(0);
94    delete d;
95    d = 0;
96}
97
98/*!
99    Bind this inspector to the QWebPage to be inspected.
100
101    \bold {Notes:}
102    \list
103        \o There can only be one QWebInspector associated with a QWebPage
104           and vice versa.
105        \o Calling this method with a null \a page will break the current association, if any.
106        \o If \a page is already associated to another QWebInspector, the association
107           will be replaced and the previous QWebInspector will become unbound
108    \endlist
109
110    \sa page()
111*/
112void QWebInspector::setPage(QWebPage* page)
113{
114    if (d->page) {
115        // Break currentPage-->this
116        d->page->d->setInspector(0);
117    }
118    if (page && page->d->inspector && page->d->inspector != this) {
119        // Break newPage<->newPageCurrentInspector
120        page->d->inspector->setPage(0);
121    }
122
123    d->page = page;
124
125    if (page) {
126        // Setup the reciprocal association
127        page->d->setInspector(this);
128    }
129}
130
131/*!
132    Returns the inspected QWebPage.
133    If no web page is currently associated, a null pointer is returned.
134*/
135QWebPage* QWebInspector::page() const
136{
137    return d->page;
138}
139
140/*! \reimp */
141QSize QWebInspector::sizeHint() const
142{
143    return QSize(450, 300);
144}
145
146/*! \reimp */
147bool QWebInspector::event(QEvent* ev)
148{
149    return QWidget::event(ev);
150}
151
152/*! \reimp */
153void QWebInspector::resizeEvent(QResizeEvent* event)
154{
155    d->adjustFrontendSize(event->size());
156}
157
158/*! \reimp */
159void QWebInspector::showEvent(QShowEvent* event)
160{
161#if ENABLE(INSPECTOR)
162    // Allows QWebInspector::show() to init the inspector.
163    if (d->page)
164        d->page->d->inspectorController()->show();
165#endif
166}
167
168/*! \reimp */
169void QWebInspector::hideEvent(QHideEvent* event)
170{
171#if ENABLE(INSPECTOR)
172    if (d->page)
173        d->page->d->inspectorController()->close();
174#endif
175}
176
177/*! \reimp */
178void QWebInspector::closeEvent(QCloseEvent* event)
179{
180#if ENABLE(INSPECTOR)
181    if (d->page)
182        d->page->d->inspectorController()->close();
183#endif
184}
185
186/*! \internal */
187void QWebInspectorPrivate::setFrontend(QWidget* newFrontend)
188{
189    if (frontend)
190        frontend->setParent(0);
191
192    frontend = newFrontend;
193
194    if (frontend) {
195        frontend->setParent(q);
196        frontend->show();
197        adjustFrontendSize(q->size());
198    }
199}
200
201/*!
202 * \internal
203 */
204void QWebInspectorPrivate::attachAndReplaceRemoteFrontend(QObject* newRemoteFrontend)
205{
206    if (remoteFrontend)
207        remoteFrontend->setParent(0);
208
209    remoteFrontend = newRemoteFrontend;
210
211    if (remoteFrontend)
212        remoteFrontend->setParent(q);
213}
214
215/*!
216 * \internal
217 */
218void QWebInspectorPrivate::detachRemoteFrontend()
219{
220    if (remoteFrontend) {
221        remoteFrontend->deleteLater();
222        remoteFrontend = 0;
223    }
224}
225
226void QWebInspectorPrivate::adjustFrontendSize(const QSize& size)
227{
228    if (frontend)
229        frontend->resize(size);
230}
231
232