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: 51 StatusView() 52 : 53 BStringView(NULL, "") 54 { 55 } 56 57 virtual ~StatusView() 58 { 59 } 60 61 void SetStatus(const BString &text) 62 { 63 fStatus = text; 64 Invalidate(); 65 } 66 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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