1 /*
2 * Copyright 2004-2006, Jérôme DUVAL. All rights reserved.
3 * Copyright 2010, Karsten Heimrich. All rights reserved.
4 * Copyright 2013, Rene Gollent, rene@gollent.com.
5 * Distributed under the terms of the MIT License.
6 */
7
8
9 #include "ExpanderWindow.h"
10
11 #include <algorithm>
12
13 #include <Alert.h>
14 #include <Box.h>
15 #include <Button.h>
16 #include <Catalog.h>
17 #include <CheckBox.h>
18 #include <ControlLook.h>
19 #include <Entry.h>
20 #include <File.h>
21 #include <LayoutBuilder.h>
22 #include <Locale.h>
23 #include <Menu.h>
24 #include <MenuBar.h>
25 #include <MenuItem.h>
26 #include <Path.h>
27 #include <Screen.h>
28 #include <ScrollView.h>
29 #include <StringView.h>
30 #include <TextView.h>
31
32 #include "ExpanderApp.h"
33 #include "ExpanderThread.h"
34 #include "ExpanderPreferences.h"
35 #include "PasswordAlert.h"
36
37
38 const uint32 MSG_SOURCE = 'mSOU';
39 const uint32 MSG_DEST = 'mDES';
40 const uint32 MSG_EXPAND = 'mEXP';
41 const uint32 MSG_SHOW = 'mSHO';
42 const uint32 MSG_STOP = 'mSTO';
43 const uint32 MSG_PREFERENCES = 'mPRE';
44 const uint32 MSG_SOURCETEXT = 'mSTX';
45 const uint32 MSG_DESTTEXT = 'mDTX';
46 const uint32 MSG_SHOWCONTENTS = 'mSCT';
47
48
49 class StatusView : public BStringView {
50 public:
StatusView()51 StatusView()
52 :
53 BStringView(NULL, "")
54 {
55 }
56
~StatusView()57 virtual ~StatusView()
58 {
59 }
60
SetStatus(const BString & text)61 void SetStatus(const BString &text)
62 {
63 fStatus = text;
64 Invalidate();
65 }
66
Draw(BRect updateRect)67 void Draw(BRect updateRect)
68 {
69 BString truncated = fStatus;
70 if(fStatus.IsEmpty() == false) {
71 be_plain_font->TruncateString(&truncated, B_TRUNCATE_END,
72 Bounds().Width());
73 }
74
75 SetText(truncated);
76 BStringView::Draw(updateRect);
77 }
78
79 private:
80 BString fStatus;
81 };
82
83
84 #undef B_TRANSLATION_CONTEXT
85 #define B_TRANSLATION_CONTEXT "ExpanderWindow"
86
87
ExpanderWindow(BRect frame,const entry_ref * ref,BMessage * settings)88 ExpanderWindow::ExpanderWindow(BRect frame, const entry_ref* ref,
89 BMessage* settings)
90 :
91 BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Expander"), B_TITLED_WINDOW,
92 B_NORMAL_WINDOW_FEEL),
93 fSourcePanel(NULL),
94 fDestPanel(NULL),
95 fSourceChanged(true),
96 fListingThread(NULL),
97 fListingStarted(false),
98 fExpandingThread(NULL),
99 fExpandingStarted(false),
100 fSettings(*settings),
101 fPreferences(NULL)
102 {
103 _CreateMenuBar();
104
105 fDestButton = new BButton(B_TRANSLATE("Destination"),
106 new BMessage(MSG_DEST));
107 fSourceButton = new BButton(B_TRANSLATE("Source"),
108 new BMessage(MSG_SOURCE));
109 fExpandButton = new BButton(B_TRANSLATE("Expand"),
110 new BMessage(MSG_EXPAND));
111
112 BSize size = fDestButton->PreferredSize();
113 size.width = std::max(size.width, fSourceButton->PreferredSize().width);
114 size.width = std::max(size.width, fExpandButton->PreferredSize().width);
115
116 fDestButton->SetExplicitSize(size);
117 fSourceButton->SetExplicitSize(size);
118 fExpandButton->SetExplicitSize(size);
119
120 fListingText = new BTextView("listingText");
121 fListingText->SetText("");
122 fListingText->MakeEditable(false);
123 fListingText->SetStylable(false);
124 fListingText->SetWordWrap(false);
125 BFont font = be_fixed_font;
126 fListingText->SetFontAndColor(&font);
127 fScrollView = new BScrollView("", fListingText, B_INVALIDATE_AFTER_LAYOUT,
128 true, true);
129
130 const float spacing = be_control_look->DefaultItemSpacing();
131 BGroupLayout* pathLayout;
132 BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
133 .Add(fBar)
134 .AddGroup(B_VERTICAL, B_USE_ITEM_SPACING)
135 .AddGroup(B_HORIZONTAL, B_USE_ITEM_SPACING)
136 .Add(fSourceButton)
137 .Add(fSourceText = new BTextControl(NULL, NULL,
138 new BMessage(MSG_SOURCETEXT)))
139 .End()
140 .AddGroup(B_HORIZONTAL, B_USE_ITEM_SPACING)
141 .Add(fDestButton)
142 .Add(fDestText = new BTextControl(NULL, NULL,
143 new BMessage(MSG_DESTTEXT)))
144 .End()
145 .AddGroup(B_HORIZONTAL, B_USE_ITEM_SPACING)
146 .Add(fExpandButton)
147 .AddGroup(B_HORIZONTAL, B_USE_ITEM_SPACING)
148 .GetLayout(&pathLayout)
149 .Add(fShowContents = new BCheckBox(
150 B_TRANSLATE("Show contents"),
151 new BMessage(MSG_SHOWCONTENTS)))
152 .Add(fStatusView = new StatusView())
153 .End()
154 .End()
155 .SetInsets(B_USE_WINDOW_SPACING)
156 .End()
157 .Add(fScrollView);
158
159 pathLayout->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
160 size = GetLayout()->View()->PreferredSize();
161 fSizeLimit = size.Height() - fScrollView->PreferredSize().height - spacing;
162
163 fStatusView->SetExplicitMinSize(BSize(50.0f, B_SIZE_UNSET));
164 fStatusView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
165
166 ResizeTo(Bounds().Width(), fSizeLimit);
167 SetSizeLimits(size.Width(), 32767.0f, fSizeLimit, fSizeLimit);
168 SetZoomLimits(Bounds().Width(), fSizeLimit);
169 fPreviousHeight = -1;
170
171 fScrollView->Hide();
172
173 Show();
174 }
175
176
~ExpanderWindow()177 ExpanderWindow::~ExpanderWindow()
178 {
179 if (fDestPanel && fDestPanel->RefFilter())
180 delete fDestPanel->RefFilter();
181
182 if (fSourcePanel && fSourcePanel->RefFilter())
183 delete fSourcePanel->RefFilter();
184
185 delete fDestPanel;
186 delete fSourcePanel;
187 }
188
189
190 bool
ValidateDest()191 ExpanderWindow::ValidateDest()
192 {
193 BEntry entry(fDestText->Text(), true);
194 BVolume volume;
195 if (!entry.Exists()) {
196 BAlert* alert = new BAlert("destAlert",
197 B_TRANSLATE("Destination folder doesn't exist. "
198 "Would you like to create it?"),
199 B_TRANSLATE("Cancel"), B_TRANSLATE("Create"), NULL,
200 B_WIDTH_AS_USUAL, B_INFO_ALERT);
201 alert->SetShortcut(0, B_ESCAPE);
202
203 if (alert->Go() == 0)
204 return false;
205
206 if (create_directory(fDestText->Text(), 0755) != B_OK) {
207 BAlert* alert = new BAlert("destAlert",
208 B_TRANSLATE("Failed to create the destination folder."),
209 B_TRANSLATE("OK"), NULL, NULL,
210 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
211 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
212 alert->Go();
213 return false;
214 }
215
216 BEntry newEntry(fDestText->Text(), true);
217 newEntry.GetRef(&fDestRef);
218 return true;
219 }
220
221 if (!entry.IsDirectory()) {
222 BAlert* alert = new BAlert("destAlert",
223 B_TRANSLATE("The destination is not a folder."),
224 B_TRANSLATE("OK"), NULL, NULL,
225 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
226 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
227 alert->Go();
228 return false;
229 }
230
231 if (entry.GetVolume(&volume) != B_OK || volume.IsReadOnly()) {
232 BAlert* alert = new BAlert("destAlert",
233 B_TRANSLATE("The destination is read only."),
234 B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL,
235 B_WARNING_ALERT);
236 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
237 alert->Go();
238 return false;
239 }
240
241 entry.GetRef(&fDestRef);
242 return true;
243 }
244
245
246 void
MessageReceived(BMessage * message)247 ExpanderWindow::MessageReceived(BMessage* message)
248 {
249 switch (message->what) {
250 case MSG_SOURCE:
251 {
252 BEntry entry(fSourceText->Text(), true);
253 entry_ref srcRef;
254 if (entry.Exists() && entry.IsDirectory())
255 entry.GetRef(&srcRef);
256 if (!fSourcePanel) {
257 BMessenger messenger(this);
258 fSourcePanel = new BFilePanel(B_OPEN_PANEL, &messenger, &srcRef,
259 B_FILE_NODE, false, NULL, new RuleRefFilter(fRules), true);
260 (fSourcePanel->Window())->SetTitle(
261 B_TRANSLATE("Expander: Open"));
262 } else
263 fSourcePanel->SetPanelDirectory(&srcRef);
264 fSourcePanel->Show();
265 break;
266 }
267
268 case MSG_DEST:
269 {
270 BEntry entry(fDestText->Text(), true);
271 entry_ref destRef;
272 if (entry.Exists() && entry.IsDirectory())
273 entry.GetRef(&destRef);
274 if (!fDestPanel) {
275 BMessenger messenger(this);
276 fDestPanel = new DirectoryFilePanel(B_OPEN_PANEL, &messenger,
277 &destRef, B_DIRECTORY_NODE, false, NULL,
278 new DirectoryRefFilter(), true);
279 } else
280 fDestPanel->SetPanelDirectory(&destRef);
281 fDestPanel->Show();
282 break;
283 }
284
285 case MSG_DIRECTORY:
286 {
287 entry_ref ref;
288 fDestPanel->GetPanelDirectory(&ref);
289 fDestRef = ref;
290 BEntry entry(&ref);
291 BPath path(&entry);
292 fDestText->SetText(path.Path());
293 fDestPanel->Hide();
294 break;
295 }
296
297 case B_SIMPLE_DATA:
298 case B_REFS_RECEIVED:
299 RefsReceived(message);
300 break;
301
302 case MSG_EXPAND:
303 if (!ValidateDest())
304 break;
305 if (!fExpandingStarted) {
306 StartExpanding();
307 break;
308 }
309 // supposed to fall through
310 case MSG_STOP:
311 if (fExpandingStarted) {
312 fExpandingThread->SuspendExternalExpander();
313 BAlert* alert = new BAlert("stopAlert",
314 B_TRANSLATE("Are you sure you want to stop expanding this "
315 "archive? The expanded items may not be complete."),
316 B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL,
317 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
318 alert->SetShortcut(0, B_ESCAPE);
319 if (alert->Go() == 0) {
320 fExpandingThread->ResumeExternalExpander();
321 StopExpanding();
322 } else
323 fExpandingThread->ResumeExternalExpander();
324 }
325 break;
326
327 case MSG_SHOW:
328 fShowContents->SetValue(fShowContents->Value() == B_CONTROL_OFF
329 ? B_CONTROL_ON : B_CONTROL_OFF);
330 // supposed to fall through
331 case MSG_SHOWCONTENTS:
332 // change menu item label
333 fShowItem->SetLabel(fShowContents->Value() == B_CONTROL_OFF
334 ? B_TRANSLATE("Show contents") : B_TRANSLATE("Hide contents"));
335
336 if (fShowContents->Value() == B_CONTROL_OFF) {
337 if (fListingStarted)
338 StopListing();
339
340 fScrollView->Hide();
341 _UpdateWindowSize(false);
342 } else {
343 fScrollView->Show();
344 StartListing();
345 }
346 break;
347
348 case MSG_SOURCETEXT:
349 {
350 BEntry entry(fSourceText->Text(), true);
351 if (!entry.Exists()) {
352 BAlert* alert = new BAlert("srcAlert",
353 B_TRANSLATE("The file doesn't exist"),
354 B_TRANSLATE("Cancel"), NULL, NULL,
355 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
356 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
357 alert->Go();
358 break;
359 }
360
361 entry_ref ref;
362 entry.GetRef(&ref);
363 ExpanderRule* rule = fRules.MatchingRule(&ref);
364 if (rule) {
365 fSourceChanged = true;
366 fSourceRef = ref;
367 fShowContents->SetEnabled(true);
368 fExpandButton->SetEnabled(true);
369 fExpandItem->SetEnabled(true);
370 fShowItem->SetEnabled(true);
371 break;
372 }
373
374 BString string = "The file : ";
375 string += fSourceText->Text();
376 string += B_TRANSLATE_MARK(" is not supported");
377 BAlert* alert = new BAlert("srcAlert", string.String(),
378 B_TRANSLATE("Cancel"),
379 NULL, NULL, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_INFO_ALERT);
380 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
381 alert->Go();
382
383 fShowContents->SetEnabled(false);
384 fExpandButton->SetEnabled(false);
385 fExpandItem->SetEnabled(false);
386 fShowItem->SetEnabled(false);
387 break;
388 }
389
390 case MSG_DESTTEXT:
391 ValidateDest();
392 break;
393
394 case MSG_PREFERENCES:
395 if (fPreferences == NULL)
396 fPreferences = new ExpanderPreferences(&fSettings);
397
398 fPreferences->Show();
399 break;
400
401 case 'outp':
402 if (!fExpandingStarted && fListingStarted) {
403 // Check if the vertical scroll bar is at the end
404 float max, pos;
405 fScrollView->ScrollBar(B_VERTICAL)->GetRange(NULL, &max);
406 pos = fScrollView->ScrollBar(B_VERTICAL)->Value();
407 bool atEnd = (pos == max);
408
409 BString string;
410 int32 i = 0;
411 while (message->FindString("output", i++, &string) == B_OK) {
412 float length = fListingText->StringWidth(string.String());
413
414 if (length > fLongestLine)
415 fLongestLine = length;
416
417 fListingText->Insert(string.String());
418 }
419
420 if (atEnd && fScrollView->ScrollBar(B_VERTICAL)->Value() == pos) {
421 fScrollView->ScrollBar(B_VERTICAL)->GetRange(NULL, &max);
422 fScrollView->ScrollBar(B_VERTICAL)->SetValue(max);
423 }
424 } else if (fExpandingStarted) {
425 BString string;
426 int32 i = 0;
427 while (message->FindString("output", i++, &string) == B_OK) {
428 if (strstr(string.String(), "Enter password") != NULL) {
429 fExpandingThread->SuspendExternalExpander();
430 BString password;
431 PasswordAlert* alert =
432 new PasswordAlert("passwordAlert", string);
433 alert->Go(password);
434 fExpandingThread->ResumeExternalExpander();
435 fExpandingThread->PushInput(password);
436 }
437 }
438 }
439 break;
440
441 case 'errp':
442 {
443 BString string;
444 if (message->FindString("error", &string) == B_OK
445 && fExpandingStarted) {
446 fExpandingThread->SuspendExternalExpander();
447 if (strstr(string.String(), "password") != NULL) {
448 BString password;
449 PasswordAlert* alert = new PasswordAlert("passwordAlert",
450 string);
451 alert->Go(password);
452 fExpandingThread->ResumeExternalExpander();
453 fExpandingThread->PushInput(password);
454 } else {
455 BAlert* alert = new BAlert("stopAlert", string,
456 B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL,
457 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
458 alert->SetShortcut(0, B_ESCAPE);
459 if (alert->Go() == 0) {
460 fExpandingThread->ResumeExternalExpander();
461 StopExpanding();
462 } else
463 fExpandingThread->ResumeExternalExpander();
464 }
465 }
466 break;
467 }
468
469 case 'exit':
470 // thread has finished
471 // (finished, quit, killed, we don't know)
472 // reset window state
473 if (fExpandingStarted) {
474 fStatusView->SetStatus(B_TRANSLATE("File expanded"));
475 StopExpanding();
476 OpenDestFolder();
477 CloseWindowOrKeepOpen();
478 } else if (fListingStarted) {
479 fSourceChanged = false;
480 StopListing();
481 _ExpandListingText();
482 } else
483 fStatusView->SetStatus("");
484 break;
485
486 case 'exrr':
487 // thread has finished
488 // reset window state
489
490 fStatusView->SetStatus(B_TRANSLATE("Error when expanding archive"));
491 CloseWindowOrKeepOpen();
492 break;
493
494 default:
495 BWindow::MessageReceived(message);
496 }
497 }
498
499
500 bool
CanQuit()501 ExpanderWindow::CanQuit()
502 {
503 if ((fSourcePanel && fSourcePanel->IsShowing())
504 || (fDestPanel && fDestPanel->IsShowing())) {
505 return false;
506 }
507
508 if (fExpandingStarted) {
509 fExpandingThread->SuspendExternalExpander();
510 BAlert* alert = new BAlert("stopAlert",
511 B_TRANSLATE("Are you sure you want to stop expanding this "
512 "archive? The expanded items may not be complete."),
513 B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL,
514 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
515 alert->SetShortcut(0, B_ESCAPE);
516
517 if (alert->Go() == 0) {
518 fExpandingThread->ResumeExternalExpander();
519 StopExpanding();
520 } else {
521 fExpandingThread->ResumeExternalExpander();
522 return false;
523 }
524 }
525
526 return true;
527 }
528
529
530 bool
QuitRequested()531 ExpanderWindow::QuitRequested()
532 {
533 if (!CanQuit())
534 return false;
535
536 if (fListingStarted)
537 StopListing();
538
539 be_app->PostMessage(B_QUIT_REQUESTED);
540 fSettings.ReplacePoint("window_position", Frame().LeftTop());
541 ((ExpanderApp*)(be_app))->UpdateSettingsFrom(&fSettings);
542
543 return true;
544 }
545
546
547 void
RefsReceived(BMessage * message)548 ExpanderWindow::RefsReceived(BMessage* message)
549 {
550 entry_ref ref;
551 int32 i = 0;
552 int8 destinationFolder = 0x63;
553 fSettings.FindInt8("destination_folder", &destinationFolder);
554
555 while (message->FindRef("refs", i++, &ref) == B_OK) {
556 BEntry entry(&ref, true);
557 BPath path(&entry);
558 BNode node(&entry);
559
560 if (node.IsFile()) {
561 fSourceChanged = true;
562 fSourceRef = ref;
563 fSourceText->SetText(path.Path());
564 if (destinationFolder == 0x63) {
565 BPath parent;
566 path.GetParent(&parent);
567 fDestText->SetText(parent.Path());
568 get_ref_for_path(parent.Path(), &fDestRef);
569 } else if (destinationFolder == 0x65) {
570 fSettings.FindRef("destination_folder_use", &fDestRef);
571 BEntry dEntry(&fDestRef, true);
572 BPath dPath(&dEntry);
573 fDestText->SetText(dPath.Path());
574 }
575
576 BEntry dEntry(&fDestRef, true);
577 if (dEntry.Exists()) {
578 fExpandButton->SetEnabled(true);
579 fExpandItem->SetEnabled(true);
580 }
581
582 if (fShowContents->Value() == B_CONTROL_ON) {
583 StopListing();
584 StartListing();
585 } else {
586 fShowContents->SetEnabled(true);
587 fShowItem->SetEnabled(true);
588 }
589
590 bool fromApp;
591 if (message->FindBool("fromApp", &fromApp) == B_OK) {
592 AutoExpand();
593 } else
594 AutoListing();
595 } else if (node.IsDirectory()) {
596 fDestRef = ref;
597 fDestText->SetText(path.Path());
598 }
599 }
600 }
601
602
603 #undef B_TRANSLATION_CONTEXT
604 #define B_TRANSLATION_CONTEXT "ExpanderMenu"
605
606 void
_CreateMenuBar()607 ExpanderWindow::_CreateMenuBar()
608 {
609 fBar = new BMenuBar("menu_bar", B_ITEMS_IN_ROW, B_INVALIDATE_AFTER_LAYOUT);
610 BMenu* menu = new BMenu(B_TRANSLATE("File"));
611 menu->AddItem(fSourceItem
612 = new BMenuItem(B_TRANSLATE("Set source" B_UTF8_ELLIPSIS),
613 new BMessage(MSG_SOURCE), 'O'));
614 menu->AddItem(fDestItem
615 = new BMenuItem(B_TRANSLATE("Set destination" B_UTF8_ELLIPSIS),
616 new BMessage(MSG_DEST), 'D'));
617 menu->AddSeparatorItem();
618 menu->AddItem(fExpandItem = new BMenuItem(B_TRANSLATE("Expand"),
619 new BMessage(MSG_EXPAND), 'E'));
620 fExpandItem->SetEnabled(false);
621 menu->AddItem(fShowItem = new BMenuItem(B_TRANSLATE("Show contents"),
622 new BMessage(MSG_SHOW), 'L'));
623 fShowItem->SetEnabled(false);
624 menu->AddSeparatorItem();
625 menu->AddItem(fStopItem = new BMenuItem(B_TRANSLATE("Stop"),
626 new BMessage(MSG_STOP), 'K'));
627 fStopItem->SetEnabled(false);
628 menu->AddSeparatorItem();
629 menu->AddItem(new BMenuItem(B_TRANSLATE("Close"),
630 new BMessage(B_QUIT_REQUESTED), 'W'));
631 fBar->AddItem(menu);
632
633 menu = new BMenu(B_TRANSLATE("Settings"));
634 menu->AddItem(fPreferencesItem
635 = new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS),
636 new BMessage(MSG_PREFERENCES), ','));
637 fBar->AddItem(menu);
638 }
639
640
641 #undef B_TRANSLATION_CONTEXT
642 #define B_TRANSLATION_CONTEXT "ExpanderWindow"
643
644 void
StartExpanding()645 ExpanderWindow::StartExpanding()
646 {
647 ExpanderRule* rule = fRules.MatchingRule(&fSourceRef);
648 if (!rule)
649 return;
650
651 BEntry destEntry(fDestText->Text(), true);
652 if (!destEntry.Exists()) {
653 BAlert* alert = new BAlert("destAlert",
654 B_TRANSLATE("The folder was either moved, renamed or not supported."),
655 B_TRANSLATE("Cancel"), NULL, NULL,
656 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
657 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
658 alert->Go();
659 return;
660 }
661
662 BMessage message;
663 message.AddString("cmd", rule->ExpandCmd());
664 message.AddRef("srcRef", &fSourceRef);
665 message.AddRef("destRef", &fDestRef);
666
667 fExpandButton->SetLabel(B_TRANSLATE("Stop"));
668 fSourceButton->SetEnabled(false);
669 fDestButton->SetEnabled(false);
670 fShowContents->SetEnabled(false);
671 fSourceItem->SetEnabled(false);
672 fDestItem->SetEnabled(false);
673 fExpandItem->SetEnabled(false);
674 fShowItem->SetEnabled(false);
675 fStopItem->SetEnabled(true);
676 fPreferencesItem->SetEnabled(false);
677
678 BEntry entry(&fSourceRef);
679 BPath path(&entry);
680 BString text(B_TRANSLATE("Expanding '%s'" B_UTF8_ELLIPSIS));
681 text.ReplaceFirst("%s", path.Leaf());
682 fStatusView->SetStatus(text.String());
683
684 fExpandingThread = new ExpanderThread(&message, new BMessenger(this));
685 fExpandingThread->Start();
686
687 fExpandingStarted = true;
688 }
689
690
691 void
StopExpanding(void)692 ExpanderWindow::StopExpanding(void)
693 {
694 if (fExpandingThread) {
695 fExpandingThread->InterruptExternalExpander();
696 fExpandingThread = NULL;
697 }
698
699 fExpandingStarted = false;
700
701 fExpandButton->SetLabel(B_TRANSLATE("Expand"));
702 fSourceButton->SetEnabled(true);
703 fDestButton->SetEnabled(true);
704 fShowContents->SetEnabled(true);
705 fSourceItem->SetEnabled(true);
706 fDestItem->SetEnabled(true);
707 fExpandItem->SetEnabled(true);
708 fShowItem->SetEnabled(true);
709 fStopItem->SetEnabled(false);
710 fPreferencesItem->SetEnabled(true);
711 }
712
713
714 void
_ExpandListingText()715 ExpanderWindow::_ExpandListingText()
716 {
717 float delta = fLongestLine - fListingText->Frame().Width();
718
719 if (delta > 0) {
720 BScreen screen;
721 BRect screenFrame = screen.Frame();
722
723 if (Frame().right + delta > screenFrame.right)
724 delta = screenFrame.right - Frame().right - 4.0f;
725
726 ResizeBy(delta, 0.0f);
727 }
728
729 float minWidth, maxWidth, minHeight, maxHeight;
730 GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
731
732 if (minWidth < Frame().Width() + delta) {
733 // set the Zoom limit as the minimal required size
734 SetZoomLimits(Frame().Width() + delta,
735 std::min(fSizeLimit + fListingText->TextRect().Height()
736 + fLineHeight + B_H_SCROLL_BAR_HEIGHT + 1.0f,
737 maxHeight));
738 } else {
739 // set the zoom limit based on minimal window size allowed
740 SetZoomLimits(minWidth,
741 std::min(fSizeLimit + fListingText->TextRect().Height()
742 + fLineHeight + B_H_SCROLL_BAR_HEIGHT + 1.0f,
743 maxHeight));
744 }
745 }
746
747
748 void
_UpdateWindowSize(bool showContents)749 ExpanderWindow::_UpdateWindowSize(bool showContents)
750 {
751 float minWidth, maxWidth, minHeight, maxHeight;
752 GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
753
754 float bottom = fSizeLimit;
755
756 if (showContents) {
757 if (fPreviousHeight < 0.0) {
758 BFont font;
759 font_height fontHeight;
760 fListingText->GetFont(&font);
761 font.GetHeight(&fontHeight);
762 fLineHeight = ceilf(fontHeight.ascent + fontHeight.descent
763 + fontHeight.leading);
764 fPreviousHeight = bottom + 10.0 * fLineHeight;
765 }
766 minHeight = bottom + 5.0 * fLineHeight;
767 maxHeight = 32767.0;
768
769 bottom = std::max(fPreviousHeight, minHeight);
770 } else {
771 minHeight = fSizeLimit;
772 maxHeight = fSizeLimit;
773 fPreviousHeight = Frame().Height();
774 }
775
776 SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
777 ResizeTo(Frame().Width(), bottom);
778 }
779
780
781 void
StartListing()782 ExpanderWindow::StartListing()
783 {
784 _UpdateWindowSize(true);
785
786 if (!fSourceChanged)
787 return;
788
789 fPreviousHeight = -1.0;
790
791 fLongestLine = 0.0f;
792
793 ExpanderRule* rule = fRules.MatchingRule(&fSourceRef);
794 if (!rule)
795 return;
796
797 BMessage message;
798 message.AddString("cmd", rule->ListingCmd());
799 message.AddRef("srcRef", &fSourceRef);
800
801 fShowContents->SetEnabled(true);
802 fSourceItem->SetEnabled(false);
803 fDestItem->SetEnabled(false);
804 fExpandItem->SetEnabled(false);
805 fShowItem->SetEnabled(true);
806 fShowItem->SetLabel(B_TRANSLATE("Hide contents"));
807 fStopItem->SetEnabled(false);
808 fPreferencesItem->SetEnabled(false);
809
810 fSourceButton->SetEnabled(false);
811 fDestButton->SetEnabled(false);
812 fExpandButton->SetEnabled(false);
813
814 BEntry entry(&fSourceRef);
815 BPath path(&entry);
816 BString text(B_TRANSLATE("Creating listing for '%s'" B_UTF8_ELLIPSIS));
817 text.ReplaceFirst("%s", path.Leaf());
818 fStatusView->SetStatus(text.String());
819 fListingText->SetText("");
820 fListingText->MakeSelectable(false);
821
822 fListingThread = new ExpanderThread(&message, new BMessenger(this));
823 fListingThread->Start();
824
825 fListingStarted = true;
826 }
827
828
829 void
StopListing(void)830 ExpanderWindow::StopListing(void)
831 {
832 if (fListingThread) {
833 fListingThread->InterruptExternalExpander();
834 fListingThread = NULL;
835 }
836
837 fListingStarted = false;
838
839 fListingText->MakeSelectable(true);
840 fShowContents->SetEnabled(true);
841 fSourceItem->SetEnabled(true);
842 fDestItem->SetEnabled(true);
843 fExpandItem->SetEnabled(true);
844 fShowItem->SetEnabled(true);
845 fStopItem->SetEnabled(false);
846 fPreferencesItem->SetEnabled(true);
847
848 fSourceButton->SetEnabled(true);
849 fDestButton->SetEnabled(true);
850 fExpandButton->SetEnabled(true);
851 fStatusView->SetStatus("");
852 }
853
854
855 void
CloseWindowOrKeepOpen()856 ExpanderWindow::CloseWindowOrKeepOpen()
857 {
858 bool expandFiles = false;
859 fSettings.FindBool("automatically_expand_files", &expandFiles);
860
861 bool closeWhenDone = false;
862 fSettings.FindBool("close_when_done", &closeWhenDone);
863
864 if (expandFiles || closeWhenDone)
865 PostMessage(B_QUIT_REQUESTED);
866 }
867
868
869 void
OpenDestFolder()870 ExpanderWindow::OpenDestFolder()
871 {
872 bool openFolder = true;
873 fSettings.FindBool("open_destination_folder", &openFolder);
874
875 if (!openFolder)
876 return;
877
878 BMessage* message = new BMessage(B_REFS_RECEIVED);
879 message->AddRef("refs", &fDestRef);
880 BPath path(&fDestRef);
881 BMessenger tracker("application/x-vnd.Be-TRAK");
882 tracker.SendMessage(message);
883 }
884
885
886 void
AutoListing()887 ExpanderWindow::AutoListing()
888 {
889 bool showContents = false;
890 fSettings.FindBool("show_contents_listing", &showContents);
891
892 if (!showContents)
893 return;
894
895 fShowContents->SetValue(B_CONTROL_ON);
896 fShowContents->Invoke();
897 }
898
899
900 void
AutoExpand()901 ExpanderWindow::AutoExpand()
902 {
903 bool expandFiles = false;
904 fSettings.FindBool("automatically_expand_files", &expandFiles);
905
906 if (!expandFiles) {
907 AutoListing();
908 return;
909 }
910
911 fExpandButton->Invoke();
912 }
913