1/* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2011-2016, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8#include "GraphicalUserInterface.h" 9 10#include <Alert.h> 11#include <AutoDeleter.h> 12#include <Autolock.h> 13#include <FilePanel.h> 14#include <Locker.h> 15 16#include "AlertWithCheckbox.h" 17#include "GuiTeamUiSettings.h" 18#include "MessageCodes.h" 19#include "TeamWindow.h" 20#include "Tracing.h" 21 22 23// #pragma mark - GraphicalUserInterface::FilePanelHandler 24 25 26class GraphicalUserInterface::FilePanelHandler : public BHandler { 27public: 28 FilePanelHandler(); 29 virtual ~FilePanelHandler(); 30 31 status_t Init(); 32 33 virtual void MessageReceived(BMessage* message); 34 35 status_t WaitForPanel(); 36 37 void SetCurrentRef(entry_ref* ref); 38 39 BLocker& Locker() 40 { return fPanelLock; } 41 42private: 43 entry_ref* fCurrentRef; 44 BLocker fPanelLock; 45 sem_id fPanelWaitSem; 46}; 47 48 49GraphicalUserInterface::FilePanelHandler::FilePanelHandler() 50 : 51 BHandler("GuiPanelHandler"), 52 fCurrentRef(NULL), 53 fPanelLock(), 54 fPanelWaitSem(-1) 55{ 56} 57 58 59GraphicalUserInterface::FilePanelHandler::~FilePanelHandler() 60{ 61 if (fPanelWaitSem >= 0) 62 delete_sem(fPanelWaitSem); 63} 64 65 66status_t 67GraphicalUserInterface::FilePanelHandler::Init() 68{ 69 fPanelWaitSem = create_sem(0, "FilePanelWaitSem"); 70 71 if (fPanelWaitSem < 0) 72 return fPanelWaitSem; 73 74 return B_OK; 75} 76 77 78void 79GraphicalUserInterface::FilePanelHandler::MessageReceived(BMessage* message) 80{ 81 switch (message->what) { 82 case MSG_USER_INTERFACE_FILE_CHOSEN: 83 { 84 entry_ref ref; 85 if (message->FindRef("refs", &ref) == B_OK 86 && fCurrentRef != NULL) { 87 *fCurrentRef = ref; 88 fCurrentRef = NULL; 89 } 90 // fall through 91 } 92 93 case B_CANCEL: 94 { 95 release_sem(fPanelWaitSem); 96 break; 97 } 98 99 default: 100 BHandler::MessageReceived(message); 101 break; 102 } 103} 104 105 106status_t 107GraphicalUserInterface::FilePanelHandler::WaitForPanel() 108{ 109 status_t result = B_OK; 110 do { 111 result = acquire_sem(fPanelWaitSem); 112 } while (result == B_INTERRUPTED); 113 114 return result; 115} 116 117 118void 119GraphicalUserInterface::FilePanelHandler::SetCurrentRef(entry_ref* ref) 120{ 121 fCurrentRef = ref; 122} 123 124 125// #pragma mark - GraphicalUserInterface 126 127 128GraphicalUserInterface::GraphicalUserInterface() 129 : 130 fTeamWindow(NULL), 131 fTeamWindowMessenger(NULL), 132 fFilePanelHandler(NULL), 133 fFilePanel(NULL), 134 fDefaultActions(10, true) 135{ 136} 137 138 139GraphicalUserInterface::~GraphicalUserInterface() 140{ 141 delete fTeamWindowMessenger; 142 delete fFilePanel; 143 delete fFilePanelHandler; 144} 145 146 147const char* 148GraphicalUserInterface::ID() const 149{ 150 return "GraphicalUserInterface"; 151} 152 153 154status_t 155GraphicalUserInterface::Init(Team* team, UserInterfaceListener* listener) 156{ 157 try { 158 fTeamWindow = TeamWindow::Create(team, listener); 159 fTeamWindowMessenger = new BMessenger(fTeamWindow); 160 fFilePanelHandler = new FilePanelHandler(); 161 status_t error = fFilePanelHandler->Init(); 162 if (error != B_OK) { 163 ERROR("Error: Failed to create file panel semaphore!\n"); 164 return error; 165 } 166 fTeamWindow->AddHandler(fFilePanelHandler); 167 168 // start the message loop 169 fTeamWindow->Hide(); 170 fTeamWindow->Show(); 171 } catch (...) { 172 // TODO: Notify the user! 173 ERROR("Error: Failed to create team window!\n"); 174 return B_NO_MEMORY; 175 } 176 177 return B_OK; 178} 179 180 181void 182GraphicalUserInterface::Show() 183{ 184 if (fTeamWindow->IsHidden()) 185 fTeamWindow->Show(); 186 else 187 fTeamWindow->Activate(); 188} 189 190 191void 192GraphicalUserInterface::Terminate() 193{ 194 // quit window 195 if (fTeamWindowMessenger && fTeamWindowMessenger->LockTarget()) 196 fTeamWindow->Quit(); 197} 198 199 200UserInterface* 201GraphicalUserInterface::Clone() const 202{ 203 return new(std::nothrow) GraphicalUserInterface; 204} 205 206 207bool 208GraphicalUserInterface::IsInteractive() const 209{ 210 return true; 211} 212 213 214status_t 215GraphicalUserInterface::LoadSettings(const TeamUiSettings* settings) 216{ 217 status_t result = fTeamWindow->LoadSettings((GuiTeamUiSettings*)settings); 218 219 return result; 220} 221 222 223status_t 224GraphicalUserInterface::SaveSettings(TeamUiSettings*& settings) const 225{ 226 settings = new(std::nothrow) GuiTeamUiSettings(ID()); 227 if (settings == NULL) 228 return B_NO_MEMORY; 229 230 fTeamWindow->SaveSettings((GuiTeamUiSettings*)settings); 231 232 return B_OK; 233} 234 235 236void 237GraphicalUserInterface::NotifyUser(const char* title, const char* message, 238 user_notification_type type) 239{ 240 // convert notification type to alert type 241 alert_type alertType; 242 switch (type) { 243 case USER_NOTIFICATION_INFO: 244 alertType = B_INFO_ALERT; 245 break; 246 case USER_NOTIFICATION_WARNING: 247 case USER_NOTIFICATION_ERROR: 248 default: 249 alertType = B_WARNING_ALERT; 250 break; 251 } 252 253 BAlert* alert = new(std::nothrow) BAlert(title, message, "OK", 254 NULL, NULL, B_WIDTH_AS_USUAL, alertType); 255 if (alert != NULL) 256 alert->Go(NULL); 257 258 // TODO: We need to let the alert run asynchronously, but we shouldn't just 259 // create it and don't care anymore. Maybe an error window, which can 260 // display a list of errors would be the better choice. 261} 262 263 264void 265GraphicalUserInterface::NotifyBackgroundWorkStatus(const char* message) 266{ 267 fTeamWindow->DisplayBackgroundStatus(message); 268} 269 270 271int32 272GraphicalUserInterface::SynchronouslyAskUser(const char* title, 273 const char* message, const char* choice1, const char* choice2, 274 const char* choice3) 275{ 276 // If the user already answered the question and asked for their choice to be remembered, 277 // return the previously made choice again 278 BString key(title); 279 key += choice1; 280 key += choice2; 281 key += choice3; 282 283 for (int i = 0; i < fDefaultActions.CountItems(); i++) { 284 if (fDefaultActions.ItemAt(i)->fKey == key) 285 return fDefaultActions.ItemAt(i)->fDecision; 286 } 287 288 AlertWithCheckbox* alert = new(std::nothrow) AlertWithCheckbox(title, message, 289 "Don't ask again", choice1, choice2, choice3); 290 291 if (alert == NULL) 292 return 0; 293 294 bool dontAskAgain = false; 295 int result = alert->Go(dontAskAgain); 296 297 if (dontAskAgain) { 298 DefaultAction* defaultAction = new DefaultAction; 299 defaultAction->fKey = key; 300 defaultAction->fDecision = result; 301 fDefaultActions.AddItem(defaultAction); 302 } 303 304 return result; 305} 306 307 308status_t 309GraphicalUserInterface::SynchronouslyAskUserForFile(entry_ref* _ref) 310{ 311 BAutolock lock(&fFilePanelHandler->Locker()); 312 313 if (fFilePanel == NULL) { 314 BMessenger messenger(fFilePanelHandler); 315 BMessage* message = new(std::nothrow) BMessage( 316 MSG_USER_INTERFACE_FILE_CHOSEN); 317 if (message == NULL) 318 return B_NO_MEMORY; 319 ObjectDeleter<BMessage> messageDeleter(message); 320 fFilePanel = new(std::nothrow) BFilePanel(B_OPEN_PANEL, 321 &messenger, NULL, B_FILE_NODE, false, message); 322 if (fFilePanel == NULL) 323 return B_NO_MEMORY; 324 messageDeleter.Detach(); 325 } 326 327 fFilePanelHandler->SetCurrentRef(_ref); 328 fFilePanel->Show(); 329 return fFilePanelHandler->WaitForPanel(); 330} 331