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