xref: /haiku/src/kits/tracker/RecentItems.cpp (revision 0d452c8f34013b611a54c746a71c05e28796eae2)
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 		:	BSlowMenu(title),
55 			fTargetMesage(openMessage),
56 			fItemTarget(itemTarget),
57 			fMaxCount(maxItems)
58 		{}
59 	virtual ~RecentItemsMenu();
60 
61 	virtual bool StartBuildingItemList();
62 	virtual bool AddNextItem();
63 	virtual void DoneBuildingItemList() {}
64 	virtual void ClearMenuBuildingState();
65 
66 protected:
67 	virtual const BMessage *FileMessage()
68 		{ return fTargetMesage; }
69 	virtual const BMessage *ContainerMessage()
70 		{ return fTargetMesage; }
71 
72 	BRecentItemsList *fTterator;
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 -
120 
121 
122 RecentItemsMenu::~RecentItemsMenu()
123 {
124 	delete fTterator;
125 	delete fTargetMesage;
126 }
127 
128 
129 bool
130 RecentItemsMenu::AddNextItem()
131 {
132 	BMenuItem *item = fTterator->GetNextMenuItem(FileMessage(),
133 		ContainerMessage(), fItemTarget);
134 
135 	if (item) {
136 		AddItem(item);
137 		fCount++;
138 	}
139 	fSanityCount++;
140 
141 	return fCount < fMaxCount - 1 && (fSanityCount < fMaxCount + 20);
142 		// fSanityCount is a hacky way of dealing with a lot of stale
143 		// recent apps
144 }
145 
146 
147 bool
148 RecentItemsMenu::StartBuildingItemList()
149 {
150 	// remove any preexisting items
151 	int32 itemCount = CountItems();
152 	while (itemCount--)
153 		delete RemoveItem((int32)0);
154 
155 	fCount = 0;
156 	fSanityCount = 0;
157 	fTterator->Rewind();
158 	return true;
159 }
160 
161 
162 void
163 RecentItemsMenu::ClearMenuBuildingState()
164 {
165 	fMenuBuilt = false;
166 		// force rebuilding each time
167 	fTterator->Rewind();
168 }
169 
170 
171 // #pragma mark -
172 
173 
174 RecentFilesMenu::RecentFilesMenu(const char *title, BMessage *openFileMessage,
175 	BMessage *openFolderMessage, BHandler *target, int32 maxItems,
176 	bool navMenuFolders, const char *ofType, const char *openedByAppSig)
177 	:
178 	RecentItemsMenu(title, openFileMessage, target, maxItems),
179 	openFolderMessage(openFolderMessage)
180 {
181 	fTterator = new BRecentFilesList(maxItems + 10, navMenuFolders,
182 		ofType, openedByAppSig);
183 }
184 
185 
186 RecentFilesMenu::RecentFilesMenu(const char *title, BMessage *openFileMessage,
187 	BMessage *openFolderMessage, BHandler *target, int32 maxItems,
188 	bool navMenuFolders, const char *ofTypeList[], int32 ofTypeListCount,
189 	const char *openedByAppSig)
190 	:
191 	RecentItemsMenu(title, openFileMessage, target, maxItems),
192 	openFolderMessage(openFolderMessage)
193 {
194 	fTterator = new BRecentFilesList(maxItems + 10, navMenuFolders,
195 		ofTypeList, ofTypeListCount, openedByAppSig);
196 }
197 
198 
199 RecentFilesMenu::~RecentFilesMenu()
200 {
201 	delete openFolderMessage;
202 }
203 
204 
205 // #pragma mark -
206 
207 
208 RecentFoldersMenu::RecentFoldersMenu(const char *title, BMessage *openMessage,
209 	BHandler *target, int32 maxItems, bool navMenuFolders,
210 	const char *openedByAppSig)
211 	:
212 	RecentItemsMenu(title, openMessage, target, maxItems)
213 {
214 	fTterator = new BRecentFoldersList(maxItems + 10, navMenuFolders,
215 		openedByAppSig);
216 }
217 
218 
219 // #pragma mark -
220 
221 
222 RecentAppsMenu::RecentAppsMenu(const char *title, BMessage *openMessage,
223 	BHandler *target, int32 maxItems)
224 	:	RecentItemsMenu(title, openMessage, target, maxItems)
225 {
226 	fTterator = new BRecentAppsList(maxItems);
227 }
228 
229 
230 // #pragma mark -
231 
232 
233 BRecentItemsList::BRecentItemsList(int32 maxItems, bool navMenuFolders)
234 	:
235 	fMaxItems(maxItems),
236 	fNavMenuFolders(navMenuFolders)
237 {
238 	InitIconPreloader();
239 		// need the icon cache
240 	Rewind();
241 }
242 
243 
244 void
245 BRecentItemsList::Rewind()
246 {
247 	fIndex = 0;
248 	fItems.MakeEmpty();
249 }
250 
251 
252 BMenuItem *
253 BRecentItemsList::GetNextMenuItem(const BMessage *fileOpenInvokeMessage,
254 	const BMessage *containerOpenInvokeMessage, BHandler *target,
255 	entry_ref *currentItemRef)
256 {
257 	entry_ref ref;
258 	if (GetNextRef(&ref) != B_OK)
259 		return NULL;
260 
261 	Model model(&ref, true);
262 	if (model.InitCheck() != B_OK)
263 		return NULL;
264 
265 	bool container = false;
266 	if (model.IsSymLink()) {
267 
268 		Model *newResolvedModel = NULL;
269 		Model *result = model.LinkTo();
270 
271 		if (!result) {
272 			newResolvedModel = new Model(model.EntryRef(), true, true);
273 
274 			if (newResolvedModel->InitCheck() != B_OK) {
275 				// broken link, still can show though, bail
276 				delete newResolvedModel;
277 				result = NULL;
278 			} else
279 				result = newResolvedModel;
280 		}
281 
282 		if (result) {
283 			BModelOpener opener(result);
284 				// open the model, if it ain't open already
285 
286 			PoseInfo poseInfo;
287 			ssize_t size = -1;
288 
289 			if (result->Node())
290 				size = result->Node()->ReadAttr(kAttrPoseInfo, B_RAW_TYPE, 0,
291 					&poseInfo, sizeof(poseInfo));
292 
293 			result->CloseNode();
294 
295 			ref = *result->EntryRef();
296 			container = result->IsContainer();
297 		}
298 		model.SetLinkTo(result);
299 	} else {
300 		ref = *model.EntryRef();
301 		container = model.IsContainer();
302 	}
303 
304 	// if user asked for it, return the current item ref
305 	if (currentItemRef)
306 		*currentItemRef = ref;
307 
308 	BMessage *message;
309 	if (container && containerOpenInvokeMessage)
310 		message = new BMessage(*containerOpenInvokeMessage);
311 	else if (!container && fileOpenInvokeMessage)
312 		message = new BMessage(*fileOpenInvokeMessage);
313 	else
314 		message = new BMessage(B_REFS_RECEIVED);
315 
316 	message->AddRef("refs", model.EntryRef());
317 
318 	// Truncate the name if necessary
319 	BString truncatedString(model.Name());
320 	be_plain_font->TruncateString(&truncatedString, B_TRUNCATE_END,
321 		BNavMenu::GetMaxMenuWidth());
322 
323 	ModelMenuItem *item = NULL;
324 	if (!container || !fNavMenuFolders)
325 		item = new ModelMenuItem(&model, truncatedString.String(), message);
326 	else {
327 		// add another nav menu item if it's a directory
328 		BNavMenu *menu = new BNavMenu(truncatedString.String(), message->what,
329 			target, 0);
330 
331 		menu->SetNavDir(&ref);
332 		item = new ModelMenuItem(&model, menu);
333 		item->SetMessage(message);
334 	}
335 
336 	if (item && target)
337 		item->SetTarget(target);
338 
339 	return item;
340 }
341 
342 
343 status_t
344 BRecentItemsList::GetNextRef(entry_ref *result)
345 {
346 	return fItems.FindRef("refs", fIndex++, result);
347 }
348 
349 
350 // #pragma mark -
351 
352 
353 BRecentFilesList::BRecentFilesList(int32 maxItems, bool navMenuFolders,
354 	const char *ofType, const char *openedByAppSig)
355 	:
356 	BRecentItemsList(maxItems, navMenuFolders),
357 	fType(ofType),
358 	fTypes(NULL),
359 	fTypeCount(0),
360 	fAppSig(openedByAppSig)
361 {
362 }
363 
364 
365 BRecentFilesList::BRecentFilesList(int32 maxItems, bool navMenuFolders,
366 	const char *ofTypeList[], int32 ofTypeListCount, const char *openedByAppSig)
367 	:
368 	BRecentItemsList(maxItems, navMenuFolders),
369 	fType(NULL),
370 	fTypes(NULL),
371 	fTypeCount(ofTypeListCount),
372 	fAppSig(openedByAppSig)
373 {
374 	if (fTypeCount) {
375 		fTypes = new char *[ofTypeListCount];
376 		for (int32 index = 0; index < ofTypeListCount; index++)
377 			fTypes[index] = strdup(ofTypeList[index]);
378 	}
379 }
380 
381 
382 BRecentFilesList::~BRecentFilesList()
383 {
384 	if (fTypeCount) {
385 		for (int32 index = 0; index < fTypeCount; index++)
386 			free(fTypes[index]);
387 		delete [] fTypes;
388 	}
389 }
390 
391 
392 status_t
393 BRecentFilesList::GetNextRef(entry_ref *ref)
394 {
395 	if (fIndex == 0) {
396 		// Lazy roster Get
397 		if (fTypes)
398 			BRoster().GetRecentDocuments(&fItems, fMaxItems,
399 				const_cast<const char **>(fTypes),
400 				fTypeCount, fAppSig.Length() ? fAppSig.String() : NULL);
401 		else
402 			BRoster().GetRecentDocuments(&fItems, fMaxItems,
403 				fType.Length() ? fType.String() : NULL,
404 				fAppSig.Length() ? fAppSig.String() : NULL);
405 
406 	}
407 	return BRecentItemsList::GetNextRef(ref);
408 }
409 
410 
411 BMenu *
412 BRecentFilesList::NewFileListMenu(const char *title,
413 	BMessage *openFileMessage, BMessage *openFolderMessage,
414 	BHandler *target, int32 maxItems, bool navMenuFolders, const char *ofType,
415 	const char *openedByAppSig)
416 {
417 	return new RecentFilesMenu(title, openFileMessage,
418 		openFolderMessage, target, maxItems, navMenuFolders, ofType, openedByAppSig);
419 }
420 
421 
422 BMenu *
423 BRecentFilesList::NewFileListMenu(const char *title,
424 	BMessage *openFileMessage, BMessage *openFolderMessage,
425 	BHandler *target, int32 maxItems, bool navMenuFolders, const char *ofTypeList[],
426 	int32 ofTypeListCount, const char *openedByAppSig)
427 {
428 	return new RecentFilesMenu(title, openFileMessage,
429 		openFolderMessage, target, maxItems, navMenuFolders, ofTypeList,
430 		ofTypeListCount, openedByAppSig);
431 }
432 
433 
434 // #pragma mark -
435 
436 
437 BMenu *
438 BRecentFoldersList::NewFolderListMenu(const char *title,
439 	BMessage *openMessage, BHandler *target, int32 maxItems,
440 	bool navMenuFolders, const char *openedByAppSig)
441 {
442 	return new RecentFoldersMenu(title, openMessage, target, maxItems,
443 		navMenuFolders, openedByAppSig);
444 }
445 
446 
447 BRecentFoldersList::BRecentFoldersList(int32 maxItems, bool navMenuFolders,
448 	const char *openedByAppSig)
449 	:
450 	BRecentItemsList(maxItems, navMenuFolders),
451 	fAppSig(openedByAppSig)
452 {
453 }
454 
455 
456 status_t
457 BRecentFoldersList::GetNextRef(entry_ref *ref)
458 {
459 	if (fIndex == 0) {
460 		// Lazy roster Get
461 		BRoster().GetRecentFolders(&fItems, fMaxItems,
462 			fAppSig.Length() ? fAppSig.String() : NULL);
463 
464 	}
465 	return BRecentItemsList::GetNextRef(ref);
466 }
467 
468 
469 // #pragma mark -
470 
471 
472 BRecentAppsList::BRecentAppsList(int32 maxItems)
473 	:
474 	BRecentItemsList(maxItems, false)
475 {
476 }
477 
478 
479 status_t
480 BRecentAppsList::GetNextRef(entry_ref *ref)
481 {
482 	if (fIndex == 0) {
483 		// Lazy roster Get
484 		BRoster().GetRecentApps(&fItems, fMaxItems);
485 	}
486 	return BRecentItemsList::GetNextRef(ref);
487 }
488 
489 
490 BMenu *
491 BRecentAppsList::NewAppListMenu(const char *title, BMessage *openMessage,
492 	 BHandler *target, int32 maxItems)
493 {
494 	return new RecentAppsMenu(title, openMessage, target, maxItems);
495 }
496