BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / text_search / GrepWindow.cpp
blob144feb71fd66bc33af3d0473acce70d2847c3d71
1 /*
2 * Copyright (c) 1998-2007 Matthijs Hollemans
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5 #include "GrepWindow.h"
7 #include <ctype.h>
8 #include <errno.h>
9 #include <new>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
15 #include <Application.h>
16 #include <AppFileInfo.h>
17 #include <Alert.h>
18 #include <Clipboard.h>
19 #include <LayoutBuilder.h>
20 #include <MessageRunner.h>
21 #include <Path.h>
22 #include <PathMonitor.h>
23 #include <Roster.h>
24 #include <SpaceLayoutItem.h>
25 #include <String.h>
26 #include <UTF8.h>
28 #include "ChangesIterator.h"
29 #include "GlobalDefs.h"
30 #include "Grepper.h"
31 #include "InitialIterator.h"
33 #undef B_TRANSLATION_CONTEXT
34 #define B_TRANSLATION_CONTEXT "GrepWindow"
37 using std::nothrow;
39 static const bigtime_t kChangesPulseInterval = 150000;
41 #define TRACE_NODE_MONITORING
42 #ifdef TRACE_NODE_MONITORING
43 # define TRACE_NM(x...) printf(x)
44 #else
45 # define TRACE_NM(x...)
46 #endif
48 //#define TRACE_FUNCTIONS
49 #ifdef TRACE_FUNCTIONS
50 class FunctionTracer {
51 public:
52 FunctionTracer(const char* functionName)
53 : fName(functionName)
55 printf("%s - enter\n", fName.String());
57 ~FunctionTracer()
59 printf("%s - exit\n", fName.String());
61 private:
62 BString fName;
64 # define CALLED() FunctionTracer functionTracer(__PRETTY_FUNCTION__)
65 #else
66 # define CALLED()
67 #endif // TRACE_FUNCTIONS
70 GrepWindow::GrepWindow(BMessage* message)
71 : BWindow(BRect(0, 0, 525, 430), NULL, B_DOCUMENT_WINDOW,
72 B_AUTO_UPDATE_SIZE_LIMITS),
73 fSearchText(NULL),
74 fSearchResults(NULL),
75 fMenuBar(NULL),
76 fFileMenu(NULL),
77 fNew(NULL),
78 fOpen(NULL),
79 fClose(NULL),
80 fQuit(NULL),
81 fActionMenu(NULL),
82 fSelectAll(NULL),
83 fSearch(NULL),
84 fTrimSelection(NULL),
85 fCopyText(NULL),
86 fSelectInTracker(NULL),
87 fOpenSelection(NULL),
88 fPreferencesMenu(NULL),
89 fRecurseLinks(NULL),
90 fRecurseDirs(NULL),
91 fSkipDotDirs(NULL),
92 fCaseSensitive(NULL),
93 fRegularExpression(NULL),
94 fTextOnly(NULL),
95 fInvokePe(NULL),
96 fHistoryMenu(NULL),
97 fEncodingMenu(NULL),
98 fUTF8(NULL),
99 fShiftJIS(NULL),
100 fEUC(NULL),
101 fJIS(NULL),
103 fShowLinesCheckbox(NULL),
104 fButton(NULL),
106 fGrepper(NULL),
107 fOldPattern(""),
108 fModel(new (nothrow) Model()),
109 fLastNodeMonitorEvent(system_time()),
110 fChangesIterator(NULL),
111 fChangesPulse(NULL),
113 fFilePanel(NULL)
115 if (fModel == NULL)
116 return;
118 entry_ref directory;
119 _InitRefsReceived(&directory, message);
121 fModel->fDirectory = directory;
122 fModel->fSelectedFiles = *message;
124 _SetWindowTitle();
125 _CreateMenus();
126 _CreateViews();
127 _LayoutViews();
128 _LoadPrefs();
129 _TileIfMultipleWindows();
131 Show();
135 GrepWindow::~GrepWindow()
137 delete fGrepper;
138 delete fModel;
142 void GrepWindow::FrameResized(float width, float height)
144 BWindow::FrameResized(width, height);
145 fModel->fFrame = Frame();
146 _SavePrefs();
150 void GrepWindow::FrameMoved(BPoint origin)
152 BWindow::FrameMoved(origin);
153 fModel->fFrame = Frame();
154 _SavePrefs();
158 void GrepWindow::MenusBeginning()
160 fModel->FillHistoryMenu(fHistoryMenu);
161 BWindow::MenusBeginning();
165 void GrepWindow::MenusEnded()
167 for (int32 t = fHistoryMenu->CountItems(); t > 0; --t)
168 delete fHistoryMenu->RemoveItem(t - 1);
170 BWindow::MenusEnded();
174 void GrepWindow::MessageReceived(BMessage* message)
176 switch (message->what) {
177 case MSG_NEW_WINDOW:
178 _OnNewWindow();
179 break;
181 case B_SIMPLE_DATA:
182 _OnFileDrop(message);
183 break;
185 case MSG_OPEN_PANEL:
186 _OnOpenPanel();
187 break;
189 case MSG_REFS_RECEIVED:
190 _OnRefsReceived(message);
191 break;
193 case B_CANCEL:
194 _OnOpenPanelCancel();
195 break;
197 case MSG_RECURSE_LINKS:
198 _OnRecurseLinks();
199 break;
201 case MSG_RECURSE_DIRS:
202 _OnRecurseDirs();
203 break;
205 case MSG_SKIP_DOT_DIRS:
206 _OnSkipDotDirs();
207 break;
209 case MSG_CASE_SENSITIVE:
210 _OnCaseSensitive();
211 break;
213 case MSG_REGULAR_EXPRESSION:
214 _OnRegularExpression();
215 break;
217 case MSG_TEXT_ONLY:
218 _OnTextOnly();
219 break;
221 case MSG_INVOKE_PE:
222 _OnInvokePe();
223 break;
225 case MSG_SEARCH_TEXT:
226 _OnSearchText();
227 break;
229 case MSG_SELECT_HISTORY:
230 _OnHistoryItem(message);
231 break;
233 case MSG_START_CANCEL:
234 _OnStartCancel();
235 break;
237 case MSG_SEARCH_FINISHED:
238 _OnSearchFinished();
239 break;
241 case MSG_START_NODE_MONITORING:
242 _StartNodeMonitoring();
243 break;
245 case B_PATH_MONITOR:
246 _OnNodeMonitorEvent(message);
247 break;
249 case MSG_NODE_MONITOR_PULSE:
250 _OnNodeMonitorPulse();
251 break;
253 case MSG_REPORT_FILE_NAME:
254 _OnReportFileName(message);
255 break;
257 case MSG_REPORT_RESULT:
258 _OnReportResult(message);
259 break;
261 case MSG_REPORT_ERROR:
262 _OnReportError(message);
263 break;
265 case MSG_SELECT_ALL:
266 _OnSelectAll(message);
267 break;
269 case MSG_TRIM_SELECTION:
270 _OnTrimSelection();
271 break;
273 case MSG_COPY_TEXT:
274 _OnCopyText();
275 break;
277 case MSG_SELECT_IN_TRACKER:
278 _OnSelectInTracker();
279 break;
281 case MSG_CHECKBOX_SHOW_LINES:
282 _OnCheckboxShowLines();
283 break;
285 case MSG_OPEN_SELECTION:
286 // fall through
287 case MSG_INVOKE_ITEM:
288 _OnInvokeItem();
289 break;
291 case MSG_QUIT_NOW:
292 _OnQuitNow();
293 break;
295 case 'utf8':
296 fModel->fEncoding = 0;
297 break;
299 case B_SJIS_CONVERSION:
300 fModel->fEncoding = B_SJIS_CONVERSION;
301 break;
303 case B_EUC_CONVERSION:
304 fModel->fEncoding = B_EUC_CONVERSION;
305 break;
307 case B_JIS_CONVERSION:
308 fModel->fEncoding = B_JIS_CONVERSION;
309 break;
311 default:
312 BWindow::MessageReceived(message);
313 break;
318 void
319 GrepWindow::Quit()
321 CALLED();
323 _StopNodeMonitoring();
324 _SavePrefs();
326 // TODO: stippi: Looks like this could be done
327 // by maintaining a counter in GrepApp with the number of open
328 // grep windows... and just quit when it goes zero
329 if (be_app->Lock()) {
330 be_app->PostMessage(MSG_TRY_QUIT);
331 be_app->Unlock();
332 BWindow::Quit();
337 // #pragma mark -
340 void
341 GrepWindow::_InitRefsReceived(entry_ref* directory, BMessage* message)
343 // HACK-HACK-HACK:
344 // If the user selected a single folder and invoked TextSearch on it,
345 // but recurse directories is switched off, TextSearch would do nothing.
346 // In that special case, we'd like it to recurse into that folder (but
347 // not go any deeper after that).
349 type_code code;
350 int32 count;
351 message->GetInfo("refs", &code, &count);
353 if (count == 0) {
354 if (message->FindRef("dir_ref", 0, directory) == B_OK)
355 message->MakeEmpty();
358 if (count == 1) {
359 entry_ref ref;
360 if (message->FindRef("refs", 0, &ref) == B_OK) {
361 BEntry entry(&ref, true);
362 if (entry.IsDirectory()) {
363 // ok, special case, we use this folder as base directory
364 // and pretend nothing had been selected:
365 *directory = ref;
366 message->MakeEmpty();
373 void
374 GrepWindow::_SetWindowTitle()
376 BEntry entry(&fModel->fDirectory, true);
377 BString title;
378 if (entry.InitCheck() == B_OK) {
379 BPath path;
380 if (entry.GetPath(&path) == B_OK) {
381 if (fOldPattern.Length()) {
382 title = B_TRANSLATE("%appname% : %path% : %searchtext%");
383 title.ReplaceAll("%searchtext%", fOldPattern.String());
384 } else
385 title = B_TRANSLATE("%appname% : %path%");
387 title.ReplaceAll("%appname%", B_TRANSLATE(APP_NAME));
388 title.ReplaceAll("%path%", path.Path());
392 if (!title.Length())
393 title = B_TRANSLATE(APP_NAME);
395 SetTitle(title.String());
399 void
400 GrepWindow::_CreateMenus()
402 fMenuBar = new BMenuBar("menubar");
404 fFileMenu = new BMenu(B_TRANSLATE("File"));
405 fActionMenu = new BMenu(B_TRANSLATE("Actions"));
406 fPreferencesMenu = new BMenu(B_TRANSLATE("Settings"));
407 fHistoryMenu = new BMenu(B_TRANSLATE("History"));
408 fEncodingMenu = new BMenu(B_TRANSLATE("Encoding"));
410 fNew = new BMenuItem(
411 B_TRANSLATE("New window"), new BMessage(MSG_NEW_WINDOW), 'N');
413 fOpen = new BMenuItem(
414 B_TRANSLATE("Set target" B_UTF8_ELLIPSIS), new BMessage(MSG_OPEN_PANEL), 'F');
416 fClose = new BMenuItem(
417 B_TRANSLATE("Close"), new BMessage(B_QUIT_REQUESTED), 'W');
419 fQuit = new BMenuItem(
420 B_TRANSLATE("Quit"), new BMessage(MSG_QUIT_NOW), 'Q');
422 fSearch = new BMenuItem(
423 B_TRANSLATE("Search"), new BMessage(MSG_START_CANCEL), 'S');
425 fSelectAll = new BMenuItem(
426 B_TRANSLATE("Select all"), new BMessage(MSG_SELECT_ALL), 'A');
428 fTrimSelection = new BMenuItem(
429 B_TRANSLATE("Trim to selection"), new BMessage(MSG_TRIM_SELECTION), 'T');
431 fOpenSelection = new BMenuItem(
432 B_TRANSLATE("Open selection"), new BMessage(MSG_OPEN_SELECTION), 'O');
434 fSelectInTracker = new BMenuItem(
435 B_TRANSLATE("Show files in Tracker"),
436 new BMessage(MSG_SELECT_IN_TRACKER), 'K');
438 fCopyText = new BMenuItem(
439 B_TRANSLATE("Copy text to clipboard"), new BMessage(MSG_COPY_TEXT), 'B');
441 fRecurseLinks = new BMenuItem(
442 B_TRANSLATE("Follow symbolic links"), new BMessage(MSG_RECURSE_LINKS));
444 fRecurseDirs = new BMenuItem(
445 B_TRANSLATE("Look in sub-folders"), new BMessage(MSG_RECURSE_DIRS));
447 fSkipDotDirs = new BMenuItem(
448 B_TRANSLATE("Skip folders starting with a dot"),
449 new BMessage(MSG_SKIP_DOT_DIRS));
451 fCaseSensitive = new BMenuItem(
452 B_TRANSLATE("Case-sensitive"), new BMessage(MSG_CASE_SENSITIVE));
454 fRegularExpression = new BMenuItem(
455 B_TRANSLATE("Regular expression"), new BMessage(MSG_REGULAR_EXPRESSION));
457 fTextOnly = new BMenuItem(
458 B_TRANSLATE("Text files only"), new BMessage(MSG_TEXT_ONLY));
460 fInvokePe = new BMenuItem(
461 B_TRANSLATE("Open files in Pe"), new BMessage(MSG_INVOKE_PE));
463 fUTF8 = new BMenuItem("UTF8", new BMessage('utf8'));
464 fShiftJIS = new BMenuItem("ShiftJIS", new BMessage(B_SJIS_CONVERSION));
465 fEUC = new BMenuItem("EUC", new BMessage(B_EUC_CONVERSION));
466 fJIS = new BMenuItem("JIS", new BMessage(B_JIS_CONVERSION));
468 fFileMenu->AddItem(fNew);
469 fFileMenu->AddSeparatorItem();
470 fFileMenu->AddItem(fOpen);
471 fFileMenu->AddItem(fClose);
472 fFileMenu->AddSeparatorItem();
473 fFileMenu->AddItem(fQuit);
475 fActionMenu->AddItem(fSearch);
476 fActionMenu->AddSeparatorItem();
477 fActionMenu->AddItem(fSelectAll);
478 fActionMenu->AddItem(fTrimSelection);
479 fActionMenu->AddSeparatorItem();
480 fActionMenu->AddItem(fOpenSelection);
481 fActionMenu->AddItem(fSelectInTracker);
482 fActionMenu->AddItem(fCopyText);
484 fPreferencesMenu->AddItem(fRecurseLinks);
485 fPreferencesMenu->AddItem(fRecurseDirs);
486 fPreferencesMenu->AddItem(fSkipDotDirs);
487 fPreferencesMenu->AddItem(fCaseSensitive);
488 fPreferencesMenu->AddItem(fRegularExpression);
489 fPreferencesMenu->AddItem(fTextOnly);
490 fPreferencesMenu->AddItem(fInvokePe);
492 fEncodingMenu->AddItem(fUTF8);
493 fEncodingMenu->AddItem(fShiftJIS);
494 fEncodingMenu->AddItem(fEUC);
495 fEncodingMenu->AddItem(fJIS);
497 // fEncodingMenu->SetLabelFromMarked(true);
498 // Do we really want this ?
499 fEncodingMenu->SetRadioMode(true);
500 fEncodingMenu->ItemAt(0)->SetMarked(true);
502 fMenuBar->AddItem(fFileMenu);
503 fMenuBar->AddItem(fActionMenu);
504 fMenuBar->AddItem(fPreferencesMenu);
505 fMenuBar->AddItem(fHistoryMenu);
506 fMenuBar->AddItem(fEncodingMenu);
508 fSearch->SetEnabled(false);
512 void
513 GrepWindow::_CreateViews()
515 // The search pattern entry field does not send a message when
516 // <Enter> is pressed, because the "Search/Cancel" button already
517 // does this and we don't want to send the same message twice.
519 fSearchText = new BTextControl(
520 "SearchText", NULL, NULL, NULL,
521 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE);
523 fSearchText->TextView()->SetMaxBytes(1000);
524 fSearchText->SetModificationMessage(new BMessage(MSG_SEARCH_TEXT));
526 fButton = new BButton(
527 "Button", B_TRANSLATE("Search"),
528 new BMessage(MSG_START_CANCEL));
529 fButton->MakeDefault(true);
530 fButton->SetEnabled(false);
532 fShowLinesCheckbox = new BCheckBox(
533 "ShowLines", B_TRANSLATE("Show lines"),
534 new BMessage(MSG_CHECKBOX_SHOW_LINES));
535 fShowLinesCheckbox->SetValue(B_CONTROL_ON);
537 fSearchResults = new GrepListView();
538 fSearchResults->SetInvocationMessage(new BMessage(MSG_INVOKE_ITEM));
542 void
543 GrepWindow::_LayoutViews()
545 BScrollView* scroller = new BScrollView(
546 "ScrollSearchResults", fSearchResults,
547 B_FULL_UPDATE_ON_RESIZE, true, true);
549 BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
550 .SetInsets(0, 0, -1, -1)
551 .Add(fMenuBar)
552 .AddGrid(B_USE_HALF_ITEM_INSETS)
553 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
554 B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING)
555 .Add(fSearchText, 0, 0, 3)
556 .Add(fShowLinesCheckbox, 0, 1)
557 .Add(BSpaceLayoutItem::CreateGlue(), 1, 1)
558 .Add(fButton, 2, 1)
559 .End()
560 .AddGroup(B_VERTICAL, 0)
561 .SetInsets(-2, 0, -1, -1)
562 .Add(scroller)
563 .End()
564 .End();
566 fSearchText->MakeFocus(true);
568 SetKeyMenuBar(fMenuBar);
572 void
573 GrepWindow::_TileIfMultipleWindows()
575 if (be_app->Lock()) {
576 int32 windowCount = be_app->CountWindows();
577 be_app->Unlock();
579 if (windowCount > 1)
580 MoveBy(20, 20);
583 BScreen screen(this);
584 BRect screenFrame = screen.Frame();
585 BRect windowFrame = Frame();
587 if (windowFrame.left > screenFrame.right
588 || windowFrame.top > screenFrame.bottom
589 || windowFrame.right < screenFrame.left
590 || windowFrame.bottom < screenFrame.top)
591 MoveTo(50, 50);
595 // #pragma mark -
598 void
599 GrepWindow::_LoadPrefs()
601 Lock();
603 fModel->LoadPrefs();
605 fRecurseDirs->SetMarked(fModel->fRecurseDirs);
606 fRecurseLinks->SetMarked(fModel->fRecurseLinks);
607 fSkipDotDirs->SetMarked(fModel->fSkipDotDirs);
608 fCaseSensitive->SetMarked(fModel->fCaseSensitive);
609 fRegularExpression->SetMarked(fModel->fRegularExpression);
610 fTextOnly->SetMarked(fModel->fTextOnly);
611 fInvokePe->SetMarked(fModel->fInvokePe);
613 fShowLinesCheckbox->SetValue(fModel->fShowLines);
615 switch (fModel->fEncoding) {
616 case 0:
617 fUTF8->SetMarked(true);
618 break;
619 case B_SJIS_CONVERSION:
620 fShiftJIS->SetMarked(true);
621 break;
622 case B_EUC_CONVERSION:
623 fEUC->SetMarked(true);
624 break;
625 case B_JIS_CONVERSION:
626 fJIS->SetMarked(true);
627 break;
628 default:
629 printf("Woops. Bad fModel->fEncoding value.\n");
630 break;
633 MoveTo(fModel->fFrame.left, fModel->fFrame.top);
634 ResizeTo(fModel->fFrame.Width(), fModel->fFrame.Height());
636 Unlock();
640 void
641 GrepWindow::_SavePrefs()
643 fModel->SavePrefs();
647 void
648 GrepWindow::_StartNodeMonitoring()
650 CALLED();
652 _StopNodeMonitoring();
654 BMessenger messenger(this);
655 uint32 fileFlags = B_WATCH_NAME | B_WATCH_STAT | B_WATCH_ATTR;
658 // watch the top level folder only, rest should be done through filtering
659 // the node monitor notifications
660 BPath path(&fModel->fDirectory);
661 if (path.InitCheck() == B_OK) {
662 TRACE_NM("start monitoring root folder: %s\n", path.Path());
663 BPrivate::BPathMonitor::StartWatching(path.Path(),
664 fileFlags | B_WATCH_RECURSIVELY | B_WATCH_FILES_ONLY, messenger);
667 if (fChangesPulse == NULL) {
668 BMessage message(MSG_NODE_MONITOR_PULSE);
669 fChangesPulse = new BMessageRunner(BMessenger(this), &message,
670 kChangesPulseInterval);
675 void
676 GrepWindow::_StopNodeMonitoring()
678 if (fChangesPulse == NULL)
679 return;
681 CALLED();
683 BPrivate::BPathMonitor::StopWatching(BMessenger(this));
684 delete fChangesIterator;
685 fChangesIterator = NULL;
686 delete fChangesPulse;
687 fChangesPulse = NULL;
691 // #pragma mark - events
694 void
695 GrepWindow::_OnStartCancel()
697 CALLED();
699 _StopNodeMonitoring();
701 if (fModel->fState == STATE_IDLE) {
702 fSearchResults->MakeEmpty();
704 if (fSearchText->TextView()->TextLength() == 0)
705 return;
707 fModel->fState = STATE_SEARCH;
709 fModel->AddToHistory(fSearchText->Text());
711 // From now on, we don't want to be notified when the
712 // search pattern changes, because the control will be
713 // displaying the names of the files we are grepping.
715 fSearchText->SetModificationMessage(NULL);
717 fFileMenu->SetEnabled(false);
718 fActionMenu->SetEnabled(false);
719 fPreferencesMenu->SetEnabled(false);
720 fHistoryMenu->SetEnabled(false);
721 fEncodingMenu->SetEnabled(false);
723 fSearchText->SetEnabled(false);
725 fButton->MakeFocus(true);
726 fButton->SetLabel(B_TRANSLATE("Cancel"));
728 fSearch->SetEnabled(false);
730 // We need to remember the search pattern, because during
731 // the grepping, the text control's text will be replaced
732 // by the name of the file that's currently being grepped.
733 // When the grepping finishes, we need to restore the old
734 // search pattern.
736 fOldPattern = fSearchText->Text();
738 _SetWindowTitle();
740 FileIterator* iterator = new (nothrow) InitialIterator(fModel);
741 fGrepper = new (nothrow) Grepper(fOldPattern.String(), fModel,
742 this, iterator);
743 if (fGrepper != NULL && fGrepper->IsValid())
744 fGrepper->Start();
745 else {
746 // roll back in case of problems
747 if (fGrepper == NULL)
748 delete iterator;
749 else {
750 // Grepper owns iterator
751 delete fGrepper;
752 fGrepper = NULL;
754 fModel->fState = STATE_IDLE;
755 // TODO: better notification to user
756 fprintf(stderr, "Out of memory.\n");
758 } else if (fModel->fState == STATE_SEARCH) {
759 fModel->fState = STATE_CANCEL;
760 fGrepper->Cancel();
765 void
766 GrepWindow::_OnSearchFinished()
768 fModel->fState = STATE_IDLE;
770 delete fGrepper;
771 fGrepper = NULL;
773 fFileMenu->SetEnabled(true);
774 fActionMenu->SetEnabled(true);
775 fPreferencesMenu->SetEnabled(true);
776 fHistoryMenu->SetEnabled(true);
777 fEncodingMenu->SetEnabled(true);
779 fButton->SetLabel(B_TRANSLATE("Search"));
781 fButton->SetEnabled(true);
782 fSearch->SetEnabled(true);
784 fSearchText->SetEnabled(true);
785 fSearchText->MakeFocus(true);
786 fSearchText->SetText(fOldPattern.String());
787 fSearchText->TextView()->SelectAll();
788 fSearchText->SetModificationMessage(new BMessage(MSG_SEARCH_TEXT));
790 PostMessage(MSG_START_NODE_MONITORING);
794 void
795 GrepWindow::_OnNodeMonitorEvent(BMessage* message)
797 int32 opCode;
798 if (message->FindInt32("opcode", &opCode) != B_OK)
799 return;
801 if (fChangesIterator == NULL) {
802 fChangesIterator = new (nothrow) ChangesIterator(fModel);
803 if (fChangesIterator == NULL || !fChangesIterator->IsValid()) {
804 delete fChangesIterator;
805 fChangesIterator = NULL;
809 switch (opCode) {
810 case B_ENTRY_CREATED:
811 case B_ENTRY_REMOVED:
813 TRACE_NM("%s\n", opCode == B_ENTRY_CREATED ? "B_ENTRY_CREATED"
814 : "B_ENTRY_REMOVED");
815 BString path;
816 if (message->FindString("path", &path) == B_OK) {
817 if (opCode == B_ENTRY_CREATED) {
818 if (fChangesIterator != NULL)
819 fChangesIterator->EntryAdded(path.String());
820 } else {
821 // in order to remove temporary files
822 if (fChangesIterator != NULL)
823 fChangesIterator->EntryRemoved(path.String());
824 // remove from the list view already
825 BEntry entry(path.String());
826 entry_ref ref;
827 if (entry.GetRef(&ref) == B_OK)
828 fSearchResults->RemoveResults(ref, true);
830 } else {
831 #ifdef TRACE_NODE_MONITORING
832 printf("incompatible message:\n");
833 message->PrintToStream();
834 #endif
836 TRACE_NM("path: %s\n", path.String());
837 break;
839 case B_ENTRY_MOVED:
841 TRACE_NM("B_ENTRY_MOVED\n");
843 BString path;
844 if (message->FindString("path", &path) != B_OK) {
845 #ifdef TRACE_NODE_MONITORING
846 printf("incompatible message:\n");
847 message->PrintToStream();
848 #endif
849 break;
852 bool added;
853 if (message->FindBool("added", &added) != B_OK)
854 added = false;
855 bool removed;
856 if (message->FindBool("removed", &removed) != B_OK)
857 removed = false;
859 if (added) {
860 // new files
861 } else if (removed) {
862 // remove files
863 } else {
864 // files changed location, but are still within the search
865 // path!
866 BEntry entry(path.String());
867 entry_ref ref;
868 if (entry.GetRef(&ref) == B_OK) {
869 int32 index;
870 ResultItem* item = fSearchResults->FindItem(ref, &index);
871 if (item != NULL) {
872 item->SetText(path.String());
873 // take care of invalidation, the index is currently
874 // the full list index, but needs to be the visible
875 // items index for this
876 index = fSearchResults->IndexOf(item);
877 fSearchResults->InvalidateItem(index);
881 break;
883 case B_STAT_CHANGED:
884 case B_ATTR_CHANGED:
886 TRACE_NM("%s\n", opCode == B_STAT_CHANGED ? "B_STAT_CHANGED"
887 : "B_ATTR_CHANGED");
888 // For directly watched files, the path will include the
889 // name. When the event occurs for a file in a watched directory,
890 // the message will have an extra name field for the respective
891 // file.
892 BString path;
893 if (message->FindString("path", &path) == B_OK) {
894 if (fChangesIterator != NULL)
895 fChangesIterator->EntryChanged(path.String());
896 } else {
897 #ifdef TRACE_NODE_MONITORING
898 printf("incompatible message:\n");
899 message->PrintToStream();
900 #endif
902 TRACE_NM("path: %s\n", path.String());
903 // message->PrintToStream();
904 break;
907 default:
908 TRACE_NM("unkown op code\n");
909 break;
912 fLastNodeMonitorEvent = system_time();
916 void
917 GrepWindow::_OnNodeMonitorPulse()
919 if (fChangesIterator == NULL || fChangesIterator->IsEmpty())
920 return;
922 if (system_time() - fLastNodeMonitorEvent < kChangesPulseInterval) {
923 // wait for things to settle down before running the search for changes
924 return;
927 if (fModel->fState != STATE_IDLE) {
928 // An update or search is still in progress. New node monitor messages
929 // may arrive while an update is still running. They should not arrive
930 // during a regular search, but we want to be prepared for that anyways
931 // and check != STATE_IDLE.
932 return;
935 fOldPattern = fSearchText->Text();
937 #ifdef TRACE_NODE_MONITORING
938 fChangesIterator->PrintToStream();
939 #endif
941 fGrepper = new (nothrow) Grepper(fOldPattern.String(), fModel,
942 this, fChangesIterator);
943 if (fGrepper != NULL && fGrepper->IsValid()) {
944 fGrepper->Start();
945 fChangesIterator = NULL;
946 fModel->fState = STATE_UPDATE;
947 } else {
948 // roll back in case of problems
949 if (fGrepper == NULL)
950 delete fChangesIterator;
951 else {
952 // Grepper owns iterator
953 delete fGrepper;
954 fGrepper = NULL;
956 fprintf(stderr, "Out of memory.\n");
961 void
962 GrepWindow::_OnReportFileName(BMessage* message)
964 if (fModel->fState != STATE_UPDATE) {
965 BString name = message->FindString("filename");
966 fSearchText->TruncateString(&name, B_TRUNCATE_MIDDLE,
967 fSearchText->Bounds().Width() - 10);
969 fSearchText->SetText(name);
974 void
975 GrepWindow::_OnReportResult(BMessage* message)
977 CALLED();
978 entry_ref ref;
979 if (message->FindRef("ref", &ref) != B_OK)
980 return;
982 type_code type;
983 int32 count;
984 message->GetInfo("text", &type, &count);
986 BStringItem* item = NULL;
987 if (fModel->fState == STATE_UPDATE) {
988 // During updates because of node monitor events, negatives are
989 // also reported (count == 0).
990 item = fSearchResults->RemoveResults(ref, count == 0);
993 if (count == 0)
994 return;
996 if (item == NULL) {
997 item = new ResultItem(ref);
998 fSearchResults->AddItem(item);
999 item->SetExpanded(fShowLinesCheckbox->Value() == 1);
1002 const char* buf;
1003 while (message->FindString("text", --count, &buf) == B_OK) {
1004 uchar* temp = (uchar*)strdup(buf);
1005 uchar* ptr = temp;
1007 while (true) {
1008 // replace all non-printable characters by spaces
1009 uchar c = *ptr;
1011 if (c == '\0')
1012 break;
1014 if (!(c & 0x80) && iscntrl(c))
1015 *ptr = ' ';
1017 ++ptr;
1020 fSearchResults->AddUnder(new BStringItem((const char*)temp), item);
1022 free(temp);
1027 void
1028 GrepWindow::_OnReportError(BMessage* message)
1030 const char* buf;
1031 if (message->FindString("error", &buf) == B_OK)
1032 fSearchResults->AddItem(new BStringItem(buf));
1036 void
1037 GrepWindow::_OnRecurseLinks()
1039 fModel->fRecurseLinks = !fModel->fRecurseLinks;
1040 fRecurseLinks->SetMarked(fModel->fRecurseLinks);
1041 _ModelChanged();
1045 void
1046 GrepWindow::_OnRecurseDirs()
1048 fModel->fRecurseDirs = !fModel->fRecurseDirs;
1049 fRecurseDirs->SetMarked(fModel->fRecurseDirs);
1050 _ModelChanged();
1054 void
1055 GrepWindow::_OnSkipDotDirs()
1057 fModel->fSkipDotDirs = !fModel->fSkipDotDirs;
1058 fSkipDotDirs->SetMarked(fModel->fSkipDotDirs);
1059 _ModelChanged();
1063 void
1064 GrepWindow::_OnRegularExpression()
1066 fModel->fRegularExpression = !fModel->fRegularExpression;
1067 fRegularExpression->SetMarked(fModel->fRegularExpression);
1068 _ModelChanged();
1072 void
1073 GrepWindow::_OnCaseSensitive()
1075 fModel->fCaseSensitive = !fModel->fCaseSensitive;
1076 fCaseSensitive->SetMarked(fModel->fCaseSensitive);
1077 _ModelChanged();
1081 void
1082 GrepWindow::_OnTextOnly()
1084 fModel->fTextOnly = !fModel->fTextOnly;
1085 fTextOnly->SetMarked(fModel->fTextOnly);
1086 _ModelChanged();
1090 void
1091 GrepWindow::_OnInvokePe()
1093 fModel->fInvokePe = !fModel->fInvokePe;
1094 fInvokePe->SetMarked(fModel->fInvokePe);
1095 _SavePrefs();
1099 void
1100 GrepWindow::_OnCheckboxShowLines()
1102 // Selection in BOutlineListView in multiple selection mode
1103 // gets weird when collapsing. I've tried all sorts of things.
1104 // It seems impossible to make it behave just right.
1106 // Going from collapsed to expande mode, the superitems
1107 // keep their selection, the subitems don't (yet) have
1108 // a selection. This works as expected, AFAIK.
1110 // Going from expanded to collapsed mode, I would like
1111 // for a selected subitem (line) to select its superitem,
1112 // (its file) and the subitem be unselected.
1114 // I've successfully tried code patches that apply the
1115 // selection pattern that I want, but with weird effects
1116 // on subsequent manual selection.
1117 // Lines stay selected while the user tries to select
1118 // some other line. It just gets weird.
1120 // It's as though listItem->Select() and Deselect()
1121 // put the items in some semi-selected state.
1122 // Or maybe I've got it all wrong.
1124 // So, here's the plain basic collapse/expand.
1125 // I think it's the least bad of what's possible on BeOS R5,
1126 // but perhaps someone comes along with a patch of magic.
1128 fModel->fShowLines = (fShowLinesCheckbox->Value() == 1);
1130 int32 numItems = fSearchResults->FullListCountItems();
1131 for (int32 x = 0; x < numItems; ++x) {
1132 BListItem* listItem = fSearchResults->FullListItemAt(x);
1133 if (listItem->OutlineLevel() == 0) {
1134 if (fModel->fShowLines) {
1135 if (!fSearchResults->IsExpanded(x))
1136 fSearchResults->Expand(listItem);
1137 } else {
1138 if (fSearchResults->IsExpanded(x))
1139 fSearchResults->Collapse(listItem);
1144 fSearchResults->Invalidate();
1146 _SavePrefs();
1150 void
1151 GrepWindow::_OnInvokeItem()
1153 for (int32 selectionIndex = 0; ; selectionIndex++) {
1154 int32 itemIndex = fSearchResults->CurrentSelection(selectionIndex);
1155 BListItem* item = fSearchResults->ItemAt(itemIndex);
1156 if (item == NULL)
1157 break;
1159 int32 level = item->OutlineLevel();
1160 int32 lineNum = -1;
1162 // Get the line number.
1163 // only this level has line numbers
1164 if (level == 1) {
1165 BStringItem* str = dynamic_cast<BStringItem*>(item);
1166 if (str != NULL) {
1167 lineNum = atol(str->Text());
1168 // fortunately, atol knows when to stop the conversion
1172 // Get the top-most item and launch its entry_ref.
1173 while (level != 0) {
1174 item = fSearchResults->Superitem(item);
1175 if (item == NULL)
1176 break;
1177 level = item->OutlineLevel();
1180 ResultItem* entry = dynamic_cast<ResultItem*>(item);
1181 if (entry != NULL) {
1182 if (fModel->fInvokePe && _OpenInPe(entry->ref, lineNum))
1183 return;
1185 // ask tracker to open it for us
1186 BMessenger target(TRACKER_SIGNATURE);
1187 BMessage message(B_REFS_RECEIVED);
1188 message.AddRef("refs", &entry->ref);
1189 if (lineNum > -1) {
1190 message.AddInt32("be:line", lineNum);
1192 target.SendMessage(&message);
1198 void
1199 GrepWindow::_OnSearchText()
1201 CALLED();
1203 bool enabled = fSearchText->TextView()->TextLength() != 0;
1204 fButton->SetEnabled(enabled);
1205 fSearch->SetEnabled(enabled);
1206 _StopNodeMonitoring();
1210 void
1211 GrepWindow::_OnHistoryItem(BMessage* message)
1213 const char* buf;
1214 if (message->FindString("text", &buf) == B_OK)
1215 fSearchText->SetText(buf);
1219 void
1220 GrepWindow::_OnTrimSelection()
1222 if (fSearchResults->CurrentSelection() < 0) {
1223 BString text;
1224 text << B_TRANSLATE("Please select the files you wish to keep searching.");
1225 text << "\n";
1226 text << B_TRANSLATE("The unselected files will be removed from the list.");
1227 text << "\n";
1228 BAlert* alert = new BAlert(NULL, text.String(), B_TRANSLATE("OK"), NULL, NULL,
1229 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1230 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
1231 alert->Go(NULL);
1232 return;
1235 BMessage message;
1236 BString path;
1238 for (int32 index = 0; ; index++) {
1239 BStringItem* item = dynamic_cast<BStringItem*>(
1240 fSearchResults->ItemAt(index));
1241 if (item == NULL)
1242 break;
1244 if (!item->IsSelected() || item->OutlineLevel() != 0)
1245 continue;
1247 if (path == item->Text())
1248 continue;
1250 path = item->Text();
1251 entry_ref ref;
1252 if (get_ref_for_path(path.String(), &ref) == B_OK)
1253 message.AddRef("refs", &ref);
1256 fModel->fDirectory = entry_ref();
1257 // invalidated on purpose
1259 fModel->fSelectedFiles.MakeEmpty();
1260 fModel->fSelectedFiles = message;
1262 PostMessage(MSG_START_CANCEL);
1264 _SetWindowTitle();
1268 void
1269 GrepWindow::_OnCopyText()
1271 bool onlyCopySelection = true;
1273 if (fSearchResults->CurrentSelection() < 0)
1274 onlyCopySelection = false;
1276 BString buffer;
1278 for (int32 index = 0; ; index++) {
1279 BStringItem* item = dynamic_cast<BStringItem*>(
1280 fSearchResults->ItemAt(index));
1281 if (item == NULL)
1282 break;
1284 if (onlyCopySelection) {
1285 if (item->IsSelected())
1286 buffer << item->Text() << "\n";
1287 } else
1288 buffer << item->Text() << "\n";
1291 status_t status = B_OK;
1293 BMessage* clip = NULL;
1295 if (be_clipboard->Lock()) {
1296 be_clipboard->Clear();
1298 clip = be_clipboard->Data();
1300 clip->AddData("text/plain", B_MIME_TYPE, buffer.String(),
1301 buffer.Length());
1303 status = be_clipboard->Commit();
1305 if (status != B_OK) {
1306 be_clipboard->Unlock();
1307 return;
1310 be_clipboard->Unlock();
1315 void
1316 GrepWindow::_OnSelectInTracker()
1318 if (fSearchResults->CurrentSelection() < 0) {
1319 BAlert* alert = new BAlert("Info",
1320 B_TRANSLATE("Please select the files you wish to have selected for you in "
1321 "Tracker."),
1322 B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1323 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
1324 alert->Go(NULL);
1325 return;
1328 BMessage message;
1329 BString filePath;
1330 BPath folderPath;
1331 BList folderList;
1332 BString lastFolderAddedToList;
1334 for (int32 index = 0; ; index++) {
1335 BStringItem* item = dynamic_cast<BStringItem*>(
1336 fSearchResults->ItemAt(index));
1337 if (item == NULL)
1338 break;
1340 // only open selected and top level (file) items
1341 if (!item->IsSelected() || item->OutlineLevel() > 0)
1342 continue;
1344 // check if this was previously opened
1345 if (filePath == item->Text())
1346 continue;
1348 filePath = item->Text();
1349 entry_ref file_ref;
1350 if (get_ref_for_path(filePath.String(), &file_ref) != B_OK)
1351 continue;
1353 message.AddRef("refs", &file_ref);
1355 // add parent folder to list of folders to open
1356 folderPath.SetTo(filePath.String());
1357 if (folderPath.GetParent(&folderPath) == B_OK) {
1358 BPath* path = new BPath(folderPath);
1359 if (path->Path() != lastFolderAddedToList) {
1360 // catches some duplicates
1361 folderList.AddItem(path);
1362 lastFolderAddedToList = path->Path();
1363 } else
1364 delete path;
1368 _RemoveFolderListDuplicates(&folderList);
1369 _OpenFoldersInTracker(&folderList);
1371 int32 aShortWhile = 100000;
1372 snooze(aShortWhile);
1374 if (!_AreAllFoldersOpenInTracker(&folderList)) {
1375 for (int32 x = 0; x < 5; x++) {
1376 aShortWhile += 100000;
1377 snooze(aShortWhile);
1378 _OpenFoldersInTracker(&folderList);
1382 if (!_AreAllFoldersOpenInTracker(&folderList)) {
1383 BString str1;
1384 str1 << B_TRANSLATE("%APP_NAME couldn't open one or more folders.");
1385 str1.ReplaceFirst("%APP_NAME",APP_NAME);
1386 BAlert* alert = new BAlert(NULL, str1.String(), B_TRANSLATE("OK"),
1387 NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
1388 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
1389 alert->Go(NULL);
1390 goto out;
1393 _SelectFilesInTracker(&folderList, &message);
1395 out:
1396 // delete folderList contents
1397 int32 folderCount = folderList.CountItems();
1398 for (int32 x = 0; x < folderCount; x++)
1399 delete static_cast<BPath*>(folderList.ItemAt(x));
1403 void
1404 GrepWindow::_OnQuitNow()
1406 if (be_app->Lock()) {
1407 be_app->PostMessage(B_QUIT_REQUESTED);
1408 be_app->Unlock();
1413 void
1414 GrepWindow::_OnFileDrop(BMessage* message)
1416 if (fModel->fState != STATE_IDLE)
1417 return;
1419 entry_ref directory;
1420 _InitRefsReceived(&directory, message);
1422 fModel->fDirectory = directory;
1423 fModel->fSelectedFiles.MakeEmpty();
1424 fModel->fSelectedFiles = *message;
1426 fSearchResults->MakeEmpty();
1427 fOldPattern = "";
1429 _SetWindowTitle();
1433 void
1434 GrepWindow::_OnRefsReceived(BMessage* message)
1436 _OnFileDrop(message);
1437 fOldPattern = "";
1438 // It seems a B_CANCEL always follows a B_REFS_RECEIVED
1439 // from a BFilePanel in Open mode.
1441 // _OnOpenPanelCancel() is called on B_CANCEL.
1442 // That's where saving the current dir of the file panel occurs, for now,
1443 // and also the neccesary deletion of the file panel object.
1444 // A hidden file panel would otherwise jam the shutdown process.
1448 void
1449 GrepWindow::_OnOpenPanel()
1451 if (fFilePanel != NULL)
1452 return;
1454 entry_ref path;
1455 if (get_ref_for_path(fModel->fFilePanelPath.String(), &path) != B_OK)
1456 return;
1458 BMessenger messenger(this);
1459 BMessage message(MSG_REFS_RECEIVED);
1460 fFilePanel = new BFilePanel(B_OPEN_PANEL, &messenger, &path,
1461 B_FILE_NODE | B_DIRECTORY_NODE | B_SYMLINK_NODE, true,
1462 &message, NULL, true, true);
1464 fFilePanel->Show();
1468 void
1469 GrepWindow::_OnOpenPanelCancel()
1471 entry_ref panelDirRef;
1472 fFilePanel->GetPanelDirectory(&panelDirRef);
1473 BPath path(&panelDirRef);
1474 fModel->fFilePanelPath = path.Path();
1475 delete fFilePanel;
1476 fFilePanel = NULL;
1480 void
1481 GrepWindow::_OnSelectAll(BMessage* message)
1483 BMessenger messenger(fSearchResults);
1484 messenger.SendMessage(B_SELECT_ALL);
1488 void
1489 GrepWindow::_OnNewWindow()
1491 BMessage cloneRefs;
1492 // we don't want GrepWindow::InitRefsReceived()
1493 // to mess with the refs of the current window
1495 cloneRefs = fModel->fSelectedFiles;
1496 cloneRefs.AddRef("dir_ref", &(fModel->fDirectory));
1498 new GrepWindow(&cloneRefs);
1502 // #pragma mark -
1505 void
1506 GrepWindow::_ModelChanged()
1508 CALLED();
1510 _StopNodeMonitoring();
1511 _SavePrefs();
1515 bool
1516 GrepWindow::_OpenInPe(const entry_ref &ref, int32 lineNum)
1518 BMessage message('Cmdl');
1519 message.AddRef("refs", &ref);
1521 if (lineNum != -1)
1522 message.AddInt32("line", lineNum);
1524 entry_ref pe;
1525 if (be_roster->FindApp(PE_SIGNATURE, &pe) != B_OK)
1526 return false;
1528 if (be_roster->IsRunning(&pe)) {
1529 BMessenger msngr(NULL, be_roster->TeamFor(&pe));
1530 if (msngr.SendMessage(&message) != B_OK)
1531 return false;
1532 } else {
1533 if (be_roster->Launch(&pe, &message) != B_OK)
1534 return false;
1537 return true;
1541 void
1542 GrepWindow::_RemoveFolderListDuplicates(BList* folderList)
1544 if (folderList == NULL)
1545 return;
1547 int32 folderCount = folderList->CountItems();
1548 BString folderX;
1549 BString folderY;
1551 for (int32 x = 0; x < folderCount; x++) {
1552 BPath* path = static_cast<BPath*>(folderList->ItemAt(x));
1553 folderX = path->Path();
1555 for (int32 y = x + 1; y < folderCount; y++) {
1556 path = static_cast<BPath*>(folderList->ItemAt(y));
1557 folderY = path->Path();
1558 if (folderX == folderY) {
1559 delete static_cast<BPath*>(folderList->RemoveItem(y));
1560 folderCount--;
1561 y--;
1568 status_t
1569 GrepWindow::_OpenFoldersInTracker(BList* folderList)
1571 status_t status = B_OK;
1572 BMessage refsMsg(B_REFS_RECEIVED);
1574 int32 folderCount = folderList->CountItems();
1575 for (int32 index = 0; index < folderCount; index++) {
1576 BPath* path = static_cast<BPath*>(folderList->ItemAt(index));
1578 entry_ref folderRef;
1579 status = get_ref_for_path(path->Path(), &folderRef);
1580 if (status != B_OK)
1581 return status;
1583 status = refsMsg.AddRef("refs", &folderRef);
1584 if (status != B_OK)
1585 return status;
1588 status = be_roster->Launch(TRACKER_SIGNATURE, &refsMsg);
1589 if (status != B_OK && status != B_ALREADY_RUNNING)
1590 return status;
1592 return B_OK;
1596 bool
1597 GrepWindow::_AreAllFoldersOpenInTracker(BList* folderList)
1599 // Compare the folders we want open in Tracker to
1600 // the actual Tracker windows currently open.
1602 // We build a list of open Tracker windows, and compare
1603 // it to the list of folders we want open in Tracker.
1605 // If all folders exists in the list of Tracker windows
1606 // return true
1608 status_t status = B_OK;
1609 BMessenger trackerMessenger(TRACKER_SIGNATURE);
1610 BMessage sendMessage;
1611 BMessage replyMessage;
1612 BList windowList;
1614 if (!trackerMessenger.IsValid())
1615 return false;
1617 for (int32 count = 1; ; count++) {
1618 sendMessage.MakeEmpty();
1619 replyMessage.MakeEmpty();
1621 sendMessage.what = B_GET_PROPERTY;
1622 sendMessage.AddSpecifier("Path");
1623 sendMessage.AddSpecifier("Poses");
1624 sendMessage.AddSpecifier("Window", count);
1626 status = trackerMessenger.SendMessage(&sendMessage, &replyMessage);
1627 if (status != B_OK)
1628 return false;
1630 entry_ref* trackerRef = new (nothrow) entry_ref;
1631 status = replyMessage.FindRef("result", trackerRef);
1632 if (status != B_OK || !windowList.AddItem(trackerRef)) {
1633 delete trackerRef;
1634 break;
1638 int32 folderCount = folderList->CountItems();
1639 int32 windowCount = windowList.CountItems();
1641 int32 found = 0;
1642 BPath* folderPath;
1643 entry_ref* windowRef;
1644 BString folderString;
1645 BString windowString;
1646 bool result = false;
1648 if (folderCount > windowCount) {
1649 // at least one folder is not open in Tracker
1650 goto out;
1653 // Loop over the two lists and see if all folders exist as window
1654 for (int32 x = 0; x < folderCount; x++) {
1655 for (int32 y = 0; y < windowCount; y++) {
1657 folderPath = static_cast<BPath*>(folderList->ItemAt(x));
1658 windowRef = static_cast<entry_ref*>(windowList.ItemAt(y));
1660 if (folderPath == NULL)
1661 break;
1663 if (windowRef == NULL)
1664 break;
1666 folderString = folderPath->Path();
1668 BEntry entry;
1669 BPath path;
1671 if (entry.SetTo(windowRef) == B_OK && path.SetTo(&entry) == B_OK) {
1673 windowString = path.Path();
1675 if (folderString == windowString) {
1676 found++;
1677 break;
1683 result = found == folderCount;
1685 out:
1686 // delete list of window entry_refs
1687 for (int32 x = 0; x < windowCount; x++)
1688 delete static_cast<entry_ref*>(windowList.ItemAt(x));
1690 return result;
1694 status_t
1695 GrepWindow::_SelectFilesInTracker(BList* folderList, BMessage* refsMessage)
1697 // loops over Tracker windows, find each windowRef,
1698 // extract the refs that are children of windowRef,
1699 // add refs to selection-message
1701 status_t status = B_OK;
1702 BMessenger trackerMessenger(TRACKER_SIGNATURE);
1703 BMessage windowSendMessage;
1704 BMessage windowReplyMessage;
1705 BMessage selectionSendMessage;
1706 BMessage selectionReplyMessage;
1708 if (!trackerMessenger.IsValid())
1709 return status;
1711 // loop over Tracker windows
1712 for (int32 windowCount = 1; ; windowCount++) {
1714 windowSendMessage.MakeEmpty();
1715 windowReplyMessage.MakeEmpty();
1717 windowSendMessage.what = B_GET_PROPERTY;
1718 windowSendMessage.AddSpecifier("Path");
1719 windowSendMessage.AddSpecifier("Poses");
1720 windowSendMessage.AddSpecifier("Window", windowCount);
1722 status = trackerMessenger.SendMessage(&windowSendMessage,
1723 &windowReplyMessage);
1725 if (status != B_OK)
1726 return status;
1728 entry_ref windowRef;
1729 status = windowReplyMessage.FindRef("result", &windowRef);
1730 if (status != B_OK)
1731 break;
1733 int32 folderCount = folderList->CountItems();
1735 // loop over folders in folderList
1736 for (int32 x = 0; x < folderCount; x++) {
1737 BPath* folderPath = static_cast<BPath*>(folderList->ItemAt(x));
1738 if (folderPath == NULL)
1739 break;
1741 BString folderString = folderPath->Path();
1743 BEntry windowEntry;
1744 BPath windowPath;
1745 BString windowString;
1747 status = windowEntry.SetTo(&windowRef);
1748 if (status != B_OK)
1749 break;
1751 status = windowPath.SetTo(&windowEntry);
1752 if (status != B_OK)
1753 break;
1755 windowString = windowPath.Path();
1757 // if match, loop over items in refsMessage
1758 // and add those that live in window/folder
1759 // to a selection message
1761 if (windowString == folderString) {
1762 selectionSendMessage.MakeEmpty();
1763 selectionSendMessage.what = B_SET_PROPERTY;
1764 selectionReplyMessage.MakeEmpty();
1766 // loop over refs and add to message
1767 entry_ref ref;
1768 for (int32 index = 0; ; index++) {
1769 status = refsMessage->FindRef("refs", index, &ref);
1770 if (status != B_OK)
1771 break;
1773 BDirectory directory(&windowRef);
1774 BEntry entry(&ref);
1775 if (directory.Contains(&entry))
1776 selectionSendMessage.AddRef("data", &ref);
1779 // finish selection message
1780 selectionSendMessage.AddSpecifier("Selection");
1781 selectionSendMessage.AddSpecifier("Poses");
1782 selectionSendMessage.AddSpecifier("Window", windowCount);
1784 trackerMessenger.SendMessage(&selectionSendMessage,
1785 &selectionReplyMessage);
1790 return B_OK;