1 #include "GroupedMenu.h" 2 3 #include <stdlib.h> 4 #include <string.h> 5 6 7 using namespace BPrivate; 8 9 10 TMenuItemGroup::TMenuItemGroup(const char* name) 11 : 12 fMenu(NULL), 13 fFirstItemIndex(-1), 14 fItemsTotal(0), 15 fHasSeparator(false) 16 { 17 if (name != NULL && name[0] != '\0') 18 fName = strdup(name); 19 else 20 fName = NULL; 21 } 22 23 24 TMenuItemGroup::~TMenuItemGroup() 25 { 26 free((char*)fName); 27 28 if (fMenu == NULL) { 29 BMenuItem* item; 30 while ((item = RemoveItem((int32)0)) != NULL) 31 delete item; 32 } 33 } 34 35 36 bool 37 TMenuItemGroup::AddItem(BMenuItem* item) 38 { 39 if (!fList.AddItem(item)) 40 return false; 41 42 if (fMenu) 43 fMenu->AddGroupItem(this, item, fList.IndexOf(item)); 44 45 fItemsTotal++; 46 return true; 47 } 48 49 50 bool 51 TMenuItemGroup::AddItem(BMenuItem* item, int32 atIndex) 52 { 53 if (!fList.AddItem(item, atIndex)) 54 return false; 55 56 if (fMenu) 57 fMenu->AddGroupItem(this, item, atIndex); 58 59 fItemsTotal++; 60 return true; 61 } 62 63 64 bool 65 TMenuItemGroup::AddItem(BMenu* menu) 66 { 67 BMenuItem* item = new BMenuItem(menu); 68 if (item == NULL) 69 return false; 70 71 if (!AddItem(item)) { 72 delete item; 73 return false; 74 } 75 76 return true; 77 } 78 79 80 bool 81 TMenuItemGroup::AddItem(BMenu* menu, int32 atIndex) 82 { 83 BMenuItem* item = new BMenuItem(menu); 84 if (item == NULL) 85 return false; 86 87 if (!AddItem(item, atIndex)) { 88 delete item; 89 return false; 90 } 91 92 return true; 93 } 94 95 96 bool 97 TMenuItemGroup::RemoveItem(BMenuItem* item) 98 { 99 if (fMenu) 100 fMenu->RemoveGroupItem(this, item); 101 102 return fList.RemoveItem(item); 103 } 104 105 106 bool 107 TMenuItemGroup::RemoveItem(BMenu* menu) 108 { 109 BMenuItem* item = menu->Superitem(); 110 if (item == NULL) 111 return false; 112 113 return RemoveItem(item); 114 } 115 116 117 BMenuItem* 118 TMenuItemGroup::RemoveItem(int32 index) 119 { 120 BMenuItem* item = ItemAt(index); 121 if (item == NULL) 122 return NULL; 123 124 if (RemoveItem(item)) 125 return item; 126 127 return NULL; 128 } 129 130 131 BMenuItem* 132 TMenuItemGroup::ItemAt(int32 index) 133 { 134 return static_cast<BMenuItem*>(fList.ItemAt(index)); 135 } 136 137 138 int32 139 TMenuItemGroup::CountItems() 140 { 141 return fList.CountItems(); 142 } 143 144 145 void 146 TMenuItemGroup::Separated(bool separated) 147 { 148 if (separated == fHasSeparator) 149 return; 150 151 fHasSeparator = separated; 152 153 if (separated) 154 fItemsTotal++; 155 else 156 fItemsTotal--; 157 } 158 159 160 bool 161 TMenuItemGroup::HasSeparator() 162 { 163 return fHasSeparator; 164 } 165 166 167 // #pragma mark - 168 169 170 TGroupedMenu::TGroupedMenu(const char* name) 171 : BMenu(name) 172 { 173 } 174 175 176 TGroupedMenu::~TGroupedMenu() 177 { 178 TMenuItemGroup* group; 179 while ((group = static_cast<TMenuItemGroup*>(fGroups.RemoveItem((int32)0))) 180 != NULL) { 181 delete group; 182 } 183 } 184 185 186 bool 187 TGroupedMenu::AddGroup(TMenuItemGroup* group) 188 { 189 if (!fGroups.AddItem(group)) 190 return false; 191 192 group->fMenu = this; 193 194 for (int32 i = 0; i < group->CountItems(); i++) { 195 AddGroupItem(group, group->ItemAt(i), i); 196 } 197 198 return true; 199 } 200 201 202 bool 203 TGroupedMenu::AddGroup(TMenuItemGroup* group, int32 atIndex) 204 { 205 if (!fGroups.AddItem(group, atIndex)) 206 return false; 207 208 group->fMenu = this; 209 210 for (int32 i = 0; i < group->CountItems(); i++) { 211 AddGroupItem(group, group->ItemAt(i), i); 212 } 213 214 return true; 215 } 216 217 218 bool 219 TGroupedMenu::RemoveGroup(TMenuItemGroup* group) 220 { 221 if (group->HasSeparator()) { 222 delete RemoveItem(group->fFirstItemIndex); 223 group->Separated(false); 224 } 225 226 group->fMenu = NULL; 227 group->fFirstItemIndex = -1; 228 229 for (int32 i = 0; i < group->CountItems(); i++) { 230 RemoveItem(group->ItemAt(i)); 231 } 232 233 return fGroups.RemoveItem(group); 234 } 235 236 237 TMenuItemGroup* 238 TGroupedMenu::GroupAt(int32 index) 239 { 240 return static_cast<TMenuItemGroup*>(fGroups.ItemAt(index)); 241 } 242 243 244 int32 245 TGroupedMenu::CountGroups() 246 { 247 return fGroups.CountItems(); 248 } 249 250 251 void 252 TGroupedMenu::AddGroupItem(TMenuItemGroup* group, BMenuItem* item, 253 int32 atIndex) 254 { 255 int32 groupIndex = fGroups.IndexOf(group); 256 bool addSeparator = false; 257 258 if (group->fFirstItemIndex == -1) { 259 // find new home for this group 260 if (groupIndex > 0) { 261 // add this group after an existing one 262 TMenuItemGroup* previous = GroupAt(groupIndex - 1); 263 group->fFirstItemIndex = previous->fFirstItemIndex 264 + previous->fItemsTotal; 265 addSeparator = true; 266 } else { 267 // this is the first group 268 TMenuItemGroup* successor = GroupAt(groupIndex + 1); 269 if (successor != NULL) { 270 group->fFirstItemIndex = successor->fFirstItemIndex; 271 if (successor->fHasSeparator) { 272 // we'll need one as well 273 addSeparator = true; 274 } 275 } else { 276 group->fFirstItemIndex = CountItems(); 277 if (group->fFirstItemIndex > 0) 278 addSeparator = true; 279 } 280 } 281 282 if (addSeparator) { 283 AddItem(new BSeparatorItem(), group->fFirstItemIndex); 284 group->Separated(true); 285 } 286 } 287 288 // insert item for real 289 290 AddItem(item, 291 atIndex + group->fFirstItemIndex + (group->HasSeparator() ? 1 : 0)); 292 293 // move the groups after this one 294 295 for (int32 i = groupIndex + 1; i < CountGroups(); i++) { 296 group = GroupAt(i); 297 group->fFirstItemIndex += addSeparator ? 2 : 1; 298 } 299 } 300 301 302 void 303 TGroupedMenu::RemoveGroupItem(TMenuItemGroup* group, BMenuItem* item) 304 { 305 int32 groupIndex = fGroups.IndexOf(group); 306 bool removedSeparator = false; 307 308 if (group->CountItems() == 1) { 309 // this is the last item 310 if (group->HasSeparator()) { 311 RemoveItem(group->fFirstItemIndex); 312 group->Separated(false); 313 removedSeparator = true; 314 } 315 } 316 317 // insert item for real 318 319 RemoveItem(item); 320 321 // move the groups after this one 322 323 for (int32 i = groupIndex + 1; i < CountGroups(); i++) { 324 group = GroupAt(i); 325 group->fFirstItemIndex -= removedSeparator ? 2 : 1; 326 } 327 } 328