xref: /haiku/src/apps/screenshot/ScreenshotWindow.cpp (revision 85fb3e7df81f8d5b6e47a9a64a53873ea906ea6e)
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