1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "SettingsMenu.h"
8
9 #include <new>
10
11 #include <Looper.h>
12 #include <Menu.h>
13
14 #include <AutoDeleter.h>
15
16 #include "AppMessageCodes.h"
17 #include "SettingsDescription.h"
18
19
20 // #pragma mark - SettingsMenu
21
22
SettingsMenu()23 SettingsMenu::SettingsMenu()
24 {
25 }
26
27
~SettingsMenu()28 SettingsMenu::~SettingsMenu()
29 {
30 }
31
32
33 // #pragma mark - SettingMenuItem
34
35
SettingMenuItem(Setting * setting,const char * label,BMessage * message,char shortcut,uint32 modifiers)36 SettingMenuItem::SettingMenuItem(Setting* setting, const char* label,
37 BMessage* message, char shortcut, uint32 modifiers)
38 :
39 BMenuItem(label, message, shortcut, modifiers),
40 fSetting(setting)
41 {
42 fSetting->AcquireReference();
43 }
44
45
SettingMenuItem(Setting * setting,BMenu * menu,BMessage * message)46 SettingMenuItem::SettingMenuItem(Setting* setting, BMenu* menu,
47 BMessage* message)
48 :
49 BMenuItem(menu, message),
50 fSetting(setting)
51 {
52 fSetting->AcquireReference();
53 }
54
55
~SettingMenuItem()56 SettingMenuItem::~SettingMenuItem()
57 {
58 fSetting->ReleaseReference();
59 }
60
61
62 void
PrepareToShow(BLooper * parentLooper,BHandler * targetHandler,Settings * settings)63 SettingMenuItem::PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
64 Settings* settings)
65 {
66 }
67
68
69 bool
Finish(BLooper * parentLooper,BHandler * targetHandler,bool force)70 SettingMenuItem::Finish(BLooper* parentLooper, BHandler* targetHandler,
71 bool force)
72 {
73 return false;
74 }
75
76
77 void
ItemSelected(Settings * settings)78 SettingMenuItem::ItemSelected(Settings* settings)
79 {
80 }
81
82
83 // #pragma mark - BoolMenuItem
84
85
86 class SettingsMenuImpl::MenuItem : public SettingMenuItem {
87 public:
MenuItem(Setting * setting,const char * label,BMessage * message,char shortcut=0,uint32 modifiers=0)88 MenuItem(Setting* setting,
89 const char* label, BMessage* message,
90 char shortcut = 0, uint32 modifiers = 0)
91 :
92 SettingMenuItem(setting, label, message, shortcut, modifiers)
93 {
94 }
95
MenuItem(Setting * setting,BMenu * menu,BMessage * message=NULL)96 MenuItem(Setting* setting, BMenu* menu, BMessage* message = NULL)
97 :
98 SettingMenuItem(setting, menu, message)
99 {
100 }
101
PrepareToShow(BLooper * parentLooper,BHandler * targetHandler,Settings * settings)102 virtual void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
103 Settings* settings)
104 {
105 BMessage* message = new BMessage(
106 MSG_SETTINGS_MENU_IMPL_ITEM_SELECTED);
107 if (message == NULL)
108 return;
109 message->AddPointer("setting", fSetting);
110
111 SetMessage(message);
112 SetTarget(targetHandler);
113 }
114 };
115
116
117 class SettingsMenuImpl::BoolMenuItem : public MenuItem {
118 public:
BoolMenuItem(BoolSetting * setting)119 BoolMenuItem(BoolSetting* setting)
120 :
121 MenuItem(setting, setting->Name(), NULL)
122 {
123 }
124 };
125
126
127 // #pragma mark - OptionMenuItem
128
129
130 class SettingsMenuImpl::OptionMenuItem : public BMenuItem {
131 public:
OptionMenuItem(SettingsOption * option)132 OptionMenuItem(SettingsOption* option)
133 :
134 BMenuItem(option->Name(), NULL),
135 fOption(option)
136 {
137 }
138
Option() const139 SettingsOption* Option() const
140 {
141 return fOption;
142 }
143
PrepareToShow(BLooper * parentLooper,BHandler * targetHandler,Settings * settings,OptionsSetting * setting)144 void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
145 Settings* settings, OptionsSetting* setting)
146 {
147 BMessage* message = new BMessage(
148 MSG_SETTINGS_MENU_IMPL_OPTION_ITEM_SELECTED);
149 if (message == NULL)
150 return;
151 message->AddPointer("setting", static_cast<Setting*>(setting));
152 message->AddPointer("option", fOption);
153
154 SetMessage(message);
155 SetTarget(targetHandler);
156 }
157
158 private:
159 SettingsOption* fOption;
160 };
161
162
163 // #pragma mark - OptionsMenuItem
164
165
166 class SettingsMenuImpl::OptionsMenuItem : public MenuItem {
167 public:
OptionsMenuItem(OptionsSetting * setting,BMenu * menu)168 OptionsMenuItem(OptionsSetting* setting, BMenu* menu)
169 :
170 MenuItem(setting, menu)
171 {
172 }
173
PrepareToShow(BLooper * parentLooper,BHandler * targetHandler,Settings * settings)174 virtual void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
175 Settings* settings)
176 {
177 SettingsOption* selectedOption = settings->OptionValue(
178 dynamic_cast<OptionsSetting*>(GetSetting()));
179
180 for (int32 i = 0; BMenuItem* item = Submenu()->ItemAt(i); i++) {
181 OptionMenuItem* optionItem = dynamic_cast<OptionMenuItem*>(item);
182 if (optionItem != NULL)
183 optionItem->PrepareToShow(parentLooper, targetHandler,
184 settings, dynamic_cast<OptionsSetting*>(GetSetting()));
185
186 optionItem->SetMarked(optionItem->Option() == selectedOption);
187 }
188 }
189
OptionItemSelected(Settings * settings,SettingsOption * option)190 void OptionItemSelected(Settings* settings, SettingsOption* option)
191 {
192 settings->SetValue(fSetting,
193 BVariant(option->ID(), B_VARIANT_DONT_COPY_DATA));
194 }
195 };
196
197
198 // #pragma mark - SettingsMenuImpl
199
200
SettingsMenuImpl(Settings * settings)201 SettingsMenuImpl::SettingsMenuImpl(Settings* settings)
202 :
203 fSettings(settings),
204 fMenu(NULL)
205 {
206 fSettings->AcquireReference();
207 }
208
209
~SettingsMenuImpl()210 SettingsMenuImpl::~SettingsMenuImpl()
211 {
212 RemoveFromMenu();
213 fSettings->ReleaseReference();
214 }
215
216
217 bool
AddItem(SettingMenuItem * item)218 SettingsMenuImpl::AddItem(SettingMenuItem* item)
219 {
220 return fMenuItems.AddItem(item);
221 }
222
223
224 bool
AddBoolItem(BoolSetting * setting)225 SettingsMenuImpl::AddBoolItem(BoolSetting* setting)
226 {
227 SettingMenuItem* item = new(std::nothrow) BoolMenuItem(setting);
228 if (item == NULL || !AddItem(item)) {
229 delete item;
230 return false;
231 }
232
233 return true;
234 }
235
236
237 bool
AddOptionsItem(OptionsSetting * setting)238 SettingsMenuImpl::AddOptionsItem(OptionsSetting* setting)
239 {
240 // create the submenu
241 BMenu* menu = new(std::nothrow) BMenu(setting->Name());
242 if (menu == NULL)
243 return false;
244
245 // create the menu item
246 OptionsMenuItem* item = new(std::nothrow) OptionsMenuItem(setting, menu);
247 if (item == NULL) {
248 delete menu;
249 return false;
250 }
251 ObjectDeleter<OptionsMenuItem> itemDeleter(item);
252
253 // create sub menu items for the options
254 int32 count = setting->CountOptions();
255 for (int32 i = 0; i < count; i++) {
256 SettingsOption* option = setting->OptionAt(i);
257 BMenuItem* optionItem = new(std::nothrow) OptionMenuItem(option);
258 if (optionItem == NULL || !menu->AddItem(optionItem)) {
259 delete optionItem;
260 return false;
261 }
262 }
263
264 if (!AddItem(item))
265 return false;
266
267 itemDeleter.Detach();
268 return true;
269 }
270
271
272 status_t
AddToMenu(BMenu * menu,int32 index)273 SettingsMenuImpl::AddToMenu(BMenu* menu, int32 index)
274 {
275 if (fMenu != NULL)
276 return B_BAD_VALUE;
277
278 fMenu = menu;
279
280 for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++) {
281 if (!fMenu->AddItem(item, index + i)) {
282 for (i--; i >= 0; i--)
283 fMenu->RemoveItem(fMenuItems.ItemAt(i));
284
285 menu = NULL;
286 return B_NO_MEMORY;
287 }
288 }
289
290 return B_OK;
291 }
292
293
294 void
RemoveFromMenu()295 SettingsMenuImpl::RemoveFromMenu()
296 {
297 if (fMenu == NULL)
298 return;
299
300 for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
301 fMenu->RemoveItem(item);
302
303 fMenu = NULL;
304 }
305
306
307 void
PrepareToShow(BLooper * parentLooper)308 SettingsMenuImpl::PrepareToShow(BLooper* parentLooper)
309 {
310 parentLooper->AddHandler(this);
311
312 for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
313 item->PrepareToShow(parentLooper, this, fSettings);
314 }
315
316
317 bool
Finish(BLooper * parentLooper,bool force)318 SettingsMenuImpl::Finish(BLooper* parentLooper, bool force)
319 {
320 bool stillActive = false;
321
322 for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
323 stillActive |= item->Finish(parentLooper, this, force);
324
325 parentLooper->RemoveHandler(this);
326
327 return stillActive;
328 }
329
330
331 void
MessageReceived(BMessage * message)332 SettingsMenuImpl::MessageReceived(BMessage* message)
333 {
334 switch (message->what) {
335 case MSG_SETTINGS_MENU_IMPL_ITEM_SELECTED:
336 {
337 Setting* setting;
338 if (message->FindPointer("setting", (void**)&setting) != B_OK)
339 break;
340
341 if (SettingMenuItem* item = _FindMenuItem(setting))
342 item->ItemSelected(fSettings);
343
344 break;
345 }
346
347 case MSG_SETTINGS_MENU_IMPL_OPTION_ITEM_SELECTED:
348 {
349 Setting* setting;
350 SettingsOption* option;
351 if (message->FindPointer("setting", (void**)&setting) != B_OK
352 || message->FindPointer("option", (void**)&option) != B_OK) {
353 break;
354 }
355
356 // get the options setting item
357 OptionsMenuItem* optionsItem = dynamic_cast<OptionsMenuItem*>(
358 _FindMenuItem(setting));
359 if (optionsItem == NULL)
360 break;
361
362 optionsItem->OptionItemSelected(fSettings, option);
363 break;
364 }
365
366 default:
367 BHandler::MessageReceived(message);
368 break;
369 }
370 }
371
372
373 SettingMenuItem*
_FindMenuItem(Setting * setting) const374 SettingsMenuImpl::_FindMenuItem(Setting* setting) const
375 {
376 for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++) {
377 if (item->GetSetting() == setting)
378 return item;
379 }
380
381 return NULL;
382 }
383