1 /*****************************************************************************/ 2 // Expander 3 // Written by Jérôme Duval 4 // 5 // ExpanderWindow.cpp 6 // 7 // Copyright (c) 2004 OpenBeOS Project 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining a 10 // copy of this software and associated documentation files (the "Software"), 11 // to deal in the Software without restriction, including without limitation 12 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 // and/or sell copies of the Software, and to permit persons to whom the 14 // Software is furnished to do so, subject to the following conditions: 15 // 16 // The above copyright notice and this permission notice shall be included 17 // in all copies or substantial portions of the Software. 18 // 19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 // DEALINGS IN THE SOFTWARE. 26 /*****************************************************************************/ 27 28 #include <Application.h> 29 #include <Box.h> 30 #include <Button.h> 31 #include <Entry.h> 32 #include <File.h> 33 #include <Menu.h> 34 #include <MenuBar.h> 35 #include <MenuItem.h> 36 #include <Path.h> 37 #include <Screen.h> 38 #include <Alert.h> 39 #include <SupportDefs.h> 40 41 #include "ExpanderApp.h" 42 #include "ExpanderWindow.h" 43 #include "ExpanderThread.h" 44 #include "ExpanderPreferences.h" 45 46 const uint32 MSG_SOURCE = 'mSOU'; 47 const uint32 MSG_DEST = 'mDES'; 48 const uint32 MSG_EXPAND = 'mEXP'; 49 const uint32 MSG_SHOW = 'mSHO'; 50 const uint32 MSG_STOP = 'mSTO'; 51 const uint32 MSG_CLOSE = 'mCLO'; 52 const uint32 MSG_PREFERENCES = 'mPRE'; 53 const uint32 MSG_SOURCETEXT = 'mSTX'; 54 const uint32 MSG_DESTTEXT = 'mDTX'; 55 const uint32 MSG_SHOWCONTENTS = 'mSCT'; 56 57 ExpanderWindow::ExpanderWindow(BRect frame_rect, const entry_ref *ref, BMessage *settings) 58 : BWindow(frame_rect, "Expand-O-Matic", B_TITLED_WINDOW, B_NOT_ZOOMABLE), 59 fSourceChanged(true), 60 fListingThread(NULL), 61 fListingStarted(false), 62 fExpandingThread(NULL), 63 fExpandingStarted(false), 64 fSettings(*settings), 65 fPreferences(NULL) 66 { 67 fSourcePanel = NULL; 68 fDestPanel = NULL; 69 70 // create menu bar 71 fBar = new BMenuBar(BRect(0, 0, Bounds().right, 20), "menu_bar"); 72 BMenu *menu = new BMenu("File"); 73 BMenuItem *item; 74 menu->AddItem(item = new BMenuItem("About Expander", new BMessage(B_ABOUT_REQUESTED))); 75 item->SetTarget(be_app_messenger); 76 menu->AddSeparatorItem(); 77 menu->AddItem(fSourceItem = new BMenuItem("Set Source...", new BMessage(MSG_SOURCE), 'O')); 78 menu->AddItem(fDestItem = new BMenuItem("Set Destination...", new BMessage(MSG_DEST), 'D')); 79 menu->AddSeparatorItem(); 80 menu->AddItem(fExpandItem = new BMenuItem("Expand", new BMessage(MSG_EXPAND), 'E')); 81 fExpandItem->SetEnabled(false); 82 menu->AddItem(fShowItem = new BMenuItem("Show Contents", new BMessage(MSG_SHOW), 'L')); 83 fShowItem->SetEnabled(false); 84 menu->AddSeparatorItem(); 85 menu->AddItem(fStopItem = new BMenuItem("Stop", new BMessage(MSG_STOP), 'K')); 86 fStopItem->SetEnabled(false); 87 menu->AddSeparatorItem(); 88 menu->AddItem(new BMenuItem("Close", new BMessage(MSG_CLOSE), 'W')); 89 fBar->AddItem(menu); 90 91 menu = new BMenu("Edit"); 92 menu->AddItem(fPreferencesItem = new BMenuItem("Preferences...", new BMessage(MSG_PREFERENCES), 'P')); 93 fBar->AddItem(menu); 94 AddChild(fBar); 95 96 BRect rect = Bounds(); 97 rect.top += fBar->Bounds().Height() + 1; 98 BBox *box = new BBox(rect, "background", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER); 99 AddChild(box); 100 101 float size = 8 + be_plain_font->StringWidth("Destination")/2; 102 rect = BRect(42 - size, 10, 42 + size, 25); 103 fSourceButton = new BButton(rect, "sourceButton", "Source", 104 new BMessage(MSG_SOURCE), B_FOLLOW_LEFT | B_FOLLOW_TOP); 105 box->AddChild(fSourceButton); 106 rect.OffsetBy(0, 28); 107 fDestButton = new BButton(rect, "destButton", "Destination", 108 new BMessage(MSG_DEST), B_FOLLOW_LEFT | B_FOLLOW_TOP); 109 box->AddChild(fDestButton); 110 rect.OffsetBy(0, 28); 111 fExpandButton = new BButton(rect, "expandButton", "Expand", 112 new BMessage(MSG_EXPAND), B_FOLLOW_LEFT | B_FOLLOW_TOP); 113 box->AddChild(fExpandButton); 114 fExpandButton->SetEnabled(false); 115 116 rect = BRect(80, 12, Bounds().right - 10, 25); 117 fSourceText = new BTextControl(rect, "sourceText", "", NULL, 118 new BMessage(MSG_SOURCETEXT), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); 119 fSourceText->SetDivider(0); 120 box->AddChild(fSourceText); 121 122 rect.OffsetBy(0, 28); 123 fDestText = new BTextControl(rect, "destText", "", NULL, 124 new BMessage(MSG_DESTTEXT), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); 125 fDestText->SetDivider(0); 126 box->AddChild(fDestText); 127 128 BRect frameRect = rect.OffsetByCopy(0, 27); 129 frameRect.left += 4; 130 frameRect.right = frameRect.left + 250; 131 BRect textRect(frameRect); 132 textRect.OffsetTo(B_ORIGIN); 133 textRect.InsetBy(1,1); 134 fExpandedText = new BTextView(frameRect, "expandedText", textRect, 135 be_plain_font, NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); 136 fExpandedText->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 137 fExpandedText->MakeEditable(false); 138 fExpandedText->MakeSelectable(false); 139 box->AddChild(fExpandedText); 140 fExpandedText->SetText(""); 141 142 rect = BRect(Bounds().right - 38 - be_plain_font->StringWidth("Show Contents"), rect.bottom + 13, Bounds().right - 10, rect.bottom + 28); 143 fShowContents = new BCheckBox(rect, "showContents", "Show Contents", 144 new BMessage(MSG_SHOWCONTENTS), B_FOLLOW_RIGHT | B_FOLLOW_TOP); 145 box->AddChild(fShowContents); 146 fShowContents->SetEnabled(false); 147 148 frameRect = Bounds(); 149 frameRect.InsetBy(10, 0); 150 frameRect.top += frameRect.Height() - 21; 151 frameRect.bottom = frameRect.top + 100; 152 frameRect.right -= B_V_SCROLL_BAR_WIDTH; 153 154 textRect = frameRect; 155 textRect.OffsetTo(B_ORIGIN); 156 textRect.InsetBy(1,1); 157 fListingText = new BTextView(frameRect, "listingText", textRect, 158 be_fixed_font, NULL, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS); 159 fListingText->SetText(""); 160 fListingText->MakeEditable(false); 161 fListingScroll = new BScrollView("listingScroll", fListingText, 162 B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true); 163 box->AddChild(fListingScroll); 164 fListingScroll->Hide(); 165 166 SetSizeLimits(450, BScreen().Frame().Width(), 120, 120); 167 168 // finish creating window 169 Show(); 170 } 171 172 ExpanderWindow::~ExpanderWindow() 173 { 174 } 175 176 void 177 ExpanderWindow::FrameResized(float width, float height) 178 { 179 if (fListingText->DoesWordWrap()) { 180 BRect textRect; 181 textRect = fListingText->Bounds(); 182 textRect.OffsetTo(B_ORIGIN); 183 textRect.InsetBy(1,1); 184 fListingText->SetTextRect(textRect); 185 } 186 } 187 188 void 189 ExpanderWindow::MessageReceived(BMessage *msg) 190 { 191 switch (msg->what) { 192 case MSG_SOURCE: 193 if (!fSourcePanel) 194 fSourcePanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, 195 B_FILE_NODE, false, NULL, new RuleRefFilter(fRules), true); 196 fSourcePanel->Show(); 197 break; 198 case MSG_DEST: 199 if (!fDestPanel) 200 fDestPanel = new DirectoryFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, 201 B_DIRECTORY_NODE, false, NULL, new DirectoryRefFilter(), true); 202 fDestPanel->Show(); 203 break; 204 case MSG_DIRECTORY: 205 { 206 entry_ref ref; 207 fDestPanel->GetPanelDirectory(&ref); 208 fDestRef = ref; 209 BEntry entry(&ref); 210 BPath path(&entry); 211 fDestText->SetText(path.Path()); 212 fDestPanel->Hide(); 213 } 214 break; 215 case B_SIMPLE_DATA: 216 case B_REFS_RECEIVED: 217 { 218 RefsReceived(msg); 219 break; 220 } 221 case MSG_CLOSE: 222 PostMessage(B_QUIT_REQUESTED); 223 break; 224 case MSG_EXPAND: 225 if (!fExpandingStarted) { 226 StartExpanding(); 227 break; 228 } 229 case MSG_STOP: 230 if (fExpandingStarted) { 231 fExpandingThread->SuspendExternalExpander(); 232 BAlert *alert = new BAlert("stopAlert", "Are you sure you want to stop expanding this\n" 233 "archive? The expanded items may not be complete.", "Stop", "Continue", NULL, 234 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 235 if (alert->Go()==0) { 236 fExpandingThread->ResumeExternalExpander(); 237 StopExpanding(); 238 } else 239 fExpandingThread->ResumeExternalExpander(); 240 } 241 break; 242 case MSG_SHOW: 243 fShowContents->SetValue(fShowContents->Value() == B_CONTROL_OFF ? B_CONTROL_ON : B_CONTROL_OFF); 244 fShowItem->SetLabel(fShowContents->Value() == B_CONTROL_OFF ? "Show Contents" : "Hide Contents"); 245 case MSG_SHOWCONTENTS: 246 if (fShowContents->Value() == B_CONTROL_OFF) { 247 if (fListingStarted) 248 StopListing(); 249 SetSizeLimits(450, BScreen().Frame().Width(), 120, 120); 250 ResizeTo(Frame().Width(), 120); 251 fShowItem->SetLabel("Show Contents"); 252 } else 253 StartListing(); 254 break; 255 case MSG_SOURCETEXT: 256 { 257 BEntry entry(fSourceText->Text(), true); 258 if (!entry.Exists()) { 259 BAlert *alert = new BAlert("srcAlert", "The file doesn't exist", 260 "Cancel", NULL, NULL, 261 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 262 alert->Go(); 263 break; 264 } 265 266 entry_ref ref; 267 entry.GetRef(&ref); 268 ExpanderRule *rule = fRules.MatchingRule(&ref); 269 if (rule) { 270 fSourceChanged = true; 271 fSourceRef = ref; 272 fShowContents->SetEnabled(true); 273 fExpandButton->SetEnabled(true); 274 fExpandItem->SetEnabled(true); 275 fShowItem->SetEnabled(true); 276 break; 277 } 278 279 BString string = "The file : "; 280 string += fSourceText->Text(); 281 string += " is not supported"; 282 BAlert *alert = new BAlert("srcAlert", string.String(), 283 "Cancel", NULL, NULL, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_INFO_ALERT); 284 alert->Go(); 285 286 fShowContents->SetEnabled(false); 287 fExpandButton->SetEnabled(false); 288 fExpandItem->SetEnabled(false); 289 fShowItem->SetEnabled(false); 290 } 291 break; 292 case MSG_DESTTEXT: 293 { 294 BEntry entry(fDestText->Text(), true); 295 if (!entry.Exists()) { 296 BAlert *alert = new BAlert("destAlert", "The directory was either moved, renamed or not\n" 297 "supported.", 298 "Cancel", NULL, NULL, 299 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 300 alert->Go(); 301 break; 302 } 303 entry.GetRef(&fDestRef); 304 } 305 break; 306 case MSG_PREFERENCES: 307 if (!fPreferences) 308 fPreferences = new ExpanderPreferences(&fSettings); 309 fPreferences->Show(); 310 break; 311 case 'outp': 312 if (!fExpandingStarted && fListingStarted) { 313 BString string; 314 int32 i=0; 315 while (msg->FindString("output", i++, &string)==B_OK) 316 fListingText->Insert(string.String()); 317 fListingText->ScrollToSelection(); 318 } 319 320 break; 321 case 'exit': // thread has finished (finished, quit, killed, we don't know) 322 // reset window state 323 if (fExpandingStarted) { 324 fExpandedText->SetText("File expanded"); 325 StopExpanding(); 326 OpenDestFolder(); 327 CloseWindowOrKeepOpen(); 328 } else if (fListingStarted){ 329 fSourceChanged = false; 330 StopListing(); 331 } else 332 fExpandedText->SetText(""); 333 break; 334 case 'exrr': // thread has finished 335 // reset window state 336 337 fExpandedText->SetText("Error when expanding archive"); 338 CloseWindowOrKeepOpen(); 339 break; 340 default: 341 BWindow::MessageReceived(msg); 342 break; 343 } 344 } 345 346 bool 347 ExpanderWindow::CanQuit() 348 { 349 if ((fSourcePanel && fSourcePanel->IsShowing()) 350 || (fDestPanel && fDestPanel->IsShowing())) 351 return false; 352 353 if (fExpandingStarted) { 354 fExpandingThread->SuspendExternalExpander(); 355 BAlert *alert = new BAlert("stopAlert", "Are you sure you want to stop expanding this\n" 356 "archive? The expanded items may not be complete.", "Stop", "Continue", NULL, 357 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 358 if (alert->Go()==0) { 359 fExpandingThread->ResumeExternalExpander(); 360 StopExpanding(); 361 } else { 362 fExpandingThread->ResumeExternalExpander(); 363 return false; 364 } 365 } 366 return true; 367 } 368 369 bool 370 ExpanderWindow::QuitRequested() 371 { 372 if (!CanQuit()) 373 return false; 374 375 if (fListingStarted) { 376 StopListing(); 377 } 378 379 be_app->PostMessage(B_QUIT_REQUESTED); 380 fSettings.ReplacePoint("window_position", Frame().LeftTop()); 381 ((ExpanderApp*)(be_app))->UpdateSettingsFrom(&fSettings); 382 return true; 383 } 384 385 void 386 ExpanderWindow::RefsReceived(BMessage *msg) 387 { 388 entry_ref ref; 389 int32 i = 0; 390 int8 destination_folder = 0x63; 391 fSettings.FindInt8("destination_folder", &destination_folder); 392 393 while (msg->FindRef("refs", i++, &ref) == B_OK) { 394 395 BEntry entry(&ref, true); 396 BPath path(&entry); 397 BNode node(&entry); 398 399 if (node.IsFile()) { 400 fSourceChanged = true; 401 fSourceRef = ref; 402 fSourceText->SetText(path.Path()); 403 if (destination_folder==0x63) { 404 BPath parent; 405 path.GetParent(&parent); 406 fDestText->SetText(parent.Path()); 407 get_ref_for_path(parent.Path(), &fDestRef); 408 } else if (destination_folder==0x65) { 409 fSettings.FindRef("destination_folder_use", &fDestRef); 410 BEntry dEntry(&fDestRef, true); 411 BPath dPath(&dEntry); 412 fDestText->SetText(dPath.Path()); 413 } 414 415 BEntry dEntry(&fDestRef, true); 416 if (dEntry.Exists()) { 417 fExpandButton->SetEnabled(true); 418 fExpandItem->SetEnabled(true); 419 } 420 421 if (fShowContents->Value() == B_CONTROL_ON) { 422 StopListing(); 423 StartListing(); 424 } else { 425 fShowContents->SetEnabled(true); 426 fShowItem->SetEnabled(true); 427 } 428 429 bool fromApp; 430 if (msg->FindBool("fromApp", &fromApp)==B_OK) { 431 AutoExpand(); 432 } else 433 AutoListing(); 434 } else if(node.IsDirectory()) { 435 fDestRef = ref; 436 fDestText->SetText(path.Path()); 437 } 438 } 439 } 440 441 void 442 ExpanderWindow::StartExpanding() 443 { 444 BMessage message; 445 446 ExpanderRule *rule = fRules.MatchingRule(&fSourceRef); 447 if (!rule) { 448 return; 449 } 450 451 BEntry destEntry(fDestText->Text(), true); 452 if (!destEntry.Exists()) { 453 BAlert *alert = new BAlert("destAlert", "The directory was either moved, renamed or not\n" 454 "supported.", 455 "Cancel", NULL, NULL, 456 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 457 alert->Go(); 458 return; 459 } 460 461 message.AddString("cmd", rule->ExpandCmd()); 462 message.AddRef("srcRef", &fSourceRef); 463 message.AddRef("destRef", &fDestRef); 464 465 fExpandButton->SetLabel("Stop"); 466 fSourceButton->SetEnabled(false); 467 fDestButton->SetEnabled(false); 468 fShowContents->SetEnabled(false); 469 fSourceItem->SetEnabled(false); 470 fDestItem->SetEnabled(false); 471 fExpandItem->SetEnabled(false); 472 fShowItem->SetEnabled(false); 473 fStopItem->SetEnabled(true); 474 fPreferencesItem->SetEnabled(false); 475 476 BEntry entry(&fSourceRef); 477 BPath path(&entry); 478 BString text("Expanding file "); 479 text.Append(path.Leaf()); 480 fExpandedText->SetText(text.String()); 481 482 fExpandingThread = new ExpanderThread(&message, new BMessenger(this)); 483 fExpandingThread->Start(); 484 485 fExpandingStarted = true; 486 } 487 488 void 489 ExpanderWindow::StopExpanding(void) 490 { 491 if (fExpandingThread) { 492 fExpandingThread->InterruptExternalExpander(); 493 fExpandingThread = NULL; 494 } 495 496 fExpandingStarted = false; 497 498 fExpandButton->SetLabel("Expand"); 499 fSourceButton->SetEnabled(true); 500 fDestButton->SetEnabled(true); 501 fShowContents->SetEnabled(true); 502 fSourceItem->SetEnabled(true); 503 fDestItem->SetEnabled(true); 504 fExpandItem->SetEnabled(true); 505 fShowItem->SetEnabled(true); 506 fStopItem->SetEnabled(false); 507 fPreferencesItem->SetEnabled(true); 508 } 509 510 void 511 ExpanderWindow::StartListing() 512 { 513 SetSizeLimits(450, BScreen().Frame().Width(), 335, BScreen().Frame().Height()); 514 ResizeTo(Frame().Width(), 335); 515 fListingScroll->ResizeTo(fListingScroll->Bounds().Width(), 210); 516 if (fListingScroll->IsHidden()) 517 fListingScroll->Show(); 518 519 if (!fSourceChanged) 520 return; 521 522 BMessage message; 523 524 ExpanderRule *rule = fRules.MatchingRule(&fSourceRef); 525 if (!rule) { 526 return; 527 } 528 message.AddString("cmd", rule->ListingCmd()); 529 message.AddRef("srcRef", &fSourceRef); 530 531 fShowContents->SetEnabled(true); 532 fSourceItem->SetEnabled(false); 533 fDestItem->SetEnabled(false); 534 fExpandItem->SetEnabled(false); 535 fShowItem->SetEnabled(true); 536 fShowItem->SetLabel("Hide Contents"); 537 fStopItem->SetEnabled(false); 538 fPreferencesItem->SetEnabled(false); 539 540 fSourceButton->SetEnabled(false); 541 fDestButton->SetEnabled(false); 542 fExpandButton->SetEnabled(false); 543 544 BEntry entry(&fSourceRef); 545 BPath path(&entry); 546 BString text("Creating listing for "); 547 text.Append(path.Leaf()); 548 fExpandedText->SetText(text.String()); 549 fListingText->SetText(""); 550 551 fListingThread = new ExpanderThread(&message, new BMessenger(this)); 552 fListingThread->Start(); 553 554 fListingStarted = true; 555 } 556 557 void 558 ExpanderWindow::StopListing(void) 559 { 560 if (fListingThread) { 561 fListingThread->InterruptExternalExpander(); 562 fListingThread = NULL; 563 } 564 565 fListingStarted = false; 566 567 fShowContents->SetEnabled(true); 568 fSourceItem->SetEnabled(true); 569 fDestItem->SetEnabled(true); 570 fExpandItem->SetEnabled(true); 571 fShowItem->SetEnabled(true); 572 fStopItem->SetEnabled(false); 573 fPreferencesItem->SetEnabled(true); 574 575 fSourceButton->SetEnabled(true); 576 fDestButton->SetEnabled(true); 577 fExpandButton->SetEnabled(true); 578 fExpandedText->SetText(""); 579 } 580 581 void 582 ExpanderWindow::CloseWindowOrKeepOpen() 583 { 584 bool automatically_expand_files = false; 585 fSettings.FindBool("automatically_expand_files", &automatically_expand_files); 586 bool close_when_done = false; 587 fSettings.FindBool("close_when_done", &close_when_done); 588 if (automatically_expand_files || close_when_done) 589 PostMessage(B_QUIT_REQUESTED); 590 } 591 592 void 593 ExpanderWindow::OpenDestFolder() 594 { 595 bool open_destination_folder = true; 596 fSettings.FindBool("open_destination_folder", &open_destination_folder); 597 598 if (!open_destination_folder) 599 return; 600 601 BMessage * message = new BMessage(B_REFS_RECEIVED); 602 message->AddRef("refs", &fDestRef); 603 BPath path(&fDestRef); 604 BMessenger tracker( "application/x-vnd.Be-TRAK" ); 605 tracker.SendMessage( message ); 606 } 607 608 void 609 ExpanderWindow::AutoListing() 610 { 611 bool show_contents_listing = false; 612 fSettings.FindBool("show_contents_listing", &show_contents_listing); 613 614 if (!show_contents_listing) 615 return; 616 617 fShowContents->SetValue(B_CONTROL_ON); 618 fShowContents->Invoke(); 619 } 620 621 void 622 ExpanderWindow::AutoExpand() 623 { 624 bool automatically_expand_files = false; 625 fSettings.FindBool("automatically_expand_files", &automatically_expand_files); 626 627 if (!automatically_expand_files) { 628 AutoListing(); 629 return; 630 } 631 632 fExpandButton->Invoke(); 633 } 634