xref: /haiku/src/kits/tracker/GroupedMenu.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
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