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