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