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