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
Locker()39 BLocker& Locker()
40 { return fPanelLock; }
41
42 private:
43 entry_ref* fCurrentRef;
44 BLocker fPanelLock;
45 sem_id fPanelWaitSem;
46 };
47
48
FilePanelHandler()49 GraphicalUserInterface::FilePanelHandler::FilePanelHandler()
50 :
51 BHandler("GuiPanelHandler"),
52 fCurrentRef(NULL),
53 fPanelLock(),
54 fPanelWaitSem(-1)
55 {
56 }
57
58
~FilePanelHandler()59 GraphicalUserInterface::FilePanelHandler::~FilePanelHandler()
60 {
61 if (fPanelWaitSem >= 0)
62 delete_sem(fPanelWaitSem);
63 }
64
65
66 status_t
Init()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
MessageReceived(BMessage * message)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
WaitForPanel()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
SetCurrentRef(entry_ref * ref)119 GraphicalUserInterface::FilePanelHandler::SetCurrentRef(entry_ref* ref)
120 {
121 fCurrentRef = ref;
122 }
123
124
125 // #pragma mark - GraphicalUserInterface
126
127
GraphicalUserInterface()128 GraphicalUserInterface::GraphicalUserInterface()
129 :
130 fTeamWindow(NULL),
131 fTeamWindowMessenger(NULL),
132 fFilePanelHandler(NULL),
133 fFilePanel(NULL),
134 fDefaultActions(10, true)
135 {
136 }
137
138
~GraphicalUserInterface()139 GraphicalUserInterface::~GraphicalUserInterface()
140 {
141 delete fTeamWindowMessenger;
142 delete fFilePanel;
143 delete fFilePanelHandler;
144 }
145
146
147 const char*
ID() const148 GraphicalUserInterface::ID() const
149 {
150 return "GraphicalUserInterface";
151 }
152
153
154 status_t
Init(Team * team,UserInterfaceListener * listener)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
Show()182 GraphicalUserInterface::Show()
183 {
184 if (fTeamWindow->IsHidden())
185 fTeamWindow->Show();
186 else
187 fTeamWindow->Activate();
188 }
189
190
191 void
Terminate()192 GraphicalUserInterface::Terminate()
193 {
194 // quit window
195 if (fTeamWindowMessenger && fTeamWindowMessenger->LockTarget())
196 fTeamWindow->Quit();
197 }
198
199
200 UserInterface*
Clone() const201 GraphicalUserInterface::Clone() const
202 {
203 return new(std::nothrow) GraphicalUserInterface;
204 }
205
206
207 bool
IsInteractive() const208 GraphicalUserInterface::IsInteractive() const
209 {
210 return true;
211 }
212
213
214 status_t
LoadSettings(const TeamUiSettings * settings)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
SaveSettings(TeamUiSettings * & settings) const224 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
NotifyUser(const char * title,const char * message,user_notification_type type)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
NotifyBackgroundWorkStatus(const char * message)265 GraphicalUserInterface::NotifyBackgroundWorkStatus(const char* message)
266 {
267 fTeamWindow->DisplayBackgroundStatus(message);
268 }
269
270
271 int32
SynchronouslyAskUser(const char * title,const char * message,const char * choice1,const char * choice2,const char * choice3)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
SynchronouslyAskUserForFile(entry_ref * _ref)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