xref: /haiku/src/apps/debugger/user_interface/gui/GraphicalUserInterface.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
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