* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "SettingsMenu.h"
#include <new>
#include <Looper.h>
#include <Menu.h>
#include <AutoDeleter.h>
#include "AppMessageCodes.h"
#include "SettingsDescription.h"
SettingsMenu::SettingsMenu()
{
}
SettingsMenu::~SettingsMenu()
{
}
SettingMenuItem::SettingMenuItem(Setting* setting, const char* label,
BMessage* message, char shortcut, uint32 modifiers)
:
BMenuItem(label, message, shortcut, modifiers),
fSetting(setting)
{
fSetting->AcquireReference();
}
SettingMenuItem::SettingMenuItem(Setting* setting, BMenu* menu,
BMessage* message)
:
BMenuItem(menu, message),
fSetting(setting)
{
fSetting->AcquireReference();
}
SettingMenuItem::~SettingMenuItem()
{
fSetting->ReleaseReference();
}
void
SettingMenuItem::PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
Settings* settings)
{
}
bool
SettingMenuItem::Finish(BLooper* parentLooper, BHandler* targetHandler,
bool force)
{
return false;
}
void
SettingMenuItem::ItemSelected(Settings* settings)
{
}
class SettingsMenuImpl::MenuItem : public SettingMenuItem {
public:
MenuItem(Setting* setting,
const char* label, BMessage* message,
char shortcut = 0, uint32 modifiers = 0)
:
SettingMenuItem(setting, label, message, shortcut, modifiers)
{
}
MenuItem(Setting* setting, BMenu* menu, BMessage* message = NULL)
:
SettingMenuItem(setting, menu, message)
{
}
virtual void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
Settings* settings)
{
BMessage* message = new BMessage(
MSG_SETTINGS_MENU_IMPL_ITEM_SELECTED);
if (message == NULL)
return;
message->AddPointer("setting", fSetting);
SetMessage(message);
SetTarget(targetHandler);
}
};
class SettingsMenuImpl::BoolMenuItem : public MenuItem {
public:
BoolMenuItem(BoolSetting* setting)
:
MenuItem(setting, setting->Name(), NULL)
{
}
};
class SettingsMenuImpl::OptionMenuItem : public BMenuItem {
public:
OptionMenuItem(SettingsOption* option)
:
BMenuItem(option->Name(), NULL),
fOption(option)
{
}
SettingsOption* Option() const
{
return fOption;
}
void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
Settings* settings, OptionsSetting* setting)
{
BMessage* message = new BMessage(
MSG_SETTINGS_MENU_IMPL_OPTION_ITEM_SELECTED);
if (message == NULL)
return;
message->AddPointer("setting", static_cast<Setting*>(setting));
message->AddPointer("option", fOption);
SetMessage(message);
SetTarget(targetHandler);
}
private:
SettingsOption* fOption;
};
class SettingsMenuImpl::OptionsMenuItem : public MenuItem {
public:
OptionsMenuItem(OptionsSetting* setting, BMenu* menu)
:
MenuItem(setting, menu)
{
}
virtual void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
Settings* settings)
{
SettingsOption* selectedOption = settings->OptionValue(
dynamic_cast<OptionsSetting*>(GetSetting()));
for (int32 i = 0; BMenuItem* item = Submenu()->ItemAt(i); i++) {
OptionMenuItem* optionItem = dynamic_cast<OptionMenuItem*>(item);
if (optionItem != NULL)
optionItem->PrepareToShow(parentLooper, targetHandler,
settings, dynamic_cast<OptionsSetting*>(GetSetting()));
optionItem->SetMarked(optionItem->Option() == selectedOption);
}
}
void OptionItemSelected(Settings* settings, SettingsOption* option)
{
settings->SetValue(fSetting,
BVariant(option->ID(), B_VARIANT_DONT_COPY_DATA));
}
};
SettingsMenuImpl::SettingsMenuImpl(Settings* settings)
:
fSettings(settings),
fMenu(NULL)
{
fSettings->AcquireReference();
}
SettingsMenuImpl::~SettingsMenuImpl()
{
RemoveFromMenu();
fSettings->ReleaseReference();
}
bool
SettingsMenuImpl::AddItem(SettingMenuItem* item)
{
return fMenuItems.AddItem(item);
}
bool
SettingsMenuImpl::AddBoolItem(BoolSetting* setting)
{
SettingMenuItem* item = new(std::nothrow) BoolMenuItem(setting);
if (item == NULL || !AddItem(item)) {
delete item;
return false;
}
return true;
}
bool
SettingsMenuImpl::AddOptionsItem(OptionsSetting* setting)
{
BMenu* menu = new(std::nothrow) BMenu(setting->Name());
if (menu == NULL)
return false;
OptionsMenuItem* item = new(std::nothrow) OptionsMenuItem(setting, menu);
if (item == NULL) {
delete menu;
return false;
}
ObjectDeleter<OptionsMenuItem> itemDeleter(item);
int32 count = setting->CountOptions();
for (int32 i = 0; i < count; i++) {
SettingsOption* option = setting->OptionAt(i);
BMenuItem* optionItem = new(std::nothrow) OptionMenuItem(option);
if (optionItem == NULL || !menu->AddItem(optionItem)) {
delete optionItem;
return false;
}
}
if (!AddItem(item))
return false;
itemDeleter.Detach();
return true;
}
status_t
SettingsMenuImpl::AddToMenu(BMenu* menu, int32 index)
{
if (fMenu != NULL)
return B_BAD_VALUE;
fMenu = menu;
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++) {
if (!fMenu->AddItem(item, index + i)) {
for (i--; i >= 0; i--)
fMenu->RemoveItem(fMenuItems.ItemAt(i));
menu = NULL;
return B_NO_MEMORY;
}
}
return B_OK;
}
void
SettingsMenuImpl::RemoveFromMenu()
{
if (fMenu == NULL)
return;
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
fMenu->RemoveItem(item);
fMenu = NULL;
}
void
SettingsMenuImpl::PrepareToShow(BLooper* parentLooper)
{
parentLooper->AddHandler(this);
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
item->PrepareToShow(parentLooper, this, fSettings);
}
bool
SettingsMenuImpl::Finish(BLooper* parentLooper, bool force)
{
bool stillActive = false;
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
stillActive |= item->Finish(parentLooper, this, force);
parentLooper->RemoveHandler(this);
return stillActive;
}
void
SettingsMenuImpl::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_SETTINGS_MENU_IMPL_ITEM_SELECTED:
{
Setting* setting;
if (message->FindPointer("setting", (void**)&setting) != B_OK)
break;
if (SettingMenuItem* item = _FindMenuItem(setting))
item->ItemSelected(fSettings);
break;
}
case MSG_SETTINGS_MENU_IMPL_OPTION_ITEM_SELECTED:
{
Setting* setting;
SettingsOption* option;
if (message->FindPointer("setting", (void**)&setting) != B_OK
|| message->FindPointer("option", (void**)&option) != B_OK) {
break;
}
OptionsMenuItem* optionsItem = dynamic_cast<OptionsMenuItem*>(
_FindMenuItem(setting));
if (optionsItem == NULL)
break;
optionsItem->OptionItemSelected(fSettings, option);
break;
}
default:
BHandler::MessageReceived(message);
break;
}
}
SettingMenuItem*
SettingsMenuImpl::_FindMenuItem(Setting* setting) const
{
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++) {
if (item->GetSetting() == setting)
return item;
}
return NULL;
}