1b06e2e1fe6e078b28c5f984e77f7ae6bb2b6b08
[WebKit-https.git] / Source / WebKit / qt / WebCoreSupport / InspectorClientQt.cpp
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 "InspectorBackendDispatcher.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 static String variantToSetting(const QVariant& qvariant);
59 static QVariant settingToVariant(const String& value);
60
61 class InspectorClientWebPage : public QWebPage {
62     Q_OBJECT
63     friend class InspectorClientQt;
64 public:
65     InspectorClientWebPage(QObject* parent = 0)
66         : QWebPage(parent)
67     {
68         connect(mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), SLOT(javaScriptWindowObjectCleared()));
69     }
70
71     QWebPage* createWindow(QWebPage::WebWindowType)
72     {
73         QWebView* view = new QWebView;
74         QWebPage* page = new QWebPage;
75         view->setPage(page);
76         view->setAttribute(Qt::WA_DeleteOnClose);
77         return page;
78     }
79
80 public slots:
81     void javaScriptWindowObjectCleared() 
82     {
83 #ifndef QT_NO_PROPERTIES
84         QVariant inspectorJavaScriptWindowObjects = property("_q_inspectorJavaScriptWindowObjects");
85         if (!inspectorJavaScriptWindowObjects.isValid())
86             return;
87         QMap<QString, QVariant> javaScriptNameObjectMap = inspectorJavaScriptWindowObjects.toMap();
88         QWebFrame* frame = mainFrame();
89         QMap<QString, QVariant>::const_iterator it = javaScriptNameObjectMap.constBegin();
90         for ( ; it != javaScriptNameObjectMap.constEnd(); ++it) {
91             QString name = it.key();
92             QVariant value = it.value();
93             QObject* obj = value.value<QObject*>();
94             frame->addToJavaScriptWindowObject(name, obj);
95         }
96 #endif
97     }
98 };
99
100 #if USE(V8)
101 static void ensureDebuggerScriptLoaded()
102 {
103     static bool scriptLoaded = false;
104     if (scriptLoaded)
105         return;
106
107     QFile debuggerScriptFile(":/webkit/inspector/DebuggerScript.js");
108     if (debuggerScriptFile.open(QIODevice::ReadOnly)) {
109         QByteArray ba = debuggerScriptFile.readAll();
110         ScriptDebugServer::shared().setDebuggerScriptSource(String(ba.constData(), ba.length()));
111         scriptLoaded = true;
112     }
113 }
114 #endif
115
116 InspectorClientQt::InspectorClientQt(QWebPage* page)
117     : m_inspectedWebPage(page)
118     , m_frontendWebPage(0)
119     , m_frontendClient(0)
120 {
121     InspectorServerQt* webInspectorServer = InspectorServerQt::server();
122     if (webInspectorServer)
123         webInspectorServer->registerClient(this);
124 }
125
126 void InspectorClientQt::inspectorDestroyed()
127 {
128 #if ENABLE(INSPECTOR)
129     if (m_frontendClient)
130         m_frontendClient->inspectorClientDestroyed();
131
132     InspectorServerQt* webInspectorServer = InspectorServerQt::server();
133     if (webInspectorServer)
134         webInspectorServer->unregisterClient(this);
135
136     delete this;
137 #endif
138 }
139
140     
141 void InspectorClientQt::openInspectorFrontend(WebCore::InspectorController* inspectorController)
142 {
143 #if ENABLE(INSPECTOR)
144 #if USE(V8)
145     ensureDebuggerScriptLoaded();
146 #endif
147
148     QWebView* inspectorView = new QWebView;
149     InspectorClientWebPage* inspectorPage = new InspectorClientWebPage(inspectorView);
150     inspectorView->setPage(inspectorPage);
151
152     QWebInspector* inspector = m_inspectedWebPage->d->getOrCreateInspector();
153     // Remote frontend was attached.
154     if (m_inspectedWebPage->d->inspector->d->remoteFrontend)
155         return;
156
157     // This is a known hook that allows changing the default URL for the
158     // Web inspector. This is used for SDK purposes. Please keep this hook
159     // around and don't remove it.
160     // https://bugs.webkit.org/show_bug.cgi?id=35340
161     QUrl inspectorUrl;
162 #ifndef QT_NO_PROPERTIES
163     inspectorUrl = inspector->property("_q_inspectorUrl").toUrl();
164 #endif
165     if (!inspectorUrl.isValid())
166         inspectorUrl = QUrl("qrc:/webkit/inspector/inspector.html");
167
168 #ifndef QT_NO_PROPERTIES
169     QVariant inspectorJavaScriptWindowObjects = inspector->property("_q_inspectorJavaScriptWindowObjects");
170     if (inspectorJavaScriptWindowObjects.isValid())
171         inspectorPage->setProperty("_q_inspectorJavaScriptWindowObjects", inspectorJavaScriptWindowObjects);
172 #endif
173     inspectorView->page()->mainFrame()->load(inspectorUrl);
174     m_inspectedWebPage->d->inspectorFrontend = inspectorView;
175     inspector->d->setFrontend(inspectorView);
176
177     m_frontendClient = new InspectorFrontendClientQt(m_inspectedWebPage, inspectorView, this);
178     inspectorView->page()->d->page->inspectorController()->setInspectorFrontendClient(m_frontendClient);
179     m_frontendWebPage = inspectorPage;
180 #endif
181 }
182
183 void InspectorClientQt::releaseFrontendPage()
184 {
185     m_frontendWebPage = 0;
186     m_frontendClient = 0;
187 }
188
189 void InspectorClientQt::attachAndReplaceRemoteFrontend(RemoteFrontendChannel* channel)
190 {
191 #if ENABLE(INSPECTOR)
192     // Channel was allocated by InspectorServerQt. Here we transfer ownership to inspector.
193     m_inspectedWebPage->d->inspector->d->attachAndReplaceRemoteFrontend(channel);
194     m_inspectedWebPage->d->inspectorController()->connectFrontend();
195 #endif
196 }
197
198 void InspectorClientQt::detachRemoteFrontend()
199 {
200 #if ENABLE(INSPECTOR)
201     m_inspectedWebPage->d->inspector->d->detachRemoteFrontend();
202     m_inspectedWebPage->d->inspectorController()->disconnectFrontend();
203 #endif
204 }
205
206 void InspectorClientQt::highlight(Node*)
207 {
208     notImplemented();
209 }
210
211 void InspectorClientQt::hideHighlight()
212 {
213     notImplemented();
214 }
215
216 void InspectorClientQt::populateSetting(const String& key, String* setting)
217 {
218 #ifdef QT_NO_SETTINGS
219     Q_UNUSED(key)
220     Q_UNUSED(setting)
221     qWarning("QWebInspector: QSettings is not supported by Qt.");
222 #else
223     QSettings qsettings;
224     if (qsettings.status() == QSettings::AccessError) {
225         // QCoreApplication::setOrganizationName and QCoreApplication::setApplicationName haven't been called
226         qWarning("QWebInspector: QSettings couldn't read configuration setting [%s].",
227                  qPrintable(static_cast<QString>(key)));
228         return;
229     }
230
231     QString settingKey(settingStoragePrefix + QString(key));
232     QString storedValueType = qsettings.value(settingKey + settingStorageTypeSuffix).toString();
233     QVariant storedValue = qsettings.value(settingKey);
234     storedValue.convert(QVariant::nameToType(storedValueType.toAscii().data()));
235     *setting = variantToSetting(storedValue);
236 #endif // QT_NO_SETTINGS
237 }
238
239 void InspectorClientQt::storeSetting(const String& key, const String& setting)
240 {
241 #ifdef QT_NO_SETTINGS
242     Q_UNUSED(key)
243     Q_UNUSED(setting)
244     qWarning("QWebInspector: QSettings is not supported by Qt.");
245 #else
246     QSettings qsettings;
247     if (qsettings.status() == QSettings::AccessError) {
248         qWarning("QWebInspector: QSettings couldn't persist configuration setting [%s].",
249                  qPrintable(static_cast<QString>(key)));
250         return;
251     }
252
253     QVariant valueToStore = settingToVariant(setting);
254     QString settingKey(settingStoragePrefix + QString(key));
255     qsettings.setValue(settingKey, valueToStore);
256     qsettings.setValue(settingKey + settingStorageTypeSuffix, QVariant::typeToName(valueToStore.type()));
257 #endif // QT_NO_SETTINGS
258 }
259
260 bool InspectorClientQt::sendMessageToFrontend(const String& message)
261 {
262 #if ENABLE(INSPECTOR)
263     if (m_inspectedWebPage->d->inspector->d->remoteFrontend) {
264         RemoteFrontendChannel* session = qobject_cast<RemoteFrontendChannel*>(m_inspectedWebPage->d->inspector->d->remoteFrontend);
265         if (session)
266             session->sendMessageToFrontend(message);
267         return true;
268     }
269     if (!m_frontendWebPage)
270         return false;
271
272     Page* frontendPage = QWebPagePrivate::core(m_frontendWebPage);
273     return doDispatchMessageOnFrontendPage(frontendPage, message);
274 #else
275     return false;
276 #endif
277 }
278
279 static String variantToSetting(const QVariant& qvariant)
280 {
281     String retVal;
282
283     switch (qvariant.type()) {
284     case QVariant::Bool:
285         retVal = qvariant.toBool() ? "true" : "false";
286     case QVariant::String:
287         retVal = qvariant.toString();
288     default:
289         break;
290     }
291
292     return retVal;
293 }
294
295 static QVariant settingToVariant(const String& setting)
296 {
297     QVariant retVal;
298     retVal.setValue(static_cast<QString>(setting));
299     return retVal;
300 }
301
302 #if ENABLE(INSPECTOR)
303 InspectorFrontendClientQt::InspectorFrontendClientQt(QWebPage* inspectedWebPage, PassOwnPtr<QWebView> inspectorView, InspectorClientQt* inspectorClient)
304     : InspectorFrontendClientLocal(inspectedWebPage->d->page->inspectorController(), inspectorView->page()->d->page) 
305     , m_inspectedWebPage(inspectedWebPage)
306     , m_inspectorView(inspectorView)
307     , m_destroyingInspectorView(false)
308     , m_inspectorClient(inspectorClient)
309 {
310 }
311
312 InspectorFrontendClientQt::~InspectorFrontendClientQt()
313 {
314     ASSERT(m_destroyingInspectorView);
315     if (m_inspectorClient)
316         m_inspectorClient->releaseFrontendPage();
317 }
318
319 void InspectorFrontendClientQt::frontendLoaded()
320 {
321     InspectorFrontendClientLocal::frontendLoaded();
322     setAttachedWindow(true);
323 }
324
325 String InspectorFrontendClientQt::localizedStringsURL()
326 {
327     notImplemented();
328     return String();
329 }
330
331 String InspectorFrontendClientQt::hiddenPanels()
332 {
333     notImplemented();
334     return String();
335 }
336
337 void InspectorFrontendClientQt::bringToFront()
338 {
339     updateWindowTitle();
340 }
341
342 void InspectorFrontendClientQt::closeWindow()
343 {
344     destroyInspectorView(true);
345 }
346
347 void InspectorFrontendClientQt::disconnectFromBackend()
348 {
349     destroyInspectorView(false);
350 }
351
352 void InspectorFrontendClientQt::attachWindow()
353 {
354     notImplemented();
355 }
356
357 void InspectorFrontendClientQt::detachWindow()
358 {
359     notImplemented();
360 }
361
362 void InspectorFrontendClientQt::setAttachedWindowHeight(unsigned)
363 {
364     notImplemented();
365 }
366
367 void InspectorFrontendClientQt::inspectedURLChanged(const String& newURL)
368 {
369     m_inspectedURL = newURL;
370     updateWindowTitle();
371 }
372
373 void InspectorFrontendClientQt::updateWindowTitle()
374 {
375     if (m_inspectedWebPage->d->inspector) {
376         QString caption = QCoreApplication::translate("QWebPage", "Web Inspector - %2").arg(m_inspectedURL);
377         m_inspectedWebPage->d->inspector->setWindowTitle(caption);
378     }
379 }
380
381 void InspectorFrontendClientQt::destroyInspectorView(bool notifyInspectorController)
382 {
383     if (m_destroyingInspectorView)
384         return;
385     m_destroyingInspectorView = true;
386
387     // Inspected page may have already been destroyed.
388     if (m_inspectedWebPage) {
389         // Clear reference from QWebInspector to the frontend view.
390         m_inspectedWebPage->d->getOrCreateInspector()->d->setFrontend(0);
391     }
392
393 #if ENABLE(INSPECTOR)
394     if (notifyInspectorController)
395         m_inspectedWebPage->d->inspectorController()->disconnectFrontend();
396 #endif
397     if (m_inspectorClient)
398         m_inspectorClient->releaseFrontendPage();
399
400     // Clear pointer before deleting WebView to avoid recursive calls to its destructor.
401     OwnPtr<QWebView> inspectorView = m_inspectorView.release();
402 }
403
404 void InspectorFrontendClientQt::inspectorClientDestroyed()
405 {
406     m_inspectorClient = 0;
407     m_inspectedWebPage = 0;
408 }
409 #endif
410 }
411
412 #include "InspectorClientQt.moc"