Commit 609f4a43 authored by hjk's avatar hjk
Browse files

debugger: Rework watch model.

It's now properly using canFetchMore/fetchMore. cdb is not yet ported.
parent 019fead3
......@@ -147,7 +147,7 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
QAction *act4 = new QAction(tr("Synchronize breakpoints"), &menu);
QModelIndex idx0 = si.front();
QModelIndex idx0 = (si.size() ? si.front() : QModelIndex());
QModelIndex idx2 = idx0.sibling(idx0.row(), 2);
bool enabled = si.isEmpty() || model()->data(idx0, Qt::UserRole).toBool();
QString str5 = enabled ? tr("Disable breakpoint") : tr("Enable breakpoint");
......
......@@ -64,7 +64,7 @@ public:
virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters);
virtual void exitDebugger();
virtual void detachDebugger();
virtual void updateWatchModel();
virtual void updateWatchData(const WatchData &data);
virtual void stepExec();
virtual void stepOutExec();
......
......@@ -151,14 +151,6 @@ DebuggerSettings *DebuggerSettings::instance()
item = new SavedAction(instance);
instance->insertItem(AssignType, item);
item = new SavedAction(instance);
item->setText(tr("Expand item"));
instance->insertItem(ExpandItem, item);
item = new SavedAction(instance);
item->setText(tr("Collapse item"));
instance->insertItem(CollapseItem, item);
//
// DebuggingHelper
//
......
......@@ -97,8 +97,6 @@ enum DebuggerActionCode
UseToolTips,
AssignValue,
AssignType,
ExpandItem,
CollapseItem,
RecheckDebuggingHelpers,
UseDebuggingHelpers,
......
......@@ -317,11 +317,11 @@ void DebuggerManager::init()
// Locals
m_watchHandler = new WatchHandler;
QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow);
localsView->setModel(m_watchHandler->model());
localsView->setModel(m_watchHandler->model(LocalsWatch));
// Watchers
QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow);
watchersView->setModel(m_watchHandler->model());
watchersView->setModel(m_watchHandler->model(WatchersWatch));
connect(m_watchHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
this, SIGNAL(sessionValueRequested(QString,QVariant*)));
connect(m_watchHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
......@@ -331,10 +331,10 @@ void DebuggerManager::init()
// Tooltip
QTreeView *tooltipView = qobject_cast<QTreeView *>(m_tooltipWindow);
tooltipView->setModel(m_watchHandler->model());
tooltipView->setModel(m_watchHandler->model(TooltipsWatch));
connect(m_watchHandler, SIGNAL(watchModelUpdateRequested()),
this, SLOT(updateWatchModel()));
connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)),
this, SLOT(updateWatchData(WatchData)));
m_continueAction = new QAction(this);
m_continueAction->setText(tr("Continue"));
......@@ -792,10 +792,10 @@ void DebuggerManager::setToolTipExpression(const QPoint &mousePos, TextEditor::I
m_engine->setToolTipExpression(mousePos, editor, cursorPos);
}
void DebuggerManager::updateWatchModel()
void DebuggerManager::updateWatchData(const WatchData &data)
{
if (m_engine)
m_engine->updateWatchModel();
m_engine->updateWatchData(data);
}
QVariant DebuggerManager::sessionValue(const QString &name)
......
......@@ -293,7 +293,7 @@ public slots:
void detachDebugger();
void addToWatchWindow();
void updateWatchModel();
void updateWatchData(const WatchData &data);
void sessionLoaded();
void sessionUnloaded();
......
......@@ -715,7 +715,7 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record)
#if 0
qDebug() << "# handleOutput,"
<< "cmd type:" << cmd.type
<< "cmd name:" << cmd.callbackName
<< " cmd synchronized:" << cmd.synchronized
<< "\n record: " << record.toString();
#endif
......@@ -727,14 +727,14 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record)
if (cmd.flags & RebuildModel) {
--m_pendingRequests;
PENDING_DEBUG(" TYPE " << cmd.type << " DECREMENTS PENDING TO: "
PENDING_DEBUG(" TYPE " << cmd.callbackName << " DECREMENTS PENDING TO: "
<< m_pendingRequests << cmd.command);
if (m_pendingRequests <= 0) {
PENDING_DEBUG(" .... AND TRIGGERS MODEL UPDATE");
updateWatchModel2();
PENDING_DEBUG("\n\n .... AND TRIGGERS MODEL UPDATE\n");
rebuildModel();
}
} else {
PENDING_DEBUG(" UNKNOWN TYPE " << cmd.type << " LEAVES PENDING AT: "
PENDING_DEBUG(" UNKNOWN TYPE " << cmd.callbackName << " LEAVES PENDING AT: "
<< m_pendingRequests << cmd.command);
}
......@@ -1968,7 +1968,6 @@ void GdbEngine::handleBreakList(const GdbMi &table)
handler->updateMarkers();
}
void GdbEngine::handleBreakIgnore(const GdbResultRecord &record, const QVariant &cookie)
{
int index = cookie.toInt();
......@@ -2724,7 +2723,7 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEd
m_toolTip.name = exp;
m_toolTip.iname = tooltipIName;
insertData(m_toolTip);
updateWatchModel2();
//updateWatchModel2();
}
......@@ -3062,55 +3061,40 @@ void GdbEngine::updateSubItem(const WatchData &data0)
QTC_ASSERT(false, return);
}
void GdbEngine::updateWatchModel()
void GdbEngine::updateWatchData(const WatchData &data)
{
m_pendingRequests = 0;
PENDING_DEBUG("EXTERNAL TRIGGERING UPDATE WATCH MODEL");
updateWatchModel2();
//m_pendingRequests = 0;
PENDING_DEBUG("UPDATE WATCH DATA");
#if DEBUG_PENDING
//qDebug() << "##############################################";
//qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
//qDebug() << data.toString();
#endif
// Bump requests to avoid model rebuilding during the nested
// updateWatchModel runs.
++m_pendingRequests;
updateSubItem(data);
//PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
--m_pendingRequests;
if (m_pendingRequests <= 0)
rebuildModel();
}
void GdbEngine::updateWatchModel2()
void GdbEngine::rebuildModel()
{
PENDING_DEBUG("UPDATE WATCH MODEL");
QList<WatchData> incomplete = qq->watchHandler()->takeCurrentIncompletes();
//QTC_ASSERT(incomplete.isEmpty(), /**/);
if (!incomplete.isEmpty()) {
#if DEBUG_PENDING
qDebug() << "##############################################";
qDebug() << "UPDATE MODEL, FOUND INCOMPLETES:";
foreach (const WatchData &data, incomplete)
qDebug() << data.toString();
#endif
// Bump requests to avoid model rebuilding during the nested
// updateWatchModel runs.
++m_pendingRequests;
foreach (const WatchData &data, incomplete)
updateSubItem(data);
PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
updateWatchModel2();
--m_pendingRequests;
return;
}
if (m_pendingRequests > 0) {
PENDING_DEBUG("UPDATE MODEL, PENDING: " << m_pendingRequests);
return;
}
PENDING_DEBUG("REBUILDING MODEL");
emit gdbInputAvailable(QString(),
_c('[') + currentTime() + _("] <Rebuild Watchmodel>"));
q->showStatusMessage(tr("Finished retrieving data."), 400);
qq->watchHandler()->rebuildModel();
qq->watchHandler()->endCycle();
if (!m_toolTipExpression.isEmpty()) {
WatchData *data = qq->watchHandler()->findData(tooltipIName);
if (data) {
WatchData *item = qq->watchHandler()->findItem(tooltipIName);
if (item) {
//m_toolTipCache[data->exp] = *data;
QToolTip::showText(m_toolTipPos,
_c('(') + data->type + _(") ") + data->exp + _(" = ") + data->value);
_c('(') + item->type + _(") ") + item->exp + _(" = ") + item->value);
} else {
QToolTip::showText(m_toolTipPos,
tr("Cannot evaluate expression: %1").arg(m_toolTipExpression));
......@@ -3498,7 +3482,7 @@ void GdbEngine::updateLocals()
PENDING_DEBUG("\nRESET PENDING");
m_toolTipCache.clear();
m_toolTipExpression.clear();
qq->watchHandler()->reinitializeWatchers();
qq->watchHandler()->beginCycle();
QString level = QString::number(currentFrame());
// '2' is 'list with type and value'
......@@ -3552,6 +3536,7 @@ void GdbEngine::handleStackListLocals(const GdbResultRecord &record, const QVari
locals += m_currentFunctionArgs;
setLocals(locals);
qq->watchHandler()->updateWatchers();
}
void GdbEngine::setLocals(const QList<GdbMi> &locals)
......
......@@ -320,8 +320,8 @@ private:
// FIXME: BaseClass. called to improve situation for a watch item
void updateSubItem(const WatchData &data);
void updateWatchModel();
Q_SLOT void updateWatchModel2();
void updateWatchData(const WatchData &data);
void rebuildModel();
void insertData(const WatchData &data);
void sendWatchParameters(const QByteArray &params0);
......
......@@ -40,13 +40,14 @@ class QString;
QT_END_NAMESPACE
namespace TextEditor {
class ITextEditor;
class ITextEditor;
}
namespace Debugger {
namespace Internal {
class Symbol;
class WatchData;
struct DebuggerStartParameters;
class IDebuggerEngine : public QObject
......@@ -59,7 +60,7 @@ public:
virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0;
virtual void exitDebugger() = 0;
virtual void detachDebugger() {}
virtual void updateWatchModel() = 0;
virtual void updateWatchData(const WatchData &data) = 0;
virtual void stepExec() = 0;
virtual void stepOutExec() = 0;
......
......@@ -572,7 +572,7 @@ void ScriptEngine::maybeBreakNow(bool byFunction)
void ScriptEngine::updateLocals()
{
QScriptContext *context = m_scriptEngine->currentContext();
qq->watchHandler()->reinitializeWatchers();
qq->watchHandler()->beginCycle();
//SDEBUG("UPDATE LOCALS");
//
......@@ -605,7 +605,6 @@ void ScriptEngine::updateLocals()
data.name = "local";
data.scriptValue = context->activationObject();
qq->watchHandler()->insertData(data);
updateWatchModel();
// FIXME: Use an extra thread. This here is evil
m_stopped = true;
......@@ -616,16 +615,10 @@ void ScriptEngine::updateLocals()
//SDEBUG("RUNNING AGAIN");
}
void ScriptEngine::updateWatchModel()
void ScriptEngine::updateWatchData(const WatchData &data)
{
while (true) {
QList<WatchData> list = qq->watchHandler()->takeCurrentIncompletes();
if (list.isEmpty())
break;
foreach (const WatchData &data, list)
updateSubItem(data);
}
qq->watchHandler()->rebuildModel();
updateSubItem(data);
//qq->watchHandler()->rebuildModel();
q->showStatusMessage(tr("Stopped."), 5000);
}
......
......@@ -107,9 +107,9 @@ private:
bool supportsThreads() const { return true; }
void maybeBreakNow(bool byFunction);
void updateWatchModel();
void updateWatchData(const WatchData &data);
void updateLocals();
void updateSubItem(const WatchData &data0);
void updateSubItem(const WatchData &data);
private:
friend class ScriptAgent;
......
......@@ -564,9 +564,9 @@ void TcfEngine::updateLocals()
{
}
void TcfEngine::updateWatchModel()
void TcfEngine::updateWatchData(const WatchData &)
{
qq->watchHandler()->rebuildModel();
//qq->watchHandler()->rebuildModel();
q->showStatusMessage(tr("Stopped."), 5000);
}
......
......@@ -112,9 +112,9 @@ private:
bool supportsThreads() const { return true; }
void maybeBreakNow(bool byFunction);
void updateWatchModel();
void updateWatchData(const WatchData &data);
void updateLocals();
void updateSubItem(const WatchData &data0);
void updateSubItem(const WatchData &data);
Q_SLOT void socketConnected();
Q_SLOT void socketDisconnected();
......
This diff is collapsed.
......@@ -42,6 +42,10 @@
namespace Debugger {
namespace Internal {
class WatchItem;
class WatchHandler;
enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch };
class WatchData
{
public:
......@@ -120,6 +124,7 @@ public:
QString framekey; // key for type cache
QScriptValue scriptValue; // if needed...
int childCount;
int generation; // when updated?
bool valuedisabled; // value will be greyed out
private:
......@@ -127,29 +132,18 @@ private:
public:
int source; // Used by some debuggers (CDB) to tell where it originates from (dumper or symbol evaluation)
int state;
// Model
int parentIndex;
int row;
int level;
QList<int> childIndex;
bool changed;
};
enum { INameRole = Qt::UserRole, ExpressionRole, ExpandedRole };
class WatchHandler : public QAbstractItemModel
class WatchModel : public QAbstractItemModel
{
Q_OBJECT
public:
WatchHandler();
QAbstractItemModel *model() { return this; }
private:
explicit WatchModel(WatchHandler *handler, WatchType type);
//
// QAbstractItemModel
//
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;
......@@ -160,23 +154,54 @@ public:
Qt::ItemFlags flags(const QModelIndex &idx) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
bool checkIndex(int id) const;
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &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 insertData(const WatchData &data);
WatchItem *findItem(const QString &iname, WatchItem *root) const;
void reinitialize();
void removeOutdated();
void removeOutdatedHelper(WatchItem *item);
WatchItem *dummyRoot() const;
void removeItem(WatchItem *item);
private:
WatchHandler *m_handler;
WatchType m_type;
WatchItem *m_root;
};
class WatchHandler : public QObject
{
Q_OBJECT
public:
WatchHandler();
WatchModel *model(WatchType type) const;
WatchModel *modelForIName(const QString &data) const;
//public slots:
void cleanup();
Q_SLOT void watchExpression(); // data in action->data().toString()
Q_SLOT void watchExpression(const QString &exp);
Q_SLOT void removeWatchExpression();
Q_SLOT void removeWatchExpression(const QString &exp);
void reinitializeWatchers();
void beginCycle(); // called at begin of updateLocals() cycle
void updateWatchers(); // called after locals are fetched
void endCycle(); // called after all results have been received
void showEditValue(const WatchData &data);
Q_SLOT void collapseChildren();
Q_SLOT void expandChildren();
Q_SLOT void collapseChildren(const QString &iname);
Q_SLOT void expandChildren(const QString &iname);
void insertData(const WatchData &data);
WatchData *findItem(const QString &iname) const;
void rebuildModel(); // unconditionally version of above
void showEditValue(const WatchData &data);
void loadSessionData();
void saveSessionData();
bool isDisplayedIName(const QString &iname) const
{ return m_displayedINames.contains(iname); }
......@@ -185,27 +210,13 @@ public:
QSet<QString> expandedINames() const
{ return m_expandedINames; }
void insertData(const WatchData &data);
QList<WatchData> takeCurrentIncompletes();
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &parent);
WatchData *findData(const QString &iname);
void loadSessionData();
void saveSessionData();
signals:
void watchModelUpdateRequested();
void watchDataUpdateNeeded(const WatchData &data);
void sessionValueRequested(const QString &name, QVariant *value);
void setSessionValueRequested(const QString &name, const QVariant &value);
private:
void reinitializeWatchersHelper();
WatchData takeData(const QString &iname);
QString toString() const;
friend class WatchModel;
void loadWatchers();
void saveWatchers();
......@@ -216,18 +227,16 @@ private:
typedef QMap<QString, QPointer<QWidget> > EditWindows;
EditWindows m_editWindows;
QList<WatchData> m_incompleteSet;
QList<WatchData> m_completeSet;
QList<WatchData> m_oldSet;
QList<WatchData> m_displaySet;
QHash<QString, int> m_watchers;
QHash<QString, int> m_watcherNames;
QString watcherName(const QString &exp);
void setDisplayedIName(const QString &iname, bool on);
QSet<QString> m_expandedINames; // those expanded in the treeview
QSet<QString> m_displayedINames; // those with "external" viewers
bool m_inFetchMore;
WatchModel *m_locals;
WatchModel *m_watchers;
WatchModel *m_tooltips;
};
} // namespace Internal
......
......@@ -127,26 +127,28 @@ WatchWindow::WatchWindow(Type type, QWidget *parent)
setAcceptDrops(true);
setDropIndicatorShown(true);
connect(this, SIGNAL(expanded(QModelIndex)),
this, SLOT(expandNode(QModelIndex)));
connect(this, SIGNAL(collapsed(QModelIndex)),
this, SLOT(collapseNode(QModelIndex)));
connect(act, SIGNAL(toggled(bool)),
this, SLOT(setAlternatingRowColorsHelper(bool)));
connect(this, SIGNAL(expanded(QModelIndex)),
this, SLOT(expandNode(QModelIndex)));
connect(this, SIGNAL(collapsed(QModelIndex)),
this, SLOT(collapseNode(QModelIndex)));
}
void WatchWindow::expandNode(const QModelIndex &idx)
{
model()->setData(idx, true, ExpandedRole);
}
void WatchWindow::collapseNode(const QModelIndex &idx)
{
model()->setData(idx, false, ExpandedRole);
}
void WatchWindow::expandNode(const QModelIndex &idx)
{
QModelIndex mi0 = idx.sibling(idx.row(), 0);
QVariant iname = model()->data(mi0, INameRole);
theDebuggerAction(ExpandItem)->trigger(iname);
}
void WatchWindow::collapseNode(const QModelIndex &idx)
void WatchWindow::reset()
{
QModelIndex mi0 = idx.sibling(idx.row(), 0);
QVariant iname = model()->data(mi0, INameRole);
theDebuggerAction(CollapseItem)->trigger(iname);
QTreeView::reset();
setRootIndex(model()->index(0, 0, QModelIndex()));
}
void WatchWindow::keyPressEvent(QKeyEvent *ev)
......@@ -259,17 +261,6 @@ void WatchWindow::editItem(const QModelIndex &idx)
Q_UNUSED(idx); // FIXME
}
void WatchWindow::reset()
{
QTreeView::reset();
int row = 0;
if (m_type == TooltipType)
row = 1;
else if (m_type == WatchersType)
row = 2;
setRootIndex(model()->index(row, 0, model()->index(0, 0)));
}
void WatchWindow::setModel(QAbstractItemModel *model)
{
QTreeView::setModel(model);
......
......@@ -59,9 +59,10 @@ public slots:
void setAlternatingRowColorsHelper(bool on) { setAlternatingRowColors(on); }
private:
Q_SLOT void expandNode(const QModelIndex &index);
Q_SLOT void collapseNode(const QModelIndex &index);
void reset();
Q_SLOT void resetHelper();
Q_SLOT void expandNode(const QModelIndex &idx);
Q_SLOT void collapseNode(const QModelIndex &idx);
void keyPressEvent(QKeyEvent *ev);
void contextMenuEvent(QContextMenuEvent *ev);
......@@ -70,7 +71,6 @@ private:
void dragMoveEvent(QDragMoveEvent *ev);
void editItem(const QModelIndex &idx);
void reset(); /* reimpl */
void resetHelper(const QModelIndex &idx);
......