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 26 class GraphicalUserInterface::FilePanelHandler : public BHandler { 27 public: 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 42 private: 43 entry_ref* fCurrentRef; 44 BLocker fPanelLock; 45 sem_id fPanelWaitSem; 46 }; 47 48 49 GraphicalUserInterface::FilePanelHandler::FilePanelHandler() 50 : 51 BHandler("GuiPanelHandler"), 52 fCurrentRef(NULL), 53 fPanelLock(), 54 fPanelWaitSem(-1) 55 { 56 } 57 58 59 GraphicalUserInterface::FilePanelHandler::~FilePanelHandler() 60 { 61 if (fPanelWaitSem >= 0) 62 delete_sem(fPanelWaitSem); 63 } 64 65 66 status_t 67 GraphicalUserInterface::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 78 void 79 GraphicalUserInterface::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 106 status_t 107 GraphicalUserInterface::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 118 void 119 GraphicalUserInterface::FilePanelHandler::SetCurrentRef(entry_ref* ref) 120 { 121 fCurrentRef = ref; 122 } 123 124 125 // #pragma mark - GraphicalUserInterface 126 127 128 GraphicalUserInterface::GraphicalUserInterface() 129 : 130 fTeamWindow(NULL), 131 fTeamWindowMessenger(NULL), 132 fFilePanelHandler(NULL), 133 fFilePanel(NULL), 134 fDefaultActions(10, true) 135 { 136 } 137 138 139 GraphicalUserInterface::~GraphicalUserInterface() 140 { 141 delete fTeamWindowMessenger; 142 delete fFilePanel; 143 delete fFilePanelHandler; 144 } 145 146 147 const char* 148 GraphicalUserInterface::ID() const 149 { 150 return "GraphicalUserInterface"; 151 } 152 153 154 status_t 155 GraphicalUserInterface::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 181 void 182 GraphicalUserInterface::Show() 183 { 184 if (fTeamWindow->IsHidden()) 185 fTeamWindow->Show(); 186 else 187 fTeamWindow->Activate(); 188 } 189 190 191 void 192 GraphicalUserInterface::Terminate() 193 { 194 // quit window 195 if (fTeamWindowMessenger && fTeamWindowMessenger->LockTarget()) 196 fTeamWindow->Quit(); 197 } 198 199 200 UserInterface* 201 GraphicalUserInterface::Clone() const 202 { 203 return new(std::nothrow) GraphicalUserInterface; 204 } 205 206 207 bool 208 GraphicalUserInterface::IsInteractive() const 209 { 210 return true; 211 } 212 213 214 status_t 215 GraphicalUserInterface::LoadSettings(const TeamUiSettings* settings) 216 { 217 status_t result = fTeamWindow->LoadSettings((GuiTeamUiSettings*)settings); 218 219 return result; 220 } 221 222 223 status_t 224 GraphicalUserInterface::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 236 void 237 GraphicalUserInterface::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 264 void 265 GraphicalUserInterface::NotifyBackgroundWorkStatus(const char* message) 266 { 267 fTeamWindow->DisplayBackgroundStatus(message); 268 } 269 270 271 int32 272 GraphicalUserInterface::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 308 status_t 309 GraphicalUserInterface::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