summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/qtcreator/dumper/qttypes.py8
-rw-r--r--src/plugins/debugger/cdb/cdbengine.cpp45
-rw-r--r--src/plugins/debugger/debuggercore.h2
-rw-r--r--src/plugins/debugger/debuggerengine.cpp30
-rw-r--r--src/plugins/debugger/debuggerengine.h11
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp13
-rw-r--r--src/plugins/debugger/debuggerstreamops.cpp2
-rw-r--r--src/plugins/debugger/debuggertooltipmanager.cpp94
-rw-r--r--src/plugins/debugger/gdb/abstractplaingdbadapter.cpp7
-rw-r--r--src/plugins/debugger/gdb/classicgdbengine.cpp63
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp126
-rw-r--r--src/plugins/debugger/gdb/gdbengine.h26
-rw-r--r--src/plugins/debugger/gdb/pythongdbengine.cpp24
-rw-r--r--src/plugins/debugger/lldb/ipcenginehost.cpp4
-rw-r--r--src/plugins/debugger/pdb/pdbengine.cpp7
-rw-r--r--src/plugins/debugger/qml/qmlengine.cpp3
-rw-r--r--src/plugins/debugger/qml/qmlinspectoragent.cpp37
-rw-r--r--src/plugins/debugger/qml/qmlinspectoragent.h1
-rw-r--r--src/plugins/debugger/qml/qmlv8debuggerclient.cpp27
-rw-r--r--src/plugins/debugger/qml/qscriptdebuggerclient.cpp48
-rw-r--r--src/plugins/debugger/script/scriptengine.cpp7
-rw-r--r--src/plugins/debugger/watchdata.cpp3
-rw-r--r--src/plugins/debugger/watchdata.h1
-rw-r--r--src/plugins/debugger/watchhandler.cpp1048
-rw-r--r--src/plugins/debugger/watchhandler.h164
-rw-r--r--src/plugins/debugger/watchwindow.cpp40
-rw-r--r--src/plugins/debugger/watchwindow.h4
27 files changed, 903 insertions, 942 deletions
diff --git a/share/qtcreator/dumper/qttypes.py b/share/qtcreator/dumper/qttypes.py
index 085f746fa4..9d00282fbc 100644
--- a/share/qtcreator/dumper/qttypes.py
+++ b/share/qtcreator/dumper/qttypes.py
@@ -2397,6 +2397,14 @@ def qdump__Debugger__Internal__GdbMi(d, value):
d.putByteArrayValue(value["m_data"])
d.putPlainChildren(value)
+def qdump__Debugger__Internal__WatchData(d, value):
+ d.putByteArrayValue(value["iname"])
+ d.putPlainChildren(value)
+
+def qdump__Debugger__Internal__WatchItem(d, value):
+ d.putByteArrayValue(value["iname"])
+ d.putPlainChildren(value)
+
def qdump__CPlusPlus__ByteArrayRef(d, value):
d.putValue(encodeCharArray(value["m_start"], 100, value["m_length"]),
Hex2EncodedLatin1)
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index 4b2864633a..112ed2524c 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -98,6 +98,12 @@ enum { debugSourceMapping = 0 };
enum { debugWatches = 0 };
enum { debugBreakpoints = 0 };
+enum HandleLocalsFlags
+{
+ PartialLocalsUpdate = 0x1,
+ LocalsUpdateForNewFrame = 0x2
+};
+
#if 0
# define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
#else
@@ -550,18 +556,16 @@ bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
// Can this be found as a local variable?
const QByteArray localsPrefix(localsPrefixC);
QByteArray iname = localsPrefix + exp.toAscii();
- QModelIndex index = watchHandler()->itemIndex(iname);
- if (!index.isValid()) {
+ if (!watchHandler()->hasItem(iname)) {
// Nope, try a 'local.this.m_foo'.
exp.prepend(QLatin1String("this."));
iname.insert(localsPrefix.size(), "this.");
- index = watchHandler()->itemIndex(iname);
- if (!index.isValid())
+ if (!watchHandler()->hasItem(iname))
return false;
}
DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
tw->setContext(context);
- tw->setDebuggerModel(LocalsWatch);
+ tw->setDebuggerModel(LocalsType);
tw->setExpression(exp);
tw->acquireEngine(this);
DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
@@ -1048,7 +1052,7 @@ void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
updateLocalVariable(item.iname);
} else {
item.setError(tr("Unable to add expression"));
- watchHandler()->insertData(item);
+ watchHandler()->insertIncompleteData(item);
showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
QString::fromLocal8Bit(reply->errorMessage)), LogError);
@@ -1086,7 +1090,10 @@ void CdbEngine::updateLocalVariable(const QByteArray &iname)
str << blankSeparator << stackFrame;
}
str << blankSeparator << iname;
- postExtensionCommand(isWatch ? "watches" : "locals", localsArguments, 0, &CdbEngine::handleLocals);
+ postExtensionCommand(isWatch ? "watches" : "locals",
+ localsArguments, 0,
+ &CdbEngine::handleLocals,
+ 0, QVariant(int(PartialLocalsUpdate)));
}
bool CdbEngine::hasCapability(unsigned cap) const
@@ -1465,8 +1472,7 @@ void CdbEngine::activateFrame(int index)
stackHandler()->setCurrentIndex(index);
const bool showAssembler = !frames.at(index).isUsable();
if (showAssembler) { // Assembly code: Clean out model and force instruction mode.
- watchHandler()->beginCycle();
- watchHandler()->endCycle();
+ watchHandler()->removeAllData();
QAction *assemblerAction = theAssemblerAction();
if (assemblerAction->isChecked()) {
gotoLocation(frame);
@@ -1485,14 +1491,12 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
const int frameIndex = stackHandler()->currentIndex();
if (frameIndex < 0) {
- watchHandler()->beginCycle();
- watchHandler()->endCycle();
+ watchHandler()->removeAllData();
return;
}
const StackFrame frame = stackHandler()->currentFrame();
if (!frame.isUsable()) {
- watchHandler()->beginCycle();
- watchHandler()->endCycle();
+ watchHandler()->removeAllData();
return;
}
/* Watchers: Forcibly discard old symbol group as switching from
@@ -1542,9 +1546,11 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
}
// Required arguments: frame
+ const int flags = forNewStackFrame ? LocalsUpdateForNewFrame : 0;
str << blankSeparator << frameIndex;
- watchHandler()->beginCycle();
- postExtensionCommand("locals", arguments, 0, &CdbEngine::handleLocals, 0, QVariant(forNewStackFrame));
+ postExtensionCommand("locals", arguments, 0,
+ &CdbEngine::handleLocals, 0,
+ QVariant(flags));
}
void CdbEngine::selectThread(int index)
@@ -1925,6 +1931,9 @@ void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply)
void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
{
+ const int flags = reply->cookie.toInt();
+ if (!(flags & PartialLocalsUpdate))
+ watchHandler()->removeAllData();
if (reply->success) {
QList<WatchData> watchData;
GdbMi root;
@@ -1940,16 +1949,14 @@ void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
dummy.name = QLatin1String(child.findChild("name").data());
parseWatchData(watchHandler()->expandedINames(), dummy, child, &watchData);
}
- watchHandler()->insertBulkData(watchData);
- watchHandler()->endCycle();
+ watchHandler()->insertData(watchData);
if (debugLocals) {
QDebug nsp = qDebug().nospace();
nsp << "Obtained " << watchData.size() << " items:\n";
foreach (const WatchData &wd, watchData)
nsp << wd.toString() <<'\n';
}
- const bool forNewStackFrame = reply->cookie.toBool();
- if (forNewStackFrame)
+ if (flags & LocalsUpdateForNewFrame)
emit stackFrameCompleted();
} else {
showMessage(QString::fromLatin1(reply->errorMessage), LogWarning);
diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h
index 897bfd677c..57d18dcd40 100644
--- a/src/plugins/debugger/debuggercore.h
+++ b/src/plugins/debugger/debuggercore.h
@@ -85,7 +85,7 @@ public:
virtual QVariant configValue(const QString &name) const = 0;
virtual void setConfigValue(const QString &name, const QVariant &value) = 0;
virtual void updateState(DebuggerEngine *engine) = 0;
- virtual void updateWatchersWindow() = 0;
+ virtual void updateWatchersWindow(bool showWatch, bool showReturn) = 0;
virtual void showQtDumperLibraryWarning(const QString &details) = 0;
virtual QIcon locationMarkIcon() const = 0;
virtual const CPlusPlus::Snapshot &cppCodeModelSnapshot() const = 0;
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index 017aa11f57..4db5bc134c 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -491,42 +491,32 @@ QAbstractItemModel *DebuggerEngine::threadsModel() const
QAbstractItemModel *DebuggerEngine::localsModel() const
{
- QAbstractItemModel *model = watchHandler()->model(LocalsWatch);
- if (model->objectName().isEmpty()) // Make debugging easier.
- model->setObjectName(objectName() + QLatin1String("LocalsModel"));
- return model;
+ return watchHandler()->model();
}
QAbstractItemModel *DebuggerEngine::watchersModel() const
{
- QAbstractItemModel *model = watchHandler()->model(WatchersWatch);
- if (model->objectName().isEmpty()) // Make debugging easier.
- model->setObjectName(objectName() + QLatin1String("WatchersModel"));
- return model;
+ return watchHandler()->model();
}
QAbstractItemModel *DebuggerEngine::returnModel() const
{
- QAbstractItemModel *model = watchHandler()->model(ReturnWatch);
- if (model->objectName().isEmpty()) // Make debugging easier.
- model->setObjectName(objectName() + QLatin1String("ReturnModel"));
- return model;
+ return watchHandler()->model();
}
QAbstractItemModel *DebuggerEngine::inspectorModel() const
{
- QAbstractItemModel *model = watchHandler()->model(InspectWatch);
- if (model->objectName().isEmpty()) // Make debugging easier.
- model->setObjectName(objectName() + QLatin1String("InspectorModel"));
- return model;
+ return watchHandler()->model();
}
QAbstractItemModel *DebuggerEngine::toolTipsModel() const
{
- QAbstractItemModel *model = watchHandler()->model(TooltipsWatch);
- if (model->objectName().isEmpty()) // Make debugging easier.
- model->setObjectName(objectName() + QLatin1String("TooltipsModel"));
- return model;
+ return watchHandler()->model();
+}
+
+QAbstractItemModel *DebuggerEngine::watchModel() const
+{
+ return watchHandler()->model();
}
QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h
index 76089e425b..c8ff90586a 100644
--- a/src/plugins/debugger/debuggerengine.h
+++ b/src/plugins/debugger/debuggerengine.h
@@ -229,11 +229,12 @@ public:
virtual QAbstractItemModel *registerModel() const;
virtual QAbstractItemModel *stackModel() const;
virtual QAbstractItemModel *threadsModel() const;
- virtual QAbstractItemModel *localsModel() const;
- virtual QAbstractItemModel *watchersModel() const;
- virtual QAbstractItemModel *returnModel() const;
- virtual QAbstractItemModel *inspectorModel() const;
- virtual QAbstractItemModel *toolTipsModel() const;
+ virtual QAbstractItemModel *localsModel() const; // Deprecated, FIXME: use watchModel
+ virtual QAbstractItemModel *watchersModel() const; // Deprecated, FIXME: use watchModel
+ virtual QAbstractItemModel *returnModel() const; // Deprecated, FIXME: use watchModel
+ virtual QAbstractItemModel *inspectorModel() const; // Deprecated, FIXME: use watchModel
+ virtual QAbstractItemModel *toolTipsModel() const; // Deprecated, FIXME: use watchModel
+ virtual QAbstractItemModel *watchModel() const;
virtual QAbstractItemModel *sourceFilesModel() const;
virtual QAbstractItemModel *qtMessageLogModel() const;
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index bc84112198..3efe927e5d 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -815,7 +815,7 @@ public slots:
void fontSettingsChanged(const TextEditor::FontSettings &settings);
void updateState(DebuggerEngine *engine);
- void updateWatchersWindow();
+ void updateWatchersWindow(bool showWatch, bool showReturn);
void onCurrentProjectChanged(ProjectExplorer::Project *project);
void sessionLoaded();
@@ -2238,12 +2238,10 @@ void DebuggerPluginPrivate::setInitialState()
m_qtMessageLogWindow->setEnabled(true);
}
-void DebuggerPluginPrivate::updateWatchersWindow()
+void DebuggerPluginPrivate::updateWatchersWindow(bool showWatch, bool showReturn)
{
- m_watchersWindow->setVisible(
- m_watchersWindow->model()->rowCount(QModelIndex()) > 0);
- m_returnWindow->setVisible(
- m_returnWindow->model()->rowCount(QModelIndex()) > 0);
+ m_watchersWindow->setVisible(showWatch);
+ m_returnWindow->setVisible(showReturn);
}
void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
@@ -2254,8 +2252,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
QTC_ASSERT(!engine->isSlaveEngine(), return);
m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThread());
-
- updateWatchersWindow();
+ engine->watchHandler()->updateWatchersWindow();
const DebuggerState state = engine->state();
//showMessage(QString("PLUGIN SET STATE: ")
diff --git a/src/plugins/debugger/debuggerstreamops.cpp b/src/plugins/debugger/debuggerstreamops.cpp
index cada0ea9d3..fae28bb69c 100644
--- a/src/plugins/debugger/debuggerstreamops.cpp
+++ b/src/plugins/debugger/debuggerstreamops.cpp
@@ -230,7 +230,6 @@ QDataStream &operator<<(QDataStream &stream, const WatchData &wd)
stream << wd.address;
stream << wd.size;
stream << wd.hasChildren;
- stream << wd.generation;
stream << wd.valueEnabled;
stream << wd.valueEditable;
stream << wd.error;
@@ -256,7 +255,6 @@ QDataStream &operator>>(QDataStream &stream, WatchData &wd)
stream >> wd.address;
stream >> wd.size;
stream >> wd.hasChildren;
- stream >> wd.generation;
stream >> wd.valueEnabled;
stream >> wd.valueEditable;
stream >> wd.error;
diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp
index ccbd610ea3..2094d29723 100644
--- a/src/plugins/debugger/debuggertooltipmanager.cpp
+++ b/src/plugins/debugger/debuggertooltipmanager.cpp
@@ -31,6 +31,7 @@
**************************************************************************/
#include "debuggertooltipmanager.h"
+#include "debuggerinternalconstants.h"
#include "watchutils.h"
#include "debuggerengine.h"
#include "debuggeractions.h"
@@ -617,7 +618,7 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(QWidget *parent) :
m_titleLabel(new DraggableLabel),
m_engineAcquired(false),
m_creationDate(QDate::currentDate()),
- m_debuggerModel(TooltipsWatch),
+ m_debuggerModel(TooltipType),
m_treeView(new DebuggerToolTipTreeView),
m_defaultModel(new QStandardItemModel(this))
{
@@ -664,7 +665,7 @@ bool DebuggerToolTipWidget::matches(const QString &fileName,
return function == m_context.function;
}
-void DebuggerToolTipWidget::acquireEngine(Debugger::DebuggerEngine *engine)
+void DebuggerToolTipWidget::acquireEngine(DebuggerEngine *engine)
{
QTC_ASSERT(engine, return);
@@ -836,7 +837,7 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
}
/*!
- \class Debugger::Internal::DebuggerToolTipExpressionFilterModel
+ \class Debugger::Internal::TooltipFilterModel
\brief Model for tooltips filtering a local variable using the locals or tooltip model,
matching on the name.
@@ -847,50 +848,46 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
In addition, suppress the model's tooltip data to avoid a tooltip on a tooltip.
*/
-class DebuggerToolTipExpressionFilterModel : public QSortFilterProxyModel
+class TooltipFilterModel : public QSortFilterProxyModel
{
public:
- explicit DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model, const QString &exp, QObject *parent = 0);
- virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+ TooltipFilterModel(QAbstractItemModel *model, const QString &exp, int debuggerModel) :
+ m_expressions(exp.split(QLatin1Char('.'))),
+ m_debuggerModel(debuggerModel)
+ {
+ setSourceModel(model);
+ }
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+ {
+ return role == Qt::ToolTipRole
+ ? QVariant() : QSortFilterProxyModel::data(index, role);
+ }
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
private:
const QStringList m_expressions;
+ int m_debuggerModel;
};
-DebuggerToolTipExpressionFilterModel::DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model,
- const QString &exp,
- QObject *parent) :
- QSortFilterProxyModel(parent),
- m_expressions(exp.split(QLatin1Char('.')))
-{
- setSourceModel(model);
-}
-
-QVariant DebuggerToolTipExpressionFilterModel::data(const QModelIndex &index, int role) const
-{
- return role != Qt::ToolTipRole ?
- QSortFilterProxyModel::data(index, role) : QVariant();
-}
-
-// Return depth of a model index, that is, 0 for root index, 1 for level-1 children, etc.
-static inline int indexDepth(QModelIndex index)
-{
- int depth = 0;
- for ( ; index.isValid() ; index = index.parent())
- depth++;
- return depth;
-}
-
-bool DebuggerToolTipExpressionFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+bool TooltipFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
+ const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent);
+ QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray();
+ if (m_debuggerModel == LocalsType && !iname.startsWith("local"))
+ return false;
+ if (m_debuggerModel == TooltipType && !iname.startsWith("tooltip"))
+ return false;
// Match on expression for top level, else pass through.
- const int depth = indexDepth(sourceParent);
- if (depth >= m_expressions.size()) // No filters at this level
+ const int depth = iname.count('.');
+ if (depth == 0)
return true;
- const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent);
- return nameIndex.data().toString() == m_expressions.at(depth);
+ if (depth > m_expressions.size())
+ return true;
+ const QString name = nameIndex.data().toString();
+ //const QString exp = nameIndex.data(LocalsExpressionRole).toString();
+ return name == m_expressions.at(depth - 1);
}
/*!
@@ -924,6 +921,7 @@ QAbstractItemModel *DebuggerToolTipTreeView::swapModel(QAbstractItemModel *newMo
if (previousModel)
previousModel->disconnect(SIGNAL(rowsInserted(QModelIndex,int,int)), this);
setModel(newModel);
+ //setRootIndex(newModel->index(0, 0));
connect(newModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(computeSize()), Qt::QueuedConnection);
computeSize();
@@ -991,24 +989,12 @@ void DebuggerToolTipTreeView::computeSize()
setRootIsDecorated(rootDecorated);
}
-void DebuggerToolTipWidget::doAcquireEngine(Debugger::DebuggerEngine *engine)
+void DebuggerToolTipWidget::doAcquireEngine(DebuggerEngine *engine)
{
// Create a filter model on the debugger's model and switch to it.
- QAbstractItemModel *model = 0;
- switch (m_debuggerModel) {
- case LocalsWatch:
- model = engine->localsModel();
- break;
- case WatchersWatch:
- model = engine->watchersModel();
- break;
- case TooltipsWatch:
- model = engine->toolTipsModel();
- break;
- }
- QTC_ASSERT(model, return);
- DebuggerToolTipExpressionFilterModel *filterModel =
- new DebuggerToolTipExpressionFilterModel(model, m_expression);
+ QAbstractItemModel *model = engine->watchModel();
+ TooltipFilterModel *filterModel =
+ new TooltipFilterModel(model, m_expression, m_debuggerModel);
swapModel(filterModel);
}
@@ -1311,7 +1297,7 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips()
}
}
-void DebuggerToolTipManager::slotDebuggerStateChanged(Debugger::DebuggerState state)
+void DebuggerToolTipManager::slotDebuggerStateChanged(DebuggerState state)
{
const QObject *engine = sender();
QTC_ASSERT(engine, return);
@@ -1319,7 +1305,7 @@ void DebuggerToolTipManager::slotDebuggerStateChanged(Debugger::DebuggerState st
const QString name = engine->objectName();
if (debugToolTips)
qDebug() << "DebuggerToolTipWidget::debuggerStateChanged"
- << engine << Debugger::DebuggerEngine::stateName(state);
+ << engine << DebuggerEngine::stateName(state);
// Release at earliest possible convenience.
switch (state) {
diff --git a/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp b/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
index a9dd32c0a4..b23fffc2aa 100644
--- a/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
+++ b/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
@@ -63,8 +63,11 @@ void AbstractPlainGdbAdapter::setupInferior()
QString args = startParameters().processArgs;
m_engine->postCommand("-exec-arguments " + toLocalEncoding(args));
}
- m_engine->postCommand("-file-exec-and-symbols \"" + execFilePath() + '"',
- CB(handleFileExecAndSymbols));
+ if (m_engine->gdbVersion() > 70000)
+ m_engine->postCommand("-file-exec-and-symbols \"" + execFilePath() + '"',
+ CB(handleFileExecAndSymbols));
+ else
+ m_engine->postCommand("file " + execFilePath(), CB(handleFileExecAndSymbols));
}
void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
diff --git a/src/plugins/debugger/gdb/classicgdbengine.cpp b/src/plugins/debugger/gdb/classicgdbengine.cpp
index 3b2f82a34a..52b97a172b 100644
--- a/src/plugins/debugger/gdb/classicgdbengine.cpp
+++ b/src/plugins/debugger/gdb/classicgdbengine.cpp
@@ -716,7 +716,7 @@ static bool parseConsoleStream(const GdbResponse &response, GdbMi *contents)
void GdbEngine::updateLocalsClassic()
{
PRECONDITION;
- m_pendingWatchRequests = 0;
+ //m_pendingWatchRequests = 0;
m_pendingBreakpointRequests = 0;
m_processedNames.clear();
@@ -724,15 +724,14 @@ void GdbEngine::updateLocalsClassic()
qDebug() << "\nRESET PENDING";
//m_toolTipCache.clear();
clearToolTip();
- watchHandler()->beginCycle();
QByteArray level = QByteArray::number(currentFrame());
// '2' is 'list with type and value'
QByteArray cmd = "-stack-list-arguments 2 " + level + ' ' + level;
- postCommand(cmd, WatchUpdate,
+ postCommand(cmd, Discardable,
CB(handleStackListArgumentsClassic));
// '2' is 'list with type and value'
- postCommand("-stack-list-locals 2", WatchUpdate,
+ postCommand("-stack-list-locals 2", Discardable,
CB(handleStackListLocalsClassic)); // stage 2/2
}
@@ -754,9 +753,9 @@ void GdbEngine::runDirectDebuggingHelperClassic(const WatchData &data, bool dump
QVariant var;
var.setValue(data);
- postCommand(cmd, WatchUpdate, CB(handleDebuggingHelperValue3Classic), var);
+ postCommand(cmd, Discardable, CB(handleDebuggingHelperValue3Classic), var);
- showStatusMessage(msgRetrievingWatchData(m_pendingWatchRequests + 1), 10000);
+ showStatusMessage(msgRetrievingWatchData(m_uncompleted.size()), 10000);
}
void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChildren)
@@ -811,25 +810,25 @@ void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChild
cmd += ',' + ex;
cmd += ')';
- postCommand(cmd, WatchUpdate | NonCriticalResponse);
+ postCommand(cmd, Discardable | NonCriticalResponse);
- showStatusMessage(msgRetrievingWatchData(m_pendingWatchRequests + 1), 10000);
+ showStatusMessage(msgRetrievingWatchData(m_uncompleted.size()), 10000);
// retrieve response
- postCommand("p (char*)&qDumpOutBuffer", WatchUpdate,
+ postCommand("p (char*)&qDumpOutBuffer", Discardable,
CB(handleDebuggingHelperValue2Classic), qVariantFromValue(data));
}
void GdbEngine::createGdbVariableClassic(const WatchData &data)
{
PRECONDITION;
- postCommand("-var-delete \"" + data.iname + '"', WatchUpdate);
+ postCommand("-var-delete \"" + data.iname + '"', Discardable);
QByteArray exp = data.exp;
if (exp.isEmpty() && data.address)
exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.hexAddress();
QVariant val = QVariant::fromValue<WatchData>(data);
postCommand("-var-create \"" + data.iname + "\" * \"" + exp + '"',
- WatchUpdate, CB(handleVarCreate), val);
+ Discardable, CB(handleVarCreate), val);
}
void GdbEngine::updateSubItemClassic(const WatchData &data0)
@@ -929,7 +928,7 @@ void GdbEngine::updateSubItemClassic(const WatchData &data0)
if (debugSubItem)
qDebug() << "UPDATE SUBITEM: VALUE";
QByteArray cmd = "-var-evaluate-expression \"" + data.iname + '"';
- postCommand(cmd, WatchUpdate,
+ postCommand(cmd, Discardable,
CB(handleEvaluateExpressionClassic), QVariant::fromValue(data));
return;
}
@@ -953,7 +952,7 @@ void GdbEngine::updateSubItemClassic(const WatchData &data0)
if (data.isChildrenNeeded()) {
QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
- postCommand(cmd, WatchUpdate,
+ postCommand(cmd, Discardable,
CB(handleVarListChildrenClassic), QVariant::fromValue(data));
return;
}
@@ -999,7 +998,7 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
if (m_cookieForToken.contains(response.token - 1)) {
m_cookieForToken.remove(response.token - 1);
showMessage(_("DETECTING LOST COMMAND %1").arg(response.token - 1));
- --m_pendingWatchRequests;
+ // --m_pendingWatchRequests;
data.setError(WatchData::msgNotInScope());
insertData(data);
return;
@@ -1025,7 +1024,7 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
parseWatchData(watchHandler()->expandedINames(), data, contents, &list);
//for (int i = 0; i != list.size(); ++i)
// qDebug() << "READ: " << list.at(i).toString();
- watchHandler()->insertBulkData(list);
+ watchHandler()->insertData(list);
}
void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
@@ -1082,7 +1081,7 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
QByteArray cmd = "qdumpqstring (" + data1.exp + ')';
QVariant var;
var.setValue(data1);
- postCommand(cmd, WatchUpdate,
+ postCommand(cmd, Discardable,
CB(handleDebuggingHelperValue3Classic), var);
}
}
@@ -1101,6 +1100,9 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
void GdbEngine::tryLoadDebuggingHelpersClassic()
{
+ if (m_forceAsyncModel)
+ return;
+
PRECONDITION;
if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) {
// Load at least gdb macro based dumpers.
@@ -1171,12 +1173,12 @@ void GdbEngine::updateAllClassic()
qDebug() << state());
tryLoadDebuggingHelpersClassic();
reloadModulesInternal();
- postCommand("-stack-list-frames", WatchUpdate,
+ postCommand("-stack-list-frames", Discardable,
CB(handleStackListFrames),
QVariant::fromValue<StackCookie>(StackCookie(false, true)));
stackHandler()->setCurrentIndex(0);
if (supportsThreads())
- postCommand("-thread-list-ids", WatchUpdate, CB(handleThreadListIds), 0);
+ postCommand("-thread-list-ids", Discardable, CB(handleThreadListIds), 0);
reloadRegisters();
updateLocals();
}
@@ -1248,11 +1250,10 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response)
frame.function, frame.file, frame.line,
&uninitializedVariables);
}
- QList<WatchData> list;
foreach (const GdbMi &item, locals) {
const WatchData data = localVariable(item, uninitializedVariables, &seen);
if (data.isValid())
- list.push_back(data);
+ insertData(data);
}
if (!m_resultVarName.isEmpty()) {
@@ -1260,10 +1261,9 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response)
rd.iname = "return.0";
rd.name = QLatin1String("return");
rd.exp = m_resultVarName;
- list.append(rd);
+ insertData(rd);
}
- watchHandler()->insertBulkData(list);
watchHandler()->updateWatchers();
}
@@ -1371,7 +1371,7 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
data.setChildrenUnneeded();
QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
//iname += '.' + exp;
- postCommand(cmd, WatchUpdate,
+ postCommand(cmd, Discardable,
CB(handleVarListChildrenClassic), QVariant::fromValue(data));
} else if (!startsWithDigit(QLatin1String(exp))
&& item.findChild("numchild").data() == "0") {
@@ -1390,7 +1390,7 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
WatchData data;
data.iname = name;
QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
- postCommand(cmd, WatchUpdate,
+ postCommand(cmd, Discardable,
CB(handleVarListChildrenClassic), QVariant::fromValue(data));
} else if (exp == "staticMetaObject") {
// && item.findChild("type").data() == "const QMetaObject")
@@ -1464,9 +1464,6 @@ void GdbEngine::handleVarListChildrenClassic(const GdbResponse &response)
//qDebug() << "VAR_LIST_CHILDREN: PARENT" << data.toString();
QList<GdbMi> children = response.data.findChild("children").children();
- for (int i = 0; i != children.size(); ++i)
- handleVarListChildrenHelperClassic(children.at(i), data, i);
-
if (children.isEmpty()) {
// happens e.g. if no debug information is present or
// if the class really has no children
@@ -1479,14 +1476,18 @@ void GdbEngine::handleVarListChildrenClassic(const GdbResponse &response)
insertData(data1);
data.setAllUnneeded();
insertData(data);
- } else if (data.variable.endsWith("private")
+ } else {
+ if (data.variable.endsWith("private")
|| data.variable.endsWith("protected")
|| data.variable.endsWith("public")) {
// this skips the spurious "public", "private" etc levels
// gdb produces
- } else {
- data.setChildrenUnneeded();
- insertData(data);
+ } else {
+ data.setChildrenUnneeded();
+ insertData(data);
+ }
+ for (int i = 0; i != children.size(); ++i)
+ handleVarListChildrenHelperClassic(children.at(i), data, i);
}
} else {
data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 83ee073d05..1a3e87f409 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -255,7 +255,6 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters,
m_oldestAcceptableToken = -1;
m_nonDiscardableCount = 0;
m_outputCodec = QTextCodec::codecForLocale();
- m_pendingWatchRequests = 0;
m_pendingBreakpointRequests = 0;
m_commandsDoneCallback = 0;
m_stackNeeded = false;
@@ -263,6 +262,7 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters,
m_disassembleUsesComma = false;
m_actingOnExpectedStop = false;
m_fullStartDone = false;
+ m_forceAsyncModel = false;
invalidateSourcesList();
@@ -788,7 +788,8 @@ void GdbEngine::readGdbStandardOutput()
int newstart = 0;
int scan = m_inbuffer.size();
- m_inbuffer.append(gdbProc()->readAllStandardOutput());
+ QByteArray out = gdbProc()->readAllStandardOutput();
+ m_inbuffer.append(out);
// This can trigger when a dialog starts a nested event loop.
if (m_busy)
@@ -811,7 +812,8 @@ void GdbEngine::readGdbStandardOutput()
continue;
}
m_busy = true;
- handleResponse(QByteArray::fromRawData(m_inbuffer.constData() + start, end - start));
+ QByteArray ba = QByteArray::fromRawData(m_inbuffer.constData() + start, end - start);
+ handleResponse(ba);
m_busy = false;
}
m_inbuffer.clear();
@@ -903,17 +905,13 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
return;
}
- if (cmd.flags & RebuildWatchModel) {
- ++m_pendingWatchRequests;
- PENDING_DEBUG(" WATCH MODEL:" << cmd.command << "=>" << cmd.callbackName
- << "INCREMENTS PENDING TO" << m_pendingWatchRequests);
- } else if (cmd.flags & RebuildBreakpointModel) {
+ if (cmd.flags & RebuildBreakpointModel) {
++m_pendingBreakpointRequests;
PENDING_DEBUG(" BRWAKPOINT MODEL:" << cmd.command << "=>" << cmd.callbackName
<< "INCREMENTS PENDING TO" << m_pendingBreakpointRequests);
} else {
PENDING_DEBUG(" OTHER (IN):" << cmd.command << "=>" << cmd.callbackName
- << "LEAVES PENDING WATCH AT" << m_pendingWatchRequests
+ << "LEAVES PENDING WATCH AT" << m_uncompleted.size()
<< "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
}
@@ -1055,7 +1053,6 @@ void GdbEngine::commandTimeout()
if (mb->exec() == QMessageBox::Ok) {
showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
// This is an undefined state, so we just pull the emergency brake.
- watchHandler()->endCycle();
gdbProc()->kill();
} else {
showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
@@ -1205,25 +1202,17 @@ void GdbEngine::handleResultRecord(GdbResponse *response)
else if (cmd.adapterCallback)
(m_gdbAdapter->*cmd.adapterCallback)(*response);
- if (cmd.flags & RebuildWatchModel) {
- --m_pendingWatchRequests;
- PENDING_DEBUG(" WATCH" << cmd.command << "=>" << cmd.callbackName
- << "DECREMENTS PENDING WATCH TO" << m_pendingWatchRequests);
- if (m_pendingWatchRequests <= 0) {
- PENDING_DEBUG("\n\n ... AND TRIGGERS WATCH MODEL UPDATE\n");
- rebuildWatchModel();
- }
- } else if (cmd.flags & RebuildBreakpointModel) {
+ if (cmd.flags & RebuildBreakpointModel) {
--m_pendingBreakpointRequests;
PENDING_DEBUG(" BREAKPOINT" << cmd.command << "=>" << cmd.callbackName
- << "DECREMENTS PENDING TO" << m_pendingWatchRequests);
+ << "DECREMENTS PENDING TO" << m_uncompleted.size());
if (m_pendingBreakpointRequests <= 0) {
PENDING_DEBUG("\n\n ... AND TRIGGERS BREAKPOINT MODEL UPDATE\n");
attemptBreakpointSynchronization();
}
} else {
PENDING_DEBUG(" OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName
- << "LEAVES PENDING WATCH AT" << m_pendingWatchRequests
+ << "LEAVES PENDING WATCH AT" << m_uncompleted.size()
<< "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
}
@@ -3918,10 +3907,10 @@ bool GdbEngine::supportsThreads() const
//
//////////////////////////////////////////////////////////////////////
-bool GdbEngine::showToolTip()
+void GdbEngine::showToolTip()
{
if (m_toolTipContext.isNull())
- return false;
+ return;
const QString expression = m_toolTipContext->expression;
const QByteArray iname = tooltipIName(m_toolTipContext->expression);
if (DebuggerToolTipManager::debug())
@@ -3929,15 +3918,15 @@ bool GdbEngine::showToolTip()
if (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)) {
watchHandler()->removeData(iname);
- return true;
+ return;
}
if (!watchHandler()->isValidToolTip(iname)) {
watchHandler()->removeData(iname);
- return true;
+ return;
}
DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
- tw->setDebuggerModel(TooltipsWatch);
+ tw->setDebuggerModel(TooltipType);
tw->setExpression(expression);
tw->setContext(*m_toolTipContext);
tw->acquireEngine(this);
@@ -3945,7 +3934,6 @@ bool GdbEngine::showToolTip()
m_toolTipContext->editor, tw);
// Prevent tooltip from re-occurring (classic GDB, QTCREATORBUG-4711).
m_toolTipContext.reset();
- return true;
}
QString GdbEngine::tooltipExpression() const
@@ -4034,7 +4022,6 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos,
toolTip.exp = exp.toLatin1();
toolTip.name = exp;
toolTip.iname = tooltipIName(exp);
- watchHandler()->removeData(toolTip.iname);
watchHandler()->insertData(toolTip);
}
return true;
@@ -4071,19 +4058,12 @@ bool GdbEngine::hasDebuggingHelperForType(const QByteArray &type) const
return m_dumperHelper.type(type) != DumperHelper::UnknownType;
}
-
void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
{
if (isSynchronous()) {
// This should only be called for fresh expanded items, not for
// items that had their children retrieved earlier.
//qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n";
-#if 0
- WatchData data1 = data;
- data1.setAllUnneeded();
- insertData(data1);
- rebuildModel();
-#else
if (data.iname.endsWith("."))
return;
@@ -4106,53 +4086,26 @@ void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &f
// triggered e.g. by manually entered command in the gdb console?
//qDebug() << "TRY PARTIAL: " << flags.tryIncremental
// << hasPython()
- // << (m_pendingWatchRequests == 0)
// << (m_pendingBreakpointRequests == 0);
UpdateParameters params;
params.tooltipOnly = data.iname.startsWith("tooltip");
params.tryPartial = flags.tryIncremental
&& hasPython()
- && m_pendingWatchRequests == 0
&& m_pendingBreakpointRequests == 0;
params.varList = data.iname;
updateLocalsPython(params);
-#endif
} else {
- // Bump requests to avoid model rebuilding during the nested
- // updateWatchModel runs.
- ++m_pendingWatchRequests;
- PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingWatchRequests);
-#if 1
- QMetaObject::invokeMethod(this, "updateWatchDataHelper",
- Qt::QueuedConnection, Q_ARG(WatchData, data));
-#else
- updateWatchDataHelper(data);
-#endif
+ PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_uncompleted.size());
+ updateSubItemClassic(data);
}
}
-void GdbEngine::updateWatchDataHelper(const WatchData &data)
-{
- //m_pendingRequests = 0;
- PENDING_DEBUG("UPDATE WATCH DATA");
-# if DEBUG_PENDING
- //qDebug() << "##############################################";
- qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
- //qDebug() << data.toString();
-# endif
-
- updateSubItemClassic(data);
- //PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
- --m_pendingWatchRequests;
- PENDING_DEBUG("UPDATE WATCH DONE BUMPS PENDING DOWN TO " << m_pendingWatchRequests);
- if (m_pendingWatchRequests <= 0)
- rebuildWatchModel();
-}
-
void GdbEngine::rebuildWatchModel()
{
+ QTC_CHECK(m_completed.isEmpty());
+ QTC_CHECK(m_uncompleted.isEmpty());
static int count = 0;
++count;
if (!isSynchronous())
@@ -4162,7 +4115,6 @@ void GdbEngine::rebuildWatchModel()
showMessage(LogWindow::logTimeStamp(), LogMiscInput);
showMessage(_("<Rebuild Watchmodel %1>").arg(count), LogMiscInput);
showStatusMessage(tr("Finished retrieving data"), 400);
- watchHandler()->endCycle();
showToolTip();
handleAutoTests();
}
@@ -4332,15 +4284,23 @@ WatchData GdbEngine::localVariable(const GdbMi &item,
return data;
}
-void GdbEngine::insertData(const WatchData &data0)
+void GdbEngine::insertData(const WatchData &data)
{
- PENDING_DEBUG("INSERT DATA" << data0.toString());
- WatchData data = data0;
- if (data.value.startsWith(QLatin1String("mi_cmd_var_create:"))) {
- qDebug() << "BOGUS VALUE:" << data.toString();
- return;
+ PENDING_DEBUG("INSERT DATA" << data.toString());
+ if (data.isSomethingNeeded()) {
+ m_uncompleted.insert(data.iname);
+ WatchUpdateFlags flags;
+ flags.tryIncremental = true;
+ updateWatchData(data, flags);
+ } else {
+ m_completed.append(data);
+ m_uncompleted.remove(data.iname);
+ if (m_uncompleted.isEmpty()) {
+ watchHandler()->insertData(m_completed);
+ m_completed.clear();
+ rebuildWatchModel();
+ }
}
- watchHandler()->insertData(data);
}
void GdbEngine::assignValueInDebugger(const WatchData *data,
@@ -4901,12 +4861,6 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &settingsIdHint)
postCommand("disassemble 0 0", ConsoleCommand, CB(handleDisassemblerCheck));
- if (sp.breakOnMain) {
- QByteArray cmd = "tbreak ";
- cmd += sp.toolChainAbi.os() == Abi::WindowsOS ? "qMain" : "main";
- postCommand(cmd);
- }
-
if (attemptQuickStart()) {
postCommand("set auto-solib-add off", ConsoleCommand);
} else {
@@ -4941,6 +4895,9 @@ void GdbEngine::loadInitScript()
void GdbEngine::loadPythonDumpers()
{
+ if (m_forceAsyncModel)
+ return;
+
const QByteArray dumperSourcePath =
Core::ICore::resourcePath().toLocal8Bit() + "/dumper/";
@@ -5091,6 +5048,12 @@ void GdbEngine::handleInferiorPrepared()
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
+ if (sp.breakOnMain) {
+ QByteArray cmd = "tbreak ";
+ cmd += sp.toolChainAbi.os() == Abi::WindowsOS ? "qMain" : "main";
+ postCommand(cmd);
+ }
+
// Initial attempt to set breakpoints.
if (sp.startMode != AttachCore) {
showStatusMessage(tr("Setting breakpoints..."));
@@ -5361,6 +5324,9 @@ void GdbEngine::requestDebugInformation(const DebugInfoTask &task)
bool GdbEngine::attemptQuickStart() const
{
+ if (m_forceAsyncModel)
+ return false;
+
// Don't try if the user does not ask for it.
if (!debuggerCore()->boolSetting(AttemptQuickStart))
return false;
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index 93760ec19c..772f5a4d3f 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -36,6 +36,7 @@
#include "debuggerengine.h"
#include "stackframe.h"
+#include "watchhandler.h"
#include "watchutils.h"
#include <QByteArray>
@@ -80,16 +81,6 @@ enum DebuggingHelperState
DebuggingHelperUnavailable
};
-class UpdateParameters
-{
-public:
- UpdateParameters() { tryPartial = tooltipOnly = false; }
-
- bool tryPartial;
- bool tooltipOnly;
- QByteArray varList;
-};
-
/* This is only used with Mac gdb since 2.2
*
* "Custom dumper" is a library compiled against the current
@@ -322,9 +313,6 @@ private: ////////// Gdb Command Management //////////
NeedsStop = 1,
// No need to wait for the reply before continuing inferior.
Discardable = 2,
- // Trigger watch model rebuild when no such commands are pending anymore.
- RebuildWatchModel = 4,
- WatchUpdate = Discardable | RebuildWatchModel,
// We can live without receiving an answer.
NonCriticalResponse = 8,
// Callback expects GdbResultRunning instead of GdbResultDone.
@@ -407,7 +395,6 @@ private: ////////// Gdb Command Management //////////
int m_oldestAcceptableToken;
int m_nonDiscardableCount;
- int m_pendingWatchRequests; // Watch updating commands in flight
int m_pendingBreakpointRequests; // Watch updating commands in flight
typedef void (GdbEngine::*CommandsDoneCallback)();
@@ -630,13 +617,11 @@ private: ////////// View & Data Stuff //////////
virtual void watchPoint(const QPoint &);
void handleWatchPoint(const GdbResponse &response);
- // FIXME: BaseClass. called to improve situation for a watch item
void updateSubItemClassic(const WatchData &data);
- void virtual updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
- Q_SLOT void updateWatchDataHelper(const WatchData &data);
+ void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
void rebuildWatchModel();
- bool showToolTip();
+ void showToolTip();
void insertData(const WatchData &data);
void sendWatchParameters(const QByteArray &params0);
@@ -753,6 +738,11 @@ private: ////////// View & Data Stuff //////////
// debug information.
bool attemptQuickStart() const;
bool m_fullStartDone;
+
+ // Test
+ bool m_forceAsyncModel;
+ QList<WatchData> m_completed;
+ QSet<QByteArray> m_uncompleted;
};
} // namespace Internal
diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp
index f69ee66055..b020cc03b0 100644
--- a/src/plugins/debugger/gdb/pythongdbengine.cpp
+++ b/src/plugins/debugger/gdb/pythongdbengine.cpp
@@ -54,12 +54,11 @@ namespace Internal {
void GdbEngine::updateLocalsPython(const UpdateParameters &params)
{
PRECONDITION;
- m_pendingWatchRequests = 0;
+ //m_pendingWatchRequests = 0;
m_pendingBreakpointRequests = 0;
m_processedNames.clear();
- WatchHandler *handler = watchHandler();
- handler->beginCycle(!params.tryPartial);
+ WatchHandler *handler = watchHandler();
QByteArray expanded = "expanded:" + handler->expansionRequests() + ' ';
expanded += "typeformats:" + handler->typeFormatRequests() + ' ';
expanded += "formats:" + handler->individualFormatRequests();
@@ -117,7 +116,7 @@ void GdbEngine::updateLocalsPython(const UpdateParameters &params)
postCommand("bb options:" + options + " vars:" + params.varList + ' '
+ resultVar + expanded + " watchers:" + watchers.toHex(),
- WatchUpdate, CB(handleStackFramePython), QVariant(params.tryPartial));
+ Discardable, CB(handleStackFramePython), QVariant(params.tryPartial));
}
void GdbEngine::handleStackFramePython(const GdbResponse &response)
@@ -136,9 +135,11 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
}
GdbMi all;
all.fromStringMultiple(out);
-
GdbMi data = all.findChild("data");
+
+ WatchHandler *handler = watchHandler();
QList<WatchData> list;
+
foreach (const GdbMi &child, data.children()) {
WatchData dummy;
dummy.iname = child.findChild("iname").data();
@@ -151,7 +152,7 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
} else {
dummy.name = _(child.findChild("name").data());
}
- parseWatchData(watchHandler()->expandedINames(), dummy, child, &list);
+ parseWatchData(handler->expandedINames(), dummy, child, &list);
}
const GdbMi typeInfo = all.findChild("typeinfo");
if (typeInfo.type() == GdbMi::List) {
@@ -169,15 +170,20 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
list[i].size = ti.size;
}
- watchHandler()->insertBulkData(list);
+ if (!partial) {
+ handler->removeChildren("local");
+ handler->removeChildren("watch");
+ }
+
+ handler->insertData(list);
//PENDING_DEBUG("AFTER handleStackFrame()");
// FIXME: This should only be used when updateLocals() was
// triggered by expanding an item in the view.
- if (m_pendingWatchRequests <= 0) {
+ //if (m_pendingWatchRequests <= 0) {
//PENDING_DEBUG("\n\n .... AND TRIGGERS MODEL UPDATE\n");
rebuildWatchModel();
- }
+ //}
if (!partial)
emit stackFrameCompleted();
} else {
diff --git a/src/plugins/debugger/lldb/ipcenginehost.cpp b/src/plugins/debugger/lldb/ipcenginehost.cpp
index 73a01839de..7586920ba4 100644
--- a/src/plugins/debugger/lldb/ipcenginehost.cpp
+++ b/src/plugins/debugger/lldb/ipcenginehost.cpp
@@ -496,9 +496,7 @@ void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload)
WatchHandler *wh = watchHandler();
if (!wh)
break;
- wh->beginCycle(fullCycle);
- wh->insertBulkData(wd);
- wh->endCycle();
+ wh->insertData(wd);
}
break;
case IPCEngineGuest::NotifyAddBreakpointOk:
diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp
index 4c02711097..7683cd8bb3 100644
--- a/src/plugins/debugger/pdb/pdbengine.cpp
+++ b/src/plugins/debugger/pdb/pdbengine.cpp
@@ -720,14 +720,12 @@ void PdbEngine::updateAll()
void PdbEngine::updateLocals()
{
- WatchHandler *handler = watchHandler();
- handler->beginCycle(true);
-
QByteArray watchers;
//if (!m_toolTipExpression.isEmpty())
// watchers += m_toolTipExpression.toLatin1()
// + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1());
+ WatchHandler *handler = watchHandler();
QHash<QByteArray, int> watcherNames = handler->watcherNames();
QHashIterator<QByteArray, int> it(watcherNames);
while (it.hasNext()) {
@@ -831,8 +829,7 @@ void PdbEngine::handleListLocals(const PdbResponse &response)
//qDebug() << "CHILD: " << child.toString();
parseWatchData(handler->expandedINames(), dummy, child, &list);
}
- handler->insertBulkData(list);
- handler->endCycle();
+ handler->insertData(list);
}
bool PdbEngine::hasCapability(unsigned cap) const
diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp
index 908770961d..67078e9781 100644
--- a/src/plugins/debugger/qml/qmlengine.cpp
+++ b/src/plugins/debugger/qml/qmlengine.cpp
@@ -1000,7 +1000,6 @@ void QmlEngine::updateWatchData(const WatchData &data,
const WatchUpdateFlags &)
{
// qDebug() << "UPDATE WATCH DATA" << data.toString();
- //watchHandler()->rebuildModel();
//showStatusMessage(tr("Stopped."), 5000);
if (data.isInspect()) {
@@ -1020,7 +1019,7 @@ void QmlEngine::updateWatchData(const WatchData &data,
if (!data.isSomethingNeeded())
- watchHandler()->insertData(data);
+ watchHandler()->insertIncompleteData(data);
}
void QmlEngine::synchronizeWatchers()
diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp
index 9cb35e0ffd..d2c2793be2 100644
--- a/src/plugins/debugger/qml/qmlinspectoragent.cpp
+++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp
@@ -103,15 +103,11 @@ void QmlInspectorAgent::updateWatchData(const WatchData &data)
if (debug)
qDebug() << __FUNCTION__ << "(" << data.id << ")";
- if (data.id) {
+ if (data.id && !m_fetchDataIds.contains(data.id)) {
// objects
+ m_fetchDataIds << data.id;
ObjectReference ref(data.id);
m_fetchCurrentObjectsQueryIds << fetchContextObject(ref);
- WatchData d = data;
- d.setAllUnneeded();
- m_engine->watchHandler()->beginCycle(InspectWatch, false);
- m_engine->watchHandler()->insertData(d);
- m_engine->watchHandler()->endCycle(InspectWatch);
}
}
@@ -126,12 +122,9 @@ void QmlInspectorAgent::selectObjectInTree(int debugId)
if (m_debugIdToIname.contains(debugId)) {
QByteArray iname = m_debugIdToIname.value(debugId);
QTC_ASSERT(iname.startsWith("inspect."), qDebug() << iname);
- QModelIndex itemIndex = m_engine->watchHandler()->itemIndex(iname);
- QTC_ASSERT(itemIndex.isValid(),
- qDebug() << "No for " << debugId << ", iname " << iname; return;);
if (debug)
qDebug() << " selecting" << iname << "in tree";
- m_engine->watchHandler()->setCurrentModelIndex(InspectWatch, itemIndex);
+ m_engine->watchHandler()->setCurrentItem(iname);
m_objectToSelect = 0;
} else {
// we've to fetch it
@@ -370,9 +363,8 @@ void QmlInspectorAgent::updateStatus()
&& debuggerCore()->boolSetting(ShowQmlObjectTree)) {
reloadEngines();
} else {
- // clear view
- m_engine->watchHandler()->beginCycle(InspectWatch, true);
- m_engine->watchHandler()->endCycle(InspectWatch);
+ // Clear view.
+ m_engine->watchHandler()->removeChildren("inspect");
}
}
@@ -588,10 +580,7 @@ void QmlInspectorAgent::objectTreeFetched(const ObjectReference &object)
<< "entries into watch handler ...";
}
- WatchHandler *watchHandler = m_engine->watchHandler();
- watchHandler->beginCycle(InspectWatch, true);
- watchHandler->insertBulkData(watchData);
- watchHandler->endCycle(InspectWatch);
+ m_engine->watchHandler()->insertData(watchData);
if (debug)
qDebug() << "inserting entries took" << t.elapsed() << "ms";
@@ -615,15 +604,16 @@ void QmlInspectorAgent::onCurrentObjectsFetched(const ObjectReference &obj)
ObjectReference last = m_fetchCurrentObjects.last();
m_fetchCurrentObjects.clear();
+ m_fetchDataIds.clear();
if (m_objectToSelect == last.debugId()) {
// select item in view
QByteArray iname = m_debugIdToIname.value(last.debugId());
- QModelIndex itemIndex = m_engine->watchHandler()->itemIndex(iname);
- QTC_ASSERT(itemIndex.isValid(), return);
+ WatchHandler *handler = m_engine->watchHandler();
+ QTC_ASSERT(handler->hasItem(iname), return);
if (debug)
qDebug() << " selecting" << iname << "in tree";
- m_engine->watchHandler()->setCurrentModelIndex(InspectWatch, itemIndex);
+ handler->setCurrentItem(iname);
m_objectToSelect = -1;
}
@@ -780,12 +770,11 @@ void QmlInspectorAgent::addObjectToTree(const ObjectReference &obj,
// find parent
QTC_ASSERT(m_debugIdToIname.contains(parentId), break);
QByteArray iname = m_debugIdToIname.value(parentId);
- const WatchData *parent = m_engine->watchHandler()->findItem(iname);
+ WatchHandler *handler = m_engine->watchHandler();
+ const WatchData *parent = handler->findData(iname);
if (parent) {
QList<WatchData> watches = buildWatchData(obj, *parent);
- m_engine->watchHandler()->beginCycle(false);
- m_engine->watchHandler()->insertBulkData(watches);
- m_engine->watchHandler()->endCycle();
+ handler->insertData(watches);
break;
}
}
diff --git a/src/plugins/debugger/qml/qmlinspectoragent.h b/src/plugins/debugger/qml/qmlinspectoragent.h
index 0d0eafbe62..67bd0b8286 100644
--- a/src/plugins/debugger/qml/qmlinspectoragent.h
+++ b/src/plugins/debugger/qml/qmlinspectoragent.h
@@ -153,6 +153,7 @@ private:
DebugIdHash m_debugIdHash;
QList<int> m_objectWatches;
+ QList<int> m_fetchDataIds;
};
} // Internal
diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
index 1f97e58a54..8d35db37c6 100644
--- a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
+++ b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
@@ -272,7 +272,7 @@ void QmlV8DebuggerClientPrivate::evaluate(const QString expr, bool global,
QScriptValue ctxtList = parser.call(QScriptValue(), QScriptValueList() << _(ARRAY ));
while (rowCount) {
QModelIndex index = localsModel->index(--rowCount, 0);
- const WatchData *data = engine->watchHandler()->watchData(LocalsWatch, index);
+ const WatchData *data = engine->watchHandler()->watchData(index);
QScriptValue ctxt = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT)));
ctxt.setProperty(_(NAME), QScriptValue(data->name));
ctxt.setProperty(_(HANDLE), QScriptValue(int(data->id)));
@@ -1173,7 +1173,7 @@ void QmlV8DebuggerClient::expandObject(const QByteArray &iname, quint64 objectId
{
if (objectId == 0) {
//We may have got the global object
- const WatchData *watch = d->engine->watchHandler()->findItem(iname);
+ const WatchData *watch = d->engine->watchHandler()->findData(iname);
if (watch->value == QLatin1String("global")) {
StackHandler *stackHandler = d->engine->stackHandler();
if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
@@ -1706,9 +1706,7 @@ void QmlV8DebuggerClient::setCurrentFrameDetails(const QVariant &bodyVal, const
data.setHasChildren(true);
data.id = 0;
}
- d->engine->watchHandler()->beginCycle();
d->engine->watchHandler()->insertData(data);
- d->engine->watchHandler()->endCycle();
}
const QVariantList currentFrameScopes = currentFrame.value(_("scopes")).toList();
@@ -1785,11 +1783,8 @@ void QmlV8DebuggerClient::updateScope(const QVariant &bodyVal, const QVariant &r
if (!handlesToLookup.isEmpty())
d->lookup(handlesToLookup);
- if (!locals.isEmpty()) {
- d->engine->watchHandler()->beginCycle(false);
- d->engine->watchHandler()->insertBulkData(locals);
- d->engine->watchHandler()->endCycle();
- }
+ if (!locals.isEmpty())
+ d->engine->watchHandler()->insertData(locals);
}
void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, const QVariant &bodyVal,
@@ -1810,7 +1805,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
d->scope(index);
//Also update "this"
QByteArray iname("local.this");
- const WatchData *parent = d->engine->watchHandler()->findItem(iname);
+ const WatchData *parent = d->engine->watchHandler()->findData(iname);
d->localsAndWatchers.insertMulti(parent->id, iname);
d->lookup(QList<int>() << parent->id);
@@ -1833,7 +1828,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
WatchData data;
//Do we have request to evaluate a local?
if (exp.startsWith("local.")) {
- const WatchData *watch = d->engine->watchHandler()->findItem(exp.toLatin1());
+ const WatchData *watch = d->engine->watchHandler()->findData(exp.toLatin1());
watchDataList << createWatchDataList(watch, body.properties, refsVal);
} else {
QByteArray iname = d->engine->watchHandler()->watcherName(exp.toLatin1());
@@ -1854,9 +1849,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
watchDataList << data << createWatchDataList(&data, body.properties, refsVal);
}
//Insert the newly evaluated expression to the Watchers Window
- d->engine->watchHandler()->beginCycle(false);
- d->engine->watchHandler()->insertBulkData(watchDataList);
- d->engine->watchHandler()->endCycle();
+ d->engine->watchHandler()->insertData(watchDataList);
}
}
}
@@ -1933,7 +1926,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
if (prepend.startsWith("local.") || prepend.startsWith("watch.")) {
//Data for expanded local/watch
//Could be an object or function
- const WatchData *parent = d->engine->watchHandler()->findItem(prepend);
+ const WatchData *parent = d->engine->watchHandler()->findData(prepend);
watchDataList << createWatchDataList(parent, bodyObjectData.properties, refsVal);
} else {
//rest
@@ -1952,9 +1945,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
}
}
- d->engine->watchHandler()->beginCycle(false);
- d->engine->watchHandler()->insertBulkData(watchDataList);
- d->engine->watchHandler()->endCycle();
+ d->engine->watchHandler()->insertData(watchDataList);
}
QList<WatchData> QmlV8DebuggerClient::createWatchDataList(const WatchData *parent,
diff --git a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
index e4fe415cdd..4b60edc7cb 100644
--- a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
+++ b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
@@ -403,6 +403,8 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
QByteArray command;
stream >> command;
+ WatchHandler *watchHandler = d->engine->watchHandler();
+
if (command == "STOPPED") {
d->engine->inferiorSpontaneousStop();
@@ -432,15 +434,13 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
d->engine->stackHandler()->setFrames(ideStackFrames);
- d->engine->watchHandler()->beginCycle();
bool needPing = false;
foreach (WatchData data, watches) {
- data.iname = d->engine->watchHandler()->watcherName(data.exp);
- d->engine->watchHandler()->insertData(data);
+ data.iname = watchHandler->watcherName(data.exp);
+ watchHandler->insertIncompleteData(data);
- if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
- qint64(data.id) != -1) {
+ if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
needPing = true;
expandObject(data.iname,data.id);
}
@@ -448,20 +448,16 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
foreach (WatchData data, locals) {
data.iname = "local." + data.exp;
- d->engine->watchHandler()->insertData(data);
+ watchHandler->insertIncompleteData(data);
- if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
- qint64(data.id) != -1) {
+ if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
needPing = true;
expandObject(data.iname,data.id);
}
}
- if (needPing) {
+ if (needPing)
sendPing();
- } else {
- d->engine->watchHandler()->endCycle();
- }
bool becauseOfException;
stream >> becauseOfException;
@@ -518,12 +514,12 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
+ QLatin1String(iname) + QLatin1Char(' ') + data.value);
data.iname = iname;
if (iname.startsWith("watch.")) {
- d->engine->watchHandler()->insertData(data);
+ watchHandler->insertIncompleteData(data);
} else if (iname == "console") {
d->engine->showMessage(data.value, QtMessageLogOutput);
} else if (iname.startsWith("local.")) {
data.name = data.name.left(data.name.indexOf(QLatin1Char(' ')));
- d->engine->watchHandler()->insertData(data);
+ watchHandler->insertIncompleteData(data);
} else {
qWarning() << "QmlEngine: Unexcpected result: " << iname << data.value;
}
@@ -538,10 +534,9 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
foreach (WatchData data, result) {
data.iname = iname + '.' + data.exp;
- d->engine->watchHandler()->insertData(data);
+ watchHandler->insertIncompleteData(data);
- if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
- qint64(data.id) != -1) {
+ if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
needPing = true;
expandObject(data.iname, data.id);
}
@@ -560,14 +555,12 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
d->logReceiveMessage(QString::fromLatin1("%1 %2 (%3 x locals) (%4 x watchdata)").arg(
QLatin1String(command), QString::number(frameId),
QString::number(locals.size()), QString::number(watches.size())));
- d->engine->watchHandler()->beginCycle();
bool needPing = false;
foreach (WatchData data, watches) {
- data.iname = d->engine->watchHandler()->watcherName(data.exp);
- d->engine->watchHandler()->insertData(data);
+ data.iname = watchHandler->watcherName(data.exp);
+ watchHandler->insertIncompleteData(data);
- if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
- qint64(data.id) != -1) {
+ if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
needPing = true;
expandObject(data.iname, data.id);
}
@@ -575,26 +568,19 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
foreach (WatchData data, locals) {
data.iname = "local." + data.exp;
- d->engine->watchHandler()->insertData(data);
- if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
- qint64(data.id) != -1) {
+ watchHandler->insertIncompleteData(data);
+ if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
needPing = true;
expandObject(data.iname, data.id);
}
}
if (needPing)
sendPing();
- else
- d->engine->watchHandler()->endCycle();
} else if (command == "PONG") {
int ping;
stream >> ping;
-
d->logReceiveMessage(QLatin1String(command) + QLatin1Char(' ') + QString::number(ping));
-
- if (ping == d->ping)
- d->engine->watchHandler()->endCycle();
} else {
qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
d->logReceiveMessage(QLatin1String(command) + QLatin1String(" UNKNOWN COMMAND!!"));
diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp
index 16d758f6c9..efe52b8d41 100644
--- a/src/plugins/debugger/script/scriptengine.cpp
+++ b/src/plugins/debugger/script/scriptengine.cpp
@@ -651,7 +651,6 @@ bool ScriptEngine::checkForBreakCondition(bool byFunction)
void ScriptEngine::updateLocals()
{
QScriptContext *context = m_scriptEngine->currentContext();
- watchHandler()->beginCycle();
SDEBUG(Q_FUNC_INFO);
//
@@ -686,9 +685,7 @@ void ScriptEngine::updateLocals()
data.iname = "local";
data.name = _(data.iname);
- watchHandler()->beginCycle();
updateSubItem(data);
- watchHandler()->endCycle();
// FIXME: Use an extra thread. This here is evil.
m_stopped = true;
showStatusMessage(tr("Stopped."), 5000);
@@ -809,9 +806,9 @@ void ScriptEngine::updateSubItem(const WatchData &data0)
}
SDEBUG(msgDebugInsert(data, children));
- watchHandler()->insertData(data);
+ watchHandler()->insertIncompleteData(data);
if (!children.isEmpty())
- watchHandler()->insertBulkData(children);
+ watchHandler()->insertData(children);
}
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp)
diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp
index be6efdcaad..e9d3517626 100644
--- a/src/plugins/debugger/watchdata.cpp
+++ b/src/plugins/debugger/watchdata.cpp
@@ -143,7 +143,6 @@ WatchData::WatchData() :
size(0),
bitpos(0),
bitsize(0),
- generation(-1),
hasChildren(false),
valueEnabled(true),
valueEditable(true),
@@ -399,8 +398,6 @@ QString WatchData::toToolTip() const
if (size)
formatToolTipRow(str, tr("Static Object Size"), tr("%1 bytes").arg(size));
formatToolTipRow(str, tr("Internal ID"), QLatin1String(iname));
- formatToolTipRow(str, tr("Generation"),
- QString::number(generation));
str << "</table></body></html>";
return res;
}
diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h
index 44f9f97624..2b63c0b71a 100644
--- a/src/plugins/debugger/watchdata.h
+++ b/src/plugins/debugger/watchdata.h
@@ -135,7 +135,6 @@ public:
uint size; // Size
uint bitpos; // Position within bit fields
uint bitsize; // Size in case of bit fields
- qint32 generation; // When updated?
bool hasChildren;
bool valueEnabled; // Value will be enabled or not
bool valueEditable; // Value will be editable
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index c9ada1d5b3..77bc4f9db5 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -40,10 +40,6 @@
#include "debuggerdialogs.h"
#include "watchutils.h"
-#if USE_WATCH_MODEL_TEST
-#include "modeltest.h"
-#endif
-
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
@@ -52,6 +48,7 @@
#include <QDebug>
#include <QEvent>
#include <QFile>
+#include <QPointer>
#include <QProcess>
#include <QTextStream>
#include <QtAlgorithms>
@@ -62,6 +59,12 @@
#include <ctype.h>
#include <utils/qtcassert.h>
+//#define USE_WATCH_MODEL_TEST 0
+//#define USE_EXPENSIVE_CHECKS 0
+
+#if USE_WATCH_MODEL_TEST
+#include "modeltest.h"
+#endif
namespace Debugger {
namespace Internal {
@@ -70,7 +73,13 @@ namespace Internal {
enum { debugModel = 0 };
#define MODEL_DEBUG(s) do { if (debugModel) qDebug() << s; } while (0)
-#define MODEL_DEBUGX(s) qDebug() << s
+
+#if USE_EXPENSIVE_CHECKS
+#define CHECK(s) s
+#else
+#define CHECK(s)
+#endif
+
static QHash<QByteArray, int> theWatcherNames;
static QHash<QByteArray, int> theTypeFormats;
@@ -100,126 +109,222 @@ static QByteArray stripForFormat(const QByteArray &ba)
return res;
}
-void WatchHandler::setUnprintableBase(int base)
-{
- theUnprintableBase = base;
- emitAllChanged();
-}
-
-int WatchHandler::unprintableBase()
-{
- return theUnprintableBase;
-}
-
////////////////////////////////////////////////////////////////////
//
// WatchItem
//
////////////////////////////////////////////////////////////////////
+// Used to make sure the item cache is notified of construction and
+// destruction of items.
+
+class WatchItem;
+WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname);
+void itemDestructor(WatchModel *model, WatchItem *item);
+
class WatchItem : public WatchData
{
public:
- WatchItem() { parent = 0; }
-
- ~WatchItem() {
- if (parent != 0)
- parent->children.removeOne(this);
- qDeleteAll(children);
- }
-
- WatchItem(const WatchData &data) : WatchData(data)
- { parent = 0; }
+ WatchItem *parent;
+ QList<WatchItem *> children;
- void setData(const WatchData &data)
- { static_cast<WatchData &>(*this) = data; }
+private:
+ friend WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname);
+ friend void itemDestructor(WatchModel *model, WatchItem *item);
- WatchItem *parent;
- QList<WatchItem *> children; // fetched children
+ WatchItem() { parent = 0; }
+ ~WatchItem() {}
+ WatchItem(const WatchItem &); // Not implemented.
};
-
///////////////////////////////////////////////////////////////////////
//
// WatchModel
//
///////////////////////////////////////////////////////////////////////
-WatchModel::WatchModel(WatchHandler *handler, WatchType type)
- : QAbstractItemModel(handler), m_generationCounter(0),
- m_handler(handler), m_type(type)
+class WatchModel : public QAbstractItemModel
{
- m_root = new WatchItem;
- m_root->hasChildren = 1;
- m_root->state = 0;
- m_root->name = WatchHandler::tr("Root");
- m_root->parent = 0;
+ Q_OBJECT
- switch (m_type) {
- case ReturnWatch:
- m_root->iname = "return";
- m_root->name = WatchHandler::tr("Return Value");
- break;
- case LocalsWatch:
- m_root->iname = "local";
- m_root->name = WatchHandler::tr("Locals");
- break;
- case WatchersWatch:
- m_root->iname = "watch";
- m_root->name = WatchHandler::tr("Expressions");
- break;
- case TooltipsWatch:
- m_root->iname = "tooltip";
- m_root->name = WatchHandler::tr("Tooltip");
- break;
- case InspectWatch:
- m_root->iname = "inspect";
- m_root->name = WatchHandler::tr("Inspector");
- break;
- }
+private:
+ explicit WatchModel(WatchHandler *handler);
+ ~WatchModel();
+
+ friend WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname);
+ friend void itemDestructor(WatchModel *model, WatchItem *item);
+
+public:
+ int rowCount(const QModelIndex &idx = QModelIndex()) const;
+ int columnCount(const QModelIndex &idx) const;
+
+signals:
+ void currentIndexRequested(const QModelIndex &idx);
+ void itemIsExpanded(const QModelIndex &idx);
+
+private:
+ QVariant data(const QModelIndex &idx, int role) const;
+ bool setData(const QModelIndex &idx, const QVariant &value, int role);
+ QModelIndex index(int, int, const QModelIndex &idx) const;
+ QModelIndex parent(const QModelIndex &idx) const;
+ bool hasChildren(const QModelIndex &idx) const;
+ Qt::ItemFlags flags(const QModelIndex &idx) const;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ bool canFetchMore(const QModelIndex &parent) const;
+ void fetchMore(const QModelIndex &parent);
+
+ void invalidateAll(const QModelIndex &parentIndex = QModelIndex());
+ WatchItem *createItem(const QByteArray &iname, const QString &name, WatchItem *parent);
+
+ friend class WatchHandler;
+
+ WatchItem *watchItem(const QModelIndex &) const;
+ QModelIndex watchIndex(const WatchItem *needle) const;
+ QModelIndex watchIndexHelper(const WatchItem *needle,
+ const WatchItem *parentItem, const QModelIndex &parentIndex) const;
+
+ void insertDataItem(const WatchData &data);
+ Q_SLOT void reinsertAllData();
+ void reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data);
+ void insertBulkData(const QList<WatchData> &data);
+ QString displayForAutoTest(const QByteArray &iname) const;
+ void reinitialize();
+ void destroyItem(WatchItem *item); // With model notification.
+ void destroyChildren(WatchItem *item); // With model notification.
+ void destroyHelper(const QList<WatchItem *> &items); // Without model notification.
+ void emitDataChanged(int column,
+ const QModelIndex &parentIndex = QModelIndex());
+
+ friend QDebug operator<<(QDebug d, const WatchModel &m);
+
+ void dump();
+ void dumpHelper(WatchItem *item);
+ Q_SLOT void emitAllChanged();
+
+ void showInEditorHelper(QString *contents, WatchItem *item, int level);
+ void setCurrentItem(const QByteArray &iname);
+
+ QString displayType(const WatchData &typeIn) const;
+ QString formattedValue(const WatchData &data) const;
+ QString removeInitialNamespace(QString str) const;
+ QString removeNamespaces(QString str) const;
+ void formatRequests(QByteArray *out, const WatchItem *item) const;
+ DebuggerEngine *engine() const;
+ QString display(const WatchItem *item, int col) const;
+ int itemFormat(const WatchData &data) const;
+ bool contentIsValid() const;
+
+ WatchHandler *m_handler; // Not owned.
+
+ WatchItem *m_root; // Owned.
+ WatchItem *m_localsRoot; // Not owned.
+ WatchItem *m_inspectorRoot; // Not owned.
+ WatchItem *m_watchRoot; // Not owned.
+ WatchItem *m_returnRoot; // Not owned.
+ WatchItem *m_tooltipRoot; // Not owned.
+
+ QSet<QByteArray> m_expandedINames;
+ QSet<QByteArray> m_fetchTriggered;
+
+ QStringList typeFormatList(const WatchData &data) const;
+ TypeFormats m_reportedTypeFormats;
+
+ // QWidgets and QProcesses taking care of special displays.
+ typedef QMap<QByteArray, QPointer<QObject> > EditHandlers;
+ EditHandlers m_editHandlers;
+
+ WatchItem *createItem(const QByteArray &iname);
+ WatchItem *createItem(const WatchData &data);
+ void assignData(WatchItem *item, const WatchData &data);
+ WatchItem *findItem(const QByteArray &iname) const;
+ friend class WatchItem;
+ QHash<QByteArray, WatchItem *> m_cache;
+
+ #if USE_EXPENSIVE_CHECKS
+ QHash<const WatchItem *, QByteArray> m_cache2;
+ void checkTree();
+ void checkItem(const WatchItem *item) const;
+ void checkTree(WatchItem *item, QSet<QByteArray> *inames);
+ #endif
+};
+
+WatchModel::WatchModel(WatchHandler *handler)
+ : m_handler(handler)
+{
+ m_root = createItem(QByteArray(), tr("Root"), 0);
+ // Note: Needs to stay
+ m_localsRoot = createItem("local", tr("Locals"), m_root);
+ m_inspectorRoot = createItem("inspect", tr("Inspector"), m_root);
+ m_watchRoot = createItem("watch", tr("Expressions"), m_root);
+ m_returnRoot = createItem("return", tr("Return Value"), m_root);
+ m_tooltipRoot = createItem("tooltip", tr("Tooltip"), m_root);
+
+ connect(debuggerCore()->action(SortStructMembers), SIGNAL(valueChanged(QVariant)),
+ SLOT(reinsertAllData()));
+ connect(debuggerCore()->action(ShowStdNamespace), SIGNAL(valueChanged(QVariant)),
+ SLOT(reinsertAllData()));
+ connect(debuggerCore()->action(ShowQtNamespace), SIGNAL(valueChanged(QVariant)),
+ SLOT(reinsertAllData()));
}
WatchModel::~WatchModel()
{
- delete m_root;
+ CHECK(checkItem(m_root));
+ destroyChildren(m_root);
+ itemDestructor(this, m_root);
+ QTC_CHECK(m_cache.isEmpty());
}
-WatchItem *WatchModel::rootItem() const
+WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname)
{
- return m_root;
+ QTC_CHECK(!model->m_cache.contains(iname));
+ WatchItem *item = new WatchItem();
+ item->iname = iname;
+ model->m_cache[iname] = item;
+ CHECK(model->m_cache2[item] = iname);
+ CHECK(model->checkItem(item));
+ return item;
}
-void WatchModel::reinitialize()
+void itemDestructor(WatchModel *model, WatchItem *item)
{
- int n = m_root->children.size();
- if (n == 0)
- return;
- //MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << m_root->iname);
- QModelIndex index = watchIndex(m_root);
- beginRemoveRows(index, 0, n - 1);
- qDeleteAll(m_root->children);
- m_root->children.clear();
- endRemoveRows();
+ QTC_ASSERT(model->m_cache.value(item->iname) == item, return);
+ CHECK(model->checkItem(item));
+ CHECK(model->m_cache2.remove(item));
+ model->m_cache.remove(item->iname);
+ delete item;
}
-void WatchModel::emitAllChanged()
+WatchItem *WatchModel::createItem(const QByteArray &iname, const QString &name, WatchItem *parent)
{
- emit layoutChanged();
+ WatchItem *item = itemConstructor(this, iname);
+ item->name = name;
+ item->hasChildren = true; // parent == 0;
+ item->state = 0;
+ item->parent = parent;
+ if (parent)
+ parent->children.append(item);
+ return item;
}
-void WatchModel::beginCycle(bool fullCycle)
+void WatchModel::reinitialize()
{
- if (fullCycle)
- m_generationCounter++;
-
- //emit enableUpdates(false);
+ CHECK(checkTree());
+ //MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << m_root->iname);
+ QTC_CHECK(m_root->children.size() == 5);
+ destroyChildren(m_localsRoot);
+ destroyChildren(m_watchRoot);
+ destroyChildren(m_returnRoot);
+ destroyChildren(m_tooltipRoot);
+ destroyChildren(m_inspectorRoot);
+ QTC_CHECK(m_cache.size() == 6);
+ CHECK(checkTree());
}
-void WatchModel::endCycle()
+void WatchModel::emitAllChanged()
{
- removeOutdated();
- m_fetchTriggered.clear();
- //emit enableUpdates(true);
+ emit layoutChanged();
}
DebuggerEngine *WatchModel::engine() const
@@ -237,43 +342,85 @@ void WatchModel::dump()
void WatchModel::dumpHelper(WatchItem *item)
{
qDebug() << "ITEM: " << item->iname
- << (item->parent ? item->parent->iname : "<none>")
- << item->generation;
+ << (item->parent ? item->parent->iname : "<none>");
foreach (WatchItem *child, item->children)
dumpHelper(child);
}
-void WatchModel::removeOutdated()
+void WatchModel::destroyHelper(const QList<WatchItem *> &items)
{
- foreach (WatchItem *child, m_root->children)
- removeOutdatedHelper(child);
-#if DEBUG_MODEL
-#if USE_WATCH_MODEL_TEST
- (void) new ModelTest(this, this);
-#endif
-#endif
-}
-
-void WatchModel::removeOutdatedHelper(WatchItem *item)
-{
- if (item->generation < m_generationCounter) {
- destroyItem(item);
- } else {
- foreach (WatchItem *child, item->children)
- removeOutdatedHelper(child);
+ for (int i = items.size(); --i >= 0; ) {
+ WatchItem *item = items.at(i);
+ destroyHelper(item->children);
+ itemDestructor(this, item);
}
}
void WatchModel::destroyItem(WatchItem *item)
{
+ const QByteArray iname = item->iname;
+ CHECK(checkTree());
+ QTC_ASSERT(m_cache.contains(iname), return);
+
+ // Deregister from model and parent.
+ // It's sufficient to do this non-recursively.
WatchItem *parent = item->parent;
- QModelIndex index = watchIndex(parent);
- int n = parent->children.indexOf(item);
+ QTC_ASSERT(parent, return);
+ QModelIndex parentIndex = watchIndex(parent);
+ const int i = parent->children.indexOf(item);
//MODEL_DEBUG("NEED TO REMOVE: " << item->iname << "AT" << n);
- beginRemoveRows(index, n, n);
- parent->children.removeAt(n);
+ beginRemoveRows(parentIndex, i, i);
+ parent->children.removeAt(i);
endRemoveRows();
- delete item;
+
+ // Destroy contents.
+ destroyHelper(item->children);
+ itemDestructor(this, item);
+ QTC_ASSERT(!m_cache.contains(iname), return);
+ CHECK(checkTree());
+}
+
+void WatchModel::destroyChildren(WatchItem *item)
+{
+ CHECK(checkTree());
+ QTC_ASSERT(m_cache.contains(item->iname), return);
+ if (item->children.isEmpty())
+ return;
+
+ QList<WatchItem *> items = item->children;
+
+ // Deregister from model and parent.
+ // It's sufficient to do this non-recursively.
+ QModelIndex idx = watchIndex(item);
+ beginRemoveRows(idx, 0, items.size() - 1);
+ item->children.clear();
+ endRemoveRows();
+
+ // Destroy contents.
+ destroyHelper(items);
+ CHECK(checkTree());
+}
+
+WatchItem *WatchModel::findItem(const QByteArray &iname) const
+{
+ return m_cache.value(iname, 0);
+}
+
+WatchItem *WatchModel::createItem(const WatchData &data)
+{
+ WatchItem *item = itemConstructor(this, data.iname);
+ static_cast<WatchData &>(*item) = data;
+ return item;
+}
+
+void WatchModel::assignData(WatchItem *item, const WatchData &data)
+{
+ CHECK(checkItem(item));
+ QTC_ASSERT(data.iname == item->iname,
+ m_cache.remove(item->iname);
+ m_cache[data.iname] = item);
+ static_cast<WatchData &>(*item) = data;
+ CHECK(checkItem(item));
}
void WatchModel::reinsertAllData()
@@ -281,26 +428,21 @@ void WatchModel::reinsertAllData()
QList<WatchData> list;
reinsertAllDataHelper(m_root, &list);
reinitialize();
- foreach (WatchItem data, list) {
- data.setAllUnneeded();
- insertData(data);
- }
- layoutChanged();
+ insertBulkData(list);
}
void WatchModel::reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data)
{
data->append(*item);
+ data->back().setAllUnneeded();
foreach (WatchItem *child, item->children)
reinsertAllDataHelper(child, data);
}
static QByteArray parentName(const QByteArray &iname)
{
- int pos = iname.lastIndexOf('.');
- if (pos == -1)
- return QByteArray();
- return iname.left(pos);
+ const int pos = iname.lastIndexOf('.');
+ return pos == -1 ? QByteArray() : iname.left(pos);
}
static QString niceTypeHelper(const QByteArray &typeIn)
@@ -576,20 +718,27 @@ static inline QVariant editValue(const WatchData &d)
return QVariant(translate(stringValue));
}
-bool WatchModel::canFetchMore(const QModelIndex &index) const
+bool WatchModel::canFetchMore(const QModelIndex &idx) const
{
- WatchItem *item = watchItem(index);
+ if (!idx.isValid())
+ return false;
+ if (!contentIsValid())
+ return false;
+ WatchItem *item = watchItem(idx);
QTC_ASSERT(item, return false);
- return index.isValid() && contentIsValid() && !m_fetchTriggered.contains(item->iname);
+ if (!item->iname.contains('.'))
+ return false;
+ return !m_fetchTriggered.contains(item->iname);
}
-void WatchModel::fetchMore(const QModelIndex &index)
+void WatchModel::fetchMore(const QModelIndex &idx)
{
- QTC_ASSERT(index.isValid(), return);
- WatchItem *item = watchItem(index);
+ if (!idx.isValid())
+ return; // Triggered by ModelTester.
+ WatchItem *item = watchItem(idx);
QTC_ASSERT(item, return);
QTC_ASSERT(!m_fetchTriggered.contains(item->iname), return);
- m_handler->m_expandedINames.insert(item->iname);
+ m_expandedINames.insert(item->iname);
m_fetchTriggered.insert(item->iname);
if (item->children.isEmpty()) {
WatchData data = *item;
@@ -634,6 +783,8 @@ QModelIndex WatchModel::parent(const QModelIndex &idx) const
int WatchModel::rowCount(const QModelIndex &idx) const
{
+ if (!idx.isValid())
+ return m_root->children.size();
if (idx.column() > 0)
return 0;
return watchItem(idx)->children.size();
@@ -653,12 +804,15 @@ bool WatchModel::hasChildren(const QModelIndex &parent) const
WatchItem *WatchModel::watchItem(const QModelIndex &idx) const
{
- return idx.isValid()
+ WatchItem *item = idx.isValid()
? static_cast<WatchItem*>(idx.internalPointer()) : m_root;
+ CHECK(checkItem(item));
+ return item;
}
QModelIndex WatchModel::watchIndex(const WatchItem *item) const
{
+ CHECK(checkItem(item));
return watchIndexHelper(item, m_root, QModelIndex());
}
@@ -719,13 +873,40 @@ int WatchModel::itemFormat(const WatchData &data) const
bool WatchModel::contentIsValid() const
{
+ // FIXME:
// inspector doesn't follow normal beginCycle()/endCycle()
- if (m_type == InspectWatch)
- return true;
+ //if (m_type == InspectWatch)
+ // return true;
return m_handler->m_contentsValid;
}
-static inline QString expression(const WatchItem *item)
+#if USE_EXPENSIVE_CHECKS
+void WatchModel::checkTree()
+{
+ QSet<QByteArray> inames;
+ checkTree(m_root, &inames);
+ QSet<QByteArray> current = m_cache.keys().toSet();
+ Q_ASSERT(inames == current);
+}
+
+void WatchModel::checkTree(WatchItem *item, QSet<QByteArray> *inames)
+{
+ checkItem(item);
+ inames->insert(item->iname);
+ for (int i = 0, n = item->children.size(); i != n; ++i)
+ checkTree(item->children.at(i), inames);
+}
+
+void WatchModel::checkItem(const WatchItem *item) const
+{
+ Q_ASSERT(item->children.size() < 1000 * 1000);
+ Q_ASSERT(m_cache2.contains(item));
+ Q_ASSERT(m_cache2.value(item) == item->iname);
+ Q_ASSERT(m_cache.value(item->iname) == item);
+}
+#endif
+
+static QString expression(const WatchItem *item)
{
if (!item->exp.isEmpty())
return QString::fromLatin1(item->exp);
@@ -746,11 +927,11 @@ QString WatchModel::display(const WatchItem *item, int col) const
QString result;
switch (col) {
case 0:
- if (m_type == WatchersWatch && item->name.isEmpty())
+ if (item->parent == m_watchRoot && item->name.isEmpty())
result = tr("<Edit>");
- else if (m_type == ReturnWatch && item->iname.count('.') == 1)
+ else if (item->parent == m_returnRoot)
result = tr("returned value");
- else if (item->name == QLatin1String("*") && item->parent)
+ else if (item->name == QLatin1String("*"))
result = QLatin1Char('*') + item->parent->name;
else
result = removeInitialNamespace(item->name);
@@ -774,7 +955,7 @@ QString WatchModel::display(const WatchItem *item, int col) const
QString WatchModel::displayForAutoTest(const QByteArray &iname) const
{
- const WatchItem *item = findItem(iname, m_root);
+ WatchItem *item = findItem(iname);
if (item)
return display(item, 1) + QLatin1Char(' ') + display(item, 2);
return QString();
@@ -782,6 +963,9 @@ QString WatchModel::displayForAutoTest(const QByteArray &iname) const
QVariant WatchModel::data(const QModelIndex &idx, int role) const
{
+ if (!idx.isValid())
+ return QVariant(); // Triggered by ModelTester.
+
const WatchItem *item = watchItem(idx);
const WatchItem &data = *item;
@@ -840,10 +1024,10 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
return data.iname;
case LocalsExpandedRole:
- return m_handler->m_expandedINames.contains(data.iname);
+ return m_expandedINames.contains(data.iname);
case LocalsTypeFormatListRole:
- return m_handler->typeFormatList(data);
+ return typeFormatList(data);
case LocalsTypeRole:
return removeNamespaces(displayType(data));
@@ -890,13 +1074,16 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
return QVariant();
}
-bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role)
+bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role)
{
- WatchItem &data = *watchItem(index);
+ if (!idx.isValid())
+ return false; // Triggered by ModelTester.
+
+ WatchItem &data = *watchItem(idx);
switch (role) {
case Qt::EditRole:
- switch (index.column()) {
+ switch (idx.column()) {
case 0: // Watch expression: See delegate.
break;
case 1: // Change value
@@ -909,10 +1096,10 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro
case LocalsExpandedRole:
if (value.toBool()) {
// Should already have been triggered by fetchMore()
- //QTC_CHECK(m_handler->m_expandedINames.contains(data.iname));
- m_handler->m_expandedINames.insert(data.iname);
+ //QTC_CHECK(m_expandedINames.contains(data.iname));
+ m_expandedINames.insert(data.iname);
} else {
- m_handler->m_expandedINames.remove(data.iname);
+ m_expandedINames.remove(data.iname);
}
break;
@@ -933,7 +1120,7 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro
}
}
- emit dataChanged(index, index);
+ //emit dataChanged(idx, idx);
return true;
}
@@ -990,7 +1177,7 @@ QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int ro
return QVariant();
}
-QStringList WatchHandler::typeFormatList(const WatchData &data) const
+QStringList WatchModel::typeFormatList(const WatchData &data) const
{
if (data.referencingAddress || isPointerType(data.type))
return QStringList()
@@ -1026,7 +1213,7 @@ QStringList WatchHandler::typeFormatList(const WatchData &data) const
}
// Determine sort order of watch items by sort order or alphabetical inames
-// according to setting 'SortStructMembers'. We need a map key for bulkInsert
+// according to setting 'SortStructMembers'. We need a map key for insertBulkData
// and a predicate for finding the insertion position of a single item.
// Set this before using any of the below according to action
@@ -1086,98 +1273,153 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
return it - list.begin();
}
-void WatchModel::insertData(const WatchData &data)
+void WatchModel::insertDataItem(const WatchData &data)
{
+#if USE_WATCH_MODEL_TEST
+ (void) new ModelTest(this, this);
+#endif
+ m_fetchTriggered.remove(data.iname);
+ CHECK(checkTree());
+
QTC_ASSERT(!data.iname.isEmpty(), qDebug() << data.toString(); return);
- WatchItem *parent = findItem(parentName(data.iname), m_root);
+ WatchItem *parent = findItem(parentName(data.iname));
if (!parent) {
WatchData parent;
parent.iname = parentName(data.iname);
MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << data.iname);
if (!parent.iname.isEmpty())
- insertData(parent);
+ insertDataItem(parent);
return;
}
- QModelIndex index = watchIndex(parent);
- if (WatchItem *oldItem = findItem(data.iname, parent)) {
- bool hadChildren = oldItem->hasChildren;
+
+ WatchItem *item = findItem(data.iname);
+#if 0
+ if (item) {
// Overwrite old entry.
- bool hasChanged = oldItem->hasChanged(data);
- oldItem->setData(data);
- oldItem->changed = hasChanged;
- oldItem->generation = m_generationCounter;
- QModelIndex idx = watchIndex(oldItem);
- emit dataChanged(idx, idx.sibling(idx.row(), 2));
+ bool hasChanged = item->hasChanged(data);
+ assignData(item, data);
+ item->changed = hasChanged;
+ // QModelIndex idx = watchIndex(oldItem);
+ // emit dataChanged(idx, idx.sibling(idx.row(), 2));
+ } else {
+ // Add new entry.
+ item = createItem(data);
+ item->parent = parent;
+ item->changed = true;
+ }
+ const int n = findInsertPosition(parent->children, item);
+ QModelIndex idx = watchIndex(parent);
+ beginInsertRows(idx, n, n);
+ parent->children.insert(n, item);
+ endInsertRows();
+#else
+ if (item) {
+ // Remove old children.
+ destroyChildren(item);
- // This works around https://bugreports.qt-project.org/browse/QTBUG-7115
- // by creating and destroying a dummy child item.
- if (!hadChildren && oldItem->hasChildren) {
- WatchData dummy = data;
- dummy.iname = data.iname + ".x";
- dummy.hasChildren = false;
- dummy.setAllUnneeded();
- insertData(dummy);
- destroyItem(findItem(dummy.iname, m_root));
- }
+ // Overwrite old entry.
+ bool hasChanged = item->hasChanged(data);
+ assignData(item, data);
+ item->changed = hasChanged;
+ QModelIndex idx = watchIndex(item);
+ emit dataChanged(idx, idx.sibling(idx.row(), 2));
} else {
// Add new entry.
- WatchItem *item = new WatchItem(data);
+ item = createItem(data);
item->parent = parent;
- item->generation = m_generationCounter;
item->changed = true;
- const int n = findInsertPosition(parent->children, item);
- beginInsertRows(index, n, n);
- parent->children.insert(n, item);
+ const int row = findInsertPosition(parent->children, item);
+ QModelIndex idx = watchIndex(parent);
+ beginInsertRows(idx, row, row);
+ parent->children.insert(row, item);
endInsertRows();
+ if (m_expandedINames.contains(parentName(data.iname))) {
+ emit itemIsExpanded(idx);
+ }
+// if (m_expandedINames.contains(data.iname)) {
+// QModelIndex child = index(row, 0, idx);
+// emit itemIsExpanded(child);
+// }
}
+#endif
}
void WatchModel::insertBulkData(const QList<WatchData> &list)
{
+ foreach (const WatchData &data, list)
+ insertDataItem(data);
+ CHECK(checkTree());
+ return;
+
#if 0
- for (int i = 0; i != list.size(); ++i)
- insertData(list.at(i));
+ QMap<QByteArray, QList<WatchData> > hash;
+
+ foreach (const WatchData &data, list) {
+ // we insert everything, including incomplete stuff
+ // to reduce the number of row add operations in the model.
+ if (data.isValid()) {
+ hash[parentName(data.iname)].append(data);
+ } else {
+ qWarning("%s:%d: Attempt to bulk-insert invalid watch item: %s",
+ __FILE__, __LINE__, qPrintable(data.toString()));
+ }
+ }
+ foreach (const QByteArray &parentIName, hash.keys()) {
+ // FIXME
+ insertBulkDataX(hash[parentIName]);
+ }
+
+ foreach (const WatchData &data, list) {
+ if (data.isSomethingNeeded())
+ m_engine->updateWatchData(data);
+ }
+ const int n = list.size();
+#if 0
+ for (int i = 0; i != n; ++i)
+ insertData(list.at(i), false);
+ layoutChanged();
return;
#endif
// This method does not properly insert items in proper "iname sort
- // order", leading to random removal of items in removeOutdated();
+ // order".
//qDebug() << "WMI:" << list.toString();
//static int bulk = 0;
//foreach (const WatchItem &data, list)
// qDebug() << "BULK: " << ++bulk << data.toString();
- QTC_ASSERT(!list.isEmpty(), return);
+ QTC_ASSERT(n > 0, return);
QByteArray parentIName = parentName(list.at(0).iname);
- WatchItem *parent = findItem(parentIName, m_root);
+ WatchItem *parent = m_handler->findItem(parentIName);
if (!parent) {
WatchData parent;
parent.iname = parentIName;
- insertData(parent);
+ insertDataItem(parent, true);
MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << list.at(0).iname);
return;
}
- QModelIndex index = watchIndex(parent);
+ QModelIndex idx = watchIndex(parent);
sortWatchDataAlphabetically = debuggerCore()->boolSetting(SortStructMembers);
QMap<WatchDataSortKey, WatchData> newList;
typedef QMap<WatchDataSortKey, WatchData>::iterator Iterator;
- foreach (const WatchItem &data, list)
- newList.insert(WatchDataSortKey(data), data);
- if (newList.size() != list.size()) {
- qDebug() << "LIST: ";
- foreach (const WatchItem &data, list)
- qDebug() << data.toString();
- qDebug() << "NEW LIST: ";
- foreach (const WatchItem &data, newList)
- qDebug() << data.toString();
- qDebug() << "P->CHILDREN: ";
- foreach (const WatchItem *item, parent->children)
- qDebug() << item->toString();
- qDebug()
- << "P->CHILDREN.SIZE: " << parent->children.size()
- << "NEWLIST SIZE: " << newList.size()
- << "LIST SIZE: " << list.size();
- }
+ for (int i = 0; i != n; ++i)
+ newList.insert(WatchDataSortKey(list.at(i)), list.at(i));
+
+ //if (newList.size() != n) {
+ // qDebug() << "LIST: ";
+ // for (int i = 0; i != n; ++i)
+ // qDebug() << list.at(i).toString();
+ // qDebug() << "NEW LIST: ";
+ // foreach (const WatchData &data, newList)
+ // qDebug() << data.toString();
+ // qDebug() << "P->CHILDREN: ";
+ // foreach (const WatchItem *item, parent->children)
+ // qDebug() << item->toString();
+ // qDebug()
+ // << "P->CHILDREN.SIZE: " << parent->children.size()
+ // << "NEWLIST SIZE: " << newList.size()
+ // << "LIST SIZE: " << list.size();
+ //}
QTC_ASSERT(newList.size() == list.size(), return);
foreach (WatchItem *oldItem, parent->children) {
@@ -1185,12 +1427,9 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
Iterator it = newList.find(oldSortKey);
if (it == newList.end()) {
WatchData data = *oldItem;
- data.generation = m_generationCounter;
newList.insert(oldSortKey, data);
} else {
it->changed = it->hasChanged(*oldItem);
- if (it->generation == -1)
- it->generation = m_generationCounter;
}
}
@@ -1206,9 +1445,7 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
if (!parent->children[i]->isEqual(*it)) {
qDebug() << "REPLACING" << parent->children.at(i)->iname
<< " WITH " << it->iname << it->generation;
- parent->children[i]->setData(*it);
- if (parent->children[i]->generation == -1)
- parent->children[i]->generation = m_generationCounter;
+ m_handler->setData(parent->children[i], *it);
//emit dataChanged(idx.sibling(i, 0), idx.sibling(i, 2));
} else {
//qDebug() << "SKIPPING REPLACEMENT" << parent->children.at(i)->iname;
@@ -1218,14 +1455,12 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
// add new items
if (oldCount < newList.size()) {
- beginInsertRows(index, oldCount, newList.size() - 1);
+ beginInsertRows(idx, oldCount, newList.size() - 1);
//MODEL_DEBUG("INSERT : " << data.iname << data.value);
for (int i = oldCount; i < newList.size(); ++i, ++it) {
- WatchItem *item = new WatchItem(*it);
+ WatchItem *item = m_handler->createItem(*it);
qDebug() << "ADDING" << it->iname;
item->parent = parent;
- if (item->generation == -1)
- item->generation = m_generationCounter;
item->changed = true;
parent->children.append(item);
}
@@ -1233,16 +1468,7 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
}
//qDebug() << "ITEMS: " << parent->children.size();
dump();
-}
-
-WatchItem *WatchModel::findItem(const QByteArray &iname, WatchItem *root) const
-{
- if (root->iname == iname)
- return root;
- for (int i = root->children.size(); --i >= 0; )
- if (WatchItem *item = findItem(iname, root->children.at(i)))
- return item;
- return 0;
+#endif
}
static void debugRecursion(QDebug &d, const WatchItem *item, int depth)
@@ -1271,6 +1497,29 @@ void WatchModel::formatRequests(QByteArray *out, const WatchItem *item) const
formatRequests(out, child);
}
+void WatchModel::showInEditorHelper(QString *contents, WatchItem *item, int depth)
+{
+ const QChar tab = QLatin1Char('\t');
+ const QChar nl = QLatin1Char('\n');
+ contents->append(QString(depth, tab));
+ contents->append(item->name);
+ contents->append(tab);
+ contents->append(item->value);
+ contents->append(tab);
+ contents->append(item->type);
+ contents->append(nl);
+ foreach (WatchItem *child, item->children)
+ showInEditorHelper(contents, child, depth + 1);
+}
+
+void WatchModel::setCurrentItem(const QByteArray &iname)
+{
+ if (WatchItem *item = findItem(iname)) {
+ QModelIndex idx = watchIndex(item);
+ emit currentIndexRequested(idx);
+ }
+}
+
///////////////////////////////////////////////////////////////////////
//
// WatchHandler
@@ -1280,92 +1529,39 @@ void WatchModel::formatRequests(QByteArray *out, const WatchItem *item) const
WatchHandler::WatchHandler(DebuggerEngine *engine)
{
m_engine = engine;
- m_inChange = false;
m_watcherCounter = debuggerCore()->sessionValue(QLatin1String("Watchers"))
.toStringList().count();
-
- m_return = new WatchModel(this, ReturnWatch);
- m_locals = new WatchModel(this, LocalsWatch);
- m_watchers = new WatchModel(this, WatchersWatch);
- m_tooltips = new WatchModel(this, TooltipsWatch);
- m_inspect = new WatchModel(this, InspectWatch);
-
+ m_model = new WatchModel(this);
m_contentsValid = false;
+ m_contentsValid = true; // FIXME
m_resetLocationScheduled = false;
-
- connect(debuggerCore()->action(SortStructMembers), SIGNAL(valueChanged(QVariant)),
- SLOT(reinsertAllData()));
- connect(debuggerCore()->action(ShowStdNamespace), SIGNAL(valueChanged(QVariant)),
- SLOT(reinsertAllData()));
- connect(debuggerCore()->action(ShowQtNamespace), SIGNAL(valueChanged(QVariant)),
- SLOT(reinsertAllData()));
-}
-
-void WatchHandler::beginCycle(bool fullCycle)
-{
- m_return->beginCycle(fullCycle);
- m_locals->beginCycle(fullCycle);
- m_watchers->beginCycle(fullCycle);
- m_tooltips->beginCycle(fullCycle);
- // don't sync m_inspect here: It's updated on it's own
-}
-
-void WatchHandler::endCycle()
-{
- m_return->endCycle();
- m_locals->endCycle();
- m_watchers->endCycle();
- m_tooltips->endCycle();
-
- m_contentsValid = true;
- m_resetLocationScheduled = false;
-
- updateWatchersWindow();
}
-void WatchHandler::beginCycle(WatchType type, bool fullCycle)
+WatchHandler::~WatchHandler()
{
- model(type)->beginCycle(fullCycle);
-}
-
-void WatchHandler::endCycle(WatchType type)
-{
- model(type)->endCycle();
+ // Do it manually to prevent calling back in model destructors
+ // after m_cache is destroyed.
+ delete m_model;
+ m_model = 0;
}
void WatchHandler::cleanup()
{
- m_expandedINames.clear();
+ m_model->m_expandedINames.clear();
theWatcherNames.remove(QByteArray());
- m_return->reinitialize();
- m_locals->reinitialize();
- m_tooltips->reinitialize();
- m_inspect->reinitialize();
- m_return->m_fetchTriggered.clear();
- m_locals->m_fetchTriggered.clear();
- m_watchers->m_fetchTriggered.clear();
- m_tooltips->m_fetchTriggered.clear();
- m_inspect->m_fetchTriggered.clear();
+ m_model->reinitialize();
+ m_model->m_fetchTriggered.clear();
#if 1
- for (EditHandlers::ConstIterator it = m_editHandlers.begin();
- it != m_editHandlers.end(); ++it) {
+ for (WatchModel::EditHandlers::ConstIterator it = m_model->m_editHandlers.begin();
+ it != m_model->m_editHandlers.end(); ++it) {
if (!it.value().isNull())
delete it.value();
}
- m_editHandlers.clear();
+ m_model->m_editHandlers.clear();
#endif
}
-void WatchHandler::emitAllChanged()
-{
- m_return->emitAllChanged();
- m_locals->emitAllChanged();
- m_watchers->emitAllChanged();
- m_tooltips->emitAllChanged();
- m_inspect->emitAllChanged();
-}
-
-void WatchHandler::insertData(const WatchData &data)
+void WatchHandler::insertIncompleteData(const WatchData &data)
{
MODEL_DEBUG("INSERTDATA: " << data.toString());
if (!data.isValid()) {
@@ -1374,14 +1570,10 @@ void WatchHandler::insertData(const WatchData &data)
return;
}
- if (data.isSomethingNeeded() && data.iname.contains(".")) {
+ if (data.isSomethingNeeded() && data.iname.contains('.')) {
MODEL_DEBUG("SOMETHING NEEDED: " << data.toString());
- if (!m_engine->isSynchronous()
- || data.isInspect()) {
- WatchModel *model = modelForIName(data.iname);
- QTC_ASSERT(model, return);
- model->insertData(data);
-
+ if (!m_engine->isSynchronous() || data.isInspect()) {
+ m_model->insertDataItem(data);
m_engine->updateWatchData(data);
} else {
m_engine->showMessage(QLatin1String("ENDLESS LOOP: SOMETHING NEEDED: ")
@@ -1390,71 +1582,47 @@ void WatchHandler::insertData(const WatchData &data)
data1.setAllUnneeded();
data1.setValue(QLatin1String("<unavailable synchronous data>"));
data1.setHasChildren(false);
- WatchModel *model = modelForIName(data.iname);
- QTC_ASSERT(model, return);
- model->insertData(data1);
+ m_model->insertDataItem(data1);
}
} else {
- WatchModel *model = modelForIName(data.iname);
- QTC_ASSERT(model, return);
MODEL_DEBUG("NOTHING NEEDED: " << data.toString());
- model->insertData(data);
+ m_model->insertDataItem(data);
showEditValue(data);
}
}
-void WatchHandler::reinsertAllData()
+void WatchHandler::insertData(const WatchData &data)
{
- m_locals->reinsertAllData();
- m_watchers->reinsertAllData();
- m_tooltips->reinsertAllData();
- m_return->reinsertAllData();
- m_inspect->reinsertAllData();
+ QList<WatchData> list;
+ list.append(data);
+ insertData(list);
}
-// Bulk-insertion
-void WatchHandler::insertBulkData(const QList<WatchData> &list)
+void WatchHandler::insertData(const QList<WatchData> &list)
{
-#if 1
- foreach (const WatchItem &data, list)
- insertData(data);
- return;
-#endif
-
- if (list.isEmpty())
- return;
- QMap<QByteArray, QList<WatchData> > hash;
+ m_model->insertBulkData(list);
- foreach (const WatchData &data, list) {
- // we insert everything, including incomplete stuff
- // to reduce the number of row add operations in the model.
- if (data.isValid()) {
- hash[parentName(data.iname)].append(data);
- } else {
- qWarning("%s:%d: Attempt to bulk-insert invalid watch item: %s",
- __FILE__, __LINE__, qPrintable(data.toString()));
- }
- }
- foreach (const QByteArray &parentIName, hash.keys()) {
- WatchModel *model = modelForIName(parentIName);
- QTC_ASSERT(model, return);
- model->insertBulkData(hash[parentIName]);
- }
+ m_contentsValid = true;
+ updateWatchersWindow();
+}
- foreach (const WatchData &data, list) {
- if (data.isSomethingNeeded())
- m_engine->updateWatchData(data);
- }
+void WatchHandler::removeAllData()
+{
+ m_model->reinitialize();
}
void WatchHandler::removeData(const QByteArray &iname)
{
- WatchModel *model = modelForIName(iname);
- if (!model)
- return;
- WatchItem *item = model->findItem(iname, model->m_root);
+ WatchItem *item = m_model->findItem(iname);
+ if (item)
+ m_model->destroyItem(item);
+}
+
+void WatchHandler::removeChildren(const QByteArray &iname)
+{
+ WatchItem *item = m_model->findItem(iname);
if (item)
- model->destroyItem(item);
+ m_model->destroyChildren(item);
}
QByteArray WatchHandler::watcherName(const QByteArray &exp)
@@ -1483,14 +1651,13 @@ void WatchHandler::watchExpression(const QString &exp)
data.setAllUnneeded();
data.setValue(QString(QLatin1Char(' ')));
data.setHasChildren(false);
- insertData(data);
+ insertIncompleteData(data);
} else if (m_engine->isSynchronous()) {
m_engine->updateWatchData(data);
} else {
- insertData(data);
+ insertIncompleteData(data);
}
updateWatchersWindow();
- emitAllChanged();
}
static void swapEndian(char *d, int nchar)
@@ -1509,9 +1676,9 @@ static void swapEndian(char *d, int nchar)
void WatchHandler::showEditValue(const WatchData &data)
{
const QByteArray key = data.address ? data.hexAddress() : data.iname;
- QObject *w = m_editHandlers.value(key);
+ QObject *w = m_model->m_editHandlers.value(key);
if (data.editformat == 0x0) {
- m_editHandlers.remove(data.iname);
+ m_model->m_editHandlers.remove(data.iname);
delete w;
} else if (data.editformat == 1 || data.editformat == 3) {
// QImage
@@ -1524,7 +1691,7 @@ void WatchHandler::showEditValue(const WatchData &data)
QLatin1String(data.hexAddress())) :
tr("%1 Object at Unknown Address").arg(QLatin1String(data.type));
l->setWindowTitle(title);
- m_editHandlers[key] = l;
+ m_model->m_editHandlers[key] = l;
}
int width, height, format;
QByteArray ba;
@@ -1563,7 +1730,7 @@ void WatchHandler::showEditValue(const WatchData &data)
if (!t) {
delete w;
t = new QTextEdit;
- m_editHandlers[key] = t;
+ m_model->m_editHandlers[key] = t;
}
QByteArray ba = QByteArray::fromHex(data.editvalue);
QString str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2);
@@ -1580,7 +1747,7 @@ void WatchHandler::showEditValue(const WatchData &data)
p = new QProcess;
p->start(QLatin1String(cmd));
p->waitForStarted();
- m_editHandlers[key] = p;
+ m_model->m_editHandlers[key] = p;
}
p->write(input + '\n');
} else {
@@ -1592,13 +1759,10 @@ void WatchHandler::clearWatches()
{
if (theWatcherNames.isEmpty())
return;
- const QList<WatchItem *> watches = m_watchers->rootItem()->children;
- for (int i = watches.size() - 1; i >= 0; i--)
- m_watchers->destroyItem(watches.at(i));
+ m_model->destroyChildren(m_model->m_watchRoot);
theWatcherNames.clear();
m_watcherCounter = 0;
updateWatchersWindow();
- emitAllChanged();
saveWatchers();
}
@@ -1607,12 +1771,12 @@ void WatchHandler::removeWatchExpression(const QString &exp0)
QByteArray exp = exp0.toLatin1();
MODEL_DEBUG("REMOVE WATCH: " << exp);
theWatcherNames.remove(exp);
- foreach (WatchItem *item, m_watchers->rootItem()->children) {
+
+ foreach (WatchItem *item, m_model->m_watchRoot->children) {
if (item->exp == exp) {
- m_watchers->destroyItem(item);
+ m_model->destroyItem(item);
saveWatchers();
updateWatchersWindow();
- emitAllChanged();
break;
}
}
@@ -1621,7 +1785,15 @@ void WatchHandler::removeWatchExpression(const QString &exp0)
void WatchHandler::updateWatchersWindow()
{
// Force show/hide of watchers and return view.
- debuggerCore()->updateWatchersWindow();
+ static int previousShowWatch = -1;
+ static int previousShowReturn = -1;
+ int showWatch = !m_model->m_watchRoot->children.isEmpty();
+ int showReturn = !m_model->m_returnRoot->children.isEmpty();
+ if (showWatch == previousShowWatch && showReturn == previousShowReturn)
+ return;
+ previousShowWatch = showWatch;
+ previousShowReturn = showReturn;
+ debuggerCore()->updateWatchersWindow(showWatch, showReturn);
}
QStringList WatchHandler::watchedExpressions()
@@ -1684,18 +1856,14 @@ void WatchHandler::loadSessionData()
theWatcherNames.clear();
m_watcherCounter = 0;
QVariant value = debuggerCore()->sessionValue(QLatin1String("Watchers"));
- foreach (WatchItem *item, m_watchers->rootItem()->children)
- m_watchers->destroyItem(item);
+ m_model->destroyChildren(m_model->m_watchRoot);
foreach (const QString &exp, value.toStringList())
watchExpression(exp);
- updateWatchersWindow();
- emitAllChanged();
}
void WatchHandler::updateWatchers()
{
- foreach (WatchItem *item, m_watchers->rootItem()->children)
- m_watchers->destroyItem(item);
+ m_model->destroyChildren(m_model->m_watchRoot);
// Copy over all watchers and mark all watchers as incomplete.
foreach (const QByteArray &exp, theWatcherNames.keys()) {
WatchData data;
@@ -1703,67 +1871,33 @@ void WatchHandler::updateWatchers()
data.setAllNeeded();
data.name = QLatin1String(exp);
data.exp = exp;
- insertData(data);
+ insertIncompleteData(data);
}
}
-WatchModel *WatchHandler::model(WatchType type) const
+QAbstractItemModel *WatchHandler::model() const
{
- switch (type) {
- case ReturnWatch: return m_return;
- case LocalsWatch: return m_locals;
- case WatchersWatch: return m_watchers;
- case TooltipsWatch: return m_tooltips;
- case InspectWatch: return m_inspect;
- }
- QTC_CHECK(false);
- return 0;
+ return m_model;
}
-WatchModel *WatchHandler::modelForIName(const QByteArray &iname) const
+const WatchData *WatchHandler::watchData(const QModelIndex &idx) const
{
- if (iname.startsWith("return"))
- return m_return;
- if (iname.startsWith("local"))
- return m_locals;
- if (iname.startsWith("tooltip"))
- return m_tooltips;
- if (iname.startsWith("watch"))
- return m_watchers;
- if (iname.startsWith("inspect"))
- return m_inspect;
- QTC_ASSERT(false, qDebug() << "INAME: " << iname);
- return 0;
+ return m_model->watchItem(idx);
}
-const WatchData *WatchHandler::watchData(WatchType type, const QModelIndex &index) const
+const WatchData *WatchHandler::findData(const QByteArray &iname) const
{
- if (index.isValid())
- if (const WatchModel *m = model(type))
- return m->watchItem(index);
- return 0;
-}
-
-const WatchData *WatchHandler::findItem(const QByteArray &iname) const
-{
- const WatchModel *model = modelForIName(iname);
- QTC_ASSERT(model, return 0);
- return model->findItem(iname, model->m_root);
+ return m_model->findItem(iname);
}
QString WatchHandler::displayForAutoTest(const QByteArray &iname) const
{
- const WatchModel *model = modelForIName(iname);
- QTC_ASSERT(model, return QString());
- return model->displayForAutoTest(iname);
+ return m_model->displayForAutoTest(iname);
}
-QModelIndex WatchHandler::itemIndex(const QByteArray &iname) const
+bool WatchHandler::hasItem(const QByteArray &iname) const
{
- if (const WatchModel *model = modelForIName(iname))
- if (WatchItem *item = model->findItem(iname, model->m_root))
- return model->watchIndex(item);
- return QModelIndex();
+ return m_model->findItem(iname);
}
void WatchHandler::setFormat(const QByteArray &type0, int format)
@@ -1774,17 +1908,13 @@ void WatchHandler::setFormat(const QByteArray &type0, int format)
else
theTypeFormats[type] = format;
saveTypeFormats();
- m_return->emitDataChanged(1);
- m_locals->emitDataChanged(1);
- m_watchers->emitDataChanged(1);
- m_tooltips->emitDataChanged(1);
- m_inspect->emitDataChanged(1);
+ m_model->emitDataChanged(1);
}
int WatchHandler::format(const QByteArray &iname) const
{
int result = -1;
- if (const WatchData *item = findItem(iname)) {
+ if (const WatchData *item = m_model->findItem(iname)) {
int result = theIndividualFormats.value(item->iname, -1);
if (result == -1)
result = theTypeFormats.value(stripForFormat(item->type), -1);
@@ -1795,10 +1925,9 @@ int WatchHandler::format(const QByteArray &iname) const
QByteArray WatchHandler::expansionRequests() const
{
QByteArray ba;
- //m_locals->formatRequests(&ba, m_locals->m_root);
- //m_watchers->formatRequests(&ba, m_watchers->m_root);
- if (!m_expandedINames.isEmpty()) {
- QSetIterator<QByteArray> jt(m_expandedINames);
+ m_model->formatRequests(&ba, m_model->m_root);
+ if (!m_model->m_expandedINames.isEmpty()) {
+ QSetIterator<QByteArray> jt(m_model->m_expandedINames);
while (jt.hasNext()) {
QByteArray iname = jt.next();
ba.append(iname);
@@ -1845,67 +1974,43 @@ QByteArray WatchHandler::individualFormatRequests() const
void WatchHandler::addTypeFormats(const QByteArray &type, const QStringList &formats)
{
- m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats);
+ m_model->m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats);
}
QString WatchHandler::editorContents()
{
QString contents;
- showInEditorHelper(&contents, m_locals->m_root, 0);
- showInEditorHelper(&contents, m_watchers->m_root, 0);
+ m_model->showInEditorHelper(&contents, m_model->m_root, 0);
return contents;
}
-void WatchHandler::showInEditorHelper(QString *contents, WatchItem *item, int depth)
-{
- const QChar tab = QLatin1Char('\t');
- const QChar nl = QLatin1Char('\n');
- contents->append(QString(depth, tab));
- contents->append(item->name);
- contents->append(tab);
- contents->append(item->value);
- contents->append(tab);
- contents->append(item->type);
- contents->append(nl);
- foreach (WatchItem *child, item->children)
- showInEditorHelper(contents, child, depth + 1);
-}
-
void WatchHandler::removeTooltip()
{
- m_tooltips->reinitialize();
- m_tooltips->emitAllChanged();
+ m_model->destroyChildren(m_model->m_tooltipRoot);
}
void WatchHandler::rebuildModel()
{
- beginCycle();
-
- const QList<WatchItem *> watches = m_watchers->rootItem()->children;
- for (int i = watches.size() - 1; i >= 0; i--)
- m_watchers->destroyItem(watches.at(i));
-
- foreach (const QString &exp, watchedExpressions()) {
- WatchData data;
- data.exp = exp.toLatin1();
- data.name = exp;
- data.iname = watcherName(data.exp);
- data.setAllUnneeded();
-
- insertData(data);
- }
+// m_model->destroyChildren(m_model->m_watchRoot);
- endCycle();
+// foreach (const QString &exp, watchedExpressions()) {
+// WatchData data;
+// data.exp = exp.toLatin1();
+// data.name = exp;
+// data.iname = watcherName(data.exp);
+// data.setAllUnneeded();
+// insertIncompleteData(data);
+// }
}
void WatchHandler::setTypeFormats(const TypeFormats &typeFormats)
{
- m_reportedTypeFormats = typeFormats;
+ m_model->m_reportedTypeFormats = typeFormats;
}
TypeFormats WatchHandler::typeFormats() const
{
- return m_reportedTypeFormats;
+ return m_model->m_reportedTypeFormats;
}
void WatchHandler::editTypeFormats(bool includeLocals, const QByteArray &iname)
@@ -1914,11 +2019,11 @@ void WatchHandler::editTypeFormats(bool includeLocals, const QByteArray &iname)
TypeFormatsDialog dlg(0);
//QHashIterator<QString, QStringList> it(m_reportedTypeFormats);
- QList<QString> l = m_reportedTypeFormats.keys();
+ QList<QString> l = m_model->m_reportedTypeFormats.keys();
qSort(l.begin(), l.end());
foreach (const QString &ba, l) {
int f = iname.isEmpty() ? -1 : format(iname);
- dlg.addTypeFormats(ba, m_reportedTypeFormats.value(ba), f);
+ dlg.addTypeFormats(ba, m_model->m_reportedTypeFormats.value(ba), f);
}
if (dlg.exec())
setTypeFormats(dlg.typeFormats());
@@ -1927,6 +2032,7 @@ void WatchHandler::editTypeFormats(bool includeLocals, const QByteArray &iname)
void WatchHandler::scheduleResetLocation()
{
m_contentsValid = false;
+ //m_contentsValid = true; // FIXME
m_resetLocationScheduled = true;
}
@@ -1934,26 +2040,19 @@ void WatchHandler::resetLocation()
{
if (m_resetLocationScheduled) {
m_resetLocationScheduled = false;
- m_return->invalidateAll();
- m_locals->invalidateAll();
- m_watchers->invalidateAll();
- m_tooltips->invalidateAll();
- m_inspect->invalidateAll();
+ //m_model->invalidateAll(); FIXME
}
}
bool WatchHandler::isValidToolTip(const QByteArray &iname) const
{
- WatchItem *item = m_tooltips->findItem(iname, m_tooltips->m_root);
+ WatchItem *item = m_model->findItem(iname);
return item && !item->type.trimmed().isEmpty();
}
-void WatchHandler::setCurrentModelIndex(WatchType modelType,
- const QModelIndex &index)
+void WatchHandler::setCurrentItem(const QByteArray &iname)
{
- if (WatchModel *m = model(modelType)) {
- emit m->setCurrentIndex(index);
- }
+ m_model->setCurrentItem(iname);
}
QHash<QByteArray, int> WatchHandler::watcherNames()
@@ -1961,5 +2060,28 @@ QHash<QByteArray, int> WatchHandler::watcherNames()
return theWatcherNames;
}
+void WatchHandler::setUnprintableBase(int base)
+{
+ theUnprintableBase = base;
+ m_model->emitAllChanged();
+}
+
+int WatchHandler::unprintableBase()
+{
+ return theUnprintableBase;
+}
+
+bool WatchHandler::isExpandedIName(const QByteArray &iname) const
+{
+ return m_model->m_expandedINames.contains(iname);
+}
+
+QSet<QByteArray> WatchHandler::expandedINames() const
+{
+ return m_model->m_expandedINames;
+}
+
} // namespace Internal
} // namespace Debugger
+
+#include "watchhandler.moc"
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index c99fe88685..db44eef08c 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -35,28 +35,38 @@
#include "watchdata.h"
-#include <QPointer>
#include <QHash>
#include <QSet>
#include <QStringList>
#include <QAbstractItemModel>
namespace Debugger {
+
class DebuggerEngine;
namespace Internal {
-class WatchItem;
-class WatchHandler;
+class WatchModel;
+
+class UpdateParameters
+{
+public:
+ UpdateParameters() { tryPartial = tooltipOnly = false; }
+
+ bool tryPartial;
+ bool tooltipOnly;
+ QByteArray varList;
+};
+
typedef QHash<QString, QStringList> TypeFormats;
enum WatchType
{
- ReturnWatch,
- LocalsWatch,
- WatchersWatch,
- TooltipsWatch,
- InspectWatch
+ LocalsType,
+ InspectType,
+ WatchersType,
+ ReturnType,
+ TooltipType
};
enum IntegerFormat
@@ -67,126 +77,38 @@ enum IntegerFormat
OctalFormat
};
-class WatchModel : public QAbstractItemModel
-{
- Q_OBJECT
-
-private:
- explicit WatchModel(WatchHandler *handler, WatchType type);
- virtual ~WatchModel();
-
-public:
- virtual int rowCount(const QModelIndex &idx = QModelIndex()) const;
- virtual int columnCount(const QModelIndex &idx) const;
-
-signals:
- void setCurrentIndex(const QModelIndex &index);
-
-private:
- QVariant data(const QModelIndex &index, int role) const;
- bool setData(const QModelIndex &index, const QVariant &value, int role);
- QModelIndex index(int, int, const QModelIndex &idx) const;
- QModelIndex parent(const QModelIndex &idx) const;
- bool hasChildren(const QModelIndex &idx) const;
- Qt::ItemFlags flags(const QModelIndex &idx) const;
- QVariant headerData(int section, Qt::Orientation orientation,
- int role = Qt::DisplayRole) const;
- bool canFetchMore(const QModelIndex &parent) const;
- void fetchMore(const QModelIndex &parent);
-
- void invalidateAll(const QModelIndex &parentIndex = QModelIndex());
-
- friend class WatchHandler;
-
- WatchItem *watchItem(const QModelIndex &) const;
- QModelIndex watchIndex(const WatchItem *needle) const;
- QModelIndex watchIndexHelper(const WatchItem *needle,
- const WatchItem *parentItem, const QModelIndex &parentIndex) const;
-
- void insertData(const WatchData &data);
- void reinsertAllData();
- void reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data);
- void insertBulkData(const QList<WatchData> &data);
- WatchItem *findItem(const QByteArray &iname, WatchItem *root) const;
- QString displayForAutoTest(const QByteArray &iname) const;
- void reinitialize();
- void removeOutdated();
- void removeOutdatedHelper(WatchItem *item);
- WatchItem *rootItem() const;
- void destroyItem(WatchItem *item);
-
- void emitDataChanged(int column,
- const QModelIndex &parentIndex = QModelIndex());
- void beginCycle(bool fullCycle); // Called at begin of updateLocals() cycle.
- void endCycle(); // Called after all results have been received.
-
- friend QDebug operator<<(QDebug d, const WatchModel &m);
-
- void dump();
- void dumpHelper(WatchItem *item);
- void emitAllChanged();
-
-private:
- QString displayType(const WatchData &typeIn) const;
- QString formattedValue(const WatchData &data) const;
- QString removeInitialNamespace(QString str) const;
- QString removeNamespaces(QString str) const;
- void formatRequests(QByteArray *out, const WatchItem *item) const;
- DebuggerEngine *engine() const;
- QString display(const WatchItem *item, int col) const;
- int itemFormat(const WatchData &data) const;
- bool contentIsValid() const;
- int m_generationCounter;
-
- WatchHandler *m_handler;
- WatchType m_type;
- WatchItem *m_root;
- QSet<QByteArray> m_fetchTriggered;
-};
-
class WatchHandler : public QObject
{
Q_OBJECT
public:
explicit WatchHandler(DebuggerEngine *engine);
- WatchModel *model(WatchType type) const;
- WatchModel *modelForIName(const QByteArray &iname) const;
+ ~WatchHandler();
+
+ QAbstractItemModel *model() const;
void cleanup();
void watchExpression(const QString &exp);
void removeWatchExpression(const QString &exp);
Q_SLOT void clearWatches();
- Q_SLOT void emitAllChanged();
- void beginCycle(bool fullCycle = true); // Called at begin of updateLocals() cycle
void updateWatchers(); // Called after locals are fetched
- void endCycle(); // Called after all results have been received
-
- void beginCycle(WatchType type, bool fullCycle = true);
- void endCycle(WatchType type);
void showEditValue(const WatchData &data);
- void insertData(const WatchData &data);
- void insertBulkData(const QList<WatchData> &data);
- void removeData(const QByteArray &iname);
- Q_SLOT void reinsertAllData();
-
- const WatchData *watchData(WatchType type, const QModelIndex &) const;
- const WatchData *findItem(const QByteArray &iname) const;
+ const WatchData *watchData(const QModelIndex &) const;
+ const WatchData *findData(const QByteArray &iname) const;
QString displayForAutoTest(const QByteArray &iname) const;
- QModelIndex itemIndex(const QByteArray &iname) const;
+ bool hasItem(const QByteArray &iname) const;
void loadSessionData();
void saveSessionData();
void removeTooltip();
void rebuildModel();
- bool isExpandedIName(const QByteArray &iname) const
- { return m_expandedINames.contains(iname); }
- QSet<QByteArray> expandedINames() const
- { return m_expandedINames; }
+ bool isExpandedIName(const QByteArray &iname) const;
+ QSet<QByteArray> expandedINames() const;
+
static QStringList watchedExpressions();
static QHash<QByteArray, int> watcherNames();
@@ -199,7 +121,6 @@ public:
void addTypeFormats(const QByteArray &type, const QStringList &formats);
void setTypeFormats(const TypeFormats &typeFormats);
TypeFormats typeFormats() const;
- QStringList typeFormatList(const WatchData &data) const;
void setUnprintableBase(int base);
static int unprintableBase();
@@ -213,7 +134,15 @@ public:
void resetLocation();
bool isValidToolTip(const QByteArray &iname) const;
- void setCurrentModelIndex(WatchType modelType, const QModelIndex &index);
+ void setCurrentItem(const QByteArray &iname);
+ void updateWatchersWindow();
+
+ void insertData(const WatchData &data); // Convenience.
+ void insertData(const QList<WatchData> &list);
+ void insertIncompleteData(const WatchData &data);
+ void removeData(const QByteArray &iname);
+ void removeChildren(const QByteArray &iname);
+ void removeAllData();
private:
friend class WatchModel;
@@ -223,25 +152,8 @@ private:
static void saveTypeFormats();
void setFormat(const QByteArray &type, int format);
- void updateWatchersWindow();
- void showInEditorHelper(QString *contents, WatchItem *item, int level);
-
- bool m_inChange;
- // QWidgets and QProcesses taking care of special displays.
- typedef QMap<QByteArray, QPointer<QObject> > EditHandlers;
- EditHandlers m_editHandlers;
-
- TypeFormats m_reportedTypeFormats;
-
- // Items expanded in the Locals & Watchers view.
- QSet<QByteArray> m_expandedINames;
-
- WatchModel *m_return;
- WatchModel *m_locals;
- WatchModel *m_watchers;
- WatchModel *m_tooltips;
- WatchModel *m_inspect;
+ WatchModel *m_model;
DebuggerEngine *m_engine;
int m_watcherCounter;
@@ -253,4 +165,6 @@ private:
} // namespace Internal
} // namespace Debugger
+Q_DECLARE_METATYPE(Debugger::Internal::UpdateParameters)
+
#endif // DEBUGGER_WATCHHANDLER_H
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index 9f5ae27609..0cdac8da9c 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -530,12 +530,12 @@ void WatchTreeView::keyPressEvent(QKeyEvent *ev)
QString exp = model()->data(idx1).toString();
watchExpression(exp);
}
- QTreeView::keyPressEvent(ev);
+ BaseTreeView::keyPressEvent(ev);
}
void WatchTreeView::dragEnterEvent(QDragEnterEvent *ev)
{
- //QTreeView::dragEnterEvent(ev);
+ //BaseTreeView::dragEnterEvent(ev);
if (ev->mimeData()->hasText()) {
ev->setDropAction(Qt::CopyAction);
ev->accept();
@@ -544,7 +544,7 @@ void WatchTreeView::dragEnterEvent(QDragEnterEvent *ev)
void WatchTreeView::dragMoveEvent(QDragMoveEvent *ev)
{
- //QTreeView::dragMoveEvent(ev);
+ //BaseTreeView::dragMoveEvent(ev);
if (ev->mimeData()->hasText()) {
ev->setDropAction(Qt::CopyAction);
ev->accept();
@@ -559,7 +559,7 @@ void WatchTreeView::dropEvent(QDropEvent *ev)
ev->setDropAction(Qt::CopyAction);
ev->accept();
}
- //QTreeView::dropEvent(ev);
+ //BaseTreeView::dropEvent(ev);
}
void WatchTreeView::mouseDoubleClickEvent(QMouseEvent *ev)
@@ -570,7 +570,7 @@ void WatchTreeView::mouseDoubleClickEvent(QMouseEvent *ev)
watchExpression(QString());
return;
}
- QTreeView::mouseDoubleClickEvent(ev);
+ BaseTreeView::mouseDoubleClickEvent(ev);
}
// Text for add watch action with truncated expression.
@@ -971,7 +971,7 @@ bool WatchTreeView::event(QEvent *ev)
releaseMouse();
currentEngine()->watchPoint(mapToGlobal(mev->pos()));
}
- return QTreeView::event(ev);
+ return BaseTreeView::event(ev);
}
void WatchTreeView::editItem(const QModelIndex &idx)
@@ -982,6 +982,7 @@ void WatchTreeView::editItem(const QModelIndex &idx)
void WatchTreeView::setModel(QAbstractItemModel *model)
{
BaseTreeView::setModel(model);
+ setRootIndex(model->index(m_type, 0, QModelIndex()));
setRootIsDecorated(true);
if (header()) {
header()->setDefaultAlignment(Qt::AlignLeft);
@@ -990,15 +991,25 @@ void WatchTreeView::setModel(QAbstractItemModel *model)
}
connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper()));
-
- QTC_ASSERT(qobject_cast<WatchModel*>(model), return);
- connect(model, SIGNAL(setCurrentIndex(QModelIndex)),
+ connect(model, SIGNAL(currentIndexRequested(QModelIndex)),
SLOT(setCurrentIndex(QModelIndex)));
+ connect(model, SIGNAL(itemIsExpanded(QModelIndex)),
+ SLOT(handleItemIsExpanded(QModelIndex)));
+}
+
+void WatchTreeView::handleItemIsExpanded(const QModelIndex &idx)
+{
+ bool on = idx.data(LocalsExpandedRole).toBool();
+ QTC_ASSERT(on, return);
+ if (!isExpanded(idx))
+ expand(idx);
}
void WatchTreeView::resetHelper()
{
- resetHelper(model()->index(0, 0));
+ QModelIndex idx = model()->index(m_type, 0);
+ resetHelper(idx);
+ expand(idx);
}
void WatchTreeView::resetHelper(const QModelIndex &idx)
@@ -1019,6 +1030,13 @@ void WatchTreeView::resetHelper(const QModelIndex &idx)
}
}
+void WatchTreeView::reset()
+{
+ BaseTreeView::reset();
+ setRootIndex(model()->index(m_type, 0));
+ resetHelper();
+}
+
void WatchTreeView::watchExpression(const QString &exp)
{
currentEngine()->watchHandler()->watchExpression(exp);
@@ -1063,7 +1081,5 @@ void WatchTreeView::setWatchpointAtExpression(const QString &exp)
breakHandler()->appendBreakpoint(data);
}
-
} // namespace Internal
} // namespace Debugger
-
diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h
index 9a28f6380e..17760dda73 100644
--- a/src/plugins/debugger/watchwindow.h
+++ b/src/plugins/debugger/watchwindow.h
@@ -49,15 +49,17 @@ class WatchTreeView : public BaseTreeView
Q_OBJECT
public:
- enum Type { ReturnType, LocalsType, TooltipType, WatchersType, InspectType };
+ enum Type { LocalsType, InspectType, WatchersType, ReturnType, TooltipType };
explicit WatchTreeView(Type type, QWidget *parent = 0);
Type type() const { return m_type; }
void setModel(QAbstractItemModel *model);
+ void reset();
public slots:
void watchExpression(const QString &exp);
void removeWatchExpression(const QString &exp);
+ void handleItemIsExpanded(const QModelIndex &idx);
private:
Q_SLOT void resetHelper();