xref: /haiku/src/kits/tracker/RecentItems.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
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 IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 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 trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 
36 #include "RecentItems.h"
37 
38 #include <Roster.h>
39 
40 #include "Attributes.h"
41 #include "IconMenuItem.h"
42 #include "Model.h"
43 #include "NavMenu.h"
44 #include "PoseView.h"
45 #include "SlowMenu.h"
46 #include "Tracker.h"
47 #include "Utilities.h"
48 
49 
50 class RecentItemsMenu : public BSlowMenu {
51 public:
52 	RecentItemsMenu(const char* title, BMessage* openMessage,
53 		BHandler* itemTarget, int32 maxItems);
54 	virtual ~RecentItemsMenu();
55 
56 	virtual bool StartBuildingItemList();
57 	virtual bool AddNextItem();
58 	virtual void DoneBuildingItemList() {}
59 	virtual void ClearMenuBuildingState();
60 
61 protected:
62 	virtual const BMessage* FileMessage()
63 	{
64 		return fTargetMesage;
65 	}
66 
67 	virtual const BMessage* ContainerMessage()
68 	{
69 		return fTargetMesage;
70 	}
71 
72 	BRecentItemsList* fIterator;
73 	BMessage* fTargetMesage;
74 	BHandler* fItemTarget;
75 	int32 fCount;
76 	int32 fSanityCount;
77 	int32 fMaxCount;
78 };
79 
80 
81 class RecentFilesMenu : public RecentItemsMenu {
82 public:
83 	RecentFilesMenu(const char* title, BMessage* openFileMessage,
84 		BMessage* openFolderMessage, BHandler* target,
85 		int32 maxItems, bool navMenuFolders, const char* ofType,
86 		const char* openedByAppSig);
87 
88 	RecentFilesMenu(const char* title, BMessage* openFileMessage,
89 		BMessage* openFolderMessage, BHandler* target,
90 		int32 maxItems, bool navMenuFolders, const char* ofTypeList[],
91 		int32 ofTypeListCount, const char* openedByAppSig);
92 
93 	virtual ~RecentFilesMenu();
94 
95 protected:
96 	virtual const BMessage* ContainerMessage()
97 		{ return openFolderMessage; }
98 
99 private:
100 	BMessage* openFolderMessage;
101 };
102 
103 
104 class RecentFoldersMenu : public RecentItemsMenu {
105 public:
106 	RecentFoldersMenu(const char* title, BMessage* openMessage,
107 		BHandler* target, int32 maxItems, bool navMenuFolders,
108 		const char* openedByAppSig);
109 };
110 
111 
112 class RecentAppsMenu : public RecentItemsMenu {
113 public:
114 	RecentAppsMenu(const char* title, BMessage* openMessage,
115 		BHandler* target, int32 maxItems);
116 };
117 
118 
119 // #pragma mark - RecentItemsMenu
120 
121 
122 RecentItemsMenu::RecentItemsMenu(const char* title, BMessage* openMessage,
123 	BHandler* itemTarget, int32 maxItems)
124 	:
125 	BSlowMenu(title),
126 	fIterator(NULL),
127 	fTargetMesage(openMessage),
128 	fItemTarget(itemTarget),
129 	fCount(-1),
130 	fSanityCount(-1),
131 	fMaxCount(maxItems)
132 {
133 }
134 
135 
136 RecentItemsMenu::~RecentItemsMenu()
137 {
138 	delete fIterator;
139 	delete fTargetMesage;
140 }
141 
142 
143 bool
144 RecentItemsMenu::AddNextItem()
145 {
146 	BMenuItem* item = fIterator->GetNextMenuItem(FileMessage(),
147 		ContainerMessage(), fItemTarget);
148 	if (item != NULL) {
149 		AddItem(item);
150 		fCount++;
151 	}
152 	fSanityCount++;
153 
154 	return fCount < fMaxCount - 1 && (fSanityCount < fMaxCount + 20);
155 		// fSanityCount is a hacky way of dealing with a lot of stale
156 		// recent apps
157 }
158 
159 
160 bool
161 RecentItemsMenu::StartBuildingItemList()
162 {
163 	// remove any preexisting items
164 	int32 itemCount = CountItems();
165 	while (itemCount--)
166 		delete RemoveItem((int32)0);
167 
168 	fCount = 0;
169 	fSanityCount = 0;
170 	fIterator->Rewind();
171 
172 	return true;
173 }
174 
175 
176 void
177 RecentItemsMenu::ClearMenuBuildingState()
178 {
179 	fMenuBuilt = false;
180 		// force rebuilding each time
181 	fIterator->Rewind();
182 }
183 
184 
185 // #pragma mark - RecentFilesMenu
186 
187 
188 RecentFilesMenu::RecentFilesMenu(const char* title, BMessage* openFileMessage,
189 	BMessage* openFolderMessage, BHandler* target, int32 maxItems,
190 	bool navMenuFolders, const char* ofType, const char* openedByAppSig)
191 	:
192 	RecentItemsMenu(title, openFileMessage, target, maxItems),
193 	openFolderMessage(openFolderMessage)
194 {
195 	fIterator = new BRecentFilesList(maxItems + 10, navMenuFolders,
196 		ofType, openedByAppSig);
197 }
198 
199 
200 RecentFilesMenu::RecentFilesMenu(const char* title, BMessage* openFileMessage,
201 	BMessage* openFolderMessage, BHandler* target, int32 maxItems,
202 	bool navMenuFolders, const char* ofTypeList[], int32 ofTypeListCount,
203 	const char* openedByAppSig)
204 	:
205 	RecentItemsMenu(title, openFileMessage, target, maxItems),
206 	openFolderMessage(openFolderMessage)
207 {
208 	fIterator = new BRecentFilesList(maxItems + 10, navMenuFolders,
209 		ofTypeList, ofTypeListCount, openedByAppSig);
210 }
211 
212 
213 RecentFilesMenu::~RecentFilesMenu()
214 {
215 	delete openFolderMessage;
216 }
217 
218 
219 // #pragma mark - RecentFoldersMenu
220 
221 
222 RecentFoldersMenu::RecentFoldersMenu(const char* title, BMessage* openMessage,
223 	BHandler* target, int32 maxItems, bool navMenuFolders,
224 	const char* openedByAppSig)
225 	:
226 	RecentItemsMenu(title, openMessage, target, maxItems)
227 {
228 	fIterator = new BRecentFoldersList(maxItems + 10, navMenuFolders,
229 		openedByAppSig);
230 }
231 
232 
233 // #pragma mark - RecentAppsMenu
234 
235 
236 RecentAppsMenu::RecentAppsMenu(const char* title, BMessage* openMessage,
237 	BHandler* target, int32 maxItems)
238 	:
239 	RecentItemsMenu(title, openMessage, target, maxItems)
240 {
241 	fIterator = new BRecentAppsList(maxItems);
242 }
243 
244 
245 // #pragma mark - BRecentItemsList
246 
247 
248 BRecentItemsList::BRecentItemsList(int32 maxItems, bool navMenuFolders)
249 	:
250 	fMaxItems(maxItems),
251 	fNavMenuFolders(navMenuFolders)
252 {
253 	InitIconPreloader();
254 		// need the icon cache
255 	Rewind();
256 }
257 
258 
259 void
260 BRecentItemsList::Rewind()
261 {
262 	fIndex = 0;
263 	fItems.MakeEmpty();
264 }
265 
266 
267 BMenuItem*
268 BRecentItemsList::GetNextMenuItem(const BMessage* fileOpenInvokeMessage,
269 	const BMessage* containerOpenInvokeMessage, BHandler* target,
270 	entry_ref* currentItemRef)
271 {
272 	entry_ref ref;
273 	if (GetNextRef(&ref) != B_OK)
274 		return NULL;
275 
276 	Model model(&ref, true);
277 	if (model.InitCheck() != B_OK)
278 		return NULL;
279 
280 	bool container = false;
281 	if (model.IsSymLink()) {
282 
283 		Model* newResolvedModel = NULL;
284 		Model* result = model.LinkTo();
285 
286 		if (result == NULL) {
287 			newResolvedModel = new Model(model.EntryRef(), true, true);
288 
289 			if (newResolvedModel->InitCheck() != B_OK) {
290 				// broken link, still can show though, bail
291 				delete newResolvedModel;
292 				result = NULL;
293 			} else
294 				result = newResolvedModel;
295 		} else {
296 			BModelOpener opener(result);
297 				// open the model, if it ain't open already
298 
299 			PoseInfo poseInfo;
300 			BNode* resultNode = result->Node();
301 			if (resultNode != NULL) {
302 				resultNode->ReadAttr(kAttrPoseInfo, B_RAW_TYPE, 0,
303 					&poseInfo, sizeof(poseInfo));
304 			}
305 
306 			result->CloseNode();
307 
308 			ref = *result->EntryRef();
309 			container = result->IsContainer();
310 		}
311 		model.SetLinkTo(result);
312 	} else {
313 		ref = *model.EntryRef();
314 		container = model.IsContainer();
315 	}
316 
317 	// if user asked for it, return the current item ref
318 	if (currentItemRef != NULL)
319 		*currentItemRef = ref;
320 
321 	BMessage* message;
322 	if (container && containerOpenInvokeMessage)
323 		message = new BMessage(*containerOpenInvokeMessage);
324 	else if (!container && fileOpenInvokeMessage)
325 		message = new BMessage(*fileOpenInvokeMessage);
326 	else
327 		message = new BMessage(B_REFS_RECEIVED);
328 
329 	message->AddRef("refs", model.EntryRef());
330 
331 	// menu font
332 	menu_info info;
333 	get_menu_info(&info);
334 	BFont menuFont;
335 	menuFont.SetFamilyAndStyle(info.f_family, info.f_style);
336 	menuFont.SetSize(info.font_size);
337 
338 	// Truncate the name if necessary
339 	BString truncatedString(model.Name());
340 	menuFont.TruncateString(&truncatedString, B_TRUNCATE_END, BNavMenu::GetMaxMenuWidth());
341 
342 	ModelMenuItem* item = NULL;
343 	if (!container || !fNavMenuFolders)
344 		item = new ModelMenuItem(&model, truncatedString.String(), message);
345 	else {
346 		// add another nav menu item if it's a directory
347 		BNavMenu* menu = new BNavMenu(truncatedString.String(), message->what,
348 			target, 0);
349 
350 		menu->SetNavDir(&ref);
351 		item = new ModelMenuItem(&model, menu);
352 		item->SetMessage(message);
353 	}
354 
355 	if (item != NULL && target != NULL)
356 		item->SetTarget(target);
357 
358 	return item;
359 }
360 
361 
362 status_t
363 BRecentItemsList::GetNextRef(entry_ref* result)
364 {
365 	return fItems.FindRef("refs", fIndex++, result);
366 }
367 
368 
369 // #pragma mark - BRecentFilesList
370 
371 
372 BRecentFilesList::BRecentFilesList(int32 maxItems, bool navMenuFolders,
373 	const char* ofType, const char* openedByAppSig)
374 	:
375 	BRecentItemsList(maxItems, navMenuFolders),
376 	fType(ofType),
377 	fTypes(NULL),
378 	fTypeCount(0),
379 	fAppSig(openedByAppSig)
380 {
381 }
382 
383 
384 BRecentFilesList::BRecentFilesList(int32 maxItems, bool navMenuFolders,
385 	const char* ofTypeList[], int32 ofTypeListCount,
386 	const char* openedByAppSig)
387 	:
388 	BRecentItemsList(maxItems, navMenuFolders),
389 	fType(NULL),
390 	fTypes(NULL),
391 	fTypeCount(ofTypeListCount),
392 	fAppSig(openedByAppSig)
393 {
394 	if (fTypeCount > 0) {
395 		fTypes = new char *[ofTypeListCount];
396 		for (int32 index = 0; index < ofTypeListCount; index++)
397 			fTypes[index] = strdup(ofTypeList[index]);
398 	}
399 }
400 
401 
402 BRecentFilesList::~BRecentFilesList()
403 {
404 	if (fTypeCount > 0) {
405 		for (int32 index = 0; index < fTypeCount; index++)
406 			free(fTypes[index]);
407 		delete[] fTypes;
408 	}
409 }
410 
411 
412 status_t
413 BRecentFilesList::GetNextRef(entry_ref* ref)
414 {
415 	if (fIndex == 0) {
416 		// Lazy roster Get
417 		if (fTypes != NULL) {
418 			BRoster().GetRecentDocuments(&fItems, fMaxItems,
419 				const_cast<const char**>(fTypes),
420 				fTypeCount, fAppSig.Length() ? fAppSig.String() : NULL);
421 		} else {
422 			BRoster().GetRecentDocuments(&fItems, fMaxItems,
423 				fType.Length() ? fType.String() : NULL,
424 				fAppSig.Length() ? fAppSig.String() : NULL);
425 		}
426 
427 	}
428 
429 	return BRecentItemsList::GetNextRef(ref);
430 }
431 
432 
433 BMenu*
434 BRecentFilesList::NewFileListMenu(const char* title,
435 	BMessage* openFileMessage, BMessage* openFolderMessage,
436 	BHandler* target, int32 maxItems, bool navMenuFolders, const char* ofType,
437 	const char* openedByAppSig)
438 {
439 	return new RecentFilesMenu(title, openFileMessage,
440 		openFolderMessage, target, maxItems, navMenuFolders, ofType,
441 		openedByAppSig);
442 }
443 
444 
445 BMenu*
446 BRecentFilesList::NewFileListMenu(const char* title,
447 	BMessage* openFileMessage, BMessage* openFolderMessage,
448 	BHandler* target, int32 maxItems, bool navMenuFolders,
449 	const char* ofTypeList[], int32 ofTypeListCount,
450 	const char* openedByAppSig)
451 {
452 	return new RecentFilesMenu(title, openFileMessage,
453 		openFolderMessage, target, maxItems, navMenuFolders, ofTypeList,
454 		ofTypeListCount, openedByAppSig);
455 }
456 
457 
458 // #pragma mark - BRecentFoldersList
459 
460 
461 BMenu*
462 BRecentFoldersList::NewFolderListMenu(const char* title,
463 	BMessage* openMessage, BHandler* target, int32 maxItems,
464 	bool navMenuFolders, const char* openedByAppSig)
465 {
466 	return new RecentFoldersMenu(title, openMessage, target, maxItems,
467 		navMenuFolders, openedByAppSig);
468 }
469 
470 
471 BRecentFoldersList::BRecentFoldersList(int32 maxItems, bool navMenuFolders,
472 	const char* openedByAppSig)
473 	:
474 	BRecentItemsList(maxItems, navMenuFolders),
475 	fAppSig(openedByAppSig)
476 {
477 }
478 
479 
480 status_t
481 BRecentFoldersList::GetNextRef(entry_ref* ref)
482 {
483 	if (fIndex == 0) {
484 		// Lazy roster Get
485 		BRoster().GetRecentFolders(&fItems, fMaxItems,
486 			fAppSig.Length() ? fAppSig.String() : NULL);
487 
488 	}
489 
490 	return BRecentItemsList::GetNextRef(ref);
491 }
492 
493 
494 // #pragma mark - BRecentAppsList
495 
496 
497 BRecentAppsList::BRecentAppsList(int32 maxItems)
498 	:
499 	BRecentItemsList(maxItems, false)
500 {
501 }
502 
503 
504 status_t
505 BRecentAppsList::GetNextRef(entry_ref* ref)
506 {
507 	if (fIndex == 0) {
508 		// Lazy roster Get
509 		BRoster().GetRecentApps(&fItems, fMaxItems);
510 	}
511 
512 	return BRecentItemsList::GetNextRef(ref);
513 }
514 
515 
516 BMenu*
517 BRecentAppsList::NewAppListMenu(const char* title, BMessage* openMessage,
518 	 BHandler* target, int32 maxItems)
519 {
520 	return new RecentAppsMenu(title, openMessage, target, maxItems);
521 }
522