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