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