1/* 2Open Tracker License 3 4Terms and Conditions 5 6Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a copy of 9this software and associated documentation files (the "Software"), to deal in 10the Software without restriction, including without limitation the rights to 11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12of the Software, and to permit persons to whom the Software is furnished to do 13so, subject to the following conditions: 14 15The above copyright notice and this permission notice applies to all licensees 16and shall be included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN 23CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of Be Incorporated shall not be 26used in advertising or otherwise to promote the sale, use or other dealings in 27this Software without prior written authorization from Be Incorporated. 28 29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered 30trademarks of Be Incorporated in the United States and other countries. Other 31brand product names are registered trademarks or trademarks of their 32respective holders. All rights reserved. 33*/ 34 35 36#include "GroupedMenu.h" 37 38#include <stdlib.h> 39#include <string.h> 40 41 42using namespace BPrivate; 43 44 45TMenuItemGroup::TMenuItemGroup(const char* name) 46 : 47 fMenu(NULL), 48 fFirstItemIndex(-1), 49 fItemsTotal(0), 50 fHasSeparator(false) 51{ 52 if (name != NULL && name[0] != '\0') 53 fName = strdup(name); 54 else 55 fName = NULL; 56} 57 58 59TMenuItemGroup::~TMenuItemGroup() 60{ 61 free((char*)fName); 62 63 if (fMenu == NULL) { 64 BMenuItem* item; 65 while ((item = RemoveItem((int32)0)) != NULL) 66 delete item; 67 } 68} 69 70 71bool 72TMenuItemGroup::AddItem(BMenuItem* item) 73{ 74 if (!fList.AddItem(item)) 75 return false; 76 77 if (fMenu) 78 fMenu->AddGroupItem(this, item, fList.IndexOf(item)); 79 80 fItemsTotal++; 81 return true; 82} 83 84 85bool 86TMenuItemGroup::AddItem(BMenuItem* item, int32 atIndex) 87{ 88 if (!fList.AddItem(item, atIndex)) 89 return false; 90 91 if (fMenu) 92 fMenu->AddGroupItem(this, item, atIndex); 93 94 fItemsTotal++; 95 return true; 96} 97 98 99bool 100TMenuItemGroup::AddItem(BMenu* menu) 101{ 102 BMenuItem* item = new BMenuItem(menu); 103 if (item == NULL) 104 return false; 105 106 if (!AddItem(item)) { 107 delete item; 108 return false; 109 } 110 111 return true; 112} 113 114 115bool 116TMenuItemGroup::AddItem(BMenu* menu, int32 atIndex) 117{ 118 BMenuItem* item = new BMenuItem(menu); 119 if (item == NULL) 120 return false; 121 122 if (!AddItem(item, atIndex)) { 123 delete item; 124 return false; 125 } 126 127 return true; 128} 129 130 131bool 132TMenuItemGroup::RemoveItem(BMenuItem* item) 133{ 134 if (fMenu) 135 fMenu->RemoveGroupItem(this, item); 136 137 return fList.RemoveItem(item); 138} 139 140 141bool 142TMenuItemGroup::RemoveItem(BMenu* menu) 143{ 144 BMenuItem* item = menu->Superitem(); 145 if (item == NULL) 146 return false; 147 148 return RemoveItem(item); 149} 150 151 152BMenuItem* 153TMenuItemGroup::RemoveItem(int32 index) 154{ 155 BMenuItem* item = ItemAt(index); 156 if (item == NULL) 157 return NULL; 158 159 if (RemoveItem(item)) 160 return item; 161 162 return NULL; 163} 164 165 166BMenuItem* 167TMenuItemGroup::ItemAt(int32 index) 168{ 169 return static_cast<BMenuItem*>(fList.ItemAt(index)); 170} 171 172 173int32 174TMenuItemGroup::CountItems() 175{ 176 return fList.CountItems(); 177} 178 179 180void 181TMenuItemGroup::Separated(bool separated) 182{ 183 if (separated == fHasSeparator) 184 return; 185 186 fHasSeparator = separated; 187 188 if (separated) 189 fItemsTotal++; 190 else 191 fItemsTotal--; 192} 193 194 195bool 196TMenuItemGroup::HasSeparator() 197{ 198 return fHasSeparator; 199} 200 201 202// #pragma mark - 203 204 205TGroupedMenu::TGroupedMenu(const char* name) 206 : BMenu(name) 207{ 208} 209 210 211TGroupedMenu::~TGroupedMenu() 212{ 213 TMenuItemGroup* group; 214 while ((group = static_cast<TMenuItemGroup*>(fGroups.RemoveItem((int32)0))) 215 != NULL) { 216 delete group; 217 } 218} 219 220 221bool 222TGroupedMenu::AddGroup(TMenuItemGroup* group) 223{ 224 if (!fGroups.AddItem(group)) 225 return false; 226 227 group->fMenu = this; 228 229 for (int32 i = 0; i < group->CountItems(); i++) { 230 AddGroupItem(group, group->ItemAt(i), i); 231 } 232 233 return true; 234} 235 236 237bool 238TGroupedMenu::AddGroup(TMenuItemGroup* group, int32 atIndex) 239{ 240 if (!fGroups.AddItem(group, atIndex)) 241 return false; 242 243 group->fMenu = this; 244 245 for (int32 i = 0; i < group->CountItems(); i++) { 246 AddGroupItem(group, group->ItemAt(i), i); 247 } 248 249 return true; 250} 251 252 253bool 254TGroupedMenu::RemoveGroup(TMenuItemGroup* group) 255{ 256 if (group->HasSeparator()) { 257 delete RemoveItem(group->fFirstItemIndex); 258 group->Separated(false); 259 } 260 261 group->fMenu = NULL; 262 group->fFirstItemIndex = -1; 263 264 for (int32 i = 0; i < group->CountItems(); i++) { 265 RemoveItem(group->ItemAt(i)); 266 } 267 268 return fGroups.RemoveItem(group); 269} 270 271 272TMenuItemGroup* 273TGroupedMenu::GroupAt(int32 index) 274{ 275 return static_cast<TMenuItemGroup*>(fGroups.ItemAt(index)); 276} 277 278 279int32 280TGroupedMenu::CountGroups() 281{ 282 return fGroups.CountItems(); 283} 284 285 286void 287TGroupedMenu::AddGroupItem(TMenuItemGroup* group, BMenuItem* item, 288 int32 atIndex) 289{ 290 int32 groupIndex = fGroups.IndexOf(group); 291 bool addSeparator = false; 292 293 if (group->fFirstItemIndex == -1) { 294 // find new home for this group 295 if (groupIndex > 0) { 296 // add this group after an existing one 297 TMenuItemGroup* previous = GroupAt(groupIndex - 1); 298 group->fFirstItemIndex = previous->fFirstItemIndex 299 + previous->fItemsTotal; 300 addSeparator = true; 301 } else { 302 // this is the first group 303 TMenuItemGroup* successor = GroupAt(groupIndex + 1); 304 if (successor != NULL) { 305 group->fFirstItemIndex = successor->fFirstItemIndex; 306 if (successor->fHasSeparator) { 307 // we'll need one as well 308 addSeparator = true; 309 } 310 } else { 311 group->fFirstItemIndex = CountItems(); 312 if (group->fFirstItemIndex > 0) 313 addSeparator = true; 314 } 315 } 316 317 if (addSeparator) { 318 AddItem(new BSeparatorItem(), group->fFirstItemIndex); 319 group->Separated(true); 320 } 321 } 322 323 // insert item for real 324 325 AddItem(item, 326 atIndex + group->fFirstItemIndex + (group->HasSeparator() ? 1 : 0)); 327 328 // move the groups after this one 329 330 for (int32 i = groupIndex + 1; i < CountGroups(); i++) { 331 group = GroupAt(i); 332 group->fFirstItemIndex += addSeparator ? 2 : 1; 333 } 334} 335 336 337void 338TGroupedMenu::RemoveGroupItem(TMenuItemGroup* group, BMenuItem* item) 339{ 340 int32 groupIndex = fGroups.IndexOf(group); 341 bool removedSeparator = false; 342 343 if (group->CountItems() == 1) { 344 // this is the last item 345 if (group->HasSeparator()) { 346 RemoveItem(group->fFirstItemIndex); 347 group->Separated(false); 348 removedSeparator = true; 349 } 350 } 351 352 // insert item for real 353 354 RemoveItem(item); 355 356 // move the groups after this one 357 358 for (int32 i = groupIndex + 1; i < CountGroups(); i++) { 359 group = GroupAt(i); 360 group->fFirstItemIndex -= removedSeparator ? 2 : 1; 361 } 362} 363