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