OSDN Git Service

Qml Live Preview: lazily create QmlJSLiveTextPreview
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmljsinspector / qmljsinspector.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29 #include "qmljsinspectorconstants.h"
30 #include "qmljsinspector.h"
31 #include "qmljsclientproxy.h"
32 #include "qmljsinspectorcontext.h"
33 #include "qmljsdelta.h"
34 #include "qmljslivetextpreview.h"
35 #include "qmljsprivateapi.h"
36
37 #include <qmljseditor/qmljseditorconstants.h>
38
39 #include <qmljs/qmljsmodelmanagerinterface.h>
40 #include <qmljs/qmljsdocument.h>
41
42 #include <debugger/debuggerrunner.h>
43 #include <debugger/debuggerconstants.h>
44 #include <debugger/debuggerengine.h>
45 #include <debugger/debuggermainwindow.h>
46 #include <debugger/debuggerplugin.h>
47 #include <debugger/debuggerrunner.h>
48 #include <debugger/debuggeruiswitcher.h>
49 #include <debugger/debuggerconstants.h>
50
51 #include <utils/qtcassert.h>
52 #include <utils/styledbar.h>
53 #include <utils/fancymainwindow.h>
54
55 #include <coreplugin/icontext.h>
56 #include <coreplugin/basemode.h>
57 #include <coreplugin/findplaceholder.h>
58 #include <coreplugin/minisplitter.h>
59 #include <coreplugin/outputpane.h>
60 #include <coreplugin/rightpane.h>
61 #include <coreplugin/navigationwidget.h>
62 #include <coreplugin/icore.h>
63 #include <coreplugin/coreconstants.h>
64 #include <coreplugin/uniqueidmanager.h>
65 #include <coreplugin/actionmanager/actioncontainer.h>
66 #include <coreplugin/actionmanager/actionmanager.h>
67 #include <coreplugin/actionmanager/command.h>
68 #include <coreplugin/editormanager/editormanager.h>
69
70 #include <texteditor/itexteditor.h>
71 #include <texteditor/basetexteditor.h>
72
73 #include <projectexplorer/runconfiguration.h>
74 #include <projectexplorer/projectexplorer.h>
75 #include <projectexplorer/projectexplorerconstants.h>
76 #include <projectexplorer/project.h>
77 #include <projectexplorer/target.h>
78 #include <projectexplorer/applicationrunconfiguration.h>
79 #include <qmlprojectmanager/qmlprojectconstants.h>
80 #include <qmlprojectmanager/qmlprojectrunconfiguration.h>
81
82 #include <extensionsystem/pluginmanager.h>
83
84 #include <QtCore/QDebug>
85 #include <QtCore/QStringList>
86 #include <QtCore/QTimer>
87 #include <QtCore/QtPlugin>
88 #include <QtCore/QDateTime>
89
90 #include <QtGui/QLabel>
91 #include <QtGui/QDockWidget>
92 #include <QtGui/QAction>
93 #include <QtGui/QLineEdit>
94 #include <QtGui/QLabel>
95 #include <QtGui/QSpinBox>
96 #include <QtGui/QMessageBox>
97 #include <QtGui/QTextBlock>
98
99 #include <QtNetwork/QHostAddress>
100
101 using namespace QmlJS;
102 using namespace QmlJS::AST;
103 using namespace QmlJSInspector::Internal;
104 using namespace Debugger::Internal;
105
106
107
108
109
110
111 enum {
112     MaxConnectionAttempts = 50,
113     ConnectionAttemptDefaultInterval = 75,
114
115     // used when debugging with c++ - connection can take a lot of time
116     ConnectionAttemptSimultaneousInterval = 500
117 };
118
119 Inspector::Inspector(QObject *parent)
120     : QObject(parent),
121       m_connectionTimer(new QTimer(this)),
122       m_connectionAttempts(0),
123       m_cppDebuggerState(0),
124       m_simultaneousCppAndQmlDebugMode(false),
125       m_debugMode(StandaloneMode)
126 {
127     m_clientProxy = ClientProxy::instance();
128
129 //#warning set up the context widget
130     QWidget *contextWidget = 0;
131     m_context = new InspectorContext(contextWidget);
132
133     connect(m_clientProxy, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)),
134             SLOT(setSelectedItemsByObjectReference(QList<QDeclarativeDebugObjectReference>)));
135
136     connect(m_clientProxy, SIGNAL(connectionStatusMessage(QString)), SIGNAL(statusMessage(QString)));
137     connect(m_clientProxy, SIGNAL(connected(QDeclarativeEngineDebug*)), SLOT(connected(QDeclarativeEngineDebug*)));
138     connect(m_clientProxy, SIGNAL(disconnected()), SLOT(disconnected()));
139     connect(m_clientProxy, SIGNAL(aboutToReloadEngines()), SLOT(aboutToReloadEngines()));
140     connect(m_clientProxy, SIGNAL(enginesChanged()), SLOT(updateEngineList()));
141     connect(m_clientProxy, SIGNAL(aboutToDisconnect()), SLOT(disconnectWidgets()));
142     connect(m_clientProxy, SIGNAL(serverReloaded()), this, SLOT(serverReloaded()));
143
144     connect(Debugger::DebuggerPlugin::instance(),
145             SIGNAL(stateChanged(int)), this, SLOT(debuggerStateChanged(int)));
146
147     connect(m_connectionTimer, SIGNAL(timeout()), SLOT(pollInspector()));
148 }
149
150
151 Inspector::~Inspector()
152 {
153 }
154
155 void Inspector::disconnectWidgets()
156 {
157 }
158
159 void Inspector::disconnected()
160 {
161     Core::EditorManager *em = Core::EditorManager::instance();
162     disconnect(em, SIGNAL(editorAboutToClose(Core::IEditor*)), this, SLOT(removePreviewForEditor(Core::IEditor*)));
163     disconnect(em, SIGNAL(editorOpened(Core::IEditor*)), this, SLOT(createPreviewForEditor(Core::IEditor*)));
164     resetViews();
165     updateMenuActions();
166 }
167
168 void Inspector::aboutToReloadEngines()
169 {
170 }
171
172 void Inspector::updateEngineList()
173 {
174     const QList<QDeclarativeDebugEngineReference> engines = m_clientProxy->engines();
175
176 //#warning update the QML engines combo
177
178     if (engines.isEmpty())
179         qWarning("qmldebugger: no engines found!");
180     else {
181         const QDeclarativeDebugEngineReference engine = engines.first();
182         m_clientProxy->queryEngineContext(engine.debugId());
183     }
184 }
185
186 void Inspector::changeSelectedItems(const QList<QDeclarativeDebugObjectReference> &objects)
187 {
188     m_clientProxy->setSelectedItemsByObjectId(objects);
189 }
190
191 void Inspector::shutdown()
192 {
193 //#warning save the inspector settings here
194 }
195
196 void Inspector::pollInspector()
197 {
198     ++m_connectionAttempts;
199
200     const QString host = m_runConfigurationDebugData.serverAddress;
201     const quint16 port = quint16(m_runConfigurationDebugData.serverPort);
202
203     if (m_clientProxy->connectToViewer(host, port)) {
204         initializeDocuments();
205         m_connectionTimer->stop();
206         m_connectionAttempts = 0;
207     } else if (m_connectionAttempts == MaxConnectionAttempts) {
208         m_connectionTimer->stop();
209         m_connectionAttempts = 0;
210
211         QMessageBox::critical(0,
212                               tr("Failed to connect to debugger"),
213                               tr("Could not connect to debugger server.") );
214     }
215     updateMenuActions();
216 }
217
218 QmlJS::ModelManagerInterface *Inspector::modelManager()
219 {
220     return ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>();
221 }
222
223 void Inspector::initializeDocuments()
224 {
225     if (!modelManager())
226         return;
227
228     m_loadedSnapshot = modelManager()->snapshot();
229     Core::EditorManager *em = Core::EditorManager::instance();
230     connect(em, SIGNAL(editorAboutToClose(Core::IEditor*)), SLOT(removePreviewForEditor(Core::IEditor*)));
231     connect(em, SIGNAL(editorOpened(Core::IEditor*)), SLOT(createPreviewForEditor(Core::IEditor*)));
232
233     // initial update
234     foreach (Core::IEditor *editor, em->openedEditors()) {
235         createPreviewForEditor(editor);
236     }
237 }
238
239 void Inspector::serverReloaded()
240 {
241     QmlJS::Snapshot snapshot = modelManager()->snapshot();
242     m_loadedSnapshot = snapshot;
243     for (QHash<QString, QmlJSLiveTextPreview *>::const_iterator it = m_textPreviews.constBegin();
244          it != m_textPreviews.constEnd(); ++it) {
245         Document::Ptr doc = snapshot.document(it.key());
246         it.value()->resetInitialDoc(doc);
247     }
248     ClientProxy::instance()->queryEngineContext(0);
249     //ClientProxy::instance()->refreshObjectTree();
250 }
251
252
253 void Inspector::removePreviewForEditor(Core::IEditor *oldEditor)
254 {
255     if (QmlJSLiveTextPreview *preview = m_textPreviews.value(oldEditor->file()->fileName())) {
256         preview->unassociateEditor(oldEditor);
257     }
258 }
259
260 void Inspector::createPreviewForEditor(Core::IEditor *newEditor)
261 {
262     if (newEditor && newEditor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
263         QString filename = newEditor->file()->fileName();
264         QmlJS::Document::Ptr doc = modelManager()->snapshot().document(filename);
265         if (!doc || !doc->qmlProgram())
266             return;
267         QmlJS::Document::Ptr initdoc = m_loadedSnapshot.document(filename);
268         if (!initdoc)
269             initdoc = doc;
270
271         if (m_textPreviews.contains(filename)) {
272             m_textPreviews.value(filename)->associateEditor(newEditor);
273         } else {
274             QmlJSLiveTextPreview *preview = new QmlJSLiveTextPreview(doc, initdoc, this);
275             connect(preview,
276                     SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)),
277                     SLOT(changeSelectedItems(QList<QDeclarativeDebugObjectReference>)));
278             m_textPreviews.insert(newEditor->file()->fileName(), preview);
279             preview->updateDebugIds(m_clientProxy->rootObjectReference());
280         }
281     }
282 }
283
284 bool Inspector::setDebugConfigurationDataFromProject(ProjectExplorer::Project *projectToDebug)
285 {
286     if (!projectToDebug) {
287         emit statusMessage(tr("Invalid project, debugging canceled."));
288         return false;
289     }
290
291     QmlProjectManager::QmlProjectRunConfiguration* config =
292             qobject_cast<QmlProjectManager::QmlProjectRunConfiguration*>(projectToDebug->activeTarget()->activeRunConfiguration());
293     if (!config) {
294         emit statusMessage(tr("Cannot find project run configuration, debugging canceled."));
295         return false;
296     }
297     m_runConfigurationDebugData.serverAddress = config->debugServerAddress();
298     m_runConfigurationDebugData.serverPort = config->debugServerPort();
299     m_connectionTimer->setInterval(ConnectionAttemptDefaultInterval);
300
301     return true;
302 }
303
304 void Inspector::startQmlProjectDebugger()
305 {
306     m_simultaneousCppAndQmlDebugMode = false;
307     m_connectionTimer->start();
308 }
309
310 void Inspector::resetViews()
311 {
312 //#warning reset the views here
313 }
314
315 void Inspector::simultaneouslyDebugQmlCppApplication()
316 {
317     QString errorMessage;
318     ProjectExplorer::ProjectExplorerPlugin *pex = ProjectExplorer::ProjectExplorerPlugin::instance();
319     ProjectExplorer::Project *project = pex->startupProject();
320
321     if (!project)
322          errorMessage = tr("No project was found.");
323     else if (project->id() == QLatin1String("QmlProjectManager.QmlProject"))
324         errorMessage = attachToQmlViewerAsExternalApp(project);
325     else
326         errorMessage = attachToExternalCppAppWithQml(project);
327
328     if (!errorMessage.isEmpty())
329         QMessageBox::warning(Core::ICore::instance()->mainWindow(), tr("Failed to debug C++ and QML"), errorMessage);
330 }
331
332 QString Inspector::attachToQmlViewerAsExternalApp(ProjectExplorer::Project *project)
333 {
334     Q_UNUSED(project);
335
336
337 //#warning implement attachToQmlViewerAsExternalApp
338     return QString();
339
340
341 #if 0
342     m_debugMode = QmlProjectWithCppPlugins;
343
344     QmlProjectManager::QmlProjectRunConfiguration* runConfig =
345                 qobject_cast<QmlProjectManager::QmlProjectRunConfiguration*>(project->activeTarget()->activeRunConfiguration());
346
347     if (!runConfig)
348         return tr("No run configurations were found for the project '%1'.").arg(project->displayName());
349
350     Internal::StartExternalQmlDialog dlg(Debugger::DebuggerUISwitcher::instance()->mainWindow());
351
352     QString importPathArgument = "-I";
353     QString execArgs;
354     if (runConfig->viewerArguments().contains(importPathArgument))
355         execArgs = runConfig->viewerArguments().join(" ");
356     else {
357         QFileInfo qmlFileInfo(runConfig->viewerArguments().last());
358         importPathArgument.append(" " + qmlFileInfo.absolutePath() + " ");
359         execArgs = importPathArgument + runConfig->viewerArguments().join(" ");
360     }
361
362
363     dlg.setPort(runConfig->debugServerPort());
364     dlg.setDebuggerUrl(runConfig->debugServerAddress());
365     dlg.setProjectDisplayName(project->displayName());
366     dlg.setDebugMode(Internal::StartExternalQmlDialog::QmlProjectWithCppPlugins);
367     dlg.setQmlViewerArguments(execArgs);
368     dlg.setQmlViewerPath(runConfig->viewerPath());
369
370     if (dlg.exec() != QDialog::Accepted)
371         return QString();
372
373     m_runConfigurationDebugData.serverAddress = dlg.debuggerUrl();
374     m_runConfigurationDebugData.serverPort = dlg.port();
375     m_settings.setExternalPort(dlg.port());
376     m_settings.setExternalUrl(dlg.debuggerUrl());
377
378     ProjectExplorer::Environment customEnv = ProjectExplorer::Environment::systemEnvironment(); // empty env by default
379     customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
380
381     Debugger::DebuggerRunControl *debuggableRunControl =
382      createDebuggerRunControl(runConfig, dlg.qmlViewerPath(), dlg.qmlViewerArguments());
383
384     return executeDebuggerRunControl(debuggableRunControl, &customEnv);
385 #endif
386 }
387
388 QString Inspector::attachToExternalCppAppWithQml(ProjectExplorer::Project *project)
389 {
390     Q_UNUSED(project);
391 //#warning implement attachToExternalCppAppWithQml
392
393     return QString();
394
395 #if 0
396     m_debugMode = CppProjectWithQmlEngines;
397
398     ProjectExplorer::LocalApplicationRunConfiguration* runConfig =
399                 qobject_cast<ProjectExplorer::LocalApplicationRunConfiguration*>(project->activeTarget()->activeRunConfiguration());
400
401     if (!project->activeTarget() || !project->activeTarget()->activeRunConfiguration())
402         return tr("No run configurations were found for the project '%1'.").arg(project->displayName());
403     else if (!runConfig)
404         return tr("No valid run configuration was found for the project %1. "
405                                   "Only locally runnable configurations are supported.\n"
406                                   "Please check your project settings.").arg(project->displayName());
407
408     Internal::StartExternalQmlDialog dlg(Debugger::DebuggerUISwitcher::instance()->mainWindow());
409
410     dlg.setPort(m_settings.externalPort());
411     dlg.setDebuggerUrl(m_settings.externalUrl());
412     dlg.setProjectDisplayName(project->displayName());
413     dlg.setDebugMode(Internal::StartExternalQmlDialog::CppProjectWithQmlEngine);
414     if (dlg.exec() != QDialog::Accepted)
415         return QString();
416
417     m_runConfigurationDebugData.serverAddress = dlg.debuggerUrl();
418     m_runConfigurationDebugData.serverPort = dlg.port();
419     m_settings.setExternalPort(dlg.port());
420     m_settings.setExternalUrl(dlg.debuggerUrl());
421
422     ProjectExplorer::Environment customEnv = runConfig->environment();
423     customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
424     Debugger::DebuggerRunControl *debuggableRunControl = createDebuggerRunControl(runConfig);
425     return executeDebuggerRunControl(debuggableRunControl, &customEnv);
426 #endif
427 }
428
429 QString Inspector::executeDebuggerRunControl(Debugger::DebuggerRunControl *debuggableRunControl,
430                                              ProjectExplorer::Environment *environment)
431 {
432     Q_UNUSED(debuggableRunControl);
433     Q_UNUSED(environment);
434     ProjectExplorer::ProjectExplorerPlugin *pex = ProjectExplorer::ProjectExplorerPlugin::instance();
435
436     // to make sure we have a valid, debuggable run control, find the correct factory for it
437     if (debuggableRunControl) {
438
439         // modify the env
440         debuggableRunControl->setCustomEnvironment(*environment);
441
442         pex->startRunControl(debuggableRunControl, ProjectExplorer::Constants::DEBUGMODE);
443         m_simultaneousCppAndQmlDebugMode = true;
444
445         return QString();
446     }
447     return tr("A valid run control was not registered in Qt Creator for this project run configuration.");
448 }
449
450 Debugger::DebuggerRunControl *Inspector::createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
451                                                                   const QString &executableFile,
452                                                                   const QString &executableArguments)
453 {
454     ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
455     const QList<Debugger::DebuggerRunControlFactory *> factories = pm->getObjects<Debugger::DebuggerRunControlFactory>();
456     ProjectExplorer::RunControl *runControl = 0;
457
458     if (m_debugMode == QmlProjectWithCppPlugins) {
459         Debugger::DebuggerStartParameters sp;
460         sp.startMode = Debugger::StartExternal;
461         sp.executable = executableFile;
462         sp.processArgs = executableArguments.split(QLatin1Char(' '));
463         runControl = factories.first()->create(sp);
464         return qobject_cast<Debugger::DebuggerRunControl *>(runControl);
465     }
466
467     if (m_debugMode == CppProjectWithQmlEngines) {
468         if (factories.length() && factories.first()->canRun(runConfig, ProjectExplorer::Constants::DEBUGMODE)) {
469             runControl = factories.first()->create(runConfig, ProjectExplorer::Constants::DEBUGMODE);
470             return qobject_cast<Debugger::DebuggerRunControl *>(runControl);
471         }
472     }
473
474     return 0;
475 }
476
477 void Inspector::connected(QDeclarativeEngineDebug *client)
478 {
479     m_client = client;
480     resetViews();
481 }
482
483 void Inspector::updateMenuActions()
484 {
485     bool enabled = true;
486     if (m_simultaneousCppAndQmlDebugMode)
487         enabled = (m_cppDebuggerState == Debugger::DebuggerNotReady && m_clientProxy->isUnconnected());
488     else
489         enabled = m_clientProxy->isUnconnected();
490 }
491
492 void Inspector::debuggerStateChanged(int newState)
493 {
494 #if 0
495     // FIXME: AAA: adjsut to new debugger states
496     if (m_simultaneousCppAndQmlDebugMode) {
497         switch(newState) {
498         case Debugger::EngineStarting:
499             {
500                 m_connectionInitialized = false;
501                 break;
502             }
503         case Debugger::EngineStartFailed:
504         case Debugger::InferiorStartFailed:
505             emit statusMessage(tr("Debugging failed: could not start C++ debugger."));
506             break;
507         case Debugger::InferiorRunningRequested:
508             {
509                 if (m_cppDebuggerState == Debugger::InferiorStopped) {
510                     // re-enable UI again
511 //#warning enable the UI here
512                 }
513                 break;
514             }
515         case Debugger::InferiorRunning:
516             {
517                 if (!m_connectionInitialized) {
518                     m_connectionInitialized = true;
519                     m_connectionTimer->setInterval(ConnectionAttemptSimultaneousInterval);
520                     m_connectionTimer->start();
521                 }
522                 break;
523             }
524         case Debugger::InferiorStopped:
525             {
526 //#warning disable the UI here
527                 break;
528             }
529         case Debugger::EngineShuttingDown:
530             {
531                 m_connectionInitialized = false;
532                 // here it's safe to enable the debugger windows again -
533                 // disabled ones look ugly.
534 //#warning enable the UI here
535                 m_simultaneousCppAndQmlDebugMode = false;
536                 break;
537             }
538         default:
539             break;
540         }
541     }
542 #endif
543     m_cppDebuggerState = newState;
544     updateMenuActions();
545 }
546
547 void Inspector::reloadQmlViewer()
548 {
549     m_clientProxy->reloadQmlViewer();
550 }
551
552 void Inspector::setSimpleDockWidgetArrangement()
553 {
554 #if 0
555     Utils::FancyMainWindow *mainWindow = Debugger::DebuggerUISwitcher::instance()->mainWindow();
556
557     mainWindow->setTrackingEnabled(false);
558     QList<QDockWidget *> dockWidgets = mainWindow->dockWidgets();
559     foreach (QDockWidget *dockWidget, dockWidgets) {
560         if (m_dockWidgets.contains(dockWidget)) {
561             dockWidget->setFloating(false);
562             mainWindow->removeDockWidget(dockWidget);
563         }
564     }
565
566     foreach (QDockWidget *dockWidget, dockWidgets) {
567         if (m_dockWidgets.contains(dockWidget)) {
568             mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
569             dockWidget->show();
570         }
571     }
572     mainWindow->splitDockWidget(mainWindow->toolBarDockWidget(), m_propertyWatcherDock, Qt::Vertical);
573     //mainWindow->tabifyDockWidget(m_frameRateDock, m_propertyWatcherDock);
574     mainWindow->tabifyDockWidget(m_propertyWatcherDock, m_expressionQueryDock);
575     mainWindow->tabifyDockWidget(m_propertyWatcherDock, m_inspectorOutputDock);
576     m_propertyWatcherDock->raise();
577
578     m_inspectorOutputDock->setVisible(false);
579
580     mainWindow->setTrackingEnabled(true);
581 #endif
582 }
583
584 void Inspector::setSelectedItemsByObjectReference(QList<QDeclarativeDebugObjectReference> objectReferences)
585 {
586     if (objectReferences.length())
587         gotoObjectReferenceDefinition(objectReferences.first());
588 }
589
590 void Inspector::gotoObjectReferenceDefinition(const QDeclarativeDebugObjectReference &obj)
591 {
592     Q_UNUSED(obj);
593
594     QDeclarativeDebugFileReference source = obj.source();
595     const QString fileName = source.url().toLocalFile();
596
597     if (source.lineNumber() < 0 || !QFile::exists(fileName))
598         return;
599
600     Core::EditorManager *editorManager = Core::EditorManager::instance();
601     Core::IEditor *editor = editorManager->openEditor(fileName, QString(), Core::EditorManager::NoModeSwitch);
602     TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor);
603
604     if (textEditor) {
605         editorManager->addCurrentPositionToNavigationHistory();
606         textEditor->gotoLine(source.lineNumber());
607         textEditor->widget()->setFocus();
608     }
609 }
610
611 QDeclarativeDebugExpressionQuery *Inspector::executeExpression(int objectDebugId, const QString &objectId,
612                                                                const QString &propertyName, const QVariant &value)
613 {
614     if (objectId.length()) {
615         QString quoteWrappedValue = value.toString();
616         if (addQuotesForData(value))
617             quoteWrappedValue = QString("'%1'").arg(quoteWrappedValue); // ### FIXME this code is wrong!
618
619         QString constructedExpression = objectId + "." + propertyName + "=" + quoteWrappedValue;
620         return m_client.data()->queryExpressionResult(objectDebugId, constructedExpression, this);
621     }
622
623     return 0;
624 }
625
626 bool Inspector::addQuotesForData(const QVariant &value) const
627 {
628     switch (value.type()) {
629     case QVariant::String:
630     case QVariant::Color:
631     case QVariant::Date:
632         return true;
633     default:
634         break;
635     }
636
637     return false;
638 }