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