xref: /haiku/src/apps/debugger/user_interface/gui/teams_window/TeamsWindow.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2009-2010, Philippe Houdoin, phoudoin@haiku-os.org. All rights reserved.
3  * Copyright 2013-2016, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 #include "TeamsWindow.h"
7 
8 
9 #include <new>
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdarg.h>
14 
15 #include <Application.h>
16 #include <Button.h>
17 #include <File.h>
18 #include <FilePanel.h>
19 #include <FindDirectory.h>
20 #include <LayoutBuilder.h>
21 #include <ListView.h>
22 #include <Menu.h>
23 #include <MenuField.h>
24 #include <Path.h>
25 #include <Screen.h>
26 #include <ScrollView.h>
27 
28 #include <AutoDeleter.h>
29 #include <AutoLocker.h>
30 
31 #include "AppMessageCodes.h"
32 #include "SettingsManager.h"
33 #include "TargetHostInterface.h"
34 #include "TargetHostInterfaceRoster.h"
35 #include "TeamsListView.h"
36 
37 
38 enum {
39 	MSG_TEAM_SELECTION_CHANGED = 'tesc',
40 	MSG_CHOSE_CORE_FILE = 'chcf',
41 	MSG_SWITCH_TARGET_CONNECTION = 'stco'
42 };
43 
44 
45 TeamsWindow::TeamsWindow(SettingsManager* settingsManager)
46 	:
47 	BWindow(BRect(100, 100, 500, 250), "Teams", B_DOCUMENT_WINDOW,
48 		B_ASYNCHRONOUS_CONTROLS),
49 	fTargetHostInterface(NULL),
50 	fTeamsListView(NULL),
51 	fAttachTeamButton(NULL),
52 	fCreateTeamButton(NULL),
53 	fLoadCoreButton(NULL),
54 	fConnectionField(NULL),
55 	fCoreSelectionPanel(NULL),
56 	fSettingsManager(settingsManager),
57 	fListeners()
58 {
59 	team_info info;
60 	get_team_info(B_CURRENT_TEAM, &info);
61 	fCurrentTeam = info.team;
62 }
63 
64 
65 TeamsWindow::~TeamsWindow()
66 {
67 }
68 
69 
70 /*static*/ TeamsWindow*
71 TeamsWindow::Create(SettingsManager* settingsManager)
72 {
73 	TeamsWindow* self = new TeamsWindow(settingsManager);
74 
75 	try {
76 		self->_Init();
77 	} catch (...) {
78 		delete self;
79 		throw;
80 	}
81 
82 	return self;
83 }
84 
85 
86 void
87 TeamsWindow::Zoom(BPoint, float, float)
88 {
89 	BSize preferredSize = fTeamsListView->PreferredSize();
90 	ResizeBy(preferredSize.Width() - Bounds().Width(),
91 		0.0);
92 
93 	// if the new size would extend us past the screen border,
94 	// move sufficiently to the left to bring us back within the bounds
95 	// + a bit of extra margin so we're not flush against the edge.
96 	BScreen screen;
97 	float offset = screen.Frame().right - Frame().right;
98 	if (offset < 0)
99 		MoveBy(offset - 5.0, 0.0);
100 }
101 
102 
103 void
104 TeamsWindow::MessageReceived(BMessage* message)
105 {
106 	switch (message->what) {
107 		case MSG_DEBUG_THIS_TEAM:
108 		{
109 			TeamRow* row = dynamic_cast<TeamRow*>(
110 				fTeamsListView->CurrentSelection());
111 			if (row != NULL) {
112 				BMessage message(MSG_DEBUG_THIS_TEAM);
113 				message.AddInt32("team", row->TeamID());
114 				message.AddPointer("interface", fTargetHostInterface);
115 				be_app_messenger.SendMessage(&message);
116 			}
117 			break;
118 		}
119 
120 		case MSG_TEAM_SELECTION_CHANGED:
121 		{
122 			TeamRow* row = dynamic_cast<TeamRow*>(
123 				fTeamsListView->CurrentSelection());
124 			bool enabled = false;
125 			if (row != NULL) {
126 				team_id id = row->TeamID();
127 				if (id != fCurrentTeam && id != B_SYSTEM_TEAM)
128 					enabled = true;
129 			}
130 
131 			fAttachTeamButton->SetEnabled(enabled);
132 			break;
133 		}
134 
135 		case MSG_SHOW_START_TEAM_WINDOW:
136 		{
137 			BMessage startMessage(*message);
138 			startMessage.AddPointer("interface", fTargetHostInterface);
139 			be_app_messenger.SendMessage(&startMessage);
140 			break;
141 		}
142 
143 		case MSG_CHOSE_CORE_FILE:
144 		case B_CANCEL:
145 		{
146 			delete fCoreSelectionPanel;
147 			fCoreSelectionPanel = NULL;
148 			if (message->what == B_CANCEL)
149 				break;
150 
151 			entry_ref ref;
152 			if (message->FindRef("refs", &ref) != B_OK)
153 				break;
154 
155 			BMessage coreMessage(MSG_LOAD_CORE_TEAM);
156 			coreMessage.AddPointer("interface", fTargetHostInterface);
157 			coreMessage.AddRef("core", &ref);
158 			be_app_messenger.SendMessage(&coreMessage);
159 			break;
160 		}
161 
162 		case MSG_LOAD_CORE_TEAM:
163 		{
164 			try {
165 				BMessenger messenger(this);
166 				fCoreSelectionPanel = new BFilePanel(B_OPEN_PANEL, &messenger,
167 					NULL, 0, false, new BMessage(MSG_CHOSE_CORE_FILE));
168 				fCoreSelectionPanel->Show();
169 			} catch (...) {
170 				delete fCoreSelectionPanel;
171 				fCoreSelectionPanel = NULL;
172 			}
173 			break;
174 		}
175 
176 		case MSG_SWITCH_TARGET_CONNECTION:
177 		{
178 			TargetHostInterface* interface;
179 			if (message->FindPointer("interface", reinterpret_cast<void**>(
180 					&interface)) != B_OK) {
181 				break;
182 			}
183 
184 			if (interface == fTargetHostInterface)
185 				break;
186 
187 			fTargetHostInterface = interface;
188 			_NotifySelectedInterfaceChanged(interface);
189 			fLoadCoreButton->SetEnabled(fTargetHostInterface->IsLocal());
190 			break;
191 		}
192 
193 		default:
194 			BWindow::MessageReceived(message);
195 			break;
196 	}
197 }
198 
199 
200 bool
201 TeamsWindow::QuitRequested()
202 {
203 	_SaveSettings();
204 
205 	be_app_messenger.SendMessage(MSG_TEAMS_WINDOW_CLOSED);
206 	return true;
207 }
208 
209 
210 void
211 TeamsWindow::AddListener(Listener* listener)
212 {
213 	AutoLocker<TeamsWindow> locker(this);
214 	fListeners.Add(listener);
215 }
216 
217 
218 void
219 TeamsWindow::RemoveListener(Listener* listener)
220 {
221 	AutoLocker<TeamsWindow> locker(this);
222 	fListeners.Remove(listener);
223 }
224 
225 
226 // #pragma mark --
227 
228 
229 void
230 TeamsWindow::_Init()
231 {
232 	BMessage settings;
233 	_LoadSettings(settings);
234 
235 	BRect frame;
236 	if (settings.FindRect("teams window frame", &frame) == B_OK) {
237 		MoveTo(frame.LeftTop());
238 		ResizeTo(frame.Width(), frame.Height());
239 	}
240 
241 	BMenu* connectionMenu = new BMenu("Connection");
242 	ObjectDeleter<BMenu> menuDeleter(connectionMenu);
243 	connectionMenu->SetLabelFromMarked(true);
244 
245 	TargetHostInterfaceRoster* roster = TargetHostInterfaceRoster::Default();
246 	for (int32 i = 0; i < roster->CountActiveInterfaces(); i++) {
247 		TargetHostInterface* interface = roster->ActiveInterfaceAt(i);
248 		BMenuItem* item = new BMenuItem(interface->GetTargetHost()->Name(),
249 			new BMessage(MSG_SWITCH_TARGET_CONNECTION));
250 		if (item->Message()->AddPointer("interface", interface) != B_OK) {
251 			delete item;
252 			throw std::bad_alloc();
253 		}
254 
255 		if (interface->IsLocal()) {
256 			item->SetMarked(true);
257 			fTargetHostInterface = interface;
258 		}
259 
260 		connectionMenu->AddItem(item);
261 	}
262 
263 	BGroupLayout* connectionLayout = NULL;
264 
265 	BLayoutBuilder::Group<>(this, B_VERTICAL)
266 		.AddGroup(B_HORIZONTAL)
267 			.SetInsets(B_USE_DEFAULT_SPACING)
268 			.GetLayout(&connectionLayout)
269 			.Add(fConnectionField = new BMenuField("Connected to:",
270 				connectionMenu))
271 			.AddGlue()
272 			.Add(fCreateConnectionButton = new BButton("Create new connection"
273 					B_UTF8_ELLIPSIS, new BMessage(
274 						MSG_SHOW_CONNECTION_CONFIG_WINDOW)))
275 		.End()
276 		.Add(fTeamsListView = new TeamsListView("TeamsList"))
277 		.SetInsets(1.0f, 1.0f, 1.0f, 5.0f)
278 		.AddGroup(B_HORIZONTAL)
279 			.SetInsets(B_USE_DEFAULT_SPACING)
280 			.Add(fAttachTeamButton = new BButton("Attach", new BMessage(
281 					MSG_DEBUG_THIS_TEAM)))
282 			.AddGlue()
283 			.Add(fCreateTeamButton = new BButton("Start new team"
284 					B_UTF8_ELLIPSIS, new BMessage(MSG_SHOW_START_TEAM_WINDOW)))
285 			.Add(fLoadCoreButton = new BButton("Load core" B_UTF8_ELLIPSIS,
286 					new BMessage(MSG_LOAD_CORE_TEAM)))
287 			.End()
288 		.End();
289 
290 	connectionLayout->SetVisible(false);
291 
292 	menuDeleter.Detach();
293 
294 	AddListener(fTeamsListView);
295 
296 	connectionMenu->SetTargetForItems(this);
297 
298 	fTeamsListView->SetInvocationMessage(new BMessage(MSG_DEBUG_THIS_TEAM));
299 	fTeamsListView->SetSelectionMessage(new BMessage(
300 			MSG_TEAM_SELECTION_CHANGED));
301 
302 	fAttachTeamButton->SetEnabled(false);
303 	fCreateTeamButton->SetTarget(this);
304 	fLoadCoreButton->SetTarget(this);
305 	fCreateConnectionButton->SetTarget(be_app);
306 
307 	_NotifySelectedInterfaceChanged(fTargetHostInterface);
308 }
309 
310 
311 status_t
312 TeamsWindow::_OpenSettings(BFile& file, uint32 mode)
313 {
314 	BPath path;
315 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
316 		return B_ERROR;
317 
318 	path.Append("Debugger settings");
319 
320 	return file.SetTo(path.Path(), mode);
321 }
322 
323 
324 status_t
325 TeamsWindow::_LoadSettings(BMessage& settings)
326 {
327 	BFile file;
328 	status_t status = _OpenSettings(file, B_READ_ONLY);
329 	if (status < B_OK)
330 		return status;
331 
332 	return settings.Unflatten(&file);
333 }
334 
335 
336 status_t
337 TeamsWindow::_SaveSettings()
338 {
339 	BFile file;
340 	status_t status = _OpenSettings(file,
341 		B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
342 
343 	if (status < B_OK)
344 		return status;
345 
346 	BMessage settings('hdbg');
347 	status = settings.AddRect("teams window frame", Frame());
348 	if (status != B_OK)
349 		return status;
350 
351 	if (status == B_OK)
352 		status = settings.Flatten(&file);
353 
354 	return status;
355 }
356 
357 
358 void
359 TeamsWindow::_NotifySelectedInterfaceChanged(TargetHostInterface* interface)
360 {
361 	for (ListenerList::Iterator it = fListeners.GetIterator();
362 			Listener* listener = it.Next();) {
363 		listener->SelectedInterfaceChanged(interface);
364 	}
365 }
366 
367 
368 // #pragma mark - TeamsWindow::Listener
369 
370 
371 TeamsWindow::Listener::~Listener()
372 {
373 }
374