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 fShowContents->SetEnabled(true); 421 fShowItem->SetEnabled(true); 422 423 bool fromApp; 424 if (msg->FindBool("fromApp", &fromApp)==B_OK) { 425 AutoExpand(); 426 } else 427 AutoListing(); 428 } else if(node.IsDirectory()) { 429 fDestRef = ref; 430 fDestText->SetText(path.Path()); 431 } 432 } 433 } 434 435 void 436 ExpanderWindow::StartExpanding() 437 { 438 BMessage message; 439 440 ExpanderRule *rule = fRules.MatchingRule(&fSourceRef); 441 if (!rule) { 442 return; 443 } 444 445 BEntry destEntry(fDestText->Text(), true); 446 if (!destEntry.Exists()) { 447 BAlert *alert = new BAlert("destAlert", "The directory was either moved, renamed or not\n" 448 "supported.", 449 "Cancel", NULL, NULL, 450 B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 451 alert->Go(); 452 return; 453 } 454 455 message.AddString("cmd", rule->ExpandCmd()); 456 message.AddRef("srcRef", &fSourceRef); 457 message.AddRef("destRef", &fDestRef); 458 459 fExpandButton->SetLabel("Stop"); 460 fSourceButton->SetEnabled(false); 461 fDestButton->SetEnabled(false); 462 fShowContents->SetEnabled(false); 463 fSourceItem->SetEnabled(false); 464 fDestItem->SetEnabled(false); 465 fExpandItem->SetEnabled(false); 466 fShowItem->SetEnabled(false); 467 fStopItem->SetEnabled(true); 468 fPreferencesItem->SetEnabled(false); 469 470 BEntry entry(&fSourceRef); 471 BPath path(&entry); 472 BString text("Expanding file "); 473 text.Append(path.Leaf()); 474 fExpandedText->SetText(text.String()); 475 476 fExpandingThread = new ExpanderThread(&message, new BMessenger(this)); 477 fExpandingThread->Start(); 478 479 fExpandingStarted = true; 480 } 481 482 void 483 ExpanderWindow::StopExpanding(void) 484 { 485 if (fExpandingThread) { 486 fExpandingThread->InterruptExternalExpander(); 487 fExpandingThread = NULL; 488 } 489 490 fExpandingStarted = false; 491 492 fExpandButton->SetLabel("Expand"); 493 fSourceButton->SetEnabled(true); 494 fDestButton->SetEnabled(true); 495 fShowContents->SetEnabled(true); 496 fSourceItem->SetEnabled(true); 497 fDestItem->SetEnabled(true); 498 fExpandItem->SetEnabled(true); 499 fShowItem->SetEnabled(true); 500 fStopItem->SetEnabled(false); 501 fPreferencesItem->SetEnabled(true); 502 } 503 504 void 505 ExpanderWindow::StartListing() 506 { 507 SetSizeLimits(450, BScreen().Frame().Width(), 335, BScreen().Frame().Height()); 508 ResizeTo(Frame().Width(), 335); 509 fListingScroll->ResizeTo(fListingScroll->Bounds().Width(), 210); 510 if (fListingScroll->IsHidden()) 511 fListingScroll->Show(); 512 513 if (!fSourceChanged) 514 return; 515 516 BMessage message; 517 518 ExpanderRule *rule = fRules.MatchingRule(&fSourceRef); 519 if (!rule) { 520 return; 521 } 522 message.AddString("cmd", rule->ListingCmd()); 523 message.AddRef("srcRef", &fSourceRef); 524 525 fShowContents->SetEnabled(true); 526 fSourceItem->SetEnabled(false); 527 fDestItem->SetEnabled(false); 528 fExpandItem->SetEnabled(false); 529 fShowItem->SetEnabled(true); 530 fShowItem->SetLabel("Hide Contents"); 531 fStopItem->SetEnabled(false); 532 fPreferencesItem->SetEnabled(false); 533 534 fSourceButton->SetEnabled(false); 535 fDestButton->SetEnabled(false); 536 fExpandButton->SetEnabled(false); 537 538 BEntry entry(&fSourceRef); 539 BPath path(&entry); 540 BString text("Creating listing for "); 541 text.Append(path.Leaf()); 542 fExpandedText->SetText(text.String()); 543 fListingText->SetText(""); 544 545 fListingThread = new ExpanderThread(&message, new BMessenger(this)); 546 fListingThread->Start(); 547 548 fListingStarted = true; 549 } 550 551 void 552 ExpanderWindow::StopListing(void) 553 { 554 if (fListingThread) { 555 fListingThread->InterruptExternalExpander(); 556 fListingThread = NULL; 557 } 558 559 fListingStarted = false; 560 561 fShowContents->SetEnabled(true); 562 fSourceItem->SetEnabled(true); 563 fDestItem->SetEnabled(true); 564 fExpandItem->SetEnabled(true); 565 fShowItem->SetEnabled(true); 566 fStopItem->SetEnabled(false); 567 fPreferencesItem->SetEnabled(true); 568 569 fSourceButton->SetEnabled(true); 570 fDestButton->SetEnabled(true); 571 fExpandButton->SetEnabled(true); 572 fExpandedText->SetText(""); 573 } 574 575 void 576 ExpanderWindow::CloseWindowOrKeepOpen() 577 { 578 bool automatically_expand_files = false; 579 fSettings.FindBool("automatically_expand_files", &automatically_expand_files); 580 bool close_when_done = false; 581 fSettings.FindBool("close_when_done", &close_when_done); 582 if (automatically_expand_files || close_when_done) 583 PostMessage(B_QUIT_REQUESTED); 584 } 585 586 void 587 ExpanderWindow::OpenDestFolder() 588 { 589 bool open_destination_folder = true; 590 fSettings.FindBool("open_destination_folder", &open_destination_folder); 591 592 if (!open_destination_folder) 593 return; 594 595 BMessage * message = new BMessage(B_REFS_RECEIVED); 596 message->AddRef("refs", &fDestRef); 597 BPath path(&fDestRef); 598 BMessenger tracker( "application/x-vnd.Be-TRAK" ); 599 tracker.SendMessage( message ); 600 } 601 602 void 603 ExpanderWindow::AutoListing() 604 { 605 bool show_contents_listing = false; 606 fSettings.FindBool("show_contents_listing", &show_contents_listing); 607 608 if (!show_contents_listing) 609 return; 610 611 fShowContents->SetValue(B_CONTROL_ON); 612 fShowContents->Invoke(); 613 } 614 615 void 616 ExpanderWindow::AutoExpand() 617 { 618 bool automatically_expand_files = false; 619 fSettings.FindBool("automatically_expand_files", &automatically_expand_files); 620 621 if (!automatically_expand_files) { 622 AutoListing(); 623 return; 624 } 625 626 fExpandButton->Invoke(); 627 } 628