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 .Add(fScrollView) 156 .SetInsets(B_USE_WINDOW_SPACING) 157 .End(); 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("Create"), B_TRANSLATE("Cancel"), NULL, 200 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_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("stopAlert", 208 B_TRANSLATE("Failed to create the destination folder."), 209 B_TRANSLATE("Cancel"), NULL, NULL, 210 B_WIDTH_AS_USUAL, B_EVEN_SPACING, 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 222 if (!entry.IsDirectory()) { 223 BAlert* alert = new BAlert("destAlert", 224 B_TRANSLATE("The destination is not a folder."), 225 B_TRANSLATE("Cancel"), NULL, NULL, 226 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 227 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 228 alert->Go(); 229 return false; 230 } 231 232 if (entry.GetVolume(&volume) != B_OK || volume.IsReadOnly()) { 233 BAlert* alert = new BAlert("destAlert", 234 B_TRANSLATE("The destination is read only."), 235 B_TRANSLATE("Cancel"), NULL, NULL, B_WIDTH_AS_USUAL, 236 B_EVEN_SPACING, B_WARNING_ALERT); 237 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 238 alert->Go(); 239 return false; 240 } 241 242 entry.GetRef(&fDestRef); 243 return true; 244 } 245 246 247 void 248 ExpanderWindow::MessageReceived(BMessage* message) 249 { 250 switch (message->what) { 251 case MSG_SOURCE: 252 { 253 BEntry entry(fSourceText->Text(), true); 254 entry_ref srcRef; 255 if (entry.Exists() && entry.IsDirectory()) 256 entry.GetRef(&srcRef); 257 if (!fSourcePanel) { 258 BMessenger messenger(this); 259 fSourcePanel = new BFilePanel(B_OPEN_PANEL, &messenger, &srcRef, 260 B_FILE_NODE, false, NULL, new RuleRefFilter(fRules), true); 261 (fSourcePanel->Window())->SetTitle( 262 B_TRANSLATE("Expander: Open")); 263 } else 264 fSourcePanel->SetPanelDirectory(&srcRef); 265 fSourcePanel->Show(); 266 break; 267 } 268 269 case MSG_DEST: 270 { 271 BEntry entry(fDestText->Text(), true); 272 entry_ref destRef; 273 if (entry.Exists() && entry.IsDirectory()) 274 entry.GetRef(&destRef); 275 if (!fDestPanel) { 276 BMessenger messenger(this); 277 fDestPanel = new DirectoryFilePanel(B_OPEN_PANEL, &messenger, 278 &destRef, B_DIRECTORY_NODE, false, NULL, 279 new DirectoryRefFilter(), true); 280 } else 281 fDestPanel->SetPanelDirectory(&destRef); 282 fDestPanel->Show(); 283 break; 284 } 285 286 case MSG_DIRECTORY: 287 { 288 entry_ref ref; 289 fDestPanel->GetPanelDirectory(&ref); 290 fDestRef = ref; 291 BEntry entry(&ref); 292 BPath path(&entry); 293 fDestText->SetText(path.Path()); 294 fDestPanel->Hide(); 295 break; 296 } 297 298 case B_SIMPLE_DATA: 299 case B_REFS_RECEIVED: 300 RefsReceived(message); 301 break; 302 303 case MSG_EXPAND: 304 if (!ValidateDest()) 305 break; 306 if (!fExpandingStarted) { 307 StartExpanding(); 308 break; 309 } 310 // supposed to fall through 311 case MSG_STOP: 312 if (fExpandingStarted) { 313 fExpandingThread->SuspendExternalExpander(); 314 BAlert* alert = new BAlert("stopAlert", 315 B_TRANSLATE("Are you sure you want to stop expanding this " 316 "archive? The expanded items may not be complete."), 317 B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL, 318 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 319 alert->SetShortcut(0, B_ESCAPE); 320 if (alert->Go() == 0) { 321 fExpandingThread->ResumeExternalExpander(); 322 StopExpanding(); 323 } else 324 fExpandingThread->ResumeExternalExpander(); 325 } 326 break; 327 328 case MSG_SHOW: 329 fShowContents->SetValue(fShowContents->Value() == B_CONTROL_OFF 330 ? B_CONTROL_ON : B_CONTROL_OFF); 331 // supposed to fall through 332 case MSG_SHOWCONTENTS: 333 // change menu item label 334 fShowItem->SetLabel(fShowContents->Value() == B_CONTROL_OFF 335 ? B_TRANSLATE("Show contents") : B_TRANSLATE("Hide contents")); 336 337 if (fShowContents->Value() == B_CONTROL_OFF) { 338 if (fListingStarted) 339 StopListing(); 340 341 fScrollView->Hide(); 342 _UpdateWindowSize(false); 343 } else { 344 fScrollView->Show(); 345 StartListing(); 346 } 347 break; 348 349 case MSG_SOURCETEXT: 350 { 351 BEntry entry(fSourceText->Text(), true); 352 if (!entry.Exists()) { 353 BAlert* alert = new BAlert("srcAlert", 354 B_TRANSLATE("The file doesn't exist"), 355 B_TRANSLATE("Cancel"), NULL, NULL, 356 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 357 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 358 alert->Go(); 359 break; 360 } 361 362 entry_ref ref; 363 entry.GetRef(&ref); 364 ExpanderRule* rule = fRules.MatchingRule(&ref); 365 if (rule) { 366 fSourceChanged = true; 367 fSourceRef = ref; 368 fShowContents->SetEnabled(true); 369 fExpandButton->SetEnabled(true); 370 fExpandItem->SetEnabled(true); 371 fShowItem->SetEnabled(true); 372 break; 373 } 374 375 BString string = "The file : "; 376 string += fSourceText->Text(); 377 string += B_TRANSLATE_MARK(" is not supported"); 378 BAlert* alert = new BAlert("srcAlert", string.String(), 379 B_TRANSLATE("Cancel"), 380 NULL, NULL, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_INFO_ALERT); 381 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 382 alert->Go(); 383 384 fShowContents->SetEnabled(false); 385 fExpandButton->SetEnabled(false); 386 fExpandItem->SetEnabled(false); 387 fShowItem->SetEnabled(false); 388 break; 389 } 390 391 case MSG_DESTTEXT: 392 ValidateDest(); 393 break; 394 395 case MSG_PREFERENCES: 396 if (fPreferences == NULL) 397 fPreferences = new ExpanderPreferences(&fSettings); 398 399 fPreferences->Show(); 400 break; 401 402 case 'outp': 403 if (!fExpandingStarted && fListingStarted) { 404 // Check if the vertical scroll bar is at the end 405 float max, pos; 406 fScrollView->ScrollBar(B_VERTICAL)->GetRange(NULL, &max); 407 pos = fScrollView->ScrollBar(B_VERTICAL)->Value(); 408 bool atEnd = (pos == max); 409 410 BString string; 411 int32 i = 0; 412 while (message->FindString("output", i++, &string) == B_OK) { 413 float length = fListingText->StringWidth(string.String()); 414 415 if (length > fLongestLine) 416 fLongestLine = length; 417 418 fListingText->Insert(string.String()); 419 } 420 421 if (atEnd && fScrollView->ScrollBar(B_VERTICAL)->Value() == pos) { 422 fScrollView->ScrollBar(B_VERTICAL)->GetRange(NULL, &max); 423 fScrollView->ScrollBar(B_VERTICAL)->SetValue(max); 424 } 425 } else if (fExpandingStarted) { 426 BString string; 427 int32 i = 0; 428 while (message->FindString("output", i++, &string) == B_OK) { 429 if (strstr(string.String(), "Enter password") != NULL) { 430 fExpandingThread->SuspendExternalExpander(); 431 BString password; 432 PasswordAlert* alert = 433 new PasswordAlert("passwordAlert", string); 434 alert->Go(password); 435 fExpandingThread->ResumeExternalExpander(); 436 fExpandingThread->PushInput(password); 437 } 438 } 439 } 440 break; 441 442 case 'errp': 443 { 444 BString string; 445 if (message->FindString("error", &string) == B_OK 446 && fExpandingStarted) { 447 fExpandingThread->SuspendExternalExpander(); 448 if (strstr(string.String(), "password") != NULL) { 449 BString password; 450 PasswordAlert* alert = new PasswordAlert("passwordAlert", 451 string); 452 alert->Go(password); 453 fExpandingThread->ResumeExternalExpander(); 454 fExpandingThread->PushInput(password); 455 } else { 456 BAlert* alert = new BAlert("stopAlert", string, 457 B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL, 458 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 459 alert->SetShortcut(0, B_ESCAPE); 460 if (alert->Go() == 0) { 461 fExpandingThread->ResumeExternalExpander(); 462 StopExpanding(); 463 } else 464 fExpandingThread->ResumeExternalExpander(); 465 } 466 } 467 break; 468 } 469 470 case 'exit': 471 // thread has finished 472 // (finished, quit, killed, we don't know) 473 // reset window state 474 if (fExpandingStarted) { 475 fStatusView->SetStatus(B_TRANSLATE("File expanded")); 476 StopExpanding(); 477 OpenDestFolder(); 478 CloseWindowOrKeepOpen(); 479 } else if (fListingStarted) { 480 fSourceChanged = false; 481 StopListing(); 482 _ExpandListingText(); 483 } else 484 fStatusView->SetStatus(""); 485 break; 486 487 case 'exrr': 488 // thread has finished 489 // reset window state 490 491 fStatusView->SetStatus(B_TRANSLATE("Error when expanding archive")); 492 CloseWindowOrKeepOpen(); 493 break; 494 495 default: 496 BWindow::MessageReceived(message); 497 } 498 } 499 500 501 bool 502 ExpanderWindow::CanQuit() 503 { 504 if ((fSourcePanel && fSourcePanel->IsShowing()) 505 || (fDestPanel && fDestPanel->IsShowing())) { 506 return false; 507 } 508 509 if (fExpandingStarted) { 510 fExpandingThread->SuspendExternalExpander(); 511 BAlert* alert = new BAlert("stopAlert", 512 B_TRANSLATE("Are you sure you want to stop expanding this " 513 "archive? The expanded items may not be complete."), 514 B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL, 515 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 516 alert->SetShortcut(0, B_ESCAPE); 517 518 if (alert->Go() == 0) { 519 fExpandingThread->ResumeExternalExpander(); 520 StopExpanding(); 521 } else { 522 fExpandingThread->ResumeExternalExpander(); 523 return false; 524 } 525 } 526 527 return true; 528 } 529 530 531 bool 532 ExpanderWindow::QuitRequested() 533 { 534 if (!CanQuit()) 535 return false; 536 537 if (fListingStarted) 538 StopListing(); 539 540 be_app->PostMessage(B_QUIT_REQUESTED); 541 fSettings.ReplacePoint("window_position", Frame().LeftTop()); 542 ((ExpanderApp*)(be_app))->UpdateSettingsFrom(&fSettings); 543 544 return true; 545 } 546 547 548 void 549 ExpanderWindow::RefsReceived(BMessage* message) 550 { 551 entry_ref ref; 552 int32 i = 0; 553 int8 destinationFolder = 0x63; 554 fSettings.FindInt8("destination_folder", &destinationFolder); 555 556 while (message->FindRef("refs", i++, &ref) == B_OK) { 557 BEntry entry(&ref, true); 558 BPath path(&entry); 559 BNode node(&entry); 560 561 if (node.IsFile()) { 562 fSourceChanged = true; 563 fSourceRef = ref; 564 fSourceText->SetText(path.Path()); 565 if (destinationFolder == 0x63) { 566 BPath parent; 567 path.GetParent(&parent); 568 fDestText->SetText(parent.Path()); 569 get_ref_for_path(parent.Path(), &fDestRef); 570 } else if (destinationFolder == 0x65) { 571 fSettings.FindRef("destination_folder_use", &fDestRef); 572 BEntry dEntry(&fDestRef, true); 573 BPath dPath(&dEntry); 574 fDestText->SetText(dPath.Path()); 575 } 576 577 BEntry dEntry(&fDestRef, true); 578 if (dEntry.Exists()) { 579 fExpandButton->SetEnabled(true); 580 fExpandItem->SetEnabled(true); 581 } 582 583 if (fShowContents->Value() == B_CONTROL_ON) { 584 StopListing(); 585 StartListing(); 586 } else { 587 fShowContents->SetEnabled(true); 588 fShowItem->SetEnabled(true); 589 } 590 591 bool fromApp; 592 if (message->FindBool("fromApp", &fromApp) == B_OK) { 593 AutoExpand(); 594 } else 595 AutoListing(); 596 } else if (node.IsDirectory()) { 597 fDestRef = ref; 598 fDestText->SetText(path.Path()); 599 } 600 } 601 } 602 603 604 #undef B_TRANSLATION_CONTEXT 605 #define B_TRANSLATION_CONTEXT "ExpanderMenu" 606 607 void 608 ExpanderWindow::_CreateMenuBar() 609 { 610 fBar = new BMenuBar("menu_bar", B_ITEMS_IN_ROW, B_INVALIDATE_AFTER_LAYOUT); 611 BMenu* menu = new BMenu(B_TRANSLATE("File")); 612 menu->AddItem(fSourceItem 613 = new BMenuItem(B_TRANSLATE("Set source" B_UTF8_ELLIPSIS), 614 new BMessage(MSG_SOURCE), 'O')); 615 menu->AddItem(fDestItem 616 = new BMenuItem(B_TRANSLATE("Set destination" B_UTF8_ELLIPSIS), 617 new BMessage(MSG_DEST), 'D')); 618 menu->AddSeparatorItem(); 619 menu->AddItem(fExpandItem = new BMenuItem(B_TRANSLATE("Expand"), 620 new BMessage(MSG_EXPAND), 'E')); 621 fExpandItem->SetEnabled(false); 622 menu->AddItem(fShowItem = new BMenuItem(B_TRANSLATE("Show contents"), 623 new BMessage(MSG_SHOW), 'L')); 624 fShowItem->SetEnabled(false); 625 menu->AddSeparatorItem(); 626 menu->AddItem(fStopItem = new BMenuItem(B_TRANSLATE("Stop"), 627 new BMessage(MSG_STOP), 'K')); 628 fStopItem->SetEnabled(false); 629 menu->AddSeparatorItem(); 630 menu->AddItem(new BMenuItem(B_TRANSLATE("Close"), 631 new BMessage(B_QUIT_REQUESTED), 'W')); 632 fBar->AddItem(menu); 633 634 menu = new BMenu(B_TRANSLATE("Settings")); 635 menu->AddItem(fPreferencesItem 636 = new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS), 637 new BMessage(MSG_PREFERENCES), 'S')); 638 fBar->AddItem(menu); 639 } 640 641 642 #undef B_TRANSLATION_CONTEXT 643 #define B_TRANSLATION_CONTEXT "ExpanderWindow" 644 645 void 646 ExpanderWindow::StartExpanding() 647 { 648 ExpanderRule* rule = fRules.MatchingRule(&fSourceRef); 649 if (!rule) 650 return; 651 652 BEntry destEntry(fDestText->Text(), true); 653 if (!destEntry.Exists()) { 654 BAlert* alert = new BAlert("destAlert", 655 B_TRANSLATE("The folder was either moved, renamed or not supported."), 656 B_TRANSLATE("Cancel"), NULL, NULL, 657 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 658 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 659 alert->Go(); 660 return; 661 } 662 663 BMessage message; 664 message.AddString("cmd", rule->ExpandCmd()); 665 message.AddRef("srcRef", &fSourceRef); 666 message.AddRef("destRef", &fDestRef); 667 668 fExpandButton->SetLabel(B_TRANSLATE("Stop")); 669 fSourceButton->SetEnabled(false); 670 fDestButton->SetEnabled(false); 671 fShowContents->SetEnabled(false); 672 fSourceItem->SetEnabled(false); 673 fDestItem->SetEnabled(false); 674 fExpandItem->SetEnabled(false); 675 fShowItem->SetEnabled(false); 676 fStopItem->SetEnabled(true); 677 fPreferencesItem->SetEnabled(false); 678 679 BEntry entry(&fSourceRef); 680 BPath path(&entry); 681 BString text(B_TRANSLATE("Expanding '%s'" B_UTF8_ELLIPSIS)); 682 text.ReplaceFirst("%s", path.Leaf()); 683 fStatusView->SetStatus(text.String()); 684 685 fExpandingThread = new ExpanderThread(&message, new BMessenger(this)); 686 fExpandingThread->Start(); 687 688 fExpandingStarted = true; 689 } 690 691 692 void 693 ExpanderWindow::StopExpanding(void) 694 { 695 if (fExpandingThread) { 696 fExpandingThread->InterruptExternalExpander(); 697 fExpandingThread = NULL; 698 } 699 700 fExpandingStarted = false; 701 702 fExpandButton->SetLabel(B_TRANSLATE("Expand")); 703 fSourceButton->SetEnabled(true); 704 fDestButton->SetEnabled(true); 705 fShowContents->SetEnabled(true); 706 fSourceItem->SetEnabled(true); 707 fDestItem->SetEnabled(true); 708 fExpandItem->SetEnabled(true); 709 fShowItem->SetEnabled(true); 710 fStopItem->SetEnabled(false); 711 fPreferencesItem->SetEnabled(true); 712 } 713 714 715 void 716 ExpanderWindow::_ExpandListingText() 717 { 718 float delta = fLongestLine - fListingText->Frame().Width(); 719 720 if (delta > 0) { 721 BScreen screen; 722 BRect screenFrame = screen.Frame(); 723 724 if (Frame().right + delta > screenFrame.right) 725 delta = screenFrame.right - Frame().right - 4.0f; 726 727 ResizeBy(delta, 0.0f); 728 } 729 730 float minWidth, maxWidth, minHeight, maxHeight; 731 GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); 732 733 if (minWidth < Frame().Width() + delta) { 734 // set the Zoom limit as the minimal required size 735 SetZoomLimits(Frame().Width() + delta, 736 std::min(fSizeLimit + fListingText->TextRect().Height() 737 + fLineHeight + B_H_SCROLL_BAR_HEIGHT + 1.0f, 738 maxHeight)); 739 } else { 740 // set the zoom limit based on minimal window size allowed 741 SetZoomLimits(minWidth, 742 std::min(fSizeLimit + fListingText->TextRect().Height() 743 + fLineHeight + B_H_SCROLL_BAR_HEIGHT + 1.0f, 744 maxHeight)); 745 } 746 } 747 748 749 void 750 ExpanderWindow::_UpdateWindowSize(bool showContents) 751 { 752 float minWidth, maxWidth, minHeight, maxHeight; 753 GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); 754 755 float bottom = fSizeLimit; 756 757 if (showContents) { 758 if (fPreviousHeight < 0.0) { 759 BFont font; 760 font_height fontHeight; 761 fListingText->GetFont(&font); 762 font.GetHeight(&fontHeight); 763 fLineHeight = ceilf(fontHeight.ascent + fontHeight.descent 764 + fontHeight.leading); 765 fPreviousHeight = bottom + 10.0 * fLineHeight; 766 } 767 minHeight = bottom + 5.0 * fLineHeight; 768 maxHeight = 32767.0; 769 770 bottom = std::max(fPreviousHeight, minHeight); 771 } else { 772 minHeight = fSizeLimit; 773 maxHeight = fSizeLimit; 774 fPreviousHeight = Frame().Height(); 775 } 776 777 SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight); 778 ResizeTo(Frame().Width(), bottom); 779 } 780 781 782 void 783 ExpanderWindow::StartListing() 784 { 785 _UpdateWindowSize(true); 786 787 if (!fSourceChanged) 788 return; 789 790 fPreviousHeight = -1.0; 791 792 fLongestLine = 0.0f; 793 794 ExpanderRule* rule = fRules.MatchingRule(&fSourceRef); 795 if (!rule) 796 return; 797 798 BMessage message; 799 message.AddString("cmd", rule->ListingCmd()); 800 message.AddRef("srcRef", &fSourceRef); 801 802 fShowContents->SetEnabled(true); 803 fSourceItem->SetEnabled(false); 804 fDestItem->SetEnabled(false); 805 fExpandItem->SetEnabled(false); 806 fShowItem->SetEnabled(true); 807 fShowItem->SetLabel(B_TRANSLATE("Hide contents")); 808 fStopItem->SetEnabled(false); 809 fPreferencesItem->SetEnabled(false); 810 811 fSourceButton->SetEnabled(false); 812 fDestButton->SetEnabled(false); 813 fExpandButton->SetEnabled(false); 814 815 BEntry entry(&fSourceRef); 816 BPath path(&entry); 817 BString text(B_TRANSLATE("Creating listing for '%s'" B_UTF8_ELLIPSIS)); 818 text.ReplaceFirst("%s", path.Leaf()); 819 fStatusView->SetStatus(text.String()); 820 fListingText->SetText(""); 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 fShowContents->SetEnabled(true); 840 fSourceItem->SetEnabled(true); 841 fDestItem->SetEnabled(true); 842 fExpandItem->SetEnabled(true); 843 fShowItem->SetEnabled(true); 844 fStopItem->SetEnabled(false); 845 fPreferencesItem->SetEnabled(true); 846 847 fSourceButton->SetEnabled(true); 848 fDestButton->SetEnabled(true); 849 fExpandButton->SetEnabled(true); 850 fStatusView->SetStatus(""); 851 } 852 853 854 void 855 ExpanderWindow::CloseWindowOrKeepOpen() 856 { 857 bool expandFiles = false; 858 fSettings.FindBool("automatically_expand_files", &expandFiles); 859 860 bool closeWhenDone = false; 861 fSettings.FindBool("close_when_done", &closeWhenDone); 862 863 if (expandFiles || closeWhenDone) 864 PostMessage(B_QUIT_REQUESTED); 865 } 866 867 868 void 869 ExpanderWindow::OpenDestFolder() 870 { 871 bool openFolder = true; 872 fSettings.FindBool("open_destination_folder", &openFolder); 873 874 if (!openFolder) 875 return; 876 877 BMessage* message = new BMessage(B_REFS_RECEIVED); 878 message->AddRef("refs", &fDestRef); 879 BPath path(&fDestRef); 880 BMessenger tracker("application/x-vnd.Be-TRAK"); 881 tracker.SendMessage(message); 882 } 883 884 885 void 886 ExpanderWindow::AutoListing() 887 { 888 bool showContents = false; 889 fSettings.FindBool("show_contents_listing", &showContents); 890 891 if (!showContents) 892 return; 893 894 fShowContents->SetValue(B_CONTROL_ON); 895 fShowContents->Invoke(); 896 } 897 898 899 void 900 ExpanderWindow::AutoExpand() 901 { 902 bool expandFiles = false; 903 fSettings.FindBool("automatically_expand_files", &expandFiles); 904 905 if (!expandFiles) { 906 AutoListing(); 907 return; 908 } 909 910 fExpandButton->Invoke(); 911 } 912