/* * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2011-2016, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #include "GraphicalUserInterface.h" #include #include #include #include #include #include "AlertWithCheckbox.h" #include "GuiTeamUiSettings.h" #include "MessageCodes.h" #include "TeamWindow.h" #include "Tracing.h" // #pragma mark - GraphicalUserInterface::FilePanelHandler class GraphicalUserInterface::FilePanelHandler : public BHandler { public: FilePanelHandler(); virtual ~FilePanelHandler(); status_t Init(); virtual void MessageReceived(BMessage* message); status_t WaitForPanel(); void SetCurrentRef(entry_ref* ref); BLocker& Locker() { return fPanelLock; } private: entry_ref* fCurrentRef; BLocker fPanelLock; sem_id fPanelWaitSem; }; GraphicalUserInterface::FilePanelHandler::FilePanelHandler() : BHandler("GuiPanelHandler"), fCurrentRef(NULL), fPanelLock(), fPanelWaitSem(-1) { } GraphicalUserInterface::FilePanelHandler::~FilePanelHandler() { if (fPanelWaitSem >= 0) delete_sem(fPanelWaitSem); } status_t GraphicalUserInterface::FilePanelHandler::Init() { fPanelWaitSem = create_sem(0, "FilePanelWaitSem"); if (fPanelWaitSem < 0) return fPanelWaitSem; return B_OK; } void GraphicalUserInterface::FilePanelHandler::MessageReceived(BMessage* message) { switch (message->what) { case MSG_USER_INTERFACE_FILE_CHOSEN: { entry_ref ref; if (message->FindRef("refs", &ref) == B_OK && fCurrentRef != NULL) { *fCurrentRef = ref; fCurrentRef = NULL; } // fall through } case B_CANCEL: { release_sem(fPanelWaitSem); break; } default: BHandler::MessageReceived(message); break; } } status_t GraphicalUserInterface::FilePanelHandler::WaitForPanel() { status_t result = B_OK; do { result = acquire_sem(fPanelWaitSem); } while (result == B_INTERRUPTED); return result; } void GraphicalUserInterface::FilePanelHandler::SetCurrentRef(entry_ref* ref) { fCurrentRef = ref; } // #pragma mark - GraphicalUserInterface GraphicalUserInterface::GraphicalUserInterface() : fTeamWindow(NULL), fTeamWindowMessenger(NULL), fFilePanelHandler(NULL), fFilePanel(NULL), fDefaultActions(10, true) { } GraphicalUserInterface::~GraphicalUserInterface() { delete fTeamWindowMessenger; delete fFilePanel; delete fFilePanelHandler; } const char* GraphicalUserInterface::ID() const { return "GraphicalUserInterface"; } status_t GraphicalUserInterface::Init(Team* team, UserInterfaceListener* listener) { try { fTeamWindow = TeamWindow::Create(team, listener); fTeamWindowMessenger = new BMessenger(fTeamWindow); fFilePanelHandler = new FilePanelHandler(); status_t error = fFilePanelHandler->Init(); if (error != B_OK) { ERROR("Error: Failed to create file panel semaphore!\n"); return error; } fTeamWindow->AddHandler(fFilePanelHandler); // start the message loop fTeamWindow->Hide(); fTeamWindow->Show(); } catch (...) { // TODO: Notify the user! ERROR("Error: Failed to create team window!\n"); return B_NO_MEMORY; } return B_OK; } void GraphicalUserInterface::Show() { if (fTeamWindow->IsHidden()) fTeamWindow->Show(); else fTeamWindow->Activate(); } void GraphicalUserInterface::Terminate() { // quit window if (fTeamWindowMessenger && fTeamWindowMessenger->LockTarget()) fTeamWindow->Quit(); } UserInterface* GraphicalUserInterface::Clone() const { return new(std::nothrow) GraphicalUserInterface; } bool GraphicalUserInterface::IsInteractive() const { return true; } status_t GraphicalUserInterface::LoadSettings(const TeamUiSettings* settings) { status_t result = fTeamWindow->LoadSettings((GuiTeamUiSettings*)settings); return result; } status_t GraphicalUserInterface::SaveSettings(TeamUiSettings*& settings) const { settings = new(std::nothrow) GuiTeamUiSettings(ID()); if (settings == NULL) return B_NO_MEMORY; fTeamWindow->SaveSettings((GuiTeamUiSettings*)settings); return B_OK; } void GraphicalUserInterface::NotifyUser(const char* title, const char* message, user_notification_type type) { // convert notification type to alert type alert_type alertType; switch (type) { case USER_NOTIFICATION_INFO: alertType = B_INFO_ALERT; break; case USER_NOTIFICATION_WARNING: case USER_NOTIFICATION_ERROR: default: alertType = B_WARNING_ALERT; break; } BAlert* alert = new(std::nothrow) BAlert(title, message, "OK", NULL, NULL, B_WIDTH_AS_USUAL, alertType); if (alert != NULL) alert->Go(NULL); // TODO: We need to let the alert run asynchronously, but we shouldn't just // create it and don't care anymore. Maybe an error window, which can // display a list of errors would be the better choice. } void GraphicalUserInterface::NotifyBackgroundWorkStatus(const char* message) { fTeamWindow->DisplayBackgroundStatus(message); } int32 GraphicalUserInterface::SynchronouslyAskUser(const char* title, const char* message, const char* choice1, const char* choice2, const char* choice3) { // If the user already answered the question and asked for their choice to be remembered, // return the previously made choice again BString key(title); key += choice1; key += choice2; key += choice3; for (int i = 0; i < fDefaultActions.CountItems(); i++) { if (fDefaultActions.ItemAt(i)->fKey == key) return fDefaultActions.ItemAt(i)->fDecision; } AlertWithCheckbox* alert = new(std::nothrow) AlertWithCheckbox(title, message, "Don't ask again", choice1, choice2, choice3); if (alert == NULL) return 0; bool dontAskAgain = false; int result = alert->Go(dontAskAgain); if (dontAskAgain) { DefaultAction* defaultAction = new DefaultAction; defaultAction->fKey = key; defaultAction->fDecision = result; fDefaultActions.AddItem(defaultAction); } return result; } status_t GraphicalUserInterface::SynchronouslyAskUserForFile(entry_ref* _ref) { BAutolock lock(&fFilePanelHandler->Locker()); if (fFilePanel == NULL) { BMessenger messenger(fFilePanelHandler); BMessage* message = new(std::nothrow) BMessage( MSG_USER_INTERFACE_FILE_CHOSEN); if (message == NULL) return B_NO_MEMORY; ObjectDeleter messageDeleter(message); fFilePanel = new(std::nothrow) BFilePanel(B_OPEN_PANEL, &messenger, NULL, B_FILE_NODE, false, message); if (fFilePanel == NULL) return B_NO_MEMORY; messageDeleter.Detach(); } fFilePanelHandler->SetCurrentRef(_ref); fFilePanel->Show(); return fFilePanelHandler->WaitForPanel(); }