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 rect = BRect(10, 10, 75, 25); 102 fSourceButton = new BButton(rect, "sourceButton", "Source", 103 new BMessage(MSG_SOURCE), B_FOLLOW_LEFT | B_FOLLOW_TOP); 104 box->AddChild(fSourceButton); 105 rect.OffsetBy(0, 28); 106 fDestButton = new BButton(rect, "destButton", "Destination", 107 new BMessage(MSG_DEST), B_FOLLOW_LEFT | B_FOLLOW_TOP); 108 box->AddChild(fDestButton); 109 rect.OffsetBy(0, 28); 110 fExpandButton = new BButton(rect, "expandButton", "Expand", 111 new BMessage(MSG_EXPAND), B_FOLLOW_LEFT | B_FOLLOW_TOP); 112 box->AddChild(fExpandButton); 113 fExpandButton->SetEnabled(false); 114 115 rect = BRect(80, 12, Bounds().right - 10, 25); 116 fSourceText = new BTextControl(rect, "sourceText", "", NULL, 117 new BMessage(MSG_SOURCETEXT), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); 118 fSourceText->SetDivider(0); 119 box->AddChild(fSourceText); 120 121 rect.OffsetBy(0, 28); 122 fDestText = new BTextControl(rect, "destText", "", NULL, 123 new BMessage(MSG_DESTTEXT), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); 124 fDestText->SetDivider(0); 125 box->AddChild(fDestText); 126 127 BRect frameRect = rect.OffsetByCopy(0, 27); 128 frameRect.left += 4; 129 frameRect.right = frameRect.left + 250; 130 BRect textRect(frameRect); 131 textRect.OffsetTo(B_ORIGIN); 132 textRect.InsetBy(1,1); 133 fExpandedText = new BTextView(frameRect, "expandedText", textRect, 134 be_plain_font, NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); 135 fExpandedText->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 136 fExpandedText->MakeEditable(false); 137 fExpandedText->MakeSelectable(false); 138 box->AddChild(fExpandedText); 139 fExpandedText->SetText(""); 140 141 rect = BRect(Bounds().right - 105, rect.bottom + 13, Bounds().right - 10, rect.bottom + 28); 142 fShowContents = new BCheckBox(rect, "showContents", "Show Contents", 143 new BMessage(MSG_SHOWCONTENTS), B_FOLLOW_RIGHT | B_FOLLOW_TOP); 144 box->AddChild(fShowContents); 145 fShowContents->SetEnabled(false); 146 147 frameRect = Bounds(); 148 frameRect.InsetBy(10, 0); 149 frameRect.top += frameRect.Height() - 21; 150 frameRect.bottom = frameRect.top + 100; 151 frameRect.right -= B_V_SCROLL_BAR_WIDTH; 152 153 textRect = frameRect; 154 textRect.OffsetTo(B_ORIGIN); 155 textRect.InsetBy(1,1); 156 fListingText = new BTextView(frameRect, "listingText", textRect, 157 be_fixed_font, NULL, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS); 158 fListingText->SetText(""); 159 fListingText->MakeEditable(false); 160 fListingScroll = new BScrollView("listingScroll", fListingText, 161 B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true); 162 box->AddChild(fListingScroll); 163 fListingScroll->Hide(); 164 165 SetSizeLimits(450, BScreen().Frame().Width(), 120, 120); 166 167 // finish creating window 168 Show(); 169 } 170 171 ExpanderWindow::~ExpanderWindow() 172 { 173 } 174 175 void 176 ExpanderWindow::FrameResized(float width, float height) 177 { 178 if (fListingText->DoesWordWrap()) { 179 BRect textRect; 180 textRect = fListingText->Bounds(); 181 textRect.OffsetTo(B_ORIGIN); 182 textRect.InsetBy(1,1); 183 fListingText->SetTextRect(textRect); 184 } 185 } 186 187 void 188 ExpanderWindow::MessageReceived(BMessage *msg) 189 { 190 switch (msg->what) { 191 case MSG_SOURCE: 192 if (!fSourcePanel) 193 fSourcePanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, 194 B_FILE_NODE, false, NULL, new RuleRefFilter(fRules), true); 195 fSourcePanel->Show(); 196 break; 197 case MSG_DEST: 198 if (!fDestPanel) 199 fDestPanel = new DirectoryFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, 200 B_DIRECTORY_NODE, false, NULL, new DirectoryRefFilter(), true); 201 fDestPanel->Show(); 202 break; 203 case MSG_DIRECTORY: 204 { 205 entry_ref ref; 206 fDestPanel->GetPanelDirectory(&ref); 207 fDestRef = ref; 208 BEntry entry(&ref); 209 BPath path(&entry); 210 fDestText->SetText(path.Path()); 211 fDestPanel->Hide(); 212 } 213 break; 214 case B_SIMPLE_DATA: 215 case B_REFS_RECEIVED: 216 { 217 RefsReceived(msg); 218 break; 219 } 220 case MSG_CLOSE: 221 PostMessage(B_QUIT_REQUESTED); 222 break; 223 case MSG_EXPAND: 224 if (!fExpandingStarted) { 225 StartExpanding(); 226 break; 227 } 228 case MSG_STOP: 229 if (fExpandingStarted) { 230 fExpandingThread->SuspendExternalExpander(); 231 BAlert *alert = new BAlert("stopAlert", "Are you sure you want to stop expanding this\n" 232 "archive? The expanded items may not be complete.", "Stop", "Continue", NULL, 233 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 234 if (alert->Go()==0) { 235 fExpandingThread->ResumeExternalExpander(); 236 StopExpanding(); 237 } else 238 fExpandingThread->ResumeExternalExpander(); 239 } 240 break; 241 case MSG_SHOW: 242 fShowContents->SetValue(fShowContents->Value() == B_CONTROL_OFF ? B_CONTROL_ON : B_CONTROL_OFF); 243 fShowItem->SetLabel(fShowContents->Value() == B_CONTROL_OFF ? "Show Contents" : "Hide Contents"); 244 case MSG_SHOWCONTENTS: 245 if (fShowContents->Value() == B_CONTROL_OFF) { 246 if (fListingStarted) 247 StopListing(); 248 SetSizeLimits(450, BScreen().Frame().Width(), 120, 120); 249 ResizeTo(Frame().Width(), 120); 250 fShowItem->SetLabel("Show Contents"); 251 } else 252 StartListing(); 253 break; 254 case MSG_SOURCETEXT: 255 { 256 BEntry entry(fSourceText->Text(), true); 257 if (!entry.Exists()) { 258 BAlert *alert = new BAlert("srcAlert", "The file doesn't exist", 259 "Cancel", NULL, NULL, 260 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 261 alert->Go(); 262 break; 263 } 264 265 entry_ref ref; 266 entry.GetRef(&ref); 267 ExpanderRule *rule = fRules.MatchingRule(&ref); 268 if (rule) { 269 fSourceChanged = true; 270 fSourceRef = ref; 271 fShowContents->SetEnabled(true); 272 fExpandButton->SetEnabled(true); 273 fExpandItem->SetEnabled(true); 274 fShowItem->SetEnabled(true); 275 break; 276 } 277 278 BString string = "The file : "; 279 string += fSourceText->Text(); 280 string += " is not supported"; 281 BAlert *alert = new BAlert("srcAlert", string.String(), 282 "Cancel", NULL, NULL, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_INFO_ALERT); 283 alert->Go(); 284 285 fShowContents->SetEnabled(false); 286 fExpandButton->SetEnabled(false); 287 fExpandItem->SetEnabled(false); 288 fShowItem->SetEnabled(false); 289 } 290 break; 291 case MSG_DESTTEXT: 292 { 293 BEntry entry(fDestText->Text(), true); 294 if (!entry.Exists()) { 295 BAlert *alert = new BAlert("destAlert", "The directory was either moved, renamed or not\n" 296 "supported.", 297 "Cancel", NULL, NULL, 298 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 299 alert->Go(); 300 break; 301 } 302 entry.GetRef(&fDestRef); 303 } 304 break; 305 case MSG_PREFERENCES: 306 if (!fPreferences) 307 fPreferences = new ExpanderPreferences(&fSettings); 308 fPreferences->Show(); 309 break; 310 case 'outp': 311 if (!fExpandingStarted && fListingStarted) { 312 BString string; 313 int32 i=0; 314 while (msg->FindString("output", i++, &string)==B_OK) 315 fListingText->Insert(string.String()); 316 fListingText->ScrollToSelection(); 317 } 318 319 break; 320 case 'exit': // thread has finished (finished, quit, killed, we don't know) 321 // reset window state 322 if (fExpandingStarted) { 323 fExpandedText->SetText("File expanded"); 324 StopExpanding(); 325 OpenDestFolder(); 326 CloseWindowOrKeepOpen(); 327 } else if (fListingStarted){ 328 fSourceChanged = false; 329 StopListing(); 330 } else 331 fExpandedText->SetText(""); 332 break; 333 case 'exrr': // thread has finished 334 // reset window state 335 336 fExpandedText->SetText("Error when expanding archive"); 337 CloseWindowOrKeepOpen(); 338 break; 339 default: 340 BWindow::MessageReceived(msg); 341 break; 342 } 343 } 344 345 bool 346 ExpanderWindow::CanQuit() 347 { 348 if ((fSourcePanel && fSourcePanel->IsShowing()) 349 || (fDestPanel && fDestPanel->IsShowing())) 350 return false; 351 352 if (fExpandingStarted) { 353 fExpandingThread->SuspendExternalExpander(); 354 BAlert *alert = new BAlert("stopAlert", "Are you sure you want to stop expanding this\n" 355 "archive? The expanded items may not be complete.", "Stop", "Continue", NULL, 356 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 357 if (alert->Go()==0) { 358 fExpandingThread->ResumeExternalExpander(); 359 StopExpanding(); 360 } else { 361 fExpandingThread->ResumeExternalExpander(); 362 return false; 363 } 364 } 365 return true; 366 } 367 368 bool 369 ExpanderWindow::QuitRequested() 370 { 371 if (!CanQuit()) 372 return false; 373 374 if (fListingStarted) { 375 StopListing(); 376 } 377 378 be_app->PostMessage(B_QUIT_REQUESTED); 379 fSettings.ReplacePoint("window_position", Frame().LeftTop()); 380 ((ExpanderApp*)(be_app))->UpdateSettingsFrom(&fSettings); 381 return true; 382 } 383 384 void 385 ExpanderWindow::RefsReceived(BMessage *msg) 386 { 387 entry_ref ref; 388 int32 i = 0; 389 int8 destination_folder = 0x63; 390 fSettings.FindInt8("destination_folder", &destination_folder); 391 392 while (msg->FindRef("refs", i++, &ref) == B_OK) { 393 394 BEntry entry(&ref, true); 395 BPath path(&entry); 396 BNode node(&entry); 397 398 if (node.IsFile()) { 399 fSourceChanged = true; 400 fSourceRef = ref; 401 fSourceText->SetText(path.Path()); 402 if (destination_folder==0x63) { 403 BPath parent; 404 path.GetParent(&parent); 405 fDestText->SetText(parent.Path()); 406 get_ref_for_path(parent.Path(), &fDestRef); 407 } else if (destination_folder==0x65) { 408 fSettings.FindRef("destination_folder_use", &fDestRef); 409 BEntry dEntry(&fDestRef, true); 410 BPath dPath(&dEntry); 411 fDestText->SetText(dPath.Path()); 412 } 413 414 BEntry dEntry(&fDestRef, true); 415 if (dEntry.Exists()) { 416 fExpandButton->SetEnabled(true); 417 fExpandItem->SetEnabled(true); 418 } 419 420 if (fShowContents->Value() == B_CONTROL_ON) { 421 StopListing(); 422 StartListing(); 423 } else { 424 fShowContents->SetEnabled(true); 425 fShowItem->SetEnabled(true); 426 } 427 428 bool fromApp; 429 if (msg->FindBool("fromApp", &fromApp)==B_OK) { 430 AutoExpand(); 431 } else 432 AutoListing(); 433 } else if(node.IsDirectory()) { 434 fDestRef = ref; 435 fDestText->SetText(path.Path()); 436 } 437 } 438 } 439 440 void 441 ExpanderWindow::StartExpanding() 442 { 443 BMessage message; 444 445 ExpanderRule *rule = fRules.MatchingRule(&fSourceRef); 446 if (!rule) { 447 return; 448 } 449 450 BEntry destEntry(fDestText->Text(), true); 451 if (!destEntry.Exists()) { 452 BAlert *alert = new BAlert("destAlert", "The directory was either moved, renamed or not\n" 453 "supported.", 454 "Cancel", NULL, NULL, 455 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 456 alert->Go(); 457 return; 458 } 459 460 message.AddString("cmd", rule->ExpandCmd()); 461 message.AddRef("srcRef", &fSourceRef); 462 message.AddRef("destRef", &fDestRef); 463 464 fExpandButton->SetLabel("Stop"); 465 fSourceButton->SetEnabled(false); 466 fDestButton->SetEnabled(false); 467 fShowContents->SetEnabled(false); 468 fSourceItem->SetEnabled(false); 469 fDestItem->SetEnabled(false); 470 fExpandItem->SetEnabled(false); 471 fShowItem->SetEnabled(false); 472 fStopItem->SetEnabled(true); 473 fPreferencesItem->SetEnabled(false); 474 475 BEntry entry(&fSourceRef); 476 BPath path(&entry); 477 BString text("Expanding file "); 478 text.Append(path.Leaf()); 479 fExpandedText->SetText(text.String()); 480 481 fExpandingThread = new ExpanderThread(&message, new BMessenger(this)); 482 fExpandingThread->Start(); 483 484 fExpandingStarted = true; 485 } 486 487 void 488 ExpanderWindow::StopExpanding(void) 489 { 490 if (fExpandingThread) { 491 fExpandingThread->InterruptExternalExpander(); 492 fExpandingThread = NULL; 493 } 494 495 fExpandingStarted = false; 496 497 fExpandButton->SetLabel("Expand"); 498 fSourceButton->SetEnabled(true); 499 fDestButton->SetEnabled(true); 500 fShowContents->SetEnabled(true); 501 fSourceItem->SetEnabled(true); 502 fDestItem->SetEnabled(true); 503 fExpandItem->SetEnabled(true); 504 fShowItem->SetEnabled(true); 505 fStopItem->SetEnabled(false); 506 fPreferencesItem->SetEnabled(true); 507 } 508 509 void 510 ExpanderWindow::StartListing() 511 { 512 SetSizeLimits(450, BScreen().Frame().Width(), 335, BScreen().Frame().Height()); 513 ResizeTo(Frame().Width(), 335); 514 fListingScroll->ResizeTo(fListingScroll->Bounds().Width(), 210); 515 if (fListingScroll->IsHidden()) 516 fListingScroll->Show(); 517 518 if (!fSourceChanged) 519 return; 520 521 BMessage message; 522 523 ExpanderRule *rule = fRules.MatchingRule(&fSourceRef); 524 if (!rule) { 525 return; 526 } 527 message.AddString("cmd", rule->ListingCmd()); 528 message.AddRef("srcRef", &fSourceRef); 529 530 fShowContents->SetEnabled(true); 531 fSourceItem->SetEnabled(false); 532 fDestItem->SetEnabled(false); 533 fExpandItem->SetEnabled(false); 534 fShowItem->SetEnabled(true); 535 fShowItem->SetLabel("Hide Contents"); 536 fStopItem->SetEnabled(false); 537 fPreferencesItem->SetEnabled(false); 538 539 fSourceButton->SetEnabled(false); 540 fDestButton->SetEnabled(false); 541 fExpandButton->SetEnabled(false); 542 543 BEntry entry(&fSourceRef); 544 BPath path(&entry); 545 BString text("Creating listing for "); 546 text.Append(path.Leaf()); 547 fExpandedText->SetText(text.String()); 548 fListingText->SetText(""); 549 550 fListingThread = new ExpanderThread(&message, new BMessenger(this)); 551 fListingThread->Start(); 552 553 fListingStarted = true; 554 } 555 556 void 557 ExpanderWindow::StopListing(void) 558 { 559 if (fListingThread) { 560 fListingThread->InterruptExternalExpander(); 561 fListingThread = NULL; 562 } 563 564 fListingStarted = false; 565 566 fShowContents->SetEnabled(true); 567 fSourceItem->SetEnabled(true); 568 fDestItem->SetEnabled(true); 569 fExpandItem->SetEnabled(true); 570 fShowItem->SetEnabled(true); 571 fStopItem->SetEnabled(false); 572 fPreferencesItem->SetEnabled(true); 573 574 fSourceButton->SetEnabled(true); 575 fDestButton->SetEnabled(true); 576 fExpandButton->SetEnabled(true); 577 fExpandedText->SetText(""); 578 } 579 580 void 581 ExpanderWindow::CloseWindowOrKeepOpen() 582 { 583 bool automatically_expand_files = false; 584 fSettings.FindBool("automatically_expand_files", &automatically_expand_files); 585 bool close_when_done = false; 586 fSettings.FindBool("close_when_done", &close_when_done); 587 if (automatically_expand_files || close_when_done) 588 PostMessage(B_QUIT_REQUESTED); 589 } 590 591 void 592 ExpanderWindow::OpenDestFolder() 593 { 594 bool open_destination_folder = true; 595 fSettings.FindBool("open_destination_folder", &open_destination_folder); 596 597 if (!open_destination_folder) 598 return; 599 600 BMessage * message = new BMessage(B_REFS_RECEIVED); 601 message->AddRef("refs", &fDestRef); 602 BPath path(&fDestRef); 603 BMessenger tracker( "application/x-vnd.Be-TRAK" ); 604 tracker.SendMessage( message ); 605 } 606 607 void 608 ExpanderWindow::AutoListing() 609 { 610 bool show_contents_listing = false; 611 fSettings.FindBool("show_contents_listing", &show_contents_listing); 612 613 if (!show_contents_listing) 614 return; 615 616 fShowContents->SetValue(B_CONTROL_ON); 617 fShowContents->Invoke(); 618 } 619 620 void 621 ExpanderWindow::AutoExpand() 622 { 623 bool automatically_expand_files = false; 624 fSettings.FindBool("automatically_expand_files", &automatically_expand_files); 625 626 if (!automatically_expand_files) { 627 AutoListing(); 628 return; 629 } 630 631 fExpandButton->Invoke(); 632 } 633