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();
DoneBuildingItemList()58 virtual void DoneBuildingItemList() {}
59 virtual void ClearMenuBuildingState();
60
61 protected:
FileMessage()62 virtual const BMessage* FileMessage()
63 {
64 return fTargetMesage;
65 }
66
ContainerMessage()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:
ContainerMessage()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
RecentItemsMenu(const char * title,BMessage * openMessage,BHandler * itemTarget,int32 maxItems)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
~RecentItemsMenu()136 RecentItemsMenu::~RecentItemsMenu()
137 {
138 delete fIterator;
139 delete fTargetMesage;
140 }
141
142
143 bool
AddNextItem()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
StartBuildingItemList()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
ClearMenuBuildingState()177 RecentItemsMenu::ClearMenuBuildingState()
178 {
179 fMenuBuilt = false;
180 // force rebuilding each time
181 fIterator->Rewind();
182 }
183
184
185 // #pragma mark - RecentFilesMenu
186
187
RecentFilesMenu(const char * title,BMessage * openFileMessage,BMessage * openFolderMessage,BHandler * target,int32 maxItems,bool navMenuFolders,const char * ofType,const char * openedByAppSig)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
RecentFilesMenu(const char * title,BMessage * openFileMessage,BMessage * openFolderMessage,BHandler * target,int32 maxItems,bool navMenuFolders,const char * ofTypeList[],int32 ofTypeListCount,const char * openedByAppSig)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
~RecentFilesMenu()213 RecentFilesMenu::~RecentFilesMenu()
214 {
215 delete openFolderMessage;
216 }
217
218
219 // #pragma mark - RecentFoldersMenu
220
221
RecentFoldersMenu(const char * title,BMessage * openMessage,BHandler * target,int32 maxItems,bool navMenuFolders,const char * openedByAppSig)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
RecentAppsMenu(const char * title,BMessage * openMessage,BHandler * target,int32 maxItems)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
BRecentItemsList(int32 maxItems,bool navMenuFolders)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
Rewind()260 BRecentItemsList::Rewind()
261 {
262 fIndex = 0;
263 fItems.MakeEmpty();
264 }
265
266
267 BMenuItem*
GetNextMenuItem(const BMessage * fileOpenInvokeMessage,const BMessage * containerOpenInvokeMessage,BHandler * target,entry_ref * currentItemRef)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
GetNextRef(entry_ref * result)363 BRecentItemsList::GetNextRef(entry_ref* result)
364 {
365 return fItems.FindRef("refs", fIndex++, result);
366 }
367
368
369 // #pragma mark - BRecentFilesList
370
371
BRecentFilesList(int32 maxItems,bool navMenuFolders,const char * ofType,const char * openedByAppSig)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
BRecentFilesList(int32 maxItems,bool navMenuFolders,const char * ofTypeList[],int32 ofTypeListCount,const char * openedByAppSig)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
~BRecentFilesList()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
GetNextRef(entry_ref * ref)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*
NewFileListMenu(const char * title,BMessage * openFileMessage,BMessage * openFolderMessage,BHandler * target,int32 maxItems,bool navMenuFolders,const char * ofType,const char * openedByAppSig)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*
NewFileListMenu(const char * title,BMessage * openFileMessage,BMessage * openFolderMessage,BHandler * target,int32 maxItems,bool navMenuFolders,const char * ofTypeList[],int32 ofTypeListCount,const char * openedByAppSig)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*
NewFolderListMenu(const char * title,BMessage * openMessage,BHandler * target,int32 maxItems,bool navMenuFolders,const char * openedByAppSig)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
BRecentFoldersList(int32 maxItems,bool navMenuFolders,const char * openedByAppSig)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
GetNextRef(entry_ref * ref)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
BRecentAppsList(int32 maxItems)497 BRecentAppsList::BRecentAppsList(int32 maxItems)
498 :
499 BRecentItemsList(maxItems, false)
500 {
501 }
502
503
504 status_t
GetNextRef(entry_ref * ref)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*
NewAppListMenu(const char * title,BMessage * openMessage,BHandler * target,int32 maxItems)517 BRecentAppsList::NewAppListMenu(const char* title, BMessage* openMessage,
518 BHandler* target, int32 maxItems)
519 {
520 return new RecentAppsMenu(title, openMessage, target, maxItems);
521 }
522