1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "BreakpointListView.h"
9
10#include <stdio.h>
11
12#include <new>
13
14#include <AutoLocker.h>
15#include <ObjectList.h>
16
17#include "FunctionID.h"
18#include "GuiSettingsUtils.h"
19#include "LocatableFile.h"
20#include "table/TableColumns.h"
21#include "TargetAddressTableColumn.h"
22#include "Team.h"
23#include "UserBreakpoint.h"
24#include "Watchpoint.h"
25
26
27// #pragma mark - BreakpointsTableModel
28
29
30class BreakpointListView::BreakpointsTableModel : public TableModel {
31public:
32	BreakpointsTableModel(Team* team)
33		:
34		fTeam(team)
35	{
36		UpdateBreakpoint(NULL);
37		UpdateWatchpoint(NULL);
38	}
39
40	~BreakpointsTableModel()
41	{
42		fTeam = NULL;
43		UpdateBreakpoint(NULL);
44		UpdateWatchpoint(NULL);
45	}
46
47	bool UpdateBreakpoint(UserBreakpoint* changedBreakpoint)
48	{
49		if (fTeam == NULL) {
50			for (int32 i = 0;
51				UserBreakpoint* breakpoint = fBreakpoints.ItemAt(i);
52				i++) {
53				breakpoint->ReleaseReference();
54			}
55			fBreakpoints.MakeEmpty();
56
57			return true;
58		}
59
60		AutoLocker<Team> locker(fTeam);
61
62		UserBreakpointList::ConstIterator it
63			= fTeam->UserBreakpoints().GetIterator();
64		UserBreakpoint* newBreakpoint = it.Next();
65		int32 index = 0;
66
67		// remove no longer existing breakpoints
68		while (UserBreakpoint* oldBreakpoint = fBreakpoints.ItemAt(index)) {
69			if (oldBreakpoint == newBreakpoint) {
70				if (oldBreakpoint == changedBreakpoint)
71					NotifyRowsChanged(index, 1);
72				index++;
73				newBreakpoint = it.Next();
74			} else {
75				// TODO: Not particularly efficient!
76				fBreakpoints.RemoveItemAt(index);
77				oldBreakpoint->ReleaseReference();
78				NotifyRowsRemoved(index, 1);
79			}
80		}
81
82		// add new breakpoints
83		int32 countBefore = fBreakpoints.CountItems();
84		while (newBreakpoint != NULL) {
85			if (!fBreakpoints.AddItem(newBreakpoint))
86				return false;
87
88			newBreakpoint->AcquireReference();
89			newBreakpoint = it.Next();
90		}
91
92		int32 count = fBreakpoints.CountItems();
93		if (count > countBefore)
94			NotifyRowsAdded(countBefore, count - countBefore);
95
96		return true;
97	}
98
99	bool UpdateWatchpoint(Watchpoint* changedWatchpoint)
100	{
101		if (fTeam == NULL) {
102			for (int32 i = 0;
103				Watchpoint* watchpoint = fWatchpoints.ItemAt(i);
104				i++) {
105				watchpoint->ReleaseReference();
106			}
107			fWatchpoints.MakeEmpty();
108
109			return true;
110		}
111
112		AutoLocker<Team> locker(fTeam);
113
114		int32 breakpointCount = fBreakpoints.CountItems();
115		int32 index = 0;
116		int32 teamIndex = 0;
117		Watchpoint* newWatchpoint = fTeam->WatchpointAt(teamIndex);
118		// remove no longer existing breakpoints
119		while (Watchpoint* oldWatchpoint = fWatchpoints.ItemAt(index)) {
120			if (oldWatchpoint == newWatchpoint) {
121				if (oldWatchpoint == changedWatchpoint)
122					NotifyRowsChanged(index + breakpointCount, 1);
123				index++;
124				teamIndex++;
125				newWatchpoint = fTeam->WatchpointAt(teamIndex);
126			} else {
127				// TODO: Not particularly efficient!
128				fWatchpoints.RemoveItemAt(index);
129				oldWatchpoint->ReleaseReference();
130				NotifyRowsRemoved(index + breakpointCount, 1);
131			}
132		}
133
134		// add new breakpoints
135		int32 countBefore = fWatchpoints.CountItems();
136		while (newWatchpoint != NULL) {
137			if (!fWatchpoints.AddItem(newWatchpoint))
138				return false;
139
140			newWatchpoint->AcquireReference();
141			teamIndex++;
142			newWatchpoint = fTeam->WatchpointAt(teamIndex);
143		}
144
145		int32 count = fWatchpoints.CountItems();
146		if (count > countBefore)
147			NotifyRowsAdded(countBefore + breakpointCount, count - countBefore);
148
149		return true;
150	}
151
152	virtual int32 CountColumns() const
153	{
154		return 5;
155	}
156
157	virtual int32 CountRows() const
158	{
159		return fBreakpoints.CountItems() + fWatchpoints.CountItems();
160	}
161
162	virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value)
163	{
164		int32 breakpointCount = fBreakpoints.CountItems();
165		if (rowIndex < breakpointCount)
166			return _GetBreakpointValueAt(rowIndex, columnIndex, value);
167
168		return _GetWatchpointValueAt(rowIndex - breakpointCount, columnIndex,
169			value);
170	}
171
172	UserBreakpoint* BreakpointAt(int32 index) const
173	{
174		return fBreakpoints.ItemAt(index);
175	}
176
177	Watchpoint* WatchpointAt(int32 index) const
178	{
179		return fWatchpoints.ItemAt(index - fBreakpoints.CountItems());
180	}
181
182private:
183
184	bool _GetBreakpointValueAt(int32 rowIndex, int32 columnIndex,
185		BVariant &value)
186	{
187		UserBreakpoint* breakpoint = fBreakpoints.ItemAt(rowIndex);
188		if (breakpoint == NULL)
189			return false;
190		const UserBreakpointLocation& location = breakpoint->Location();
191
192		switch (columnIndex) {
193			case 0:
194				value.SetTo((int32)breakpoint->IsEnabled());
195				return true;
196			case 1:
197				value.SetTo(location.GetFunctionID()->FunctionName(),
198					B_VARIANT_DONT_COPY_DATA);
199				return true;
200			case 2:
201				if (LocatableFile* sourceFile = location.SourceFile()) {
202					value.SetTo(sourceFile->Name(), B_VARIANT_DONT_COPY_DATA);
203					return true;
204				}
205				return false;
206			case 3:
207				if (location.SourceFile() != NULL) {
208					value.SetTo(location.GetSourceLocation().Line() + 1);
209					return true;
210				}
211				return false;
212			case 4:
213				if (location.SourceFile() == NULL) {
214					AutoLocker<Team> teamLocker(fTeam);
215					if (UserBreakpointInstance* instance
216							= breakpoint->InstanceAt(0)) {
217						value.SetTo(instance->Address());
218						return true;
219					}
220				}
221				return false;
222			default:
223				return false;
224		}
225	}
226
227	bool _GetWatchpointValueAt(int32 rowIndex, int32 columnIndex,
228		BVariant& value)
229	{
230		Watchpoint* watchpoint = fWatchpoints.ItemAt(rowIndex);
231		if (watchpoint == NULL)
232			return false;
233
234		switch (columnIndex) {
235			case 0:
236				value.SetTo((int32)watchpoint->IsEnabled());
237				return true;
238			case 1:
239				value.SetTo("Watchpoint");
240				return true;
241			case 2:
242				return false;
243			case 3:
244				return false;
245			case 4:
246				value.SetTo(watchpoint->Address());
247				return true;
248			default:
249				return false;
250		}
251	}
252
253private:
254	Team*						fTeam;
255	BObjectList<UserBreakpoint>	fBreakpoints;
256	BObjectList<Watchpoint>		fWatchpoints;
257};
258
259
260// #pragma mark - BreakpointListView
261
262
263BreakpointListView::BreakpointListView(Team* team, Listener* listener)
264	:
265	BGroupView(B_VERTICAL),
266	fTeam(team),
267	fBreakpoint(NULL),
268	fBreakpointsTable(NULL),
269	fBreakpointsTableModel(NULL),
270	fListener(listener)
271{
272}
273
274
275BreakpointListView::~BreakpointListView()
276{
277	fBreakpointsTable->SetTableModel(NULL);
278	delete fBreakpointsTableModel;
279}
280
281
282/*static*/ BreakpointListView*
283BreakpointListView::Create(Team* team, Listener* listener)
284{
285	BreakpointListView* self = new BreakpointListView(team, listener);
286
287	try {
288		self->_Init();
289	} catch (...) {
290		delete self;
291		throw;
292	}
293
294	return self;
295}
296
297
298void
299BreakpointListView::UnsetListener()
300{
301	fListener = NULL;
302}
303
304
305void
306BreakpointListView::SetBreakpoint(UserBreakpoint* breakpoint,
307	Watchpoint* watchpoint)
308{
309	if (breakpoint == fBreakpoint)
310		return;
311
312	if (fBreakpoint != NULL)
313		fBreakpoint->ReleaseReference();
314
315	fBreakpoint = breakpoint;
316
317	if (fBreakpoint != NULL) {
318		fBreakpoint->AcquireReference();
319
320		for (int32 i = 0;
321			UserBreakpoint* other = fBreakpointsTableModel->BreakpointAt(i);
322			i++) {
323			if (fBreakpoint == other) {
324				fBreakpointsTable->SelectRow(i, false);
325				return;
326			}
327		}
328	}
329
330	fBreakpointsTable->DeselectAllRows();
331}
332
333
334void
335BreakpointListView::UserBreakpointChanged(UserBreakpoint* breakpoint)
336{
337	fBreakpointsTableModel->UpdateBreakpoint(breakpoint);
338}
339
340
341void
342BreakpointListView::WatchpointChanged(Watchpoint* watchpoint)
343{
344	fBreakpointsTableModel->UpdateWatchpoint(watchpoint);
345}
346
347
348void
349BreakpointListView::LoadSettings(const BMessage& settings)
350{
351	BMessage tableSettings;
352	if (settings.FindMessage("breakpointsTable", &tableSettings) == B_OK) {
353		GuiSettingsUtils::UnarchiveTableSettings(tableSettings,
354			fBreakpointsTable);
355	}
356}
357
358
359status_t
360BreakpointListView::SaveSettings(BMessage& settings)
361{
362	settings.MakeEmpty();
363
364	BMessage tableSettings;
365	status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings,
366		fBreakpointsTable);
367	if (result == B_OK)
368		result = settings.AddMessage("breakpointsTable", &tableSettings);
369
370	return result;
371}
372
373
374void
375BreakpointListView::TableSelectionChanged(Table* table)
376{
377	if (fListener == NULL)
378		return;
379
380	TableSelectionModel* selectionModel = table->SelectionModel();
381	UserBreakpoint* breakpoint = fBreakpointsTableModel->BreakpointAt(
382		selectionModel->RowAt(0));
383	if (breakpoint != NULL)
384		fListener->BreakpointSelectionChanged(breakpoint);
385	else {
386		Watchpoint* watchpoint = fBreakpointsTableModel->WatchpointAt(
387			selectionModel->RowAt(0));
388		fListener->WatchpointSelectionChanged(watchpoint);
389	}
390}
391
392
393void
394BreakpointListView::_Init()
395{
396	fBreakpointsTable = new Table("breakpoints list", 0, B_FANCY_BORDER);
397	AddChild(fBreakpointsTable->ToView());
398
399	// columns
400	fBreakpointsTable->AddColumn(new BoolStringTableColumn(0, "State", 70, 20,
401		1000, "Enabled", "Disabled"));
402	fBreakpointsTable->AddColumn(new StringTableColumn(1, "Function", 250, 40,
403		1000, B_TRUNCATE_END, B_ALIGN_LEFT));
404	fBreakpointsTable->AddColumn(new StringTableColumn(2, "File", 250, 40,
405		1000, B_TRUNCATE_END, B_ALIGN_LEFT));
406	fBreakpointsTable->AddColumn(new Int32TableColumn(3, "Line", 60, 20,
407		1000, B_TRUNCATE_END, B_ALIGN_RIGHT));
408	fBreakpointsTable->AddColumn(new TargetAddressTableColumn(4, "Address", 100,
409		20, 1000, B_TRUNCATE_END, B_ALIGN_RIGHT));
410
411	fBreakpointsTable->SetSelectionMode(B_SINGLE_SELECTION_LIST);
412	fBreakpointsTable->AddTableListener(this);
413
414	fBreakpointsTableModel = new BreakpointsTableModel(fTeam);
415	fBreakpointsTable->SetTableModel(fBreakpointsTableModel);
416}
417
418
419// #pragma mark - Listener
420
421
422BreakpointListView::Listener::~Listener()
423{
424}
425