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