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 23 SettingsMenu::SettingsMenu() 24 { 25 } 26 27 28 SettingsMenu::~SettingsMenu() 29 { 30 } 31 32 33 // #pragma mark - SettingMenuItem 34 35 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 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 56 SettingMenuItem::~SettingMenuItem() 57 { 58 fSetting->ReleaseReference(); 59 } 60 61 62 void 63 SettingMenuItem::PrepareToShow(BLooper* parentLooper, BHandler* targetHandler, 64 Settings* settings) 65 { 66 } 67 68 69 bool 70 SettingMenuItem::Finish(BLooper* parentLooper, BHandler* targetHandler, 71 bool force) 72 { 73 return false; 74 } 75 76 77 void 78 SettingMenuItem::ItemSelected(Settings* settings) 79 { 80 } 81 82 83 // #pragma mark - BoolMenuItem 84 85 86 class SettingsMenuImpl::MenuItem : public SettingMenuItem { 87 public: 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 117 class SettingsMenuImpl::BoolMenuItem : public MenuItem { 118 public: 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: 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 158 private: 159 SettingsOption* fOption; 160 }; 161 162 163 // #pragma mark - OptionsMenuItem 164 165 166 class SettingsMenuImpl::OptionsMenuItem : public MenuItem { 167 public: 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 201 SettingsMenuImpl::SettingsMenuImpl(Settings* settings) 202 : 203 fSettings(settings), 204 fMenu(NULL) 205 { 206 fSettings->AcquireReference(); 207 } 208 209 210 SettingsMenuImpl::~SettingsMenuImpl() 211 { 212 RemoveFromMenu(); 213 fSettings->ReleaseReference(); 214 } 215 216 217 bool 218 SettingsMenuImpl::AddItem(SettingMenuItem* item) 219 { 220 return fMenuItems.AddItem(item); 221 } 222 223 224 bool 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 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 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 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 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 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 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* 374 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