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