xref: /haiku/src/kits/tracker/GroupedMenu.cpp (revision a83fb6fed8946eb2f1c330c0239bc0f7e7d61a70)
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 
TMenuItemGroup(const char * name)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 
~TMenuItemGroup()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
AddItem(BMenuItem * item)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
AddItem(BMenuItem * item,int32 atIndex)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
AddItem(BMenu * menu)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
AddItem(BMenu * menu,int32 atIndex)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
RemoveItem(BMenuItem * item)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
RemoveItem(BMenu * menu)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*
RemoveItem(int32 index)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*
ItemAt(int32 index)167 TMenuItemGroup::ItemAt(int32 index)
168 {
169 	return static_cast<BMenuItem*>(fList.ItemAt(index));
170 }
171 
172 
173 int32
CountItems()174 TMenuItemGroup::CountItems()
175 {
176 	return fList.CountItems();
177 }
178 
179 
180 void
Separated(bool separated)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
HasSeparator()196 TMenuItemGroup::HasSeparator()
197 {
198 	return fHasSeparator;
199 }
200 
201 
202 //	#pragma mark -
203 
204 
TGroupedMenu(const char * name)205 TGroupedMenu::TGroupedMenu(const char* name)
206 	: BMenu(name)
207 {
208 }
209 
210 
~TGroupedMenu()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
AddGroup(TMenuItemGroup * group)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
AddGroup(TMenuItemGroup * group,int32 atIndex)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
RemoveGroup(TMenuItemGroup * group)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*
GroupAt(int32 index)273 TGroupedMenu::GroupAt(int32 index)
274 {
275 	return static_cast<TMenuItemGroup*>(fGroups.ItemAt(index));
276 }
277 
278 
279 int32
CountGroups()280 TGroupedMenu::CountGroups()
281 {
282 	return fGroups.CountItems();
283 }
284 
285 
286 void
AddGroupItem(TMenuItemGroup * group,BMenuItem * item,int32 atIndex)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
RemoveGroupItem(TMenuItemGroup * group,BMenuItem * item)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