1 /* 2 * Copyright 2010-2014, Haiku Inc. All rights reserved. 3 * Copyright 2010 Wim van der Meer <WPJvanderMeer@gmail.com> 4 * Copyright Karsten Heimrich, host.haiku@gmx.de. 5 * All rights reserved. Distributed under the terms of the MIT License. 6 * 7 * Authors: 8 * Karsten Heimrich 9 * Fredrik Modéen 10 * Christophe Huriaux 11 * Wim van der Meer 12 */ 13 14 15 #include "ScreenshotWindow.h" 16 17 #include <stdlib.h> 18 19 #include <Alert.h> 20 #include <Application.h> 21 #include <Bitmap.h> 22 #include <Box.h> 23 #include <Button.h> 24 #include <Catalog.h> 25 #include <CheckBox.h> 26 #include <ControlLook.h> 27 #include <File.h> 28 #include <FilePanel.h> 29 #include <FindDirectory.h> 30 #include <LayoutBuilder.h> 31 #include <Locale.h> 32 #include <Menu.h> 33 #include <MenuField.h> 34 #include <MenuItem.h> 35 #include <MessageFilter.h> 36 #include <Path.h> 37 #include <Roster.h> 38 #include <SeparatorView.h> 39 #include <SpaceLayoutItem.h> 40 #include <String.h> 41 #include <StringView.h> 42 #include <TextControl.h> 43 #include <TranslationUtils.h> 44 #include <TranslatorRoster.h> 45 46 #include "Utility.h" 47 48 49 #undef B_TRANSLATION_CONTEXT 50 #define B_TRANSLATION_CONTEXT "ScreenshotWindow" 51 52 53 enum { 54 kActiveWindow, 55 kIncludeBorder, 56 kIncludeCursor, 57 kNewScreenshot, 58 kImageFormat, 59 kLocationChanged, 60 kChooseLocation, 61 kSaveScreenshot, 62 kSettings, 63 kCloseTranslatorSettings 64 }; 65 66 67 // #pragma mark - QuitMessageFilter 68 69 70 class QuitMessageFilter : public BMessageFilter { 71 public: 72 QuitMessageFilter(BWindow* window) 73 : 74 BMessageFilter((uint32)B_QUIT_REQUESTED), 75 fWindow(window) 76 { 77 } 78 79 virtual filter_result Filter(BMessage* message, BHandler** target) 80 { 81 BMessenger(fWindow).SendMessage(kCloseTranslatorSettings); 82 return B_SKIP_MESSAGE; 83 } 84 85 private: 86 BWindow* fWindow; 87 }; 88 89 90 // #pragma mark - DirectoryRefFilter 91 92 93 class DirectoryRefFilter : public BRefFilter { 94 public: 95 virtual ~DirectoryRefFilter() 96 { 97 } 98 99 virtual bool Filter(const entry_ref* ref, BNode* node, 100 struct stat_beos* stat, const char* filetype) 101 { 102 return node->IsDirectory(); 103 } 104 }; 105 106 107 // #pragma mark - ScreenshotWindow 108 109 110 ScreenshotWindow::ScreenshotWindow(const Utility& utility, bool silent, 111 bool clipboard) 112 : 113 BWindow(BRect(0, 0, 200.0, 100.0), B_TRANSLATE_SYSTEM_NAME("Screenshot"), 114 B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_AVOID_FRONT 115 | B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS 116 | B_CLOSE_ON_ESCAPE), 117 fUtility(utility), 118 fDelayControl(NULL), 119 fScreenshot(NULL), 120 fOutputPathPanel(NULL), 121 fLastSelectedPath(NULL), 122 fSettingsWindow(NULL), 123 fDelay(0), 124 fIncludeBorder(false), 125 fIncludeCursor(false), 126 fGrabActiveWindow(false), 127 fOutputFilename(NULL), 128 fExtension(""), 129 fImageFileType(B_PNG_FORMAT) 130 { 131 // _ReadSettings() needs a valid fOutputPathMenu 132 fOutputPathMenu = new BMenu(B_TRANSLATE("Please select")); 133 _ReadSettings(); 134 135 // _NewScreenshot() needs a valid fNameControl 136 BString name(B_TRANSLATE_NOCOLLECT(fUtility.sDefaultFileNameBase)); 137 name << 1; 138 name = _FindValidFileName(name.String()); 139 fNameControl = new BTextControl("", B_TRANSLATE("Name:"), name, NULL); 140 141 // Check if fUtility contains valid data 142 if (fUtility.wholeScreen == NULL) { 143 _NewScreenshot(silent, clipboard, true); 144 return; 145 } 146 147 fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, fGrabActiveWindow, 148 fIncludeBorder); 149 150 fActiveWindow = new BCheckBox(B_TRANSLATE("Capture active window"), 151 new BMessage(kActiveWindow)); 152 if (fGrabActiveWindow) 153 fActiveWindow->SetValue(B_CONTROL_ON); 154 155 fWindowBorder = new BCheckBox(B_TRANSLATE("Include window border"), 156 new BMessage(kIncludeBorder)); 157 if (fIncludeBorder) 158 fWindowBorder->SetValue(B_CONTROL_ON); 159 if (!fGrabActiveWindow) 160 fWindowBorder->SetEnabled(false); 161 162 fShowCursor = new BCheckBox(B_TRANSLATE("Include mouse pointer"), 163 new BMessage(kIncludeCursor)); 164 if (fIncludeCursor) 165 fShowCursor->SetValue(B_CONTROL_ON); 166 167 BString delay; 168 delay << fDelay / 1000000; 169 fDelayControl = new BTextControl("", B_TRANSLATE("Delay:"), delay.String(), 170 NULL); 171 _DisallowChar(fDelayControl->TextView()); 172 fDelayControl->TextView()->SetAlignment(B_ALIGN_RIGHT); 173 BStringView* seconds = new BStringView("", B_TRANSLATE("seconds")); 174 seconds->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 175 176 BMenuField* menuLocation = new BMenuField(B_TRANSLATE("Save in:"), 177 fOutputPathMenu); 178 menuLocation->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 179 180 fTranslatorMenu = new BMenu(B_TRANSLATE("Please select")); 181 _SetupTranslatorMenu(); 182 BMenuField* menuFormat = new BMenuField(B_TRANSLATE("Save as:"), 183 fTranslatorMenu); 184 menuFormat->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 185 186 BButton* showSettings = new BButton("", 187 B_TRANSLATE("Settings" B_UTF8_ELLIPSIS), new BMessage(kSettings)); 188 showSettings->SetExplicitAlignment( 189 BAlignment(B_ALIGN_RIGHT, B_ALIGN_BOTTOM)); 190 191 BBox* divider = new BBox(B_FANCY_BORDER, NULL); 192 divider->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1)); 193 194 BButton* saveScreenshot = new BButton("", B_TRANSLATE("Save"), 195 new BMessage(kSaveScreenshot)); 196 197 const float kSpacing = be_control_look->DefaultItemSpacing(); 198 const float kLabelSpacing = be_control_look->DefaultLabelSpacing(); 199 200 fPreview = new BView("preview", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE); 201 BBox* previewBox = new BBox(B_FANCY_BORDER, fPreview); 202 203 BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 204 .AddGroup(B_HORIZONTAL) 205 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, 206 B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING) 207 .Add(previewBox) 208 .AddGroup(B_VERTICAL, 0) 209 .Add(fActiveWindow) 210 .Add(fWindowBorder) 211 .Add(fShowCursor) 212 .AddStrut(kSpacing) 213 .AddGrid(0.0, kSpacing / 2) 214 .Add(fDelayControl->CreateLabelLayoutItem(), 0, 0) 215 .Add(fDelayControl->CreateTextViewLayoutItem(), 1, 0) 216 .Add(BSpaceLayoutItem::CreateHorizontalStrut(kLabelSpacing), 217 2, 0) 218 .Add(seconds, 3, 0) 219 .Add(fNameControl->CreateLabelLayoutItem(), 0, 1) 220 .Add(fNameControl->CreateTextViewLayoutItem(), 1, 1, 3, 1) 221 .Add(menuLocation->CreateLabelLayoutItem(), 0, 2) 222 .Add(menuLocation->CreateMenuBarLayoutItem(), 1, 2, 3, 1) 223 .Add(menuFormat->CreateLabelLayoutItem(), 0, 3) 224 .Add(menuFormat->CreateMenuBarLayoutItem(), 1, 3, 3, 1) 225 .End() 226 .AddStrut(kSpacing / 2) 227 .Add(showSettings) 228 .AddGlue() 229 .End() 230 .End() 231 .Add(new BSeparatorView(B_HORIZONTAL)) 232 .AddGroup(B_HORIZONTAL) 233 .SetInsets(B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING, 234 B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING) 235 .Add(new BButton("", B_TRANSLATE("Copy to clipboard"), 236 new BMessage(B_COPY))) 237 .Add(new BButton("", B_TRANSLATE("New screenshot"), 238 new BMessage(kNewScreenshot))) 239 .AddGlue() 240 .Add(saveScreenshot); 241 242 saveScreenshot->MakeDefault(true); 243 244 _UpdatePreviewPanel(); 245 _UpdateFilenameSelection(); 246 247 CenterOnScreen(); 248 Show(); 249 } 250 251 252 ScreenshotWindow::~ScreenshotWindow() 253 { 254 if (fOutputPathPanel) 255 delete fOutputPathPanel->RefFilter(); 256 257 delete fOutputPathPanel; 258 delete fScreenshot; 259 } 260 261 262 void 263 ScreenshotWindow::MessageReceived(BMessage* message) 264 { 265 switch (message->what) { 266 case kActiveWindow: 267 fGrabActiveWindow = false; 268 if (fActiveWindow->Value() == B_CONTROL_ON) 269 fGrabActiveWindow = true; 270 271 fWindowBorder->SetEnabled(fGrabActiveWindow); 272 273 delete fScreenshot; 274 fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, 275 fGrabActiveWindow, fIncludeBorder); 276 _UpdatePreviewPanel(); 277 break; 278 279 case kIncludeBorder: 280 fIncludeBorder = (fWindowBorder->Value() == B_CONTROL_ON); 281 delete fScreenshot; 282 fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, 283 fGrabActiveWindow, fIncludeBorder); 284 _UpdatePreviewPanel(); 285 break; 286 287 case kIncludeCursor: 288 fIncludeCursor = (fShowCursor->Value() == B_CONTROL_ON); 289 delete fScreenshot; 290 fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, 291 fGrabActiveWindow, fIncludeBorder); 292 _UpdatePreviewPanel(); 293 break; 294 295 case kNewScreenshot: 296 fDelay = (atoi(fDelayControl->Text()) * 1000000) + 50000; 297 _NewScreenshot(); 298 break; 299 300 case kImageFormat: 301 message->FindInt32("be:type", &fImageFileType); 302 fNameControl->SetText(_FindValidFileName( 303 fNameControl->Text()).String()); 304 _UpdateFilenameSelection(); 305 _ShowSettings(false); 306 break; 307 308 case kLocationChanged: 309 { 310 void* source = NULL; 311 if (message->FindPointer("source", &source) == B_OK) 312 fLastSelectedPath = static_cast<BMenuItem*> (source); 313 314 fNameControl->SetText(_FindValidFileName( 315 fNameControl->Text()).String()); 316 317 _UpdateFilenameSelection(); 318 break; 319 } 320 321 case kChooseLocation: 322 { 323 if (!fOutputPathPanel) { 324 BMessenger target(this); 325 fOutputPathPanel = new BFilePanel(B_OPEN_PANEL, &target, NULL, 326 B_DIRECTORY_NODE, false, NULL, new DirectoryRefFilter()); 327 fOutputPathPanel->Window()->SetTitle( 328 B_TRANSLATE("Choose folder")); 329 fOutputPathPanel->SetButtonLabel(B_DEFAULT_BUTTON, 330 B_TRANSLATE("Select")); 331 fOutputPathPanel->SetButtonLabel(B_CANCEL_BUTTON, 332 B_TRANSLATE("Cancel")); 333 } 334 fOutputPathPanel->Show(); 335 break; 336 } 337 338 case B_REFS_RECEIVED: 339 { 340 entry_ref ref; 341 if (message->FindRef("refs", &ref) == B_OK) { 342 BEntry entry(&ref, true); 343 if (entry.InitCheck() == B_OK) { 344 BPath path; 345 if (entry.GetPath(&path) == B_OK) { 346 BString label(path.Path()); 347 _AddItemToPathMenu(path.Path(), label, 3, true); 348 } 349 } 350 } 351 break; 352 } 353 354 case B_CANCEL: 355 fLastSelectedPath->SetMarked(true); 356 break; 357 358 case kSaveScreenshot: 359 if (_SaveScreenshot() == B_OK) 360 be_app->PostMessage(B_QUIT_REQUESTED); 361 break; 362 363 case B_COPY: 364 fUtility.CopyToClipboard(fScreenshot); 365 break; 366 367 case kSettings: 368 _ShowSettings(true); 369 break; 370 371 case kCloseTranslatorSettings: 372 fSettingsWindow->Lock(); 373 fSettingsWindow->Quit(); 374 fSettingsWindow = NULL; 375 break; 376 377 default: 378 BWindow::MessageReceived(message); 379 break; 380 } 381 } 382 383 384 void 385 ScreenshotWindow::Quit() 386 { 387 if (fUtility.wholeScreen != NULL) 388 _WriteSettings(); 389 BWindow::Quit(); 390 } 391 392 393 void 394 ScreenshotWindow::_NewScreenshot(bool silent, bool clipboard, bool ignoreDelay) 395 { 396 BMessage message(B_ARGV_RECEIVED); 397 int32 argc = 1; 398 message.AddString("argv", "screenshot"); 399 400 if (!ignoreDelay) { 401 argc += 2; 402 BString delay; 403 delay << fDelay / 1000000; 404 message.AddString("argv", "--delay"); 405 message.AddString("argv", delay); 406 } 407 408 if (silent || clipboard) { 409 if (silent) { 410 argc++; 411 message.AddString("argv", "--silent"); 412 } 413 if (clipboard) { 414 argc++; 415 message.AddString("argv", "--clipboard"); 416 } 417 if (fIncludeBorder) { 418 argc++; 419 message.AddString("argv", "--border"); 420 } 421 if (fIncludeCursor) { 422 argc++; 423 message.AddString("argv", "--mouse-pointer"); 424 } 425 if (fGrabActiveWindow) { 426 argc++; 427 message.AddString("argv", "--window"); 428 } 429 if (fLastSelectedPath) { 430 BPath path(_GetDirectory()); 431 if (path != NULL) { 432 path.Append(fNameControl->Text()); 433 argc++; 434 message.AddString("argv", path.Path()); 435 } 436 } 437 } 438 message.AddInt32("argc", argc); 439 440 be_roster->Launch("application/x-vnd.haiku-screenshot-cli", &message); 441 be_app->PostMessage(B_QUIT_REQUESTED); 442 } 443 444 445 void 446 ScreenshotWindow::_UpdatePreviewPanel() 447 { 448 // Set the height of fPreview to what the layout suggests 449 fPreview->SetExplicitMinSize(BSize()); 450 fPreview->SetExplicitMaxSize(BSize()); 451 Layout(false); 452 453 float height = fPreview->Bounds().Height(); 454 float width = (fScreenshot->Bounds().Width() 455 / fScreenshot->Bounds().Height()) * height; 456 457 // to prevent a preview way too wide 458 if (width > 400.0f) { 459 width = 400.0f; 460 height = (fScreenshot->Bounds().Height() 461 / fScreenshot->Bounds().Width()) * width; 462 } 463 464 fPreview->SetExplicitMinSize(BSize(width, height)); 465 fPreview->SetExplicitMaxSize(BSize(width, height)); 466 467 fPreview->ClearViewBitmap(); 468 fPreview->SetViewBitmap(fScreenshot, fScreenshot->Bounds(), 469 fPreview->Bounds(), B_FOLLOW_ALL, B_FILTER_BITMAP_BILINEAR); 470 } 471 472 473 void 474 ScreenshotWindow::_DisallowChar(BTextView* textView) 475 { 476 for (uint32 i = 0; i < '0'; ++i) 477 textView->DisallowChar(i); 478 479 for (uint32 i = '9' + 1; i < 255; ++i) 480 textView->DisallowChar(i); 481 } 482 483 484 void 485 ScreenshotWindow::_SetupOutputPathMenu(const BMessage& settings) 486 { 487 fOutputPathMenu->SetLabelFromMarked(true); 488 489 BString lastSelectedPath; 490 settings.FindString("lastSelectedPath", &lastSelectedPath); 491 492 BPath path; 493 find_directory(B_USER_DIRECTORY, &path); 494 495 BString label(B_TRANSLATE("Home folder")); 496 _AddItemToPathMenu(path.Path(), label, 0, 497 path.Path() == lastSelectedPath, 'H'); 498 499 path.Append("Desktop"); 500 label.SetTo(B_TRANSLATE("Desktop")); 501 _AddItemToPathMenu(path.Path(), label, 0, 502 path.Path() == lastSelectedPath, 'D'); 503 504 find_directory(B_USER_NONPACKAGED_DATA_DIRECTORY, &path); 505 path.Append("artwork"); 506 507 label.SetTo(B_TRANSLATE("Artwork folder")); 508 _AddItemToPathMenu(path.Path(), label, 2, 509 path.Path() == lastSelectedPath, 'A'); 510 511 int32 i = 0; 512 BString userPath; 513 while (settings.FindString("path", ++i, &userPath) == B_OK) { 514 _AddItemToPathMenu(userPath.String(), userPath, 3, 515 userPath == lastSelectedPath); 516 } 517 518 if (!fLastSelectedPath) { 519 if (settings.IsEmpty() || lastSelectedPath.Length() == 0) { 520 fOutputPathMenu->ItemAt(1)->SetMarked(true); 521 fLastSelectedPath = fOutputPathMenu->ItemAt(1); 522 } else { 523 _AddItemToPathMenu(lastSelectedPath.String(), lastSelectedPath, 3, 524 true); 525 } 526 } 527 528 fOutputPathMenu->AddItem(new BSeparatorItem()); 529 fOutputPathMenu->AddItem(new BMenuItem( 530 B_TRANSLATE("Choose folder" B_UTF8_ELLIPSIS), 531 new BMessage(kChooseLocation), 'F')); 532 } 533 534 535 void 536 ScreenshotWindow::_AddItemToPathMenu(const char* path, BString& label, 537 int32 index, bool markItem, uint32 shortcutKey) 538 { 539 // Make sure that item won't be a duplicate of an existing one 540 for (int32 i = fOutputPathMenu->CountItems() - 1; i >= 0; --i) { 541 BMenuItem* menuItem = fOutputPathMenu->ItemAt(i); 542 BMessage* message = menuItem->Message(); 543 const char* pathFromItem; 544 if (message != NULL && message->what == kLocationChanged 545 && message->FindString("path", &pathFromItem) == B_OK 546 && !strcmp(path, pathFromItem)) { 547 548 if (markItem) { 549 fOutputPathMenu->ItemAt(i)->SetMarked(true); 550 fLastSelectedPath = fOutputPathMenu->ItemAt(i); 551 } 552 return; 553 } 554 } 555 556 BMessage* message = new BMessage(kLocationChanged); 557 message->AddString("path", path); 558 559 fOutputPathMenu->TruncateString(&label, B_TRUNCATE_MIDDLE, 560 fOutputPathMenu->StringWidth("SomethingLongHere")); 561 562 fOutputPathMenu->AddItem(new BMenuItem(label.String(), message, 563 shortcutKey), index); 564 565 if (markItem) { 566 fOutputPathMenu->ItemAt(index)->SetMarked(true); 567 fLastSelectedPath = fOutputPathMenu->ItemAt(index); 568 } 569 } 570 571 572 void 573 ScreenshotWindow::_UpdateFilenameSelection() 574 { 575 fNameControl->MakeFocus(true); 576 fNameControl->TextView()->Select(0, fNameControl->TextView()->TextLength() 577 - fExtension.Length()); 578 579 fNameControl->TextView()->ScrollToSelection(); 580 } 581 582 583 void 584 ScreenshotWindow::_SetupTranslatorMenu() 585 { 586 BMessage message(kImageFormat); 587 fTranslatorMenu = new BMenu("Please select"); 588 BTranslationUtils::AddTranslationItems(fTranslatorMenu, B_TRANSLATOR_BITMAP, 589 &message, NULL, NULL, NULL); 590 591 fTranslatorMenu->SetLabelFromMarked(true); 592 593 if (fTranslatorMenu->ItemAt(0)) 594 fTranslatorMenu->ItemAt(0)->SetMarked(true); 595 596 int32 imageFileType; 597 for (int32 i = 0; i < fTranslatorMenu->CountItems(); ++i) { 598 BMenuItem* item = fTranslatorMenu->ItemAt(i); 599 if (item != NULL && item->Message()) { 600 item->Message()->FindInt32("be:type", &imageFileType); 601 if (fImageFileType == imageFileType) { 602 item->SetMarked(true); 603 MessageReceived(item->Message()); 604 break; 605 } 606 } 607 } 608 } 609 610 611 void 612 ScreenshotWindow::_DisplaySaveError(BString _message) { 613 BString alertText; 614 alertText.SetToFormat(B_TRANSLATE("Error saving \"%s\":\n\t%s"), 615 fNameControl->Text(), _message.String()); 616 617 BAlert* alert = new BAlert(B_TRANSLATE("Failed to save screenshot"), 618 alertText.String(), B_TRANSLATE("OK"), 619 NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 620 621 alert->SetShortcut(0, B_ESCAPE); 622 alert->Go(); 623 } 624 625 626 status_t 627 ScreenshotWindow::_SaveScreenshot() 628 { 629 if (!fScreenshot || !fLastSelectedPath) 630 return B_ERROR; 631 632 BPath path(_GetDirectory()); 633 634 if (path == NULL) 635 return B_ERROR; 636 637 BEntry directoryEntry; 638 directoryEntry.SetTo(path.Path()); 639 640 // create folder if it doesn't exist 641 // necessary, for example, when the user selects the Artwork folder from 642 // the list of predefined folders. 643 if (!directoryEntry.Exists()) { 644 status_t directoryCreateStatus = create_directory(path.Path(), 0755); 645 if (directoryCreateStatus != B_OK) { 646 _DisplaySaveError(strerror(directoryCreateStatus)); 647 648 return directoryCreateStatus; 649 } 650 } else if (!directoryEntry.IsDirectory()) { 651 // the entry exists but is not a directory. 652 // not much we can do 653 _DisplaySaveError( 654 B_TRANSLATE("The destination path exists but is not a folder.")); 655 656 return B_NOT_A_DIRECTORY; 657 } 658 659 path.Append(fNameControl->Text()); 660 661 BEntry entry; 662 entry.SetTo(path.Path()); 663 664 if (entry.Exists()) { 665 BAlert* overwriteAlert = new BAlert( 666 B_TRANSLATE("overwrite"), 667 B_TRANSLATE("This file already exists.\n Are you sure you would " 668 "like to overwrite it?"), 669 B_TRANSLATE("Cancel"), 670 B_TRANSLATE("Overwrite"), 671 NULL, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT); 672 673 overwriteAlert->SetShortcut(0, B_ESCAPE); 674 675 if (overwriteAlert->Go() == 0) 676 return B_CANCELED; 677 } 678 679 status_t saveStatus = fUtility.Save(fScreenshot, 680 path.Path(), fImageFileType); 681 682 if (saveStatus != B_OK) { 683 _DisplaySaveError(strerror(saveStatus)); 684 return saveStatus; 685 } 686 return B_OK; 687 } 688 689 690 void 691 ScreenshotWindow::_ShowSettings(bool activate) 692 { 693 if (!fSettingsWindow && !activate) 694 return; 695 696 // Find a translator 697 translator_id translator; 698 if (fUtility.FindTranslator(fImageFileType, translator) != B_OK) 699 return; 700 701 // Create a window with a configuration view 702 BView* view; 703 BRect rect(0, 0, 239, 239); 704 705 status_t status = BTranslatorRoster::Default()->MakeConfigurationView( 706 translator, NULL, &view, &rect); 707 if (status != B_OK || view == NULL) { 708 // TODO: proper translation, better error dialog 709 BAlert* alert = new BAlert(NULL, strerror(status), B_TRANSLATE("OK")); 710 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 711 alert->Go(); 712 } else if (fSettingsWindow != NULL) { 713 fSettingsWindow->RemoveChild(fSettingsWindow->ChildAt(0)); 714 float width, height; 715 view->GetPreferredSize(&width, &height); 716 fSettingsWindow->ResizeTo(width, height); 717 fSettingsWindow->AddChild(view); 718 if (activate) 719 fSettingsWindow->Activate(); 720 } else { 721 fSettingsWindow = new BWindow(rect, 722 B_TRANSLATE("Translator Settings"), 723 B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 724 B_NOT_ZOOMABLE | B_NOT_RESIZABLE); 725 fSettingsWindow->AddFilter(new QuitMessageFilter(this)); 726 fSettingsWindow->AddChild(view); 727 fSettingsWindow->CenterOnScreen(); 728 fSettingsWindow->Show(); 729 } 730 } 731 732 733 BString 734 ScreenshotWindow::_FindValidFileName(const char* name) 735 { 736 BString baseName(name); 737 738 if (!fExtension.IsEmpty()) 739 baseName.RemoveLast(fExtension); 740 741 if (!fLastSelectedPath) 742 return baseName; 743 744 BPath orgPath(_GetDirectory()); 745 if (orgPath == NULL) 746 return baseName; 747 748 fExtension = fUtility.FileNameExtension(fImageFileType); 749 750 BPath outputPath = orgPath; 751 BString fileName; 752 fileName << baseName << fExtension; 753 outputPath.Append(fileName); 754 755 if (!BEntry(outputPath.Path()).Exists()) 756 return fileName; 757 758 if (baseName.FindFirst(B_TRANSLATE_NOCOLLECT( 759 fUtility.sDefaultFileNameBase)) == 0) 760 baseName.SetTo(fUtility.sDefaultFileNameBase); 761 762 BEntry entry; 763 int32 index = 1; 764 765 do { 766 fileName = ""; 767 fileName << baseName << index++ << fExtension; 768 outputPath.SetTo(orgPath.Path()); 769 outputPath.Append(fileName); 770 entry.SetTo(outputPath.Path()); 771 } while (entry.Exists()); 772 773 return fileName; 774 } 775 776 777 BPath 778 ScreenshotWindow::_GetDirectory() 779 { 780 BPath path; 781 782 BMessage* message = fLastSelectedPath->Message(); 783 const char* stringPath; 784 if (message && message->FindString("path", &stringPath) == B_OK) 785 path.SetTo(stringPath); 786 787 return path; 788 } 789 790 791 void 792 ScreenshotWindow::_ReadSettings() 793 { 794 BMessage settings; 795 796 BPath settingsPath; 797 if (find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath) != B_OK) 798 return; 799 800 settingsPath.Append("Screenshot_settings"); 801 802 BFile file(settingsPath.Path(), B_READ_ONLY); 803 if (file.InitCheck() == B_OK) 804 settings.Unflatten(&file); 805 806 if (settings.FindInt32("type", &fImageFileType) != B_OK) 807 fImageFileType = B_PNG_FORMAT; 808 settings.FindBool("includeBorder", &fIncludeBorder); 809 settings.FindBool("includeCursor", &fIncludeCursor); 810 settings.FindBool("grabActiveWindow", &fGrabActiveWindow); 811 settings.FindInt64("delay", &fDelay); 812 settings.FindString("outputFilename", &fOutputFilename); 813 814 _SetupOutputPathMenu(settings); 815 } 816 817 818 void 819 ScreenshotWindow::_WriteSettings() 820 { 821 if (fDelayControl) 822 fDelay = (atoi(fDelayControl->Text()) * 1000000) + 50000; 823 824 BMessage settings; 825 826 settings.AddInt32("type", fImageFileType); 827 settings.AddBool("includeBorder", fIncludeBorder); 828 settings.AddBool("includeCursor", fIncludeCursor); 829 settings.AddBool("grabActiveWindow", fGrabActiveWindow); 830 settings.AddInt64("delay", fDelay); 831 settings.AddString("outputFilename", fOutputFilename); 832 833 BString path; 834 int32 count = fOutputPathMenu->CountItems(); 835 if (count > 5) { 836 for (int32 i = count - 3; i > count - 8 && i > 2; --i) { 837 BMenuItem* item = fOutputPathMenu->ItemAt(i); 838 if (item) { 839 BMessage* msg = item->Message(); 840 if (msg && msg->FindString("path", &path) == B_OK) 841 settings.AddString("path", path.String()); 842 } 843 } 844 } 845 846 if (fLastSelectedPath) { 847 BMessage* msg = fLastSelectedPath->Message(); 848 if (msg && msg->FindString("path", &path) == B_OK) 849 settings.AddString("lastSelectedPath", path.String()); 850 } 851 852 BPath settingsPath; 853 if (find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath) != B_OK) 854 return; 855 settingsPath.Append("Screenshot_settings"); 856 857 BFile file(settingsPath.Path(), B_CREATE_FILE | B_ERASE_FILE 858 | B_WRITE_ONLY); 859 if (file.InitCheck() == B_OK) { 860 ssize_t size; 861 settings.Flatten(&file, &size); 862 } 863 } 864