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