Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / kits / tracker / OpenWithWindow.cpp
blob607500202f0bbc29555c46ce996d67e0d87cb432
1 /*
2 Open Tracker License
4 Terms and Conditions
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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:
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.
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.
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.
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.
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"
45 #include <Alert.h>
46 #include <Button.h>
47 #include <Catalog.h>
48 #include <GroupView.h>
49 #include <GridView.h>
50 #include <Locale.h>
51 #include <Mime.h>
52 #include <NodeInfo.h>
53 #include <Path.h>
54 #include <Roster.h>
55 #include <SpaceLayoutItem.h>
56 #include <Volume.h>
57 #include <VolumeRoster.h>
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <strings.h>
64 const char* kDefaultOpenWithTemplate = "OpenWithSettings";
66 // ToDo:
67 // filter out trash
68 // allow column configuring
69 // make SaveState/RestoreState save the current window setting for
70 // other windows
72 const float kMaxMenuWidth = 150;
74 const int32 kDocumentKnobWidth = 16;
75 const int32 kOpenAndMakeDefault = 'OpDf';
76 const rgb_color kOpenWithDefaultColor = { 0xFF, 0xFF, 0xCC, 255};
79 // #pragma mark - OpenWithContainerWindow
82 #undef B_TRANSLATION_CONTEXT
83 #define B_TRANSLATION_CONTEXT "OpenWithWindow"
86 OpenWithContainerWindow::OpenWithContainerWindow(BMessage* entriesToOpen,
87 LockingList<BWindow>* windowList)
89 BContainerWindow(windowList, 0),
90 fEntriesToOpen(entriesToOpen)
92 AutoLock<BWindow> lock(this);
94 BRect windowRect(85, 50, 718, 296);
95 MoveTo(windowRect.LeftTop());
96 ResizeTo(windowRect.Width(), windowRect.Height());
98 // Create controls
99 fButtonContainer = new BGroupView(B_HORIZONTAL, B_USE_ITEM_SPACING);
100 fButtonContainer->GroupLayout()->SetInsets(0, B_USE_ITEM_INSETS,
101 B_USE_ITEM_INSETS, 0);
103 fLaunchButton = new BButton("ok", B_TRANSLATE("Open"),
104 new BMessage(kDefaultButton));
106 fLaunchButton->MakeDefault(true);
108 fLaunchAndMakeDefaultButton = new BButton("make default",
109 B_TRANSLATE("Open and make preferred"),
110 new BMessage(kOpenAndMakeDefault));
111 // wide button, have to resize to fit text
112 fLaunchAndMakeDefaultButton->SetEnabled(false);
114 fCancelButton = new BButton("cancel", B_TRANSLATE("Cancel"),
115 new BMessage(kCancelButton));
117 // Add pose view
118 fPoseView = NewPoseView(NULL, kListMode);
119 fBorderedView->GroupLayout()->AddView(fPoseView);
121 fPoseView->SetFlags(fPoseView->Flags() | B_NAVIGABLE);
122 fPoseView->SetPoseEditing(false);
124 // set the window title
125 if (CountRefs(fEntriesToOpen) == 1) {
126 // if opening just one file, use it in the title
127 entry_ref ref;
128 fEntriesToOpen->FindRef("refs", &ref);
129 BString buffer(B_TRANSLATE("Open %name with:"));
130 buffer.ReplaceFirst("%name", ref.name);
132 SetTitle(buffer.String());
133 } else {
134 // use generic title
135 SetTitle(B_TRANSLATE("Open selection with:"));
138 AddCommonFilter(new BMessageFilter(B_KEY_DOWN,
139 &OpenWithContainerWindow::KeyDownFilter));
143 OpenWithContainerWindow::~OpenWithContainerWindow()
145 delete fEntriesToOpen;
149 BPoseView*
150 OpenWithContainerWindow::NewPoseView(Model*, uint32)
152 return new OpenWithPoseView;
156 OpenWithPoseView*
157 OpenWithContainerWindow::PoseView() const
159 ASSERT(dynamic_cast<OpenWithPoseView*>(fPoseView) != NULL);
161 return static_cast<OpenWithPoseView*>(fPoseView);
165 const BMessage*
166 OpenWithContainerWindow::EntryList() const
168 return fEntriesToOpen;
172 void
173 OpenWithContainerWindow::OpenWithSelection()
175 int32 count = PoseView()->SelectionList()->CountItems();
176 ASSERT(count == 1);
177 if (count == 0)
178 return;
180 PoseView()->OpenSelection(PoseView()->SelectionList()->FirstItem(), 0);
184 static const BString*
185 FindOne(const BString* element, void* castToString)
187 if (strcasecmp(element->String(), (const char*)castToString) == 0)
188 return element;
190 return 0;
194 static const entry_ref*
195 AddOneUniqueDocumentType(const entry_ref* ref, void* castToList)
197 BObjectList<BString>* list = (BObjectList<BString>*)castToList;
199 BEntry entry(ref, true);
200 // traverse symlinks
202 // get this documents type
203 char type[B_MIME_TYPE_LENGTH];
204 BFile file(&entry, O_RDONLY);
205 if (file.InitCheck() != B_OK)
206 return 0;
208 BNodeInfo info(&file);
209 if (info.GetType(type) != B_OK)
210 return 0;
212 if (list->EachElement(FindOne, &type))
213 // type already in list, bail
214 return 0;
216 // add type to list
217 list->AddItem(new BString(type));
219 return 0;
223 static const BString*
224 SetDefaultAppForOneType(const BString* element, void* castToEntryRef)
226 const entry_ref* appRef = (const entry_ref*)castToEntryRef;
228 // set entry as default handler for one mime string
229 BMimeType mime(element->String());
230 if (!mime.IsInstalled())
231 return 0;
233 // first set it's app signature as the preferred type
234 BFile appFile(appRef, O_RDONLY);
235 if (appFile.InitCheck() != B_OK)
236 return 0;
238 char appSignature[B_MIME_TYPE_LENGTH];
239 if (GetAppSignatureFromAttr(&appFile, appSignature) != B_OK)
240 return 0;
242 if (mime.SetPreferredApp(appSignature) != B_OK)
243 return 0;
245 // set the app hint on the metamime for this signature
246 mime.SetTo(appSignature);
247 #if xDEBUG
248 status_t result =
249 #endif
250 mime.SetAppHint(appRef);
252 #if xDEBUG
253 BEntry debugEntry(appRef);
254 BPath debugPath;
255 debugEntry.GetPath(&debugPath);
257 PRINT(("setting %s, sig %s as default app for %s, result %s\n",
258 debugPath.Path(), appSignature, element->String(), strerror(result)));
259 #endif
261 return 0;
265 void
266 OpenWithContainerWindow::MakeDefaultAndOpen()
268 int32 count = PoseView()->SelectionList()->CountItems();
269 ASSERT(count == 1);
270 if (count == 0)
271 return;
273 BPose* selectedAppPose = PoseView()->SelectionList()->FirstItem();
274 ASSERT(selectedAppPose != NULL);
275 if (selectedAppPose == NULL)
276 return;
278 // collect all the types of all the opened documents into a list
279 BObjectList<BString> openedFileTypes(10, true);
280 EachEntryRef(EntryList(), AddOneUniqueDocumentType, &openedFileTypes, 100);
282 // set the default application to be the selected pose for all the
283 // mime types in the list
284 openedFileTypes.EachElement(SetDefaultAppForOneType,
285 (void*)selectedAppPose->TargetModel()->EntryRef());
287 // done setting the default application, now launch the app with the
288 // documents
289 OpenWithSelection();
293 void
294 OpenWithContainerWindow::MessageReceived(BMessage* message)
296 switch (message->what) {
297 case kDefaultButton:
298 OpenWithSelection();
299 PostMessage(B_QUIT_REQUESTED);
300 return;
302 case kOpenAndMakeDefault:
303 MakeDefaultAndOpen();
304 PostMessage(B_QUIT_REQUESTED);
305 return;
307 case kCancelButton:
308 PostMessage(B_QUIT_REQUESTED);
309 return;
311 case B_OBSERVER_NOTICE_CHANGE:
312 return;
314 case kResizeToFit:
315 ResizeToFit();
316 break;
319 _inherited::MessageReceived(message);
323 filter_result
324 OpenWithContainerWindow::KeyDownFilter(BMessage* message, BHandler**,
325 BMessageFilter* filter)
327 uchar key;
328 if (message->FindInt8("byte", (int8*)&key) != B_OK)
329 return B_DISPATCH_MESSAGE;
331 int32 modifiers = 0;
332 message->FindInt32("modifiers", &modifiers);
333 if (modifiers == 0 && key == B_ESCAPE) {
334 filter->Looper()->PostMessage(kCancelButton);
335 return B_SKIP_MESSAGE;
338 return B_DISPATCH_MESSAGE;
342 bool
343 OpenWithContainerWindow::ShouldAddMenus() const
345 return false;
349 void
350 OpenWithContainerWindow::ShowContextMenu(BPoint, const entry_ref*, BView*)
355 void
356 OpenWithContainerWindow::AddShortcuts()
358 AddShortcut('I', B_COMMAND_KEY, new BMessage(kGetInfo), PoseView());
359 AddShortcut('Y', B_COMMAND_KEY, new BMessage(kResizeToFit), PoseView());
363 void
364 OpenWithContainerWindow::NewAttributeMenu(BMenu* menu)
366 _inherited::NewAttributeMenu(menu);
368 BMessage* message = new BMessage(kAttributeItem);
369 message->AddString("attr_name", kAttrOpenWithRelation);
370 message->AddInt32("attr_type", B_STRING_TYPE);
371 message->AddInt32("attr_hash",
372 (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);
378 BMenuItem* item = new BMenuItem(B_TRANSLATE("Relation"), message);
379 menu->AddItem(item);
380 message = new BMessage(kAttributeItem);
381 message->AddString("attr_name", kAttrAppVersion);
382 message->AddInt32("attr_type", B_STRING_TYPE);
383 message->AddInt32("attr_hash",
384 (int32)AttrHashString(kAttrAppVersion, B_STRING_TYPE));
385 message->AddFloat("attr_width", 70);
386 message->AddInt32("attr_align", B_ALIGN_LEFT);
387 message->AddBool("attr_editable", false);
388 message->AddBool("attr_statfield", false);
390 item = new BMenuItem(B_TRANSLATE("Version"), message);
391 menu->AddItem(item);
395 void
396 OpenWithContainerWindow::SaveState(bool)
398 BNode defaultingNode;
399 if (DefaultStateSourceNode(kDefaultOpenWithTemplate, &defaultingNode,
400 true, false)) {
401 AttributeStreamFileNode streamNodeDestination(&defaultingNode);
402 SaveWindowState(&streamNodeDestination);
403 fPoseView->SaveState(&streamNodeDestination);
408 void
409 OpenWithContainerWindow::SaveState(BMessage &message) const
411 _inherited::SaveState(message);
415 void
416 OpenWithContainerWindow::Init(const BMessage* message)
418 _inherited::Init(message);
422 void
423 OpenWithContainerWindow::InitLayout()
425 _inherited::InitLayout();
427 // Remove the menu container, since we don't have a menu bar
428 fMenuContainer->RemoveSelf();
430 // Reset insets
431 fRootLayout->SetInsets(B_USE_ITEM_INSETS);
432 fPoseContainer->GridLayout()->SetInsets(0);
433 fVScrollBarContainer->GroupLayout()->SetInsets(-1, 0, 0, 0);
434 fCountContainer->GroupLayout()->SetInsets(0);
436 fRootLayout->AddView(fButtonContainer);
437 fButtonContainer->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue());
438 fButtonContainer->GroupLayout()->AddView(fCancelButton);
439 fButtonContainer->GroupLayout()->AddView(fLaunchAndMakeDefaultButton);
440 fButtonContainer->GroupLayout()->AddView(fLaunchButton);
444 void
445 OpenWithContainerWindow::RestoreState()
447 BNode defaultingNode;
448 if (DefaultStateSourceNode(kDefaultOpenWithTemplate, &defaultingNode,
449 false)) {
450 AttributeStreamFileNode streamNodeSource(&defaultingNode);
451 RestoreWindowState(&streamNodeSource);
452 fPoseView->Init(&streamNodeSource);
453 } else {
454 RestoreWindowState(NULL);
455 fPoseView->Init(NULL);
457 InitLayout();
461 void
462 OpenWithContainerWindow::RestoreState(const BMessage &message)
464 _inherited::RestoreState(message);
468 void
469 OpenWithContainerWindow::RestoreWindowState(AttributeStreamNode* node)
471 if (node == NULL)
472 return;
474 const char* rectAttributeName = kAttrWindowFrame;
475 BRect frame(Frame());
476 if (node->Read(rectAttributeName, 0, B_RECT_TYPE, sizeof(BRect), &frame)
477 == sizeof(BRect)) {
478 MoveTo(frame.LeftTop());
479 ResizeTo(frame.Width(), frame.Height());
484 void
485 OpenWithContainerWindow::RestoreWindowState(const BMessage &message)
487 _inherited::RestoreWindowState(message);
491 bool
492 OpenWithContainerWindow::NeedsDefaultStateSetup()
494 return true;
498 void
499 OpenWithContainerWindow::SetUpDefaultState()
504 bool
505 OpenWithContainerWindow::IsShowing(const node_ref*) const
507 return false;
511 bool
512 OpenWithContainerWindow::IsShowing(const entry_ref*) const
514 return false;
518 void
519 OpenWithContainerWindow::SetCanSetAppAsDefault(bool on)
521 fLaunchAndMakeDefaultButton->SetEnabled(on);
525 void
526 OpenWithContainerWindow::SetCanOpen(bool on)
528 fLaunchButton->SetEnabled(on);
532 // #pragma mark - OpenWithPoseView
535 OpenWithPoseView::OpenWithPoseView()
537 BPoseView(new Model(), kListMode),
538 fHaveCommonPreferredApp(false),
539 fIterator(NULL),
540 fRefFilter(NULL)
542 fSavePoseLocations = false;
543 fMultipleSelection = false;
544 fDragEnabled = false;
548 OpenWithPoseView::~OpenWithPoseView()
550 delete fRefFilter;
551 delete fIterator;
555 OpenWithContainerWindow*
556 OpenWithPoseView::ContainerWindow() const
558 OpenWithContainerWindow* window
559 = dynamic_cast<OpenWithContainerWindow*>(Window());
560 ASSERT(window != NULL);
562 return window;
566 void
567 OpenWithPoseView::AttachedToWindow()
569 _inherited::AttachedToWindow();
571 SetViewColor(kOpenWithDefaultColor);
572 SetLowColor(kOpenWithDefaultColor);
576 bool
577 OpenWithPoseView::CanHandleDragSelection(const Model*, const BMessage*, bool)
579 return false;
583 static void
584 AddSupportingAppForTypeToQuery(SearchForSignatureEntryList* queryIterator,
585 const char* type)
587 // get supporting apps for type
588 BMimeType mime(type);
589 if (!mime.IsInstalled())
590 return;
592 BMessage message;
593 mime.GetSupportingApps(&message);
595 // push each of the supporting apps signature uniquely
597 const char* signature;
598 for (int32 index = 0; message.FindString("applications", index,
599 &signature) == B_OK; index++) {
600 queryIterator->PushUniqueSignature(signature);
605 static const entry_ref*
606 AddOneRefSignatures(const entry_ref* ref, void* castToIterator)
608 // TODO: resolve cases where each entry has a different type and
609 // their supporting apps are disjoint sets
611 SearchForSignatureEntryList* queryIterator =
612 (SearchForSignatureEntryList*)castToIterator;
614 Model model(ref, true, true);
615 if (model.InitCheck() != B_OK)
616 return NULL;
618 BString mimeType(model.MimeType());
620 if (!mimeType.Length() || mimeType.ICompare(B_FILE_MIMETYPE) == 0)
621 // if model is of unknown type, try mimeseting it first
622 model.Mimeset(true);
624 entry_ref preferredRef;
626 // add preferred app for file, if any
627 if (model.PreferredAppSignature()[0]) {
628 // got one, mark it as preferred for this node
629 if (be_roster->FindApp(model.PreferredAppSignature(), &preferredRef)
630 == B_OK) {
631 queryIterator->PushUniqueSignature(model.PreferredAppSignature());
632 queryIterator->TrySettingPreferredAppForFile(&preferredRef);
636 mimeType = model.MimeType();
637 mimeType.ToLower();
639 if (mimeType.Length() && !mimeType.ICompare(B_FILE_MIMETYPE) == 0)
640 queryIterator->NonGenericFileFound();
642 // get supporting apps for type
643 AddSupportingAppForTypeToQuery(queryIterator, mimeType.String());
645 // find the preferred app for this type
646 if (be_roster->FindApp(mimeType.String(), &preferredRef) == B_OK)
647 queryIterator->TrySettingPreferredApp(&preferredRef);
649 return NULL;
653 EntryListBase*
654 OpenWithPoseView::InitDirentIterator(const entry_ref*)
656 OpenWithContainerWindow* window = ContainerWindow();
658 const BMessage* entryList = window->EntryList();
660 fIterator = new SearchForSignatureEntryList(true);
662 // push all the supporting apps from all the entries into the
663 // search for signature iterator
664 EachEntryRef(entryList, AddOneRefSignatures, fIterator, 100);
666 // push superhandlers
667 AddSupportingAppForTypeToQuery(fIterator, B_FILE_MIMETYPE);
668 fHaveCommonPreferredApp = fIterator->GetPreferredApp(&fPreferredRef);
670 if (fIterator->Rewind() != B_OK) {
671 delete fIterator;
672 fIterator = NULL;
673 HideBarberPole();
674 return NULL;
677 fRefFilter = new OpenWithRefFilter(fIterator, entryList,
678 fHaveCommonPreferredApp ? &fPreferredRef : 0);
679 SetRefFilter(fRefFilter);
681 return fIterator;
685 void
686 OpenWithPoseView::ReturnDirentIterator(EntryListBase* iterator)
688 // Do nothing. We keep our fIterator around as it is used by fRefFilter.
692 void
693 OpenWithPoseView::OpenSelection(BPose* pose, int32*)
695 OpenWithContainerWindow* window = ContainerWindow();
697 int32 count = fSelectionList->CountItems();
698 if (count == 0)
699 return;
701 if (pose == NULL)
702 pose = fSelectionList->FirstItem();
704 ASSERT(pose != NULL);
706 BEntry entry(pose->TargetModel()->EntryRef());
707 if (entry.InitCheck() != B_OK) {
708 BString errorString(
709 B_TRANSLATE("Could not find application \"%appname\""));
710 errorString.ReplaceFirst("%appname", pose->TargetModel()->Name());
712 BAlert* alert = new BAlert("", errorString.String(), B_TRANSLATE("OK"),
713 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
714 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
715 alert->Go();
716 return;
719 if (OpenWithRelation(pose->TargetModel()) == kNoRelation) {
720 if (!fIterator->GenericFilesOnly()) {
721 BString warning(B_TRANSLATE(
722 "The application \"%appname\" does not support the type of "
723 "document you are about to open.\nAre you sure you want to "
724 "proceed?\n\nIf you know that the application supports the "
725 "document type, you should contact the publisher of the "
726 "application and ask them to update their application to list "
727 "the type of your document as supported."));
728 warning.ReplaceFirst("%appname", pose->TargetModel()->Name());
730 BAlert* alert = new BAlert("", warning.String(),
731 B_TRANSLATE("Cancel"), B_TRANSLATE("Open"), 0, B_WIDTH_AS_USUAL,
732 B_WARNING_ALERT);
733 alert->SetShortcut(0, B_ESCAPE);
734 if (alert->Go() == 0)
735 return;
737 // else - once we have an extensible sniffer, tell users to ask
738 // publishers to fix up sniffers
741 BMessage message(*window->EntryList());
742 // make a clone to send
743 message.RemoveName("launchUsingSelector");
744 // make sure the old selector is not in the message
745 message.AddRef("handler", pose->TargetModel()->EntryRef());
746 // add ref of the selected handler
748 ASSERT(fSelectionHandler != NULL);
749 if (fSelectionHandler != NULL)
750 fSelectionHandler->PostMessage(&message);
752 window->PostMessage(B_QUIT_REQUESTED);
756 void
757 OpenWithPoseView::Pulse()
759 // disable the Open and make default button if the default
760 // app matches the selected app
762 // disable the Open button if no apps selected
764 OpenWithContainerWindow* window = ContainerWindow();
766 if (!fSelectionList->CountItems()) {
767 window->SetCanSetAppAsDefault(false);
768 window->SetCanOpen(false);
769 _inherited::Pulse();
770 return;
773 // if we selected a non-handling application, don't allow setting
774 // it as preferred
775 Model* firstSelected = fSelectionList->FirstItem()->TargetModel();
776 if (OpenWithRelation(firstSelected) == kNoRelation) {
777 window->SetCanSetAppAsDefault(false);
778 window->SetCanOpen(true);
779 _inherited::Pulse();
780 return;
783 // make the open button enabled, because we have na app selected
784 window->SetCanOpen(true);
785 if (!fHaveCommonPreferredApp) {
786 window->SetCanSetAppAsDefault(true);
787 _inherited::Pulse();
788 return;
791 ASSERT(fSelectionList->CountItems() == 1);
793 // enable the Open and make default if selected application different
794 // from preferred app ref
795 window->SetCanSetAppAsDefault((*fSelectionList->FirstItem()->
796 TargetModel()->EntryRef()) != fPreferredRef);
798 _inherited::Pulse();
802 void
803 OpenWithPoseView::SetUpDefaultColumnsIfNeeded()
805 // in case there were errors getting some columns
806 if (fColumnList->CountItems() != 0)
807 return;
809 BColumn* nameColumn = new BColumn(B_TRANSLATE("Name"), kColumnStart, 125,
810 B_ALIGN_LEFT, kAttrStatName, B_STRING_TYPE, true, true);
811 fColumnList->AddItem(nameColumn);
812 BColumn* relationColumn = new BColumn(B_TRANSLATE("Relation"), 180, 100,
813 B_ALIGN_LEFT, kAttrOpenWithRelation, B_STRING_TYPE, false, false);
814 fColumnList->AddItem(relationColumn);
815 fColumnList->AddItem(new BColumn(B_TRANSLATE("Location"), 290, 225,
816 B_ALIGN_LEFT, kAttrPath, B_STRING_TYPE, true, false));
817 fColumnList->AddItem(new BColumn(B_TRANSLATE("Version"), 525, 70,
818 B_ALIGN_LEFT, kAttrAppVersion, B_STRING_TYPE, false, false));
820 // sort by relation and by name
821 SetPrimarySort(relationColumn->AttrHash());
822 SetSecondarySort(nameColumn->AttrHash());
826 bool
827 OpenWithPoseView::AddPosesThreadValid(const entry_ref*) const
829 return true;
833 void
834 OpenWithPoseView::CreatePoses(Model** models, PoseInfo* poseInfoArray,
835 int32 count, BPose** resultingPoses, bool insertionSort,
836 int32* lastPoseIndexPtr, BRect* boundsPtr, bool forceDraw)
838 // overridden to try to select the preferred handling app
839 _inherited::CreatePoses(models, poseInfoArray, count, resultingPoses,
840 insertionSort, lastPoseIndexPtr, boundsPtr, forceDraw);
842 if (resultingPoses != NULL) {
843 for (int32 index = 0; index < count; index++) {
844 if (resultingPoses[index] && fHaveCommonPreferredApp
845 && *(models[index]->EntryRef()) == fPreferredRef) {
846 // this is our preferred app, select it's pose
847 SelectPose(resultingPoses[index],
848 IndexOfPose(resultingPoses[index]));
855 void
856 OpenWithPoseView::KeyDown(const char* bytes, int32 count)
858 if (bytes[0] == B_TAB) {
859 // just shift the focus, don't tab to the next pose
860 BView::KeyDown(bytes, count);
861 } else
862 _inherited::KeyDown(bytes, count);
866 void
867 OpenWithPoseView::SaveState(AttributeStreamNode* node)
869 _inherited::SaveState(node);
873 void
874 OpenWithPoseView::RestoreState(AttributeStreamNode* node)
876 _inherited::RestoreState(node);
877 fViewState->SetViewMode(kListMode);
881 void
882 OpenWithPoseView::SaveState(BMessage &message) const
884 _inherited::SaveState(message);
888 void
889 OpenWithPoseView::RestoreState(const BMessage &message)
891 _inherited::RestoreState(message);
892 fViewState->SetViewMode(kListMode);
896 void
897 OpenWithPoseView::SavePoseLocations(BRect*)
902 void
903 OpenWithPoseView::MoveSelectionToTrash(bool)
908 void
909 OpenWithPoseView::MoveSelectionTo(BPoint, BPoint, BContainerWindow*)
914 void
915 OpenWithPoseView::MoveSelectionInto(Model*, BContainerWindow*, bool, bool)
920 bool
921 OpenWithPoseView::Represents(const node_ref*) const
923 return false;
927 bool
928 OpenWithPoseView::Represents(const entry_ref*) const
930 return false;
934 bool
935 OpenWithPoseView::HandleMessageDropped(BMessage* DEBUG_ONLY(message))
937 #if DEBUG
938 // in debug mode allow tweaking the colors
939 const rgb_color* color;
940 ssize_t size;
941 // handle roColour-style color drops
942 if (message->FindData("RGBColor", 'RGBC', (const void**)&color, &size)
943 == B_OK) {
944 SetViewColor(*color);
945 SetLowColor(*color);
946 Invalidate();
947 return true;
949 #endif
950 return false;
954 int32
955 OpenWithPoseView::OpenWithRelation(const Model* model) const
957 OpenWithContainerWindow* window = ContainerWindow();
959 return SearchForSignatureEntryList::Relation(window->EntryList(),
960 model, fHaveCommonPreferredApp ? &fPreferredRef : 0, 0);
964 void
965 OpenWithPoseView::OpenWithRelationDescription(const Model* model,
966 BString* description) const
968 OpenWithContainerWindow* window = ContainerWindow();
970 SearchForSignatureEntryList::RelationDescription(window->EntryList(),
971 model, description, fHaveCommonPreferredApp ? &fPreferredRef : 0, 0);
975 // #pragma mark - OpenWithRefFilter
978 OpenWithRefFilter::OpenWithRefFilter(SearchForSignatureEntryList* iterator,
979 const BMessage *entryList, entry_ref* preferredRef)
981 fIterator(iterator),
982 fEntryList(entryList),
983 fPreferredRef(preferredRef)
988 bool
989 OpenWithRefFilter::Filter(const entry_ref* ref, BNode* node, stat_beos* st,
990 const char* filetype)
992 Model *model = new Model(ref, true, true);
993 bool canOpen = fIterator->CanOpenWithFilter(model, fEntryList,
994 fPreferredRef);
995 delete model;
997 return canOpen;
1001 // #pragma mark -
1004 RelationCachingModelProxy::RelationCachingModelProxy(Model* model)
1006 fModel(model),
1007 fRelation(kUnknownRelation)
1012 RelationCachingModelProxy::~RelationCachingModelProxy()
1014 delete fModel;
1018 int32
1019 RelationCachingModelProxy::Relation(SearchForSignatureEntryList* iterator,
1020 BMessage* entries) const
1022 if (fRelation == kUnknownRelation)
1023 fRelation = iterator->Relation(entries, fModel);
1025 return fRelation;
1029 // #pragma mark - OpenWithMenu
1032 OpenWithMenu::OpenWithMenu(const char* label, const BMessage* entriesToOpen,
1033 BWindow* parentWindow, BHandler* target)
1035 BSlowMenu(label),
1036 fEntriesToOpen(*entriesToOpen),
1037 target(target),
1038 fIterator(NULL),
1039 fSupportingAppList(NULL),
1040 fParentWindow(parentWindow)
1042 InitIconPreloader();
1044 SetFont(be_plain_font);
1046 // too long to have triggers
1047 SetTriggersEnabled(false);
1051 OpenWithMenu::OpenWithMenu(const char* label, const BMessage* entriesToOpen,
1052 BWindow* parentWindow, const BMessenger &messenger)
1054 BSlowMenu(label),
1055 fEntriesToOpen(*entriesToOpen),
1056 target(NULL),
1057 fMessenger(messenger),
1058 fIterator(NULL),
1059 fSupportingAppList(NULL),
1060 fParentWindow(parentWindow)
1062 InitIconPreloader();
1064 SetFont(be_plain_font);
1066 // too long to have triggers
1067 SetTriggersEnabled(false);
1071 namespace BPrivate {
1074 SortByRelationAndName(const RelationCachingModelProxy* model1,
1075 const RelationCachingModelProxy* model2, void* castToMenu)
1077 OpenWithMenu* menu = (OpenWithMenu*)castToMenu;
1079 // find out the relations of app models to the opened entries
1080 int32 relation1 = model1->Relation(menu->fIterator, &menu->fEntriesToOpen);
1081 int32 relation2 = model2->Relation(menu->fIterator, &menu->fEntriesToOpen);
1083 if (relation1 < relation2) {
1084 // relation with the lowest number goes first
1085 return 1;
1086 } else if (relation1 > relation2)
1087 return -1;
1089 // if relations match, sort by app name
1090 return strcmp(model1->fModel->Name(), model2->fModel->Name());
1093 } // namespace BPrivate
1096 bool
1097 OpenWithMenu::StartBuildingItemList()
1099 fIterator = new SearchForSignatureEntryList(false);
1100 // push all the supporting apps from all the entries into the
1101 // search for signature iterator
1102 EachEntryRef(&fEntriesToOpen, AddOneRefSignatures, fIterator, 100);
1103 // add superhandlers
1104 AddSupportingAppForTypeToQuery(fIterator, B_FILE_MIMETYPE);
1106 fHaveCommonPreferredApp = fIterator->GetPreferredApp(&fPreferredRef);
1107 status_t error = fIterator->Rewind();
1108 if (error != B_OK) {
1109 PRINT(("failed to initialize iterator %s\n", strerror(error)));
1110 return false;
1113 fSupportingAppList = new BObjectList<RelationCachingModelProxy>(20, true);
1115 //queryRetrieval = new BStopWatch("get next entry on BQuery");
1116 return true;
1120 bool
1121 OpenWithMenu::AddNextItem()
1123 BEntry entry;
1124 if (fIterator->GetNextEntry(&entry) != B_OK)
1125 return false;
1127 Model* model = new Model(&entry, true);
1128 if (model->InitCheck() != B_OK
1129 || !fIterator->CanOpenWithFilter(model, &fEntriesToOpen,
1130 (fHaveCommonPreferredApp ? &fPreferredRef : 0))) {
1131 // only allow executables, filter out multiple copies of the Tracker,
1132 // filter out version that don't list the correct types, etc.
1133 delete model;
1134 } else
1135 fSupportingAppList->AddItem(new RelationCachingModelProxy(model));
1137 return true;
1141 void
1142 OpenWithMenu::DoneBuildingItemList()
1144 // sort by app name
1145 fSupportingAppList->SortItems(SortByRelationAndName, this);
1147 // check if each app is unique
1148 bool isUnique = true;
1149 int32 count = fSupportingAppList->CountItems();
1150 for (int32 index = 0; index < count - 1; index++) {
1151 // the list is sorted, just compare two adjacent models
1152 if (strcmp(fSupportingAppList->ItemAt(index)->fModel->Name(),
1153 fSupportingAppList->ItemAt(index + 1)->fModel->Name()) == 0) {
1154 isUnique = false;
1155 break;
1159 // add apps as menu items
1160 BFont font;
1161 GetFont(&font);
1163 int32 lastRelation = -1;
1164 for (int32 index = 0; index < count ; index++) {
1165 RelationCachingModelProxy* modelProxy
1166 = fSupportingAppList->ItemAt(index);
1167 Model* model = modelProxy->fModel;
1168 BMessage* message = new BMessage(fEntriesToOpen);
1169 message->AddRef("handler", model->EntryRef());
1170 BContainerWindow* window
1171 = dynamic_cast<BContainerWindow*>(fParentWindow);
1172 if (window != NULL) {
1173 message->AddData("nodeRefsToClose", B_RAW_TYPE,
1174 window->TargetModel()->NodeRef(), sizeof(node_ref));
1177 BString result;
1178 if (isUnique) {
1179 // just use the app name
1180 result = model->Name();
1181 } else {
1182 // get a truncated full path
1183 BPath path;
1184 BEntry entry(model->EntryRef());
1185 if (entry.GetPath(&path) != B_OK) {
1186 PRINT(("stale entry ref %s\n", model->Name()));
1187 delete message;
1188 continue;
1190 result = path.Path();
1191 font.TruncateString(&result, B_TRUNCATE_MIDDLE, kMaxMenuWidth);
1193 #if DEBUG
1194 BString relationDescription;
1195 fIterator->RelationDescription(&fEntriesToOpen, model, &relationDescription);
1196 result += " (";
1197 result += relationDescription;
1198 result += ")";
1199 #endif
1201 // divide different relations of opening with a separator
1202 int32 relation = modelProxy->Relation(fIterator, &fEntriesToOpen);
1203 if (lastRelation != -1 && relation != lastRelation)
1204 AddSeparatorItem();
1205 lastRelation = relation;
1207 ModelMenuItem* item = new ModelMenuItem(model, result.String(),
1208 message);
1209 AddItem(item);
1210 // mark item if it represents the preferred app
1211 if (fHaveCommonPreferredApp && *(model->EntryRef()) == fPreferredRef) {
1212 //PRINT(("marking item for % as preferred", model->Name()));
1213 item->SetMarked(true);
1217 // target the menu
1218 if (target != NULL)
1219 SetTargetForItems(target);
1220 else
1221 SetTargetForItems(fMessenger);
1223 if (CountItems() == 0) {
1224 BMenuItem* item = new BMenuItem(B_TRANSLATE("no supporting apps"), 0);
1225 item->SetEnabled(false);
1226 AddItem(item);
1231 void
1232 OpenWithMenu::ClearMenuBuildingState()
1234 delete fIterator;
1235 fIterator = NULL;
1236 delete fSupportingAppList;
1237 fSupportingAppList = NULL;
1241 // #pragma mark - SearchForSignatureEntryList
1244 SearchForSignatureEntryList::SearchForSignatureEntryList(bool canAddAllApps)
1246 fIteratorList(NULL),
1247 fSignatures(20, true),
1248 fPreferredAppCount(0),
1249 fPreferredAppForFileCount(0),
1250 fGenericFilesOnly(true),
1251 fCanAddAllApps(canAddAllApps),
1252 fFoundOneNonSuperHandler(false)
1257 SearchForSignatureEntryList::~SearchForSignatureEntryList()
1259 delete fIteratorList;
1263 void
1264 SearchForSignatureEntryList::PushUniqueSignature(const char* str)
1266 // do a unique add
1267 if (fSignatures.EachElement(FindOne, (void*)str))
1268 return;
1270 fSignatures.AddItem(new BString(str));
1274 status_t
1275 SearchForSignatureEntryList::GetNextEntry(BEntry* entry, bool)
1277 return fIteratorList->GetNextEntry(entry);
1281 status_t
1282 SearchForSignatureEntryList::GetNextRef(entry_ref* ref)
1284 return fIteratorList->GetNextRef(ref);
1288 int32
1289 SearchForSignatureEntryList::GetNextDirents(struct dirent* buffer,
1290 size_t length, int32 count)
1292 return fIteratorList->GetNextDirents(buffer, length, count);
1296 struct AddOneTermParams {
1297 BString* result;
1298 bool first;
1302 static const BString*
1303 AddOnePredicateTerm(const BString* item, void* castToParams)
1305 AddOneTermParams* params = (AddOneTermParams*)castToParams;
1306 if (!params->first)
1307 (*params->result) << " || ";
1308 (*params->result) << kAttrAppSignature << " = " << item->String();
1310 params->first = false;
1312 return 0;
1316 status_t
1317 SearchForSignatureEntryList::Rewind()
1319 if (fIteratorList)
1320 return fIteratorList->Rewind();
1322 if (!fSignatures.CountItems())
1323 return ENOENT;
1325 // build up the iterator
1326 fIteratorList = new CachedEntryIteratorList(false);
1327 // We cannot sort the cached inodes, as CanOpenWithFilter() relies
1328 // on the fact that ConditionalAllAppsIterator results come last.
1330 // build the predicate string by oring queries for the individual
1331 // signatures
1332 BString predicateString;
1334 AddOneTermParams params;
1335 params.result = &predicateString;
1336 params.first = true;
1338 fSignatures.EachElement(AddOnePredicateTerm, &params);
1340 ASSERT(predicateString.Length());
1341 // PRINT(("query predicate %s\n", predicateString.String()));
1342 fIteratorList->AddItem(new TWalkerWrapper(
1343 new BTrackerPrivate::TQueryWalker(predicateString.String())));
1344 fIteratorList->AddItem(new ConditionalAllAppsIterator(this));
1346 return fIteratorList->Rewind();
1350 int32
1351 SearchForSignatureEntryList::CountEntries()
1353 return 0;
1357 bool
1358 SearchForSignatureEntryList::GetPreferredApp(entry_ref* ref) const
1360 if (fPreferredAppCount == 1)
1361 *ref = fPreferredRef;
1363 return fPreferredAppCount == 1;
1367 void
1368 SearchForSignatureEntryList::TrySettingPreferredApp(const entry_ref* ref)
1370 if (!fPreferredAppCount) {
1371 fPreferredRef = *ref;
1372 fPreferredAppCount++;
1373 } else if (fPreferredRef != *ref) {
1374 // if more than one, will not return any
1375 fPreferredAppCount++;
1380 void
1381 SearchForSignatureEntryList::TrySettingPreferredAppForFile(const entry_ref* ref)
1383 if (!fPreferredAppForFileCount) {
1384 fPreferredRefForFile = *ref;
1385 fPreferredAppForFileCount++;
1386 } else if (fPreferredRefForFile != *ref) {
1387 // if more than one, will not return any
1388 fPreferredAppForFileCount++;
1393 void
1394 SearchForSignatureEntryList::NonGenericFileFound()
1396 fGenericFilesOnly = false;
1400 bool
1401 SearchForSignatureEntryList::GenericFilesOnly() const
1403 return fGenericFilesOnly;
1407 bool
1408 SearchForSignatureEntryList::ShowAllApplications() const
1410 return fCanAddAllApps && !fFoundOneNonSuperHandler;
1414 int32
1415 SearchForSignatureEntryList::Relation(const Model* nodeModel,
1416 const Model* applicationModel)
1418 int32 supportsMimeType = applicationModel->SupportsMimeType(
1419 nodeModel->MimeType(), 0, true);
1420 switch (supportsMimeType) {
1421 case kDoesNotSupportType:
1422 return kNoRelation;
1424 case kSuperhandlerModel:
1425 return kSuperhandler;
1427 case kModelSupportsSupertype:
1428 return kSupportsSupertype;
1430 case kModelSupportsType:
1431 return kSupportsType;
1434 TRESPASS();
1435 return kNoRelation;
1439 int32
1440 SearchForSignatureEntryList::Relation(const BMessage* entriesToOpen,
1441 const Model* model) const
1443 return Relation(entriesToOpen, model,
1444 fPreferredAppCount == 1 ? &fPreferredRef : 0,
1445 fPreferredAppForFileCount == 1 ? &fPreferredRefForFile : 0);
1449 void
1450 SearchForSignatureEntryList::RelationDescription(const BMessage* entriesToOpen,
1451 const Model* model, BString* description) const
1453 RelationDescription(entriesToOpen, model, description,
1454 fPreferredAppCount == 1 ? &fPreferredRef : 0,
1455 fPreferredAppForFileCount == 1 ? &fPreferredRefForFile : 0);
1459 int32
1460 SearchForSignatureEntryList::Relation(const BMessage* entriesToOpen,
1461 const Model* applicationModel, const entry_ref* preferredApp,
1462 const entry_ref* preferredAppForFile)
1464 for (int32 index = 0; ; index++) {
1465 entry_ref ref;
1466 if (entriesToOpen->FindRef("refs", index, &ref) != B_OK)
1467 break;
1469 // need to init a model so that typeless folders etc. will still
1470 // appear to have a mime type
1472 Model model(&ref, true, true);
1473 if (model.InitCheck())
1474 continue;
1476 int32 result = Relation(&model, applicationModel);
1477 if (result != kNoRelation) {
1478 if (preferredAppForFile
1479 && *applicationModel->EntryRef() == *preferredAppForFile) {
1480 return kPreferredForFile;
1483 if (result == kSupportsType && preferredApp
1484 && *applicationModel->EntryRef() == *preferredApp) {
1485 // application matches cached preferred app, we are done
1486 return kPreferredForType;
1489 return result;
1493 return kNoRelation;
1497 void
1498 SearchForSignatureEntryList::RelationDescription(const BMessage* entriesToOpen,
1499 const Model* applicationModel, BString* description,
1500 const entry_ref* preferredApp, const entry_ref* preferredAppForFile)
1502 for (int32 index = 0; ;index++) {
1503 entry_ref ref;
1504 if (entriesToOpen->FindRef("refs", index, &ref) != B_OK)
1505 break;
1507 if (preferredAppForFile && ref == *preferredAppForFile) {
1508 description->SetTo(B_TRANSLATE("Preferred for file"));
1509 return;
1512 Model model(&ref, true, true);
1513 if (model.InitCheck())
1514 continue;
1516 BMimeType mimeType;
1517 int32 result = Relation(&model, applicationModel);
1518 switch (result) {
1519 case kDoesNotSupportType:
1520 continue;
1522 case kSuperhandler:
1523 description->SetTo(B_TRANSLATE("Handles any file"));
1524 return;
1526 case kSupportsSupertype:
1528 mimeType.SetTo(model.MimeType());
1529 // status_t result = mimeType.GetSupertype(&mimeType);
1531 char* type = (char*)mimeType.Type();
1532 char* tmp = strchr(type, '/');
1533 if (tmp != NULL)
1534 *tmp = '\0';
1536 //PRINT(("getting supertype for %s, result %s, got %s\n",
1537 // model.MimeType(), strerror(result), mimeType.Type()));
1538 description->SetTo(B_TRANSLATE("Handles any %type"));
1539 //*description += mimeType.Type();
1540 description->ReplaceFirst("%type", type);
1541 return;
1544 case kSupportsType:
1546 mimeType.SetTo(model.MimeType());
1548 if (preferredApp != NULL
1549 && *applicationModel->EntryRef() == *preferredApp) {
1550 // application matches cached preferred app, we are done
1551 description->SetTo(B_TRANSLATE("Preferred for %type"));
1552 } else
1553 description->SetTo(B_TRANSLATE("Handles %type"));
1555 char shortDescription[256];
1556 if (mimeType.GetShortDescription(shortDescription) == B_OK)
1557 description->ReplaceFirst("%type", shortDescription);
1558 else
1559 description->ReplaceFirst("%type", mimeType.Type());
1561 return;
1566 description->SetTo(B_TRANSLATE("Does not handle file"));
1570 bool
1571 SearchForSignatureEntryList::CanOpenWithFilter(const Model* appModel,
1572 const BMessage* entriesToOpen, const entry_ref* preferredApp)
1574 ThrowOnAssert(appModel != NULL);
1576 if (!appModel->IsExecutable() || !appModel->Node()) {
1577 // weed out non-executable
1578 #if xDEBUG
1579 BPath path;
1580 BEntry entry(appModel->EntryRef());
1581 entry.GetPath(&path);
1582 PRINT(("filtering out %s- not executable \n", path.Path()));
1583 #endif
1584 return false;
1587 if (strcasecmp(appModel->MimeType(), B_APP_MIME_TYPE) != 0) {
1588 // filter out pe containers on PPC etc.
1589 return false;
1592 BFile* file = dynamic_cast<BFile*>(appModel->Node());
1593 ASSERT(file != NULL);
1595 char signature[B_MIME_TYPE_LENGTH];
1596 if (GetAppSignatureFromAttr(file, signature) == B_OK
1597 && strcasecmp(signature, kTrackerSignature) == 0) {
1598 // special case the Tracker - make sure only the running copy is
1599 // in the list
1600 app_info trackerInfo;
1601 if (*appModel->EntryRef() != trackerInfo.ref) {
1602 // this is an inactive copy of the Tracker, remove it
1604 #if xDEBUG
1605 BPath path1;
1606 BPath path2;
1607 BEntry entry(appModel->EntryRef());
1608 entry.GetPath(&path1);
1610 BEntry entry2(&trackerInfo.ref);
1611 entry2.GetPath(&path2);
1613 PRINT(("filtering out %s, sig %s, active Tracker at %s, "
1614 "result %s, refName %s\n",
1615 path1.Path(), signature, path2.Path(),
1616 strerror(be_roster->GetActiveAppInfo(&trackerInfo)),
1617 trackerInfo.ref.name));
1618 #endif
1619 return false;
1623 if (FSInTrashDir(appModel->EntryRef()))
1624 return false;
1626 if (ShowAllApplications()) {
1627 // don't check for these if we didn't look for every single app
1628 // to not slow filtering down
1629 uint32 flags;
1630 BAppFileInfo appFileInfo(dynamic_cast<BFile*>(appModel->Node()));
1631 if (appFileInfo.GetAppFlags(&flags) != B_OK)
1632 return false;
1634 if ((flags & B_BACKGROUND_APP) || (flags & B_ARGV_ONLY))
1635 return false;
1637 if (!signature[0])
1638 // weed out apps with empty signatures
1639 return false;
1642 int32 relation = Relation(entriesToOpen, appModel, preferredApp, 0);
1643 if (relation == kNoRelation && !ShowAllApplications()) {
1644 #if xDEBUG
1645 BPath path;
1646 BEntry entry(appModel->EntryRef());
1647 entry.GetPath(&path);
1649 PRINT(("filtering out %s, does not handle any of opened files\n",
1650 path.Path()));
1651 #endif
1652 return false;
1655 if (relation != kNoRelation && relation != kSuperhandler
1656 && !fGenericFilesOnly) {
1657 // we hit at least one app that is not a superhandler and
1658 // handles the document
1659 fFoundOneNonSuperHandler = true;
1662 return true;
1666 // #pragma mark - ConditionalAllAppsIterator
1669 ConditionalAllAppsIterator::ConditionalAllAppsIterator(
1670 SearchForSignatureEntryList* parent)
1672 fParent(parent),
1673 fWalker(NULL)
1678 void
1679 ConditionalAllAppsIterator::Instantiate()
1681 if (fWalker != NULL)
1682 return;
1684 BString lookForAppsPredicate;
1685 lookForAppsPredicate << "(" << kAttrAppSignature << " = \"*\" ) && ( "
1686 << kAttrMIMEType << " = " << B_APP_MIME_TYPE << " ) ";
1687 fWalker
1688 = new BTrackerPrivate::TQueryWalker(lookForAppsPredicate.String());
1692 ConditionalAllAppsIterator::~ConditionalAllAppsIterator()
1694 delete fWalker;
1698 status_t
1699 ConditionalAllAppsIterator::GetNextEntry(BEntry* entry, bool traverse)
1701 if (!Iterate())
1702 return B_ENTRY_NOT_FOUND;
1704 Instantiate();
1705 return fWalker->GetNextEntry(entry, traverse);
1709 status_t
1710 ConditionalAllAppsIterator::GetNextRef(entry_ref* ref)
1712 if (!Iterate())
1713 return B_ENTRY_NOT_FOUND;
1715 Instantiate();
1716 return fWalker->GetNextRef(ref);
1720 int32
1721 ConditionalAllAppsIterator::GetNextDirents(struct dirent* buffer,
1722 size_t length, int32 count)
1724 if (!Iterate())
1725 return 0;
1727 Instantiate();
1728 return fWalker->GetNextDirents(buffer, length, count);
1732 status_t
1733 ConditionalAllAppsIterator::Rewind()
1735 if (!Iterate())
1736 return B_OK;
1738 Instantiate();
1739 return fWalker->Rewind();
1743 int32
1744 ConditionalAllAppsIterator::CountEntries()
1746 if (!Iterate())
1747 return 0;
1749 Instantiate();
1750 return fWalker->CountEntries();
1754 bool
1755 ConditionalAllAppsIterator::Iterate() const
1757 return fParent->ShowAllApplications();