xref: /haiku/src/kits/tracker/RecentItems.cpp (revision 37fedaf8494b34aad811abcc49e79aa32943f880)
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 
288 			if (result->Node()) {
289 				result->Node()->ReadAttr(kAttrPoseInfo, B_RAW_TYPE, 0,
290 					&poseInfo, sizeof(poseInfo));
291 			}
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,
367 	const char* openedByAppSig)
368 	:
369 	BRecentItemsList(maxItems, navMenuFolders),
370 	fType(NULL),
371 	fTypes(NULL),
372 	fTypeCount(ofTypeListCount),
373 	fAppSig(openedByAppSig)
374 {
375 	if (fTypeCount) {
376 		fTypes = new char *[ofTypeListCount];
377 		for (int32 index = 0; index < ofTypeListCount; index++)
378 			fTypes[index] = strdup(ofTypeList[index]);
379 	}
380 }
381 
382 
383 BRecentFilesList::~BRecentFilesList()
384 {
385 	if (fTypeCount) {
386 		for (int32 index = 0; index < fTypeCount; index++)
387 			free(fTypes[index]);
388 		delete[] fTypes;
389 	}
390 }
391 
392 
393 status_t
394 BRecentFilesList::GetNextRef(entry_ref* ref)
395 {
396 	if (fIndex == 0) {
397 		// Lazy roster Get
398 		if (fTypes)
399 			BRoster().GetRecentDocuments(&fItems, fMaxItems,
400 				const_cast<const char**>(fTypes),
401 				fTypeCount, fAppSig.Length() ? fAppSig.String() : NULL);
402 		else
403 			BRoster().GetRecentDocuments(&fItems, fMaxItems,
404 				fType.Length() ? fType.String() : NULL,
405 				fAppSig.Length() ? fAppSig.String() : NULL);
406 
407 	}
408 	return BRecentItemsList::GetNextRef(ref);
409 }
410 
411 
412 BMenu*
413 BRecentFilesList::NewFileListMenu(const char* title,
414 	BMessage* openFileMessage, BMessage* openFolderMessage,
415 	BHandler* target, int32 maxItems, bool navMenuFolders, const char* ofType,
416 	const char* openedByAppSig)
417 {
418 	return new RecentFilesMenu(title, openFileMessage,
419 		openFolderMessage, target, maxItems, navMenuFolders, ofType,
420 		openedByAppSig);
421 }
422 
423 
424 BMenu*
425 BRecentFilesList::NewFileListMenu(const char* title,
426 	BMessage* openFileMessage, BMessage* openFolderMessage,
427 	BHandler* target, int32 maxItems, bool navMenuFolders,
428 	const char* ofTypeList[], int32 ofTypeListCount,
429 	const char* openedByAppSig)
430 {
431 	return new RecentFilesMenu(title, openFileMessage,
432 		openFolderMessage, target, maxItems, navMenuFolders, ofTypeList,
433 		ofTypeListCount, openedByAppSig);
434 }
435 
436 
437 // #pragma mark -
438 
439 
440 BMenu*
441 BRecentFoldersList::NewFolderListMenu(const char* title,
442 	BMessage* openMessage, BHandler* target, int32 maxItems,
443 	bool navMenuFolders, const char* openedByAppSig)
444 {
445 	return new RecentFoldersMenu(title, openMessage, target, maxItems,
446 		navMenuFolders, openedByAppSig);
447 }
448 
449 
450 BRecentFoldersList::BRecentFoldersList(int32 maxItems, bool navMenuFolders,
451 	const char* openedByAppSig)
452 	:
453 	BRecentItemsList(maxItems, navMenuFolders),
454 	fAppSig(openedByAppSig)
455 {
456 }
457 
458 
459 status_t
460 BRecentFoldersList::GetNextRef(entry_ref* ref)
461 {
462 	if (fIndex == 0) {
463 		// Lazy roster Get
464 		BRoster().GetRecentFolders(&fItems, fMaxItems,
465 			fAppSig.Length() ? fAppSig.String() : NULL);
466 
467 	}
468 	return BRecentItemsList::GetNextRef(ref);
469 }
470 
471 
472 // #pragma mark -
473 
474 
475 BRecentAppsList::BRecentAppsList(int32 maxItems)
476 	:
477 	BRecentItemsList(maxItems, false)
478 {
479 }
480 
481 
482 status_t
483 BRecentAppsList::GetNextRef(entry_ref* ref)
484 {
485 	if (fIndex == 0) {
486 		// Lazy roster Get
487 		BRoster().GetRecentApps(&fItems, fMaxItems);
488 	}
489 	return BRecentItemsList::GetNextRef(ref);
490 }
491 
492 
493 BMenu*
494 BRecentAppsList::NewAppListMenu(const char* title, BMessage* openMessage,
495 	 BHandler* target, int32 maxItems)
496 {
497 	return new RecentAppsMenu(title, openMessage, target, maxItems);
498 }
499