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