**************************************************************************/
#include "qmlengine.h"
+#include "qmladapter.h"
+#include "debuggeractions.h"
+#include "debuggertooltip.h"
#include "debuggerconstants.h"
#include "debuggerplugin.h"
#include "debuggerdialogs.h"
#include "debuggerstringutils.h"
+#include "debuggeruiswitcher.h"
+#include "debuggerrunner.h"
#include "breakhandler.h"
#include "moduleshandler.h"
#include "watchhandler.h"
#include "watchutils.h"
-#include "canvasframerate.h"
-
-#include <projectexplorer/environment.h>
+#include <extensionsystem/pluginmanager.h>
+#include <projectexplorer/applicationlauncher.h>
+#include <utils/environment.h>
#include <utils/qtcassert.h>
#include <QtCore/QDateTime>
#include <QtGui/QMainWindow>
#include <QtGui/QMessageBox>
#include <QtGui/QToolTip>
+#include <QtGui/QTextDocument>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
-#include <private/qdeclarativedebug_p.h>
-#include <private/qdeclarativedebugclient_p.h>
-
#define DEBUG_QML 1
#if DEBUG_QML
# define SDEBUG(s) qDebug() << s
#endif
# define XSDEBUG(s) qDebug() << s
-#define CB(callback) &QmlEngine::callback, STRINGIFY(callback)
-
-//#define USE_CONGESTION_CONTROL
-
+enum {
+ MaxConnectionAttempts = 50,
+ ConnectionAttemptDefaultInterval = 200
+};
namespace Debugger {
namespace Internal {
QString type;
bool hasChildren;
s >> data.exp >> data.name >> value >> type >> hasChildren >> data.objectId;
- data.setType(type, false);
+ data.setType(type.toUtf8(), false);
data.setValue(value);
data.setHasChildren(hasChildren);
data.setAllUnneeded();
return s;
}
-class QmlResponse
-{
-public:
- QmlResponse() {}
- QmlResponse(const QByteArray &data_) : data(data_) {}
+} // namespace Internal
- QString toString() const { return data; }
+struct QmlEnginePrivate {
+ explicit QmlEnginePrivate(QmlEngine *q);
- QByteArray data;
+ int m_ping;
+ QmlAdapter *m_adapter;
+ ProjectExplorer::ApplicationLauncher m_applicationLauncher;
+ bool m_addedAdapterToObjectPool;
+ bool m_attachToRunningExternalApp;
+ bool m_hasShutdown;
};
+QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q) :
+ m_ping(0)
+, m_adapter(new QmlAdapter(q))
+, m_addedAdapterToObjectPool(false)
+, m_attachToRunningExternalApp(false)
+, m_hasShutdown(false)
+{
+}
+
///////////////////////////////////////////////////////////////////////
//
-// QmlDebuggerClient
+// QmlEngine
//
///////////////////////////////////////////////////////////////////////
-#if 0 //QmlJSInspector does that for us now.
-class QmlDebuggerClient : public QDeclarativeDebugClient
+QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters)
+ : DebuggerEngine(startParameters), d(new QmlEnginePrivate(this))
{
- Q_OBJECT
+ setObjectName(QLatin1String("QmlEngine"));
+}
-public:
- QmlDebuggerClient(QDeclarativeDebugConnection *connection, QmlEngine *engine)
- : QDeclarativeDebugClient(QLatin1String("QDeclarativeEngine"), connection)
- , m_connection(connection), m_engine(engine)
- {
- setEnabled(true);
- }
+QmlEngine::~QmlEngine()
+{
+}
- void sendMessage(const QByteArray &msg)
- {
- QTC_kASSERT(isConnected(), /**/);
- qDebug() << "SENDING: " << quoteUnprintableLatin1(msg);
- QDeclarativeDebugClient::sendMessage(msg);
- }
+void QmlEngine::setAttachToRunningExternalApp(bool value)
+{
+ d->m_attachToRunningExternalApp = value;
+}
- void messageReceived(const QByteArray &data)
- {
- m_engine->messageReceived(data);
- }
+void QmlEngine::pauseConnection()
+{
+ d->m_adapter->pauseConnection();
+}
+void QmlEngine::gotoLocation(const QString &fileName, int lineNumber, bool setMarker)
+{
+ QString processedFilename = fileName;
- QDeclarativeDebugConnection *m_connection;
- QmlEngine *m_engine;
-};
+ if (isShadowBuildProject())
+ processedFilename = fromShadowBuildFilename(fileName);
+ DebuggerEngine::gotoLocation(processedFilename, lineNumber, setMarker);
+}
-class QmlFrameRateClient : public QDeclarativeDebugClient
+void QmlEngine::gotoLocation(const Internal::StackFrame &frame, bool setMarker)
{
- Q_OBJECT
+ Internal::StackFrame adjustedFrame = frame;
+ if (isShadowBuildProject())
+ adjustedFrame.file = fromShadowBuildFilename(frame.file);
-public:
- QmlFrameRateClient(QDeclarativeDebugConnection *connection, QmlEngine *engine)
- : QDeclarativeDebugClient(QLatin1String("CanvasFrameRate"), connection)
- , m_connection(connection), m_engine(engine)
- {
- setEnabled(true);
- }
+ DebuggerEngine::gotoLocation(adjustedFrame, setMarker);
+}
- void messageReceived(const QByteArray &data)
- {
- Q_UNUSED(data);
- // FIXME
- //qDebug() << "CANVAS FRAME RATE: " << data.size();
- //m_engine->messageReceived(data);
- }
+void QmlEngine::setupInferior()
+{
+ QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
+ if (startParameters().startMode == AttachToRemote) {
+ emit remoteStartupRequested();
+ } else {
+ connect(&d->m_applicationLauncher, SIGNAL(processExited(int)),
+ this, SLOT(disconnected()));
+ connect(&d->m_applicationLauncher, SIGNAL(appendMessage(QString,bool)),
+ runControl(), SLOT(emitAppendMessage(QString,bool)));
+ connect(&d->m_applicationLauncher, SIGNAL(appendOutput(QString, bool)),
+ runControl(), SLOT(emitAddToOutputWindow(QString, bool)));
+ connect(&d->m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
+ runControl(), SLOT(bringApplicationToForeground(qint64)));
- QDeclarativeDebugConnection *m_connection;
- QmlEngine *m_engine;
-};
-#endif
+ d->m_applicationLauncher.setEnvironment(startParameters().environment);
+ d->m_applicationLauncher.setWorkingDirectory(startParameters().workingDirectory);
-///////////////////////////////////////////////////////////////////////
-//
-// QmlEngine
-//
-///////////////////////////////////////////////////////////////////////
+ notifyInferiorSetupOk();
+ }
+}
-QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters)
- : DebuggerEngine(startParameters)
+void QmlEngine::connectionEstablished()
{
-/*
- m_conn = 0;
- m_client = 0;
- m_engineDebugInterface = 0;
- m_frameRate = 0;
-
- m_watchTableModel = new Internal::WatchTableModel(0, this);
-
- m_objectTreeWidget = new Internal::ObjectTree;
- m_propertiesWidget = new Internal::ObjectPropertiesView(m_watchTableModel);
- m_watchTableView = new Internal::WatchTableView(m_watchTableModel);
- m_expressionWidget = new Internal::ExpressionQueryWidget(Internal::ExpressionQueryWidget::SeparateEntryMode);
-// m_frameRateWidget = new Internal::CanvasFrameRate;
-// m_frameRateWidget->setObjectName(QLatin1String("QmlDebugFrameRate"));
+ attemptBreakpointSynchronization();
- connect(Debugger::DebuggerPlugin::instance(),
- SIGNAL(stateChanged(int)), this, SLOT(debuggerStateChanged(int)));
+ ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
+ pluginManager->addObject(d->m_adapter);
+ pluginManager->addObject(this);
+ d->m_addedAdapterToObjectPool = true;
- m_editablePropertyTypes = QStringList() << "qreal" << "bool" << "QString"
- << "int" << "QVariant" << "QUrl" << "QColor";
+ plugin()->showMessage(tr("QML Debugger connected."), StatusBar);
- connect(m_connectionTimer, SIGNAL(timeout()), SLOT(pollInspector()));
- */
+ notifyEngineRunAndInferiorRunOk();
}
-QmlEngine::~QmlEngine()
+void QmlEngine::connectionStartupFailed()
{
+ QMessageBox::critical(0,
+ tr("Failed to connect to debugger"),
+ tr("Could not connect to QML debugger server at %1:%2.")
+ .arg(startParameters().qmlServerAddress)
+ .arg(startParameters().qmlServerPort));
+ notifyEngineRunFailed();
}
-void QmlEngine::executeDebuggerCommand(const QString &command)
+void QmlEngine::connectionError(QAbstractSocket::SocketError socketError)
{
- QByteArray cmd = command.toUtf8();
- cmd = cmd.mid(cmd.indexOf(' ') + 1);
- QByteArray null;
- null.append('\0');
- // FIXME: works for single-digit escapes only
- cmd.replace("\\0", null);
- cmd.replace("\\1", "\1");
- cmd.replace("\\3", "\3");
- //QmlCommand tcf;
- //tcf.command = cmd;
- //enqueueCommand(tcf);
+ if (socketError ==QAbstractSocket::RemoteHostClosedError)
+ plugin()->showMessage(tr("QML Debugger: Remote host closed connection."), StatusBar);
}
-void QmlEngine::setupInferior()
+
+void QmlEngine::serviceConnectionError(const QString &serviceName)
{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- attemptBreakpointSynchronization();
- notifyInferiorSetupOk();
+ plugin()->showMessage(tr("QML Debugger: Couldn't connect to service '%1'.").arg(serviceName), StatusBar);
}
void QmlEngine::runEngine()
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
- notifyEngineRunAndInferiorRunOk();
+
+ if (!d->m_attachToRunningExternalApp) {
+ d->m_applicationLauncher.start(ProjectExplorer::ApplicationLauncher::Gui,
+ startParameters().executable,
+ startParameters().processArgs);
+ }
+
+ d->m_adapter->beginConnection();
+ plugin()->showMessage(tr("QML Debugger connecting..."), StatusBar);
}
-void QmlEngine::shutdownInferior()
+void QmlEngine::handleRemoteSetupDone()
{
- QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
- notifyInferiorShutdownOk();
+ notifyInferiorSetupOk();
}
-void QmlEngine::shutdownEngine()
+void QmlEngine::handleRemoteSetupFailed(const QString &message)
{
- QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
- //m_objectTreeWidget->saveSettings(m_settings);
- //m_propertiesWidget->saveSettings(m_settings);
- //m_settings.saveSettings(Core::ICore::instance()->settings());
+ QMessageBox::critical(0,tr("Failed to start application"),
+ tr("Application startup failed: %1").arg(message));
+ notifyInferiorSetupFailed();
}
-const int serverPort = 3768;
-
-void QmlEngine::setupEngine()
+void QmlEngine::shutdownInferiorAsSlave()
{
- #if 0
- QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
- const DebuggerStartParameters &sp = startParameters();
- const int pos = sp.remoteChannel.indexOf(QLatin1Char(':'));
- const QString host = sp.remoteChannel.left(pos);
- const quint16 port = sp.remoteChannel.mid(pos + 1).toInt();
- qDebug() << "STARTING QML ENGINE" << host << port << sp.remoteChannel
- << sp.executable << sp.processArgs << sp.workingDirectory;
-
- ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); // empty env by default
- env.set("QML_DEBUG_SERVER_PORT", QString::number(serverPort));
-
- connect(&m_proc, SIGNAL(error(QProcess::ProcessError)),
- SLOT(handleProcError(QProcess::ProcessError)));
- connect(&m_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
- SLOT(handleProcFinished(int, QProcess::ExitStatus)));
- connect(&m_proc, SIGNAL(readyReadStandardOutput()),
- SLOT(readProcStandardOutput()));
- connect(&m_proc, SIGNAL(readyReadStandardError()),
- SLOT(readProcStandardError()));
-
- m_proc.setEnvironment(env.toStringList());
- m_proc.setWorkingDirectory(sp.workingDirectory);
- m_proc.start(sp.executable, sp.processArgs);
-
- if (!m_proc.waitForStarted()) {
- notifyEngineSetupFailed();
- return;
- }
-#endif
- notifyEngineSetupOk();
+ resetLocation();
- //m_frameRate = new CanvasFrameRate(0);
- //m_frameRate->show();
+ // This can be issued in almost any state. We assume, though,
+ // that at this point of time the inferior is not running anymore,
+ // even if stop notification were not issued or got lost.
+ if (state() == InferiorRunOk) {
+ setState(InferiorStopRequested);
+ setState(InferiorStopOk);
+ }
+ setState(InferiorShutdownRequested);
+ setState(InferiorShutdownOk);
}
-void QmlEngine::setupConnection()
+void QmlEngine::shutdownEngineAsSlave()
{
- #if 0
- //the qmlviewer right now connected using QmlJSInspector::InternalInspectorPlugin::ClientProxy
- QTC_ASSERT(m_conn == 0, /**/);
- m_conn = new QDeclarativeDebugConnection(this);
+ if (d->m_hasShutdown)
+ return;
+
+ disconnect(d->m_adapter, SIGNAL(connectionStartupFailed()), this, SLOT(connectionStartupFailed()));
+ d->m_adapter->closeConnection();
- connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
- SLOT(connectionStateChanged()));
- connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
- SLOT(connectionError()));
- connect(m_conn, SIGNAL(connected()),
- SLOT(connectionConnected()));
+ if (d->m_addedAdapterToObjectPool) {
+ ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
+ pluginManager->removeObject(d->m_adapter);
+ pluginManager->removeObject(this);
+ }
- QTC_ASSERT(m_client == 0, /**/);
- m_client = new QmlDebuggerClient(m_conn, this);
- (void) new QmlFrameRateClient(m_conn, this);
+ if (d->m_attachToRunningExternalApp) {
+ setState(EngineShutdownRequested, true);
+ setState(EngineShutdownOk, true);
+ setState(DebuggerFinished, true);
+ } else {
+ if (d->m_applicationLauncher.isRunning()) {
+ // should only happen if engine is ill
+ disconnect(&d->m_applicationLauncher, SIGNAL(processExited(int)), this, SLOT(disconnected()));
+ d->m_applicationLauncher.stop();
+ }
+ }
+ d->m_hasShutdown = true;
+}
+void QmlEngine::shutdownInferior()
+{
+ // don't do normal shutdown if running as slave engine
+ if (d->m_attachToRunningExternalApp)
+ return;
- QTC_ASSERT(m_engineDebugInterface == 0, /**/);
- m_engineDebugInterface = new QDeclarativeEngineDebug(m_conn, this);
+ QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
+ if (!d->m_applicationLauncher.isRunning()) {
+ showMessage(tr("Trying to stop while process is no longer running."), LogError);
+ } else {
+ disconnect(&d->m_applicationLauncher, SIGNAL(processExited(int)), this, SLOT(disconnected()));
+ if (!d->m_attachToRunningExternalApp)
+ d->m_applicationLauncher.stop();
+ }
+ notifyInferiorShutdownOk();
+}
- //m_objectTreeWidget->setEngineDebug(m_engineDebugInterface);
- //m_propertiesWidget->setEngineDebug(m_engineDebugInterface);
- //m_watchTableModel->setEngineDebug(m_engineDebugInterface);
- //m_expressionWidget->setEngineDebug(m_engineDebugInterface);
- //resetViews();
- //m_frameRateWidget->reset(m_conn);
+void QmlEngine::shutdownEngine()
+{
+ QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
- QHostAddress ha(QHostAddress::LocalHost);
+ shutdownEngineAsSlave();
- qDebug() << "CONNECTING TO " << ha.toString() << serverPort;
- m_conn->connectToHost(ha, serverPort);
+ notifyEngineShutdownOk();
+ plugin()->showMessage(QString(), StatusBar);
+}
- if (!m_conn->waitForConnected()) {
- qDebug() << "CONNECTION FAILED";
- notifyEngineSetupFailed();
- return;
+void QmlEngine::setupEngine()
+{
+ if (!d->m_attachToRunningExternalApp
+ && !startParameters().qmlObserverAvailable
+ && Internal::theDebuggerBoolSetting(Internal::UseQmlObserver))
+ {
+ showQmlObserverToolWarning();
}
- #endif
- notifyEngineRunAndInferiorStopOk();
+ d->m_adapter->setMaxConnectionAttempts(MaxConnectionAttempts);
+ d->m_adapter->setConnectionAttemptInterval(ConnectionAttemptDefaultInterval);
+ connect(d->m_adapter, SIGNAL(connectionError(QAbstractSocket::SocketError)),
+ SLOT(connectionError(QAbstractSocket::SocketError)));
+ connect(d->m_adapter, SIGNAL(serviceConnectionError(QString)), SLOT(serviceConnectionError(QString)));
+ connect(d->m_adapter, SIGNAL(connected()), SLOT(connectionEstablished()));
+ connect(d->m_adapter, SIGNAL(connectionStartupFailed()), SLOT(connectionStartupFailed()));
-// reloadEngines();
-// continueInferior();
+ notifyEngineSetupOk();
}
void QmlEngine::continueInferior()
{
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
- SDEBUG("QmlEngine::continueInferior()");
QByteArray reply;
QDataStream rs(&reply, QIODevice::WriteOnly);
rs << QByteArray("CONTINUE");
QDataStream rs(&reply, QIODevice::WriteOnly);
rs << QByteArray("INTERRUPT");
sendMessage(reply);
+ notifyInferiorStopOk();
}
void QmlEngine::executeStep()
{
- SDEBUG("QmlEngine::executeStep()");
QByteArray reply;
QDataStream rs(&reply, QIODevice::WriteOnly);
rs << QByteArray("STEPINTO");
void QmlEngine::executeStepI()
{
- SDEBUG("QmlEngine::executeStepI()");
QByteArray reply;
QDataStream rs(&reply, QIODevice::WriteOnly);
rs << QByteArray("STEPINTO");
void QmlEngine::executeStepOut()
{
- SDEBUG("QmlEngine::executeStepOut()");
QByteArray reply;
QDataStream rs(&reply, QIODevice::WriteOnly);
rs << QByteArray("STEPOUT");
sendMessage(reply);
notifyInferiorRunRequested();
notifyInferiorRunOk();
- SDEBUG("QmlEngine::nextExec()");
}
void QmlEngine::executeNextI()
void QmlEngine::attemptBreakpointSynchronization()
{
- BreakHandler *handler = breakHandler();
+ Internal::BreakHandler *handler = breakHandler();
//bool updateNeeded = false;
QSet< QPair<QString, qint32> > breakList;
for (int index = 0; index != handler->size(); ++index) {
- BreakpointData *data = handler->at(index);
- breakList << qMakePair(data->fileName, data->lineNumber.toInt());
+ Internal::BreakpointData *data = handler->at(index);
+ QString processedFilename = data->fileName;
+ if (isShadowBuildProject())
+ processedFilename = toShadowBuildFilename(data->fileName);
+ breakList << qMakePair(processedFilename, data->lineNumber);
}
{
}
}
+bool QmlEngine::acceptsBreakpoint(const Internal::BreakpointData *br)
+{
+ return (br->fileName.endsWith(QLatin1String("qml")) || br->fileName.endsWith(QLatin1String("js")));
+}
+
void QmlEngine::loadSymbols(const QString &moduleName)
{
Q_UNUSED(moduleName)
Q_UNUSED(moduleName)
}
-#if 0 //this is currently a signal connected to the QmlJSInspector::Internal::DebuggerClient
-void QmlEngine::sendMessage(const QByteArray &msg)
-{
- QTC_ASSERT(m_client, return);
- m_client->sendMessage(msg);
-}
-#endif
-
-
//////////////////////////////////////////////////////////////////////
//
// Tooltip specific stuff
//
//////////////////////////////////////////////////////////////////////
-static WatchData m_toolTip;
-static QPoint m_toolTipPos;
-static QHash<QString, WatchData> m_toolTipCache;
-
void QmlEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
{
- Q_UNUSED(mousePos)
- Q_UNUSED(editor)
- Q_UNUSED(cursorPos)
+ // this is processed by QML inspector, which has deps to qml js editor. Makes life easier.
+ emit tooltipRequested(mousePos, editor, cursorPos);
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
-void QmlEngine::assignValueInDebugger(const QString &expression,
- const QString &value)
-{
- XSDEBUG("ASSIGNING: " << expression + '=' + value);
+void QmlEngine::assignValueInDebugger(const Internal::WatchData *,
+ const QString &expression, const QVariant &valueV)
+{
+ QRegExp inObject("@([0-9a-fA-F]+)->(.+)");
+ if (inObject.exactMatch(expression)) {
+ bool ok = false;
+ quint64 objectId = inObject.cap(1).toULongLong(&ok, 16);
+ QString property = inObject.cap(2);
+ if (ok && objectId > 0 && !property.isEmpty()) {
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("SET_PROPERTY");
+ rs << expression.toUtf8() << objectId << property << valueV.toString();
+ sendMessage(reply);
+ }
+ }
}
-void QmlEngine::updateWatchData(const WatchData &data)
+void QmlEngine::updateWatchData(const Internal::WatchData &data, const Internal::WatchUpdateFlags &)
{
// qDebug() << "UPDATE WATCH DATA" << data.toString();
//watchHandler()->rebuildModel();
sendMessage(reply);
}
- if (!data.name.isEmpty() && data.isChildrenNeeded() && watchHandler()->isExpandedIName(data.iname)) {
+ if (!data.name.isEmpty() && data.isChildrenNeeded()
+ && watchHandler()->isExpandedIName(data.iname))
expandObject(data.iname, data.objectId);
- }
{
QByteArray reply;
rs << watchHandler()->watchedExpressions();
sendMessage(reply);
}
+
+ if (!data.isSomethingNeeded())
+ watchHandler()->insertData(data);
}
void QmlEngine::expandObject(const QByteArray& iname, quint64 objectId)
sendMessage(reply);
}
+void QmlEngine::sendPing()
+{
+ d->m_ping++;
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("PING");
+ rs << d->m_ping;
+ sendMessage(reply);
+}
+namespace Internal {
DebuggerEngine *createQmlEngine(const DebuggerStartParameters &sp)
{
return new QmlEngine(sp);
}
+} // namespace Internal
unsigned QmlEngine::debuggerCapabilities() const
{
QByteArray command;
stream >> command;
- showMessage(_("RECEIVED RESPONSE: ") + quoteUnprintableLatin1(message));
+ showMessage(QLatin1String("RECEIVED RESPONSE: ") + Internal::quoteUnprintableLatin1(message));
if (command == "STOPPED") {
- notifyInferiorSpontaneousStop();
+ if (state() == InferiorRunOk) {
+ notifyInferiorSpontaneousStop();
+ }
QList<QPair<QString, QPair<QString, qint32> > > backtrace;
- QList<WatchData> watches;
- QList<WatchData> locals;
+ QList<Internal::WatchData> watches;
+ QList<Internal::WatchData> locals;
stream >> backtrace >> watches >> locals;
- StackFrames stackFrames;
+ Internal::StackFrames stackFrames;
typedef QPair<QString, QPair<QString, qint32> > Iterator;
foreach (const Iterator &it, backtrace) {
- StackFrame frame;
+ Internal::StackFrame frame;
frame.file = it.second.first;
frame.line = it.second.second;
frame.function = it.first;
stackHandler()->setFrames(stackFrames);
watchHandler()->beginCycle();
+ bool needPing = false;
- foreach (WatchData data, watches) {
+ foreach (Internal::WatchData data, watches) {
data.iname = watchHandler()->watcherName(data.exp);
watchHandler()->insertData(data);
- if (watchHandler()->expandedINames().contains(data.iname))
+ if (watchHandler()->expandedINames().contains(data.iname)) {
+ needPing = true;
expandObject(data.iname, data.objectId);
+ }
}
- foreach (WatchData data, locals) {
+ foreach (Internal::WatchData data, locals) {
data.iname = "local." + data.exp;
watchHandler()->insertData(data);
- if (watchHandler()->expandedINames().contains(data.iname))
+ if (watchHandler()->expandedINames().contains(data.iname)) {
+ needPing = true;
expandObject(data.iname, data.objectId);
+ }
}
- watchHandler()->endCycle();
+ if (needPing)
+ sendPing();
+ else
+ watchHandler()->endCycle();
+
+ bool becauseOfException;
+ stream >> becauseOfException;
+ if (becauseOfException) {
+ QString error;
+ stream >> error;
+
+ QString msg =
+ tr("<p>An Uncaught Exception occured in <i>%1</i>:</p><p>%2</p>")
+ .arg(stackFrames.value(0).file, Qt::escape(error));
+ showMessageBox(QMessageBox::Information, tr("Uncaught Exception"), msg);
+ } else {
+ //
+ // Make breakpoint non-pending
+ //
+ QString file;
+ int line = -1;
+
+ if (!stackFrames.isEmpty()) {
+ file = stackFrames.at(0).file;
+ line = stackFrames.at(0).line;
+
+ if (isShadowBuildProject()) {
+ file = fromShadowBuildFilename(file);
+ }
+ }
+
+ Internal::BreakHandler *handler = breakHandler();
+ for (int index = 0; index != handler->size(); ++index) {
+ Internal::BreakpointData *data = handler->at(index);
+ QString processedFilename = data->fileName;
+ if (processedFilename == file
+ && data->lineNumber == line) {
+ data->pending = false;
+ data->updateMarker();
+ }
+ }
+ }
} else if (command == "RESULT") {
- WatchData data;
+ Internal::WatchData data;
QByteArray iname;
stream >> iname >> data;
data.iname = iname;
- watchHandler()->insertData(data);
-
+ if (iname.startsWith("watch.")) {
+ watchHandler()->insertData(data);
+ } else if(iname == "console") {
+ plugin()->showMessage(data.value, ScriptConsoleOutput);
+ } else {
+ qWarning() << "QmlEngine: Unexcpected result: " << iname << data.value;
+ }
} else if (command == "EXPANDED") {
- QList<WatchData> result;
+ QList<Internal::WatchData> result;
QByteArray iname;
stream >> iname >> result;
- foreach (WatchData data, result) {
+ bool needPing = false;
+ foreach (Internal::WatchData data, result) {
data.iname = iname + '.' + data.exp;
watchHandler()->insertData(data);
- if (watchHandler()->expandedINames().contains(data.iname))
+ if (watchHandler()->expandedINames().contains(data.iname)) {
+ needPing = true;
expandObject(data.iname, data.objectId);
+ }
}
+ if (needPing)
+ sendPing();
} else if (command == "LOCALS") {
- QList<WatchData> locals;
+ QList<Internal::WatchData> locals;
int frameId;
stream >> frameId >> locals;
watchHandler()->beginCycle();
- foreach (WatchData data, locals) {
+ bool needPing = false;
+ foreach (Internal::WatchData data, locals) {
data.iname = "local." + data.exp;
watchHandler()->insertData(data);
- if (watchHandler()->expandedINames().contains(data.iname))
+ if (watchHandler()->expandedINames().contains(data.iname)) {
+ needPing = true;
expandObject(data.iname, data.objectId);
+ }
}
- watchHandler()->endCycle();
+ if (needPing)
+ sendPing();
+ else
+ watchHandler()->endCycle();
+
+ } else if (command == "PONG") {
+ int ping;
+ stream >> ping;
+ if (ping == d->m_ping)
+ watchHandler()->endCycle();
} else {
qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
}
}
-
-#if 0
-class EngineComboBox : public QComboBox
-{
- Q_OBJECT
-public:
- struct EngineInfo
- {
- QString name;
- int id;
- };
-
- EngineComboBox(QWidget *parent = 0);
-
- void addEngine(int engine, const QString &name);
- void clearEngines();
-
-protected:
-
-private:
- QList<EngineInfo> m_engines;
-};
-
-EngineComboBox::EngineComboBox(QWidget *parent)
- : QComboBox(parent)
-{
- setEnabled(false);
- setEditable(false);
-}
-
-void EngineComboBox::addEngine(int engine, const QString &name)
+void QmlEngine::disconnected()
{
- EngineInfo info;
- info.id = engine;
- if (name.isEmpty())
- info.name = tr("Engine %1", "engine number").arg(engine);
- else
- info.name = name;
- m_engines << info;
-
- addItem(info.name);
+ plugin()->showMessage(tr("QML Debugger disconnected."), StatusBar);
+ notifyInferiorExited();
}
-void EngineComboBox::clearEngines()
+void QmlEngine::executeDebuggerCommand(const QString& command)
{
- m_engines.clear();
- clear();
-}
-
-
-bool QmlEngine::setDebugConfigurationDataFromProject(ProjectExplorer::Project *projectToDebug)
-{
- if (!projectToDebug) {
- emit statusMessage(tr("Invalid project, debugging canceled."));
- return false;
- }
-
- QmlProjectManager::QmlProjectRunConfiguration* config =
- qobject_cast<QmlProjectManager::QmlProjectRunConfiguration*>(projectToDebug->activeTarget()->activeRunConfiguration());
- if (!config) {
- emit statusMessage(tr("Cannot find project run configuration, debugging canceled."));
- return false;
- }
- m_runConfigurationDebugData.serverAddress = config->debugServerAddress();
- m_runConfigurationDebugData.serverPort = config->debugServerPort();
- m_connectionTimer->setInterval(ConnectionAttemptDefaultInterval);
-
- return true;
-}
-
-void QmlEngine::startQmlProjectDebugger()
-{
- m_simultaneousCppAndQmlDebugMode = false;
- m_connectionTimer->start();
-}
-
-bool QmlEngine::connectToViewer()
-{
- if (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState)
- return false;
-
- delete m_engineDebugInterface; m_engineDebugInterface = 0;
-
- if (m_conn) {
- m_conn->disconnectFromHost();
- delete m_conn;
- m_conn = 0;
- }
-
- QString host = m_runConfigurationDebugData.serverAddress;
- quint16 port = quint16(m_runConfigurationDebugData.serverPort);
-
- m_conn = new QDeclarativeDebugConnection(this);
- connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
- SLOT(connectionStateChanged()));
- connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
- SLOT(connectionError()));
-
- emit statusMessage(tr("[Inspector] set to connect to debug server %1:%2").arg(host).arg(port));
- m_conn->connectToHost(host, port);
- // blocks until connected; if no connection is available, will fail immediately
-
- if (!m_conn->waitForConnected())
- return false;
-
- QTC_ASSERT(m_debuggerRunControl, return false);
- QmlEngine *engine = qobject_cast<QmlEngine *>(m_debuggerRunControl->engine());
- QTC_ASSERT(engine, return false);
-
- (void) new DebuggerClient(m_conn, engine);
-
- return true;
-}
-
-void QmlEngine::disconnectFromViewer()
-{
- m_conn->disconnectFromHost();
- updateMenuActions();
-}
-
-void QmlEngine::connectionStateChanged()
-{
- switch (m_conn->state()) {
- case QAbstractSocket::UnconnectedState:
- {
- emit statusMessage(tr("[Inspector] disconnected.\n\n"));
- resetViews();
- updateMenuActions();
- break;
- }
- case QAbstractSocket::HostLookupState:
- emit statusMessage(tr("[Inspector] resolving host..."));
- break;
- case QAbstractSocket::ConnectingState:
- emit statusMessage(tr("[Inspector] connecting to debug server..."));
- break;
- case QAbstractSocket::ConnectedState:
- {
- emit statusMessage(tr("[Inspector] connected.\n"));
-
- resetViews();
-// m_frameRateWidget->reset(m_conn);
-
- break;
- }
- case QAbstractSocket::ClosingState:
- emit statusMessage(tr("[Inspector] closing..."));
- break;
- case QAbstractSocket::BoundState:
- case QAbstractSocket::ListeningState:
- break;
- }
-}
-
-void QmlEngine::resetViews()
-{
- m_objectTreeWidget->cleanup();
- m_propertiesWidget->clear();
- m_expressionWidget->clear();
- m_watchTableModel->removeAllWatches();
-}
-
-void QmlEngine::createDockWidgets()
-{
-
- m_engineComboBox = new Internal::EngineComboBox;
- m_engineComboBox->setEnabled(false);
- connect(m_engineComboBox, SIGNAL(currentIndexChanged(int)),
- SLOT(queryEngineContext(int)));
-
- // FancyMainWindow uses widgets' window titles for tab labels
-// m_frameRateWidget->setWindowTitle(tr("Frame rate"));
-
- Utils::StyledBar *treeOptionBar = new Utils::StyledBar;
- QHBoxLayout *treeOptionBarLayout = new QHBoxLayout(treeOptionBar);
- treeOptionBarLayout->setContentsMargins(5, 0, 5, 0);
- treeOptionBarLayout->setSpacing(5);
- treeOptionBarLayout->addWidget(new QLabel(tr("QML engine:")));
- treeOptionBarLayout->addWidget(m_engineComboBox);
-
- QWidget *treeWindow = new QWidget;
- treeWindow->setObjectName(QLatin1String("QmlDebugTree"));
- treeWindow->setWindowTitle(tr("Object Tree"));
- QVBoxLayout *treeWindowLayout = new QVBoxLayout(treeWindow);
- treeWindowLayout->setMargin(0);
- treeWindowLayout->setSpacing(0);
- treeWindowLayout->setContentsMargins(0,0,0,0);
- treeWindowLayout->addWidget(treeOptionBar);
- treeWindowLayout->addWidget(m_objectTreeWidget);
-
-
- m_watchTableView->setModel(m_watchTableModel);
- Internal::WatchTableHeaderView *header = new Internal::WatchTableHeaderView(m_watchTableModel);
- m_watchTableView->setHorizontalHeader(header);
-
- connect(m_objectTreeWidget, SIGNAL(activated(QDeclarativeDebugObjectReference)),
- this, SLOT(treeObjectActivated(QDeclarativeDebugObjectReference)));
-
- connect(m_objectTreeWidget, SIGNAL(currentObjectChanged(QDeclarativeDebugObjectReference)),
- m_propertiesWidget, SLOT(reload(QDeclarativeDebugObjectReference)));
-
- connect(m_objectTreeWidget, SIGNAL(expressionWatchRequested(QDeclarativeDebugObjectReference,QString)),
- m_watchTableModel, SLOT(expressionWatchRequested(QDeclarativeDebugObjectReference,QString)));
-
- connect(m_propertiesWidget, SIGNAL(watchToggleRequested(QDeclarativeDebugObjectReference,QDeclarativeDebugPropertyReference)),
- m_watchTableModel, SLOT(togglePropertyWatch(QDeclarativeDebugObjectReference,QDeclarativeDebugPropertyReference)));
-
- connect(m_watchTableModel, SIGNAL(watchCreated(QDeclarativeDebugWatch*)),
- m_propertiesWidget, SLOT(watchCreated(QDeclarativeDebugWatch*)));
-
- connect(m_watchTableModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
- m_watchTableView, SLOT(scrollToBottom()));
-
- connect(m_watchTableView, SIGNAL(objectActivated(int)),
- m_objectTreeWidget, SLOT(setCurrentObject(int)));
-
- connect(m_objectTreeWidget, SIGNAL(currentObjectChanged(QDeclarativeDebugObjectReference)),
- m_expressionWidget, SLOT(setCurrentObject(QDeclarativeDebugObjectReference)));
-
-
- Core::MiniSplitter *propSplitter = new Core::MiniSplitter(Qt::Horizontal);
- Core::MiniSplitter *propWatcherSplitter = new Core::MiniSplitter(Qt::Vertical);
- propWatcherSplitter->addWidget(m_propertiesWidget);
- propWatcherSplitter->addWidget(m_watchTableView);
- propWatcherSplitter->setStretchFactor(0, 2);
- propWatcherSplitter->setStretchFactor(1, 1);
- propWatcherSplitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
-
- propSplitter->setWindowTitle(tr("Properties and Watchers"));
- propSplitter->setObjectName(QLatin1String("QmlDebugProperties"));
- propSplitter->addWidget(m_objectTreeWidget);
- propSplitter->addWidget(propWatcherSplitter);
- propSplitter->setStretchFactor(0, 1);
- propSplitter->setStretchFactor(1, 3);
-
- InspectorOutputWidget *inspectorOutput = new InspectorOutputWidget();
- inspectorOutput->setObjectName(QLatin1String("QmlDebugInspectorOutput"));
- connect(this, SIGNAL(statusMessage(QString)),
- inspectorOutput, SLOT(addInspectorStatus(QString)));
-
- Debugger::DebuggerUISwitcher *uiSwitcher = Debugger::DebuggerUISwitcher::instance();
-
- m_watchTableView->hide();
-// m_objectTreeDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
-// treeWindow, Qt::BottomDockWidgetArea);
-// m_frameRateDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
-// m_frameRateWidget, Qt::BottomDockWidgetArea);
- m_propertyWatcherDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
- propSplitter, Qt::BottomDockWidgetArea);
- m_inspectorOutputDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
- inspectorOutput, Qt::BottomDockWidgetArea);
-
- m_expressionWidget->setWindowTitle(tr("Script Console"));
- m_expressionQueryDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
- m_expressionWidget, Qt::BottomDockWidgetArea);
-
- m_inspectorOutputDock->setToolTip(tr("Output of the QML inspector, such as information on connecting to the server."));
-
- m_dockWidgets << /*m_objectTreeDock << *//*m_frameRateDock << */ m_propertyWatcherDock
- << m_inspectorOutputDock << m_expressionQueryDock;
-
- m_context = new Internal::InspectorContext(m_objectTreeWidget);
- m_propWatcherContext = new Internal::InspectorContext(m_propertyWatcherDock);
-
- Core::ICore *core = Core::ICore::instance();
- core->addContextObject(m_propWatcherContext);
- core->addContextObject(m_context);
-
- m_simultaneousDebugAction = new QAction(this);
- m_simultaneousDebugAction->setText(tr("Start Debugging C++ and QML Simultaneously..."));
- connect(m_simultaneousDebugAction, SIGNAL(triggered()),
- this, SLOT(simultaneouslyDebugQmlCppApplication()));
-
- Core::ActionManager *am = core->actionManager();
- Core::ActionContainer *mstart = am->actionContainer(ProjectExplorer::Constants::M_DEBUG_STARTDEBUGGING);
- Core::Command *cmd = am->registerAction(m_simultaneousDebugAction, Constants::M_DEBUG_SIMULTANEOUSLY,
- m_context->context());
- cmd->setAttribute(Core::Command::CA_Hide);
- mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
-
- m_settings.readSettings(core->settings());
- m_objectTreeWidget->readSettings(m_settings);
- m_propertiesWidget->readSettings(m_settings);
-
- connect(m_objectTreeWidget, SIGNAL(contextHelpIdChanged(QString)), m_context,
- SLOT(setContextHelpId(QString)));
- connect(m_watchTableView, SIGNAL(contextHelpIdChanged(QString)), m_propWatcherContext,
- SLOT(setContextHelpId(QString)));
- connect(m_propertiesWidget, SIGNAL(contextHelpIdChanged(QString)), m_propWatcherContext,
- SLOT(setContextHelpId(QString)));
- connect(m_expressionWidget, SIGNAL(contextHelpIdChanged(QString)), m_propWatcherContext,
- SLOT(setContextHelpId(QString)));
-}
-
-void QmlEngine::simultaneouslyDebugQmlCppApplication()
-{
- QString errorMessage;
- ProjectExplorer::ProjectExplorerPlugin *pex = ProjectExplorer::ProjectExplorerPlugin::instance();
- ProjectExplorer::Project *project = pex->startupProject();
-
- if (!project)
- errorMessage = QString(tr("No project was found."));
- else {
- if (project->id() == "QmlProjectManager.QmlProject")
- errorMessage = attachToQmlViewerAsExternalApp(project);
- else {
- errorMessage = attachToExternalCppAppWithQml(project);
- }
- }
-
- if (!errorMessage.isEmpty())
- QMessageBox::warning(Core::ICore::instance()->mainWindow(), "Failed to debug C++ and QML", errorMessage);
-}
-
-QString QmlEngine::attachToQmlViewerAsExternalApp(ProjectExplorer::Project *project)
-{
- m_debugMode = QmlProjectWithCppPlugins;
-
- QmlProjectManager::QmlProjectRunConfiguration* runConfig =
- qobject_cast<QmlProjectManager::QmlProjectRunConfiguration*>(project->activeTarget()->activeRunConfiguration());
-
- if (!runConfig)
- return QString(tr("No run configurations were found for the project '%1'.").arg(project->displayName()));
-
- Internal::StartExternalQmlDialog dlg(Debugger::DebuggerUISwitcher::instance()->mainWindow());
-
- QString importPathArgument = "-I";
- QString execArgs;
- if (runConfig->viewerArguments().contains(importPathArgument))
- execArgs = runConfig->viewerArguments().join(" ");
- else {
- QFileInfo qmlFileInfo(runConfig->viewerArguments().last());
- importPathArgument.append(" " + qmlFileInfo.absolutePath() + " ");
- execArgs = importPathArgument + runConfig->viewerArguments().join(" ");
- }
-
-
- dlg.setPort(runConfig->debugServerPort());
- dlg.setDebuggerUrl(runConfig->debugServerAddress());
- dlg.setProjectDisplayName(project->displayName());
- dlg.setDebugMode(Internal::StartExternalQmlDialog::QmlProjectWithCppPlugins);
- dlg.setQmlViewerArguments(execArgs);
- dlg.setQmlViewerPath(runConfig->viewerPath());
-
- if (dlg.exec() != QDialog::Accepted)
- return QString();
-
- m_runConfigurationDebugData.serverAddress = dlg.debuggerUrl();
- m_runConfigurationDebugData.serverPort = dlg.port();
- m_settings.setExternalPort(dlg.port());
- m_settings.setExternalUrl(dlg.debuggerUrl());
-
- ProjectExplorer::Environment customEnv = ProjectExplorer::Environment::systemEnvironment(); // empty env by default
- customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
-
- Debugger::DebuggerRunControl *debuggableRunControl =
- createDebuggerRunControl(runConfig, dlg.qmlViewerPath(), dlg.qmlViewerArguments());
-
- return executeDebuggerRunControl(debuggableRunControl, &customEnv);
-}
-
-QString QmlEngine::attachToExternalCppAppWithQml(ProjectExplorer::Project *project)
-{
- m_debugMode = CppProjectWithQmlEngines;
-
- ProjectExplorer::LocalApplicationRunConfiguration* runConfig =
- qobject_cast<ProjectExplorer::LocalApplicationRunConfiguration*>(project->activeTarget()->activeRunConfiguration());
-
- if (!project->activeTarget() || !project->activeTarget()->activeRunConfiguration())
- return QString(tr("No run configurations were found for the project '%1'.").arg(project->displayName()));
- else if (!runConfig)
- return QString(tr("No valid run configuration was found for the project %1. "
- "Only locally runnable configurations are supported.\n"
- "Please check your project settings.").arg(project->displayName()));
-
- Internal::StartExternalQmlDialog dlg(Debugger::DebuggerUISwitcher::instance()->mainWindow());
-
- dlg.setPort(m_settings.externalPort());
- dlg.setDebuggerUrl(m_settings.externalUrl());
- dlg.setProjectDisplayName(project->displayName());
- dlg.setDebugMode(Internal::StartExternalQmlDialog::CppProjectWithQmlEngine);
- if (dlg.exec() != QDialog::Accepted)
- return QString();
-
- m_runConfigurationDebugData.serverAddress = dlg.debuggerUrl();
- m_runConfigurationDebugData.serverPort = dlg.port();
- m_settings.setExternalPort(dlg.port());
- m_settings.setExternalUrl(dlg.debuggerUrl());
-
- ProjectExplorer::Environment customEnv = runConfig->environment();
- customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
- Debugger::DebuggerRunControl *debuggableRunControl = createDebuggerRunControl(runConfig);
- return executeDebuggerRunControl(debuggableRunControl, &customEnv);
-}
-
-QString QmlEngine::executeDebuggerRunControl(Debugger::DebuggerRunControl *debuggableRunControl, ProjectExplorer::Environment *environment)
-{
- ProjectExplorer::ProjectExplorerPlugin *pex = ProjectExplorer::ProjectExplorerPlugin::instance();
-
- // to make sure we have a valid, debuggable run control, find the correct factory for it
- if (debuggableRunControl) {
-
- // modify the env
- debuggableRunControl->setCustomEnvironment(*environment);
-
- pex->startRunControl(debuggableRunControl, ProjectExplorer::Constants::DEBUGMODE);
- m_simultaneousCppAndQmlDebugMode = true;
-
- return QString();
- }
- return QString(tr("A valid run control was not registered in Qt Creator for this project run configuration."));;
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("EXEC");
+ rs << QByteArray("console") << command;
+ sendMessage(reply);
}
-Debugger::DebuggerRunControl *QmlEngine::createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
- const QString &executableFile, const QString &executableArguments)
+bool QmlEngine::isShadowBuildProject() const
{
- ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
- const QList<Debugger::DebuggerRunControlFactory *> factories = pm->getObjects<Debugger::DebuggerRunControlFactory>();
- ProjectExplorer::RunControl *runControl = 0;
-
- if (m_debugMode == QmlProjectWithCppPlugins) {
- Debugger::DebuggerStartParameters sp;
- sp.startMode = Debugger::StartExternal;
- sp.executable = executableFile;
- sp.processArgs = executableArguments.split(QLatin1Char(' '));
- runControl = factories.first()->create(sp);
- return qobject_cast<Debugger::DebuggerRunControl *>(runControl);
- }
-
- if (m_debugMode == CppProjectWithQmlEngines) {
- if (factories.length() && factories.first()->canRun(runConfig, ProjectExplorer::Constants::DEBUGMODE)) {
- runControl = factories.first()->create(runConfig, ProjectExplorer::Constants::DEBUGMODE);
- return qobject_cast<Debugger::DebuggerRunControl *>(runControl);
- }
+ if (!startParameters().projectBuildDir.isEmpty()
+ && (startParameters().projectDir != startParameters().projectBuildDir))
+ {
+ return true;
}
-
- return 0;
-}
-
-void QmlEngine::updateMenuActions()
-{
-
- bool enabled = true;
- if (m_simultaneousCppAndQmlDebugMode)
- enabled = (m_cppDebuggerState == Debugger::DebuggerNotReady && (!m_conn || m_conn->state() == QAbstractSocket::UnconnectedState));
- else
- enabled = (!m_conn || m_conn->state() == QAbstractSocket::UnconnectedState);
-
- m_simultaneousDebugAction->setEnabled(enabled);
+ return false;
}
-
-void QmlEngine::debuggerStateChanged(int newState)
+QString QmlEngine::qmlImportPath() const
{
- if (m_simultaneousCppAndQmlDebugMode) {
-
- switch(newState) {
- case Debugger::EngineSetupRequested:
- {
- m_connectionInitialized = false;
- break;
- }
- case Debugger::AdapterStartFailed:
- case Debugger::InferiorSetupFailed:
- emit statusMessage(QString(tr("Debugging failed: could not start C++ debugger.")));
- break;
- case Debugger::InferiorRunRequested:
- {
- if (m_cppDebuggerState == Debugger::InferiorStopOk) {
- // re-enable UI again
- m_objectTreeWidget->setEnabled(true);
- m_propertiesWidget->setEnabled(true);
- m_expressionWidget->setEnabled(true);
- }
- break;
- }
- case Debugger::InferiorRunOk:
- {
- if (!m_connectionInitialized) {
- m_connectionInitialized = true;
- m_connectionTimer->setInterval(ConnectionAttemptSimultaneousInterval);
- m_connectionTimer->start();
- }
- break;
- }
- case Debugger::InferiorStopOk:
- {
- m_objectTreeWidget->setEnabled(false);
- m_propertiesWidget->setEnabled(false);
- m_expressionWidget->setEnabled(false);
- break;
- }
- case Debugger::EngineShutdownRequested:
- {
- m_connectionInitialized = false;
- // here it's safe to enable the debugger windows again -
- // disabled ones look ugly.
- m_objectTreeWidget->setEnabled(true);
- m_propertiesWidget->setEnabled(true);
- m_expressionWidget->setEnabled(true);
- m_simultaneousCppAndQmlDebugMode = false;
- break;
- }
- default:
+ QString result;
+ const QString qmlImportPathPrefix("QML_IMPORT_PATH=");
+ QStringList env = startParameters().environment;
+ foreach(const QString &envStr, env) {
+ if (envStr.startsWith(qmlImportPathPrefix)) {
+ result = envStr.mid(qmlImportPathPrefix.length());
break;
}
}
-
- m_cppDebuggerState = newState;
- updateMenuActions();
+ return result;
}
-
-void QmlEngine::setSimpleDockWidgetArrangement()
+QString QmlEngine::toShadowBuildFilename(const QString &filename) const
{
- Utils::FancyMainWindow *mainWindow = Debugger::DebuggerUISwitcher::instance()->mainWindow();
-
- mainWindow->setTrackingEnabled(false);
- QList<QDockWidget *> dockWidgets = mainWindow->dockWidgets();
- foreach (QDockWidget *dockWidget, dockWidgets) {
- if (m_dockWidgets.contains(dockWidget)) {
- dockWidget->setFloating(false);
- mainWindow->removeDockWidget(dockWidget);
- }
- }
+ QString newFilename = filename;
+ QString importPath = qmlImportPath();
- foreach (QDockWidget *dockWidget, dockWidgets) {
- if (m_dockWidgets.contains(dockWidget)) {
- mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
- dockWidget->show();
- }
+ newFilename = mangleFilenamePaths(filename, startParameters().projectDir, startParameters().projectBuildDir);
+ if (newFilename == filename && !importPath.isEmpty()) {
+ newFilename = mangleFilenamePaths(filename, startParameters().projectDir, importPath);
}
- mainWindow->splitDockWidget(mainWindow->toolBarDockWidget(), m_propertyWatcherDock, Qt::Vertical);
- //mainWindow->tabifyDockWidget(m_frameRateDock, m_propertyWatcherDock);
- mainWindow->tabifyDockWidget(m_propertyWatcherDock, m_expressionQueryDock);
- mainWindow->tabifyDockWidget(m_propertyWatcherDock, m_inspectorOutputDock);
- m_propertyWatcherDock->raise();
- m_inspectorOutputDock->setVisible(false);
-
- mainWindow->setTrackingEnabled(true);
-}
-#endif
-#if 0
-void QmlEngine::reloadEngines()
-{
- //m_engineComboBox->setEnabled(false);
-
- QDeclarativeDebugEnginesQuery *query =
- m_engineDebugInterface->queryAvailableEngines(this);
- if (!query->isWaiting())
- enginesChanged(query);
- else
- QObject::connect(query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
- this, SLOT(enginesChanged()));
-}
-
-void QmlEngine::enginesChanged()
-{
- enginesChanged(qobject_cast<QDeclarativeDebugEnginesQuery *>(sender()));
+ return newFilename;
}
-void QmlEngine::enginesChanged(QDeclarativeDebugEnginesQuery *query)
+QString QmlEngine::mangleFilenamePaths(const QString &filename, const QString &oldBasePath, const QString &newBasePath) const
{
- //m_engineComboBox->clearEngines();
- QList<QDeclarativeDebugEngineReference> engines = query->engines();
- if (engines.isEmpty())
- qWarning("QMLDEBUGGER: NO ENGINES FOUND!");
-
- //m_engineComboBox->setEnabled(true);
-
- for (int i = 0; i < engines.count(); ++i)
- qDebug() << "ENGINE: " << engines.at(i).debugId() << engines.at(i).name();
- // m_engineComboBox->addEngine(engines.at(i).debugId(), engines.at(i).name());
+ QDir oldBaseDir(oldBasePath);
+ QDir newBaseDir(newBasePath);
+ QFileInfo fileInfo(filename);
- if (engines.count() > 0) {
- // m_engineComboBox->setCurrentIndex(engines.at(0).debugId());
- queryEngineContext(engines.at(0));
- }
-}
+ if (oldBaseDir.exists() && newBaseDir.exists() && fileInfo.exists()) {
+ if (fileInfo.absoluteFilePath().startsWith(oldBaseDir.canonicalPath())) {
+ QString fileRelativePath = fileInfo.canonicalFilePath().mid(oldBasePath.length());
+ QFileInfo projectFile(newBaseDir.canonicalPath() + QLatin1Char('/') + fileRelativePath);
-void QmlEngine::queryEngineContext(const QDeclarativeDebugEngineReference &engine)
-{
- QDeclarativeDebugRootContextQuery *query =
- m_engineDebugInterface->queryRootContexts(engine, this);
-
- if (!query->isWaiting())
- contextChanged();
- else
- QObject::connect(query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
- this, SLOT(contextChanged()));
-}
-
-void QmlEngine::contextChanged()
-{
- contextChanged(qobject_cast<QDeclarativeDebugRootContextQuery *>(sender()));
-}
-
-void QmlEngine::contextChanged(QDeclarativeDebugRootContextQuery *query)
-{
- QTC_ASSERT(query, return);
- //dump(query->rootContext(), 0);
- foreach (const QDeclarativeDebugObjectReference &object, query->rootContext().objects())
- reloadObject(object);
-}
-
-void QmlEngine::reloadObject(const QDeclarativeDebugObjectReference &object)
-{
- qDebug() << "RELOAD OBJECT: " << object.debugId() << object.idString()
- << object.className();
- QDeclarativeDebugObjectQuery *query =
- m_engineDebugInterface->queryObjectRecursive(object, this);
- if (!query->isWaiting())
- objectFetched(query, QDeclarativeDebugQuery::Completed);
- else
- QObject::connect(query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
- this, SLOT(objectFetched(QDeclarativeDebugQuery::State)));
-}
-
-void QmlEngine::objectFetched(QDeclarativeDebugQuery::State state)
-{
- objectFetched(qobject_cast<QDeclarativeDebugObjectQuery *>(sender()), state);
-}
-
-void QmlEngine::objectFetched(QDeclarativeDebugObjectQuery *query,
- QDeclarativeDebugQuery::State state)
-{
- QTC_ASSERT(query, return);
- QTC_ASSERT(state == QDeclarativeDebugQuery::Completed, return);
- //dump(m_query->object(), 0);
-
- m_watches.clear();
- buildTree(query->object(), "local");
-
- qDebug() << "WATCHES CREATED: " << m_watches.size();
- //watchHandler()->beginCycle();
- //watchHandler()->insertBulkData(list);
- //watchHandler()->endCycle();
- //setCurrentItem(topLevelItem(0));
-
- // this ugly hack is needed if user wants to see internal structs
- // on startup - debugger does not load them until towards the end,
- // so essentially loading twice gives us the full list as everything
- // is already loaded.
- //if (m_showUninspectableItems && !m_showUninspectableOnInitDone) {
- // m_showUninspectableOnInitDone = true;
- // reloadObject(m_currentObjectDebugId);
- //}
-}
-
-void QmlEngine::buildTree(const QDeclarativeDebugObjectReference &obj,
- const QByteArray &iname)
-{
- //QTC_ASSERT(obj.contextDebugId() >= 0, return);
- WatchData data;
- data.iname = iname;
-
- if (obj.idString().isEmpty())
- data.name = QString("<%1>").arg(obj.className());
- else
- data.name = obj.idString();
-
- data.value = "?";
- data.type = "?";
- data.setHasChildren(!obj.children().isEmpty());
- data.setAllUnneeded();
- qDebug() << "CREATED ITEM " << data.iname << data.name;
- m_watches.append(m_engineDebugInterface->addWatch(obj, data.name, 0));
- //QDeclarativeDebugPropertyWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugPropertyReference &property, QObject *parent)
-
- //data.userRole = qVariantFromValue(obj);
- /*
- if (parent && obj.contextDebugId() >= 0
- && obj.contextDebugId() != parent->data(0, Qt::UserRole
- ).value<QDeclarativeDebugObjectReference>().contextDebugId())
- {
-
- QDeclarativeDebugFileReference source = obj.source();
- if (!source.url().isEmpty()) {
- QString toolTipString = QLatin1String("URL: ") + source.url().toString();
- item->setToolTip(0, toolTipString);
+ if (projectFile.exists())
+ return projectFile.canonicalFilePath();
}
-
- } else {
- item->setExpanded(true);
}
-
- if (obj.contextDebugId() < 0)
- item->setHasValidDebugId(false);
-*/
-
- for (int i = 0; i < obj.children().size(); ++i)
- buildTree(obj.children().at(i), iname + '.' + QByteArray::number(i));
-}
-#endif
-#if 0
-void QmlEngine::treeObjectActivated(const QDeclarativeDebugObjectReference &obj)
-{
- QDeclarativeDebugFileReference source = obj.source();
- QString fileName = source.url().toLocalFile();
-
- if (source.lineNumber() < 0 || !QFile::exists(fileName))
- return;
-
- Core::EditorManager *editorManager = Core::EditorManager::instance();
- Core::IEditor *editor = editorManager->openEditor(fileName, QString(), Core::EditorManager::NoModeSwitch);
- TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor);
-
- if (textEditor) {
- editorManager->addCurrentPositionToNavigationHistory();
- textEditor->gotoLine(source.lineNumber());
- textEditor->widget()->setFocus();
- }
-}
-
-bool QmlEngine::canEditProperty(const QString &propertyType)
-{
- return m_editablePropertyTypes.contains(propertyType);
-}
-
-QDeclarativeDebugExpressionQuery *QmlEngine::executeExpression(int objectDebugId, const QString &objectId,
- const QString &propertyName, const QVariant &value)
-{
- //qDebug() << entity.property << entity.title << entity.objectId;
- if (objectId.length()) {
-
- QString quoteWrappedValue = value.toString();
- if (addQuotesForData(value))
- quoteWrappedValue = QString("'%1'").arg(quoteWrappedValue);
-
- QString constructedExpression = objectId + "." + propertyName + "=" + quoteWrappedValue;
- //qDebug() << "EXPRESSION:" << constructedExpression;
- return m_client->queryExpressionResult(objectDebugId, constructedExpression, this);
- }
-
- return 0;
-}
-
-bool QmlEngine::addQuotesForData(const QVariant &value) const
-{
- switch (value.type()) {
- case QVariant::String:
- case QVariant::Color:
- case QVariant::Date:
- return true;
- default:
- break;
- }
-
- return false;
-}
-
-ObjectTree::ObjectTree(QDeclarativeEngineDebug *client, QWidget *parent)
- : QTreeWidget(parent),
- m_client(client),
- m_query(0), m_clickedItem(0), m_showUninspectableItems(false),
- m_currentObjectDebugId(0), m_showUninspectableOnInitDone(false)
-{
- setAttribute(Qt::WA_MacShowFocusRect, false);
- setFrameStyle(QFrame::NoFrame);
- setHeaderHidden(true);
- setExpandsOnDoubleClick(false);
-
- m_addWatchAction = new QAction(tr("Add watch expression..."), this);
- m_toggleUninspectableItemsAction = new QAction(tr("Show uninspectable items"), this);
- m_toggleUninspectableItemsAction->setCheckable(true);
- m_goToFileAction = new QAction(tr("Go to file"), this);
- connect(m_toggleUninspectableItemsAction, SIGNAL(triggered()), SLOT(toggleUninspectableItems()));
- connect(m_addWatchAction, SIGNAL(triggered()), SLOT(addWatch()));
- connect(m_goToFileAction, SIGNAL(triggered()), SLOT(goToFile()));
-
- connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
- SLOT(currentItemChanged(QTreeWidgetItem *)));
- connect(this, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
- SLOT(activated(QTreeWidgetItem *)));
- connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged()));
-}
-
-void ObjectTree::readSettings(const InspectorSettings &settings)
-{
- if (settings.showUninspectableItems() != m_showUninspectableItems)
- toggleUninspectableItems();
-}
-void ObjectTree::saveSettings(InspectorSettings &settings)
-{
- settings.setShowUninspectableItems(m_showUninspectableItems);
-}
-
-void ObjectTree::setEngineDebug(QDeclarativeEngineDebug *client)
-{
- m_client = client;
-}
-
-void ObjectTree::toggleUninspectableItems()
-{
- m_showUninspectableItems = !m_showUninspectableItems;
- m_toggleUninspectableItemsAction->setChecked(m_showUninspectableItems);
- reload(m_currentObjectDebugId);
-}
-
-void ObjectTree::selectionChanged()
-{
- if (selectedItems().isEmpty())
- return;
-
- QTreeWidgetItem *item = selectedItems().first();
- if (item)
- emit contextHelpIdChanged(InspectorContext::contextHelpIdForItem(item->text(0)));
-}
-
-
-void ObjectTree::setCurrentObject(int debugId)
-{
- QTreeWidgetItem *item = findItemByObjectId(debugId);
- if (item) {
- setCurrentItem(item);
- scrollToItem(item);
- item->setExpanded(true);
- }
-
-
+ return filename;
}
+QString QmlEngine::fromShadowBuildFilename(const QString &filename) const
{
- if (!item)
- return;
+ QString newFilename = filename;
+ QString importPath = qmlImportPath();
- QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
- if (obj.debugId() >= 0)
- emit currentObjectChanged(obj);
-}
-
-void ObjectTree::activated(QTreeWidgetItem *item)
-{
- if (!item)
- return;
-
- QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
- if (obj.debugId() >= 0)
- emit activated(obj);
-}
-
-void ObjectTree::cleanup()
-{
- m_showUninspectableOnInitDone = false;
- clear();
-}
-
-void ObjectTree::dump(const QDeclarativeDebugContextReference &ctxt, int ind)
-{
- QByteArray indent(ind * 4, ' ');
- qWarning().nospace() << indent.constData() << ctxt.debugId() << " "
- << qPrintable(ctxt.name());
-
- for (int ii = 0; ii < ctxt.contexts().count(); ++ii)
- dump(ctxt.contexts().at(ii), ind + 1);
-
- for (int ii = 0; ii < ctxt.objects().count(); ++ii)
- dump(ctxt.objects().at(ii), ind);
-}
-
-void ObjectTree::dump(const QDeclarativeDebugObjectReference &obj, int ind)
-{
- QByteArray indent(ind * 4, ' ');
- qWarning().nospace() << indent.constData() << qPrintable(obj.className())
- << " " << qPrintable(obj.idString()) << " "
- << obj.debugId();
-
- for (int ii = 0; ii < obj.children().count(); ++ii)
- dump(obj.children().at(ii), ind + 1);
-}
-
-QTreeWidgetItem *ObjectTree::findItemByObjectId(int debugId) const
-{
- for (int i=0; i<topLevelItemCount(); ++i) {
- QTreeWidgetItem *item = findItem(topLevelItem(i), debugId);
- if (item)
- return item;
+ newFilename = mangleFilenamePaths(filename, startParameters().projectBuildDir, startParameters().projectDir);
+ if (newFilename == filename && !importPath.isEmpty()) {
+ newFilename = mangleFilenamePaths(filename, startParameters().projectBuildDir, importPath);
}
- return 0;
+ return newFilename;
}
-QTreeWidgetItem *ObjectTree::findItem(QTreeWidgetItem *item, int debugId) const
-{
- if (item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>().debugId() == debugId)
- return item;
-
- QTreeWidgetItem *child;
- for (int i=0; i<item->childCount(); ++i) {
- child = findItem(item->child(i), debugId);
- if (child)
- return child;
- }
-
- return 0;
-}
-
-void ObjectTree::addWatch()
-{
- QDeclarativeDebugObjectReference obj =
- currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
-
- bool ok = false;
- QString watch = QInputDialog::getText(this, tr("Watch expression"),
- tr("Expression:"), QLineEdit::Normal, QString(), &ok);
- if (ok && !watch.isEmpty())
- emit expressionWatchRequested(obj, watch);
-
-}
-
-void ObjectTree::goToFile()
-{
- QDeclarativeDebugObjectReference obj =
- currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
-
- if (obj.debugId() >= 0)
- emit activated(obj);
-}
-
-void ObjectTree::contextMenuEvent(QContextMenuEvent *event)
-{
-
- m_clickedItem = itemAt(QPoint(event->pos().x(),
- event->pos().y() ));
- if (!m_clickedItem)
- return;
-
- QMenu menu;
- menu.addAction(m_addWatchAction);
- menu.addAction(m_goToFileAction);
- if (m_currentObjectDebugId) {
- menu.addSeparator();
- menu.addAction(m_toggleUninspectableItemsAction);
- }
-
- menu.exec(event->globalPos());
-}
-
-} // Internal
-} // Qml
-#endif
-
-} // namespace Internal
} // namespace Debugger
-#include "qmlengine.moc"