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 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 66 TeamsWindow::~TeamsWindow() 67 { 68 } 69 70 71 /*static*/ TeamsWindow* 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 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 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 202 TeamsWindow::QuitRequested() 203 { 204 _SaveSettings(); 205 206 be_app_messenger.SendMessage(MSG_TEAMS_WINDOW_CLOSED); 207 return true; 208 } 209 210 211 void 212 TeamsWindow::AddListener(Listener* listener) 213 { 214 AutoLocker<TeamsWindow> locker(this); 215 fListeners.Add(listener); 216 } 217 218 219 void 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 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 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 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 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 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 373 TeamsWindow::Listener::~Listener() 374 { 375 } 376