1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011-2016, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "BreakpointsView.h"
9
10#include <new>
11
12#include <Button.h>
13#include <CheckBox.h>
14#include <LayoutBuilder.h>
15
16#include <AutoLocker.h>
17#include <ObjectList.h>
18
19#include "AppMessageCodes.h"
20#include "MessageCodes.h"
21#include "Team.h"
22#include "UserBreakpoint.h"
23
24
25// #pragma mark - BreakpointsView
26
27
28BreakpointsView::BreakpointsView(Team* team, Listener* listener)
29	:
30	BGroupView(B_HORIZONTAL, 4.0f),
31	fTeam(team),
32	fListView(NULL),
33	fToggleBreakpointButton(NULL),
34	fEditBreakpointButton(NULL),
35	fRemoveBreakpointButton(NULL),
36	fListener(listener)
37{
38	SetName("Breakpoints");
39}
40
41
42BreakpointsView::~BreakpointsView()
43{
44	if (fListView != NULL)
45		fListView->UnsetListener();
46}
47
48
49/*static*/ BreakpointsView*
50BreakpointsView::Create(Team* team, Listener* listener)
51{
52	BreakpointsView* self = new BreakpointsView(team, listener);
53
54	try {
55		self->_Init();
56	} catch (...) {
57		delete self;
58		throw;
59	}
60
61	return self;
62}
63
64
65void
66BreakpointsView::UnsetListener()
67{
68	fListener = NULL;
69}
70
71
72void
73BreakpointsView::UserBreakpointChanged(UserBreakpoint* breakpoint)
74{
75	fListView->UserBreakpointChanged(breakpoint);
76
77	_UpdateButtons();
78}
79
80
81void
82BreakpointsView::WatchpointChanged(Watchpoint* watchpoint)
83{
84	fListView->WatchpointChanged(watchpoint);
85
86	_UpdateButtons();
87}
88
89
90void
91BreakpointsView::MessageReceived(BMessage* message)
92{
93	switch (message->what) {
94		case MSG_ENABLE_BREAKPOINT:
95		case MSG_DISABLE_BREAKPOINT:
96		case MSG_CLEAR_BREAKPOINT:
97			_HandleBreakpointAction(message->what);
98			break;
99
100		case MSG_SHOW_BREAKPOINT_EDIT_WINDOW:
101			message->AddPointer("breakpoint",
102				fSelectedBreakpoints.ItemAt(0)->GetBreakpoint());
103			Window()->PostMessage(message);
104			break;
105
106		default:
107			BGroupView::MessageReceived(message);
108			break;
109	}
110}
111
112
113void
114BreakpointsView::AttachedToWindow()
115{
116	fEditBreakpointButton->SetTarget(this);
117	fToggleBreakpointButton->SetTarget(this);
118	fRemoveBreakpointButton->SetTarget(this);
119}
120
121
122void
123BreakpointsView::LoadSettings(const BMessage& settings)
124{
125	BMessage breakpointListSettings;
126	if (settings.FindMessage("breakpointList", &breakpointListSettings)
127		== B_OK)
128		fListView->LoadSettings(breakpointListSettings);
129}
130
131
132status_t
133BreakpointsView::SaveSettings(BMessage& settings)
134{
135	BMessage breakpointListSettings;
136	if (fListView->SaveSettings(breakpointListSettings) != B_OK)
137		return B_NO_MEMORY;
138
139	if (settings.AddMessage("breakpointList", &breakpointListSettings) != B_OK)
140		return B_NO_MEMORY;
141
142	return B_OK;
143}
144
145
146void
147BreakpointsView::BreakpointSelectionChanged(BreakpointProxyList& proxies)
148{
149	if (fListener != NULL)
150		fListener->BreakpointSelectionChanged(proxies);
151
152	_SetSelection(proxies);
153}
154
155
156void
157BreakpointsView::_Init()
158{
159	BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
160		.Add(fListView = BreakpointListView::Create(fTeam, this, this))
161		.AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING)
162			.SetInsets(B_USE_SMALL_SPACING)
163			.AddGlue()
164			.Add(fRemoveBreakpointButton = new BButton("Remove"))
165			.Add(fEditBreakpointButton = new BButton("Edit" B_UTF8_ELLIPSIS))
166			.Add(fToggleBreakpointButton = new BButton("Toggle"))
167		.End();
168
169	fToggleBreakpointButton->SetMessage(new BMessage(MSG_ENABLE_BREAKPOINT));
170	fRemoveBreakpointButton->SetMessage(new BMessage(MSG_CLEAR_BREAKPOINT));
171	fEditBreakpointButton->SetMessage(
172		new BMessage(MSG_SHOW_BREAKPOINT_EDIT_WINDOW));
173
174	_UpdateButtons();
175}
176
177
178void
179BreakpointsView::_UpdateButtons()
180{
181	AutoLocker<Team> teamLocker(fTeam);
182
183	bool hasEnabled = false;
184	bool hasDisabled = false;
185	bool valid = false;
186
187	for (int32 i = 0; i < fSelectedBreakpoints.CountItems(); i++) {
188		BreakpointProxy* proxy = fSelectedBreakpoints.ItemAt(i);
189		switch (proxy->Type()) {
190			case BREAKPOINT_PROXY_TYPE_BREAKPOINT:
191			{
192				UserBreakpoint* breakpoint = proxy->GetBreakpoint();
193				if (breakpoint->IsValid()) {
194					valid = true;
195					if (breakpoint->IsEnabled())
196						hasEnabled = true;
197					else
198						hasDisabled = true;
199
200				}
201				break;
202			}
203			case BREAKPOINT_PROXY_TYPE_WATCHPOINT:
204			{
205				Watchpoint* watchpoint = proxy->GetWatchpoint();
206				valid = true;
207				if (watchpoint->IsEnabled())
208					hasEnabled = true;
209				else
210					hasDisabled = true;
211				break;
212			}
213			default:
214				break;
215		}
216	}
217
218	if (valid) {
219		// only allow condition editing if we have a single
220		// actual breakpoint selected.
221		// TODO: allow using this to modify watchpoints as
222		// well.
223		if (fSelectedBreakpoints.CountItems() == 1
224			&& fSelectedBreakpoints.ItemAt(0)->Type()
225				== BREAKPOINT_PROXY_TYPE_BREAKPOINT) {
226			fEditBreakpointButton->SetEnabled(true);
227		} else
228			fEditBreakpointButton->SetEnabled(false);
229
230		// if we have at least one disabled breakpoint in the
231		// selection, we leave the button as an Enable button
232		if (hasEnabled && !hasDisabled) {
233			fToggleBreakpointButton->SetLabel("Disable");
234			fToggleBreakpointButton->SetMessage(
235				new BMessage(MSG_DISABLE_BREAKPOINT));
236		} else {
237			fToggleBreakpointButton->SetLabel("Enable");
238			fToggleBreakpointButton->SetMessage(
239				new BMessage(MSG_ENABLE_BREAKPOINT));
240		}
241
242		fToggleBreakpointButton->SetEnabled(true);
243		fRemoveBreakpointButton->SetEnabled(true);
244	} else {
245		fToggleBreakpointButton->SetLabel("Enable");
246		fToggleBreakpointButton->SetEnabled(false);
247		fEditBreakpointButton->SetEnabled(false);
248		fRemoveBreakpointButton->SetEnabled(false);
249	}
250}
251
252
253void
254BreakpointsView::_SetSelection(BreakpointProxyList& proxies)
255{
256	for (int32 i = 0; i < fSelectedBreakpoints.CountItems(); i++)
257		fSelectedBreakpoints.ItemAt(i)->ReleaseReference();
258
259	fSelectedBreakpoints.MakeEmpty();
260
261	for (int32 i = 0; i < proxies.CountItems(); i++) {
262		BreakpointProxy* proxy = proxies.ItemAt(i);
263		if (!fSelectedBreakpoints.AddItem(proxy))
264			return;
265		proxy->AcquireReference();
266	}
267
268	_UpdateButtons();
269}
270
271
272void
273BreakpointsView::_HandleBreakpointAction(uint32 action)
274{
275	if (fListener == NULL)
276		return;
277
278	for (int32 i = 0; i < fSelectedBreakpoints.CountItems(); i++) {
279		BreakpointProxy* proxy = fSelectedBreakpoints.ItemAt(i);
280		if (proxy->Type() == BREAKPOINT_PROXY_TYPE_BREAKPOINT) {
281			UserBreakpoint* breakpoint = proxy->GetBreakpoint();
282			if (action == MSG_ENABLE_BREAKPOINT && !breakpoint->IsEnabled())
283				fListener->SetBreakpointEnabledRequested(breakpoint, true);
284			else if (action == MSG_DISABLE_BREAKPOINT
285				&& breakpoint->IsEnabled()) {
286				fListener->SetBreakpointEnabledRequested(breakpoint, false);
287			} else if (action == MSG_CLEAR_BREAKPOINT)
288				fListener->ClearBreakpointRequested(breakpoint);
289		} else {
290			Watchpoint* watchpoint = proxy->GetWatchpoint();
291			if (action == MSG_ENABLE_BREAKPOINT && !watchpoint->IsEnabled())
292				fListener->SetWatchpointEnabledRequested(watchpoint, true);
293			else if (action == MSG_DISABLE_BREAKPOINT
294				&& watchpoint->IsEnabled()) {
295				fListener->SetWatchpointEnabledRequested(watchpoint, false);
296			} else if (action == MSG_CLEAR_BREAKPOINT)
297				fListener->ClearWatchpointRequested(watchpoint);
298		}
299	}
300}
301
302
303// #pragma mark - Listener
304
305
306BreakpointsView::Listener::~Listener()
307{
308}
309