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 *signature) 547 { 548 // get supporting apps for type 549 BMimeType mime(signature); 550 if (!mime.IsInstalled()) 551 return; 552 553 BMessage message; 554 mime.GetSupportingApps(&message); 555 556 for (int32 index =0; ; index++) { 557 const char *signature; 558 int32 length; 559 560 if (message.FindData("applications", 'CSTR', index, (const void **)&signature, 561 &length) != B_OK) 562 break; 563 564 // push each of the supporting apps signature uniquely 565 queryIterator->PushUniqueSignature(signature); 566 } 567 } 568 569 570 static const entry_ref * 571 AddOneRefSignatures(const entry_ref *ref, void *castToIterator) 572 { 573 // ToDo: 574 // resolve cases where each entry has a different type and 575 // their supporting apps are disjoint sets 576 577 SearchForSignatureEntryList *queryIterator = 578 (SearchForSignatureEntryList *)castToIterator; 579 580 Model model(ref, true, true); 581 if (model.InitCheck() != B_OK) 582 return NULL; 583 584 BString mimeType(model.MimeType()); 585 586 if (!mimeType.Length() || mimeType.ICompare(B_FILE_MIMETYPE) == 0) 587 // if model is of unknown type, try mimeseting it first 588 model.Mimeset(true); 589 590 bool preferredAppFromNode = false; 591 entry_ref preferredRef; 592 593 // add preferred app for file, if any 594 if (model.PreferredAppSignature()[0]) { 595 queryIterator->PushUniqueSignature(model.PreferredAppSignature()); 596 597 // got one, mark it as preferred for this node 598 if (be_roster->FindApp(model.PreferredAppSignature(), &preferredRef) == B_OK) { 599 preferredAppFromNode = true; 600 queryIterator->TrySettingPreferredAppForFile(&preferredRef); 601 } 602 } 603 604 mimeType = model.MimeType(); 605 mimeType.ToLower(); 606 607 if (mimeType.Length() && !mimeType.ICompare(B_FILE_MIMETYPE) == 0) 608 queryIterator->NonGenericFileFound(); 609 610 // get supporting apps for type 611 AddSupportingAppForTypeToQuery(queryIterator, mimeType.String()); 612 613 // find the preferred app for this type 614 if (be_roster->FindApp(mimeType.String(), &preferredRef) == B_OK) 615 queryIterator->TrySettingPreferredApp(&preferredRef); 616 617 return NULL; 618 } 619 620 621 EntryListBase * 622 OpenWithPoseView::InitDirentIterator(const entry_ref *) 623 { 624 OpenWithContainerWindow *window = ContainerWindow(); 625 626 const BMessage *entryList = window->EntryList(); 627 628 fIterator = new SearchForSignatureEntryList(true); 629 630 // push all the supporting apps from all the entries into the 631 // search for signature iterator 632 EachEntryRef(entryList, AddOneRefSignatures, fIterator, 100); 633 634 // push superhandlers 635 AddSupportingAppForTypeToQuery(fIterator, B_FILE_MIMETYPE); 636 fHaveCommonPreferredApp = fIterator->GetPreferredApp(&fPreferredRef); 637 638 if (fIterator->Rewind() != B_OK) { 639 delete fIterator; 640 fIterator = NULL; 641 HideBarberPole(); 642 return NULL; 643 } 644 return fIterator; 645 } 646 647 648 void 649 OpenWithPoseView::OpenSelection(BPose *pose, int32 *) 650 { 651 OpenWithContainerWindow *window = ContainerWindow(); 652 653 int32 count = fSelectionList->CountItems(); 654 if (!count) 655 return; 656 657 if (!pose) 658 pose = fSelectionList->FirstItem(); 659 660 ASSERT(pose); 661 662 BEntry entry(pose->TargetModel()->EntryRef()); 663 if (entry.InitCheck() != B_OK) { 664 BString errorString; 665 errorString << "Could not find application \"" 666 << pose->TargetModel()->Name() << "\""; 667 668 (new BAlert("", errorString.String(), "OK", 0, 0, B_WIDTH_AS_USUAL, 669 B_WARNING_ALERT))->Go(); 670 return; 671 } 672 673 if (OpenWithRelation(pose->TargetModel()) == kNoRelation) { 674 if (!fIterator->GenericFilesOnly()) { 675 BString warning; 676 warning << "The application \"" << pose->TargetModel()->Name() 677 << "\" does not support the type of document you are " 678 "about to open. Are you sure you want to proceed? If you know that " 679 "the application supports the document type, you should contact the " 680 "publisher of the application and ask them to update their application " 681 "to list the type of your document as supported."; 682 683 if ((new BAlert("", warning.String(), "Cancel", "Open", 0, 684 B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go() == 0) 685 return; 686 } 687 // else - once we have an extensible sniffer, tell users to ask 688 // publishers to fix up sniffers 689 } 690 691 692 BMessage message(*window->EntryList()); 693 // make a clone to send 694 message.RemoveName("launchUsingSelector"); 695 // make sure the old selector is not in the message 696 message.AddRef("handler", pose->TargetModel()->EntryRef()); 697 // add ref of the selected handler 698 699 ASSERT(fSelectionHandler); 700 701 if (fSelectionHandler) 702 fSelectionHandler->PostMessage(&message); 703 704 window->PostMessage(B_QUIT_REQUESTED); 705 } 706 707 708 void 709 OpenWithPoseView::Pulse() 710 { 711 // disable the Open and make default button if the default 712 // app matches the selected app 713 // 714 // disable the Open button if no apps selected 715 716 OpenWithContainerWindow *window = ContainerWindow(); 717 718 if (!fSelectionList->CountItems()) { 719 window->SetCanSetAppAsDefault(false); 720 window->SetCanOpen(false); 721 _inherited::Pulse(); 722 return; 723 } 724 725 // if we selected a non-handling application, don't allow setting 726 // it as preferred 727 Model *firstSelected = fSelectionList->FirstItem()->TargetModel(); 728 if (OpenWithRelation(firstSelected) == kNoRelation) { 729 window->SetCanSetAppAsDefault(false); 730 window->SetCanOpen(true); 731 _inherited::Pulse(); 732 return; 733 } 734 735 // make the open button enabled, because we have na app selected 736 window->SetCanOpen(true); 737 if (!fHaveCommonPreferredApp) { 738 window->SetCanSetAppAsDefault(true); 739 _inherited::Pulse(); 740 return; 741 } 742 743 ASSERT(fSelectionList->CountItems() == 1); 744 745 // enable the Open and make default if selected application different 746 // from preferred app ref 747 window->SetCanSetAppAsDefault((*fSelectionList->FirstItem()-> 748 TargetModel()->EntryRef()) != fPreferredRef); 749 750 _inherited::Pulse(); 751 } 752 753 754 void 755 OpenWithPoseView::SetUpDefaultColumnsIfNeeded() 756 { 757 // in case there were errors getting some columns 758 if (fColumnList->CountItems() != 0) 759 return; 760 761 BColumn *nameColumn = new BColumn("Name", kColumnStart, 125, B_ALIGN_LEFT, 762 kAttrStatName, B_STRING_TYPE, true, true); 763 fColumnList->AddItem(nameColumn); 764 BColumn *relationColumn = new BColumn("Relation", 180, 100, B_ALIGN_LEFT, 765 kAttrOpenWithRelation, B_STRING_TYPE, false, false); 766 fColumnList->AddItem(relationColumn); 767 fColumnList->AddItem(new BColumn("Path", 290, 225, B_ALIGN_LEFT, 768 kAttrPath, B_STRING_TYPE, true, false)); 769 fColumnList->AddItem(new BColumn("Version", 525, 70, B_ALIGN_LEFT, 770 kAttrAppVersion, B_STRING_TYPE, false, false)); 771 772 // sort by relation and by name 773 SetPrimarySort(relationColumn->AttrHash()); 774 SetSecondarySort(nameColumn->AttrHash()); 775 } 776 777 778 bool 779 OpenWithPoseView::AddPosesThreadValid(const entry_ref *) const 780 { 781 return true; 782 } 783 784 785 void 786 OpenWithPoseView::CreatePoses(Model **models, PoseInfo *poseInfoArray, int32 count, 787 BPose **resultingPoses, bool insertionSort, int32 *lastPoseIndexPtr, 788 BRect *boundsPtr, bool forceDraw) 789 { 790 // overridden to try to select the preferred handling app 791 _inherited::CreatePoses(models, poseInfoArray, count, resultingPoses, insertionSort, 792 lastPoseIndexPtr, boundsPtr, forceDraw); 793 794 if (resultingPoses) 795 for (int32 index = 0; index < count; index++) 796 if (resultingPoses[index] && fHaveCommonPreferredApp 797 && *(models[index]->EntryRef()) == fPreferredRef) 798 // this is our preferred app, select it's pose 799 SelectPose(resultingPoses[index], IndexOfPose(resultingPoses[index])); 800 } 801 802 803 void 804 OpenWithPoseView::KeyDown(const char *bytes, int32 count) 805 { 806 if (bytes[0] == B_TAB) 807 // just shift the focus, don't tab to the next pose 808 BView::KeyDown(bytes, count); 809 else 810 _inherited::KeyDown(bytes, count); 811 } 812 813 814 void 815 OpenWithPoseView::SaveState(AttributeStreamNode *node) 816 { 817 _inherited::SaveState(node); 818 } 819 820 821 void 822 OpenWithPoseView::RestoreState(AttributeStreamNode *node) 823 { 824 _inherited::RestoreState(node); 825 fViewState->SetViewMode(kListMode); 826 } 827 828 829 void 830 OpenWithPoseView::SaveState(BMessage &message) const 831 { 832 _inherited::SaveState(message); 833 } 834 835 836 void 837 OpenWithPoseView::RestoreState(const BMessage &message) 838 { 839 _inherited::RestoreState(message); 840 fViewState->SetViewMode(kListMode); 841 } 842 843 844 void 845 OpenWithPoseView::SavePoseLocations(BRect *) 846 { 847 // do nothing 848 } 849 850 851 void 852 OpenWithPoseView::MoveSelectionToTrash(bool) 853 { 854 } 855 856 857 void 858 OpenWithPoseView::MoveSelectionTo(BPoint, BPoint, BContainerWindow *) 859 { 860 } 861 862 863 void 864 OpenWithPoseView::MoveSelectionInto(Model *, BContainerWindow *, bool, bool) 865 { 866 } 867 868 869 bool 870 OpenWithPoseView::Represents(const node_ref *) const 871 { 872 return false; 873 } 874 875 876 bool 877 OpenWithPoseView::Represents(const entry_ref *) const 878 { 879 return false; 880 } 881 882 883 bool 884 OpenWithPoseView::HandleMessageDropped(BMessage *DEBUG_ONLY(message)) 885 { 886 #if DEBUG 887 // in debug mode allow tweaking the colors 888 const rgb_color *color; 889 int32 size; 890 // handle roColour-style color drops 891 if (message->FindData("RGBColor", 'RGBC', (const void **)&color, &size) == B_OK) { 892 SetViewColor(*color); 893 SetLowColor(*color); 894 Invalidate(); 895 return true; 896 } 897 #endif 898 return false; 899 } 900 901 902 int32 903 OpenWithPoseView::OpenWithRelation(const Model *model) const 904 { 905 OpenWithContainerWindow *window = ContainerWindow(); 906 907 return SearchForSignatureEntryList::Relation(window->EntryList(), 908 model, fHaveCommonPreferredApp ? &fPreferredRef : 0, 0); 909 } 910 911 912 void 913 OpenWithPoseView::OpenWithRelationDescription(const Model *model, 914 BString *description) const 915 { 916 OpenWithContainerWindow *window = ContainerWindow(); 917 918 SearchForSignatureEntryList::RelationDescription(window->EntryList(), 919 model, description, fHaveCommonPreferredApp ? &fPreferredRef : 0, 0); 920 } 921 922 923 bool 924 OpenWithPoseView::ShouldShowPose(const Model *model, const PoseInfo *poseInfo) 925 { 926 OpenWithContainerWindow *window = ContainerWindow(); 927 // filter for add_poses 928 if (!fIterator->CanOpenWithFilter(model, window->EntryList(), 929 fHaveCommonPreferredApp ? &fPreferredRef : 0)) 930 return false; 931 932 return _inherited::ShouldShowPose(model, poseInfo); 933 } 934 935 936 // #pragma mark - 937 938 939 RelationCachingModelProxy::RelationCachingModelProxy(Model *model) 940 : 941 fModel(model), 942 fRelation(kUnknownRelation) 943 { 944 } 945 946 947 RelationCachingModelProxy::~RelationCachingModelProxy() 948 { 949 delete fModel; 950 } 951 952 953 int32 954 RelationCachingModelProxy::Relation(SearchForSignatureEntryList *iterator, 955 BMessage *entries) const 956 { 957 if (fRelation == kUnknownRelation) 958 fRelation = iterator->Relation(entries, fModel); 959 960 return fRelation; 961 } 962 963 964 // #pragma mark - 965 966 967 OpenWithMenu::OpenWithMenu(const char *label, const BMessage *entriesToOpen, 968 BWindow *parentWindow, BHandler *target) 969 : BSlowMenu(label), 970 fEntriesToOpen(*entriesToOpen), 971 target(target), 972 fIterator(NULL), 973 fSupportingAppList(NULL), 974 fParentWindow(parentWindow) 975 { 976 InitIconPreloader(); 977 978 SetFont(be_plain_font); 979 980 // too long to have triggers 981 SetTriggersEnabled(false); 982 } 983 984 985 OpenWithMenu::OpenWithMenu(const char *label, const BMessage *entriesToOpen, 986 BWindow *parentWindow, const BMessenger &messenger) 987 : BSlowMenu(label), 988 fEntriesToOpen(*entriesToOpen), 989 target(NULL), 990 fMessenger(messenger), 991 fIterator(NULL), 992 fSupportingAppList(NULL), 993 fParentWindow(parentWindow) 994 { 995 InitIconPreloader(); 996 997 SetFont(be_plain_font); 998 999 // too long to have triggers 1000 SetTriggersEnabled(false); 1001 } 1002 1003 1004 namespace BPrivate { 1005 1006 int 1007 SortByRelationAndName(const RelationCachingModelProxy *model1, 1008 const RelationCachingModelProxy *model2, void *castToMenu) 1009 { 1010 OpenWithMenu *menu = (OpenWithMenu *)castToMenu; 1011 1012 // find out the relations of app models to the opened entries 1013 int32 relation1 = model1->Relation(menu->fIterator, &menu->fEntriesToOpen); 1014 int32 relation2 = model2->Relation(menu->fIterator, &menu->fEntriesToOpen); 1015 1016 if (relation1 < relation2) { 1017 // relation with the lowest number goes first 1018 return 1; 1019 } else if (relation1 > relation2) 1020 return -1; 1021 1022 // if relations match, sort by app name 1023 return strcmp(model1->fModel->Name(), model2->fModel->Name()); 1024 } 1025 1026 } // namespace BPrivate 1027 1028 1029 bool 1030 OpenWithMenu::StartBuildingItemList() 1031 { 1032 fIterator = new SearchForSignatureEntryList(false); 1033 // push all the supporting apps from all the entries into the 1034 // search for signature iterator 1035 EachEntryRef(&fEntriesToOpen, AddOneRefSignatures, fIterator, 100); 1036 // add superhandlers 1037 AddSupportingAppForTypeToQuery(fIterator, B_FILE_MIMETYPE); 1038 1039 fHaveCommonPreferredApp = fIterator->GetPreferredApp(&fPreferredRef); 1040 status_t error = fIterator->Rewind(); 1041 if (error != B_OK) { 1042 PRINT(("failed to initialize iterator %s\n", strerror(error))); 1043 return false; 1044 } 1045 1046 fSupportingAppList = new BObjectList<RelationCachingModelProxy>(20, true); 1047 1048 //queryRetrieval = new BStopWatch("get next entry on BQuery"); 1049 return true; 1050 } 1051 1052 1053 bool 1054 OpenWithMenu::AddNextItem() 1055 { 1056 BEntry entry; 1057 if (fIterator->GetNextEntry(&entry) != B_OK) 1058 return false; 1059 1060 Model *model = new Model(&entry, true); 1061 if (model->InitCheck() != B_OK 1062 || !fIterator->CanOpenWithFilter(model, &fEntriesToOpen, 1063 fHaveCommonPreferredApp ? &fPreferredRef : 0)) { 1064 // only allow executables, filter out multiple copies of the 1065 // Tracker, filter out version that don't list the correct types, 1066 // etc. 1067 delete model; 1068 } else 1069 fSupportingAppList->AddItem(new RelationCachingModelProxy(model)); 1070 1071 return true; 1072 } 1073 1074 1075 void 1076 OpenWithMenu::DoneBuildingItemList() 1077 { 1078 // sort by app name 1079 fSupportingAppList->SortItems(SortByRelationAndName, this); 1080 1081 // check if each app is unique 1082 bool unique = true; 1083 int32 count = fSupportingAppList->CountItems(); 1084 for (int32 index = 0; index < count - 1; index++) { 1085 // the list is sorted, just compare two adjacent models 1086 if (strcmp(fSupportingAppList->ItemAt(index)->fModel->Name(), 1087 fSupportingAppList->ItemAt(index + 1)->fModel->Name()) == 0) { 1088 unique = false; 1089 break; 1090 } 1091 } 1092 1093 // add apps as menu items 1094 BFont font; 1095 GetFont(&font); 1096 1097 int32 lastRelation = -1; 1098 for (int32 index = 0; index < count ; index++) { 1099 RelationCachingModelProxy *modelProxy = fSupportingAppList->ItemAt(index); 1100 Model *model = modelProxy->fModel; 1101 BMessage *message = new BMessage(fEntriesToOpen); 1102 message->AddRef("handler", model->EntryRef()); 1103 BContainerWindow *window = dynamic_cast<BContainerWindow *>(fParentWindow); 1104 if (window) 1105 message->AddData("nodeRefsToClose", B_RAW_TYPE, window->TargetModel()->NodeRef(), 1106 sizeof (node_ref)); 1107 1108 BString result; 1109 if (unique) { 1110 // just use the app name 1111 result = model->Name(); 1112 } else { 1113 // get a truncated full path 1114 BPath path; 1115 BEntry entry(model->EntryRef()); 1116 if (entry.GetPath(&path) != B_OK) { 1117 PRINT(("stale entry ref %s\n", model->Name())); 1118 delete message; 1119 continue; 1120 } 1121 result = path.Path(); 1122 font.TruncateString(&result, B_TRUNCATE_MIDDLE, kMaxMenuWidth); 1123 } 1124 #if DEBUG 1125 BString relationDescription; 1126 fIterator->RelationDescription(&fEntriesToOpen, model, &relationDescription); 1127 result += " ("; 1128 result += relationDescription; 1129 result += ")"; 1130 #endif 1131 1132 // divide different relations of opening with a separator 1133 int32 relation = modelProxy->Relation(fIterator, &fEntriesToOpen); 1134 if (lastRelation != -1 && relation != lastRelation) 1135 AddSeparatorItem(); 1136 lastRelation = relation; 1137 1138 ModelMenuItem *item = new ModelMenuItem(model, result.String(), message); 1139 AddItem(item); 1140 // mark item if it represents the preferred app 1141 if (fHaveCommonPreferredApp && *(model->EntryRef()) == fPreferredRef) { 1142 //PRINT(("marking item for % as preferred", model->Name())); 1143 item->SetMarked(true); 1144 } 1145 } 1146 1147 // target the menu 1148 if (target) 1149 SetTargetForItems(target); 1150 else 1151 SetTargetForItems(fMessenger); 1152 1153 if (!CountItems()) { 1154 BMenuItem *item = new BMenuItem("no supporting apps", 0); 1155 item->SetEnabled(false); 1156 AddItem(item); 1157 } 1158 } 1159 1160 1161 void 1162 OpenWithMenu::ClearMenuBuildingState() 1163 { 1164 delete fIterator; 1165 fIterator = NULL; 1166 delete fSupportingAppList; 1167 fSupportingAppList = NULL; 1168 } 1169 1170 1171 // #pragma mark - 1172 1173 1174 SearchForSignatureEntryList::SearchForSignatureEntryList(bool canAddAllApps) 1175 : 1176 fIteratorList(NULL), 1177 fSignatures(20, true), 1178 fPreferredAppCount(0), 1179 fPreferredAppForFileCount(0), 1180 fGenericFilesOnly(true), 1181 fCanAddAllApps(canAddAllApps), 1182 fFoundOneNonSuperHandler(false) 1183 { 1184 } 1185 1186 1187 SearchForSignatureEntryList::~SearchForSignatureEntryList() 1188 { 1189 delete fIteratorList; 1190 } 1191 1192 1193 void 1194 SearchForSignatureEntryList::PushUniqueSignature(const char *str) 1195 { 1196 // do a unique add 1197 if (fSignatures.EachElement(FindOne, (void *)str)) 1198 return; 1199 1200 fSignatures.AddItem(new BString(str)); 1201 } 1202 1203 1204 status_t 1205 SearchForSignatureEntryList::GetNextEntry(BEntry *entry, bool) 1206 { 1207 return fIteratorList->GetNextEntry(entry); 1208 } 1209 1210 1211 status_t 1212 SearchForSignatureEntryList::GetNextRef(entry_ref *ref) 1213 { 1214 return fIteratorList->GetNextRef(ref); 1215 } 1216 1217 1218 int32 1219 SearchForSignatureEntryList::GetNextDirents(struct dirent *buffer, 1220 size_t length, int32 count) 1221 { 1222 return fIteratorList->GetNextDirents(buffer, length, count); 1223 } 1224 1225 struct AddOneTermParams { 1226 BString *result; 1227 bool first; 1228 }; 1229 1230 1231 static const BString * 1232 AddOnePredicateTerm(const BString *item, void *castToParams) 1233 { 1234 AddOneTermParams *params = (AddOneTermParams *)castToParams; 1235 if (!params->first) 1236 (*params->result) << " || "; 1237 (*params->result) << kAttrAppSignature << " = " << item->String(); 1238 1239 params->first = false; 1240 1241 return 0; 1242 } 1243 1244 1245 status_t 1246 SearchForSignatureEntryList::Rewind() 1247 { 1248 if (fIteratorList) 1249 return fIteratorList->Rewind(); 1250 1251 if (!fSignatures.CountItems()) 1252 return ENOENT; 1253 1254 // build up the iterator 1255 fIteratorList = new CachedEntryIteratorList; 1256 1257 // build the predicate string by oring queries for the individual 1258 // signatures 1259 BString predicateString; 1260 1261 AddOneTermParams params; 1262 params.result = &predicateString; 1263 params.first = true; 1264 1265 fSignatures.EachElement(AddOnePredicateTerm, ¶ms); 1266 1267 ASSERT(predicateString.Length()); 1268 // PRINT(("query predicate %s\n", predicateString.String())); 1269 fIteratorList->AddItem(new TWalkerWrapper( 1270 new WALKER_NS::TQueryWalker(predicateString.String()))); 1271 fIteratorList->AddItem(new ConditionalAllAppsIterator(this)); 1272 1273 return fIteratorList->Rewind(); 1274 } 1275 1276 1277 int32 1278 SearchForSignatureEntryList::CountEntries() 1279 { 1280 return 0; 1281 } 1282 1283 1284 bool 1285 SearchForSignatureEntryList::GetPreferredApp(entry_ref *ref) const 1286 { 1287 if (fPreferredAppCount == 1) 1288 *ref = fPreferredRef; 1289 1290 return fPreferredAppCount == 1; 1291 } 1292 1293 1294 void 1295 SearchForSignatureEntryList::TrySettingPreferredApp(const entry_ref *ref) 1296 { 1297 if (!fPreferredAppCount) { 1298 fPreferredRef = *ref; 1299 fPreferredAppCount++; 1300 } else if (fPreferredRef != *ref) 1301 // if more than one, will not return any 1302 fPreferredAppCount++; 1303 } 1304 1305 1306 void 1307 SearchForSignatureEntryList::TrySettingPreferredAppForFile(const entry_ref *ref) 1308 { 1309 if (!fPreferredAppForFileCount) { 1310 fPreferredRefForFile = *ref; 1311 fPreferredAppForFileCount++; 1312 } else if (fPreferredRefForFile != *ref) { 1313 // if more than one, will not return any 1314 fPreferredAppForFileCount++; 1315 } 1316 } 1317 1318 1319 void 1320 SearchForSignatureEntryList::NonGenericFileFound() 1321 { 1322 fGenericFilesOnly = false; 1323 } 1324 1325 1326 bool 1327 SearchForSignatureEntryList::GenericFilesOnly() const 1328 { 1329 return fGenericFilesOnly; 1330 } 1331 1332 1333 bool 1334 SearchForSignatureEntryList::ShowAllApplications() const 1335 { 1336 return fCanAddAllApps && !fFoundOneNonSuperHandler; 1337 } 1338 1339 1340 int32 1341 SearchForSignatureEntryList::Relation(const Model *nodeModel, 1342 const Model *applicationModel) 1343 { 1344 switch (applicationModel->SupportsMimeType(nodeModel->MimeType(), 0, true)) { 1345 case kDoesNotSupportType: 1346 return kNoRelation; 1347 1348 case kSuperhandlerModel: 1349 return kSuperhandler; 1350 1351 case kModelSupportsSupertype: 1352 return kSupportsSupertype; 1353 1354 case kModelSupportsType: 1355 return kSupportsType; 1356 } 1357 1358 TRESPASS(); 1359 return kNoRelation; 1360 } 1361 1362 1363 int32 1364 SearchForSignatureEntryList::Relation(const BMessage *entriesToOpen, 1365 const Model *model) const 1366 { 1367 return Relation(entriesToOpen, model, 1368 fPreferredAppCount == 1 ? &fPreferredRef : 0, 1369 fPreferredAppForFileCount == 1 ? &fPreferredRefForFile : 0); 1370 } 1371 1372 1373 void 1374 SearchForSignatureEntryList::RelationDescription(const BMessage *entriesToOpen, 1375 const Model *model, BString *description) const 1376 { 1377 RelationDescription(entriesToOpen, model, description, 1378 fPreferredAppCount == 1 ? &fPreferredRef : 0, 1379 fPreferredAppForFileCount == 1 ? &fPreferredRefForFile : 0); 1380 } 1381 1382 1383 int32 1384 SearchForSignatureEntryList::Relation(const BMessage *entriesToOpen, 1385 const Model *applicationModel, const entry_ref *preferredApp, 1386 const entry_ref *preferredAppForFile) 1387 { 1388 for (int32 index = 0; ; index++) { 1389 entry_ref ref; 1390 if (entriesToOpen->FindRef("refs", index, &ref) != B_OK) 1391 break; 1392 1393 // need to init a model so that typeless folders etc. will still appear to 1394 // have a mime type 1395 1396 Model model(&ref, true, true); 1397 if (model.InitCheck()) 1398 continue; 1399 1400 int32 result = Relation(&model, applicationModel); 1401 if (result != kNoRelation) { 1402 if (preferredAppForFile 1403 && *applicationModel->EntryRef() == *preferredAppForFile) 1404 return kPreferredForFile; 1405 1406 if (result == kSupportsType && preferredApp 1407 && *applicationModel->EntryRef() == *preferredApp) 1408 // application matches cached preferred app, we are done 1409 return kPreferredForType; 1410 1411 return result; 1412 } 1413 } 1414 1415 return kNoRelation; 1416 } 1417 1418 1419 void 1420 SearchForSignatureEntryList::RelationDescription(const BMessage *entriesToOpen, 1421 const Model *applicationModel, BString *description, const entry_ref *preferredApp, 1422 const entry_ref *preferredAppForFile) 1423 { 1424 for (int32 index = 0; ;index++) { 1425 entry_ref ref; 1426 if (entriesToOpen->FindRef("refs", index, &ref) != B_OK) 1427 break; 1428 1429 if (preferredAppForFile && ref == *preferredAppForFile) { 1430 *description = "Preferred for file"; 1431 return; 1432 } 1433 1434 Model model(&ref, true, true); 1435 if (model.InitCheck()) 1436 continue; 1437 1438 BMimeType mimeType; 1439 int32 result = Relation(&model, applicationModel); 1440 switch (result) { 1441 case kDoesNotSupportType: 1442 continue; 1443 1444 case kSuperhandler: 1445 *description = "Handles any file"; 1446 return; 1447 1448 case kSupportsSupertype: 1449 { 1450 mimeType.SetTo(model.MimeType()); 1451 // status_t result = mimeType.GetSupertype(&mimeType); 1452 1453 char *type = (char *)mimeType.Type(); 1454 char *tmp = strchr(type, '/'); 1455 if (tmp) 1456 *tmp = '\0'; 1457 1458 //PRINT(("getting supertype for %s, result %s, got %s\n", 1459 // model.MimeType(), strerror(result), mimeType.Type())); 1460 *description = "Handles any "; 1461 // *description += mimeType.Type(); 1462 *description += type; 1463 return; 1464 } 1465 1466 case kSupportsType: 1467 { 1468 mimeType.SetTo(model.MimeType()); 1469 1470 if (preferredApp && *applicationModel->EntryRef() == *preferredApp) 1471 // application matches cached preferred app, we are done 1472 *description = "Preferred for "; 1473 else 1474 *description = "Handles "; 1475 1476 char shortDescription[256]; 1477 if (mimeType.GetShortDescription(shortDescription) == B_OK) 1478 *description += shortDescription; 1479 else 1480 *description += mimeType.Type(); 1481 return; 1482 } 1483 } 1484 } 1485 1486 *description = "Does not handle file"; 1487 } 1488 1489 1490 bool 1491 SearchForSignatureEntryList::CanOpenWithFilter(const Model *appModel, 1492 const BMessage *entriesToOpen, const entry_ref *preferredApp) 1493 { 1494 if (!appModel->IsExecutable() || !appModel->Node()) { 1495 // weed out non-executable 1496 #if xDEBUG 1497 BPath path; 1498 BEntry entry(appModel->EntryRef()); 1499 entry.GetPath(&path); 1500 PRINT(("filtering out %s- not executable \n", path.Path())); 1501 #endif 1502 return false; 1503 } 1504 1505 if (strcasecmp(appModel->MimeType(), B_APP_MIME_TYPE) != 0) { 1506 // filter out pe containers on PPC etc. 1507 return false; 1508 } 1509 1510 ASSERT(dynamic_cast<BFile *>(appModel->Node())); 1511 char signature[B_MIME_TYPE_LENGTH]; 1512 status_t result = GetAppSignatureFromAttr( 1513 dynamic_cast<BFile *>(appModel->Node()), signature); 1514 1515 if (result == B_OK && strcasecmp(signature, kTrackerSignature) == 0) { 1516 // special case the Tracker - make sure only the running copy is 1517 // in the list 1518 app_info trackerInfo; 1519 result = be_roster->GetActiveAppInfo(&trackerInfo); 1520 if (*appModel->EntryRef() != trackerInfo.ref) { 1521 // this is an inactive copy of the Tracker, remove it 1522 1523 #if xDEBUG 1524 BPath path, path2; 1525 BEntry entry(appModel->EntryRef()); 1526 entry.GetPath(&path); 1527 1528 BEntry entry2(&trackerInfo.ref); 1529 entry2.GetPath(&path2); 1530 1531 PRINT(("filtering out %s, sig %s, active Tracker at %s, result %s, refName %s\n", 1532 path.Path(), signature, path2.Path(), strerror(result), 1533 trackerInfo.ref.name)); 1534 #endif 1535 return false; 1536 } 1537 } 1538 1539 if (FSInTrashDir(appModel->EntryRef())) 1540 return false; 1541 1542 if (ShowAllApplications()) { 1543 // don't check for these if we didn't look for every single app 1544 // to not slow filtering down 1545 uint32 flags; 1546 BAppFileInfo appFileInfo(dynamic_cast<BFile *>(appModel->Node())); 1547 if (appFileInfo.GetAppFlags(&flags) != B_OK) 1548 return false; 1549 1550 if ((flags & B_BACKGROUND_APP) || (flags & B_ARGV_ONLY)) 1551 return false; 1552 1553 if (!signature[0]) 1554 // weed out apps with empty signatures 1555 return false; 1556 } 1557 1558 int32 relation = Relation(entriesToOpen, appModel, preferredApp, 0); 1559 if (relation == kNoRelation && !ShowAllApplications()) { 1560 #if xDEBUG 1561 BPath path; 1562 BEntry entry(appModel->EntryRef()); 1563 entry.GetPath(&path); 1564 1565 PRINT(("filtering out %s, does not handle any of opened files\n", 1566 path.Path())); 1567 #endif 1568 return false; 1569 } 1570 1571 if (relation != kNoRelation && relation != kSuperhandler && !fGenericFilesOnly) { 1572 // we hit at least one app that is not a superhandler and 1573 // handles the document 1574 fFoundOneNonSuperHandler = true; 1575 } 1576 1577 return true; 1578 } 1579 1580 1581 // #pragma mark - 1582 1583 1584 ConditionalAllAppsIterator::ConditionalAllAppsIterator( 1585 SearchForSignatureEntryList *parent) 1586 : 1587 fParent(parent), 1588 fWalker(NULL) 1589 { 1590 } 1591 1592 1593 void 1594 ConditionalAllAppsIterator::Instantiate() 1595 { 1596 if (fWalker) 1597 return; 1598 1599 BString lookForAppsPredicate; 1600 lookForAppsPredicate << "(" << kAttrAppSignature << " = \"*\" ) && ( " 1601 << kAttrMIMEType << " = " << B_APP_MIME_TYPE << " ) "; 1602 fWalker = new WALKER_NS::TQueryWalker(lookForAppsPredicate.String()); 1603 } 1604 1605 1606 ConditionalAllAppsIterator::~ConditionalAllAppsIterator() 1607 { 1608 delete fWalker; 1609 } 1610 1611 1612 status_t 1613 ConditionalAllAppsIterator::GetNextEntry(BEntry *entry, bool traverse) 1614 { 1615 if (!Iterate()) 1616 return B_ENTRY_NOT_FOUND; 1617 1618 Instantiate(); 1619 return fWalker->GetNextEntry(entry, traverse); 1620 } 1621 1622 1623 status_t 1624 ConditionalAllAppsIterator::GetNextRef(entry_ref *ref) 1625 { 1626 if (!Iterate()) 1627 return B_ENTRY_NOT_FOUND; 1628 1629 Instantiate(); 1630 return fWalker->GetNextRef(ref); 1631 } 1632 1633 1634 int32 1635 ConditionalAllAppsIterator::GetNextDirents(struct dirent *buffer, size_t length, int32 count) 1636 { 1637 if (!Iterate()) 1638 return 0; 1639 1640 Instantiate(); 1641 return fWalker->GetNextDirents(buffer, length, count); 1642 } 1643 1644 1645 status_t 1646 ConditionalAllAppsIterator::Rewind() 1647 { 1648 if (!Iterate()) 1649 return B_OK; 1650 1651 Instantiate(); 1652 return fWalker->Rewind(); 1653 } 1654 1655 1656 int32 1657 ConditionalAllAppsIterator::CountEntries() 1658 { 1659 if (!Iterate()) 1660 return 0; 1661 1662 Instantiate(); 1663 return fWalker->CountEntries(); 1664 } 1665 1666 1667 bool 1668 ConditionalAllAppsIterator::Iterate() const 1669 { 1670 return fParent->ShowAllApplications(); 1671 } 1672 1673