File: | /boot/home/haiku/haiku/src/apps/text_search/GrepWindow.cpp |
Location: | line 887, column 6 |
Description: | Called C++ object pointer is null |
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 | ||||
53 | using std::nothrow; | |||
54 | ||||
55 | static 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 | ||||
86 | GrepWindow::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 | ||||
151 | GrepWindow::~GrepWindow() | |||
152 | { | |||
153 | delete fGrepper; | |||
154 | delete fModel; | |||
155 | } | |||
156 | ||||
157 | ||||
158 | void GrepWindow::FrameResized(float width, float height) | |||
159 | { | |||
160 | BWindow::FrameResized(width, height); | |||
161 | fModel->fFrame = Frame(); | |||
162 | _SavePrefs(); | |||
163 | } | |||
164 | ||||
165 | ||||
166 | void GrepWindow::FrameMoved(BPoint origin) | |||
167 | { | |||
168 | BWindow::FrameMoved(origin); | |||
169 | fModel->fFrame = Frame(); | |||
170 | _SavePrefs(); | |||
171 | } | |||
172 | ||||
173 | ||||
174 | void GrepWindow::MenusBeginning() | |||
175 | { | |||
176 | fModel->FillHistoryMenu(fHistoryMenu); | |||
177 | BWindow::MenusBeginning(); | |||
178 | } | |||
179 | ||||
180 | ||||
181 | void 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 | ||||
190 | void 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 | ||||
338 | void | |||
339 | GrepWindow::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 | ||||
360 | void | |||
361 | GrepWindow::_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 | ||||
393 | void | |||
394 | GrepWindow::_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 | ||||
411 | void | |||
412 | GrepWindow::_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 | ||||
531 | void | |||
532 | GrepWindow::_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 | ||||
571 | void | |||
572 | GrepWindow::_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 | ||||
632 | void | |||
633 | GrepWindow::_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 | ||||
658 | void | |||
659 | GrepWindow::_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 | ||||
703 | void | |||
704 | GrepWindow::_SavePrefs() | |||
705 | { | |||
706 | fModel->SavePrefs(); | |||
707 | } | |||
708 | ||||
709 | ||||
710 | void | |||
711 | GrepWindow::_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 | ||||
738 | void | |||
739 | GrepWindow::_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 | ||||
757 | void | |||
758 | GrepWindow::_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 | ||||
830 | void | |||
831 | GrepWindow::_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 | ||||
863 | void | |||
864 | GrepWindow::_OnNodeMonitorEvent(BMessage* message) | |||
865 | { | |||
866 | int32 opCode; | |||
867 | if (message->FindInt32("opcode", &opCode) != B_OK((int)0)) | |||
| ||||
868 | return; | |||
869 | ||||
870 | if (fChangesIterator == NULL__null) { | |||
871 | fChangesIterator = new (nothrow) ChangesIterator(fModel); | |||
872 | if (fChangesIterator == NULL__null || !fChangesIterator->IsValid()) { | |||
873 | delete fChangesIterator; | |||
874 | fChangesIterator = NULL__null; | |||
875 | } | |||
876 | } | |||
877 | ||||
878 | switch (opCode) { | |||
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)) { | |||
959 | fChangesIterator->EntryChanged(path.String()); | |||
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 | ||||
980 | void | |||
981 | GrepWindow::_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 | ||||
1025 | void | |||
1026 | GrepWindow::_OnReportFileName(BMessage* message) | |||
1027 | { | |||
1028 | if (fModel->fState != STATE_UPDATE) | |||
1029 | fSearchText->SetText(message->FindString("filename")); | |||
1030 | } | |||
1031 | ||||
1032 | ||||
1033 | void | |||
1034 | GrepWindow::_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 | ||||
1087 | void | |||
1088 | GrepWindow::_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 | ||||
1096 | void | |||
1097 | GrepWindow::_OnRecurseLinks() | |||
1098 | { | |||
1099 | fModel->fRecurseLinks = !fModel->fRecurseLinks; | |||
1100 | fRecurseLinks->SetMarked(fModel->fRecurseLinks); | |||
1101 | _ModelChanged(); | |||
1102 | } | |||
1103 | ||||
1104 | ||||
1105 | void | |||
1106 | GrepWindow::_OnRecurseDirs() | |||
1107 | { | |||
1108 | fModel->fRecurseDirs = !fModel->fRecurseDirs; | |||
1109 | fRecurseDirs->SetMarked(fModel->fRecurseDirs); | |||
1110 | _ModelChanged(); | |||
1111 | } | |||
1112 | ||||
1113 | ||||
1114 | void | |||
1115 | GrepWindow::_OnSkipDotDirs() | |||
1116 | { | |||
1117 | fModel->fSkipDotDirs = !fModel->fSkipDotDirs; | |||
1118 | fSkipDotDirs->SetMarked(fModel->fSkipDotDirs); | |||
1119 | _ModelChanged(); | |||
1120 | } | |||
1121 | ||||
1122 | ||||
1123 | void | |||
1124 | GrepWindow::_OnEscapeText() | |||
1125 | { | |||
1126 | fModel->fEscapeText = !fModel->fEscapeText; | |||
1127 | fEscapeText->SetMarked(fModel->fEscapeText); | |||
1128 | _ModelChanged(); | |||
1129 | } | |||
1130 | ||||
1131 | ||||
1132 | void | |||
1133 | GrepWindow::_OnCaseSensitive() | |||
1134 | { | |||
1135 | fModel->fCaseSensitive = !fModel->fCaseSensitive; | |||
1136 | fCaseSensitive->SetMarked(fModel->fCaseSensitive); | |||
1137 | _ModelChanged(); | |||
1138 | } | |||
1139 | ||||
1140 | ||||
1141 | void | |||
1142 | GrepWindow::_OnTextOnly() | |||
1143 | { | |||
1144 | fModel->fTextOnly = !fModel->fTextOnly; | |||
1145 | fTextOnly->SetMarked(fModel->fTextOnly); | |||
1146 | _ModelChanged(); | |||
1147 | } | |||
1148 | ||||
1149 | ||||
1150 | void | |||
1151 | GrepWindow::_OnInvokePe() | |||
1152 | { | |||
1153 | fModel->fInvokePe = !fModel->fInvokePe; | |||
1154 | fInvokePe->SetMarked(fModel->fInvokePe); | |||
1155 | _SavePrefs(); | |||
1156 | } | |||
1157 | ||||
1158 | ||||
1159 | void | |||
1160 | GrepWindow::_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 | ||||
1212 | void | |||
1213 | GrepWindow::_OnMenuShowLines() | |||
1214 | { | |||
1215 | // toggle companion checkbox | |||
1216 | fShowLinesCheckbox->SetValue(!fShowLinesCheckbox->Value()); | |||
1217 | _OnCheckboxShowLines(); | |||
1218 | } | |||
1219 | ||||
1220 | ||||
1221 | void | |||
1222 | GrepWindow::_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 | ||||
1265 | void | |||
1266 | GrepWindow::_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 | ||||
1277 | void | |||
1278 | GrepWindow::_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 | ||||
1286 | void | |||
1287 | GrepWindow::_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 | ||||
1335 | void | |||
1336 | GrepWindow::_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 | ||||
1382 | void | |||
1383 | GrepWindow::_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 | ||||
1462 | out: | |||
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 | ||||
1470 | void | |||
1471 | GrepWindow::_OnQuitNow() | |||
1472 | { | |||
1473 | if (be_app->Lock()) { | |||
1474 | be_app->PostMessage(B_QUIT_REQUESTED); | |||
1475 | be_app->Unlock(); | |||
1476 | } | |||
1477 | } | |||
1478 | ||||
1479 | ||||
1480 | void | |||
1481 | GrepWindow::_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 | ||||
1499 | void | |||
1500 | GrepWindow::_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 | ||||
1513 | void | |||
1514 | GrepWindow::_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 | ||||
1533 | void | |||
1534 | GrepWindow::_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 | ||||
1545 | void | |||
1546 | GrepWindow::_OnSelectAll(BMessage *message) | |||
1547 | { | |||
1548 | BMessenger messenger(fSearchResults); | |||
1549 | messenger.SendMessage(B_SELECT_ALL); | |||
1550 | } | |||
1551 | ||||
1552 | ||||
1553 | void | |||
1554 | GrepWindow::_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 | ||||
1570 | void | |||
1571 | GrepWindow::_ModelChanged() | |||
1572 | { | |||
1573 | CALLED(); | |||
1574 | ||||
1575 | _StopNodeMonitoring(); | |||
1576 | _SavePrefs(); | |||
1577 | } | |||
1578 | ||||
1579 | bool | |||
1580 | GrepWindow::_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 | ||||
1605 | void | |||
1606 | GrepWindow::_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 | ||||
1632 | status_t | |||
1633 | GrepWindow::_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 | ||||
1660 | bool | |||
1661 | GrepWindow::_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 | ||||
1749 | out: | |||
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 | ||||
1758 | status_t | |||
1759 | GrepWindow::_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 | } |