diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index b3623f42867..05708c6ca4b 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1239,14 +1239,9 @@ void CdbEngine::updateAll() updateLocals(); } -void CdbEngine::selectThread(ThreadId threadId) +void CdbEngine::selectThread(const Thread &thread) { - if (!threadId.isValid() || threadId == threadsHandler()->currentThread()) - return; - - threadsHandler()->setCurrentThread(threadId); - - runCommand({'~' + QString::number(threadId.raw()) + " s", BuiltinCommand, + runCommand({'~' + thread->id() + " s", BuiltinCommand, [this](const DebuggerResponse &) { reloadFullStack(); }}); } @@ -1809,7 +1804,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT // Further examine stop and report to user QString message; QString exceptionBoxMessage; - ThreadId forcedThreadId; + Thread forcedThread; const unsigned stopFlags = examineStopReason(stopReason, &message, &exceptionBoxMessage, conditionalBreakPointTriggered); m_stopMode = NoStopRequested; @@ -1847,7 +1842,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT if (stopFlags & StopInArtificialThread) { showMessage(tr("Switching to main thread..."), LogMisc); runCommand({"~0 s", NoFlags}); - forcedThreadId = ThreadId(0); + forcedThread = Thread(); // Re-fetch stack again. reloadFullStack(); } else { @@ -1872,8 +1867,8 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT const GdbMi threads = stopReason["threads"]; if (threads.isValid()) { threadsHandler()->updateThreads(threads); - if (forcedThreadId.isValid()) - threadsHandler()->setCurrentThread(forcedThreadId); + if (forcedThread) + threadsHandler()->setCurrentThread(forcedThread); } else { showMessage(stopReason["threaderror"].data(), LogError); } diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index cfc822c658f..e5b617eb437 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -80,7 +80,7 @@ public: void executeDebuggerCommand(const QString &command) override; void activateFrame(int index) override; - void selectThread(ThreadId threadId) override; + void selectThread(const Thread &thread) override; bool stateAcceptsBreakpointChanges() const override; bool acceptsBreakpoint(const BreakpointParameters ¶ms) const override; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 028fa92211b..3717e502fd9 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -397,8 +397,12 @@ public: void selectThread(int index) { - ThreadId id = m_engine->threadsHandler()->threadAt(index); - m_engine->selectThread(id); + const Thread thread = m_engine->threadsHandler()->rootItem()->childAt(index); + QTC_ASSERT(thread, return); + // For immediate visual feedback. + m_engine->threadsHandler()->setCurrentThread(thread); + // Initiate the actual switching in the debugger backend. + m_engine->selectThread(thread); } void handleOperateByInstructionTriggered(bool on) @@ -745,6 +749,7 @@ void DebuggerEnginePrivate::setupViews() m_threadBox = new QComboBox; m_threadBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + m_threadBox->setModel(m_threadsHandler.model()); connect(m_threadBox, static_cast(&QComboBox::activated), this, &DebuggerEnginePrivate::selectThread); @@ -857,15 +862,6 @@ bool DebuggerEngine::isModulesWindowVisible() const return d->m_modulesWindow->isVisible(); } -void DebuggerEngine::setThreadBoxContents(const QStringList &list, int index) -{ - QSignalBlocker blocker(d->m_threadBox); - d->m_threadBox->clear(); - for (const QString &item : list) - d->m_threadBox->addItem(item); - d->m_threadBox->setCurrentIndex(index); -} - void DebuggerEngine::frameUp() { int currentIndex = stackHandler()->currentIndex(); diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 14634085837..7b2bdbf7c9d 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -30,6 +30,7 @@ #include "debuggeritem.h" #include "debuggerprotocol.h" #include "breakhandler.h" +#include "threadshandler.h" #include #include @@ -37,7 +38,6 @@ #include #include -#include #include QT_BEGIN_NAMESPACE @@ -74,13 +74,11 @@ class RegisterHandler; class StackHandler; class StackFrame; class SourceFilesHandler; -class ThreadsHandler; class WatchHandler; class WatchTreeView; class DebuggerToolTipContext; class MemoryViewSetupData; class TerminalRunner; -class ThreadId; class DebuggerRunParameters { @@ -317,7 +315,7 @@ public: virtual void assignValueInDebugger(WatchItem *item, const QString &expr, const QVariant &value); - virtual void selectThread(Internal::ThreadId threadId) = 0; + virtual void selectThread(const Internal::Thread &thread) = 0; virtual void executeRecordReverse(bool) {} virtual void executeReverse(bool) {} @@ -417,8 +415,6 @@ public: bool isRegistersWindowVisible() const; bool isModulesWindowVisible() const; - void setThreadBoxContents(const QStringList &list, int index); - void openMemoryEditor(); void handleExecDetach(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index a5b80b7e7c1..fe64936e929 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -523,7 +523,7 @@ void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result QString id = result["id"].data(); showStatusMessage(tr("Thread %1 created.").arg(id), 1000); ThreadData thread; - thread.id = ThreadId(id.toLong()); + thread.id = id; thread.groupId = result["group-id"].data(); threadsHandler()->updateThread(thread); } else if (asyncClass == "thread-group-exited") { @@ -537,7 +537,7 @@ void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result QString groupid = result["group-id"].data(); showStatusMessage(tr("Thread %1 in group %2 exited.") .arg(id).arg(groupid), 1000); - threadsHandler()->removeThread(ThreadId(id.toLong())); + threadsHandler()->removeThread(id); } else if (asyncClass == "thread-selected") { QString id = result["id"].data(); showStatusMessage(tr("Thread %1 selected.").arg(id), 1000); @@ -2880,12 +2880,11 @@ void GdbEngine::reloadSourceFiles() // ////////////////////////////////////////////////////////////////////// -void GdbEngine::selectThread(ThreadId threadId) +void GdbEngine::selectThread(const Thread &thread) { - threadsHandler()->setCurrentThread(threadId); - showStatusMessage(tr("Retrieving data for stack view thread 0x%1...") - .arg(threadId.raw(), 0, 16), 10000); - DebuggerCommand cmd("-thread-select " + QString::number(threadId.raw()), Discardable); + showStatusMessage(tr("Retrieving data for stack view thread %1...") + .arg(thread->id()), 10000); + DebuggerCommand cmd("-thread-select " + thread->id(), Discardable); cmd.callback = [this](const DebuggerResponse &) { QTC_CHECK(state() == InferiorUnrunnable || state() == InferiorStopOk); showStatusMessage(tr("Retrieving data for stack view..."), 3000); @@ -2987,9 +2986,8 @@ void GdbEngine::handleThreadInfo(const DebuggerResponse &response) ThreadsHandler *handler = threadsHandler(); handler->updateThreads(response.data); // This is necessary as the current thread might not be in the list. - if (!handler->currentThread().isValid()) { - ThreadId other = handler->threadAt(0); - if (other.isValid()) + if (!handler->currentThread()) { + if (Thread other = handler->threadAt(0)) selectThread(other); } updateState(false); // Adjust Threads combobox. @@ -3011,9 +3009,9 @@ void GdbEngine::handleThreadListIds(const DebuggerResponse &response) // In gdb 7.1+ additionally: current-thread-id="1" ThreadsHandler *handler = threadsHandler(); const QVector &items = response.data["thread-ids"].children(); - for (int index = 0, n = items.size(); index != n; ++index) { + for (const GdbMi &item : items) { ThreadData thread; - thread.id = ThreadId(items.at(index).toInt()); + thread.id = item.data(); handler->updateThread(thread); } reloadStack(); // Will trigger register reload. @@ -3027,7 +3025,7 @@ void GdbEngine::handleThreadNames(const DebuggerResponse &response) names.fromString(response.consoleStreamOutput); for (const GdbMi &name : names.children()) { ThreadData thread; - thread.id = ThreadId(name["id"].toInt()); + thread.id = name["id"].data(); thread.name = decodeData(name["value"].data(), name["valueencoded"].data()); handler->updateThread(thread); } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index dbd437ffd8a..c93178ee71b 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -219,7 +219,7 @@ private: ////////// General Interface ////////// ////////// View & Data Stuff ////////// - void selectThread(ThreadId threadId) final; + void selectThread(const Thread &thread) final; void activateFrame(int index) final; // diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 952505e51fc..3e5b88d5187 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -444,17 +444,18 @@ void LldbEngine::activateFrame(int frameIndex) DebuggerCommand cmd("activateFrame"); cmd.arg("index", frameIndex); - cmd.arg("thread", threadsHandler()->currentThread().raw()); + cmd.arg("thread", threadsHandler()->currentThread()->id()); runCommand(cmd); updateLocals(); reloadRegisters(); } -void LldbEngine::selectThread(ThreadId threadId) +void LldbEngine::selectThread(const Thread &thread) { + QTC_ASSERT(thread, return); DebuggerCommand cmd("selectThread"); - cmd.arg("id", threadId.raw()); + cmd.arg("id", thread->id()); cmd.callback = [this](const DebuggerResponse &) { fetchStack(action(MaximalStackDepth)->value().toInt()); }; diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index a6487de3bc0..907a5c2bdfa 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -82,7 +82,7 @@ private: void executeJumpToLine(const ContextData &data) override; void activateFrame(int index) override; - void selectThread(ThreadId threadId) override; + void selectThread(const Thread &thread) override; void fetchFullBacktrace(); // This should be always the last call in a function. diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 981951894d6..5089365f7b5 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -240,9 +240,9 @@ void PdbEngine::activateFrame(int frameIndex) updateLocals(); } -void PdbEngine::selectThread(ThreadId threadId) +void PdbEngine::selectThread(const Thread &thread) { - Q_UNUSED(threadId) + Q_UNUSED(thread) } bool PdbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index 09966f229ed..420e0639c7b 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -69,7 +69,7 @@ private: void executeJumpToLine(const ContextData &data) override; void activateFrame(int index) override; - void selectThread(ThreadId threadId) override; + void selectThread(const Thread &thread) override; bool acceptsBreakpoint(const BreakpointParameters &bp) const override; void insertBreakpoint(const Breakpoint &bp) override; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 8f8816ff449..91bd3e2e552 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -684,9 +684,9 @@ void QmlEngine::activateFrame(int index) d->updateLocals(); } -void QmlEngine::selectThread(ThreadId threadId) +void QmlEngine::selectThread(const Thread &thread) { - Q_UNUSED(threadId) + Q_UNUSED(thread) } void QmlEngine::insertBreakpoint(const Breakpoint &bp) diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 76b0452c160..8d407b11ae1 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -93,7 +93,7 @@ private: void executeJumpToLine(const ContextData &data) override; void activateFrame(int index) override; - void selectThread(ThreadId threadId) override; + void selectThread(const Thread &thread) override; bool acceptsBreakpoint(const BreakpointParameters &bp) const final; void insertBreakpoint(const Breakpoint &bp) final; diff --git a/src/plugins/debugger/threaddata.h b/src/plugins/debugger/threaddata.h index e54d0f37716..5d7a4a25805 100644 --- a/src/plugins/debugger/threaddata.h +++ b/src/plugins/debugger/threaddata.h @@ -31,28 +31,6 @@ namespace Debugger { namespace Internal { -//////////////////////////////////////////////////////////////////////// -// -// ThreadId -// -//////////////////////////////////////////////////////////////////////// - -/*! A typesafe identifier. */ -class ThreadId -{ -public: - ThreadId() = default; - explicit ThreadId(qint64 id) : m_id(id) {} - - bool isValid() const { return m_id != -1; } - qint64 raw() const { return m_id; } - bool operator==(const ThreadId other) const { return m_id == other.m_id; } - bool operator!=(const ThreadId other) const { return m_id != other.m_id; } - -private: - qint64 m_id = -1; -}; - //////////////////////////////////////////////////////////////////////// // // ThreadData @@ -77,12 +55,10 @@ struct ThreadData CoreColumn, ComboNameColumn, ColumnCount = CoreColumn, - - IdRole = Qt::UserRole }; // Permanent data. - ThreadId id; + QString id; QString groupId; QString targetId; QString core; diff --git a/src/plugins/debugger/threadshandler.cpp b/src/plugins/debugger/threadshandler.cpp index a4fd57dad61..acb3c4f35b7 100644 --- a/src/plugins/debugger/threadshandler.cpp +++ b/src/plugins/debugger/threadshandler.cpp @@ -53,168 +53,156 @@ namespace Internal { // /////////////////////////////////////////////////////////////////////// -class ThreadItem : public TreeItem +// ThreadItem + +ThreadItem::ThreadItem(const ThreadsHandler *handler, const ThreadData &data) + : threadData(data), handler(handler) +{} + +QVariant ThreadItem::data(int column, int role) const { - Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::ThreadsHandler) - -public: - ThreadItem(const ThreadsHandler *handler, const ThreadData &data = ThreadData()) - : threadData(data), handler(handler) - {} - - QVariant data(int column, int role) const override - { - switch (role) { - case Qt::DisplayRole: - return threadPart(column); - case Qt::ToolTipRole: - return threadToolTip(); - case Qt::DecorationRole: - // Return icon that indicates whether this is the active stack frame. - if (column == 0) - return threadData.id == handler->currentThread() ? Icons::LOCATION.icon() - : Icons::EMPTY.icon(); - break; - case ThreadData::IdRole: - return threadData.id.raw(); - default: - break; - } - return QVariant(); + switch (role) { + case Qt::DisplayRole: + if (column == 0) + return QString("#%1 %2").arg(threadData.id).arg(threadData.name); + return threadPart(column); + case Qt::ToolTipRole: + return threadToolTip(); + case Qt::DecorationRole: + // Return icon that indicates whether this is the active stack frame. + if (column == 0) + return this == handler->currentThread() ? Icons::LOCATION.icon() + : Icons::EMPTY.icon(); + break; + default: + break; } + return QVariant(); +} - Qt::ItemFlags flags(int column) const override - { - return threadData.stopped ? TreeItem::flags(column) : Qt::ItemFlags({}); +Qt::ItemFlags ThreadItem::flags(int column) const +{ + return threadData.stopped ? TreeItem::flags(column) : Qt::ItemFlags({}); +} + +QString ThreadItem::threadToolTip() const +{ + const char start[] = ""; + const char sep[] = ""; + const char end[] = ""; + QString rc; + QTextStream str(&rc); + str << "" + << start << ThreadsHandler::tr("Thread id:") + << sep << threadData.id << end; + if (!threadData.targetId.isEmpty()) + str << start << ThreadsHandler::tr("Target id:") + << sep << threadData.targetId << end; + if (!threadData.groupId.isEmpty()) + str << start << ThreadsHandler::tr("Group id:") + << sep << threadData.groupId << end; + if (!threadData.name.isEmpty()) + str << start << ThreadsHandler::tr("Name:") + << sep << threadData.name << end; + if (!threadData.state.isEmpty()) + str << start << ThreadsHandler::tr("State:") + << sep << threadData.state << end; + if (!threadData.core.isEmpty()) + str << start << ThreadsHandler::tr("Core:") + << sep << threadData.core << end; + if (threadData.address) { + str << start << ThreadsHandler::tr("Stopped at:") << sep; + if (!threadData.function.isEmpty()) + str << threadData.function << "
"; + if (!threadData.fileName.isEmpty()) + str << threadData.fileName << ':' << threadData.lineNumber << "
"; + str << formatToolTipAddress(threadData.address); } + str << "
"; + return rc; +} - QString threadToolTip() const - { - const char start[] = ""; - const char sep[] = ""; - const char end[] = ""; - QString rc; - QTextStream str(&rc); - str << "" - << start << ThreadsHandler::tr("Thread id:") - << sep << threadData.id.raw() << end; - if (!threadData.targetId.isEmpty()) - str << start << ThreadsHandler::tr("Target id:") - << sep << threadData.targetId << end; - if (!threadData.groupId.isEmpty()) - str << start << ThreadsHandler::tr("Group id:") - << sep << threadData.groupId << end; - if (!threadData.name.isEmpty()) - str << start << ThreadsHandler::tr("Name:") - << sep << threadData.name << end; - if (!threadData.state.isEmpty()) - str << start << ThreadsHandler::tr("State:") - << sep << threadData.state << end; - if (!threadData.core.isEmpty()) - str << start << ThreadsHandler::tr("Core:") - << sep << threadData.core << end; - if (threadData.address) { - str << start << ThreadsHandler::tr("Stopped at:") << sep; - if (!threadData.function.isEmpty()) - str << threadData.function << "
"; - if (!threadData.fileName.isEmpty()) - str << threadData.fileName << ':' << threadData.lineNumber << "
"; - str << formatToolTipAddress(threadData.address); - } - str << "
"; - return rc; +QVariant ThreadItem::threadPart(int column) const +{ + switch (column) { + case ThreadData::IdColumn: + return threadData.id; + case ThreadData::FunctionColumn: + return threadData.function; + case ThreadData::FileColumn: + return threadData.fileName.isEmpty() ? threadData.module : threadData.fileName; + case ThreadData::LineColumn: + return threadData.lineNumber >= 0 + ? QString::number(threadData.lineNumber) : QString(); + case ThreadData::AddressColumn: + return threadData.address > 0 + ? QLatin1String("0x") + QString::number(threadData.address, 16) + : QString(); + case ThreadData::CoreColumn: + return threadData.core; + case ThreadData::StateColumn: + return threadData.state; + case ThreadData::TargetIdColumn: + if (threadData.targetId.startsWith(QLatin1String("Thread "))) + return threadData.targetId.mid(7); + return threadData.targetId; + case ThreadData::NameColumn: + return threadData.name; + case ThreadData::DetailsColumn: + return threadData.details; + case ThreadData::ComboNameColumn: + return QString::fromLatin1("#%1 %2").arg(threadData.id).arg(threadData.name); } + return QVariant(); +} - QVariant threadPart(int column) const - { - switch (column) { - case ThreadData::IdColumn: - return threadData.id.raw(); - case ThreadData::FunctionColumn: - return threadData.function; - case ThreadData::FileColumn: - return threadData.fileName.isEmpty() ? threadData.module : threadData.fileName; - case ThreadData::LineColumn: - return threadData.lineNumber >= 0 - ? QString::number(threadData.lineNumber) : QString(); - case ThreadData::AddressColumn: - return threadData.address > 0 - ? QLatin1String("0x") + QString::number(threadData.address, 16) - : QString(); - case ThreadData::CoreColumn: - return threadData.core; - case ThreadData::StateColumn: - return threadData.state; - case ThreadData::TargetIdColumn: - if (threadData.targetId.startsWith(QLatin1String("Thread "))) - return threadData.targetId.mid(7); - return threadData.targetId; - case ThreadData::NameColumn: - return threadData.name; - case ThreadData::DetailsColumn: - return threadData.details; - case ThreadData::ComboNameColumn: - return QString::fromLatin1("#%1 %2").arg(threadData.id.raw()).arg(threadData.name); - } - return QVariant(); - } +void ThreadItem::notifyRunning() // Clear state information. +{ + threadData.address = 0; + threadData.function.clear(); + threadData.fileName.clear(); + threadData.frameLevel = -1; + threadData.state.clear(); + threadData.lineNumber = -1; + threadData.stopped = false; + update(); +} - void notifyRunning() // Clear state information. - { - threadData.address = 0; - threadData.function.clear(); - threadData.fileName.clear(); - threadData.frameLevel = -1; - threadData.state.clear(); - threadData.lineNumber = -1; - threadData.stopped = false; - update(); - } +void ThreadItem::notifyStopped() +{ + threadData.stopped = true; + update(); +} - void notifyStopped() - { - threadData.stopped = true; - update(); - } - - void mergeThreadData(const ThreadData &other) - { - if (!other.core.isEmpty()) - threadData.core = other.core; - if (!other.fileName.isEmpty()) - threadData.fileName = other.fileName; - if (!other.targetId.isEmpty()) - threadData.targetId = other.targetId; - if (!other.name.isEmpty()) - threadData.name = other.name; - if (other.frameLevel != -1) - threadData.frameLevel = other.frameLevel; - if (!other.function.isEmpty()) - threadData.function = other.function; - if (other.address) - threadData.address = other.address; - if (!other.module.isEmpty()) - threadData.module = other.module; - if (!other.details.isEmpty()) - threadData.details = other.details; - if (!other.state.isEmpty()) - threadData.state = other.state; - if (other.lineNumber != -1) - threadData.lineNumber = other.lineNumber; - update(); - } +void ThreadItem::mergeThreadData(const ThreadData &other) +{ + if (!other.core.isEmpty()) + threadData.core = other.core; + if (!other.fileName.isEmpty()) + threadData.fileName = other.fileName; + if (!other.targetId.isEmpty()) + threadData.targetId = other.targetId; + if (!other.name.isEmpty()) + threadData.name = other.name; + if (other.frameLevel != -1) + threadData.frameLevel = other.frameLevel; + if (!other.function.isEmpty()) + threadData.function = other.function; + if (other.address) + threadData.address = other.address; + if (!other.module.isEmpty()) + threadData.module = other.module; + if (!other.details.isEmpty()) + threadData.details = other.details; + if (!other.state.isEmpty()) + threadData.state = other.state; + if (other.lineNumber != -1) + threadData.lineNumber = other.lineNumber; + update(); +} -public: - ThreadData threadData; - const ThreadsHandler * const handler; -}; - -//////////////////////////////////////////////////////////////////////// -// // ThreadsHandler -// -/////////////////////////////////////////////////////////////////////// /*! \class Debugger::Internal::ThreadData @@ -235,17 +223,17 @@ ThreadsHandler::ThreadsHandler(DebuggerEngine *engine) { setObjectName(QLatin1String("ThreadsModel")); setHeader({ - QLatin1String(" ") + tr("ID") + QLatin1String(" "), - tr("Address"), tr("Function"), tr("File"), tr("Line"), tr("State"), - tr("Name"), tr("Target ID"), tr("Details"), tr("Core"), - }); + QLatin1String(" ") + tr("ID") + QLatin1String(" "), + tr("Address"), tr("Function"), tr("File"), tr("Line"), tr("State"), + tr("Name"), tr("Target ID"), tr("Details"), tr("Core"), + }); } bool ThreadsHandler::setData(const QModelIndex &idx, const QVariant &data, int role) { if (role == BaseTreeView::ItemActivatedRole) { - ThreadId id = ThreadId(idx.data(ThreadData::IdRole).toLongLong()); - m_engine->selectThread(id); + const Thread thread = itemForIndexAtLevel<1>(idx); + m_engine->selectThread(thread); return true; } @@ -263,21 +251,9 @@ bool ThreadsHandler::setData(const QModelIndex &idx, const QVariant &data, int r return false; } -static ThreadItem *itemForThreadId(const ThreadsHandler *handler, ThreadId threadId) -{ - const auto matcher = [threadId](ThreadItem *item) { return item->threadData.id == threadId; }; - return handler->findItemAtLevel<1>(matcher); -} - -static int indexForThreadId(const ThreadsHandler *handler, ThreadId threadId) -{ - ThreadItem *item = itemForThreadId(handler, threadId); - return item ? handler->rootItem()->indexOf(item) : -1; -} - int ThreadsHandler::currentThreadIndex() const { - return indexForThreadId(this, m_currentId); + return rootItem()->indexOf(m_currentThread); } void ThreadsHandler::sort(int column, Qt::SortOrder order) @@ -294,36 +270,29 @@ void ThreadsHandler::sort(int column, Qt::SortOrder order) }); } -ThreadId ThreadsHandler::currentThread() const +Thread ThreadsHandler::currentThread() const { - return m_currentId; + return m_currentThread; } -ThreadId ThreadsHandler::threadAt(int index) const +Thread ThreadsHandler::threadAt(int index) const { - QTC_ASSERT(index >= 0 && index < rootItem()->childCount(), return ThreadId()); - return rootItem()->childAt(index)->threadData.id; + QTC_ASSERT(index >= 0 && index < rootItem()->childCount(), return Thread()); + return rootItem()->childAt(index); } -void ThreadsHandler::setCurrentThread(ThreadId id) +void ThreadsHandler::setCurrentThread(const Thread &thread) { - if (id == m_currentId) + if (thread == m_currentThread) return; - ThreadItem *newItem = itemForThreadId(this, id); - if (!newItem) { - qWarning("ThreadsHandler::setCurrentThreadId: No such thread %d.", int(id.raw())); + if (!threadForId(thread->id())) { + qWarning("ThreadsHandler::setCurrentThreadId: No such thread %s.", qPrintable(thread->id())); return; } - ThreadItem *oldItem = itemForThreadId(this, m_currentId); - m_currentId = id; - if (oldItem) - oldItem->update(); - - newItem->update(); - - updateThreadBox(); + m_currentThread = thread; + thread->update(); } QString ThreadsHandler::pidForGroupId(const QString &groupId) const @@ -338,43 +307,16 @@ void ThreadsHandler::notifyGroupCreated(const QString &groupId, const QString &p void ThreadsHandler::updateThread(const ThreadData &threadData) { - if (ThreadItem *item = itemForThreadId(this, threadData.id)) - item->mergeThreadData(threadData); + if (Thread thread = threadForId(threadData.id)) + thread->mergeThreadData(threadData); else rootItem()->appendChild(new ThreadItem(this, threadData)); } -void ThreadsHandler::removeThread(ThreadId threadId) +void ThreadsHandler::removeThread(const QString &id) { - if (ThreadItem *item = itemForThreadId(this, threadId)) - destroyItem(item); -} - -void ThreadsHandler::setThreads(const Threads &threads) -{ - auto root = new ThreadItem(this); - for (int i = 0, n = threads.size(); i < n; ++i) - root->appendChild(new ThreadItem(this, threads.at(i))); - rootItem()->removeChildren(); - setRootItem(root); - m_resetLocationScheduled = false; - updateThreadBox(); -} - -void ThreadsHandler::updateThreadBox() -{ - QStringList list; - forItemsAtLevel<1>([&list](ThreadItem *item) { - list.append(QString::fromLatin1("#%1 %2").arg(item->threadData.id.raw()).arg(item->threadData.name)); - }); - m_engine->setThreadBoxContents(list, indexForThreadId(this, m_currentId)); -} - -ThreadData ThreadsHandler::thread(ThreadId id) const -{ - if (ThreadItem *item = itemForThreadId(this, id)) - return item->threadData; - return ThreadData(); + if (Thread thread = threadForId(id)) + destroyItem(thread); } void ThreadsHandler::removeAll() @@ -396,54 +338,27 @@ bool ThreadsHandler::notifyGroupExited(const QString &groupId) return m_pidForGroupId.isEmpty(); } -void ThreadsHandler::notifyRunning(const QString &data) +Thread ThreadsHandler::threadForId(const QString &id) const { - if (data.isEmpty() || data == "all") { - notifyAllRunning(); - } else { - bool ok; - qlonglong id = data.toLongLong(&ok); - if (ok) - notifyRunning(ThreadId(id)); - else // FIXME - notifyAllRunning(); - } + return findItemAtLevel<1>([id](const Thread &item) { + return item->threadData.id == id; + }); } -void ThreadsHandler::notifyAllRunning() +void ThreadsHandler::notifyRunning(const QString &id) { - forItemsAtLevel<1>([](ThreadItem *item) { item->notifyRunning(); }); + if (id.isEmpty() || id == "all") + forItemsAtLevel<1>([](const Thread &thread) { thread->notifyRunning(); }); + else if (Thread thread = threadForId(id)) + thread->notifyRunning(); } -void ThreadsHandler::notifyRunning(ThreadId threadId) +void ThreadsHandler::notifyStopped(const QString &id) { - if (ThreadItem *item = itemForThreadId(this, threadId)) - item->notifyRunning(); -} - -void ThreadsHandler::notifyStopped(const QString &data) -{ - if (data.isEmpty() || data == "all") { - notifyAllStopped(); - } else { - bool ok; - qlonglong id = data.toLongLong(&ok); - if (ok) - notifyRunning(ThreadId(id)); - else // FIXME - notifyAllStopped(); - } -} - -void ThreadsHandler::notifyAllStopped() -{ - forItemsAtLevel<1>([](ThreadItem *item) { item->notifyStopped(); }); -} - -void ThreadsHandler::notifyStopped(ThreadId threadId) -{ - if (ThreadItem *item = itemForThreadId(this, threadId)) - item->notifyStopped(); + if (id.isEmpty() || id == "all") + forItemsAtLevel<1>([](const Thread &thread) { thread->notifyStopped(); }); + else if (Thread thread = threadForId(id)) + thread->notifyStopped(); } void ThreadsHandler::updateThreads(const GdbMi &data) @@ -453,13 +368,11 @@ void ThreadsHandler::updateThreads(const GdbMi &data) // file="/.../app.cpp",fullname="/../app.cpp",line="1175"}, // state="stopped",core="0"}],current-thread-id="1" - const QVector items = data["threads"].children(); - const int n = int(items.size()); - for (int index = 0; index != n; ++index) { - const GdbMi item = items[index]; - const GdbMi frame = item["frame"]; + const QVector &items = data["threads"].children(); + for (const GdbMi &item : items) { + const GdbMi &frame = item["frame"]; ThreadData thread; - thread.id = ThreadId(item["id"].toInt()); + thread.id = item["id"].data(); thread.targetId = item["target-id"].data(); thread.details = item["details"].data(); thread.core = item["core"].data(); @@ -474,10 +387,8 @@ void ThreadsHandler::updateThreads(const GdbMi &data) updateThread(thread); } - const GdbMi current = data["current-thread-id"]; - m_currentId = current.isValid() ? ThreadId(current.data().toLongLong()) : ThreadId(); - - updateThreadBox(); + const QString ¤tId = data["current-thread-id"].data(); + m_currentThread = threadForId(currentId); } void ThreadsHandler::scheduleResetLocation() diff --git a/src/plugins/debugger/threadshandler.h b/src/plugins/debugger/threadshandler.h index 8f0b662afea..d071d02fac1 100644 --- a/src/plugins/debugger/threadshandler.h +++ b/src/plugins/debugger/threadshandler.h @@ -29,6 +29,8 @@ #include +#include + //////////////////////////////////////////////////////////////////////// // // ThreadsHandler @@ -40,7 +42,33 @@ namespace Internal { class DebuggerEngine; class GdbMi; -class ThreadItem; +class ThreadsHandler; + +class ThreadItem : public QObject, public Utils::TreeItem +{ + Q_OBJECT + +public: + ThreadItem(const ThreadsHandler *handler, const ThreadData &data = ThreadData()); + + QVariant data(int column, int role) const override; + Qt::ItemFlags flags(int column) const override; + + QString threadToolTip() const; + QVariant threadPart(int column) const; + + void notifyRunning(); + void notifyStopped(); + + void mergeThreadData(const ThreadData &other); + QString id() const { return threadData.id; } + +public: + ThreadData threadData; + const ThreadsHandler * const handler; +}; + +using Thread = QPointer; class ThreadsHandler : public Utils::TreeModel, ThreadItem> { @@ -50,43 +78,34 @@ public: explicit ThreadsHandler(DebuggerEngine *engine); int currentThreadIndex() const; - ThreadId currentThread() const; - ThreadId threadAt(int index) const; - void setCurrentThread(ThreadId id); + Thread currentThread() const; + Thread threadAt(int index) const; + Thread threadForId(const QString &id) const; + void setCurrentThread(const Thread &thread); QString pidForGroupId(const QString &groupId) const; void updateThread(const ThreadData &threadData); void updateThreads(const GdbMi &data); - void removeThread(ThreadId threadId); - void setThreads(const Threads &threads); + void removeThread(const QString &id); void removeAll(); - ThreadData thread(ThreadId id) const; QAbstractItemModel *model(); void notifyGroupCreated(const QString &groupId, const QString &pid); bool notifyGroupExited(const QString &groupId); // Returns true when empty. - // Clear out all frame information - void notifyRunning(const QString &data); - void notifyRunning(ThreadId threadId); - void notifyAllRunning(); - - void notifyStopped(const QString &data); - void notifyStopped(ThreadId threadId); - void notifyAllStopped(); + void notifyRunning(const QString &id); + void notifyStopped(const QString &id); void resetLocation(); void scheduleResetLocation(); private: - void updateThreadBox(); - void sort(int column, Qt::SortOrder order) override; bool setData(const QModelIndex &idx, const QVariant &data, int role) override; DebuggerEngine *m_engine; - ThreadId m_currentId; + Thread m_currentThread; bool m_resetLocationScheduled = false; QHash m_pidForGroupId; };