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.
36 #include "FindPanel.h"
42 #include <parsedate.h>
47 #include <Application.h>
52 #include <ControlLook.h>
54 #include <Directory.h>
55 #include <FindDirectory.h>
57 #include <FilePanel.h>
58 #include <GroupLayout.h>
59 #include <InterfaceDefs.h>
60 #include <LayoutBuilder.h>
62 #include <MenuField.h>
66 #include <PopUpMenu.h>
69 #include <SeparatorView.h>
71 #include <SpaceLayoutItem.h>
72 #include <TextControl.h>
76 #include <VolumeRoster.h>
78 #include "Attributes.h"
81 #include "ContainerWindow.h"
83 #include "FunctionObject.h"
84 #include "IconMenuItem.h"
85 #include "MimeTypes.h"
89 #undef B_TRANSLATION_CONTEXT
90 #define B_TRANSLATION_CONTEXT "FindPanel"
93 const char* kAllMimeTypes
= "mime/ALLTYPES";
95 const BRect
kInitialRect(0, 0, 0, 0);
96 const int32 kInitialAttrModeWindowHeight
= 140;
97 const int32 kIncrementPerAttribute
= 30;
98 const float kMoreOptionsDelta
= 20;
100 const uint32 kMoreOptionsMessage
= 'mrop';
101 const uint32 kNameModifiedMessage
= 'nmmd';
102 const uint32 kSwitchToQueryTemplate
= 'swqt';
103 const uint32 kRunSaveAsTemplatePanel
= 'svtm';
104 const uint32 kLatchChanged
= 'ltch';
106 const char* kDragNDropTypes
[] = {
108 B_QUERY_TEMPLATE_MIMETYPE
110 static const char* kDragNDropActionSpecifiers
[] = {
111 B_TRANSLATE_MARK("Create a Query"),
112 B_TRANSLATE_MARK("Create a Query template")
115 const uint32 kAttachFile
= 'attf';
117 const int32 operators
[] = {
127 static const char* operatorLabels
[] = {
128 B_TRANSLATE_MARK("contains"),
129 B_TRANSLATE_MARK("is"),
130 B_TRANSLATE_MARK("is not"),
131 B_TRANSLATE_MARK("starts with"),
132 B_TRANSLATE_MARK("ends with"),
133 B_TRANSLATE_MARK("greater than"),
134 B_TRANSLATE_MARK("less than"),
135 B_TRANSLATE_MARK("before"),
136 B_TRANSLATE_MARK("after")
142 class MostUsedNames
{
144 MostUsedNames(const char* fileName
, const char* directory
,
148 bool ObtainList(BList
* list
);
151 void AddName(const char*);
159 static int CompareNames(const void* a
, const void* b
);
163 const char* fFileName
;
164 const char* fDirectory
;
166 mutable Benaphore fLock
;
172 MostUsedNames
gMostUsedMimeTypes("MostUsedMimeTypes", "Tracker");
175 // #pragma mark - MoreOptionsStruct
179 MoreOptionsStruct::EndianSwap(void*)
186 MoreOptionsStruct::SetQueryTemporary(BNode
* node
, bool on
)
188 MoreOptionsStruct saveMoreOptions
;
190 if (ReadAttr(node
, kAttrQueryMoreOptions
, kAttrQueryMoreOptionsForeign
,
191 B_RAW_TYPE
, 0, &saveMoreOptions
, sizeof(MoreOptionsStruct
),
192 &MoreOptionsStruct::EndianSwap
) == B_OK
) {
193 saveMoreOptions
.temporary
= on
;
194 node
->WriteAttr(kAttrQueryMoreOptions
, B_RAW_TYPE
, 0, &saveMoreOptions
,
195 sizeof(saveMoreOptions
));
201 MoreOptionsStruct::QueryTemporary(const BNode
* node
)
203 MoreOptionsStruct saveMoreOptions
;
205 if (ReadAttr(node
, kAttrQueryMoreOptions
, kAttrQueryMoreOptionsForeign
,
206 B_RAW_TYPE
, 0, &saveMoreOptions
, sizeof(MoreOptionsStruct
),
207 &MoreOptionsStruct::EndianSwap
) == kReadAttrFailed
) {
211 return saveMoreOptions
.temporary
;
215 // #pragma mark - FindWindow
218 FindWindow::FindWindow(const entry_ref
* newRef
, bool editIfTemplateOnly
)
220 BWindow(kInitialRect
, B_TRANSLATE("Find"), B_TITLED_WINDOW
,
221 B_NOT_RESIZABLE
| B_NOT_ZOOMABLE
| B_CLOSE_ON_ESCAPE
222 | B_AUTO_UPDATE_SIZE_LIMITS
),
223 fFile(TryOpening(newRef
)),
224 fFromTemplate(false),
225 fEditTemplateOnly(false),
226 fSaveAsTemplatePanel(NULL
)
230 if (editIfTemplateOnly
) {
231 char type
[B_MIME_TYPE_LENGTH
];
232 if (BNodeInfo(fFile
).GetType(type
) == B_OK
233 && strcasecmp(type
, B_QUERY_TEMPLATE_MIMETYPE
) == 0) {
234 fEditTemplateOnly
= true;
235 SetTitle(B_TRANSLATE("Edit Query template"));
239 // no initial query, fall back on the default query template
241 GetDefaultQuery(entry
);
245 fFile
= TryOpening(&fRef
);
247 // no default query template yet
248 fFile
= new BFile(&entry
, O_RDWR
| O_CREAT
);
249 if (fFile
->InitCheck() < B_OK
) {
253 SaveQueryAttributes(fFile
, true);
257 fFromTemplate
= IsQueryTemplate(fFile
);
259 fBackground
= new FindPanel(fFile
, this, fFromTemplate
,
261 SetLayout(new BGroupLayout(B_VERTICAL
));
262 GetLayout()->AddView(fBackground
);
267 FindWindow::~FindWindow()
270 delete fSaveAsTemplatePanel
;
275 FindWindow::TryOpening(const entry_ref
* ref
)
280 BFile
* result
= new BFile(ref
, O_RDWR
);
281 if (result
->InitCheck() != B_OK
) {
290 FindWindow::GetDefaultQuery(BEntry
& entry
)
293 if (find_directory(B_USER_DIRECTORY
, &path
, true) == B_OK
294 && path
.Append("queries") == B_OK
295 && (mkdir(path
.Path(), 0777) == 0 || errno
== EEXIST
)) {
296 BDirectory
directory(path
.Path());
297 entry
.SetTo(&directory
, "default");
303 FindWindow::IsQueryTemplate(BNode
* file
)
305 char type
[B_MIME_TYPE_LENGTH
];
306 if (BNodeInfo(file
).GetType(type
) != B_OK
)
309 return strcasecmp(type
, B_QUERY_TEMPLATE_MIMETYPE
) == 0;
314 FindWindow::SwitchToTemplate(const entry_ref
* ref
)
317 BEntry
entry(ref
, true);
318 BFile
templateFile(&entry
, O_RDONLY
);
320 ThrowOnInitCheckError(&templateFile
);
321 fBackground
->SwitchToTemplate(&templateFile
);
329 FindWindow::QueryName() const
332 if (!fQueryNameFromTemplate
.Length()) {
333 fFile
->ReadAttrString(kAttrQueryTemplateName
,
334 &fQueryNameFromTemplate
);
337 return fQueryNameFromTemplate
.String();
347 MakeValidFilename(BString
& string
)
349 // make a file name that is legal under bfs and hfs - possibly could
350 // add code here to accomodate FAT32 etc. too
351 if (string
.Length() > B_FILE_NAME_LENGTH
- 1) {
352 string
.Truncate(B_FILE_NAME_LENGTH
- 4);
353 string
+= B_UTF8_ELLIPSIS
;
357 int32 length
= string
.Length();
358 char* buf
= string
.LockBuffer(length
);
359 for (int32 index
= length
; index
-- > 0;) {
360 if (buf
[index
] == '/' /*|| buf[index] == ':'*/)
363 string
.UnlockBuffer(length
);
365 return string
.String();
370 FindWindow::GetPredicateString(BString
& predicate
, bool& dynamicDate
)
373 switch (fBackground
->Mode()) {
375 fBackground
->GetByNamePredicate(&query
);
376 query
.GetPredicate(&predicate
);
381 BTextControl
* textControl
382 = dynamic_cast<BTextControl
*>(FindView("TextControl"));
383 if (textControl
!= NULL
)
384 predicate
.SetTo(textControl
->Text(), 1023);
388 case kByAttributeItem
:
389 fBackground
->GetByAttrPredicate(&query
, dynamicDate
);
390 query
.GetPredicate(&predicate
);
397 FindWindow::GetDefaultName(BString
& name
)
399 fBackground
->GetDefaultName(name
);
401 time_t timeValue
= time(0);
402 char namebuf
[B_FILE_NAME_LENGTH
];
405 localtime_r(&timeValue
, &timeData
);
407 strftime(namebuf
, 32, " - %b %d, %I:%M:%S %p", &timeData
);
410 MakeValidFilename(name
);
415 FindWindow::SaveQueryAttributes(BNode
* file
, bool queryTemplate
)
417 ThrowOnError(BNodeInfo(file
).SetType(
418 queryTemplate
? B_QUERY_TEMPLATE_MIMETYPE
: B_QUERY_MIMETYPE
));
420 // save date/time info for recent query support and transient query killer
421 int32 currentTime
= (int32
)time(0);
422 file
->WriteAttr(kAttrQueryLastChange
, B_INT32_TYPE
, 0, ¤tTime
,
425 file
->WriteAttr("_trk/recentQuery", B_INT32_TYPE
, 0, &tmp
, sizeof(int32
));
430 FindWindow::SaveQueryAsAttributes(BNode
* file
, BEntry
* entry
,
431 bool queryTemplate
, const BMessage
* oldAttributes
,
432 const BPoint
* oldLocation
)
434 if (oldAttributes
!= NULL
) {
435 // revive old window settings
436 BContainerWindow::SetLayoutState(file
, oldAttributes
);
439 if (oldLocation
!= NULL
) {
440 // and the file's location
441 FSSetPoseLocation(entry
, *oldLocation
);
444 BNodeInfo(file
).SetType(queryTemplate
445 ? B_QUERY_TEMPLATE_MIMETYPE
: B_QUERY_MIMETYPE
);
449 GetPredicateString(predicate
, dynamicDate
);
450 file
->WriteAttrString(kAttrQueryString
, &predicate
);
453 file
->WriteAttr(kAttrDynamicDateQuery
, B_BOOL_TYPE
, 0, &dynamicDate
,
454 sizeof(dynamicDate
));
458 file
->WriteAttr("_trk/recentQuery", B_INT32_TYPE
, 0, &tmp
, sizeof(int32
));
460 // write some useful info to help locate the volume to query
461 BMenuItem
* item
= fBackground
->VolMenu()->FindMarked();
467 int32 itemCount
= fBackground
->VolMenu()->CountItems();
468 for (int32 index
= 2; index
< itemCount
; index
++) {
469 BMenuItem
* item
= fBackground
->VolMenu()->ItemAt(index
);
471 if (!item
->IsMarked())
474 if (item
->Message()->FindInt32("device", &dev
) != B_OK
)
479 EmbedUniqueVolumeInfo(&message
, &volume
);
483 // do we need to embed any volumes
484 ssize_t size
= message
.FlattenedSize();
486 status_t result
= message
.Flatten(buffer
.LockBuffer(size
), size
);
487 if (result
== B_OK
) {
488 if (file
->WriteAttr(kAttrQueryVolume
, B_MESSAGE_TYPE
, 0,
489 buffer
.String(), (size_t)size
) != size
) {
493 buffer
.UnlockBuffer();
495 // default to query for everything
498 fBackground
->SaveWindowState(file
, fEditTemplateOnly
);
499 // write out all the dialog items as attributes so that the query can
500 // be reopened and edited later
502 BView
* focusedItem
= CurrentFocus();
503 if (focusedItem
!= NULL
) {
504 // text controls never get the focus, their internal text views do
505 BView
* parent
= focusedItem
->Parent();
506 if (dynamic_cast<BTextControl
*>(parent
) != NULL
)
507 focusedItem
= parent
;
509 // write out the current focus and, if text control, selection
510 BString
name(focusedItem
->Name());
511 file
->WriteAttrString("_trk/focusedView", &name
);
512 BTextControl
* textControl
= dynamic_cast<BTextControl
*>(focusedItem
);
513 if (textControl
!= NULL
&& textControl
->TextView() != NULL
) {
516 textControl
->TextView()->GetSelection(&selStart
, &selEnd
);
517 file
->WriteAttr("_trk/focusedSelStart", B_INT32_TYPE
, 0,
518 &selStart
, sizeof(selStart
));
519 file
->WriteAttr("_trk/focusedSelEnd", B_INT32_TYPE
, 0,
520 &selEnd
, sizeof(selEnd
));
531 FindSaveCommon(false);
533 // close the find panel
534 PostMessage(B_QUIT_REQUESTED
);
541 if (!FindSaveCommon(true)) {
542 // have to wait for the node monitor to force old query to close
543 // to avoid a race condition
544 TTracker
* tracker
= dynamic_cast<TTracker
*>(be_app
);
545 ASSERT(tracker
!= NULL
);
547 for (int32 timeOut
= 0; ; timeOut
++) {
548 if (tracker
!= NULL
&& !tracker
->EntryHasWindowOpen(&fRef
)) {
549 // window quit, we can post refs received to open a
554 // PRINT(("waiting for query window to quit, %d\n", timeOut));
555 if (timeOut
== 5000) {
556 // the old query window would not quit for some reason
558 PostMessage(B_QUIT_REQUESTED
);
565 int32 currentTime
= (int32
)time(0);
566 fFile
->WriteAttr(kAttrQueryLastChange
, B_INT32_TYPE
, 0, ¤tTime
,
569 // tell the tracker about it
570 BMessage
message(B_REFS_RECEIVED
);
571 message
.AddRef("refs", &fRef
);
572 be_app
->PostMessage(&message
);
574 // close the find panel
575 PostMessage(B_QUIT_REQUESTED
);
580 FindWindow::FindSaveCommon(bool find
)
582 // figure out what we need to do
583 bool readFromOldFile
= fFile
!= NULL
;
584 bool replaceOriginal
= fFile
&& (!fFromTemplate
|| fEditTemplateOnly
);
585 bool keepPoseLocation
= replaceOriginal
;
586 bool newFile
= !fFile
|| (fFromTemplate
&& !fEditTemplateOnly
);
589 BMessage oldAttributes
;
591 bool hadLocation
= false;
592 const char* userSpecifiedName
= fBackground
->UserSpecifiedName();
594 if (readFromOldFile
) {
596 BContainerWindow::GetLayoutState(fFile
, &oldAttributes
);
597 hadLocation
= FSGetPoseLocation(fFile
, &location
);
600 if (replaceOriginal
) {
603 // remove the current entry - need to do this to quit the
604 // running query and to close the corresponding window
606 if (userSpecifiedName
!= NULL
&& !fEditTemplateOnly
) {
607 // change the name of the old query per users request
608 fRef
.set_name(userSpecifiedName
);
614 // create query file in the user's directory
616 // there might be no queries folder yet, create one
617 if (find_directory(B_USER_DIRECTORY
, &path
, true) == B_OK
618 && path
.Append("queries") == B_OK
619 && (mkdir(path
.Path(), 0777) == 0 || errno
== EEXIST
)) {
620 // either use the user specified name, or go with the name
621 // generated from the predicate, etc.
623 if (userSpecifiedName
== NULL
)
624 GetDefaultName(name
);
626 name
<< userSpecifiedName
;
628 if (path
.Append(name
.String()) == B_OK
) {
629 entry
.SetTo(path
.Path());
636 fFile
= new BFile(&entry
, O_RDWR
| O_CREAT
);
637 ASSERT(fFile
->InitCheck() == B_OK
);
639 SaveQueryAsAttributes(fFile
, &entry
, !find
, newFile
? 0 : &oldAttributes
,
640 (hadLocation
&& keepPoseLocation
) ? &location
: 0);
647 FindWindow::MessageReceived(BMessage
* message
)
649 switch (message
->what
) {
663 if (message
->FindString("name", &name
) == B_OK
664 && message
->FindRef("directory", &dir
) == B_OK
665 && message
->FindBool("template", &queryTemplate
)
669 BDirectory
directory(&dir
);
670 BEntry
entry(&directory
, name
);
672 entry
.GetRef(&tmpRef
);
673 fFile
= TryOpening(&tmpRef
);
676 SaveQueryAsAttributes(fFile
, &entry
, queryTemplate
,
678 // try to save whatever state we aleady have
679 // to the new query so that if the user
680 // opens it before runing it from the find panel,
681 // something reasonable happens
687 case kSwitchToQueryTemplate
:
690 if (message
->FindRef("refs", &ref
) == B_OK
)
691 SwitchToTemplate(&ref
);
696 case kRunSaveAsTemplatePanel
:
697 if (fSaveAsTemplatePanel
!= NULL
)
698 fSaveAsTemplatePanel
->Show();
700 BMessenger
panel(BackgroundView());
701 fSaveAsTemplatePanel
= new BFilePanel(B_SAVE_PANEL
, &panel
);
702 fSaveAsTemplatePanel
->SetSaveText(
703 B_TRANSLATE("Query template"));
704 fSaveAsTemplatePanel
->Window()->SetTitle(
705 B_TRANSLATE("Save as Query template:"));
706 fSaveAsTemplatePanel
->Show();
711 _inherited::MessageReceived(message
);
717 // #pragma mark - FindPanel
720 FindPanel::FindPanel(BFile
* node
, FindWindow
* parent
, bool fromTemplate
,
721 bool editTemplateOnly
)
723 BView("MainView", B_WILL_DRAW
),
728 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
729 SetLowUIColor(ViewUIColor());
731 uint32 initialMode
= InitialMode(node
);
733 BMessenger
self(this);
734 fRecentQueries
= new BPopUpMenu(B_TRANSLATE("Recent queries"), false,
736 AddRecentQueries(fRecentQueries
, true, &self
, kSwitchToQueryTemplate
);
738 // add popup for mime types
739 fMimeTypeMenu
= new BPopUpMenu("MimeTypeMenu");
740 fMimeTypeMenu
->SetRadioMode(false);
741 AddMimeTypesToMenu();
743 fMimeTypeField
= new BMenuField("MimeTypeMenu", "", fMimeTypeMenu
);
744 fMimeTypeField
->SetDivider(0.0f
);
745 fMimeTypeField
->MenuItem()->SetLabel(B_TRANSLATE("All files and folders"));
746 // add popup for search criteria
747 fSearchModeMenu
= new BPopUpMenu("searchMode");
748 fSearchModeMenu
->AddItem(new BMenuItem(B_TRANSLATE("by name"),
749 new BMessage(kByNameItem
)));
750 fSearchModeMenu
->AddItem(new BMenuItem(B_TRANSLATE("by attribute"),
751 new BMessage(kByAttributeItem
)));
752 fSearchModeMenu
->AddItem(new BMenuItem(B_TRANSLATE("by formula"),
753 new BMessage(kByFormulaItem
)));
755 fSearchModeMenu
->ItemAt(initialMode
== kByNameItem
? 0 :
756 (initialMode
== kByAttributeItem
? 1 : 2))->SetMarked(true);
757 // mark the appropriate mode
758 BMenuField
* searchModeField
= new BMenuField("", "", fSearchModeMenu
);
759 searchModeField
->SetDivider(0.0f
);
761 // add popup for volume list
762 fVolMenu
= new BPopUpMenu("", false, false);
763 BMenuField
* volumeField
= new BMenuField("", B_TRANSLATE("On"), fVolMenu
);
764 volumeField
->SetDivider(volumeField
->StringWidth(volumeField
->Label()) + 8);
765 AddVolumes(fVolMenu
);
767 if (!editTemplateOnly
) {
768 BPoint
draggableIconOrigin(0, 0);
769 BMessage
dragNDropMessage(B_SIMPLE_DATA
);
770 dragNDropMessage
.AddInt32("be:actions", B_COPY_TARGET
);
771 dragNDropMessage
.AddString("be:types", B_FILE_MIME_TYPE
);
772 dragNDropMessage
.AddString("be:filetypes", kDragNDropTypes
[0]);
773 dragNDropMessage
.AddString("be:filetypes", kDragNDropTypes
[1]);
774 dragNDropMessage
.AddString("be:actionspecifier",
775 B_TRANSLATE_NOCOLLECT(kDragNDropActionSpecifiers
[0]));
776 dragNDropMessage
.AddString("be:actionspecifier",
777 B_TRANSLATE_NOCOLLECT(kDragNDropActionSpecifiers
[1]));
779 BMessenger
self(this);
780 BRect draggableRect
= DraggableIcon::PreferredRect(draggableIconOrigin
,
782 fDraggableIcon
= new DraggableQueryIcon(draggableRect
,
783 "saveHere", &dragNDropMessage
, self
,
784 B_FOLLOW_LEFT
| B_FOLLOW_BOTTOM
);
785 fDraggableIcon
->SetExplicitMaxSize(
786 BSize(draggableRect
.right
- draggableRect
.left
,
787 draggableRect
.bottom
- draggableRect
.top
));
790 fQueryName
= new BTextControl("query name", B_TRANSLATE("Query name:"),
791 "", NULL
, B_WILL_DRAW
| B_NAVIGABLE
| B_NAVIGABLE_JUMP
);
792 FillCurrentQueryName(fQueryName
, parent
);
793 fSearchTrashCheck
= new BCheckBox("searchTrash",
794 B_TRANSLATE("Include trash"), NULL
);
795 fTemporaryCheck
= new BCheckBox("temporary",
796 B_TRANSLATE("Temporary"), NULL
);
797 fTemporaryCheck
->SetValue(B_CONTROL_ON
);
799 BView
* checkboxGroup
= BLayoutBuilder::Group
<>(B_HORIZONTAL
)
800 .Add(fSearchTrashCheck
)
801 .Add(fTemporaryCheck
)
804 // add the more options collapsible pane
805 fMoreOptions
= new BBox(B_NO_BORDER
, BLayoutBuilder::Group
<>()
806 .AddGrid(B_USE_SMALL_SPACING
, B_USE_SMALL_SPACING
)
807 .Add(fQueryName
->CreateLabelLayoutItem(), 0, 0)
808 .Add(fQueryName
->CreateTextViewLayoutItem(), 1, 0)
809 .Add(BSpaceLayoutItem::CreateHorizontalStrut(0), 0, 1)
810 .Add(checkboxGroup
, 1, 1)
814 fLatch
= new PaneSwitch("optionsLatch", true, B_WILL_DRAW
);
815 fLatch
->SetLabels(B_TRANSLATE("Fewer options"), B_TRANSLATE("More options"));
817 fLatch
->SetMessage(new BMessage(kLatchChanged
));
818 fLatch
->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT
,
819 B_ALIGN_VERTICAL_CENTER
));
820 fMoreOptions
->Hide();
824 if (editTemplateOnly
) {
825 button
= new BButton("save", B_TRANSLATE("Save"),
826 new BMessage(kSaveButton
), B_FOLLOW_RIGHT
+ B_FOLLOW_BOTTOM
);
828 button
= new BButton("find", B_TRANSLATE("Search"),
829 new BMessage(kFindButton
), B_FOLLOW_RIGHT
+ B_FOLLOW_BOTTOM
);
831 button
->MakeDefault(true);
833 BView
* icon
= fDraggableIcon
;
835 icon
= new BBox("no draggable icon", B_WILL_DRAW
, B_NO_BORDER
);
836 icon
->SetExplicitMaxSize(BSize(0, 0));
839 BView
* mimeTypeFieldSpacer
= new BBox("MimeTypeMenuSpacer", B_WILL_DRAW
,
841 mimeTypeFieldSpacer
->SetExplicitMaxSize(BSize(0, 0));
843 BBox
* queryControls
= new BBox("Box");
844 queryControls
->SetBorder(B_NO_BORDER
);
846 BBox
* queryBox
= new BBox("Outer Controls");
847 queryBox
->SetLabel(new BMenuField("RecentQueries", NULL
, fRecentQueries
));
849 BGroupView
* queryBoxView
= new BGroupView(B_VERTICAL
,
850 B_USE_DEFAULT_SPACING
);
851 queryBoxView
->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING
);
852 queryBox
->AddChild(queryBoxView
);
854 icon
->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT
, B_ALIGN_BOTTOM
));
855 button
->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT
, B_ALIGN_BOTTOM
));
857 BLayoutBuilder::Group
<>(queryBoxView
, B_VERTICAL
, B_USE_DEFAULT_SPACING
)
858 .SetInsets(B_USE_DEFAULT_SPACING
)
859 .AddGroup(B_HORIZONTAL
, B_USE_SMALL_SPACING
)
861 .Add(mimeTypeFieldSpacer
)
862 .Add(searchModeField
)
863 .AddStrut(B_USE_DEFAULT_SPACING
)
866 .Add(new BSeparatorView(B_HORIZONTAL
, B_PLAIN_BORDER
))
868 BLayoutBuilder::Group
<>(this, B_VERTICAL
, B_USE_DEFAULT_SPACING
)
869 .SetInsets(B_USE_WINDOW_SPACING
)
871 .AddGroup(B_HORIZONTAL
, B_USE_DEFAULT_SPACING
)
873 .AddGroup(B_VERTICAL
)
874 .AddGroup(B_HORIZONTAL
)
876 .Add(new BSeparatorView(B_HORIZONTAL
, B_PLAIN_BORDER
))
883 if (initialMode
!= kByAttributeItem
)
884 AddByNameOrFormulaItems();
886 AddByAttributeItems(node
);
888 ResizeMenuField(fMimeTypeField
);
889 ResizeMenuField(searchModeField
);
890 ResizeMenuField(volumeField
);
894 FindPanel::~FindPanel()
900 FindPanel::AttachedToWindow()
902 FindWindow
* findWindow
= dynamic_cast<FindWindow
*>(Window());
903 ASSERT(findWindow
!= NULL
);
905 if (findWindow
== NULL
)
908 BNode
* node
= findWindow
->QueryNode();
909 fSearchModeMenu
->SetTargetForItems(this);
910 fQueryName
->SetTarget(this);
911 fLatch
->SetTarget(this);
912 RestoreMimeTypeMenuSelection(node
);
913 // preselect the mime we used the last time have to do it here
914 // because AddByAttributeItems will build different menus based
915 // on which mime type is preselected
916 RestoreWindowState(node
);
918 if (!findWindow
->CurrentFocus()) {
919 // try to pick a good focus if we restore to one already
920 BTextControl
* textControl
921 = dynamic_cast<BTextControl
*>(FindView("TextControl"));
922 if (textControl
== NULL
) {
923 // pick the last text control in the attribute view
924 BString
title("TextEntry");
925 title
<< (fAttrGrid
->CountRows() - 1);
926 textControl
= dynamic_cast<BTextControl
*>(FindView(title
.String()));
928 if (textControl
!= NULL
)
929 textControl
->MakeFocus();
932 BButton
* button
= dynamic_cast<BButton
*>(FindView("remove button"));
934 button
->SetTarget(this);
936 button
= dynamic_cast<BButton
*>(FindView("add button"));
938 button
->SetTarget(this);
940 fVolMenu
->SetTargetForItems(this);
942 // set target for MIME type items
943 for (int32 index
= MimeTypeMenu()->CountItems(); index
-- > 2;) {
944 BMenu
* submenu
= MimeTypeMenu()->ItemAt(index
)->Submenu();
946 submenu
->SetTargetForItems(this);
948 fMimeTypeMenu
->SetTargetForItems(this);
950 BMenuItem
* firstItem
= fMimeTypeMenu
->ItemAt(0);
951 if (firstItem
!= NULL
)
952 firstItem
->SetMarked(true);
954 if (fDraggableIcon
!= NULL
)
955 fDraggableIcon
->SetTarget(BMessenger(this));
957 fRecentQueries
->SetTargetForItems(findWindow
);
962 FindPanel::ResizeMenuField(BMenuField
* menuField
)
965 menuField
->GetPreferredSize(&size
.width
, &size
.height
);
967 BMenu
* menu
= menuField
->Menu();
969 float padding
= 0.0f
;
972 BMenuItem
* markedItem
= menu
->FindMarked();
973 if (markedItem
!= NULL
) {
974 if (markedItem
->Submenu() != NULL
) {
975 BMenuItem
* markedSubItem
= markedItem
->Submenu()->FindMarked();
976 if (markedSubItem
!= NULL
&& markedSubItem
->Label() != NULL
) {
978 = menuField
->StringWidth(markedSubItem
->Label());
979 padding
= size
.width
- labelWidth
;
981 } else if (markedItem
->Label() != NULL
) {
982 float labelWidth
= menuField
->StringWidth(markedItem
->Label());
983 padding
= size
.width
- labelWidth
;
987 for (int32 index
= menu
->CountItems(); index
-- > 0; ) {
988 BMenuItem
* item
= menu
->ItemAt(index
);
989 if (item
->Label() != NULL
)
990 width
= std::max(width
, menuField
->StringWidth(item
->Label()));
992 BMenu
* submenu
= item
->Submenu();
993 if (submenu
!= NULL
) {
994 for (int32 subIndex
= submenu
->CountItems(); subIndex
-- > 0; ) {
995 BMenuItem
* subItem
= submenu
->ItemAt(subIndex
);
996 if (subItem
->Label() == NULL
)
999 width
= std::max(width
,
1000 menuField
->StringWidth(subItem
->Label()));
1005 float maxWidth
= be_control_look
->DefaultItemSpacing() * 20;
1006 size
.width
= std::min(width
+ padding
, maxWidth
);
1007 menuField
->SetExplicitSize(size
);
1011 PopUpMenuSetTitle(BMenu
* menu
, const char* title
)
1013 // This should really be in BMenuField
1014 BMenu
* bar
= menu
->Supermenu();
1017 ASSERT(bar
->ItemAt(0));
1018 if (bar
== NULL
|| !bar
->ItemAt(0))
1021 bar
->ItemAt(0)->SetLabel(title
);
1026 FindPanel::ShowVolumeMenuLabel()
1028 if (fVolMenu
->ItemAt(0)->IsMarked()) {
1029 // "all disks" selected
1030 PopUpMenuSetTitle(fVolMenu
, fVolMenu
->ItemAt(0)->Label());
1034 // find out if more than one items are marked
1035 int32 count
= fVolMenu
->CountItems();
1036 int32 countSelected
= 0;
1037 BMenuItem
* tmpItem
= NULL
;
1038 for (int32 index
= 2; index
< count
; index
++) {
1039 BMenuItem
* item
= fVolMenu
->ItemAt(index
);
1040 if (item
->IsMarked()) {
1046 if (countSelected
== 0) {
1047 // no disk selected, for now revert to search all disks
1049 // show no disks here and add a check that will not let the
1050 // query go if the user doesn't pick at least one
1051 fVolMenu
->ItemAt(0)->SetMarked(true);
1052 PopUpMenuSetTitle(fVolMenu
, fVolMenu
->ItemAt(0)->Label());
1053 } else if (countSelected
> 1)
1054 // if more than two disks selected, don't use the disk name
1056 PopUpMenuSetTitle(fVolMenu
, B_TRANSLATE("multiple disks"));
1059 PopUpMenuSetTitle(fVolMenu
, tmpItem
->Label());
1065 FindPanel::Draw(BRect
)
1067 if (fAttrGrid
== NULL
)
1070 for (int32 index
= 0; index
< fAttrGrid
->CountRows(); index
++) {
1071 BMenuField
* menuField
1072 = dynamic_cast<BMenuField
*>(FindAttrView("MenuField", index
));
1073 if (menuField
== NULL
)
1076 BLayoutItem
* stringViewLayoutItem
= fAttrGrid
->ItemAt(1, index
);
1077 if (stringViewLayoutItem
== NULL
)
1080 BMenu
* menuFieldMenu
= menuField
->Menu();
1081 if (menuFieldMenu
== NULL
)
1084 BMenuItem
* item
= menuFieldMenu
->FindMarked();
1085 if (item
== NULL
|| item
->Submenu() == NULL
1086 || item
->Submenu()->FindMarked() == NULL
) {
1090 if (stringViewLayoutItem
== NULL
) {
1091 stringViewLayoutItem
= fAttrGrid
->AddView(new BStringView("",
1092 item
->Submenu()->FindMarked()->Label()), 1, index
);
1093 stringViewLayoutItem
->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT
,
1094 B_ALIGN_VERTICAL_UNSET
));
1097 if (stringViewLayoutItem
!= NULL
) {
1098 BStringView
* stringView
1099 = dynamic_cast<BStringView
*>(stringViewLayoutItem
->View());
1100 if (stringView
!= NULL
) {
1101 BMenu
* submenu
= item
->Submenu();
1102 if (submenu
!= NULL
) {
1103 BMenuItem
* selected
= submenu
->FindMarked();
1104 if (selected
!= NULL
)
1105 stringView
->SetText(selected
->Label());
1114 FindPanel::MessageReceived(BMessage
* message
)
1120 switch (message
->what
) {
1124 BMenuItem
* invokedItem
;
1126 if (message
->FindPointer("source", (void**)&invokedItem
) != B_OK
)
1129 if (message
->FindInt32("device", &dev
) != B_OK
)
1132 BMenu
* menu
= invokedItem
->Menu();
1136 // all disks selected, uncheck everything else
1137 int32 count
= menu
->CountItems();
1138 for (int32 index
= 2; index
< count
; index
++)
1139 menu
->ItemAt(index
)->SetMarked(false);
1141 // make all disks the title and check it
1142 PopUpMenuSetTitle(menu
, menu
->ItemAt(0)->Label());
1143 menu
->ItemAt(0)->SetMarked(true);
1145 // a specific volume selected, unmark "all disks"
1146 menu
->ItemAt(0)->SetMarked(false);
1148 // toggle mark on invoked item
1149 int32 count
= menu
->CountItems();
1150 for (int32 index
= 2; index
< count
; index
++) {
1151 BMenuItem
* item
= menu
->ItemAt(index
);
1153 if (invokedItem
== item
) {
1154 // we just selected this
1155 bool wasMarked
= item
->IsMarked();
1156 item
->SetMarked(!wasMarked
);
1160 // make sure the right label is showing
1161 ShowVolumeMenuLabel();
1166 case kByAttributeItem
:
1168 case kByFormulaItem
:
1169 SwitchMode(message
->what
);
1182 if (fMode
== kByAttributeItem
) {
1183 // the attributes for this type may be different
1184 RemoveAttrViewItems(false);
1189 if (message
->FindPointer("source", (void**)&item
) == B_OK
) {
1190 // don't add the "All files and folders" to the list
1191 if (fMimeTypeMenu
->IndexOf(item
) != 0)
1192 gMostUsedMimeTypes
.AddName(item
->Label());
1194 SetCurrentMimeType(item
);
1200 case kNameModifiedMessage
:
1201 // the query name was edited, make the query permanent
1202 fTemporaryCheck
->SetValue(0);
1205 case kAttributeItem
:
1206 if (message
->FindPointer("source", (void**)&item
) != B_OK
)
1209 item
->Menu()->Superitem()->SetMarked(true);
1213 case kAttributeItemMain
:
1214 // in case someone selected just an attribute without the
1216 if (message
->FindPointer("source", (void**)&item
) != B_OK
)
1219 if (item
->Submenu()->ItemAt(0) != NULL
)
1220 item
->Submenu()->ItemAt(0)->SetMarked(true);
1228 if (message
->FindInt32("be:value", &value
) != B_OK
)
1231 if (value
== 0 && !fMoreOptions
->IsHidden(this))
1232 fMoreOptions
->Hide();
1233 else if (value
== 1 && fMoreOptions
->IsHidden(this))
1234 fMoreOptions
->Show();
1239 case B_SAVE_REQUESTED
:
1241 // finish saving query template from a SaveAs panel
1243 status_t error
= message
->FindRef("refs", &ref
);
1245 if (error
== B_OK
) {
1246 // direct entry selected, convert to parent dir and name
1248 error
= entry
.GetParent(&entry
);
1249 if (error
== B_OK
) {
1254 // parent dir and name selected
1255 error
= message
->FindRef("directory", &dir
);
1257 error
= message
->FindString("name", &name
);
1261 SaveAsQueryOrTemplate(&dir
, name
, true);
1270 const char* mimeType
= NULL
;
1271 const char* actionSpecifier
= NULL
;
1273 if (message
->FindString("be:types", &str
) == B_OK
1274 && strcasecmp(str
, B_FILE_MIME_TYPE
) == 0
1275 && (message
->FindString("be:actionspecifier",
1276 &actionSpecifier
) == B_OK
1277 || message
->FindString("be:filetypes", &mimeType
) == B_OK
)
1278 && message
->FindString("name", &name
) == B_OK
1279 && message
->FindRef("directory", &dir
) == B_OK
) {
1282 bool queryTemplate
= false;
1285 && strcasecmp(actionSpecifier
,
1286 B_TRANSLATE_NOCOLLECT(
1287 kDragNDropActionSpecifiers
[0])) == 0) {
1289 } else if (actionSpecifier
1290 && strcasecmp(actionSpecifier
,
1291 B_TRANSLATE_NOCOLLECT(
1292 kDragNDropActionSpecifiers
[1])) == 0) {
1293 queryTemplate
= true;
1294 } else if (mimeType
&& strcasecmp(mimeType
,
1295 kDragNDropTypes
[0]) == 0) {
1297 } else if (mimeType
&& strcasecmp(mimeType
,
1298 kDragNDropTypes
[1]) == 0) {
1299 queryTemplate
= true;
1302 if (query
|| queryTemplate
)
1303 SaveAsQueryOrTemplate(&dir
, name
, queryTemplate
);
1310 _inherited::MessageReceived(message
);
1317 FindPanel::SaveAsQueryOrTemplate(const entry_ref
* dir
, const char* name
,
1320 BDirectory
directory(dir
);
1321 BFile
file(&directory
, name
, O_RDWR
| O_CREAT
| O_TRUNC
);
1322 BNodeInfo(&file
).SetType(queryTemplate
1323 ? B_QUERY_TEMPLATE_MIMETYPE
: B_QUERY_MIMETYPE
);
1325 BMessage
attach(kAttachFile
);
1326 attach
.AddRef("directory", dir
);
1327 attach
.AddString("name", name
);
1328 attach
.AddBool("template", queryTemplate
);
1329 Window()->PostMessage(&attach
, 0);
1334 FindPanel::FindAttrView(const char* name
, int row
) const
1336 for (int32 index
= 0; index
< fAttrGrid
->CountColumns(); index
++) {
1338 BLayoutItem
* item
= fAttrGrid
->ItemAt(index
, row
);
1342 BView
* view
= item
->View();
1346 view
= view
->FindView(name
);
1356 FindPanel::BuildAttrQuery(BQuery
* query
, bool &dynamicDate
) const
1358 dynamicDate
= false;
1360 // go through each attrview and add the attr and comparison info
1361 for (int32 index
= 0; index
< fAttrGrid
->CountRows(); index
++) {
1364 title
<< "TextEntry" << index
;
1366 BTextControl
* textControl
= dynamic_cast<BTextControl
*>(
1367 FindAttrView(title
, index
));
1368 if (textControl
== NULL
)
1371 BMenuField
* menuField
= dynamic_cast<BMenuField
*>(
1372 FindAttrView("MenuField", index
));
1373 if (menuField
== NULL
)
1376 BMenuItem
* item
= menuField
->Menu()->FindMarked();
1380 BMessage
* message
= item
->Message();
1382 if (message
->FindInt32("type", &type
) == B_OK
) {
1385 if (message
->FindString("name", &str
) == B_OK
)
1386 query
->PushAttr(str
);
1388 query
->PushAttr(item
->Label());
1392 query
->PushString(textControl
->Text(), true);
1398 DEBUG_ONLY(time_t result
=)
1399 parsedate_etc(textControl
->Text(), -1,
1401 dynamicDate
= (flags
& PARSEDATE_RELATIVE_TIME
) != 0;
1402 PRINT(("parsedate_etc - date is %srelative, %"
1404 dynamicDate
? "" : "not ", result
));
1406 query
->PushDate(textControl
->Text());
1413 if (strcasecmp(textControl
->Text(),
1416 } else if (strcasecmp(textControl
->Text(),
1420 value
= (uint32
)atoi(textControl
->Text());
1423 query
->PushUInt32(value
);
1430 query
->PushUInt32((uint32
)StringToScalar(
1431 textControl
->Text()));
1437 query
->PushInt32((int32
)StringToScalar(
1438 textControl
->Text()));
1442 query
->PushUInt64((uint64
)StringToScalar(
1443 textControl
->Text()));
1448 query
->PushInt64(StringToScalar(
1449 textControl
->Text()));
1455 sscanf(textControl
->Text(), "%f",
1457 query
->PushFloat(floatVal
);
1464 sscanf(textControl
->Text(), "%lf",
1466 query
->PushDouble(doubleVal
);
1472 query_op theOperator
;
1473 BMenuItem
* operatorItem
= item
->Submenu()->FindMarked();
1474 if (operatorItem
&& operatorItem
->Message() != NULL
) {
1475 operatorItem
->Message()->FindInt32("operator",
1476 (int32
*)&theOperator
);
1477 query
->PushOp(theOperator
);
1479 query
->PushOp(B_EQ
);
1481 // add logic based on selection in Logic menufield
1483 menuField
= dynamic_cast<BMenuField
*>(
1484 FindAttrView("Logic", index
- 1));
1486 item
= menuField
->Menu()->FindMarked();
1488 message
= item
->Message();
1489 message
->FindInt32("combine", (int32
*)&theOperator
);
1490 query
->PushOp(theOperator
);
1493 query
->PushOp(B_AND
);
1500 FindPanel::PushMimeType(BQuery
* query
) const
1503 if (CurrentMimeType(&type
) == NULL
)
1506 if (strcmp(kAllMimeTypes
, type
)) {
1507 // add an asterisk if we are searching for a supertype
1508 char buffer
[B_FILE_NAME_LENGTH
];
1509 if (strchr(type
, '/') == NULL
) {
1510 strlcpy(buffer
, type
, sizeof(buffer
));
1511 strlcat(buffer
, "/*", sizeof(buffer
));
1515 query
->PushAttr(kAttrMIMEType
);
1516 query
->PushString(type
);
1517 query
->PushOp(B_EQ
);
1518 query
->PushOp(B_AND
);
1524 FindPanel::GetByAttrPredicate(BQuery
* query
, bool &dynamicDate
) const
1526 ASSERT(Mode() == (int32
)kByAttributeItem
);
1527 BuildAttrQuery(query
, dynamicDate
);
1528 PushMimeType(query
);
1533 FindPanel::GetDefaultName(BString
& name
) const
1535 BTextControl
* textControl
= dynamic_cast<BTextControl
*>(
1536 FindView("TextControl"));
1540 if (textControl
!= NULL
) {
1541 name
.SetTo(B_TRANSLATE_COMMENT("Name = %name",
1542 "FindResultTitle"));
1543 name
.ReplaceFirst("%name", textControl
->Text());
1547 case kByFormulaItem
:
1548 if (textControl
!= NULL
) {
1549 name
.SetTo(B_TRANSLATE_COMMENT("Formula %formula",
1550 "FindResultTitle"));
1551 name
.ReplaceFirst("%formula", textControl
->Text());
1555 case kByAttributeItem
:
1557 BMenuItem
* item
= fMimeTypeMenu
->FindMarked();
1559 name
<< item
->Label() << ": ";
1561 for (int32 i
= 0; i
< fAttrGrid
->CountRows(); i
++) {
1562 GetDefaultAttrName(name
, i
);
1563 if (i
+ 1 < fAttrGrid
->CountRows())
1573 FindPanel::UserSpecifiedName() const
1575 if (fQueryName
->Text()[0] == '\0')
1578 return fQueryName
->Text();
1583 FindPanel::GetByNamePredicate(BQuery
* query
) const
1585 ASSERT(Mode() == (int32
)kByNameItem
);
1587 BTextControl
* textControl
1588 = dynamic_cast<BTextControl
*>(FindView("TextControl"));
1590 ASSERT(textControl
!= NULL
);
1592 if (textControl
== NULL
)
1595 query
->PushAttr("name");
1596 query
->PushString(textControl
->Text(), true);
1598 if (strstr(textControl
->Text(), "*") != NULL
) {
1599 // assume pattern is a regular expression, try doing an exact match
1600 query
->PushOp(B_EQ
);
1602 query
->PushOp(B_CONTAINS
);
1604 PushMimeType(query
);
1609 FindPanel::SwitchMode(uint32 mode
)
1615 uint32 oldMode
= fMode
;
1619 case kByFormulaItem
:
1621 if (oldMode
== kByAttributeItem
|| oldMode
== kByNameItem
) {
1623 if (oldMode
== kByAttributeItem
) {
1625 GetByAttrPredicate(&query
, dummy
);
1627 GetByNamePredicate(&query
);
1629 query
.GetPredicate(&buffer
);
1636 RemoveByAttributeItems();
1637 ShowOrHideMimeTypeMenu();
1638 AddByNameOrFormulaItems();
1640 if (buffer
.Length() > 0) {
1641 ASSERT(mode
== kByFormulaItem
1642 || oldMode
== kByAttributeItem
);
1643 BTextControl
* textControl
1644 = dynamic_cast<BTextControl
*>(FindView("TextControl"));
1645 if (textControl
!= NULL
)
1646 textControl
->SetText(buffer
.String());
1651 case kByAttributeItem
:
1654 BTextControl
* textControl
1655 = dynamic_cast<BTextControl
*>(FindView("TextControl"));
1656 if (textControl
!= NULL
) {
1657 textControl
->RemoveSelf();
1661 ShowOrHideMimeTypeMenu();
1670 FindPanel::CurrentMimeType(const char** type
) const
1672 // search for marked item in the list
1673 BMenuItem
* item
= MimeTypeMenu()->FindMarked();
1675 if (item
!= NULL
&& MimeTypeMenu()->IndexOf(item
) != 0
1676 && item
->Submenu() == NULL
) {
1677 // if it's one of the most used items, ignore it
1682 for (int32 index
= MimeTypeMenu()->CountItems(); index
-- > 0;) {
1683 BMenu
* submenu
= MimeTypeMenu()->ItemAt(index
)->Submenu();
1684 if (submenu
!= NULL
&& (item
= submenu
->FindMarked()) != NULL
)
1689 if (type
!= NULL
&& item
!= NULL
) {
1690 BMessage
* message
= item
->Message();
1691 if (message
== NULL
)
1694 if (message
->FindString("mimetype", type
) != B_OK
)
1702 FindPanel::SetCurrentMimeType(BMenuItem
* item
)
1704 // unmark old MIME type (in most used list, and the tree)
1706 BMenuItem
* marked
= CurrentMimeType();
1707 if (marked
!= NULL
) {
1708 marked
->SetMarked(false);
1710 if ((marked
= MimeTypeMenu()->FindMarked()) != NULL
)
1711 marked
->SetMarked(false);
1714 // mark new MIME type (in most used list, and the tree)
1717 item
->SetMarked(true);
1718 fMimeTypeField
->MenuItem()->SetLabel(item
->Label());
1721 for (int32 i
= 2; (search
= MimeTypeMenu()->ItemAt(i
)) != NULL
; i
++) {
1722 if (item
== search
|| search
->Label() == NULL
)
1725 if (strcmp(item
->Label(), search
->Label()) == 0) {
1726 search
->SetMarked(true);
1730 BMenu
* submenu
= search
->Submenu();
1731 if (submenu
== NULL
)
1734 for (int32 j
= submenu
->CountItems(); j
-- > 0;) {
1735 BMenuItem
* sub
= submenu
->ItemAt(j
);
1736 if (strcmp(item
->Label(), sub
->Label()) == 0) {
1737 sub
->SetMarked(true);
1749 FindPanel::SetCurrentMimeType(const char* label
)
1751 // unmark old MIME type (in most used list, and the tree)
1753 BMenuItem
* marked
= CurrentMimeType();
1754 if (marked
!= NULL
) {
1755 marked
->SetMarked(false);
1757 if ((marked
= MimeTypeMenu()->FindMarked()) != NULL
)
1758 marked
->SetMarked(false);
1761 // mark new MIME type (in most used list, and the tree)
1763 fMimeTypeField
->MenuItem()->SetLabel(label
);
1766 for (int32 index
= MimeTypeMenu()->CountItems(); index
-- > 0;) {
1767 BMenuItem
* item
= MimeTypeMenu()->ItemAt(index
);
1768 BMenu
* submenu
= item
->Submenu();
1769 if (submenu
!= NULL
&& !found
) {
1770 for (int32 subIndex
= submenu
->CountItems(); subIndex
-- > 0;) {
1771 BMenuItem
* subItem
= submenu
->ItemAt(subIndex
);
1772 if (subItem
->Label() != NULL
1773 && strcmp(label
, subItem
->Label()) == 0) {
1774 subItem
->SetMarked(true);
1780 if (item
->Label() != NULL
&& strcmp(label
, item
->Label()) == 0) {
1781 item
->SetMarked(true);
1786 return found
? B_OK
: B_ENTRY_NOT_FOUND
;
1791 void AddSubtype(BString
& text
, const BMimeType
& type
)
1794 text
.Append(strchr(type
.Type(), '/') + 1);
1801 FindPanel::AddOneMimeTypeToMenu(const ShortMimeInfo
* info
, void* castToMenu
)
1803 BPopUpMenu
* menu
= static_cast<BPopUpMenu
*>(castToMenu
);
1805 BMimeType
type(info
->InternalName());
1807 type
.GetSupertype(&super
);
1808 if (super
.InitCheck() < B_OK
)
1811 BMenuItem
* superItem
= menu
->FindItem(super
.Type());
1812 if (superItem
!= NULL
) {
1813 BMessage
* message
= new BMessage(kMIMETypeItem
);
1814 message
->AddString("mimetype", info
->InternalName());
1816 // check to ensure previous item's name differs
1817 BMenu
* menu
= superItem
->Submenu();
1818 BMenuItem
* previous
= menu
->ItemAt(menu
->CountItems() - 1);
1819 BString text
= info
->ShortDescription();
1820 if (previous
!= NULL
1821 && strcasecmp(previous
->Label(), info
->ShortDescription()) == 0) {
1822 AddSubtype(text
, type
);
1824 // update the previous item as well
1825 BMimeType
type(previous
->Message()->GetString("mimetype", NULL
));
1826 BString label
= ShortMimeInfo(type
).ShortDescription();
1827 AddSubtype(label
, type
);
1828 previous
->SetLabel(label
.String());
1831 menu
->AddItem(new IconMenuItem(text
.String(), message
,
1832 info
->InternalName()));
1840 FindPanel::AddMimeTypesToMenu()
1842 BMessage
* itemMessage
= new BMessage(kMIMETypeItem
);
1843 itemMessage
->AddString("mimetype", kAllMimeTypes
);
1845 IconMenuItem
* firstItem
= new IconMenuItem(
1846 B_TRANSLATE("All files and folders"), itemMessage
,
1847 static_cast<BBitmap
*>(NULL
));
1848 MimeTypeMenu()->AddItem(firstItem
);
1849 MimeTypeMenu()->AddSeparatorItem();
1851 // add recent MIME types
1853 TTracker
* tracker
= dynamic_cast<TTracker
*>(be_app
);
1854 ASSERT(tracker
!= NULL
);
1857 if (tracker
!= NULL
&& gMostUsedMimeTypes
.ObtainList(&list
)) {
1859 for (int32 index
= 0; index
< list
.CountItems(); index
++) {
1860 const char* name
= (const char*)list
.ItemAt(index
);
1862 MimeTypeList
* mimeTypes
= tracker
->MimeTypes();
1863 if (mimeTypes
!= NULL
) {
1864 const ShortMimeInfo
* info
= mimeTypes
->FindMimeType(name
);
1868 BMessage
* message
= new BMessage(kMIMETypeItem
);
1869 message
->AddString("mimetype", info
->InternalName());
1871 MimeTypeMenu()->AddItem(new BMenuItem(name
, message
));
1876 MimeTypeMenu()->AddSeparatorItem();
1878 gMostUsedMimeTypes
.ReleaseList();
1881 // add MIME type tree list
1884 if (BMimeType::GetInstalledSupertypes(&types
) == B_OK
) {
1885 const char* superType
;
1888 while (types
.FindString("super_types", index
++, &superType
) == B_OK
) {
1889 BMenu
* superMenu
= new BMenu(superType
);
1891 BMessage
* message
= new BMessage(kMIMETypeItem
);
1892 message
->AddString("mimetype", superType
);
1894 MimeTypeMenu()->AddItem(new IconMenuItem(superMenu
, message
,
1897 // the MimeTypeMenu's font is not correct at this time
1898 superMenu
->SetFont(be_plain_font
);
1902 if (tracker
!= NULL
) {
1903 tracker
->MimeTypes()->EachCommonType(
1904 &FindPanel::AddOneMimeTypeToMenu
, MimeTypeMenu());
1907 // remove empty super type menus (and set target)
1909 for (int32 index
= MimeTypeMenu()->CountItems(); index
-- > 2;) {
1910 BMenuItem
* item
= MimeTypeMenu()->ItemAt(index
);
1911 BMenu
* submenu
= item
->Submenu();
1912 if (submenu
== NULL
)
1915 if (submenu
->CountItems() == 0) {
1916 MimeTypeMenu()->RemoveItem(item
);
1919 submenu
->SetTargetForItems(this);
1925 FindPanel::AddVolumes(BMenu
* menu
)
1927 // ToDo: add calls to this to rebuild the menu when a volume gets mounted
1929 BMessage
* message
= new BMessage(kVolumeItem
);
1930 message
->AddInt32("device", -1);
1931 menu
->AddItem(new BMenuItem(B_TRANSLATE("All disks"), message
));
1932 menu
->AddSeparatorItem();
1933 PopUpMenuSetTitle(menu
, B_TRANSLATE("All disks"));
1935 BVolumeRoster roster
;
1938 while (roster
.GetNextVolume(&volume
) == B_OK
) {
1939 if (volume
.IsPersistent() && volume
.KnowsQuery()) {
1941 if (volume
.GetRootDirectory(&root
) != B_OK
)
1945 root
.GetEntry(&entry
);
1947 Model
model(&entry
, true);
1948 if (model
.InitCheck() != B_OK
)
1951 message
= new BMessage(kVolumeItem
);
1952 message
->AddInt32("device", volume
.Device());
1953 menu
->AddItem(new ModelMenuItem(&model
, model
.Name(), message
));
1957 if (menu
->ItemAt(0))
1958 menu
->ItemAt(0)->SetMarked(true);
1960 menu
->SetTargetForItems(this);
1964 typedef std::pair
<entry_ref
, uint32
> EntryWithDate
;
1967 SortByDatePredicate(const EntryWithDate
* entry1
, const EntryWithDate
* entry2
)
1969 return entry1
->second
> entry2
->second
?
1970 -1 : (entry1
->second
== entry2
->second
? 0 : 1);
1973 struct AddOneRecentParams
{
1975 const BMessenger
* target
;
1979 static const entry_ref
*
1980 AddOneRecentItem(const entry_ref
* ref
, void* castToParams
)
1982 AddOneRecentParams
* params
= (AddOneRecentParams
*)castToParams
;
1984 BMessage
* message
= new BMessage(params
->what
);
1985 message
->AddRef("refs", ref
);
1987 char type
[B_MIME_TYPE_LENGTH
];
1989 BNodeInfo(&node
).GetType(type
);
1990 BMenuItem
* item
= new IconMenuItem(ref
->name
, message
, type
);
1991 item
->SetTarget(*params
->target
);
1992 params
->menu
->AddItem(item
);
1999 FindPanel::AddRecentQueries(BMenu
* menu
, bool addSaveAsItem
,
2000 const BMessenger
* target
, uint32 what
)
2002 BObjectList
<entry_ref
> templates(10, true);
2003 BObjectList
<EntryWithDate
> recentQueries(10, true);
2005 // find all the queries on all volumes
2006 BVolumeRoster roster
;
2009 while (roster
.GetNextVolume(&volume
) == B_OK
) {
2010 if (volume
.IsPersistent() && volume
.KnowsQuery()
2011 && volume
.KnowsAttr()) {
2013 query
.SetVolume(&volume
);
2014 query
.SetPredicate("_trk/recentQuery == 1");
2015 if (query
.Fetch() != B_OK
)
2019 while (query
.GetNextRef(&ref
) == B_OK
) {
2020 // ignore queries in the Trash
2021 if (FSInTrashDir(&ref
))
2024 char type
[B_MIME_TYPE_LENGTH
];
2026 BNodeInfo(&node
).GetType(type
);
2028 if (strcasecmp(type
, B_QUERY_TEMPLATE_MIMETYPE
) == 0)
2029 templates
.AddItem(new entry_ref(ref
));
2032 if (node
.ReadAttr(kAttrQueryLastChange
, B_INT32_TYPE
, 0,
2033 &changeTime
, sizeof(uint32
)) != sizeof(uint32
))
2036 recentQueries
.AddItem(new EntryWithDate(ref
, changeTime
));
2042 // we are only adding last ten queries
2043 recentQueries
.SortItems(SortByDatePredicate
);
2045 // but all templates
2046 AddOneRecentParams params
;
2048 params
.target
= target
;
2050 templates
.EachElement(AddOneRecentItem
, ¶ms
);
2052 int32 count
= recentQueries
.CountItems();
2054 // show only up to 10 recent queries
2056 } else if (count
< 0)
2059 if (templates
.CountItems() > 0 && count
> 0)
2060 menu
->AddSeparatorItem();
2062 for (int32 index
= 0; index
< count
; index
++)
2063 AddOneRecentItem(&recentQueries
.ItemAt(index
)->first
, ¶ms
);
2065 if (addSaveAsItem
) {
2066 // add a Save as template item
2067 if (count
> 0 || templates
.CountItems() > 0)
2068 menu
->AddSeparatorItem();
2070 BMessage
* message
= new BMessage(kRunSaveAsTemplatePanel
);
2071 BMenuItem
* item
= new BMenuItem(
2072 B_TRANSLATE("Save query as template" B_UTF8_ELLIPSIS
), message
);
2073 menu
->AddItem(item
);
2079 FindPanel::SetUpAddRemoveButtons()
2081 BBox
* box
= dynamic_cast<BBox
*>(FindView("Box"));
2083 ASSERT(box
!= NULL
);
2088 BButton
* removeButton
= new BButton("remove button", B_TRANSLATE("Remove"),
2089 new BMessage(kRemoveItem
));
2090 removeButton
->SetEnabled(false);
2091 removeButton
->SetTarget(this);
2093 BButton
* addButton
= new BButton("add button", B_TRANSLATE("Add"),
2094 new BMessage(kAddItem
));
2095 addButton
->SetTarget(this);
2097 BGroupLayout
* layout
= dynamic_cast<BGroupLayout
*>(box
->GetLayout());
2099 ASSERT(layout
!= NULL
);
2104 BLayoutBuilder::Group
<>(layout
)
2105 .AddGroup(B_HORIZONTAL
)
2115 FindPanel::FillCurrentQueryName(BTextControl
* queryName
, FindWindow
* window
)
2118 queryName
->SetText(window
->QueryName());
2123 FindPanel::AddAttrRow()
2125 BBox
* box
= dynamic_cast<BBox
*>(FindView("Box"));
2127 ASSERT(box
!= NULL
);
2132 BGridView
* grid
= dynamic_cast<BGridView
*>(box
->FindView("AttrFields"));
2135 BLayoutBuilder::Group
<>(box
, B_VERTICAL
);
2137 grid
= new BGridView("AttrFields");
2138 box
->AddChild(grid
);
2141 fAttrGrid
= grid
->GridLayout();
2143 AddAttributeControls(fAttrGrid
->CountRows());
2145 // add logic to previous attrview
2146 if (fAttrGrid
->CountRows() > 1)
2147 AddLogicMenu(fAttrGrid
->CountRows() - 2);
2149 BButton
* removeButton
= dynamic_cast<BButton
*>(
2150 box
->FindView("remove button"));
2151 if (removeButton
!= NULL
)
2152 removeButton
->SetEnabled(fAttrGrid
->CountRows() > 1);
2154 SetUpAddRemoveButtons();
2159 FindPanel::RemoveAttrRow()
2161 if (fAttrGrid
->CountRows() < 2)
2166 int32 row
= fAttrGrid
->CountRows() - 1;
2167 for (int32 col
= fAttrGrid
->CountColumns(); col
> 0; col
--) {
2168 BLayoutItem
* item
= fAttrGrid
->ItemAt(col
- 1, row
);
2172 view
= item
->View();
2180 BString string
= "TextEntry";
2181 string
<< (row
- 1);
2182 view
= FindAttrView(string
.String(), row
- 1);
2186 if (fAttrGrid
->CountRows() > 1) {
2187 // remove the And/Or menu field of the previous row
2188 BLayoutItem
* item
= fAttrGrid
->ItemAt(3, row
- 1);
2192 view
= item
->View();
2201 // only one row remains
2203 // disable the remove button
2204 BButton
* button
= dynamic_cast<BButton
*>(FindView("remove button"));
2206 button
->SetEnabled(false);
2208 // remove the And/Or menu field
2209 BLayoutItem
* item
= fAttrGrid
->RemoveItem(3);
2213 view
= item
->View();
2223 FindPanel::InitialMode(const BNode
* node
)
2225 if (node
== NULL
|| node
->InitCheck() != B_OK
)
2229 if (node
->ReadAttr(kAttrQueryInitialMode
, B_INT32_TYPE
, 0,
2230 (int32
*)&result
, sizeof(int32
)) <= 0)
2238 FindPanel::InitialAttrCount(const BNode
* node
)
2240 if (node
== NULL
|| node
->InitCheck() != B_OK
)
2244 if (node
->ReadAttr(kAttrQueryInitialNumAttrs
, B_INT32_TYPE
, 0,
2245 &result
, sizeof(int32
)) <= 0)
2253 SelectItemWithLabel(BMenu
* menu
, const char* label
)
2255 for (int32 index
= menu
->CountItems(); index
-- > 0;) {
2256 BMenuItem
* item
= menu
->ItemAt(index
);
2258 if (strcmp(label
, item
->Label()) == 0) {
2259 item
->SetMarked(true);
2268 FindPanel::SaveWindowState(BNode
* node
, bool editTemplate
)
2270 ASSERT(node
->InitCheck() == B_OK
);
2272 BMenuItem
* item
= CurrentMimeType();
2274 BString
label(item
->Label());
2275 node
->WriteAttrString(kAttrQueryInitialMime
, &label
);
2278 uint32 mode
= Mode();
2279 node
->WriteAttr(kAttrQueryInitialMode
, B_INT32_TYPE
, 0,
2280 (int32
*)&mode
, sizeof(int32
));
2282 MoreOptionsStruct saveMoreOptions
;
2283 saveMoreOptions
.showMoreOptions
= fLatch
->Value() != 0;
2285 saveMoreOptions
.searchTrash
= fSearchTrashCheck
->Value() != 0;
2286 saveMoreOptions
.temporary
= fTemporaryCheck
->Value() != 0;
2288 if (node
->WriteAttr(kAttrQueryMoreOptions
, B_RAW_TYPE
, 0,
2290 sizeof(saveMoreOptions
)) == sizeof(saveMoreOptions
)) {
2291 node
->RemoveAttr(kAttrQueryMoreOptionsForeign
);
2295 if (UserSpecifiedName()) {
2296 BString
name(UserSpecifiedName());
2297 node
->WriteAttrString(kAttrQueryTemplateName
, &name
);
2302 case kByAttributeItem
:
2305 int32 count
= fAttrGrid
->CountRows();
2306 node
->WriteAttr(kAttrQueryInitialNumAttrs
, B_INT32_TYPE
, 0,
2307 &count
, sizeof(int32
));
2309 for (int32 index
= 0; index
< count
; index
++)
2310 SaveAttrState(&message
, index
);
2312 ssize_t size
= message
.FlattenedSize();
2314 char* buffer
= new char[(size_t)size
];
2315 status_t result
= message
.Flatten(buffer
, size
);
2316 if (result
== B_OK
) {
2317 node
->WriteAttr(kAttrQueryInitialAttrs
, B_MESSAGE_TYPE
, 0,
2318 buffer
, (size_t)size
);
2326 case kByFormulaItem
:
2328 BTextControl
* textControl
= dynamic_cast<BTextControl
*>(
2329 FindView("TextControl"));
2331 ASSERT(textControl
!= NULL
);
2333 if (textControl
!= NULL
) {
2334 BString
formula(textControl
->Text());
2335 node
->WriteAttrString(kAttrQueryInitialString
, &formula
);
2344 FindPanel::SwitchToTemplate(const BNode
* node
)
2346 SwitchMode(InitialMode(node
));
2347 // update the menu to correspond to the mode
2348 MarkNamedMenuItem(fSearchModeMenu
, InitialMode(node
), true);
2350 if (Mode() == (int32
)kByAttributeItem
) {
2351 RemoveByAttributeItems();
2352 AddByAttributeItems(node
);
2355 RestoreWindowState(node
);
2360 FindPanel::RestoreMimeTypeMenuSelection(const BNode
* node
)
2362 if (Mode() == (int32
)kByFormulaItem
|| node
== NULL
2363 || node
->InitCheck() != B_OK
) {
2368 if (node
->ReadAttrString(kAttrQueryInitialMime
, &buffer
) == B_OK
)
2369 SetCurrentMimeType(buffer
.String());
2374 FindPanel::RestoreWindowState(const BNode
* node
)
2376 fMode
= InitialMode(node
);
2377 if (node
== NULL
|| node
->InitCheck() != B_OK
)
2380 ShowOrHideMimeTypeMenu();
2381 RestoreMimeTypeMenuSelection(node
);
2382 MoreOptionsStruct saveMoreOptions
;
2384 bool storesMoreOptions
= ReadAttr(node
, kAttrQueryMoreOptions
,
2385 kAttrQueryMoreOptionsForeign
, B_RAW_TYPE
, 0, &saveMoreOptions
,
2386 sizeof(saveMoreOptions
), &MoreOptionsStruct::EndianSwap
)
2389 if (storesMoreOptions
) {
2390 // need to sanitize to true or false here, could have picked
2391 // up garbage from attributes
2393 saveMoreOptions
.showMoreOptions
=
2394 (saveMoreOptions
.showMoreOptions
!= 0);
2396 fLatch
->SetValue(saveMoreOptions
.showMoreOptions
);
2397 if (saveMoreOptions
.showMoreOptions
== 1 && fMoreOptions
->IsHidden())
2398 fMoreOptions
->Show();
2399 else if (saveMoreOptions
.showMoreOptions
== 0 && !fMoreOptions
->IsHidden())
2400 fMoreOptions
->Hide();
2402 fSearchTrashCheck
->SetValue(saveMoreOptions
.searchTrash
);
2403 fTemporaryCheck
->SetValue(saveMoreOptions
.temporary
);
2405 fQueryName
->SetModificationMessage(NULL
);
2406 FindWindow
* findWindow
= dynamic_cast<FindWindow
*>(Window());
2407 if (findWindow
!= NULL
)
2408 FillCurrentQueryName(fQueryName
, findWindow
);
2410 // set modification message after checking the temporary check box,
2411 // and filling out the text control so that we do not always trigger
2412 // clearing of the temporary check box.
2413 fQueryName
->SetModificationMessage(
2414 new BMessage(kNameModifiedMessage
));
2417 // get volumes to perform query on
2418 bool searchAllVolumes
= true;
2421 if (node
->GetAttrInfo(kAttrQueryVolume
, &info
) == B_OK
) {
2422 char* buffer
= new char[info
.size
];
2423 if (node
->ReadAttr(kAttrQueryVolume
, B_MESSAGE_TYPE
, 0, buffer
,
2424 (size_t)info
.size
) == info
.size
) {
2426 if (message
.Unflatten(buffer
) == B_OK
) {
2427 for (int32 index
= 0; ;index
++) {
2428 ASSERT(index
< 100);
2430 // match a volume with the info embedded in
2433 = MatchArchivedVolume(&volume
, &message
, index
);
2434 if (result
== B_OK
) {
2436 volume
.GetName(name
);
2437 SelectItemWithLabel(fVolMenu
, name
);
2438 searchAllVolumes
= false;
2439 } else if (result
!= B_DEV_BAD_DRIVE_NUM
)
2440 // if B_DEV_BAD_DRIVE_NUM, the volume just isn't
2441 // mounted this time around, keep looking for more
2442 // if other error, bail
2449 // mark or unmark "All disks"
2450 fVolMenu
->ItemAt(0)->SetMarked(searchAllVolumes
);
2451 ShowVolumeMenuLabel();
2454 case kByAttributeItem
:
2456 int32 count
= InitialAttrCount(node
);
2459 if (node
->GetAttrInfo(kAttrQueryInitialAttrs
, &info
) != B_OK
)
2461 char* buffer
= new char[info
.size
];
2462 if (node
->ReadAttr(kAttrQueryInitialAttrs
, B_MESSAGE_TYPE
, 0,
2463 buffer
, (size_t)info
.size
) == info
.size
) {
2465 if (message
.Unflatten(buffer
) == B_OK
) {
2466 for (int32 index
= 0; index
< count
; index
++)
2467 RestoreAttrState(message
, index
);
2475 case kByFormulaItem
:
2478 if (node
->ReadAttrString(kAttrQueryInitialString
, &buffer
)
2480 BTextControl
* textControl
= dynamic_cast<BTextControl
*>(
2481 FindView("TextControl"));
2483 ASSERT(textControl
!= NULL
);
2485 if (textControl
!= NULL
)
2486 textControl
->SetText(buffer
.String());
2492 // try to restore focus and possibly text selection
2493 BString focusedView
;
2494 if (node
->ReadAttrString("_trk/focusedView", &focusedView
) == B_OK
) {
2495 BView
* view
= FindView(focusedView
.String());
2498 BTextControl
* textControl
= dynamic_cast<BTextControl
*>(view
);
2499 if (textControl
!= NULL
&& Mode() == kByFormulaItem
) {
2501 int32 selEnd
= INT32_MAX
;
2502 node
->ReadAttr("_trk/focusedSelStart", B_INT32_TYPE
, 0,
2503 &selStart
, sizeof(selStart
));
2504 node
->ReadAttr("_trk/focusedSelEnd", B_INT32_TYPE
, 0,
2505 &selEnd
, sizeof(selEnd
));
2506 textControl
->TextView()->Select(selStart
, selEnd
);
2514 FindPanel::AddByAttributeItems(const BNode
* node
)
2516 int32 numAttributes
= InitialAttrCount(node
);
2517 if (numAttributes
< 1)
2520 for (int32 index
= 0; index
< numAttributes
; index
++)
2526 FindPanel::AddByNameOrFormulaItems()
2528 BBox
* box
= dynamic_cast<BBox
*>(FindView("Box"));
2530 ASSERT(box
!= NULL
);
2536 BLayoutBuilder::Group
<>(box
, B_VERTICAL
);
2538 BTextControl
* textControl
= new BTextControl("TextControl",
2540 textControl
->SetDivider(0.0f
);
2541 box
->SetBorder(B_NO_BORDER
);
2542 box
->AddChild(textControl
);
2543 textControl
->MakeFocus();
2548 FindPanel::RemoveAttrViewItems(bool removeGrid
)
2550 if (fAttrGrid
== NULL
)
2553 BView
* view
= fAttrGrid
->View();
2554 for (int32 index
= view
->CountChildren(); index
> 0; index
--) {
2555 BView
* child
= view
->ChildAt(index
- 1);
2556 child
->RemoveSelf();
2569 FindPanel::RemoveByAttributeItems()
2571 RemoveAttrViewItems();
2572 BView
* view
= FindView("add button");
2578 view
= FindView("remove button");
2584 view
= FindView("TextControl");
2593 FindPanel::ShowOrHideMimeTypeMenu()
2595 BView
* menuFieldSpacer
= FindView("MimeTypeMenuSpacer");
2596 BMenuField
* menuField
2597 = dynamic_cast<BMenuField
*>(FindView("MimeTypeMenu"));
2598 if (menuFieldSpacer
== NULL
|| menuField
== NULL
)
2601 if (Mode() == (int32
)kByFormulaItem
&& !menuField
->IsHidden(this)) {
2602 BSize size
= menuField
->ExplicitMinSize();
2604 menuFieldSpacer
->SetExplicitMinSize(size
);
2605 menuFieldSpacer
->SetExplicitMaxSize(size
);
2606 if (menuFieldSpacer
->IsHidden(this))
2607 menuFieldSpacer
->Show();
2608 } else if (menuField
->IsHidden(this)) {
2609 menuFieldSpacer
->Hide();
2616 FindPanel::AddAttributeControls(int32 gridRow
)
2618 BPopUpMenu
* menu
= new BPopUpMenu("PopUp");
2620 // add NAME attribute to popup
2621 BMenu
* submenu
= new BMenu(B_TRANSLATE("Name"));
2622 submenu
->SetRadioMode(true);
2623 submenu
->SetFont(be_plain_font
);
2624 BMessage
* message
= new BMessage(kAttributeItemMain
);
2625 message
->AddString("name", "name");
2626 message
->AddInt32("type", B_STRING_TYPE
);
2627 BMenuItem
* item
= new BMenuItem(submenu
, message
);
2628 menu
->AddItem(item
);
2630 for (int32 i
= 0; i
< 5; i
++) {
2631 message
= new BMessage(kAttributeItem
);
2632 message
->AddInt32("operator", operators
[i
]);
2633 submenu
->AddItem(new BMenuItem(
2634 B_TRANSLATE_NOCOLLECT(operatorLabels
[i
]), message
));
2637 // mark first items initially
2638 menu
->ItemAt(0)->SetMarked(true);
2639 submenu
->ItemAt(0)->SetMarked(true);
2641 // add SIZE attribute
2642 submenu
= new BMenu(B_TRANSLATE("Size"));
2643 submenu
->SetRadioMode(true);
2644 submenu
->SetFont(be_plain_font
);
2645 message
= new BMessage(kAttributeItemMain
);
2646 message
->AddString("name", "size");
2647 message
->AddInt32("type", B_OFF_T_TYPE
);
2648 item
= new BMenuItem(submenu
, message
);
2649 menu
->AddItem(item
);
2651 message
= new BMessage(kAttributeItem
);
2652 message
->AddInt32("operator", B_GE
);
2653 submenu
->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(operatorLabels
[5]),
2656 message
= new BMessage(kAttributeItem
);
2657 message
->AddInt32("operator", B_LE
);
2658 submenu
->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(operatorLabels
[6]),
2661 message
= new BMessage(kAttributeItem
);
2662 message
->AddInt32("operator", B_EQ
);
2663 submenu
->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(operatorLabels
[1]),
2666 // add "modified" field
2667 submenu
= new BMenu(B_TRANSLATE("Modified"));
2668 submenu
->SetRadioMode(true);
2669 submenu
->SetFont(be_plain_font
);
2670 message
= new BMessage(kAttributeItemMain
);
2671 message
->AddString("name", "last_modified");
2672 message
->AddInt32("type", B_TIME_TYPE
);
2673 item
= new BMenuItem(submenu
, message
);
2674 menu
->AddItem(item
);
2676 message
= new BMessage(kAttributeItem
);
2677 message
->AddInt32("operator", B_LE
);
2678 submenu
->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(operatorLabels
[7]),
2681 message
= new BMessage(kAttributeItem
);
2682 message
->AddInt32("operator", B_GE
);
2683 submenu
->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(operatorLabels
[8]),
2686 BMenuField
* menuField
= new BMenuField("MenuField", "", menu
);
2687 menuField
->SetDivider(0.0f
);
2688 fAttrGrid
->AddView(menuField
, 0, gridRow
);
2690 BStringView
* stringView
= new BStringView("",
2691 menu
->FindMarked()->Submenu()->FindMarked()->Label());
2692 BLayoutItem
* layoutItem
= fAttrGrid
->AddView(stringView
, 1, gridRow
);
2693 layoutItem
->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT
,
2694 B_ALIGN_VERTICAL_UNSET
));
2696 BString
title("TextEntry");
2698 BTextControl
* textControl
= new BTextControl(title
.String(), "", "", NULL
);
2699 textControl
->SetDivider(0.0f
);
2700 fAttrGrid
->AddView(textControl
, 2, gridRow
);
2701 textControl
->MakeFocus();
2703 // target everything
2704 menu
->SetTargetForItems(this);
2705 for (int32 index
= menu
->CountItems() - 1; index
>= 0; index
--) {
2706 BMenu
* submenuAtIndex
= menu
->SubmenuAt(index
);
2707 if (submenuAtIndex
!= NULL
)
2708 submenuAtIndex
->SetTargetForItems(this);
2711 // populate mime popup
2712 AddMimeTypeAttrs(menu
);
2717 FindPanel::RestoreAttrState(const BMessage
&message
, int32 index
)
2719 BMenuField
* menuField
2720 = dynamic_cast<BMenuField
*>(FindAttrView("MenuField", index
));
2721 if (menuField
!= NULL
) {
2722 // decode menu selections
2723 BMenu
* menu
= menuField
->Menu();
2725 ASSERT(menu
!= NULL
);
2727 AddMimeTypeAttrs(menu
);
2729 if (message
.FindString("menuSelection", index
, &label
) == B_OK
) {
2730 int32 itemIndex
= SelectItemWithLabel(menu
, label
);
2731 if (itemIndex
>= 0) {
2732 menu
= menu
->SubmenuAt(itemIndex
);
2733 if (menu
!= NULL
&& message
.FindString("subMenuSelection",
2734 index
, &label
) == B_OK
) {
2735 SelectItemWithLabel(menu
, label
);
2741 // decode attribute text
2742 BString textEntryString
= "TextEntry";
2743 textEntryString
<< index
;
2744 BTextControl
* textControl
= dynamic_cast<BTextControl
*>(
2745 FindAttrView(textEntryString
.String(), index
));
2747 ASSERT(textControl
!= NULL
);
2750 if (textControl
!= NULL
2751 && message
.FindString("attrViewText", index
, &string
) == B_OK
) {
2752 textControl
->SetText(string
);
2755 int32 logicMenuSelectedIndex
;
2756 if (message
.FindInt32("logicalRelation", index
,
2757 &logicMenuSelectedIndex
) == B_OK
) {
2758 BMenuField
* field
= dynamic_cast<BMenuField
*>(
2759 FindAttrView("Logic", index
));
2760 if (field
!= NULL
) {
2761 BMenu
* fieldMenu
= field
->Menu();
2762 if (fieldMenu
!= NULL
) {
2763 BMenuItem
* logicItem
2764 = fieldMenu
->ItemAt(logicMenuSelectedIndex
);
2765 if (logicItem
!= NULL
) {
2766 logicItem
->SetMarked(true);
2772 AddLogicMenu(index
, logicMenuSelectedIndex
== 0);
2778 FindPanel::SaveAttrState(BMessage
* message
, int32 index
)
2780 BMenu
* menu
= dynamic_cast<BMenuField
*>(FindAttrView("MenuField", index
))
2783 // encode main attribute menu selection
2784 BMenuItem
* item
= menu
->FindMarked();
2785 message
->AddString("menuSelection", item
? item
->Label() : "");
2787 // encode submenu selection
2788 const char* label
= "";
2790 BMenu
* submenu
= menu
->SubmenuAt(menu
->IndexOf(item
));
2792 item
= submenu
->FindMarked();
2794 label
= item
->Label();
2797 message
->AddString("subMenuSelection", label
);
2799 // encode attribute text
2800 BString textEntryString
= "TextEntry";
2801 textEntryString
<< index
;
2802 BTextControl
* textControl
= dynamic_cast<BTextControl
*>(FindAttrView(
2803 textEntryString
.String(), index
));
2805 ASSERT(textControl
!= NULL
);
2807 if (textControl
!= NULL
)
2808 message
->AddString("attrViewText", textControl
->Text());
2810 BMenuField
* field
= dynamic_cast<BMenuField
*>(FindAttrView("Logic", index
));
2811 if (field
!= NULL
) {
2812 BMenu
* fieldMenu
= field
->Menu();
2813 if (fieldMenu
!= NULL
) {
2814 BMenuItem
* item
= fieldMenu
->FindMarked();
2815 ASSERT(item
!= NULL
);
2816 message
->AddInt32("logicalRelation",
2817 item
!= NULL
? field
->Menu()->IndexOf(item
) : 0);
2824 FindPanel::AddLogicMenu(int32 index
, bool selectAnd
)
2826 // add "AND/OR" menu
2827 BPopUpMenu
* menu
= new BPopUpMenu("");
2828 BMessage
* message
= new BMessage();
2829 message
->AddInt32("combine", B_AND
);
2830 BMenuItem
* item
= new BMenuItem(B_TRANSLATE("And"), message
);
2831 menu
->AddItem(item
);
2833 item
->SetMarked(true);
2835 message
= new BMessage();
2836 message
->AddInt32("combine", B_OR
);
2837 item
= new BMenuItem(B_TRANSLATE("Or"), message
);
2838 menu
->AddItem(item
);
2840 item
->SetMarked(true);
2842 menu
->SetTargetForItems(this);
2844 BMenuField
* menufield
= new BMenuField("Logic", "", menu
, B_WILL_DRAW
);
2845 menufield
->SetDivider(0.0f
);
2847 ResizeMenuField(menufield
);
2849 fAttrGrid
->AddView(menufield
, 3, index
);
2854 FindPanel::RemoveLogicMenu(int32 index
)
2856 BMenuField
* menufield
= dynamic_cast<BMenuField
*>(FindAttrView("Logic", index
));
2858 menufield
->RemoveSelf();
2865 FindPanel::AddAttributes(BMenu
* menu
, const BMimeType
&mimeType
)
2867 // only add things to menu which have "user-visible" data
2868 BMessage attributeMessage
;
2869 if (mimeType
.GetAttrInfo(&attributeMessage
) != B_OK
)
2872 char desc
[B_MIME_TYPE_LENGTH
];
2873 mimeType
.GetShortDescription(desc
);
2875 // go through each field in meta mime and add it to a menu
2876 for (int32 index
= 0; ; index
++) {
2877 const char* publicName
;
2878 if (attributeMessage
.FindString("attr:public_name", index
,
2879 &publicName
) != B_OK
) {
2883 if (!attributeMessage
.FindBool("attr:viewable"))
2886 const char* attributeName
;
2887 if (attributeMessage
.FindString("attr:name", index
, &attributeName
)
2893 if (attributeMessage
.FindInt32("attr:type", index
, &type
) != B_OK
)
2896 BMenu
* submenu
= new BMenu(publicName
);
2897 submenu
->SetRadioMode(true);
2898 submenu
->SetFont(be_plain_font
);
2899 BMessage
* message
= new BMessage(kAttributeItemMain
);
2900 message
->AddString("name", attributeName
);
2901 message
->AddInt32("type", type
);
2902 BMenuItem
* item
= new BMenuItem(submenu
, message
);
2903 menu
->AddItem(item
);
2904 menu
->SetTargetForItems(this);
2908 message
= new BMessage(kAttributeItem
);
2909 message
->AddInt32("operator", B_CONTAINS
);
2910 submenu
->AddItem(new BMenuItem(operatorLabels
[0], message
));
2912 message
= new BMessage(kAttributeItem
);
2913 message
->AddInt32("operator", B_EQ
);
2914 submenu
->AddItem(new BMenuItem(operatorLabels
[1], message
));
2916 message
= new BMessage(kAttributeItem
);
2917 message
->AddInt32("operator", B_NE
);
2918 submenu
->AddItem(new BMenuItem(operatorLabels
[2], message
));
2919 submenu
->SetTargetForItems(this);
2921 message
= new BMessage(kAttributeItem
);
2922 message
->AddInt32("operator", B_BEGINS_WITH
);
2923 submenu
->AddItem(new BMenuItem(operatorLabels
[3], message
));
2924 submenu
->SetTargetForItems(this);
2926 message
= new BMessage(kAttributeItem
);
2927 message
->AddInt32("operator", B_ENDS_WITH
);
2928 submenu
->AddItem(new BMenuItem(operatorLabels
[4], message
));
2943 message
= new BMessage(kAttributeItem
);
2944 message
->AddInt32("operator", B_EQ
);
2945 submenu
->AddItem(new BMenuItem(operatorLabels
[1], message
));
2947 message
= new BMessage(kAttributeItem
);
2948 message
->AddInt32("operator", B_GE
);
2949 submenu
->AddItem(new BMenuItem(operatorLabels
[5], message
));
2951 message
= new BMessage(kAttributeItem
);
2952 message
->AddInt32("operator", B_LE
);
2953 submenu
->AddItem(new BMenuItem(operatorLabels
[6], message
));
2957 message
= new BMessage(kAttributeItem
);
2958 message
->AddInt32("operator", B_LE
);
2959 submenu
->AddItem(new BMenuItem(operatorLabels
[7], message
));
2961 message
= new BMessage(kAttributeItem
);
2962 message
->AddInt32("operator", B_GE
);
2963 submenu
->AddItem(new BMenuItem(operatorLabels
[8], message
));
2966 submenu
->SetTargetForItems(this);
2972 FindPanel::AddMimeTypeAttrs(BMenu
* menu
)
2974 const char* typeName
;
2975 if (CurrentMimeType(&typeName
) == NULL
)
2978 BMimeType
mimeType(typeName
);
2979 if (!mimeType
.IsInstalled())
2982 if (!mimeType
.IsSupertypeOnly()) {
2983 // add supertype attributes
2984 BMimeType supertype
;
2985 mimeType
.GetSupertype(&supertype
);
2986 AddAttributes(menu
, supertype
);
2989 AddAttributes(menu
, mimeType
);
2994 FindPanel::GetDefaultAttrName(BString
& attrName
, int32 row
) const
2996 BMenuItem
* item
= NULL
;
2997 BMenuField
* menuField
2998 = dynamic_cast<BMenuField
*>(fAttrGrid
->ItemAt(0, row
)->View());
2999 if (menuField
!= NULL
&& menuField
->Menu() != NULL
)
3000 item
= menuField
->Menu()->FindMarked();
3003 attrName
<< item
->Label();
3005 attrName
<< B_TRANSLATE("Name");
3007 if (item
!= NULL
&& item
->Submenu() != NULL
)
3008 item
= item
->Submenu()->FindMarked();
3013 attrName
<< " " << item
->Label() << " ";
3017 BTextControl
* textControl
3018 = dynamic_cast<BTextControl
*>(fAttrGrid
->ItemAt(2, row
)->View());
3019 if (textControl
!= NULL
)
3020 attrName
<< textControl
->Text();
3027 DeleteTransientQueriesTask::DeleteTransientQueriesTask()
3035 DeleteTransientQueriesTask::~DeleteTransientQueriesTask()
3042 DeleteTransientQueriesTask::DoSomeWork()
3049 case kAllocatedWalker
:
3052 PRINT(("transient query killer done\n"));
3066 DeleteTransientQueriesTask::Initialize()
3068 PRINT(("starting up transient query killer\n"));
3070 status_t result
= find_directory(B_USER_DIRECTORY
, &path
, false);
3071 if (result
!= B_OK
) {
3075 fWalker
= new BTrackerPrivate::TNodeWalker(path
.Path());
3076 state
= kAllocatedWalker
;
3080 const int32 kBatchCount
= 100;
3083 DeleteTransientQueriesTask::GetSome()
3085 state
= kTraversing
;
3086 for (int32 count
= kBatchCount
; count
> 0; count
--) {
3088 if (fWalker
->GetNextRef(&ref
) != B_OK
) {
3093 if (model
.IsQuery())
3094 ProcessOneRef(&model
);
3097 PRINT(("transient query killer: %s not a query\n", model
.Name()));
3104 const int32 kDaysToExpire
= 7;
3107 QueryOldEnough(Model
* model
)
3109 // check if it is old and ready to be deleted
3110 time_t now
= time(0);
3115 localtime_r(&now
, &nowTimeData
);
3116 localtime_r(&model
->StatBuf()->st_ctime
, &fileModData
);
3118 if ((nowTimeData
.tm_mday
- fileModData
.tm_mday
) < kDaysToExpire
3119 && (nowTimeData
.tm_mday
- fileModData
.tm_mday
) > -kDaysToExpire
) {
3120 PRINT(("query %s, not old enough\n", model
->Name()));
3128 DeleteTransientQueriesTask::ProcessOneRef(Model
* model
)
3130 BModelOpener
opener(model
);
3132 // is this a temporary query
3133 if (!MoreOptionsStruct::QueryTemporary(model
->Node())) {
3134 PRINT(("query %s, not temporary\n", model
->Name()));
3138 if (!QueryOldEnough(model
))
3141 TTracker
* tracker
= dynamic_cast<TTracker
*>(be_app
);
3142 ASSERT(tracker
!= NULL
);
3144 // check that it is not showing
3145 if (tracker
!= NULL
&& tracker
->EntryHasWindowOpen(model
->EntryRef())) {
3146 PRINT(("query %s, showing, can't delete\n", model
->Name()));
3150 PRINT(("query %s, old, temporary, not shownig - deleting\n",
3153 BEntry
entry(model
->EntryRef());
3160 class DeleteTransientQueriesFunctor
: public FunctionObjectWithResult
<bool> {
3162 DeleteTransientQueriesFunctor(DeleteTransientQueriesTask
* task
)
3166 virtual ~DeleteTransientQueriesFunctor()
3171 virtual void operator()()
3172 { result
= task
->DoSomeWork(); }
3175 DeleteTransientQueriesTask
* task
;
3180 DeleteTransientQueriesTask::StartUpTransientQueryCleaner()
3182 TTracker
* tracker
= dynamic_cast<TTracker
*>(be_app
);
3183 ASSERT(tracker
!= NULL
);
3185 if (tracker
== NULL
)
3187 // set up a task that wakes up when the machine is idle and starts
3188 // killing off old transient queries
3189 DeleteTransientQueriesFunctor
* worker
3190 = new DeleteTransientQueriesFunctor(new DeleteTransientQueriesTask());
3192 tracker
->MainTaskLoop()->RunWhenIdle(worker
,
3193 30 * 60 * 1000000, // half an hour initial delay
3194 5 * 60 * 1000000, // idle for five minutes
3202 RecentFindItemsMenu::RecentFindItemsMenu(const char* title
,
3203 const BMessenger
* target
, uint32 what
)
3205 BMenu(title
, B_ITEMS_IN_COLUMN
),
3213 RecentFindItemsMenu::AttachedToWindow()
3215 // re-populate the menu with fresh items
3216 for (int32 index
= CountItems() - 1; index
>= 0; index
--)
3217 delete RemoveItem(index
);
3219 FindPanel::AddRecentQueries(this, false, &fTarget
, fWhat
);
3220 BMenu::AttachedToWindow();
3224 #if !B_BEOS_VERSION_DANO
3228 TrackerBuildRecentFindItemsMenu(const char* title
)
3230 BMessenger
trackerMessenger(kTrackerSignature
);
3231 return new RecentFindItemsMenu(title
, &trackerMessenger
, B_REFS_RECEIVED
);
3238 DraggableQueryIcon::DraggableQueryIcon(BRect frame
, const char* name
,
3239 const BMessage
* message
, BMessenger messenger
, uint32 resizeFlags
,
3242 DraggableIcon(frame
, name
, B_QUERY_MIMETYPE
, B_LARGE_ICON
,
3243 message
, messenger
, resizeFlags
, flags
)
3249 DraggableQueryIcon::DragStarted(BMessage
* dragMessage
)
3251 // override to substitute the user-specified query name
3252 dragMessage
->RemoveData("be:clip_name");
3254 FindWindow
* window
= dynamic_cast<FindWindow
*>(Window());
3256 ASSERT(window
!= NULL
);
3258 return window
!= NULL
&& dragMessage
->AddString("be:clip_name",
3259 window
->BackgroundView()->UserSpecifiedName() != NULL
3260 ? window
->BackgroundView()->UserSpecifiedName()
3261 : B_TRANSLATE("New Query")) == B_OK
;
3268 MostUsedNames::MostUsedNames(const char* fileName
, const char* directory
,
3271 fFileName(fileName
),
3272 fDirectory(directory
),
3279 MostUsedNames::~MostUsedNames()
3281 // only write back settings when we've been used
3285 // write most used list to file
3288 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
, true) != B_OK
3289 || path
.Append(fDirectory
) != B_OK
|| path
.Append(fFileName
) != B_OK
) {
3293 BFile
file(path
.Path(), B_WRITE_ONLY
| B_CREATE_FILE
| B_ERASE_FILE
);
3294 if (file
.InitCheck() == B_OK
) {
3295 for (int32 i
= 0; i
< fList
.CountItems(); i
++) {
3296 list_entry
* entry
= static_cast<list_entry
*>(fList
.ItemAt(i
));
3298 char line
[B_FILE_NAME_LENGTH
+ 5];
3300 // limit upper bound to react more dynamically to changes
3301 if (--entry
->count
> 20)
3304 // if the item hasn't been chosen in a while, remove it
3305 // (but leave at least one item in the list)
3306 if (entry
->count
< -10 && i
> 0)
3309 sprintf(line
, "%" B_PRId32
" %s\n", entry
->count
, entry
->name
);
3310 if (file
.Write(line
, strlen(line
)) < B_OK
)
3318 for (int32 i
= fList
.CountItems(); i
-- > 0;) {
3319 list_entry
* entry
= static_cast<list_entry
*>(fList
.ItemAt(i
));
3327 MostUsedNames::ObtainList(BList
* list
)
3338 for (int32 i
= 0; i
< fCount
; i
++) {
3339 list_entry
* entry
= static_cast<list_entry
*>(fList
.ItemAt(i
));
3343 list
->AddItem(entry
->name
);
3350 MostUsedNames::ReleaseList()
3357 MostUsedNames::AddName(const char* name
)
3364 // remove last entry if there are more than
3365 // 2*fCount entries in the list
3367 list_entry
* entry
= NULL
;
3369 if (fList
.CountItems() > fCount
* 2) {
3370 entry
= static_cast<list_entry
*>(
3371 fList
.RemoveItem(fList
.CountItems() - 1));
3373 // is this the name we want to add here?
3374 if (strcmp(name
, entry
->name
)) {
3379 fList
.AddItem(entry
);
3382 if (entry
== NULL
) {
3384 (entry
= static_cast<list_entry
*>(fList
.ItemAt(i
))) != NULL
; i
++) {
3385 if (strcmp(entry
->name
, name
) == 0)
3390 if (entry
== NULL
) {
3391 entry
= new list_entry
;
3392 entry
->name
= strdup(name
);
3395 fList
.AddItem(entry
);
3396 } else if (entry
->count
< 0)
3407 MostUsedNames::CompareNames(const void* a
,const void* b
)
3409 list_entry
* entryA
= *(list_entry
**)a
;
3410 list_entry
* entryB
= *(list_entry
**)b
;
3412 if (entryA
->count
== entryB
->count
)
3413 return strcasecmp(entryA
->name
,entryB
->name
);
3415 return entryB
->count
- entryA
->count
;
3420 MostUsedNames::LoadList()
3426 // load the most used names list
3429 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
, true) != B_OK
3430 || path
.Append(fDirectory
) != B_OK
|| path
.Append(fFileName
) != B_OK
) {
3434 FILE* file
= fopen(path
.Path(), "r");
3438 char line
[B_FILE_NAME_LENGTH
+ 5];
3439 while (fgets(line
, sizeof(line
), file
) != NULL
) {
3440 int32 length
= (int32
)strlen(line
) - 1;
3441 if (length
>= 0 && line
[length
] == '\n')
3442 line
[length
] = '\0';
3444 int32 count
= atoi(line
);
3446 char* name
= strchr(line
, ' ');
3447 if (name
== NULL
|| *(++name
) == '\0')
3450 list_entry
* entry
= new list_entry
;
3451 entry
->name
= strdup(name
);
3452 entry
->count
= count
;
3454 fList
.AddItem(entry
);
3461 MostUsedNames::UpdateList()
3463 AutoLock
<Benaphore
> locker(fLock
);
3470 fList
.SortItems(MostUsedNames::CompareNames
);
3473 } // namespace BPrivate