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