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