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
23SettingsMenu::SettingsMenu()
24{
25}
26
27
28SettingsMenu::~SettingsMenu()
29{
30}
31
32
33// #pragma mark - SettingMenuItem
34
35
36SettingMenuItem::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
46SettingMenuItem::SettingMenuItem(Setting* setting, BMenu* menu,
47	BMessage* message)
48	:
49	BMenuItem(menu, message),
50	fSetting(setting)
51{
52	fSetting->AcquireReference();
53}
54
55
56SettingMenuItem::~SettingMenuItem()
57{
58	fSetting->ReleaseReference();
59}
60
61
62void
63SettingMenuItem::PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
64		Settings* settings)
65{
66}
67
68
69bool
70SettingMenuItem::Finish(BLooper* parentLooper, BHandler* targetHandler,
71	bool force)
72{
73	return false;
74}
75
76
77void
78SettingMenuItem::ItemSelected(Settings* settings)
79{
80}
81
82
83// #pragma mark - BoolMenuItem
84
85
86class SettingsMenuImpl::MenuItem : public SettingMenuItem {
87public:
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
96	MenuItem(Setting* setting, BMenu* menu, BMessage* message = NULL)
97		:
98		SettingMenuItem(setting, menu, message)
99	{
100	}
101
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
117class SettingsMenuImpl::BoolMenuItem : public MenuItem {
118public:
119	BoolMenuItem(BoolSetting* setting)
120		:
121		MenuItem(setting, setting->Name(), NULL)
122	{
123	}
124};
125
126
127// #pragma mark - OptionMenuItem
128
129
130class SettingsMenuImpl::OptionMenuItem : public BMenuItem {
131public:
132	OptionMenuItem(SettingsOption* option)
133		:
134		BMenuItem(option->Name(), NULL),
135		fOption(option)
136	{
137	}
138
139	SettingsOption* Option() const
140	{
141		return fOption;
142	}
143
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
158private:
159	SettingsOption*	fOption;
160};
161
162
163// #pragma mark - OptionsMenuItem
164
165
166class SettingsMenuImpl::OptionsMenuItem : public MenuItem {
167public:
168	OptionsMenuItem(OptionsSetting* setting, BMenu* menu)
169		:
170		MenuItem(setting, menu)
171	{
172	}
173
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
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
201SettingsMenuImpl::SettingsMenuImpl(Settings* settings)
202	:
203	fSettings(settings),
204	fMenu(NULL)
205{
206	fSettings->AcquireReference();
207}
208
209
210SettingsMenuImpl::~SettingsMenuImpl()
211{
212	RemoveFromMenu();
213	fSettings->ReleaseReference();
214}
215
216
217bool
218SettingsMenuImpl::AddItem(SettingMenuItem* item)
219{
220	return fMenuItems.AddItem(item);
221}
222
223
224bool
225SettingsMenuImpl::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
237bool
238SettingsMenuImpl::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
272status_t
273SettingsMenuImpl::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
294void
295SettingsMenuImpl::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
307void
308SettingsMenuImpl::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
317bool
318SettingsMenuImpl::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
331void
332SettingsMenuImpl::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
373SettingMenuItem*
374SettingsMenuImpl::_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