Bug Summary

File:/boot/home/haiku/haiku/src/apps/text_search/GrepWindow.cpp
Location:line 959, column 5
Description:Called C++ object pointer is null

Annotated Source Code

1/*
2 * Copyright (c) 1998-2007 Matthijs Hollemans
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22#include "GrepWindow.h"
23
24#include <ctype.h>
25#include <errno(*(_errnop())).h>
26#include <new>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31
32#include <Application.h>
33#include <AppFileInfo.h>
34#include <Alert.h>
35#include <Clipboard.h>
36#include <MessageRunner.h>
37#include <Path.h>
38#include <PathMonitor.h>
39#include <Roster.h>
40#include <String.h>
41#include <UTF8.h>
42
43#include "ChangesIterator.h"
44#include "GlobalDefs.h"
45#include "Grepper.h"
46#include "InitialIterator.h"
47#include "Translation.h"
48
49#undef B_TRANSLATION_CONTEXT"GrepWindow"
50#define B_TRANSLATION_CONTEXT"GrepWindow" "GrepWindow"
51
52
53using std::nothrow;
54
55static const bigtime_t kChangesPulseInterval = 150000;
56
57#define TRACE_NODE_MONITORING
58#ifdef TRACE_NODE_MONITORING
59# define TRACE_NM(x...)printf(x...) printf(x)
60#else
61# define TRACE_NM(x...)printf(x...)
62#endif
63
64//#define TRACE_FUNCTIONS
65#ifdef TRACE_FUNCTIONS
66 class FunctionTracer {
67 public:
68 FunctionTracer(const char* functionName)
69 : fName(functionName)
70 {
71 printf("%s - enter\n", fName.String());
72 }
73 ~FunctionTracer()
74 {
75 printf("%s - exit\n", fName.String());
76 }
77 private:
78 BString fName;
79 };
80# define CALLED() FunctionTracer functionTracer(__PRETTY_FUNCTION__)
81#else
82# define CALLED()
83#endif // TRACE_FUNCTIONS
84
85
86GrepWindow::GrepWindow(BMessage* message)
87 : BWindow(BRect(0, 0, 1, 1), NULL__null, B_DOCUMENT_WINDOW, 0),
88 fSearchText(NULL__null),
89 fSearchResults(NULL__null),
90 fMenuBar(NULL__null),
91 fFileMenu(NULL__null),
92 fNew(NULL__null),
93 fOpen(NULL__null),
94 fClose(NULL__null),
95 fQuit(NULL__null),
96 fActionMenu(NULL__null),
97 fSelectAll(NULL__null),
98 fSearch(NULL__null),
99 fTrimSelection(NULL__null),
100 fCopyText(NULL__null),
101 fSelectInTracker(NULL__null),
102 fOpenSelection(NULL__null),
103 fPreferencesMenu(NULL__null),
104 fRecurseLinks(NULL__null),
105 fRecurseDirs(NULL__null),
106 fSkipDotDirs(NULL__null),
107 fCaseSensitive(NULL__null),
108 fEscapeText(NULL__null),
109 fTextOnly(NULL__null),
110 fInvokePe(NULL__null),
111 fShowLinesMenuitem(NULL__null),
112 fHistoryMenu(NULL__null),
113 fEncodingMenu(NULL__null),
114 fUTF8(NULL__null),
115 fShiftJIS(NULL__null),
116 fEUC(NULL__null),
117 fJIS(NULL__null),
118
119 fShowLinesCheckbox(NULL__null),
120 fButton(NULL__null),
121
122 fGrepper(NULL__null),
123 fOldPattern(""),
124 fModel(new (nothrow) Model()),
125 fLastNodeMonitorEvent(system_time()),
126 fChangesIterator(NULL__null),
127 fChangesPulse(NULL__null),
128
129 fFilePanel(NULL__null)
130{
131 if (fModel == NULL__null)
132 return;
133
134 entry_ref directory;
135 _InitRefsReceived(&directory, message);
136
137 fModel->fDirectory = directory;
138 fModel->fSelectedFiles = *message;
139
140 _SetWindowTitle();
141 _CreateMenus();
142 _CreateViews();
143 _LayoutViews();
144 _LoadPrefs();
145 _TileIfMultipleWindows();
146
147 Show();
148}
149
150
151GrepWindow::~GrepWindow()
152{
153 delete fGrepper;
154 delete fModel;
155}
156
157
158void GrepWindow::FrameResized(float width, float height)
159{
160 BWindow::FrameResized(width, height);
161 fModel->fFrame = Frame();
162 _SavePrefs();
163}
164
165
166void GrepWindow::FrameMoved(BPoint origin)
167{
168 BWindow::FrameMoved(origin);
169 fModel->fFrame = Frame();
170 _SavePrefs();
171}
172
173
174void GrepWindow::MenusBeginning()
175{
176 fModel->FillHistoryMenu(fHistoryMenu);
177 BWindow::MenusBeginning();
178}
179
180
181void GrepWindow::MenusEnded()
182{
183 for (int32 t = fHistoryMenu->CountItems(); t > 0; --t)
184 delete fHistoryMenu->RemoveItem(t - 1);
185
186 BWindow::MenusEnded();
187}
188
189
190void GrepWindow::MessageReceived(BMessage *message)
191{
192 switch (message->what) {
193 case MSG_NEW_WINDOW:
194 _OnNewWindow();
195 break;
196
197 case B_SIMPLE_DATA:
198 _OnFileDrop(message);
199 break;
200
201 case MSG_OPEN_PANEL:
202 _OnOpenPanel();
203 break;
204
205 case MSG_REFS_RECEIVED:
206 _OnRefsReceived(message);
207 break;
208
209 case B_CANCEL:
210 _OnOpenPanelCancel();
211 break;
212
213 case MSG_RECURSE_LINKS:
214 _OnRecurseLinks();
215 break;
216
217 case MSG_RECURSE_DIRS:
218 _OnRecurseDirs();
219 break;
220
221 case MSG_SKIP_DOT_DIRS:
222 _OnSkipDotDirs();
223 break;
224
225 case MSG_CASE_SENSITIVE:
226 _OnCaseSensitive();
227 break;
228
229 case MSG_ESCAPE_TEXT:
230 _OnEscapeText();
231 break;
232
233 case MSG_TEXT_ONLY:
234 _OnTextOnly();
235 break;
236
237 case MSG_INVOKE_PE:
238 _OnInvokePe();
239 break;
240
241 case MSG_SEARCH_TEXT:
242 _OnSearchText();
243 break;
244
245 case MSG_SELECT_HISTORY:
246 _OnHistoryItem(message);
247 break;
248
249 case MSG_START_CANCEL:
250 _OnStartCancel();
251 break;
252
253 case MSG_SEARCH_FINISHED:
254 _OnSearchFinished();
255 break;
256
257 case MSG_START_NODE_MONITORING:
258 _StartNodeMonitoring();
259 break;
260
261 case B_PATH_MONITOR'_PMN':
262 _OnNodeMonitorEvent(message);
263 break;
264
265 case MSG_NODE_MONITOR_PULSE:
266 _OnNodeMonitorPulse();
267 break;
268
269 case MSG_REPORT_FILE_NAME:
270 _OnReportFileName(message);
271 break;
272
273 case MSG_REPORT_RESULT:
274 _OnReportResult(message);
275 break;
276
277 case MSG_REPORT_ERROR:
278 _OnReportError(message);
279 break;
280
281 case MSG_SELECT_ALL:
282 _OnSelectAll(message);
283 break;
284
285 case MSG_TRIM_SELECTION:
286 _OnTrimSelection();
287 break;
288
289 case MSG_COPY_TEXT:
290 _OnCopyText();
291 break;
292
293 case MSG_SELECT_IN_TRACKER:
294 _OnSelectInTracker();
295 break;
296
297 case MSG_MENU_SHOW_LINES:
298 _OnMenuShowLines();
299 break;
300
301 case MSG_CHECKBOX_SHOW_LINES:
302 _OnCheckboxShowLines();
303 break;
304
305 case MSG_OPEN_SELECTION:
306 // fall through
307 case MSG_INVOKE_ITEM:
308 _OnInvokeItem();
309 break;
310
311 case MSG_QUIT_NOW:
312 _OnQuitNow();
313 break;
314
315 case 'utf8':
316 fModel->fEncoding = 0;
317 break;
318
319 case B_SJIS_CONVERSION:
320 fModel->fEncoding = B_SJIS_CONVERSION;
321 break;
322
323 case B_EUC_CONVERSION:
324 fModel->fEncoding = B_EUC_CONVERSION;
325 break;
326
327 case B_JIS_CONVERSION:
328 fModel->fEncoding = B_JIS_CONVERSION;
329 break;
330
331 default:
332 BWindow::MessageReceived(message);
333 break;
334 }
335}
336
337
338void
339GrepWindow::Quit()
340{
341 CALLED();
342
343 _StopNodeMonitoring();
344 _SavePrefs();
345
346 // TODO: stippi: Looks like this could be done
347 // by maintaining a counter in GrepApp with the number of open
348 // grep windows... and just quit when it goes zero
349 if (be_app->Lock()) {
350 be_app->PostMessage(MSG_TRY_QUIT);
351 be_app->Unlock();
352 BWindow::Quit();
353 }
354}
355
356
357// #pragma mark -
358
359
360void
361GrepWindow::_InitRefsReceived(entry_ref* directory, BMessage* message)
362{
363 // HACK-HACK-HACK:
364 // If the user selected a single folder and invoked TextSearch on it,
365 // but recurse directories is switched off, TextSearch would do nothing.
366 // In that special case, we'd like it to recurse into that folder (but
367 // not go any deeper after that).
368
369 type_code code;
370 int32 count;
371 message->GetInfo("refs", &code, &count);
372
373 if (count == 0) {
374 if (message->FindRef("dir_ref", 0, directory) == B_OK((int)0))
375 message->MakeEmpty();
376 }
377
378 if (count == 1) {
379 entry_ref ref;
380 if (message->FindRef("refs", 0, &ref) == B_OK((int)0)) {
381 BEntry entry(&ref, true);
382 if (entry.IsDirectory()) {
383 // ok, special case, we use this folder as base directory
384 // and pretend nothing had been selected:
385 *directory = ref;
386 message->MakeEmpty();
387 }
388 }
389 }
390}
391
392
393void
394GrepWindow::_SetWindowTitle()
395{
396 BEntry entry(&fModel->fDirectory, true);
397 BString title;
398 if (entry.InitCheck() == B_OK((int)0)) {
399 BPath path;
400 if (entry.GetPath(&path) == B_OK((int)0))
401 title << B_TRANSLATE(APP_NAME)BLocaleRoster::Default()->GetCatalog()->GetString(("TextSearch"
), "GrepWindow")
<< ": " << path.Path();
402 }
403
404 if (!title.Length())
405 title = B_TRANSLATE(APP_NAME)BLocaleRoster::Default()->GetCatalog()->GetString(("TextSearch"
), "GrepWindow")
;
406
407 SetTitle(title.String());
408}
409
410
411void
412GrepWindow::_CreateMenus()
413{
414 fMenuBar = new BMenuBar(BRect(0,0,1,1), "menubar");
415
416 fFileMenu = new BMenu(B_TRANSLATE("File")BLocaleRoster::Default()->GetCatalog()->GetString(("File"
), "GrepWindow")
);
417 fActionMenu = new BMenu(B_TRANSLATE("Actions")BLocaleRoster::Default()->GetCatalog()->GetString(("Actions"
), "GrepWindow")
);
418 fPreferencesMenu = new BMenu(B_TRANSLATE("Settings")BLocaleRoster::Default()->GetCatalog()->GetString(("Settings"
), "GrepWindow")
);
419 fHistoryMenu = new BMenu(B_TRANSLATE("History")BLocaleRoster::Default()->GetCatalog()->GetString(("History"
), "GrepWindow")
);
420 fEncodingMenu = new BMenu(B_TRANSLATE("Encoding")BLocaleRoster::Default()->GetCatalog()->GetString(("Encoding"
), "GrepWindow")
);
421
422 fNew = new BMenuItem(
423 B_TRANSLATE("New window")BLocaleRoster::Default()->GetCatalog()->GetString(("New window"
), "GrepWindow")
, new BMessage(MSG_NEW_WINDOW), 'N');
424
425 fOpen = new BMenuItem(
426 B_TRANSLATE("Set target" B_UTF8_ELLIPSIS)BLocaleRoster::Default()->GetCatalog()->GetString(("Set target"
"\xE2\x80\xA6"), "GrepWindow")
, new BMessage(MSG_OPEN_PANEL), 'F');
427
428 fClose = new BMenuItem(
429 B_TRANSLATE("Close")BLocaleRoster::Default()->GetCatalog()->GetString(("Close"
), "GrepWindow")
, new BMessage(B_QUIT_REQUESTED), 'W');
430
431 fQuit = new BMenuItem(
432 B_TRANSLATE("Quit")BLocaleRoster::Default()->GetCatalog()->GetString(("Quit"
), "GrepWindow")
, new BMessage(MSG_QUIT_NOW), 'Q');
433
434 fSearch = new BMenuItem(
435 B_TRANSLATE("Search")BLocaleRoster::Default()->GetCatalog()->GetString(("Search"
), "GrepWindow")
, new BMessage(MSG_START_CANCEL), 'S');
436
437 fSelectAll = new BMenuItem(
438 B_TRANSLATE("Select all")BLocaleRoster::Default()->GetCatalog()->GetString(("Select all"
), "GrepWindow")
, new BMessage(MSG_SELECT_ALL), 'A');
439
440 fTrimSelection = new BMenuItem(
441 B_TRANSLATE("Trim to selection")BLocaleRoster::Default()->GetCatalog()->GetString(("Trim to selection"
), "GrepWindow")
, new BMessage(MSG_TRIM_SELECTION), 'T');
442
443 fOpenSelection = new BMenuItem(
444 B_TRANSLATE("Open selection")BLocaleRoster::Default()->GetCatalog()->GetString(("Open selection"
), "GrepWindow")
, new BMessage(MSG_OPEN_SELECTION), 'O');
445
446 fSelectInTracker = new BMenuItem(
447 B_TRANSLATE("Show files in Tracker")BLocaleRoster::Default()->GetCatalog()->GetString(("Show files in Tracker"
), "GrepWindow")
, new BMessage(MSG_SELECT_IN_TRACKER), 'K');
448
449 fCopyText = new BMenuItem(
450 B_TRANSLATE("Copy text to clipboard")BLocaleRoster::Default()->GetCatalog()->GetString(("Copy text to clipboard"
), "GrepWindow")
, new BMessage(MSG_COPY_TEXT), 'B');
451
452 fRecurseLinks = new BMenuItem(
453 B_TRANSLATE("Follow symbolic links")BLocaleRoster::Default()->GetCatalog()->GetString(("Follow symbolic links"
), "GrepWindow")
, new BMessage(MSG_RECURSE_LINKS));
454
455 fRecurseDirs = new BMenuItem(
456 B_TRANSLATE("Look in sub-folders")BLocaleRoster::Default()->GetCatalog()->GetString(("Look in sub-folders"
), "GrepWindow")
, new BMessage(MSG_RECURSE_DIRS));
457
458 fSkipDotDirs = new BMenuItem(
459 B_TRANSLATE("Skip folders starting with a dot")BLocaleRoster::Default()->GetCatalog()->GetString(("Skip folders starting with a dot"
), "GrepWindow")
, new BMessage(MSG_SKIP_DOT_DIRS));
460
461 fCaseSensitive = new BMenuItem(
462 B_TRANSLATE("Case-sensitive")BLocaleRoster::Default()->GetCatalog()->GetString(("Case-sensitive"
), "GrepWindow")
, new BMessage(MSG_CASE_SENSITIVE));
463
464 fEscapeText = new BMenuItem(
465 B_TRANSLATE("Escape search text")BLocaleRoster::Default()->GetCatalog()->GetString(("Escape search text"
), "GrepWindow")
, new BMessage(MSG_ESCAPE_TEXT));
466
467 fTextOnly = new BMenuItem(
468 B_TRANSLATE("Text files only")BLocaleRoster::Default()->GetCatalog()->GetString(("Text files only"
), "GrepWindow")
, new BMessage(MSG_TEXT_ONLY));
469
470 fInvokePe = new BMenuItem(
471 B_TRANSLATE("Open files in Pe")BLocaleRoster::Default()->GetCatalog()->GetString(("Open files in Pe"
), "GrepWindow")
, new BMessage(MSG_INVOKE_PE));
472
473 fShowLinesMenuitem = new BMenuItem(
474 B_TRANSLATE("Show lines")BLocaleRoster::Default()->GetCatalog()->GetString(("Show lines"
), "GrepWindow")
, new BMessage(MSG_MENU_SHOW_LINES), 'L');
475 fShowLinesMenuitem->SetMarked(true);
476
477 fUTF8 = new BMenuItem("UTF8", new BMessage('utf8'));
478 fShiftJIS = new BMenuItem("ShiftJIS", new BMessage(B_SJIS_CONVERSION));
479 fEUC = new BMenuItem("EUC", new BMessage(B_EUC_CONVERSION));
480 fJIS = new BMenuItem("JIS", new BMessage(B_JIS_CONVERSION));
481
482 fFileMenu->AddItem(fNew);
483 fFileMenu->AddSeparatorItem();
484 fFileMenu->AddItem(fOpen);
485 fFileMenu->AddItem(fClose);
486 fFileMenu->AddSeparatorItem();
487 fFileMenu->AddItem(fQuit);
488
489 fActionMenu->AddItem(fSearch);
490 fActionMenu->AddSeparatorItem();
491 fActionMenu->AddItem(fSelectAll);
492 fActionMenu->AddItem(fTrimSelection);
493 fActionMenu->AddSeparatorItem();
494 fActionMenu->AddItem(fOpenSelection);
495 fActionMenu->AddItem(fSelectInTracker);
496 fActionMenu->AddItem(fCopyText);
497
498 fPreferencesMenu->AddItem(fRecurseLinks);
499 fPreferencesMenu->AddItem(fRecurseDirs);
500 fPreferencesMenu->AddItem(fSkipDotDirs);
501 fPreferencesMenu->AddItem(fCaseSensitive);
502 fPreferencesMenu->AddItem(fEscapeText);
503 fPreferencesMenu->AddItem(fTextOnly);
504 fPreferencesMenu->AddItem(fInvokePe);
505 fPreferencesMenu->AddSeparatorItem();
506 fPreferencesMenu->AddItem(fShowLinesMenuitem);
507
508 fEncodingMenu->AddItem(fUTF8);
509 fEncodingMenu->AddItem(fShiftJIS);
510 fEncodingMenu->AddItem(fEUC);
511 fEncodingMenu->AddItem(fJIS);
512
513// fEncodingMenu->SetLabelFromMarked(true);
514 // Do we really want this ?
515 fEncodingMenu->SetRadioMode(true);
516 fEncodingMenu->ItemAt(0)->SetMarked(true);
517
518 fMenuBar->AddItem(fFileMenu);
519 fMenuBar->AddItem(fActionMenu);
520 fMenuBar->AddItem(fPreferencesMenu);
521 fMenuBar->AddItem(fHistoryMenu);
522 fMenuBar->AddItem(fEncodingMenu);
523
524 AddChild(fMenuBar);
525 SetKeyMenuBar(fMenuBar);
526
527 fSearch->SetEnabled(false);
528}
529
530
531void
532GrepWindow::_CreateViews()
533{
534 // The search pattern entry field does not send a message when
535 // <Enter> is pressed, because the "Search/Cancel" button already
536 // does this and we don't want to send the same message twice.
537
538 fSearchText = new BTextControl(
539 BRect(0, 0, 0, 1), "SearchText", NULL__null, NULL__null, NULL__null,
540 B_FOLLOW_LEFT_RIGHT_rule_(0, _VIEW_LEFT_, 0, _VIEW_RIGHT_) | B_FOLLOW_TOP_rule_(_VIEW_TOP_, 0, _VIEW_TOP_, 0),
541 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE);
542
543 fSearchText->TextView()->SetMaxBytes(1000);
544 fSearchText->ResizeToPreferred();
545 // because it doesn't have a label
546
547 fSearchText->SetModificationMessage(new BMessage(MSG_SEARCH_TEXT));
548
549 fButton = new BButton(
550 BRect(0, 1, 80, 1), "Button", B_TRANSLATE("Search")BLocaleRoster::Default()->GetCatalog()->GetString(("Search"
), "GrepWindow")
,
551 new BMessage(MSG_START_CANCEL), B_FOLLOW_RIGHT_rule_(0, _VIEW_RIGHT_, 0, _VIEW_RIGHT_));
552
553 fButton->MakeDefault(true);
554 fButton->ResizeToPreferred();
555 fButton->SetEnabled(false);
556
557 fShowLinesCheckbox = new BCheckBox(
558 BRect(0, 0, 1, 1), "ShowLines", B_TRANSLATE("Show lines")BLocaleRoster::Default()->GetCatalog()->GetString(("Show lines"
), "GrepWindow")
,
559 new BMessage(MSG_CHECKBOX_SHOW_LINES), B_FOLLOW_LEFT_rule_(0, _VIEW_LEFT_, 0, _VIEW_LEFT_));
560
561 fShowLinesCheckbox->SetValue(B_CONTROL_ON);
562 fShowLinesCheckbox->ResizeToPreferred();
563
564 fSearchResults = new GrepListView();
565
566 fSearchResults->SetInvocationMessage(new BMessage(MSG_INVOKE_ITEM));
567 fSearchResults->ResizeToPreferred();
568}
569
570
571void
572GrepWindow::_LayoutViews()
573{
574 float menubarWidth, menubarHeight = 20;
575 fMenuBar->GetPreferredSize(&menubarWidth, &menubarHeight);
576
577 BBox *background = new BBox(
578 BRect(0, menubarHeight + 1, 2, menubarHeight + 2), B_EMPTY_STRING,
579 B_FOLLOW_LEFT_RIGHT_rule_(0, _VIEW_LEFT_, 0, _VIEW_RIGHT_) | B_FOLLOW_TOP_rule_(_VIEW_TOP_, 0, _VIEW_TOP_, 0),
580 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP,
581 B_PLAIN_BORDER);
582
583 BScrollView *scroller = new BScrollView(
584 "ScrollSearchResults", fSearchResults, B_FOLLOW_ALL_SIDES_rule_(_VIEW_TOP_, _VIEW_LEFT_, _VIEW_BOTTOM_, _VIEW_RIGHT_),
585 B_FULL_UPDATE_ON_RESIZE, true, true, B_NO_BORDER);
586
587 scroller->ResizeToPreferred();
588
589 float width = 8 + fShowLinesCheckbox->Frame().Width()
590 + 8 + fButton->Frame().Width() + 8;
591
592 float height = 8 + fSearchText->Frame().Height() + 8
593 + fButton->Frame().Height() + 8 + scroller->Frame().Height();
594
595 float backgroundHeight = 8 + fSearchText->Frame().Height()
596 + 8 + fButton->Frame().Height() + 8;
597
598 ResizeTo(width, height);
599
600 AddChild(background);
601 background->ResizeTo(width, backgroundHeight);
602 background->AddChild(fSearchText);
603 background->AddChild(fShowLinesCheckbox);
604 background->AddChild(fButton);
605
606 fSearchText->MoveTo(8, 8);
607 fSearchText->ResizeTo(width - 16, fSearchText->Frame().Height());
608 fSearchText->MakeFocus(true);
609
610 fShowLinesCheckbox->MoveTo(
611 8, 8 + fSearchText->Frame().Height() + 8
612 + (fButton->Frame().Height() - fShowLinesCheckbox->Frame().Height())/2);
613
614 fButton->MoveTo(
615 width - fButton->Frame().Width() - 8,
616 8 + fSearchText->Frame().Height() + 8);
617
618 AddChild(scroller);
619 scroller->MoveTo(0, menubarHeight + 1 + backgroundHeight + 1);
620 scroller->ResizeTo(width + 1, height - backgroundHeight - menubarHeight - 1);
621
622 BRect screenRect = BScreen(this).Frame();
623
624 MoveTo(
625 (screenRect.Width() - width) / 2,
626 (screenRect.Height() - height) / 2);
627
628 SetSizeLimits(width, 10000, height, 10000);
629}
630
631
632void
633GrepWindow::_TileIfMultipleWindows()
634{
635 if (be_app->Lock()) {
636 int32 windowCount = be_app->CountWindows();
637 be_app->Unlock();
638
639 if (windowCount > 1)
640 MoveBy(20,20);
641 }
642
643 BScreen screen(this);
644 BRect screenFrame = screen.Frame();
645 BRect windowFrame = Frame();
646
647 if (windowFrame.left > screenFrame.right
648 || windowFrame.top > screenFrame.bottom
649 || windowFrame.right < screenFrame.left
650 || windowFrame.bottom < screenFrame.top)
651 MoveTo(50,50);
652}
653
654
655// #pragma mark -
656
657
658void
659GrepWindow::_LoadPrefs()
660{
661 Lock();
662
663 fModel->LoadPrefs();
664
665 fRecurseDirs->SetMarked(fModel->fRecurseDirs);
666 fRecurseLinks->SetMarked(fModel->fRecurseLinks);
667 fSkipDotDirs->SetMarked(fModel->fSkipDotDirs);
668 fCaseSensitive->SetMarked(fModel->fCaseSensitive);
669 fEscapeText->SetMarked(fModel->fEscapeText);
670 fTextOnly->SetMarked(fModel->fTextOnly);
671 fInvokePe->SetMarked(fModel->fInvokePe);
672
673 fShowLinesCheckbox->SetValue(
674 fModel->fShowContents ? B_CONTROL_ON : B_CONTROL_OFF);
675 fShowLinesMenuitem->SetMarked(
676 fModel->fShowContents ? true : false);
677
678 switch (fModel->fEncoding) {
679 case 0:
680 fUTF8->SetMarked(true);
681 break;
682 case B_SJIS_CONVERSION:
683 fShiftJIS->SetMarked(true);
684 break;
685 case B_EUC_CONVERSION:
686 fEUC->SetMarked(true);
687 break;
688 case B_JIS_CONVERSION:
689 fJIS->SetMarked(true);
690 break;
691 default:
692 printf("Woops. Bad fModel->fEncoding value.\n");
693 break;
694 }
695
696 MoveTo(fModel->fFrame.left, fModel->fFrame.top);
697 ResizeTo(fModel->fFrame.Width(), fModel->fFrame.Height());
698
699 Unlock();
700}
701
702
703void
704GrepWindow::_SavePrefs()
705{
706 fModel->SavePrefs();
707}
708
709
710void
711GrepWindow::_StartNodeMonitoring()
712{
713 CALLED();
714
715 _StopNodeMonitoring();
716
717 BMessenger messenger(this);
718 uint32 fileFlags = B_WATCH_NAME | B_WATCH_STAT | B_WATCH_ATTR;
719
720
721 // watch the top level folder only, rest should be done through filtering
722 // the node monitor notifications
723 BPath path(&fModel->fDirectory);
724 if (path.InitCheck() == B_OK((int)0)) {
725 TRACE_NM("start monitoring root folder: %s\n", path.Path())printf("start monitoring root folder: %s\n", path.Path());
726 BPrivate::BPathMonitor::StartWatching(path.Path(),
727 fileFlags | B_WATCH_RECURSIVELY0x0200 | B_WATCH_FILES_ONLY0x0100, messenger);
728 }
729
730 if (fChangesPulse == NULL__null) {
731 BMessage message(MSG_NODE_MONITOR_PULSE);
732 fChangesPulse = new BMessageRunner(BMessenger(this), &message,
733 kChangesPulseInterval);
734 }
735}
736
737
738void
739GrepWindow::_StopNodeMonitoring()
740{
741 if (fChangesPulse == NULL__null)
742 return;
743
744 CALLED();
745
746 BPrivate::BPathMonitor::StopWatching(BMessenger(this));
747 delete fChangesIterator;
748 fChangesIterator = NULL__null;
749 delete fChangesPulse;
750 fChangesPulse = NULL__null;
751}
752
753
754// #pragma mark - events
755
756
757void
758GrepWindow::_OnStartCancel()
759{
760 CALLED();
761
762 _StopNodeMonitoring();
763
764 if (fModel->fState == STATE_IDLE) {
765 fSearchResults->MakeEmpty();
766
767 if (fSearchText->TextView()->TextLength() == 0)
768 return;
769
770 fModel->fState = STATE_SEARCH;
771
772 fModel->AddToHistory(fSearchText->Text());
773
774 // From now on, we don't want to be notified when the
775 // search pattern changes, because the control will be
776 // displaying the names of the files we are grepping.
777
778 fSearchText->SetModificationMessage(NULL__null);
779
780 fFileMenu->SetEnabled(false);
781 fActionMenu->SetEnabled(false);
782 fPreferencesMenu->SetEnabled(false);
783 fHistoryMenu->SetEnabled(false);
784 fEncodingMenu->SetEnabled(false);
785
786 fSearchText->SetEnabled(false);
787
788 fButton->MakeFocus(true);
789 fButton->SetLabel(B_TRANSLATE("Cancel")BLocaleRoster::Default()->GetCatalog()->GetString(("Cancel"
), "GrepWindow")
);
790 fButton->ResizeToPreferred();
791 fButton->MoveTo(
792 fMenuBar->Frame().Width() - fButton->Frame().Width() - 8,
793 8 + fSearchText->Frame().Height() + 8);
794
795 fSearch->SetEnabled(false);
796
797 // We need to remember the search pattern, because during
798 // the grepping, the text control's text will be replaced
799 // by the name of the file that's currently being grepped.
800 // When the grepping finishes, we need to restore the old
801 // search pattern.
802
803 fOldPattern = fSearchText->Text();
804
805 FileIterator* iterator = new (nothrow) InitialIterator(fModel);
806 fGrepper = new (nothrow) Grepper(fOldPattern.String(), fModel,
807 this, iterator);
808 if (fGrepper != NULL__null && fGrepper->IsValid())
809 fGrepper->Start();
810 else {
811 // roll back in case of problems
812 if (fGrepper == NULL__null)
813 delete iterator;
814 else {
815 // Grepper owns iterator
816 delete fGrepper;
817 fGrepper = NULL__null;
818 }
819 fModel->fState = STATE_IDLE;
820 // TODO: better notification to user
821 fprintf(stderr, "Out of memory.\n");
822 }
823 } else if (fModel->fState == STATE_SEARCH) {
824 fModel->fState = STATE_CANCEL;
825 fGrepper->Cancel();
826 }
827}
828
829
830void
831GrepWindow::_OnSearchFinished()
832{
833 fModel->fState = STATE_IDLE;
834
835 delete fGrepper;
836 fGrepper = NULL__null;
837
838 fFileMenu->SetEnabled(true);
839 fActionMenu->SetEnabled(true);
840 fPreferencesMenu->SetEnabled(true);
841 fHistoryMenu->SetEnabled(true);
842 fEncodingMenu->SetEnabled(true);
843
844 fButton->SetLabel(B_TRANSLATE("Search")BLocaleRoster::Default()->GetCatalog()->GetString(("Search"
), "GrepWindow")
);
845 fButton->ResizeToPreferred();
846 fButton->MoveTo(
847 fMenuBar->Frame().Width() - fButton->Frame().Width() - 8,
848 8 + fSearchText->Frame().Height() + 8);
849
850 fButton->SetEnabled(true);
851 fSearch->SetEnabled(true);
852
853 fSearchText->SetEnabled(true);
854 fSearchText->MakeFocus(true);
855 fSearchText->SetText(fOldPattern.String());
856 fSearchText->TextView()->SelectAll();
857 fSearchText->SetModificationMessage(new BMessage(MSG_SEARCH_TEXT));
858
859 PostMessage(MSG_START_NODE_MONITORING);
860}
861
862
863void
864GrepWindow::_OnNodeMonitorEvent(BMessage* message)
865{
866 int32 opCode;
867 if (message->FindInt32("opcode", &opCode) != B_OK((int)0))
1
Taking false branch
868 return;
869
870 if (fChangesIterator == NULL__null) {
2
Taking true branch
871 fChangesIterator = new (nothrow) ChangesIterator(fModel);
872 if (fChangesIterator == NULL__null || !fChangesIterator->IsValid()) {
3
Taking true branch
873 delete fChangesIterator;
874 fChangesIterator = NULL__null;
4
Null pointer value stored to field 'fChangesIterator'
875 }
876 }
877
878 switch (opCode) {
5
Control jumps to 'case 5:' at line 949
879 case B_ENTRY_CREATED1:
880 case B_ENTRY_REMOVED2:
881 {
882 TRACE_NM("%s\n", opCode == B_ENTRY_CREATED ? "B_ENTRY_CREATED"printf("%s\n", opCode == 1 ? "B_ENTRY_CREATED" : "B_ENTRY_REMOVED"
)
883 : "B_ENTRY_REMOVED")printf("%s\n", opCode == 1 ? "B_ENTRY_CREATED" : "B_ENTRY_REMOVED"
)
;
884 BString path;
885 if (message->FindString("path", &path) == B_OK((int)0)) {
886 if (opCode == B_ENTRY_CREATED1)
887 fChangesIterator->EntryAdded(path.String());
888 else {
889 // in order to remove temporary files
890 fChangesIterator->EntryRemoved(path.String());
891 // remove from the list view already
892 BEntry entry(path.String());
893 entry_ref ref;
894 if (entry.GetRef(&ref) == B_OK((int)0))
895 fSearchResults->RemoveResults(ref, true);
896 }
897 } else {
898 #ifdef TRACE_NODE_MONITORING
899 printf("incompatible message:\n");
900 message->PrintToStream();
901 #endif
902 }
903 TRACE_NM("path: %s\n", path.String())printf("path: %s\n", path.String());
904 break;
905 }
906 case B_ENTRY_MOVED3:
907 {
908 TRACE_NM("B_ENTRY_MOVED\n")printf("B_ENTRY_MOVED\n");
909
910 BString path;
911 if (message->FindString("path", &path) != B_OK((int)0)) {
912 #ifdef TRACE_NODE_MONITORING
913 printf("incompatible message:\n");
914 message->PrintToStream();
915 #endif
916 break;
917 }
918
919 bool added;
920 if (message->FindBool("added", &added) != B_OK((int)0))
921 added = false;
922 bool removed;
923 if (message->FindBool("removed", &removed) != B_OK((int)0))
924 removed = false;
925
926 if (added) {
927 // new files
928 } else if (removed) {
929 // remove files
930 } else {
931 // files changed location, but are still within the search
932 // path!
933 BEntry entry(path.String());
934 entry_ref ref;
935 if (entry.GetRef(&ref) == B_OK((int)0)) {
936 int32 index;
937 ResultItem* item = fSearchResults->FindItem(ref, &index);
938 item->SetText(path.String());
939 // take care of invalidation, the index is currently
940 // the full list index, but needs to be the visible
941 // items index for this
942 index = fSearchResults->IndexOf(item);
943 fSearchResults->InvalidateItem(index);
944 }
945 }
946 break;
947 }
948 case B_STAT_CHANGED4:
949 case B_ATTR_CHANGED5:
950 {
951 TRACE_NM("%s\n", opCode == B_STAT_CHANGED ? "B_STAT_CHANGED"printf("%s\n", opCode == 4 ? "B_STAT_CHANGED" : "B_ATTR_CHANGED"
)
952 : "B_ATTR_CHANGED")printf("%s\n", opCode == 4 ? "B_STAT_CHANGED" : "B_ATTR_CHANGED"
)
;
953 // For directly watched files, the path will include the
954 // name. When the event occurs for a file in a watched directory,
955 // the message will have an extra name field for the respective
956 // file.
957 BString path;
958 if (message->FindString("path", &path) == B_OK((int)0)) {
6
Taking true branch
959 fChangesIterator->EntryChanged(path.String());
7
Called C++ object pointer is null
960 } else {
961 #ifdef TRACE_NODE_MONITORING
962 printf("incompatible message:\n");
963 message->PrintToStream();
964 #endif
965 }
966 TRACE_NM("path: %s\n", path.String())printf("path: %s\n", path.String());
967//message->PrintToStream();
968 break;
969 }
970
971 default:
972 TRACE_NM("unkown op code\n")printf("unkown op code\n");
973 break;
974 }
975
976 fLastNodeMonitorEvent = system_time();
977}
978
979
980void
981GrepWindow::_OnNodeMonitorPulse()
982{
983 if (fChangesIterator == NULL__null || fChangesIterator->IsEmpty())
984 return;
985
986 if (system_time() - fLastNodeMonitorEvent < kChangesPulseInterval) {
987 // wait for things to settle down before running the search for changes
988 return;
989 }
990
991 if (fModel->fState != STATE_IDLE) {
992 // An update or search is still in progress. New node monitor messages
993 // may arrive while an update is still running. They should not arrive
994 // during a regular search, but we want to be prepared for that anyways
995 // and check != STATE_IDLE.
996 return;
997 }
998
999 fOldPattern = fSearchText->Text();
1000
1001#ifdef TRACE_NODE_MONITORING
1002 fChangesIterator->PrintToStream();
1003#endif
1004
1005 fGrepper = new (nothrow) Grepper(fOldPattern.String(), fModel,
1006 this, fChangesIterator);
1007 if (fGrepper != NULL__null && fGrepper->IsValid()) {
1008 fGrepper->Start();
1009 fChangesIterator = NULL__null;
1010 fModel->fState = STATE_UPDATE;
1011 } else {
1012 // roll back in case of problems
1013 if (fGrepper == NULL__null)
1014 delete fChangesIterator;
1015 else {
1016 // Grepper owns iterator
1017 delete fGrepper;
1018 fGrepper = NULL__null;
1019 }
1020 fprintf(stderr, "Out of memory.\n");
1021 }
1022}
1023
1024
1025void
1026GrepWindow::_OnReportFileName(BMessage* message)
1027{
1028 if (fModel->fState != STATE_UPDATE)
1029 fSearchText->SetText(message->FindString("filename"));
1030}
1031
1032
1033void
1034GrepWindow::_OnReportResult(BMessage* message)
1035{
1036 CALLED();
1037
1038 entry_ref ref;
1039 if (message->FindRef("ref", &ref) != B_OK((int)0))
1040 return;
1041
1042 type_code type;
1043 int32 count;
1044 message->GetInfo("text", &type, &count);
1045
1046 BStringItem* item = NULL__null;
1047 if (fModel->fState == STATE_UPDATE) {
1048 // During updates because of node monitor events, negatives are
1049 // also reported (count == 0).
1050 item = fSearchResults->RemoveResults(ref, count == 0);
1051 }
1052
1053 if (count == 0)
1054 return;
1055
1056 if (item == NULL__null) {
1057 item = new ResultItem(ref);
1058 fSearchResults->AddItem(item);
1059 item->SetExpanded(fModel->fShowContents);
1060 }
1061
1062 const char* buf;
1063 while (message->FindString("text", --count, &buf) == B_OK((int)0)) {
1064 uchar* temp = (uchar*)strdup(buf);
1065 uchar* ptr = temp;
1066
1067 while (true) {
1068 // replace all non-printable characters by spaces
1069 uchar c = *ptr;
1070
1071 if (c == '\0')
1072 break;
1073
1074 if (!(c & 0x80) && iscntrl(c)(__ctype_b[(int)((c))] & (unsigned short int)_IScntrl))
1075 *ptr = ' ';
1076
1077 ++ptr;
1078 }
1079
1080 fSearchResults->AddUnder(new BStringItem((const char*)temp), item);
1081
1082 free(temp);
1083 }
1084}
1085
1086
1087void
1088GrepWindow::_OnReportError(BMessage *message)
1089{
1090 const char* buf;
1091 if (message->FindString("error", &buf) == B_OK((int)0))
1092 fSearchResults->AddItem(new BStringItem(buf));
1093}
1094
1095
1096void
1097GrepWindow::_OnRecurseLinks()
1098{
1099 fModel->fRecurseLinks = !fModel->fRecurseLinks;
1100 fRecurseLinks->SetMarked(fModel->fRecurseLinks);
1101 _ModelChanged();
1102}
1103
1104
1105void
1106GrepWindow::_OnRecurseDirs()
1107{
1108 fModel->fRecurseDirs = !fModel->fRecurseDirs;
1109 fRecurseDirs->SetMarked(fModel->fRecurseDirs);
1110 _ModelChanged();
1111}
1112
1113
1114void
1115GrepWindow::_OnSkipDotDirs()
1116{
1117 fModel->fSkipDotDirs = !fModel->fSkipDotDirs;
1118 fSkipDotDirs->SetMarked(fModel->fSkipDotDirs);
1119 _ModelChanged();
1120}
1121
1122
1123void
1124GrepWindow::_OnEscapeText()
1125{
1126 fModel->fEscapeText = !fModel->fEscapeText;
1127 fEscapeText->SetMarked(fModel->fEscapeText);
1128 _ModelChanged();
1129}
1130
1131
1132void
1133GrepWindow::_OnCaseSensitive()
1134{
1135 fModel->fCaseSensitive = !fModel->fCaseSensitive;
1136 fCaseSensitive->SetMarked(fModel->fCaseSensitive);
1137 _ModelChanged();
1138}
1139
1140
1141void
1142GrepWindow::_OnTextOnly()
1143{
1144 fModel->fTextOnly = !fModel->fTextOnly;
1145 fTextOnly->SetMarked(fModel->fTextOnly);
1146 _ModelChanged();
1147}
1148
1149
1150void
1151GrepWindow::_OnInvokePe()
1152{
1153 fModel->fInvokePe = !fModel->fInvokePe;
1154 fInvokePe->SetMarked(fModel->fInvokePe);
1155 _SavePrefs();
1156}
1157
1158
1159void
1160GrepWindow::_OnCheckboxShowLines()
1161{
1162 // toggle checkbox and menuitem
1163 fModel->fShowContents = !fModel->fShowContents;
1164 fShowLinesMenuitem->SetMarked(!fShowLinesMenuitem->IsMarked());
1165
1166 // Selection in BOutlineListView in multiple selection mode
1167 // gets weird when collapsing. I've tried all sorts of things.
1168 // It seems impossible to make it behave just right.
1169
1170 // Going from collapsed to expande mode, the superitems
1171 // keep their selection, the subitems don't (yet) have
1172 // a selection. This works as expected, AFAIK.
1173
1174 // Going from expanded to collapsed mode, I would like
1175 // for a selected subitem (line) to select its superitem,
1176 // (its file) and the subitem be unselected.
1177
1178 // I've successfully tried code patches that apply the
1179 // selection pattern that I want, but with weird effects
1180 // on subsequent manual selection.
1181 // Lines stay selected while the user tries to select
1182 // some other line. It just gets weird.
1183
1184 // It's as though listItem->Select() and Deselect()
1185 // put the items in some semi-selected state.
1186 // Or maybe I've got it all wrong.
1187
1188 // So, here's the plain basic collapse/expand.
1189 // I think it's the least bad of what's possible on BeOS R5,
1190 // but perhaps someone comes along with a patch of magic.
1191
1192 int32 numItems = fSearchResults->FullListCountItems();
1193 for (int32 x = 0; x < numItems; ++x) {
1194 BListItem* listItem = fSearchResults->FullListItemAt(x);
1195 if (listItem->OutlineLevel() == 0) {
1196 if (fModel->fShowContents) {
1197 if (!fSearchResults->IsExpanded(x))
1198 fSearchResults->Expand(listItem);
1199 } else {
1200 if (fSearchResults->IsExpanded(x))
1201 fSearchResults->Collapse(listItem);
1202 }
1203 }
1204 }
1205
1206 fSearchResults->Invalidate();
1207
1208 _SavePrefs();
1209}
1210
1211
1212void
1213GrepWindow::_OnMenuShowLines()
1214{
1215 // toggle companion checkbox
1216 fShowLinesCheckbox->SetValue(!fShowLinesCheckbox->Value());
1217 _OnCheckboxShowLines();
1218}
1219
1220
1221void
1222GrepWindow::_OnInvokeItem()
1223{
1224 for (int32 selectionIndex = 0; ; selectionIndex++) {
1225 int32 itemIndex = fSearchResults->CurrentSelection(selectionIndex);
1226 BListItem* item = fSearchResults->ItemAt(itemIndex);
1227 if (item == NULL__null)
1228 break;
1229
1230 int32 level = item->OutlineLevel();
1231 int32 lineNum = -1;
1232
1233 // Get the line number.
1234 // only this level has line numbers
1235 if (level == 1) {
1236 BStringItem *str = dynamic_cast<BStringItem*>(item);
1237 if (str != NULL__null) {
1238 lineNum = atol(str->Text());
1239 // fortunately, atol knows when to stop the conversion
1240 }
1241 }
1242
1243 // Get the top-most item and launch its entry_ref.
1244 while (level != 0) {
1245 item = fSearchResults->Superitem(item);
1246 if (item == NULL__null)
1247 break;
1248 level = item->OutlineLevel();
1249 }
1250
1251 ResultItem* entry = dynamic_cast<ResultItem*>(item);
1252 if (entry != NULL__null) {
1253 bool done = false;
1254
1255 if (fModel->fInvokePe)
1256 done = _OpenInPe(entry->ref, lineNum);
1257
1258 if (!done)
1259 be_roster->Launch(&entry->ref);
1260 }
1261 }
1262}
1263
1264
1265void
1266GrepWindow::_OnSearchText()
1267{
1268 CALLED();
1269
1270 bool enabled = fSearchText->TextView()->TextLength() != 0;
1271 fButton->SetEnabled(enabled);
1272 fSearch->SetEnabled(enabled);
1273 _StopNodeMonitoring();
1274}
1275
1276
1277void
1278GrepWindow::_OnHistoryItem(BMessage* message)
1279{
1280 const char* buf;
1281 if (message->FindString("text", &buf) == B_OK((int)0))
1282 fSearchText->SetText(buf);
1283}
1284
1285
1286void
1287GrepWindow::_OnTrimSelection()
1288{
1289 if (fSearchResults->CurrentSelection() < 0) {
1290 BString text;
1291 text << B_TRANSLATE("Please select the files you wish to keep searching.")BLocaleRoster::Default()->GetCatalog()->GetString(("Please select the files you wish to keep searching."
), "GrepWindow")
;
1292 text << "\n";
1293 text << B_TRANSLATE("The unselected files will be removed from the list.")BLocaleRoster::Default()->GetCatalog()->GetString(("The unselected files will be removed from the list."
), "GrepWindow")
;
1294 text << "\n";
1295 BAlert* alert = new BAlert(NULL__null, text.String(), B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "GrepWindow")
, NULL__null, NULL__null,
1296 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1297 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
1298 alert->Go(NULL__null);
1299 return;
1300 }
1301
1302 BMessage message;
1303 BString path;
1304
1305 for (int32 index = 0; ; index++) {
1306 BStringItem* item = dynamic_cast<BStringItem*>(
1307 fSearchResults->ItemAt(index));
1308 if (item == NULL__null)
1309 break;
1310
1311 if (!item->IsSelected() || item->OutlineLevel() != 0)
1312 continue;
1313
1314 if (path == item->Text())
1315 continue;
1316
1317 path = item->Text();
1318 entry_ref ref;
1319 if (get_ref_for_path(path.String(), &ref) == B_OK((int)0))
1320 message.AddRef("refs", &ref);
1321 }
1322
1323 fModel->fDirectory = entry_ref();
1324 // invalidated on purpose
1325
1326 fModel->fSelectedFiles.MakeEmpty();
1327 fModel->fSelectedFiles = message;
1328
1329 PostMessage(MSG_START_CANCEL);
1330
1331 _SetWindowTitle();
1332}
1333
1334
1335void
1336GrepWindow::_OnCopyText()
1337{
1338 bool onlyCopySelection = true;
1339
1340 if (fSearchResults->CurrentSelection() < 0)
1341 onlyCopySelection = false;
1342
1343 BString buffer;
1344
1345 for (int32 index = 0; ; index++) {
1346 BStringItem* item = dynamic_cast<BStringItem*>(
1347 fSearchResults->ItemAt(index));
1348 if (item == NULL__null)
1349 break;
1350
1351 if (onlyCopySelection) {
1352 if (item->IsSelected())
1353 buffer << item->Text() << "\n";
1354 } else
1355 buffer << item->Text() << "\n";
1356 }
1357
1358 status_t status = B_OK((int)0);
1359
1360 BMessage* clip = NULL__null;
1361
1362 if (be_clipboard->Lock()) {
1363 be_clipboard->Clear();
1364
1365 clip = be_clipboard->Data();
1366
1367 clip->AddData("text/plain", B_MIME_TYPE, buffer.String(),
1368 buffer.Length());
1369
1370 status = be_clipboard->Commit();
1371
1372 if (status != B_OK((int)0)) {
1373 be_clipboard->Unlock();
1374 return;
1375 }
1376
1377 be_clipboard->Unlock();
1378 }
1379}
1380
1381
1382void
1383GrepWindow::_OnSelectInTracker()
1384{
1385 if (fSearchResults->CurrentSelection() < 0) {
1386 BAlert* alert = new BAlert("Info",
1387 B_TRANSLATE("Please select the files you wish to have selected for you in "BLocaleRoster::Default()->GetCatalog()->GetString(("Please select the files you wish to have selected for you in "
"Tracker."), "GrepWindow")
1388 "Tracker.")BLocaleRoster::Default()->GetCatalog()->GetString(("Please select the files you wish to have selected for you in "
"Tracker."), "GrepWindow")
,
1389 B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "GrepWindow")
, NULL__null, NULL__null, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1390 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
1391 alert->Go(NULL__null);
1392 return;
1393 }
1394
1395 BMessage message;
1396 BString filePath;
1397 BPath folderPath;
1398 BList folderList;
1399 BString lastFolderAddedToList;
1400
1401 for (int32 index = 0; ; index++) {
1402 BStringItem* item = dynamic_cast<BStringItem*>(
1403 fSearchResults->ItemAt(index));
1404 if (item == NULL__null)
1405 break;
1406
1407 // only open selected and top level (file) items
1408 if (!item->IsSelected() || item->OutlineLevel() > 0)
1409 continue;
1410
1411 // check if this was previously opened
1412 if (filePath == item->Text())
1413 continue;
1414
1415 filePath = item->Text();
1416 entry_ref file_ref;
1417 if (get_ref_for_path(filePath.String(), &file_ref) != B_OK((int)0))
1418 continue;
1419
1420 message.AddRef("refs", &file_ref);
1421
1422 // add parent folder to list of folders to open
1423 folderPath.SetTo(filePath.String());
1424 if (folderPath.GetParent(&folderPath) == B_OK((int)0)) {
1425 BPath* path = new BPath(folderPath);
1426 if (path->Path() != lastFolderAddedToList) {
1427 // catches some duplicates
1428 folderList.AddItem(path);
1429 lastFolderAddedToList = path->Path();
1430 } else
1431 delete path;
1432 }
1433 }
1434
1435 _RemoveFolderListDuplicates(&folderList);
1436 _OpenFoldersInTracker(&folderList);
1437
1438 int32 aShortWhile = 100000;
1439 snooze(aShortWhile);
1440
1441 if (!_AreAllFoldersOpenInTracker(&folderList)) {
1442 for (int32 x = 0; x < 5; x++) {
1443 aShortWhile += 100000;
1444 snooze(aShortWhile);
1445 _OpenFoldersInTracker(&folderList);
1446 }
1447 }
1448
1449 if (!_AreAllFoldersOpenInTracker(&folderList)) {
1450 BString str1;
1451 str1 << B_TRANSLATE("%APP_NAME couldn't open one or more folders.")BLocaleRoster::Default()->GetCatalog()->GetString(("%APP_NAME couldn't open one or more folders."
), "GrepWindow")
;
1452 str1.ReplaceFirst("%APP_NAME",APP_NAME"TextSearch");
1453 BAlert* alert = new BAlert(NULL__null, str1.String(), B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "GrepWindow")
,
1454 NULL__null, NULL__null, B_WIDTH_AS_USUAL, B_STOP_ALERT);
1455 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
1456 alert->Go(NULL__null);
1457 goto out;
1458 }
1459
1460 _SelectFilesInTracker(&folderList, &message);
1461
1462out:
1463 // delete folderList contents
1464 int32 folderCount = folderList.CountItems();
1465 for (int32 x = 0; x < folderCount; x++)
1466 delete static_cast<BPath*>(folderList.ItemAt(x));
1467}
1468
1469
1470void
1471GrepWindow::_OnQuitNow()
1472{
1473 if (be_app->Lock()) {
1474 be_app->PostMessage(B_QUIT_REQUESTED);
1475 be_app->Unlock();
1476 }
1477}
1478
1479
1480void
1481GrepWindow::_OnFileDrop(BMessage* message)
1482{
1483 if (fModel->fState != STATE_IDLE)
1484 return;
1485
1486 entry_ref directory;
1487 _InitRefsReceived(&directory, message);
1488
1489 fModel->fDirectory = directory;
1490 fModel->fSelectedFiles.MakeEmpty();
1491 fModel->fSelectedFiles = *message;
1492
1493 fSearchResults->MakeEmpty();
1494
1495 _SetWindowTitle();
1496}
1497
1498
1499void
1500GrepWindow::_OnRefsReceived(BMessage* message)
1501{
1502 _OnFileDrop(message);
1503 // It seems a B_CANCEL always follows a B_REFS_RECEIVED
1504 // from a BFilePanel in Open mode.
1505 //
1506 // _OnOpenPanelCancel() is called on B_CANCEL.
1507 // That's where saving the current dir of the file panel occurs, for now,
1508 // and also the neccesary deletion of the file panel object.
1509 // A hidden file panel would otherwise jam the shutdown process.
1510}
1511
1512
1513void
1514GrepWindow::_OnOpenPanel()
1515{
1516 if (fFilePanel != NULL__null)
1517 return;
1518
1519 entry_ref path;
1520 if (get_ref_for_path(fModel->fFilePanelPath.String(), &path) != B_OK((int)0))
1521 return;
1522
1523 BMessenger messenger(this);
1524 BMessage message(MSG_REFS_RECEIVED);
1525 fFilePanel = new BFilePanel(B_OPEN_PANEL, &messenger, &path,
1526 B_FILE_NODE | B_DIRECTORY_NODE | B_SYMLINK_NODE, true,
1527 &message, NULL__null, true, true);
1528
1529 fFilePanel->Show();
1530}
1531
1532
1533void
1534GrepWindow::_OnOpenPanelCancel()
1535{
1536 entry_ref panelDirRef;
1537 fFilePanel->GetPanelDirectory(&panelDirRef);
1538 BPath path(&panelDirRef);
1539 fModel->fFilePanelPath = path.Path();
1540 delete fFilePanel;
1541 fFilePanel = NULL__null;
1542}
1543
1544
1545void
1546GrepWindow::_OnSelectAll(BMessage *message)
1547{
1548 BMessenger messenger(fSearchResults);
1549 messenger.SendMessage(B_SELECT_ALL);
1550}
1551
1552
1553void
1554GrepWindow::_OnNewWindow()
1555{
1556 BMessage cloneRefs;
1557 // we don't want GrepWindow::InitRefsReceived()
1558 // to mess with the refs of the current window
1559
1560 cloneRefs = fModel->fSelectedFiles;
1561 cloneRefs.AddRef("dir_ref", &(fModel->fDirectory));
1562
1563 new GrepWindow(&cloneRefs);
1564}
1565
1566
1567// #pragma mark -
1568
1569
1570void
1571GrepWindow::_ModelChanged()
1572{
1573 CALLED();
1574
1575 _StopNodeMonitoring();
1576 _SavePrefs();
1577}
1578
1579bool
1580GrepWindow::_OpenInPe(const entry_ref &ref, int32 lineNum)
1581{
1582 BMessage message('Cmdl');
1583 message.AddRef("refs", &ref);
1584
1585 if (lineNum != -1)
1586 message.AddInt32("line", lineNum);
1587
1588 entry_ref pe;
1589 if (be_roster->FindApp(PE_SIGNATURE"application/x-vnd.beunited.pe", &pe) != B_OK((int)0))
1590 return false;
1591
1592 if (be_roster->IsRunning(&pe)) {
1593 BMessenger msngr(NULL__null, be_roster->TeamFor(&pe));
1594 if (msngr.SendMessage(&message) != B_OK((int)0))
1595 return false;
1596 } else {
1597 if (be_roster->Launch(&pe, &message) != B_OK((int)0))
1598 return false;
1599 }
1600
1601 return true;
1602}
1603
1604
1605void
1606GrepWindow::_RemoveFolderListDuplicates(BList* folderList)
1607{
1608 if (folderList == NULL__null)
1609 return;
1610
1611 int32 folderCount = folderList->CountItems();
1612 BString folderX;
1613 BString folderY;
1614
1615 for (int32 x = 0; x < folderCount; x++) {
1616 BPath* path = static_cast<BPath*>(folderList->ItemAt(x));
1617 folderX = path->Path();
1618
1619 for (int32 y = x + 1; y < folderCount; y++) {
1620 path = static_cast<BPath*>(folderList->ItemAt(y));
1621 folderY = path->Path();
1622 if (folderX == folderY) {
1623 delete static_cast<BPath*>(folderList->RemoveItem(y));
1624 folderCount--;
1625 y--;
1626 }
1627 }
1628 }
1629}
1630
1631
1632status_t
1633GrepWindow::_OpenFoldersInTracker(BList* folderList)
1634{
1635 status_t status = B_OK((int)0);
1636 BMessage refsMsg(B_REFS_RECEIVED);
1637
1638 int32 folderCount = folderList->CountItems();
1639 for (int32 index = 0; index < folderCount; index++) {
1640 BPath* path = static_cast<BPath*>(folderList->ItemAt(index));
1641
1642 entry_ref folderRef;
1643 status = get_ref_for_path(path->Path(), &folderRef);
1644 if (status != B_OK((int)0))
1645 return status;
1646
1647 status = refsMsg.AddRef("refs", &folderRef);
1648 if (status != B_OK((int)0))
1649 return status;
1650 }
1651
1652 status = be_roster->Launch(TRACKER_SIGNATURE"application/x-vnd.Be-TRAK", &refsMsg);
1653 if (status != B_OK((int)0) && status != B_ALREADY_RUNNING(((-2147483647 - 1) + 0x2000) + 4))
1654 return status;
1655
1656 return B_OK((int)0);
1657}
1658
1659
1660bool
1661GrepWindow::_AreAllFoldersOpenInTracker(BList *folderList)
1662{
1663 // Compare the folders we want open in Tracker to
1664 // the actual Tracker windows currently open.
1665
1666 // We build a list of open Tracker windows, and compare
1667 // it to the list of folders we want open in Tracker.
1668
1669 // If all folders exists in the list of Tracker windows
1670 // return true
1671
1672 status_t status = B_OK((int)0);
1673 BMessenger trackerMessenger(TRACKER_SIGNATURE"application/x-vnd.Be-TRAK");
1674 BMessage sendMessage;
1675 BMessage replyMessage;
1676 BList windowList;
1677
1678 if (!trackerMessenger.IsValid())
1679 return false;
1680
1681 for (int32 count = 1; ; count++) {
1682 sendMessage.MakeEmpty();
1683 replyMessage.MakeEmpty();
1684
1685 sendMessage.what = B_GET_PROPERTY;
1686 sendMessage.AddSpecifier("Path");
1687 sendMessage.AddSpecifier("Poses");
1688 sendMessage.AddSpecifier("Window", count);
1689
1690 status = trackerMessenger.SendMessage(&sendMessage, &replyMessage);
1691 if (status != B_OK((int)0))
1692 return false;
1693
1694 entry_ref* trackerRef = new (nothrow) entry_ref;
1695 status = replyMessage.FindRef("result", trackerRef);
1696 if (status != B_OK((int)0) || !windowList.AddItem(trackerRef)) {
1697 delete trackerRef;
1698 break;
1699 }
1700 }
1701
1702 int32 folderCount = folderList->CountItems();
1703 int32 windowCount = windowList.CountItems();
1704
1705 int32 found = 0;
1706 BPath* folderPath;
1707 entry_ref* windowRef;
1708 BString folderString;
1709 BString windowString;
1710 bool result = false;
1711
1712 if (folderCount > windowCount) {
1713 // at least one folder is not open in Tracker
1714 goto out;
1715 }
1716
1717 // Loop over the two lists and see if all folders exist as window
1718 for (int32 x = 0; x < folderCount; x++) {
1719 for (int32 y = 0; y < windowCount; y++) {
1720
1721 folderPath = static_cast<BPath*>(folderList->ItemAt(x));
1722 windowRef = static_cast<entry_ref*>(windowList.ItemAt(y));
1723
1724 if (folderPath == NULL__null)
1725 break;
1726
1727 if (windowRef == NULL__null)
1728 break;
1729
1730 folderString = folderPath->Path();
1731
1732 BEntry entry;
1733 BPath path;
1734
1735 if (entry.SetTo(windowRef) == B_OK((int)0) && path.SetTo(&entry) == B_OK((int)0)) {
1736
1737 windowString = path.Path();
1738
1739 if (folderString == windowString) {
1740 found++;
1741 break;
1742 }
1743 }
1744 }
1745 }
1746
1747 result = found == folderCount;
1748
1749out:
1750 // delete list of window entry_refs
1751 for (int32 x = 0; x < windowCount; x++)
1752 delete static_cast<entry_ref*>(windowList.ItemAt(x));
1753
1754 return result;
1755}
1756
1757
1758status_t
1759GrepWindow::_SelectFilesInTracker(BList* folderList, BMessage* refsMessage)
1760{
1761 // loops over Tracker windows, find each windowRef,
1762 // extract the refs that are children of windowRef,
1763 // add refs to selection-message
1764
1765 status_t status = B_OK((int)0);
1766 BMessenger trackerMessenger(TRACKER_SIGNATURE"application/x-vnd.Be-TRAK");
1767 BMessage windowSendMessage;
1768 BMessage windowReplyMessage;
1769 BMessage selectionSendMessage;
1770 BMessage selectionReplyMessage;
1771
1772 if (!trackerMessenger.IsValid())
1773 return status;
1774
1775 // loop over Tracker windows
1776 for (int32 windowCount = 1; ; windowCount++) {
1777
1778 windowSendMessage.MakeEmpty();
1779 windowReplyMessage.MakeEmpty();
1780
1781 windowSendMessage.what = B_GET_PROPERTY;
1782 windowSendMessage.AddSpecifier("Path");
1783 windowSendMessage.AddSpecifier("Poses");
1784 windowSendMessage.AddSpecifier("Window", windowCount);
1785
1786 status = trackerMessenger.SendMessage(&windowSendMessage,
1787 &windowReplyMessage);
1788
1789 if (status != B_OK((int)0))
1790 return status;
1791
1792 entry_ref windowRef;
1793 status = windowReplyMessage.FindRef("result", &windowRef);
1794 if (status != B_OK((int)0))
1795 break;
1796
1797 int32 folderCount = folderList->CountItems();
1798
1799 // loop over folders in folderList
1800 for (int32 x = 0; x < folderCount; x++) {
1801 BPath* folderPath = static_cast<BPath*>(folderList->ItemAt(x));
1802 if (folderPath == NULL__null)
1803 break;
1804
1805 BString folderString = folderPath->Path();
1806
1807 BEntry windowEntry;
1808 BPath windowPath;
1809 BString windowString;
1810
1811 status = windowEntry.SetTo(&windowRef);
1812 if (status != B_OK((int)0))
1813 break;
1814
1815 status = windowPath.SetTo(&windowEntry);
1816 if (status != B_OK((int)0))
1817 break;
1818
1819 windowString = windowPath.Path();
1820
1821 // if match, loop over items in refsMessage
1822 // and add those that live in window/folder
1823 // to a selection message
1824
1825 if (windowString == folderString) {
1826 selectionSendMessage.MakeEmpty();
1827 selectionSendMessage.what = B_SET_PROPERTY;
1828 selectionReplyMessage.MakeEmpty();
1829
1830 // loop over refs and add to message
1831 entry_ref ref;
1832 for (int32 index = 0; ; index++) {
1833 status = refsMessage->FindRef("refs", index, &ref);
1834 if (status != B_OK((int)0))
1835 break;
1836
1837 BDirectory directory(&windowRef);
1838 BEntry entry(&ref);
1839 if (directory.Contains(&entry))
1840 selectionSendMessage.AddRef("data", &ref);
1841 }
1842
1843 // finish selection message
1844 selectionSendMessage.AddSpecifier("Selection");
1845 selectionSendMessage.AddSpecifier("Poses");
1846 selectionSendMessage.AddSpecifier("Window", windowCount);
1847
1848 trackerMessenger.SendMessage(&selectionSendMessage,
1849 &selectionReplyMessage);
1850 }
1851 }
1852 }
1853
1854 return B_OK((int)0);
1855}