Debugger: Further work on memory leak hunting.
[haiku.git] / src / apps / debugger / user_interface / gui / team_window / ThreadListView.cpp
blob90b1f6b238a26d5f2901b3877db12178670691be
1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011-2017, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
8 #include "ThreadListView.h"
10 #include <new>
12 #include <Looper.h>
13 #include <Message.h>
15 #include <AutoLocker.h>
16 #include <ObjectList.h>
17 #include <ToolTip.h>
19 #include "GuiSettingsUtils.h"
20 #include "table/TableColumns.h"
21 #include "UiUtils.h"
24 enum {
25 MSG_SYNC_THREAD_LIST = 'sytl'
29 // #pragma mark - ThreadsTableModel
32 class ThreadListView::ThreadsTableModel : public TableModel,
33 public TableToolTipProvider {
34 public:
35 ThreadsTableModel(Team* team)
37 fTeam(team)
39 Update(-1);
42 ~ThreadsTableModel()
44 fTeam = NULL;
45 Update(-1);
48 bool Update(thread_id threadID)
50 if (fTeam == NULL) {
51 for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++)
52 thread->ReleaseReference();
53 fThreads.MakeEmpty();
55 return true;
58 AutoLocker<Team> locker(fTeam);
60 ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
61 Thread* newThread = it.Next();
62 int32 index = 0;
64 // remove no longer existing threads
65 while (Thread* oldThread = fThreads.ItemAt(index)) {
66 if (oldThread == newThread) {
67 if (threadID >= 0 && oldThread->ID() == threadID)
68 NotifyRowsChanged(index, 1);
69 index++;
70 newThread = it.Next();
71 } else {
72 // TODO: Not particularly efficient!
73 fThreads.RemoveItemAt(index);
74 oldThread->ReleaseReference();
75 NotifyRowsRemoved(index, 1);
79 // add new threads
80 int32 countBefore = fThreads.CountItems();
81 while (newThread != NULL) {
82 if (!fThreads.AddItem(newThread))
83 return false;
85 newThread->AcquireReference();
86 newThread = it.Next();
89 int32 count = fThreads.CountItems();
90 if (count > countBefore)
91 NotifyRowsAdded(countBefore, count - countBefore);
93 return true;
96 virtual int32 CountColumns() const
98 return 4;
101 virtual int32 CountRows() const
103 return fThreads.CountItems();
106 virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value)
108 Thread* thread = fThreads.ItemAt(rowIndex);
109 if (thread == NULL)
110 return false;
112 switch (columnIndex) {
113 case 0:
114 value.SetTo(thread->ID());
115 return true;
116 case 1:
118 const char* string = UiUtils::ThreadStateToString(
119 thread->State(), thread->StoppedReason());
120 value.SetTo(string, B_VARIANT_DONT_COPY_DATA);
121 return true;
123 case 2:
124 value.SetTo(thread->Name(), B_VARIANT_DONT_COPY_DATA);
125 return true;
126 case 3:
128 if (thread->State() != THREAD_STATE_RUNNING) {
129 value.SetTo(thread->StoppedReasonInfo(),
130 B_VARIANT_DONT_COPY_DATA);
131 return true;
133 return false;
135 default:
136 return false;
140 virtual bool GetToolTipForTableCell(int32 rowIndex, int32 columnIndex,
141 BToolTip** _tip)
143 Thread* thread = fThreads.ItemAt(rowIndex);
144 if (thread == NULL)
145 return false;
147 BString text;
148 text << "Thread: \"" << thread->Name() << "\" (" << thread->ID()
149 << ")\n";
151 switch (thread->State()) {
152 case THREAD_STATE_RUNNING:
153 text << "Running";
154 break;
155 case THREAD_STATE_STOPPED:
157 switch (thread->StoppedReason()) {
158 case THREAD_STOPPED_DEBUGGER_CALL:
159 text << "Called debugger(): "
160 << thread->StoppedReasonInfo();
161 break;
162 case THREAD_STOPPED_EXCEPTION:
163 text << "Caused exception: "
164 << thread->StoppedReasonInfo();
165 break;
166 case THREAD_STOPPED_BREAKPOINT:
167 case THREAD_STOPPED_WATCHPOINT:
168 case THREAD_STOPPED_SINGLE_STEP:
169 case THREAD_STOPPED_DEBUGGED:
170 case THREAD_STOPPED_UNKNOWN:
171 default:
172 text << "Stopped for debugging";
173 break;
175 break;
177 case THREAD_STATE_UNKNOWN:
178 default:
179 text << "Current State Unknown";
180 break;
183 BTextToolTip* tip = new(std::nothrow) BTextToolTip(text);
184 if (tip == NULL)
185 return false;
187 *_tip = tip;
188 return true;
191 Thread* ThreadAt(int32 index) const
193 return fThreads.ItemAt(index);
196 private:
197 Team* fTeam;
198 BObjectList<Thread> fThreads;
202 // #pragma mark - ThreadListView
205 ThreadListView::ThreadListView(Team* team, Listener* listener)
207 BGroupView(B_VERTICAL),
208 fTeam(team),
209 fThread(NULL),
210 fThreadsTable(NULL),
211 fThreadsTableModel(NULL),
212 fListener(listener)
214 SetName("Threads");
218 ThreadListView::~ThreadListView()
220 fTeam->RemoveListener(this);
221 fThreadsTable->SetTableModel(NULL);
222 delete fThreadsTableModel;
226 /*static*/ ThreadListView*
227 ThreadListView::Create(Team* team, Listener* listener)
229 ThreadListView* self = new ThreadListView(team, listener);
231 try {
232 self->_Init();
233 } catch (...) {
234 delete self;
235 throw;
238 return self;
242 void
243 ThreadListView::UnsetListener()
245 fListener = NULL;
249 void
250 ThreadListView::SetThread(Thread* thread)
252 if (thread == fThread)
253 return;
255 if (fThread != NULL)
256 fThread->ReleaseReference();
258 fThread = thread;
260 if (fThread != NULL) {
261 fThread->AcquireReference();
263 for (int32 i = 0; Thread* other = fThreadsTableModel->ThreadAt(i);
264 i++) {
265 if (fThread == other) {
266 fThreadsTable->SelectRow(i, false);
267 return;
272 fThreadsTable->DeselectAllRows();
276 void
277 ThreadListView::MessageReceived(BMessage* message)
279 switch (message->what) {
280 case MSG_SYNC_THREAD_LIST:
282 thread_id threadID;
283 if (message->FindInt32("thread", &threadID) != B_OK)
284 threadID = -1;
286 fThreadsTableModel->Update(threadID);
287 break;
289 default:
290 BGroupView::MessageReceived(message);
291 break;
296 void
297 ThreadListView::LoadSettings(const BMessage& settings)
299 BMessage tableSettings;
300 if (settings.FindMessage("threadsTable", &tableSettings) == B_OK) {
301 GuiSettingsUtils::UnarchiveTableSettings(tableSettings,
302 fThreadsTable);
307 status_t
308 ThreadListView::SaveSettings(BMessage& settings)
310 settings.MakeEmpty();
312 BMessage tableSettings;
313 status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings,
314 fThreadsTable);
315 if (result == B_OK)
316 result = settings.AddMessage("threadsTable", &tableSettings);
318 return result;
324 void
325 ThreadListView::ThreadAdded(const Team::ThreadEvent& event)
327 Looper()->PostMessage(MSG_SYNC_THREAD_LIST, this);
331 void
332 ThreadListView::ThreadRemoved(const Team::ThreadEvent& event)
334 Looper()->PostMessage(MSG_SYNC_THREAD_LIST, this);
338 void
339 ThreadListView::ThreadStateChanged(const Team::ThreadEvent& event)
341 BMessage message(MSG_SYNC_THREAD_LIST);
342 message.AddInt32("thread", event.GetThread()->ID());
344 Looper()->PostMessage(&message, this);
348 void
349 ThreadListView::TableSelectionChanged(Table* table)
351 if (fListener == NULL)
352 return;
354 Thread* thread = NULL;
355 TableSelectionModel* selectionModel = table->SelectionModel();
356 thread = fThreadsTableModel->ThreadAt(selectionModel->RowAt(0));
358 fListener->ThreadSelectionChanged(thread);
362 void
363 ThreadListView::_Init()
365 fThreadsTable = new Table("threads list", 0, B_FANCY_BORDER);
366 AddChild(fThreadsTable->ToView());
368 // columns
369 fThreadsTable->AddColumn(new Int32TableColumn(0, "ID", 60, 20, 1000,
370 B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT));
371 fThreadsTable->AddColumn(new StringTableColumn(1, "State", 80, 40, 1000,
372 B_TRUNCATE_END, B_ALIGN_LEFT));
373 fThreadsTable->AddColumn(new StringTableColumn(2, "Name", 200, 40, 1000,
374 B_TRUNCATE_END, B_ALIGN_LEFT));
375 fThreadsTable->AddColumn(new StringTableColumn(3, "Stop reason",
376 200, 40, 1000, B_TRUNCATE_END, B_ALIGN_LEFT));
378 fThreadsTable->SetSelectionMode(B_SINGLE_SELECTION_LIST);
379 fThreadsTable->AddTableListener(this);
381 fThreadsTableModel = new ThreadsTableModel(fTeam);
382 fThreadsTable->SetTableModel(fThreadsTableModel);
383 fThreadsTable->SetToolTipProvider(fThreadsTableModel);
384 fTeam->AddListener(this);
388 // #pragma mark - Listener
391 ThreadListView::Listener::~Listener()