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 "Attributes.h" 36 #include "AutoLock.h" 37 #include "Commands.h" 38 #include "FSUtils.h" 39 #include "IconMenuItem.h" 40 #include "OpenWithWindow.h" 41 #include "MimeTypes.h" 42 #include "StopWatch.h" 43 #include "Tracker.h" 44 45 #include <Alert.h> 46 #include <Button.h> 47 #include <Mime.h> 48 #include <NodeInfo.h> 49 #include <Path.h> 50 #include <Roster.h> 51 #include <Volume.h> 52 #include <VolumeRoster.h> 53 54 #include <stdlib.h> 55 #include <stdio.h> 56 #include <string.h> 57 58 const char *kDefaultOpenWithTemplate = "OpenWithSettings"; 59 60 // ToDo: 61 // filter out trash 62 // allow column configuring 63 // make SaveState/RestoreState save the current window setting for 64 // other windows 65 66 const float kMaxMenuWidth = 150; 67 68 const int32 kDocumentKnobWidth = 16; 69 const int32 kOpenAndMakeDefault = 'OpDf'; 70 const rgb_color kOpenWithDefaultColor = { 0xFF, 0xFF, 0xCC, 255}; 71 72 73 OpenWithContainerWindow::OpenWithContainerWindow(BMessage *entriesToOpen, 74 LockingList<BWindow> *windowList, window_look look, window_feel feel, 75 uint32 flags, uint32 workspace) 76 : BContainerWindow(windowList, 0, look, feel, flags, workspace), 77 fEntriesToOpen(entriesToOpen) 78 { 79 AutoLock<BWindow> lock(this); 80 81 BRect windowRect(85, 50, 510, 296); 82 MoveTo(windowRect.LeftTop()); 83 ResizeTo(windowRect.Width(), windowRect.Height()); 84 85 // add a background view; use the standard BackgroundView here, the same 86 // as the file panel is using 87 BRect rect(Bounds()); 88 BackgroundView *backgroundView = new BackgroundView(rect); 89 AddChild(backgroundView); 90 91 rect = Bounds(); 92 93 // add buttons 94 95 fLaunchButton = new BButton(rect, "ok", "Open", 96 new BMessage(kDefaultButton), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 97 fLaunchButton->ResizeToPreferred(); 98 fLaunchButton->MoveTo(rect.right - 10 - kDocumentKnobWidth 99 - fLaunchButton->Bounds().Width(), 100 rect.bottom - 10 - fLaunchButton->Bounds().Height()); 101 backgroundView->AddChild(fLaunchButton); 102 103 BRect buttonRect = fLaunchButton->Frame(); 104 fLaunchAndMakeDefaultButton = new BButton(buttonRect, "make default", 105 "Open and Make Preferred", new BMessage(kOpenAndMakeDefault), 106 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 107 // wide button, have to resize to fit text 108 fLaunchAndMakeDefaultButton->ResizeToPreferred(); 109 fLaunchAndMakeDefaultButton->MoveBy( 110 - 10 - fLaunchAndMakeDefaultButton->Bounds().Width(), 0); 111 backgroundView->AddChild(fLaunchAndMakeDefaultButton); 112 fLaunchAndMakeDefaultButton->SetEnabled(false); 113 114 buttonRect = fLaunchAndMakeDefaultButton->Frame(); 115 BButton *button = new BButton(buttonRect, "cancel", "Cancel", 116 new BMessage(kCancelButton), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 117 button->ResizeToPreferred(); 118 button->MoveBy(- 10 - button->Bounds().Width(), 0); 119 backgroundView->AddChild(button); 120 121 fMinimalWidth = button->Bounds().Width() + fLaunchButton->Bounds().Width() 122 + fLaunchAndMakeDefaultButton->Bounds().Width() + kDocumentKnobWidth + 40; 123 124 fLaunchButton->MakeDefault(true); 125 126 // add pose view 127 128 rect.OffsetTo(10, 10); 129 rect.bottom = buttonRect.top - 15; 130 131 rect.right -= B_V_SCROLL_BAR_WIDTH + 20; 132 rect.bottom -= B_H_SCROLL_BAR_HEIGHT; 133 // make room for scrollbars and a margin 134 fPoseView = NewPoseView(0, rect, kListMode); 135 backgroundView->AddChild(fPoseView); 136 137 fPoseView->SetFlags(fPoseView->Flags() | B_NAVIGABLE); 138 fPoseView->SetPoseEditing(false); 139 140 // set the window title 141 if (CountRefs(fEntriesToOpen) == 1) { 142 // if opening just one file, use it in the title 143 entry_ref ref; 144 fEntriesToOpen->FindRef("refs", &ref); 145 BString buffer; 146 buffer << "Open " << ref.name << " With:"; 147 SetTitle(buffer.String()); 148 } else 149 // use generic title 150 SetTitle("Open Selection With:"); 151 152 AddCommonFilter(new BMessageFilter(B_KEY_DOWN, &OpenWithContainerWindow::KeyDownFilter)); 153 } 154 155 156 OpenWithContainerWindow::~OpenWithContainerWindow() 157 { 158 delete fEntriesToOpen; 159 } 160 161 162 BPoseView * 163 OpenWithContainerWindow::NewPoseView(Model *, BRect rect, uint32) 164 { 165 return new OpenWithPoseView(rect); 166 } 167 168 169 OpenWithPoseView * 170 OpenWithContainerWindow::PoseView() const 171 { 172 ASSERT(dynamic_cast<OpenWithPoseView *>(fPoseView)); 173 return static_cast<OpenWithPoseView *>(fPoseView); 174 } 175 176 177 const BMessage * 178 OpenWithContainerWindow::EntryList() const 179 { 180 return fEntriesToOpen; 181 } 182 183 184 void 185 OpenWithContainerWindow::OpenWithSelection() 186 { 187 int32 count = PoseView()->SelectionList()->CountItems(); 188 ASSERT(count == 1); 189 if (!count) 190 return; 191 192 PoseView()->OpenSelection(PoseView()->SelectionList()->FirstItem(), 0); 193 } 194 195 196 static const BString * 197 FindOne(const BString *element, void *castToString) 198 { 199 if (strcasecmp(element->String(), (const char *)castToString) == 0) 200 return element; 201 202 return 0; 203 } 204 205 206 static const entry_ref * 207 AddOneUniqueDocumentType(const entry_ref *ref, void *castToList) 208 { 209 BObjectList<BString> *list = (BObjectList<BString> *)castToList; 210 211 BEntry entry(ref, true); 212 // traverse symlinks 213 214 // get this documents type 215 char type[B_MIME_TYPE_LENGTH]; 216 BFile file(&entry, O_RDONLY); 217 if (file.InitCheck() != B_OK) 218 return 0; 219 220 BNodeInfo info(&file); 221 if (info.GetType(type) != B_OK) 222 return 0; 223 224 if (list->EachElement(FindOne, &type)) 225 // type already in list, bail 226 return 0; 227 228 // add type to list 229 list->AddItem(new BString(type)); 230 return 0; 231 } 232 233 234 static const BString * 235 SetDefaultAppForOneType(const BString *element, void *castToEntryRef) 236 { 237 const entry_ref *appRef = (const entry_ref *)castToEntryRef; 238 239 // set entry as default handler for one mime string 240 BMimeType mime(element->String()); 241 if (!mime.IsInstalled()) 242 return 0; 243 244 // first set it's app signature as the preferred type 245 BFile appFile(appRef, O_RDONLY); 246 if (appFile.InitCheck() != B_OK) 247 return 0; 248 249 char appSignature[B_MIME_TYPE_LENGTH]; 250 if (GetAppSignatureFromAttr(&appFile, appSignature) != B_OK) 251 return 0; 252 253 if (mime.SetPreferredApp(appSignature) != B_OK) 254 return 0; 255 256 // set the app hint on the metamime for this signature 257 mime.SetTo(appSignature); 258 #if xDEBUG 259 status_t result = 260 #endif 261 mime.SetAppHint(appRef); 262 263 #if xDEBUG 264 BEntry debugEntry(appRef); 265 BPath debugPath; 266 debugEntry.GetPath(&debugPath); 267 268 PRINT(("setting %s, sig %s as default app for %s, result %s\n", 269 debugPath.Path(), appSignature, element->String(), strerror(result))); 270 #endif 271 272 return 0; 273 } 274 275 276 void 277 OpenWithContainerWindow::MakeDefaultAndOpen() 278 { 279 int32 count = PoseView()->SelectionList()->CountItems(); 280 ASSERT(count == 1); 281 if (!count) 282 return; 283 284 BPose *selectedAppPose = PoseView()->SelectionList()->FirstItem(); 285 ASSERT(selectedAppPose); 286 if (!selectedAppPose) 287 return; 288 289 // collect all the types of all the opened documents into a list 290 BObjectList<BString> openedFileTypes(10, true); 291 EachEntryRef(EntryList(), AddOneUniqueDocumentType, &openedFileTypes, 100); 292 293 // set the default application to be the selected pose for all the 294 // mime types in the list 295 openedFileTypes.EachElement(SetDefaultAppForOneType, 296 (void *)selectedAppPose->TargetModel()->EntryRef()); 297 298 // done setting the default application, now launch the app with the 299 // documents 300 OpenWithSelection(); 301 } 302 303 304 void 305 OpenWithContainerWindow::MessageReceived(BMessage *message) 306 { 307 switch (message->what) { 308 case kDefaultButton: 309 OpenWithSelection(); 310 PostMessage(B_QUIT_REQUESTED); 311 return; 312 313 case kOpenAndMakeDefault: 314 MakeDefaultAndOpen(); 315 PostMessage(B_QUIT_REQUESTED); 316 return; 317 318 case kCancelButton: 319 PostMessage(B_QUIT_REQUESTED); 320 return; 321 } 322 _inherited::MessageReceived(message); 323 } 324 325 326 filter_result 327 OpenWithContainerWindow::KeyDownFilter(BMessage *message, BHandler **, 328 BMessageFilter *filter) 329 { 330 uchar key; 331 if (message->FindInt8("byte", (int8 *)&key) != B_OK) 332 return B_DISPATCH_MESSAGE; 333 334 int32 modifier=0; 335 message->FindInt32("modifiers", &modifier); 336 if (!modifier && key == B_ESCAPE) { 337 filter->Looper()->PostMessage(kCancelButton); 338 return B_SKIP_MESSAGE; 339 } 340 341 return B_DISPATCH_MESSAGE; 342 } 343 344 345 bool 346 OpenWithContainerWindow::ShouldAddMenus() const 347 { 348 return false; 349 } 350 351 352 void 353 OpenWithContainerWindow::ShowContextMenu(BPoint, const entry_ref *, BView *) 354 { 355 } 356 357 358 void 359 OpenWithContainerWindow::AddShortcuts() 360 { 361 // add get info here 362 } 363 364 365 void 366 OpenWithContainerWindow::NewAttributeMenu(BMenu *menu) 367 { 368 _inherited::NewAttributeMenu(menu); 369 BMessage *message = new BMessage(kAttributeItem); 370 message->AddString("attr_name", kAttrOpenWithRelation); 371 message->AddInt32("attr_type", B_STRING_TYPE); 372 message->AddInt32("attr_hash", (int32)AttrHashString(kAttrOpenWithRelation, B_STRING_TYPE)); 373 message->AddFloat("attr_width", 180); 374 message->AddInt32("attr_align", B_ALIGN_LEFT); 375 message->AddBool("attr_editable", false); 376 message->AddBool("attr_statfield", false); 377 BMenuItem *item = new BMenuItem("Relation", message); 378 menu->AddItem(item); 379 message = new BMessage(kAttributeItem); 380 message->AddString("attr_name", kAttrAppVersion); 381 message->AddInt32("attr_type", B_STRING_TYPE); 382 message->AddInt32("attr_hash", (int32)AttrHashString(kAttrAppVersion, B_STRING_TYPE)); 383 message->AddFloat("attr_width", 70); 384 message->AddInt32("attr_align", B_ALIGN_LEFT); 385 message->AddBool("attr_editable", false); 386 message->AddBool("attr_statfield", false); 387 item = new BMenuItem("Version", message); 388 menu->AddItem(item); 389 } 390 391 392 void 393 OpenWithContainerWindow::SaveState(bool) 394 { 395 BNode defaultingNode; 396 if (DefaultStateSourceNode(kDefaultOpenWithTemplate, &defaultingNode, 397 true, false)) { 398 AttributeStreamFileNode streamNodeDestination(&defaultingNode); 399 SaveWindowState(&streamNodeDestination); 400 fPoseView->SaveState(&streamNodeDestination); 401 } 402 } 403 404 405 void 406 OpenWithContainerWindow::SaveState(BMessage &message) const 407 { 408 _inherited::SaveState(message); 409 } 410 411 412 void 413 OpenWithContainerWindow::Init(const BMessage *message) 414 { 415 _inherited::Init(message); 416 } 417 418 419 void 420 OpenWithContainerWindow::RestoreState() 421 { 422 BNode defaultingNode; 423 if (DefaultStateSourceNode(kDefaultOpenWithTemplate, &defaultingNode, false)) { 424 AttributeStreamFileNode streamNodeSource(&defaultingNode); 425 RestoreWindowState(&streamNodeSource); 426 fPoseView->Init(&streamNodeSource); 427 } else { 428 RestoreWindowState(NULL); 429 fPoseView->Init(NULL); 430 } 431 } 432 433 434 void 435 OpenWithContainerWindow::RestoreState(const BMessage &message) 436 { 437 _inherited::RestoreState(message); 438 } 439 440 441 void 442 OpenWithContainerWindow::RestoreWindowState(AttributeStreamNode *node) 443 { 444 SetSizeLimits(fMinimalWidth, 10000, 160, 10000); 445 if (!node) 446 return; 447 448 const char *rectAttributeName = kAttrWindowFrame; 449 BRect frame(Frame()); 450 if (node->Read(rectAttributeName, 0, B_RECT_TYPE, sizeof(BRect), &frame) 451 == sizeof(BRect)) { 452 MoveTo(frame.LeftTop()); 453 ResizeTo(frame.Width(), frame.Height()); 454 } 455 } 456 457 458 void 459 OpenWithContainerWindow::RestoreWindowState(const BMessage &message) 460 { 461 _inherited::RestoreWindowState(message); 462 } 463 464 465 bool 466 OpenWithContainerWindow::NeedsDefaultStateSetup() 467 { 468 return true; 469 } 470 471 472 void 473 OpenWithContainerWindow::SetUpDefaultState() 474 { 475 } 476 477 478 bool 479 OpenWithContainerWindow::IsShowing(const node_ref *) const 480 { 481 return false; 482 } 483 484 485 bool 486 OpenWithContainerWindow::IsShowing(const entry_ref *) const 487 { 488 return false; 489 } 490 491 492 void 493 OpenWithContainerWindow::SetCanSetAppAsDefault(bool on) 494 { 495 fLaunchAndMakeDefaultButton->SetEnabled(on); 496 } 497 498 499 void 500 OpenWithContainerWindow::SetCanOpen(bool on) 501 { 502 fLaunchButton->SetEnabled(on); 503 } 504 505 506 // #pragma mark - 507 508 509 OpenWithPoseView::OpenWithPoseView(BRect frame, uint32 resizeMask) 510 : BPoseView(0, frame, kListMode, resizeMask), 511 fHaveCommonPreferredApp(false), 512 fIterator(NULL) 513 { 514 fSavePoseLocations = false; 515 fMultipleSelection = false; 516 fDragEnabled = false; 517 } 518 519 520 OpenWithContainerWindow * 521 OpenWithPoseView::ContainerWindow() const 522 { 523 ASSERT(dynamic_cast<OpenWithContainerWindow *>(Window())); 524 return static_cast<OpenWithContainerWindow *>(Window()); 525 } 526 527 528 void 529 OpenWithPoseView::AttachedToWindow() 530 { 531 _inherited::AttachedToWindow(); 532 SetViewColor(kOpenWithDefaultColor); 533 SetLowColor(kOpenWithDefaultColor); 534 } 535 536 537 bool 538 OpenWithPoseView::CanHandleDragSelection(const Model *, const BMessage *, bool) 539 { 540 return false; 541 } 542 543 544 static void 545 AddSupportingAppForTypeToQuery(SearchForSignatureEntryList *queryIterator, 546 const char *type) 547 { 548 // get supporting apps for type 549 BMimeType mime(type); 550 if (!mime.IsInstalled()) 551 return; 552 553 BMessage message; 554 mime.GetSupportingApps(&message); 555 556 // push each of the supporting apps signature uniquely 557 558 const char *signature; 559 for (int32 index = 0; message.FindString("applications", index, 560 &signature) == B_OK; index++) { 561 queryIterator->PushUniqueSignature(signature); 562 } 563 } 564 565 566 static const entry_ref * 567 AddOneRefSignatures(const entry_ref *ref, void *castToIterator) 568 { 569 // ToDo: 570 // resolve cases where each entry has a different type and 571 // their supporting apps are disjoint sets 572 573 SearchForSignatureEntryList *queryIterator = 574 (SearchForSignatureEntryList *)castToIterator; 575 576 Model model(ref, true, true); 577 if (model.InitCheck() != B_OK) 578 return NULL; 579 580 BString mimeType(model.MimeType()); 581 582 if (!mimeType.Length() || mimeType.ICompare(B_FILE_MIMETYPE) == 0) 583 // if model is of unknown type, try mimeseting it first 584 model.Mimeset(true); 585 586 bool preferredAppFromNode = false; 587 entry_ref preferredRef; 588 589 // add preferred app for file, if any 590 if (model.PreferredAppSignature()[0]) { 591 queryIterator->PushUniqueSignature(model.PreferredAppSignature()); 592 593 // got one, mark it as preferred for this node 594 if (be_roster->FindApp(model.PreferredAppSignature(), &preferredRef) == B_OK) { 595 preferredAppFromNode = true; 596 queryIterator->TrySettingPreferredAppForFile(&preferredRef); 597 } 598 } 599 600 mimeType = model.MimeType(); 601 mimeType.ToLower(); 602 603 if (mimeType.Length() && !mimeType.ICompare(B_FILE_MIMETYPE) == 0) 604 queryIterator->NonGenericFileFound(); 605 606 // get supporting apps for type 607 AddSupportingAppForTypeToQuery(queryIterator, mimeType.String()); 608 609 // find the preferred app for this type 610 if (be_roster->FindApp(mimeType.String(), &preferredRef) == B_OK) 611 queryIterator->TrySettingPreferredApp(&preferredRef); 612 613 return NULL; 614 } 615 616 617 EntryListBase * 618 OpenWithPoseView::InitDirentIterator(const entry_ref *) 619 { 620 OpenWithContainerWindow *window = ContainerWindow(); 621 622 const BMessage *entryList = window->EntryList(); 623 624 fIterator = new SearchForSignatureEntryList(true); 625 626 // push all the supporting apps from all the entries into the 627 // search for signature iterator 628 EachEntryRef(entryList, AddOneRefSignatures, fIterator, 100); 629 630 // push superhandlers 631 AddSupportingAppForTypeToQuery(fIterator, B_FILE_MIMETYPE); 632 fHaveCommonPreferredApp = fIterator->GetPreferredApp(&fPreferredRef); 633 634 if (fIterator->Rewind() != B_OK) { 635 delete fIterator; 636 fIterator = NULL; 637 HideBarberPole(); 638 return NULL; 639 } 640 return fIterator; 641 } 642 643 644 void 645 OpenWithPoseView::OpenSelection(BPose *pose, int32 *) 646 { 647 OpenWithContainerWindow *window = ContainerWindow(); 648 649 int32 count = fSelectionList->CountItems(); 650 if (!count) 651 return; 652 653 if (!pose) 654 pose = fSelectionList->FirstItem(); 655 656 ASSERT(pose); 657 658 BEntry entry(pose->TargetModel()->EntryRef()); 659 if (entry.InitCheck() != B_OK) { 660 BString errorString; 661 errorString << "Could not find application \"" 662 << pose->TargetModel()->Name() << "\""; 663 664 (new BAlert("", errorString.String(), "OK", 0, 0, B_WIDTH_AS_USUAL, 665 B_WARNING_ALERT))->Go(); 666 return; 667 } 668 669 if (OpenWithRelation(pose->TargetModel()) == kNoRelation) { 670 if (!fIterator->GenericFilesOnly()) { 671 BString warning; 672 warning << "The application \"" << pose->TargetModel()->Name() 673 << "\" does not support the type of document you are " 674 "about to open. Are you sure you want to proceed? If you know that " 675 "the application supports the document type, you should contact the " 676 "publisher of the application and ask them to update their application " 677 "to list the type of your document as supported."; 678 679 if ((new BAlert("", warning.String(), "Cancel", "Open", 0, 680 B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go() == 0) 681 return; 682 } 683 // else - once we have an extensible sniffer, tell users to ask 684 // publishers to fix up sniffers 685 } 686 687 688 BMessage message(*window->EntryList()); 689 // make a clone to send 690 message.RemoveName("launchUsingSelector"); 691 // make sure the old selector is not in the message 692 message.AddRef("handler", pose->TargetModel()->EntryRef()); 693 // add ref of the selected handler 694 695 ASSERT(fSelectionHandler); 696 697 if (fSelectionHandler) 698 fSelectionHandler->PostMessage(&message); 699 700 window->PostMessage(B_QUIT_REQUESTED); 701 } 702 703 704 void 705 OpenWithPoseView::Pulse() 706 { 707 // disable the Open and make default button if the default 708 // app matches the selected app 709 // 710 // disable the Open button if no apps selected 711 712 OpenWithContainerWindow *window = ContainerWindow(); 713 714 if (!fSelectionList->CountItems()) { 715 window->SetCanSetAppAsDefault(false); 716 window->SetCanOpen(false); 717 _inherited::Pulse(); 718 return; 719 } 720 721 // if we selected a non-handling application, don't allow setting 722 // it as preferred 723 Model *firstSelected = fSelectionList->FirstItem()->TargetModel(); 724 if (OpenWithRelation(firstSelected) == kNoRelation) { 725 window->SetCanSetAppAsDefault(false); 726 window->SetCanOpen(true); 727 _inherited::Pulse(); 728 return; 729 } 730 731 // make the open button enabled, because we have na app selected 732 window->SetCanOpen(true); 733 if (!fHaveCommonPreferredApp) { 734 window->SetCanSetAppAsDefault(true); 735 _inherited::Pulse(); 736 return; 737 } 738 739 ASSERT(fSelectionList->CountItems() == 1); 740 741 // enable the Open and make default if selected application different 742 // from preferred app ref 743 window->SetCanSetAppAsDefault((*fSelectionList->FirstItem()-> 744 TargetModel()->EntryRef()) != fPreferredRef); 745 746 _inherited::Pulse(); 747 } 748 749 750 void 751 OpenWithPoseView::SetUpDefaultColumnsIfNeeded() 752 { 753 // in case there were errors getting some columns 754 if (fColumnList->CountItems() != 0) 755 return; 756 757 BColumn *nameColumn = new BColumn("Name", kColumnStart, 125, B_ALIGN_LEFT, 758 kAttrStatName, B_STRING_TYPE, true, true); 759 fColumnList->AddItem(nameColumn); 760 BColumn *relationColumn = new BColumn("Relation", 180, 100, B_ALIGN_LEFT, 761 kAttrOpenWithRelation, B_STRING_TYPE, false, false); 762 fColumnList->AddItem(relationColumn); 763 fColumnList->AddItem(new BColumn("Path", 290, 225, B_ALIGN_LEFT, 764 kAttrPath, B_STRING_TYPE, true, false)); 765 fColumnList->AddItem(new BColumn("Version", 525, 70, B_ALIGN_LEFT, 766 kAttrAppVersion, B_STRING_TYPE, false, false)); 767 768 // sort by relation and by name 769 SetPrimarySort(relationColumn->AttrHash()); 770 SetSecondarySort(nameColumn->AttrHash()); 771 } 772 773 774 bool 775 OpenWithPoseView::AddPosesThreadValid(const entry_ref *) const 776 { 777 return true; 778 } 779 780 781 void 782 OpenWithPoseView::CreatePoses(Model **models, PoseInfo *poseInfoArray, int32 count, 783 BPose **resultingPoses, bool insertionSort, int32 *lastPoseIndexPtr, 784 BRect *boundsPtr, bool forceDraw) 785 { 786 // overridden to try to select the preferred handling app 787 _inherited::CreatePoses(models, poseInfoArray, count, resultingPoses, insertionSort, 788 lastPoseIndexPtr, boundsPtr, forceDraw); 789 790 if (resultingPoses) 791 for (int32 index = 0; index < count; index++) 792 if (resultingPoses[index] && fHaveCommonPreferredApp 793 && *(models[index]->EntryRef()) == fPreferredRef) 794 // this is our preferred app, select it's pose 795 SelectPose(resultingPoses[index], IndexOfPose(resultingPoses[index])); 796 } 797 798 799 void 800 OpenWithPoseView::KeyDown(const char *bytes, int32 count) 801 { 802 if (bytes[0] == B_TAB) 803 // just shift the focus, don't tab to the next pose 804 BView::KeyDown(bytes, count); 805 else 806 _inherited::KeyDown(bytes, count); 807 } 808 809 810 void 811 OpenWithPoseView::SaveState(AttributeStreamNode *node) 812 { 813 _inherited::SaveState(node); 814 } 815 816 817 void 818 OpenWithPoseView::RestoreState(AttributeStreamNode *node) 819 { 820 _inherited::RestoreState(node); 821 fViewState->SetViewMode(kListMode); 822 } 823 824 825 void 826 OpenWithPoseView::SaveState(BMessage &message) const 827 { 828 _inherited::SaveState(message); 829 } 830 831 832 void 833 OpenWithPoseView::RestoreState(const BMessage &message) 834 { 835 _inherited::RestoreState(message); 836 fViewState->SetViewMode(kListMode); 837 } 838 839 840 void 841 OpenWithPoseView::SavePoseLocations(BRect *) 842 { 843 // do nothing 844 } 845 846 847 void 848 OpenWithPoseView::MoveSelectionToTrash(bool) 849 { 850 } 851 852 853 void 854 OpenWithPoseView::MoveSelectionTo(BPoint, BPoint, BContainerWindow *) 855 { 856 } 857 858 859 void 860 OpenWithPoseView::MoveSelectionInto(Model *, BContainerWindow *, bool, bool) 861 { 862 } 863 864 865 bool 866 OpenWithPoseView::Represents(const node_ref *) const 867 { 868 return false; 869 } 870 871 872 bool 873 OpenWithPoseView::Represents(const entry_ref *) const 874 { 875 return false; 876 } 877 878 879 bool 880 OpenWithPoseView::HandleMessageDropped(BMessage *DEBUG_ONLY(message)) 881 { 882 #if DEBUG 883 // in debug mode allow tweaking the colors 884 const rgb_color *color; 885 int32 size; 886 // handle roColour-style color drops 887 if (message->FindData("RGBColor", 'RGBC', (const void **)&color, &size) == B_OK) { 888 SetViewColor(*color); 889 SetLowColor(*color); 890 Invalidate(); 891 return true; 892 } 893 #endif 894 return false; 895 } 896 897 898 int32 899 OpenWithPoseView::OpenWithRelation(const Model *model) const 900 { 901 OpenWithContainerWindow *window = ContainerWindow(); 902 903 return SearchForSignatureEntryList::Relation(window->EntryList(), 904 model, fHaveCommonPreferredApp ? &fPreferredRef : 0, 0); 905 } 906 907 908 void 909 OpenWithPoseView::OpenWithRelationDescription(const Model *model, 910 BString *description) const 911 { 912 OpenWithContainerWindow *window = ContainerWindow(); 913 914 SearchForSignatureEntryList::RelationDescription(window->EntryList(), 915 model, description, fHaveCommonPreferredApp ? &fPreferredRef : 0, 0); 916 } 917 918 919 bool 920 OpenWithPoseView::ShouldShowPose(const Model *model, const PoseInfo *poseInfo) 921 { 922 OpenWithContainerWindow *window = ContainerWindow(); 923 // filter for add_poses 924 if (!fIterator->CanOpenWithFilter(model, window->EntryList(), 925 fHaveCommonPreferredApp ? &fPreferredRef : 0)) 926 return false; 927 928 return _inherited::ShouldShowPose(model, poseInfo); 929 } 930 931 932 // #pragma mark - 933 934 935 RelationCachingModelProxy::RelationCachingModelProxy(Model *model) 936 : 937 fModel(model), 938 fRelation(kUnknownRelation) 939 { 940 } 941 942 943 RelationCachingModelProxy::~RelationCachingModelProxy() 944 { 945 delete fModel; 946 } 947 948 949 int32 950 RelationCachingModelProxy::Relation(SearchForSignatureEntryList *iterator, 951 BMessage *entries) const 952 { 953 if (fRelation == kUnknownRelation) 954 fRelation = iterator->Relation(entries, fModel); 955 956 return fRelation; 957 } 958 959 960 // #pragma mark - 961 962 963 OpenWithMenu::OpenWithMenu(const char *label, const BMessage *entriesToOpen, 964 BWindow *parentWindow, BHandler *target) 965 : BSlowMenu(label), 966 fEntriesToOpen(*entriesToOpen), 967 target(target), 968 fIterator(NULL), 969 fSupportingAppList(NULL), 970 fParentWindow(parentWindow) 971 { 972 InitIconPreloader(); 973 974 SetFont(be_plain_font); 975 976 // too long to have triggers 977 SetTriggersEnabled(false); 978 } 979 980 981 OpenWithMenu::OpenWithMenu(const char *label, const BMessage *entriesToOpen, 982 BWindow *parentWindow, const BMessenger &messenger) 983 : BSlowMenu(label), 984 fEntriesToOpen(*entriesToOpen), 985 target(NULL), 986 fMessenger(messenger), 987 fIterator(NULL), 988 fSupportingAppList(NULL), 989 fParentWindow(parentWindow) 990 { 991 InitIconPreloader(); 992 993 SetFont(be_plain_font); 994 995 // too long to have triggers 996 SetTriggersEnabled(false); 997 } 998 999 1000 namespace BPrivate { 1001 1002 int 1003 SortByRelationAndName(const RelationCachingModelProxy *model1, 1004 const RelationCachingModelProxy *model2, void *castToMenu) 1005 { 1006 OpenWithMenu *menu = (OpenWithMenu *)castToMenu; 1007 1008 // find out the relations of app models to the opened entries 1009 int32 relation1 = model1->Relation(menu->fIterator, &menu->fEntriesToOpen); 1010 int32 relation2 = model2->Relation(menu->fIterator, &menu->fEntriesToOpen); 1011 1012 if (relation1 < relation2) { 1013 // relation with the lowest number goes first 1014 return 1; 1015 } else if (relation1 > relation2) 1016 return -1; 1017 1018 // if relations match, sort by app name 1019 return strcmp(model1->fModel->Name(), model2->fModel->Name()); 1020 } 1021 1022 } // namespace BPrivate 1023 1024 1025 bool 1026 OpenWithMenu::StartBuildingItemList() 1027 { 1028 fIterator = new SearchForSignatureEntryList(false); 1029 // push all the supporting apps from all the entries into the 1030 // search for signature iterator 1031 EachEntryRef(&fEntriesToOpen, AddOneRefSignatures, fIterator, 100); 1032 // add superhandlers 1033 AddSupportingAppForTypeToQuery(fIterator, B_FILE_MIMETYPE); 1034 1035 fHaveCommonPreferredApp = fIterator->GetPreferredApp(&fPreferredRef); 1036 status_t error = fIterator->Rewind(); 1037 if (error != B_OK) { 1038 PRINT(("failed to initialize iterator %s\n", strerror(error))); 1039 return false; 1040 } 1041 1042 fSupportingAppList = new BObjectList<RelationCachingModelProxy>(20, true); 1043 1044 //queryRetrieval = new BStopWatch("get next entry on BQuery"); 1045 return true; 1046 } 1047 1048 1049 bool 1050 OpenWithMenu::AddNextItem() 1051 { 1052 BEntry entry; 1053 if (fIterator->GetNextEntry(&entry) != B_OK) 1054 return false; 1055 1056 Model *model = new Model(&entry, true); 1057 if (model->InitCheck() != B_OK 1058 || !fIterator->CanOpenWithFilter(model, &fEntriesToOpen, 1059 fHaveCommonPreferredApp ? &fPreferredRef : 0)) { 1060 // only allow executables, filter out multiple copies of the 1061 // Tracker, filter out version that don't list the correct types, 1062 // etc. 1063 delete model; 1064 } else 1065 fSupportingAppList->AddItem(new RelationCachingModelProxy(model)); 1066 1067 return true; 1068 } 1069 1070 1071 void 1072 OpenWithMenu::DoneBuildingItemList() 1073 { 1074 // sort by app name 1075 fSupportingAppList->SortItems(SortByRelationAndName, this); 1076 1077 // check if each app is unique 1078 bool unique = true; 1079 int32 count = fSupportingAppList->CountItems(); 1080 for (int32 index = 0; index < count - 1; index++) { 1081 // the list is sorted, just compare two adjacent models 1082 if (strcmp(fSupportingAppList->ItemAt(index)->fModel->Name(), 1083 fSupportingAppList->ItemAt(index + 1)->fModel->Name()) == 0) { 1084 unique = false; 1085 break; 1086 } 1087 } 1088 1089 // add apps as menu items 1090 BFont font; 1091 GetFont(&font); 1092 1093 int32 lastRelation = -1; 1094 for (int32 index = 0; index < count ; index++) { 1095 RelationCachingModelProxy *modelProxy = fSupportingAppList->ItemAt(index); 1096 Model *model = modelProxy->fModel; 1097 BMessage *message = new BMessage(fEntriesToOpen); 1098 message->AddRef("handler", model->EntryRef()); 1099 BContainerWindow *window = dynamic_cast<BContainerWindow *>(fParentWindow); 1100 if (window) 1101 message->AddData("nodeRefsToClose", B_RAW_TYPE, window->TargetModel()->NodeRef(), 1102 sizeof (node_ref)); 1103 1104 BString result; 1105 if (unique) { 1106 // just use the app name 1107 result = model->Name(); 1108 } else { 1109 // get a truncated full path 1110 BPath path; 1111 BEntry entry(model->EntryRef()); 1112 if (entry.GetPath(&path) != B_OK) { 1113 PRINT(("stale entry ref %s\n", model->Name())); 1114 delete message; 1115 continue; 1116 } 1117 result = path.Path(); 1118 font.TruncateString(&result, B_TRUNCATE_MIDDLE, kMaxMenuWidth); 1119 } 1120 #if DEBUG 1121 BString relationDescription; 1122 fIterator->RelationDescription(&fEntriesToOpen, model, &relationDescription); 1123 result += " ("; 1124 result += relationDescription; 1125 result += ")"; 1126 #endif 1127 1128 // divide different relations of opening with a separator 1129 int32 relation = modelProxy->Relation(fIterator, &fEntriesToOpen); 1130 if (lastRelation != -1 && relation != lastRelation) 1131 AddSeparatorItem(); 1132 lastRelation = relation; 1133 1134 ModelMenuItem *item = new ModelMenuItem(model, result.String(), message); 1135 AddItem(item); 1136 // mark item if it represents the preferred app 1137 if (fHaveCommonPreferredApp && *(model->EntryRef()) == fPreferredRef) { 1138 //PRINT(("marking item for % as preferred", model->Name())); 1139 item->SetMarked(true); 1140 } 1141 } 1142 1143 // target the menu 1144 if (target) 1145 SetTargetForItems(target); 1146 else 1147 SetTargetForItems(fMessenger); 1148 1149 if (!CountItems()) { 1150 BMenuItem *item = new BMenuItem("no supporting apps", 0); 1151 item->SetEnabled(false); 1152 AddItem(item); 1153 } 1154 } 1155 1156 1157 void 1158 OpenWithMenu::ClearMenuBuildingState() 1159 { 1160 delete fIterator; 1161 fIterator = NULL; 1162 delete fSupportingAppList; 1163 fSupportingAppList = NULL; 1164 } 1165 1166 1167 // #pragma mark - 1168 1169 1170 SearchForSignatureEntryList::SearchForSignatureEntryList(bool canAddAllApps) 1171 : 1172 fIteratorList(NULL), 1173 fSignatures(20, true), 1174 fPreferredAppCount(0), 1175 fPreferredAppForFileCount(0), 1176 fGenericFilesOnly(true), 1177 fCanAddAllApps(canAddAllApps), 1178 fFoundOneNonSuperHandler(false) 1179 { 1180 } 1181 1182 1183 SearchForSignatureEntryList::~SearchForSignatureEntryList() 1184 { 1185 delete fIteratorList; 1186 } 1187 1188 1189 void 1190 SearchForSignatureEntryList::PushUniqueSignature(const char *str) 1191 { 1192 // do a unique add 1193 if (fSignatures.EachElement(FindOne, (void *)str)) 1194 return; 1195 1196 fSignatures.AddItem(new BString(str)); 1197 } 1198 1199 1200 status_t 1201 SearchForSignatureEntryList::GetNextEntry(BEntry *entry, bool) 1202 { 1203 return fIteratorList->GetNextEntry(entry); 1204 } 1205 1206 1207 status_t 1208 SearchForSignatureEntryList::GetNextRef(entry_ref *ref) 1209 { 1210 return fIteratorList->GetNextRef(ref); 1211 } 1212 1213 1214 int32 1215 SearchForSignatureEntryList::GetNextDirents(struct dirent *buffer, 1216 size_t length, int32 count) 1217 { 1218 return fIteratorList->GetNextDirents(buffer, length, count); 1219 } 1220 1221 1222 struct AddOneTermParams { 1223 BString *result; 1224 bool first; 1225 }; 1226 1227 static const BString * 1228 AddOnePredicateTerm(const BString *item, void *castToParams) 1229 { 1230 AddOneTermParams *params = (AddOneTermParams *)castToParams; 1231 if (!params->first) 1232 (*params->result) << " || "; 1233 (*params->result) << kAttrAppSignature << " = " << item->String(); 1234 1235 params->first = false; 1236 1237 return 0; 1238 } 1239 1240 1241 status_t 1242 SearchForSignatureEntryList::Rewind() 1243 { 1244 if (fIteratorList) 1245 return fIteratorList->Rewind(); 1246 1247 if (!fSignatures.CountItems()) 1248 return ENOENT; 1249 1250 // build up the iterator 1251 fIteratorList = new CachedEntryIteratorList; 1252 1253 // build the predicate string by oring queries for the individual 1254 // signatures 1255 BString predicateString; 1256 1257 AddOneTermParams params; 1258 params.result = &predicateString; 1259 params.first = true; 1260 1261 fSignatures.EachElement(AddOnePredicateTerm, ¶ms); 1262 1263 ASSERT(predicateString.Length()); 1264 // PRINT(("query predicate %s\n", predicateString.String())); 1265 fIteratorList->AddItem(new TWalkerWrapper( 1266 new WALKER_NS::TQueryWalker(predicateString.String()))); 1267 fIteratorList->AddItem(new ConditionalAllAppsIterator(this)); 1268 1269 return fIteratorList->Rewind(); 1270 } 1271 1272 1273 int32 1274 SearchForSignatureEntryList::CountEntries() 1275 { 1276 return 0; 1277 } 1278 1279 1280 bool 1281 SearchForSignatureEntryList::GetPreferredApp(entry_ref *ref) const 1282 { 1283 if (fPreferredAppCount == 1) 1284 *ref = fPreferredRef; 1285 1286 return fPreferredAppCount == 1; 1287 } 1288 1289 1290 void 1291 SearchForSignatureEntryList::TrySettingPreferredApp(const entry_ref *ref) 1292 { 1293 if (!fPreferredAppCount) { 1294 fPreferredRef = *ref; 1295 fPreferredAppCount++; 1296 } else if (fPreferredRef != *ref) 1297 // if more than one, will not return any 1298 fPreferredAppCount++; 1299 } 1300 1301 1302 void 1303 SearchForSignatureEntryList::TrySettingPreferredAppForFile(const entry_ref *ref) 1304 { 1305 if (!fPreferredAppForFileCount) { 1306 fPreferredRefForFile = *ref; 1307 fPreferredAppForFileCount++; 1308 } else if (fPreferredRefForFile != *ref) { 1309 // if more than one, will not return any 1310 fPreferredAppForFileCount++; 1311 } 1312 } 1313 1314 1315 void 1316 SearchForSignatureEntryList::NonGenericFileFound() 1317 { 1318 fGenericFilesOnly = false; 1319 } 1320 1321 1322 bool 1323 SearchForSignatureEntryList::GenericFilesOnly() const 1324 { 1325 return fGenericFilesOnly; 1326 } 1327 1328 1329 bool 1330 SearchForSignatureEntryList::ShowAllApplications() const 1331 { 1332 return fCanAddAllApps && !fFoundOneNonSuperHandler; 1333 } 1334 1335 1336 int32 1337 SearchForSignatureEntryList::Relation(const Model *nodeModel, 1338 const Model *applicationModel) 1339 { 1340 switch (applicationModel->SupportsMimeType(nodeModel->MimeType(), 0, true)) { 1341 case kDoesNotSupportType: 1342 return kNoRelation; 1343 1344 case kSuperhandlerModel: 1345 return kSuperhandler; 1346 1347 case kModelSupportsSupertype: 1348 return kSupportsSupertype; 1349 1350 case kModelSupportsType: 1351 return kSupportsType; 1352 } 1353 1354 TRESPASS(); 1355 return kNoRelation; 1356 } 1357 1358 1359 int32 1360 SearchForSignatureEntryList::Relation(const BMessage *entriesToOpen, 1361 const Model *model) const 1362 { 1363 return Relation(entriesToOpen, model, 1364 fPreferredAppCount == 1 ? &fPreferredRef : 0, 1365 fPreferredAppForFileCount == 1 ? &fPreferredRefForFile : 0); 1366 } 1367 1368 1369 void 1370 SearchForSignatureEntryList::RelationDescription(const BMessage *entriesToOpen, 1371 const Model *model, BString *description) const 1372 { 1373 RelationDescription(entriesToOpen, model, description, 1374 fPreferredAppCount == 1 ? &fPreferredRef : 0, 1375 fPreferredAppForFileCount == 1 ? &fPreferredRefForFile : 0); 1376 } 1377 1378 1379 int32 1380 SearchForSignatureEntryList::Relation(const BMessage *entriesToOpen, 1381 const Model *applicationModel, const entry_ref *preferredApp, 1382 const entry_ref *preferredAppForFile) 1383 { 1384 for (int32 index = 0; ; index++) { 1385 entry_ref ref; 1386 if (entriesToOpen->FindRef("refs", index, &ref) != B_OK) 1387 break; 1388 1389 // need to init a model so that typeless folders etc. will still appear to 1390 // have a mime type 1391 1392 Model model(&ref, true, true); 1393 if (model.InitCheck()) 1394 continue; 1395 1396 int32 result = Relation(&model, applicationModel); 1397 if (result != kNoRelation) { 1398 if (preferredAppForFile 1399 && *applicationModel->EntryRef() == *preferredAppForFile) 1400 return kPreferredForFile; 1401 1402 if (result == kSupportsType && preferredApp 1403 && *applicationModel->EntryRef() == *preferredApp) 1404 // application matches cached preferred app, we are done 1405 return kPreferredForType; 1406 1407 return result; 1408 } 1409 } 1410 1411 return kNoRelation; 1412 } 1413 1414 1415 void 1416 SearchForSignatureEntryList::RelationDescription(const BMessage *entriesToOpen, 1417 const Model *applicationModel, BString *description, const entry_ref *preferredApp, 1418 const entry_ref *preferredAppForFile) 1419 { 1420 for (int32 index = 0; ;index++) { 1421 entry_ref ref; 1422 if (entriesToOpen->FindRef("refs", index, &ref) != B_OK) 1423 break; 1424 1425 if (preferredAppForFile && ref == *preferredAppForFile) { 1426 *description = "Preferred for file"; 1427 return; 1428 } 1429 1430 Model model(&ref, true, true); 1431 if (model.InitCheck()) 1432 continue; 1433 1434 BMimeType mimeType; 1435 int32 result = Relation(&model, applicationModel); 1436 switch (result) { 1437 case kDoesNotSupportType: 1438 continue; 1439 1440 case kSuperhandler: 1441 *description = "Handles any file"; 1442 return; 1443 1444 case kSupportsSupertype: 1445 { 1446 mimeType.SetTo(model.MimeType()); 1447 // status_t result = mimeType.GetSupertype(&mimeType); 1448 1449 char *type = (char *)mimeType.Type(); 1450 char *tmp = strchr(type, '/'); 1451 if (tmp) 1452 *tmp = '\0'; 1453 1454 //PRINT(("getting supertype for %s, result %s, got %s\n", 1455 // model.MimeType(), strerror(result), mimeType.Type())); 1456 *description = "Handles any "; 1457 // *description += mimeType.Type(); 1458 *description += type; 1459 return; 1460 } 1461 1462 case kSupportsType: 1463 { 1464 mimeType.SetTo(model.MimeType()); 1465 1466 if (preferredApp && *applicationModel->EntryRef() == *preferredApp) 1467 // application matches cached preferred app, we are done 1468 *description = "Preferred for "; 1469 else 1470 *description = "Handles "; 1471 1472 char shortDescription[256]; 1473 if (mimeType.GetShortDescription(shortDescription) == B_OK) 1474 *description += shortDescription; 1475 else 1476 *description += mimeType.Type(); 1477 return; 1478 } 1479 } 1480 } 1481 1482 *description = "Does not handle file"; 1483 } 1484 1485 1486 bool 1487 SearchForSignatureEntryList::CanOpenWithFilter(const Model *appModel, 1488 const BMessage *entriesToOpen, const entry_ref *preferredApp) 1489 { 1490 if (!appModel->IsExecutable() || !appModel->Node()) { 1491 // weed out non-executable 1492 #if xDEBUG 1493 BPath path; 1494 BEntry entry(appModel->EntryRef()); 1495 entry.GetPath(&path); 1496 PRINT(("filtering out %s- not executable \n", path.Path())); 1497 #endif 1498 return false; 1499 } 1500 1501 if (strcasecmp(appModel->MimeType(), B_APP_MIME_TYPE) != 0) { 1502 // filter out pe containers on PPC etc. 1503 return false; 1504 } 1505 1506 ASSERT(dynamic_cast<BFile *>(appModel->Node())); 1507 char signature[B_MIME_TYPE_LENGTH]; 1508 status_t result = GetAppSignatureFromAttr( 1509 dynamic_cast<BFile *>(appModel->Node()), signature); 1510 1511 if (result == B_OK && strcasecmp(signature, kTrackerSignature) == 0) { 1512 // special case the Tracker - make sure only the running copy is 1513 // in the list 1514 app_info trackerInfo; 1515 result = be_roster->GetActiveAppInfo(&trackerInfo); 1516 if (*appModel->EntryRef() != trackerInfo.ref) { 1517 // this is an inactive copy of the Tracker, remove it 1518 1519 #if xDEBUG 1520 BPath path, path2; 1521 BEntry entry(appModel->EntryRef()); 1522 entry.GetPath(&path); 1523 1524 BEntry entry2(&trackerInfo.ref); 1525 entry2.GetPath(&path2); 1526 1527 PRINT(("filtering out %s, sig %s, active Tracker at %s, result %s, refName %s\n", 1528 path.Path(), signature, path2.Path(), strerror(result), 1529 trackerInfo.ref.name)); 1530 #endif 1531 return false; 1532 } 1533 } 1534 1535 if (FSInTrashDir(appModel->EntryRef())) 1536 return false; 1537 1538 if (ShowAllApplications()) { 1539 // don't check for these if we didn't look for every single app 1540 // to not slow filtering down 1541 uint32 flags; 1542 BAppFileInfo appFileInfo(dynamic_cast<BFile *>(appModel->Node())); 1543 if (appFileInfo.GetAppFlags(&flags) != B_OK) 1544 return false; 1545 1546 if ((flags & B_BACKGROUND_APP) || (flags & B_ARGV_ONLY)) 1547 return false; 1548 1549 if (!signature[0]) 1550 // weed out apps with empty signatures 1551 return false; 1552 } 1553 1554 int32 relation = Relation(entriesToOpen, appModel, preferredApp, 0); 1555 if (relation == kNoRelation && !ShowAllApplications()) { 1556 #if xDEBUG 1557 BPath path; 1558 BEntry entry(appModel->EntryRef()); 1559 entry.GetPath(&path); 1560 1561 PRINT(("filtering out %s, does not handle any of opened files\n", 1562 path.Path())); 1563 #endif 1564 return false; 1565 } 1566 1567 if (relation != kNoRelation && relation != kSuperhandler && !fGenericFilesOnly) { 1568 // we hit at least one app that is not a superhandler and 1569 // handles the document 1570 fFoundOneNonSuperHandler = true; 1571 } 1572 1573 return true; 1574 } 1575 1576 1577 // #pragma mark - 1578 1579 1580 ConditionalAllAppsIterator::ConditionalAllAppsIterator( 1581 SearchForSignatureEntryList *parent) 1582 : 1583 fParent(parent), 1584 fWalker(NULL) 1585 { 1586 } 1587 1588 1589 void 1590 ConditionalAllAppsIterator::Instantiate() 1591 { 1592 if (fWalker) 1593 return; 1594 1595 BString lookForAppsPredicate; 1596 lookForAppsPredicate << "(" << kAttrAppSignature << " = \"*\" ) && ( " 1597 << kAttrMIMEType << " = " << B_APP_MIME_TYPE << " ) "; 1598 fWalker = new WALKER_NS::TQueryWalker(lookForAppsPredicate.String()); 1599 } 1600 1601 1602 ConditionalAllAppsIterator::~ConditionalAllAppsIterator() 1603 { 1604 delete fWalker; 1605 } 1606 1607 1608 status_t 1609 ConditionalAllAppsIterator::GetNextEntry(BEntry *entry, bool traverse) 1610 { 1611 if (!Iterate()) 1612 return B_ENTRY_NOT_FOUND; 1613 1614 Instantiate(); 1615 return fWalker->GetNextEntry(entry, traverse); 1616 } 1617 1618 1619 status_t 1620 ConditionalAllAppsIterator::GetNextRef(entry_ref *ref) 1621 { 1622 if (!Iterate()) 1623 return B_ENTRY_NOT_FOUND; 1624 1625 Instantiate(); 1626 return fWalker->GetNextRef(ref); 1627 } 1628 1629 1630 int32 1631 ConditionalAllAppsIterator::GetNextDirents(struct dirent *buffer, size_t length, int32 count) 1632 { 1633 if (!Iterate()) 1634 return 0; 1635 1636 Instantiate(); 1637 return fWalker->GetNextDirents(buffer, length, count); 1638 } 1639 1640 1641 status_t 1642 ConditionalAllAppsIterator::Rewind() 1643 { 1644 if (!Iterate()) 1645 return B_OK; 1646 1647 Instantiate(); 1648 return fWalker->Rewind(); 1649 } 1650 1651 1652 int32 1653 ConditionalAllAppsIterator::CountEntries() 1654 { 1655 if (!Iterate()) 1656 return 0; 1657 1658 Instantiate(); 1659 return fWalker->CountEntries(); 1660 } 1661 1662 1663 bool 1664 ConditionalAllAppsIterator::Iterate() const 1665 { 1666 return fParent->ShowAllApplications(); 1667 } 1668 1669