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 39enum { 40 MSG_TEAM_SELECTION_CHANGED = 'tesc', 41 MSG_CHOSE_CORE_FILE = 'chcf', 42 MSG_SWITCH_TARGET_CONNECTION = 'stco' 43}; 44 45 46TeamsWindow::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 66TeamsWindow::~TeamsWindow() 67{ 68} 69 70 71/*static*/ TeamsWindow* 72TeamsWindow::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 87void 88TeamsWindow::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 104void 105TeamsWindow::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 201bool 202TeamsWindow::QuitRequested() 203{ 204 _SaveSettings(); 205 206 be_app_messenger.SendMessage(MSG_TEAMS_WINDOW_CLOSED); 207 return true; 208} 209 210 211void 212TeamsWindow::AddListener(Listener* listener) 213{ 214 AutoLocker<TeamsWindow> locker(this); 215 fListeners.Add(listener); 216} 217 218 219void 220TeamsWindow::RemoveListener(Listener* listener) 221{ 222 AutoLocker<TeamsWindow> locker(this); 223 fListeners.Remove(listener); 224} 225 226 227// #pragma mark -- 228 229 230void 231TeamsWindow::_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 313status_t 314TeamsWindow::_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 326status_t 327TeamsWindow::_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 338status_t 339TeamsWindow::_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 360void 361TeamsWindow::_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 373TeamsWindow::Listener::~Listener() 374{ 375} 376