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