forked from qt-creator/qt-creator
Add a stack window menu entry to display QML stack frame.
Add language field to stack frame. Add virtual for loading QML stack invoked by stack window context menu, implement for CDB, GDB. Task-number: QTCREATORBUG-11144 Change-Id: Ic39be3978b40d96ed18cb69a8355296ec572ece7 Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -1109,7 +1109,8 @@ bool CdbEngine::hasCapability(unsigned cap) const
|
|||||||
|CreateFullBacktraceCapability
|
|CreateFullBacktraceCapability
|
||||||
|OperateByInstructionCapability
|
|OperateByInstructionCapability
|
||||||
|RunToLineCapability
|
|RunToLineCapability
|
||||||
|MemoryAddressCapability);
|
|MemoryAddressCapability
|
||||||
|
|AdditionalQmlStackCapability);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbEngine::executeStep()
|
void CdbEngine::executeStep()
|
||||||
@@ -1471,6 +1472,11 @@ void CdbEngine::activateFrame(int index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const StackFrame frame = frames.at(index);
|
const StackFrame frame = frames.at(index);
|
||||||
|
if (frame.language != CppLanguage) {
|
||||||
|
gotoLocation(frame);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (debug || debugLocals)
|
if (debug || debugLocals)
|
||||||
qDebug("activateFrame idx=%d '%s' %d", index,
|
qDebug("activateFrame idx=%d '%s' %d", index,
|
||||||
qPrintable(frame.file), frame.line);
|
qPrintable(frame.file), frame.line);
|
||||||
@@ -2933,6 +2939,9 @@ static StackFrames parseFrames(const GdbMi &gdbmi, bool *incomplete = 0)
|
|||||||
frame.file = QFile::decodeName(fullName.data());
|
frame.file = QFile::decodeName(fullName.data());
|
||||||
frame.line = frameMi["line"].data().toInt();
|
frame.line = frameMi["line"].data().toInt();
|
||||||
frame.usable = false; // To be decided after source path mapping.
|
frame.usable = false; // To be decided after source path mapping.
|
||||||
|
const GdbMi languageMi = frameMi["language"];
|
||||||
|
if (languageMi.isValid() && languageMi.data() == "js")
|
||||||
|
frame.language = QmlLanguage;
|
||||||
}
|
}
|
||||||
frame.function = QLatin1String(frameMi["func"].data());
|
frame.function = QLatin1String(frameMi["func"].data());
|
||||||
frame.from = QLatin1String(frameMi["from"].data());
|
frame.from = QLatin1String(frameMi["from"].data());
|
||||||
@@ -2987,6 +2996,39 @@ unsigned CdbEngine::parseStackTrace(const GdbMi &data, bool sourceStepInto)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CdbEngine::loadAdditionalQmlStack()
|
||||||
|
{
|
||||||
|
postExtensionCommand("qmlstack", QByteArray(), 0, &CdbEngine::handleAdditionalQmlStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CdbEngine::handleAdditionalQmlStack(const CdbExtensionCommandPtr &reply)
|
||||||
|
{
|
||||||
|
QString errorMessage;
|
||||||
|
do {
|
||||||
|
if (!reply->success) {
|
||||||
|
errorMessage = QLatin1String(reply->errorMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GdbMi stackGdbMi;
|
||||||
|
stackGdbMi.fromString(reply->reply);
|
||||||
|
if (!stackGdbMi.isValid()) {
|
||||||
|
errorMessage = QLatin1String("GDBMI parser error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
StackFrames qmlFrames = parseFrames(stackGdbMi);
|
||||||
|
const int qmlFrameCount = qmlFrames.size();
|
||||||
|
if (!qmlFrameCount) {
|
||||||
|
errorMessage = QLatin1String("Empty stack");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < qmlFrameCount; ++i)
|
||||||
|
qmlFrames[i].fixQmlFrame(startParameters());
|
||||||
|
stackHandler()->prependFrames(qmlFrames);
|
||||||
|
} while (false);
|
||||||
|
if (!errorMessage.isEmpty())
|
||||||
|
showMessage(QLatin1String("Unable to obtain QML stack trace: ") + errorMessage, LogError);
|
||||||
|
}
|
||||||
|
|
||||||
void CdbEngine::mergeStartParametersSourcePathMap()
|
void CdbEngine::mergeStartParametersSourcePathMap()
|
||||||
{
|
{
|
||||||
const DebuggerStartParameters &sp = startParameters();
|
const DebuggerStartParameters &sp = startParameters();
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ public:
|
|||||||
virtual void reloadRegisters();
|
virtual void reloadRegisters();
|
||||||
virtual void reloadSourceFiles();
|
virtual void reloadSourceFiles();
|
||||||
virtual void reloadFullStack();
|
virtual void reloadFullStack();
|
||||||
|
void loadAdditionalQmlStack();
|
||||||
|
|
||||||
static QString extensionLibraryName(bool is64Bit);
|
static QString extensionLibraryName(bool is64Bit);
|
||||||
|
|
||||||
@@ -241,6 +242,7 @@ private:
|
|||||||
void handleWidgetAt(const CdbExtensionCommandPtr &);
|
void handleWidgetAt(const CdbExtensionCommandPtr &);
|
||||||
void handleBreakPoints(const CdbExtensionCommandPtr &);
|
void handleBreakPoints(const CdbExtensionCommandPtr &);
|
||||||
void handleBreakPoints(const GdbMi &value);
|
void handleBreakPoints(const GdbMi &value);
|
||||||
|
void handleAdditionalQmlStack(const CdbExtensionCommandPtr &);
|
||||||
NormalizedSourceFileName sourceMapNormalizeFileNameFromDebugger(const QString &f);
|
NormalizedSourceFileName sourceMapNormalizeFileNameFromDebugger(const QString &f);
|
||||||
void updateLocalVariable(const QByteArray &iname);
|
void updateLocalVariable(const QByteArray &iname);
|
||||||
void updateLocals(bool forNewStackFrame = false);
|
void updateLocals(bool forNewStackFrame = false);
|
||||||
|
|||||||
@@ -161,7 +161,8 @@ enum DebuggerCapabilities
|
|||||||
RunToLineCapability = 0x800000,
|
RunToLineCapability = 0x800000,
|
||||||
MemoryAddressCapability = 0x1000000,
|
MemoryAddressCapability = 0x1000000,
|
||||||
ShowModuleSectionsCapability = 0x200000,
|
ShowModuleSectionsCapability = 0x200000,
|
||||||
WatchComplexExpressionsCapability = 0x400000 // Used to filter out challenges for cdb.
|
WatchComplexExpressionsCapability = 0x400000, // Used to filter out challenges for cdb.
|
||||||
|
AdditionalQmlStackCapability = 0x800000 // C++ debugger engine is able to retrieve QML stack as well.
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LogChannel
|
enum LogChannel
|
||||||
|
|||||||
@@ -1402,6 +1402,10 @@ void DebuggerEngine::reloadFullStack()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebuggerEngine::loadAdditionalQmlStack()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void DebuggerEngine::reloadDebuggingHelpers()
|
void DebuggerEngine::reloadDebuggingHelpers()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ public:
|
|||||||
virtual void reloadRegisters();
|
virtual void reloadRegisters();
|
||||||
virtual void reloadSourceFiles();
|
virtual void reloadSourceFiles();
|
||||||
virtual void reloadFullStack();
|
virtual void reloadFullStack();
|
||||||
|
virtual void loadAdditionalQmlStack();
|
||||||
virtual void reloadDebuggingHelpers();
|
virtual void reloadDebuggingHelpers();
|
||||||
|
|
||||||
virtual void setRegisterValue(int regnr, const QString &value);
|
virtual void setRegisterValue(int regnr, const QString &value);
|
||||||
|
|||||||
@@ -2020,7 +2020,8 @@ bool GdbEngine::hasCapability(unsigned cap) const
|
|||||||
| OperateByInstructionCapability
|
| OperateByInstructionCapability
|
||||||
| RunToLineCapability
|
| RunToLineCapability
|
||||||
| WatchComplexExpressionsCapability
|
| WatchComplexExpressionsCapability
|
||||||
| MemoryAddressCapability))
|
| MemoryAddressCapability
|
||||||
|
| AdditionalQmlStackCapability))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (startParameters().startMode == AttachCore)
|
if (startParameters().startMode == AttachCore)
|
||||||
@@ -3207,6 +3208,90 @@ void GdbEngine::reloadFullStack()
|
|||||||
QVariant::fromValue<StackCookie>(StackCookie(true, true)));
|
QVariant::fromValue<StackCookie>(StackCookie(true, true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GdbEngine::loadAdditionalQmlStack()
|
||||||
|
{
|
||||||
|
// Scan for QV4::ExecutionContext parameter in the parameter list of a V4 call.
|
||||||
|
postCommand("-stack-list-arguments --simple-values", NeedsStop, CB(handleQmlStackFrameArguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan the arguments of a stack list for the address of a QV4::ExecutionContext.
|
||||||
|
static quint64 findJsExecutionContextAddress(const GdbMi &stackArgsResponse, const QByteArray &qtNamespace)
|
||||||
|
{
|
||||||
|
const GdbMi frameList = stackArgsResponse.childAt(0);
|
||||||
|
if (!frameList.childCount())
|
||||||
|
return 0;
|
||||||
|
QByteArray jsExecutionContextType = qtNamespace;
|
||||||
|
if (!jsExecutionContextType.isEmpty())
|
||||||
|
jsExecutionContextType.append("::");
|
||||||
|
jsExecutionContextType.append("QV4::ExecutionContext *");
|
||||||
|
foreach (const GdbMi &frameNode, frameList.children()) {
|
||||||
|
foreach (const GdbMi &argNode, frameNode["args"].children()) {
|
||||||
|
if (argNode["type"].data() == jsExecutionContextType) {
|
||||||
|
bool ok;
|
||||||
|
const quint64 address = argNode["value"].data().toULongLong(&ok, 16);
|
||||||
|
if (ok && address)
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString msgCannotLoadQmlStack(const QString &why)
|
||||||
|
{
|
||||||
|
return _("Unable to load QML stack: ") + why;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleQmlStackFrameArguments(const GdbResponse &response)
|
||||||
|
{
|
||||||
|
if (!response.data.isValid()) {
|
||||||
|
showMessage(msgCannotLoadQmlStack(_("No stack obtained.")), LogError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const quint64 contextAddress = findJsExecutionContextAddress(response.data, qtNamespace());
|
||||||
|
if (!contextAddress) {
|
||||||
|
showMessage(msgCannotLoadQmlStack(_("The address of the JS execution context could not be found.")), LogError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Call the debug function of QML with the context address to obtain the QML stack trace.
|
||||||
|
QByteArray command = "-data-evaluate-expression \"qt_v4StackTrace((QV4::ExecutionContext *)0x";
|
||||||
|
command += QByteArray::number(contextAddress, 16);
|
||||||
|
command += ")\"";
|
||||||
|
postCommand(command, CB(handleQmlStackTrace));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleQmlStackTrace(const GdbResponse &response)
|
||||||
|
{
|
||||||
|
if (!response.data.isValid()) {
|
||||||
|
showMessage(msgCannotLoadQmlStack(_("No result obtained.")), LogError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Prepend QML stack frames to existing C++ stack frames.
|
||||||
|
QByteArray stackData = response.data["value"].data();
|
||||||
|
const int index = stackData.indexOf("stack=");
|
||||||
|
if (index == -1) {
|
||||||
|
showMessage(msgCannotLoadQmlStack(_("Malformed result.")), LogError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stackData.remove(0, index);
|
||||||
|
stackData.replace("\\\"", "\"");
|
||||||
|
GdbMi stackMi;
|
||||||
|
stackMi.fromString(stackData);
|
||||||
|
const int qmlFrameCount = stackMi.childCount();
|
||||||
|
if (!qmlFrameCount) {
|
||||||
|
showMessage(msgCannotLoadQmlStack(_("No stack frames obtained.")), LogError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QList<StackFrame> qmlFrames;
|
||||||
|
qmlFrames.reserve(qmlFrameCount);
|
||||||
|
for (int i = 0; i < qmlFrameCount; ++i) {
|
||||||
|
StackFrame frame = parseStackFrame(stackMi.childAt(i), i);
|
||||||
|
frame.fixQmlFrame(startParameters());
|
||||||
|
qmlFrames.append(frame);
|
||||||
|
}
|
||||||
|
stackHandler()->prependFrames(qmlFrames);
|
||||||
|
}
|
||||||
|
|
||||||
void GdbEngine::reloadStack(bool forceGotoLocation)
|
void GdbEngine::reloadStack(bool forceGotoLocation)
|
||||||
{
|
{
|
||||||
PENDING_DEBUG("RELOAD STACK");
|
PENDING_DEBUG("RELOAD STACK");
|
||||||
@@ -3233,6 +3318,8 @@ StackFrame GdbEngine::parseStackFrame(const GdbMi &frameMi, int level)
|
|||||||
frame.line = frameMi["line"].toInt();
|
frame.line = frameMi["line"].toInt();
|
||||||
frame.address = frameMi["addr"].toAddress();
|
frame.address = frameMi["addr"].toAddress();
|
||||||
frame.usable = QFileInfo(frame.file).isReadable();
|
frame.usable = QFileInfo(frame.file).isReadable();
|
||||||
|
if (frameMi["language"].data() == "js")
|
||||||
|
frame.language = QmlLanguage;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3308,6 +3395,10 @@ void GdbEngine::activateFrame(int frameIndex)
|
|||||||
|
|
||||||
QTC_ASSERT(frameIndex < handler->stackSize(), return);
|
QTC_ASSERT(frameIndex < handler->stackSize(), return);
|
||||||
|
|
||||||
|
if (handler->frameAt(frameIndex).language == QmlLanguage) {
|
||||||
|
gotoLocation(handler->frameAt(frameIndex));
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Assuming the command always succeeds this saves a roundtrip.
|
// Assuming the command always succeeds this saves a roundtrip.
|
||||||
// Otherwise the lines below would need to get triggered
|
// Otherwise the lines below would need to get triggered
|
||||||
// after a response to this -stack-select-frame here.
|
// after a response to this -stack-select-frame here.
|
||||||
|
|||||||
@@ -409,6 +409,9 @@ protected:
|
|||||||
void handleThreadNames(const GdbResponse &response);
|
void handleThreadNames(const GdbResponse &response);
|
||||||
Q_SLOT void reloadStack(bool forceGotoLocation);
|
Q_SLOT void reloadStack(bool forceGotoLocation);
|
||||||
Q_SLOT virtual void reloadFullStack();
|
Q_SLOT virtual void reloadFullStack();
|
||||||
|
virtual void loadAdditionalQmlStack();
|
||||||
|
void handleQmlStackFrameArguments(const GdbResponse &response);
|
||||||
|
void handleQmlStackTrace(const GdbResponse &response);
|
||||||
int currentFrame() const;
|
int currentFrame() const;
|
||||||
|
|
||||||
QList<GdbMi> m_currentFunctionArgs;
|
QList<GdbMi> m_currentFunctionArgs;
|
||||||
|
|||||||
@@ -28,10 +28,13 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "stackframe.h"
|
#include "stackframe.h"
|
||||||
|
#include "debuggerstartparameters.h"
|
||||||
|
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
|
||||||
@@ -45,7 +48,7 @@ namespace Internal {
|
|||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
StackFrame::StackFrame()
|
StackFrame::StackFrame()
|
||||||
: level(-1), line(-1), address(0), usable(false)
|
: language(CppLanguage), level(-1), line(-1), address(0), usable(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void StackFrame::clear()
|
void StackFrame::clear()
|
||||||
@@ -90,7 +93,9 @@ QString StackFrame::toToolTip() const
|
|||||||
str << "<tr><td>" << tr("Address:") << "</td><td>"
|
str << "<tr><td>" << tr("Address:") << "</td><td>"
|
||||||
<< formatToolTipAddress(address) << "</td></tr>";
|
<< formatToolTipAddress(address) << "</td></tr>";
|
||||||
if (!function.isEmpty())
|
if (!function.isEmpty())
|
||||||
str << "<tr><td>" << tr("Function:") << "</td><td>" << function << "</td></tr>";
|
str << "<tr><td>"
|
||||||
|
<< (language == CppLanguage ? tr("Function:") : tr("JS-Function:"))
|
||||||
|
<< "</td><td>" << function << "</td></tr>";
|
||||||
if (!file.isEmpty())
|
if (!file.isEmpty())
|
||||||
str << "<tr><td>" << tr("File:") << "</td><td>" << filePath << "</td></tr>";
|
str << "<tr><td>" << tr("File:") << "</td><td>" << filePath << "</td></tr>";
|
||||||
if (line != -1)
|
if (line != -1)
|
||||||
@@ -127,6 +132,35 @@ QString StackFrame::toToolTip() const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to resolve files of a QML stack (resource files).
|
||||||
|
void StackFrame::fixQmlFrame(const DebuggerStartParameters &sp)
|
||||||
|
{
|
||||||
|
if (language != QmlLanguage)
|
||||||
|
return;
|
||||||
|
QFileInfo aFi(file);
|
||||||
|
if (aFi.isAbsolute()) {
|
||||||
|
usable = aFi.isFile();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!file.startsWith(QLatin1String("qrc:/")))
|
||||||
|
return;
|
||||||
|
const QString relativeFile = file.right(file.size() - 5);
|
||||||
|
if (!sp.projectSourceDirectory.isEmpty()) {
|
||||||
|
const QFileInfo pFi(sp.projectSourceDirectory + QLatin1Char('/') + relativeFile);
|
||||||
|
if (pFi.isFile()) {
|
||||||
|
file = pFi.absoluteFilePath();
|
||||||
|
usable = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QFileInfo cFi(QDir::currentPath() + QLatin1Char('/') + relativeFile);
|
||||||
|
if (cFi.isFile()) {
|
||||||
|
file = cFi.absoluteFilePath();
|
||||||
|
usable = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug d, const StackFrame &f)
|
QDebug operator<<(QDebug d, const StackFrame &f)
|
||||||
{
|
{
|
||||||
QString res;
|
QString res;
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
#ifndef DEBUGGER_STACKFRAME_H
|
#ifndef DEBUGGER_STACKFRAME_H
|
||||||
#define DEBUGGER_STACKFRAME_H
|
#define DEBUGGER_STACKFRAME_H
|
||||||
|
|
||||||
|
#include "debuggerconstants.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
|
||||||
@@ -38,6 +40,9 @@ class QDebug;
|
|||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
|
|
||||||
|
class DebuggerStartParameters;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class StackFrame
|
class StackFrame
|
||||||
@@ -48,8 +53,10 @@ public:
|
|||||||
bool isUsable() const;
|
bool isUsable() const;
|
||||||
QString toToolTip() const;
|
QString toToolTip() const;
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
|
void fixQmlFrame(const DebuggerStartParameters &sp);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
DebuggerLanguage language;
|
||||||
qint32 level;
|
qint32 level;
|
||||||
QString function;
|
QString function;
|
||||||
QString file; // We try to put an absolute file name in there.
|
QString file; // We try to put an absolute file name in there.
|
||||||
|
|||||||
@@ -205,6 +205,20 @@ void StackHandler::setFrames(const StackFrames &frames, bool canExpand)
|
|||||||
emit stackChanged();
|
emit stackChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StackHandler::prependFrames(const StackFrames &frames)
|
||||||
|
{
|
||||||
|
if (frames.isEmpty())
|
||||||
|
return;
|
||||||
|
const int count = frames.size();
|
||||||
|
beginInsertRows(QModelIndex(), 0, count - 1);
|
||||||
|
for (int i = count - 1; i >= 0; --i)
|
||||||
|
m_stackFrames.prepend(frames.at(i));
|
||||||
|
endInsertRows();
|
||||||
|
if (m_currentIndex >= 0)
|
||||||
|
setCurrentIndex(m_currentIndex + count);
|
||||||
|
emit stackChanged();
|
||||||
|
}
|
||||||
|
|
||||||
const StackFrames &StackHandler::frames() const
|
const StackFrames &StackHandler::frames() const
|
||||||
{
|
{
|
||||||
return m_stackFrames;
|
return m_stackFrames;
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ public:
|
|||||||
~StackHandler();
|
~StackHandler();
|
||||||
|
|
||||||
void setFrames(const StackFrames &frames, bool canExpand = false);
|
void setFrames(const StackFrames &frames, bool canExpand = false);
|
||||||
|
void prependFrames(const StackFrames &frames);
|
||||||
const StackFrames &frames() const;
|
const StackFrames &frames() const;
|
||||||
void setCurrentIndex(int index);
|
void setCurrentIndex(int index);
|
||||||
int currentIndex() const { return m_currentIndex; }
|
int currentIndex() const { return m_currentIndex; }
|
||||||
|
|||||||
@@ -168,6 +168,10 @@ void StackTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
if (engine->hasCapability(CreateFullBacktraceCapability))
|
if (engine->hasCapability(CreateFullBacktraceCapability))
|
||||||
menu.addAction(debuggerCore()->action(CreateFullBacktrace));
|
menu.addAction(debuggerCore()->action(CreateFullBacktrace));
|
||||||
|
|
||||||
|
QAction *additionalQmlStackAction = 0;
|
||||||
|
if (engine->hasCapability(AdditionalQmlStackCapability))
|
||||||
|
additionalQmlStackAction = menu.addAction(tr("Load QML stack"));
|
||||||
|
|
||||||
QAction *actShowMemory = 0;
|
QAction *actShowMemory = 0;
|
||||||
if (engine->hasCapability(ShowMemoryCapability)) {
|
if (engine->hasCapability(ShowMemoryCapability)) {
|
||||||
actShowMemory = menu.addAction(QString());
|
actShowMemory = menu.addAction(QString());
|
||||||
@@ -242,6 +246,8 @@ void StackTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
engine->loadSymbolsForStack();
|
engine->loadSymbolsForStack();
|
||||||
else if (act == actSaveTaskFile)
|
else if (act == actSaveTaskFile)
|
||||||
saveTaskFile(this, handler);
|
saveTaskFile(this, handler);
|
||||||
|
else if (act == additionalQmlStackAction)
|
||||||
|
engine->loadAdditionalQmlStack();
|
||||||
else
|
else
|
||||||
handleBaseContextAction(act);
|
handleBaseContextAction(act);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user