• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
3  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4  * Copyright (C) 2008 Holger Hans Peter Freyther
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "InspectorClientQt.h"
33 
34 #include "Frame.h"
35 #include "FrameView.h"
36 #include "InspectorController.h"
37 #include "InspectorFrontend.h"
38 #include "InspectorServerQt.h"
39 #include "NotImplemented.h"
40 #include "Page.h"
41 #include "PlatformString.h"
42 #include "ScriptDebugServer.h"
43 #include "qwebinspector.h"
44 #include "qwebinspector_p.h"
45 #include "qwebpage.h"
46 #include "qwebpage_p.h"
47 #include "qwebview.h"
48 #include <QtCore/QCoreApplication>
49 #include <QtCore/QFile>
50 #include <QtCore/QSettings>
51 #include <QtCore/QVariant>
52 
53 namespace WebCore {
54 
55 static const QLatin1String settingStoragePrefix("Qt/QtWebKit/QWebInspector/");
56 static const QLatin1String settingStorageTypeSuffix(".type");
57 
58 class InspectorClientWebPage : public QWebPage {
59     Q_OBJECT
60     friend class InspectorClientQt;
61 public:
InspectorClientWebPage(QObject * parent=0)62     InspectorClientWebPage(QObject* parent = 0)
63         : QWebPage(parent)
64     {
65         connect(mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), SLOT(javaScriptWindowObjectCleared()));
66     }
67 
createWindow(QWebPage::WebWindowType)68     QWebPage* createWindow(QWebPage::WebWindowType)
69     {
70         QWebView* view = new QWebView;
71         QWebPage* page = new QWebPage;
72         view->setPage(page);
73         view->setAttribute(Qt::WA_DeleteOnClose);
74         return page;
75     }
76 
77 public slots:
javaScriptWindowObjectCleared()78     void javaScriptWindowObjectCleared()
79     {
80 #ifndef QT_NO_PROPERTIES
81         QVariant inspectorJavaScriptWindowObjects = property("_q_inspectorJavaScriptWindowObjects");
82         if (!inspectorJavaScriptWindowObjects.isValid())
83             return;
84         QMap<QString, QVariant> javaScriptNameObjectMap = inspectorJavaScriptWindowObjects.toMap();
85         QWebFrame* frame = mainFrame();
86         QMap<QString, QVariant>::const_iterator it = javaScriptNameObjectMap.constBegin();
87         for ( ; it != javaScriptNameObjectMap.constEnd(); ++it) {
88             QString name = it.key();
89             QVariant value = it.value();
90             QObject* obj = value.value<QObject*>();
91             frame->addToJavaScriptWindowObject(name, obj);
92         }
93 #endif
94     }
95 };
96 
97 namespace {
98 
99 #if ENABLE(INSPECTOR)
100 class InspectorFrontendSettingsQt : public InspectorFrontendClientLocal::Settings {
101 public:
~InspectorFrontendSettingsQt()102     virtual ~InspectorFrontendSettingsQt() { }
getProperty(const String & name)103     virtual String getProperty(const String& name)
104     {
105 #ifdef QT_NO_SETTINGS
106         Q_UNUSED(name)
107         Q_UNUSED(value)
108         qWarning("QWebInspector: QSettings is not supported by Qt.");
109         return String();
110 #else
111         QSettings qsettings;
112         if (qsettings.status() == QSettings::AccessError) {
113             // QCoreApplication::setOrganizationName and QCoreApplication::setApplicationName haven't been called
114             qWarning("QWebInspector: QSettings couldn't read configuration setting [%s].",
115                      qPrintable(static_cast<QString>(name)));
116             return String();
117         }
118 
119         QString settingKey(settingStoragePrefix + QString(name));
120         QString storedValueType = qsettings.value(settingKey + settingStorageTypeSuffix).toString();
121         QVariant storedValue = qsettings.value(settingKey);
122         storedValue.convert(QVariant::nameToType(storedValueType.toAscii().data()));
123         return variantToSetting(storedValue);
124 #endif // QT_NO_SETTINGS
125     }
126 
setProperty(const String & name,const String & value)127     virtual void setProperty(const String& name, const String& value)
128     {
129 #ifdef QT_NO_SETTINGS
130         Q_UNUSED(name)
131         Q_UNUSED(value)
132         qWarning("QWebInspector: QSettings is not supported by Qt.");
133 #else
134         QSettings qsettings;
135         if (qsettings.status() == QSettings::AccessError) {
136             qWarning("QWebInspector: QSettings couldn't persist configuration setting [%s].",
137                      qPrintable(static_cast<QString>(name)));
138             return;
139         }
140 
141         QVariant valueToStore = settingToVariant(value);
142         QString settingKey(settingStoragePrefix + QString(name));
143         qsettings.setValue(settingKey, valueToStore);
144         qsettings.setValue(settingKey + settingStorageTypeSuffix, QLatin1String(QVariant::typeToName(valueToStore.type())));
145 #endif // QT_NO_SETTINGS
146     }
147 
148 private:
variantToSetting(const QVariant & qvariant)149     static String variantToSetting(const QVariant& qvariant)
150     {
151         String retVal;
152 
153         switch (qvariant.type()) {
154         case QVariant::Bool:
155             retVal = qvariant.toBool() ? "true" : "false";
156             break;
157         case QVariant::String:
158             retVal = qvariant.toString();
159             break;
160         default:
161             break;
162         }
163 
164         return retVal;
165     }
166 
settingToVariant(const String & setting)167     static QVariant settingToVariant(const String& setting)
168     {
169         QVariant retVal;
170         retVal.setValue(static_cast<QString>(setting));
171         return retVal;
172     }
173 };
174 #endif // ENABLE(INSPECTOR)
175 
176 }
177 
InspectorClientQt(QWebPage * page)178 InspectorClientQt::InspectorClientQt(QWebPage* page)
179     : m_inspectedWebPage(page)
180     , m_frontendWebPage(0)
181     , m_frontendClient(0)
182 {
183     InspectorServerQt* webInspectorServer = InspectorServerQt::server();
184     if (webInspectorServer)
185         webInspectorServer->registerClient(this);
186 }
187 
inspectorDestroyed()188 void InspectorClientQt::inspectorDestroyed()
189 {
190 #if ENABLE(INSPECTOR)
191     if (m_frontendClient)
192         m_frontendClient->inspectorClientDestroyed();
193 
194     InspectorServerQt* webInspectorServer = InspectorServerQt::server();
195     if (webInspectorServer)
196         webInspectorServer->unregisterClient(this);
197 
198     delete this;
199 #endif
200 }
201 
202 
openInspectorFrontend(WebCore::InspectorController * inspectorController)203 void InspectorClientQt::openInspectorFrontend(WebCore::InspectorController* inspectorController)
204 {
205 #if ENABLE(INSPECTOR)
206     QWebView* inspectorView = new QWebView;
207     InspectorClientWebPage* inspectorPage = new InspectorClientWebPage(inspectorView);
208     inspectorView->setPage(inspectorPage);
209 
210     QWebInspector* inspector = m_inspectedWebPage->d->getOrCreateInspector();
211     // Remote frontend was attached.
212     if (m_inspectedWebPage->d->inspector->d->remoteFrontend)
213         return;
214 
215     // This is a known hook that allows changing the default URL for the
216     // Web inspector. This is used for SDK purposes. Please keep this hook
217     // around and don't remove it.
218     // https://bugs.webkit.org/show_bug.cgi?id=35340
219     QUrl inspectorUrl;
220 #ifndef QT_NO_PROPERTIES
221     inspectorUrl = inspector->property("_q_inspectorUrl").toUrl();
222 #endif
223     if (!inspectorUrl.isValid())
224         inspectorUrl = QUrl(QLatin1String("qrc:/webkit/inspector/inspector.html"));
225 
226 #ifndef QT_NO_PROPERTIES
227     QVariant inspectorJavaScriptWindowObjects = inspector->property("_q_inspectorJavaScriptWindowObjects");
228     if (inspectorJavaScriptWindowObjects.isValid())
229         inspectorPage->setProperty("_q_inspectorJavaScriptWindowObjects", inspectorJavaScriptWindowObjects);
230 #endif
231     inspectorView->page()->mainFrame()->load(inspectorUrl);
232     m_inspectedWebPage->d->inspectorFrontend = inspectorView;
233     inspector->d->setFrontend(inspectorView);
234 
235     m_frontendClient = new InspectorFrontendClientQt(m_inspectedWebPage, inspectorView, this);
236     inspectorView->page()->d->page->inspectorController()->setInspectorFrontendClient(m_frontendClient);
237     m_frontendWebPage = inspectorPage;
238 #endif
239 }
240 
releaseFrontendPage()241 void InspectorClientQt::releaseFrontendPage()
242 {
243     m_frontendWebPage = 0;
244     m_frontendClient = 0;
245 }
246 
attachAndReplaceRemoteFrontend(RemoteFrontendChannel * channel)247 void InspectorClientQt::attachAndReplaceRemoteFrontend(RemoteFrontendChannel* channel)
248 {
249 #if ENABLE(INSPECTOR)
250     // Channel was allocated by InspectorServerQt. Here we transfer ownership to inspector.
251     m_inspectedWebPage->d->inspector->d->attachAndReplaceRemoteFrontend(channel);
252     m_inspectedWebPage->d->inspectorController()->connectFrontend();
253 #endif
254 }
255 
detachRemoteFrontend()256 void InspectorClientQt::detachRemoteFrontend()
257 {
258 #if ENABLE(INSPECTOR)
259     m_inspectedWebPage->d->inspector->d->detachRemoteFrontend();
260     m_inspectedWebPage->d->inspectorController()->disconnectFrontend();
261 #endif
262 }
263 
highlight(Node *)264 void InspectorClientQt::highlight(Node*)
265 {
266     hideHighlight();
267 }
268 
hideHighlight()269 void InspectorClientQt::hideHighlight()
270 {
271     WebCore::Frame* frame = m_inspectedWebPage->d->page->mainFrame();
272     if (frame) {
273         QRect rect = m_inspectedWebPage->mainFrame()->geometry();
274         if (!rect.isEmpty())
275             frame->view()->invalidateRect(rect);
276     }
277 }
278 
sendMessageToFrontend(const String & message)279 bool InspectorClientQt::sendMessageToFrontend(const String& message)
280 {
281 #if ENABLE(INSPECTOR)
282     if (m_inspectedWebPage->d->inspector->d->remoteFrontend) {
283         RemoteFrontendChannel* session = qobject_cast<RemoteFrontendChannel*>(m_inspectedWebPage->d->inspector->d->remoteFrontend);
284         if (session)
285             session->sendMessageToFrontend(message);
286         return true;
287     }
288     if (!m_frontendWebPage)
289         return false;
290 
291     Page* frontendPage = QWebPagePrivate::core(m_frontendWebPage);
292     return doDispatchMessageOnFrontendPage(frontendPage, message);
293 #else
294     return false;
295 #endif
296 }
297 
298 #if ENABLE(INSPECTOR)
InspectorFrontendClientQt(QWebPage * inspectedWebPage,PassOwnPtr<QWebView> inspectorView,InspectorClientQt * inspectorClient)299 InspectorFrontendClientQt::InspectorFrontendClientQt(QWebPage* inspectedWebPage, PassOwnPtr<QWebView> inspectorView, InspectorClientQt* inspectorClient)
300     : InspectorFrontendClientLocal(inspectedWebPage->d->page->inspectorController(), inspectorView->page()->d->page, new InspectorFrontendSettingsQt())
301     , m_inspectedWebPage(inspectedWebPage)
302     , m_inspectorView(inspectorView)
303     , m_destroyingInspectorView(false)
304     , m_inspectorClient(inspectorClient)
305 {
306 }
307 
~InspectorFrontendClientQt()308 InspectorFrontendClientQt::~InspectorFrontendClientQt()
309 {
310     ASSERT(m_destroyingInspectorView);
311     if (m_inspectorClient)
312         m_inspectorClient->releaseFrontendPage();
313 }
314 
frontendLoaded()315 void InspectorFrontendClientQt::frontendLoaded()
316 {
317     InspectorFrontendClientLocal::frontendLoaded();
318     setAttachedWindow(true);
319 }
320 
localizedStringsURL()321 String InspectorFrontendClientQt::localizedStringsURL()
322 {
323     notImplemented();
324     return String();
325 }
326 
hiddenPanels()327 String InspectorFrontendClientQt::hiddenPanels()
328 {
329     notImplemented();
330     return String();
331 }
332 
bringToFront()333 void InspectorFrontendClientQt::bringToFront()
334 {
335     updateWindowTitle();
336 }
337 
closeWindow()338 void InspectorFrontendClientQt::closeWindow()
339 {
340     destroyInspectorView(true);
341 }
342 
disconnectFromBackend()343 void InspectorFrontendClientQt::disconnectFromBackend()
344 {
345     destroyInspectorView(false);
346 }
347 
attachWindow()348 void InspectorFrontendClientQt::attachWindow()
349 {
350     notImplemented();
351 }
352 
detachWindow()353 void InspectorFrontendClientQt::detachWindow()
354 {
355     notImplemented();
356 }
357 
setAttachedWindowHeight(unsigned)358 void InspectorFrontendClientQt::setAttachedWindowHeight(unsigned)
359 {
360     notImplemented();
361 }
362 
inspectedURLChanged(const String & newURL)363 void InspectorFrontendClientQt::inspectedURLChanged(const String& newURL)
364 {
365     m_inspectedURL = newURL;
366     updateWindowTitle();
367 }
368 
updateWindowTitle()369 void InspectorFrontendClientQt::updateWindowTitle()
370 {
371     if (m_inspectedWebPage->d->inspector) {
372         QString caption = QCoreApplication::translate("QWebPage", "Web Inspector - %2").arg(m_inspectedURL);
373         m_inspectedWebPage->d->inspector->setWindowTitle(caption);
374     }
375 }
376 
destroyInspectorView(bool notifyInspectorController)377 void InspectorFrontendClientQt::destroyInspectorView(bool notifyInspectorController)
378 {
379     if (m_destroyingInspectorView)
380         return;
381     m_destroyingInspectorView = true;
382 
383     // Inspected page may have already been destroyed.
384     if (m_inspectedWebPage) {
385         // Clear reference from QWebInspector to the frontend view.
386         m_inspectedWebPage->d->getOrCreateInspector()->d->setFrontend(0);
387     }
388 
389 #if ENABLE(INSPECTOR)
390     if (notifyInspectorController)
391         m_inspectedWebPage->d->inspectorController()->disconnectFrontend();
392 #endif
393     if (m_inspectorClient)
394         m_inspectorClient->releaseFrontendPage();
395 
396     // Clear pointer before deleting WebView to avoid recursive calls to its destructor.
397     OwnPtr<QWebView> inspectorView = m_inspectorView.release();
398 }
399 
inspectorClientDestroyed()400 void InspectorFrontendClientQt::inspectorClientDestroyed()
401 {
402     m_inspectorClient = 0;
403     m_inspectedWebPage = 0;
404 }
405 #endif
406 }
407 
408 #include "InspectorClientQt.moc"
409