1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN 23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered 30 trademarks of Be Incorporated in the United States and other countries. Other 31 brand product names are registered trademarks or trademarks of their 32 respective holders. All rights reserved. 33 */ 34 35 36 #include "GroupedMenu.h" 37 38 #include <stdlib.h> 39 #include <string.h> 40 41 42 using namespace BPrivate; 43 44 45 TMenuItemGroup::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 59 TMenuItemGroup::~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 71 bool 72 TMenuItemGroup::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 85 bool 86 TMenuItemGroup::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 99 bool 100 TMenuItemGroup::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 115 bool 116 TMenuItemGroup::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 131 bool 132 TMenuItemGroup::RemoveItem(BMenuItem* item) 133 { 134 if (fMenu) 135 fMenu->RemoveGroupItem(this, item); 136 137 return fList.RemoveItem(item); 138 } 139 140 141 bool 142 TMenuItemGroup::RemoveItem(BMenu* menu) 143 { 144 BMenuItem* item = menu->Superitem(); 145 if (item == NULL) 146 return false; 147 148 return RemoveItem(item); 149 } 150 151 152 BMenuItem* 153 TMenuItemGroup::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 166 BMenuItem* 167 TMenuItemGroup::ItemAt(int32 index) 168 { 169 return static_cast<BMenuItem*>(fList.ItemAt(index)); 170 } 171 172 173 int32 174 TMenuItemGroup::CountItems() 175 { 176 return fList.CountItems(); 177 } 178 179 180 void 181 TMenuItemGroup::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 195 bool 196 TMenuItemGroup::HasSeparator() 197 { 198 return fHasSeparator; 199 } 200 201 202 // #pragma mark - 203 204 205 TGroupedMenu::TGroupedMenu(const char* name) 206 : BMenu(name) 207 { 208 } 209 210 211 TGroupedMenu::~TGroupedMenu() 212 { 213 TMenuItemGroup* group; 214 while ((group = static_cast<TMenuItemGroup*>(fGroups.RemoveItem((int32)0))) 215 != NULL) { 216 delete group; 217 } 218 } 219 220 221 bool 222 TGroupedMenu::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 237 bool 238 TGroupedMenu::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 253 bool 254 TGroupedMenu::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 272 TMenuItemGroup* 273 TGroupedMenu::GroupAt(int32 index) 274 { 275 return static_cast<TMenuItemGroup*>(fGroups.ItemAt(index)); 276 } 277 278 279 int32 280 TGroupedMenu::CountGroups() 281 { 282 return fGroups.CountItems(); 283 } 284 285 286 void 287 TGroupedMenu::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 337 void 338 TGroupedMenu::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