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(0L)) != 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 false; 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(0L))) != NULL) 180 delete group; 181 } 182 183 184 bool 185 TGroupedMenu::AddGroup(TMenuItemGroup *group) 186 { 187 if (!fGroups.AddItem(group)) 188 return false; 189 190 group->fMenu = this; 191 192 for (int32 i = 0; i < group->CountItems(); i++) { 193 AddGroupItem(group, group->ItemAt(i), i); 194 } 195 196 return true; 197 } 198 199 200 bool 201 TGroupedMenu::AddGroup(TMenuItemGroup *group, int32 atIndex) 202 { 203 if (!fGroups.AddItem(group, atIndex)) 204 return false; 205 206 group->fMenu = this; 207 208 for (int32 i = 0; i < group->CountItems(); i++) { 209 AddGroupItem(group, group->ItemAt(i), i); 210 } 211 212 return true; 213 } 214 215 216 bool 217 TGroupedMenu::RemoveGroup(TMenuItemGroup *group) 218 { 219 if (group->HasSeparator()) { 220 delete RemoveItem(group->fFirstItemIndex); 221 group->Separated(false); 222 } 223 224 group->fMenu = NULL; 225 group->fFirstItemIndex = -1; 226 227 for (int32 i = 0; i < group->CountItems(); i++) { 228 RemoveItem(group->ItemAt(i)); 229 } 230 231 return fGroups.RemoveItem(group); 232 } 233 234 235 TMenuItemGroup * 236 TGroupedMenu::GroupAt(int32 index) 237 { 238 return static_cast<TMenuItemGroup *>(fGroups.ItemAt(index)); 239 } 240 241 242 int32 243 TGroupedMenu::CountGroups() 244 { 245 return fGroups.CountItems(); 246 } 247 248 249 void 250 TGroupedMenu::AddGroupItem(TMenuItemGroup *group, BMenuItem *item, int32 atIndex) 251 { 252 int32 groupIndex = fGroups.IndexOf(group); 253 bool addSeparator = false; 254 255 if (group->fFirstItemIndex == -1) { 256 // find new home for this group 257 if (groupIndex > 0) { 258 // add this group after an existing one 259 TMenuItemGroup *previous = GroupAt(groupIndex - 1); 260 group->fFirstItemIndex = previous->fFirstItemIndex + previous->fItemsTotal; 261 addSeparator = true; 262 } else { 263 // this is the first group 264 TMenuItemGroup *successor = GroupAt(groupIndex + 1); 265 if (successor != NULL) { 266 group->fFirstItemIndex = successor->fFirstItemIndex; 267 if (successor->fHasSeparator) { 268 // we'll need one as well 269 addSeparator = true; 270 } 271 } else { 272 group->fFirstItemIndex = CountItems(); 273 if (group->fFirstItemIndex > 0) 274 addSeparator = true; 275 } 276 } 277 278 if (addSeparator) { 279 AddItem(new BSeparatorItem(), group->fFirstItemIndex); 280 group->Separated(true); 281 } 282 } 283 284 // insert item for real 285 286 AddItem(item, atIndex + group->fFirstItemIndex + (group->HasSeparator() ? 1 : 0)); 287 288 // move the groups after this one 289 290 for (int32 i = groupIndex + 1; i < CountGroups(); i++) { 291 group = GroupAt(i); 292 group->fFirstItemIndex += addSeparator ? 2 : 1; 293 } 294 } 295 296 297 void 298 TGroupedMenu::RemoveGroupItem(TMenuItemGroup *group, BMenuItem *item) 299 { 300 int32 groupIndex = fGroups.IndexOf(group); 301 bool removedSeparator = false; 302 303 if (group->CountItems() == 1) { 304 // this is the last item 305 if (group->HasSeparator()) { 306 RemoveItem(group->fFirstItemIndex); 307 group->Separated(false); 308 removedSeparator = true; 309 } 310 } 311 312 // insert item for real 313 314 RemoveItem(item); 315 316 // move the groups after this one 317 318 for (int32 i = groupIndex + 1; i < CountGroups(); i++) { 319 group = GroupAt(i); 320 group->fFirstItemIndex -= removedSeparator ? 2 : 1; 321 } 322 } 323 324