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