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