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