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