xref: /haiku/src/apps/screenshot/ScreenshotWindow.cpp (revision c6d2f9af2ca4b7b1ba866080c8caa7fa29a8e458)
1 /*
2  * Copyright 2010 Wim van der Meer <WPJvanderMeer@gmail.com>
3  * Copyright Karsten Heimrich, host.haiku@gmx.de.
4  * All rights reserved. Distributed under the terms of the MIT License.
5  *
6  * Authors:
7  *		Karsten Heimrich
8  *		Fredrik Modéen
9  *		Christophe Huriaux
10  *		Wim van der Meer
11  */
12 
13 
14 #include "ScreenshotWindow.h"
15 
16 #include <stdlib.h>
17 
18 #include <Alert.h>
19 #include <Application.h>
20 #include <Bitmap.h>
21 #include <Box.h>
22 #include <Button.h>
23 #include <Catalog.h>
24 #include <CheckBox.h>
25 #include <File.h>
26 #include <FilePanel.h>
27 #include <FindDirectory.h>
28 #include <GridLayoutBuilder.h>
29 #include <GroupLayoutBuilder.h>
30 #include <Locale.h>
31 #include <Menu.h>
32 #include <MenuField.h>
33 #include <MenuItem.h>
34 #include <MessageFilter.h>
35 #include <Path.h>
36 #include <Roster.h>
37 #include <String.h>
38 #include <StringView.h>
39 #include <TextControl.h>
40 #include <TranslationUtils.h>
41 #include <TranslatorRoster.h>
42 
43 #include "PreviewView.h"
44 #include "Utility.h"
45 
46 
47 #undef B_TRANSLATE_CONTEXT
48 #define B_TRANSLATE_CONTEXT "ScreenshotWindow"
49 
50 
51 enum {
52 	kActiveWindow,
53 	kIncludeBorder,
54 	kIncludeCursor,
55 	kNewScreenshot,
56 	kImageFormat,
57 	kLocationChanged,
58 	kChooseLocation,
59 	kSaveScreenshot,
60 	kSettings,
61 	kCloseTranslatorSettings
62 };
63 
64 
65 // #pragma mark - QuitMessageFilter
66 
67 
68 class QuitMessageFilter : public BMessageFilter {
69 public:
70 	QuitMessageFilter(BWindow* window)
71 		:
72 		BMessageFilter((uint32)B_QUIT_REQUESTED),
73 		fWindow(window)
74 	{
75 	}
76 
77 	virtual filter_result Filter(BMessage* message, BHandler** target)
78 	{
79 		BMessenger(fWindow).SendMessage(kCloseTranslatorSettings);
80 		return B_SKIP_MESSAGE;
81 	}
82 
83 private:
84 	BWindow* fWindow;
85 };
86 
87 
88 // #pragma mark - DirectoryRefFilter
89 
90 
91 class DirectoryRefFilter : public BRefFilter {
92 public:
93 	virtual ~DirectoryRefFilter()
94 	{
95 	}
96 
97 	virtual bool Filter(const entry_ref* ref, BNode* node,
98 		struct stat_beos* stat, const char* filetype)
99 	{
100 		return node->IsDirectory();
101 	}
102 };
103 
104 
105 // #pragma mark - ScreenshotWindow
106 
107 
108 ScreenshotWindow::ScreenshotWindow(const Utility& utility, bool silent,
109 	bool clipboard)
110 	:
111 	BWindow(BRect(0, 0, 200.0, 100.0), B_TRANSLATE("Screenshot"),
112 		B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_AVOID_FRONT
113 		| B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS
114 		| B_CLOSE_ON_ESCAPE),
115 	fUtility(utility),
116 	fDelayControl(NULL),
117 	fScreenshot(NULL),
118 	fOutputPathPanel(NULL),
119 	fLastSelectedPath(NULL),
120 	fSettingsWindow(NULL),
121 	fDelay(0),
122 	fIncludeBorder(false),
123 	fIncludeCursor(false),
124 	fGrabActiveWindow(false),
125 	fOutputFilename(NULL),
126 	fExtension(""),
127 	fImageFileType(B_PNG_FORMAT)
128 {
129 	// _ReadSettings() needs a valid fOutputPathMenu
130 	fOutputPathMenu = new BMenu(B_TRANSLATE("Please select"));
131 	_ReadSettings();
132 
133 	// _NewScreenshot() needs a valid fNameControl
134 	BString name(B_TRANSLATE_NOCOLLECT(fUtility.sDefaultFileNameBase));
135 	name << 1;
136 	name = _FindValidFileName(name.String());
137 	fNameControl = new BTextControl("", B_TRANSLATE("Name:"), name, NULL);
138 
139 	// Check if fUtility contains valid data
140 	if (fUtility.wholeScreen == NULL) {
141 		_NewScreenshot(silent, clipboard);
142 		return;
143 	}
144 
145 	fScreenshot = fUtility.MakeScreenshot(fIncludeCursor, fGrabActiveWindow,
146 		fIncludeBorder);
147 
148 	fActiveWindow = new BCheckBox(B_TRANSLATE("Capture active window"),
149 		new BMessage(kActiveWindow));
150 	if (fGrabActiveWindow)
151 		fActiveWindow->SetValue(B_CONTROL_ON);
152 
153 	fWindowBorder = new BCheckBox(B_TRANSLATE("Include window border"),
154 		new BMessage(kIncludeBorder));
155 	if (fIncludeBorder)
156 		fWindowBorder->SetValue(B_CONTROL_ON);
157 	if (!fGrabActiveWindow)
158 		fWindowBorder->SetEnabled(false);
159 
160 	fShowCursor = new BCheckBox(B_TRANSLATE("Include mouse pointer"),
161 		new BMessage(kIncludeCursor));
162 	if (fIncludeCursor)
163 		fShowCursor->SetValue(B_CONTROL_ON);
164 
165 	BString delay;
166 	delay << fDelay / 1000000;
167 	fDelayControl = new BTextControl("", B_TRANSLATE("Delay:"), delay.String(),
168 		NULL);
169 	_DisallowChar(fDelayControl->TextView());
170 	fDelayControl->TextView()->SetAlignment(B_ALIGN_RIGHT);
171 	BStringView* seconds = new BStringView("", B_TRANSLATE("seconds"));
172 	seconds->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
173 
174 	BMenuField* menuField2 = new BMenuField(B_TRANSLATE("Save in:"),
175 		fOutputPathMenu);
176 
177 	fTranslatorMenu = new BMenu(B_TRANSLATE("Please select"));
178 	_SetupTranslatorMenu();
179 	BMenuField* menuField = new BMenuField(B_TRANSLATE("Save as:"),
180 		fTranslatorMenu);
181 
182 	BBox* divider = new BBox(B_FANCY_BORDER, NULL);
183 	divider->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1));
184 
185 	BButton* saveScreenshot  = new BButton("", B_TRANSLATE("Save"),
186 		new BMessage(kSaveScreenshot));
187 
188 	fPreview = new PreviewView();
189 
190 	BGridLayout* gridLayout = BGridLayoutBuilder(0.0, 5.0)
191 		.Add(fNameControl->CreateLabelLayoutItem(), 0, 0)
192 		.Add(fNameControl->CreateTextViewLayoutItem(), 1, 0)
193 		.Add(menuField->CreateLabelLayoutItem(), 0, 1)
194 		.Add(menuField->CreateMenuBarLayoutItem(), 1, 1)
195 		.Add(new BButton("", B_TRANSLATE("Settings"B_UTF8_ELLIPSIS),
196 			new BMessage(kSettings)), 2, 1)
197 		.Add(menuField2->CreateLabelLayoutItem(), 0, 2)
198 		.Add(menuField2->CreateMenuBarLayoutItem(), 1, 2);
199 	gridLayout->SetMinColumnWidth(1,
200 		menuField->StringWidth("SomethingLongHere"));
201 
202 	SetLayout(new BGroupLayout(B_HORIZONTAL, 0));
203 
204 	AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
205 		.Add(BGroupLayoutBuilder(B_HORIZONTAL, 10.0)
206 			.Add(fPreview)
207 			.AddGroup(B_VERTICAL, 0)
208 				.Add(fActiveWindow)
209 				.Add(fWindowBorder)
210 				.Add(fShowCursor)
211 				.AddGroup(B_HORIZONTAL, 5.0)
212 					.Add(fDelayControl->CreateLabelLayoutItem())
213 					.Add(fDelayControl->CreateTextViewLayoutItem())
214 					.Add(seconds)
215 					.End()
216 				.AddStrut(10.0)
217 				.Add(gridLayout)
218 				.AddGlue()
219 				.End())
220 		.AddStrut(10)
221 		.Add(divider)
222 		.AddStrut(10)
223 		.AddGroup(B_HORIZONTAL, 10.0)
224 			.Add(new BButton("", B_TRANSLATE("Copy to clipboard"),
225 				new BMessage(B_COPY)))
226 			.Add(new BButton("", B_TRANSLATE("New screenshot"),
227 				new BMessage(kNewScreenshot)))
228 			.AddGlue()
229 			.Add(saveScreenshot)
230 			.End()
231 		.SetInsets(10.0, 10.0, 10.0, 10.0)
232 	);
233 
234 	saveScreenshot->MakeDefault(true);
235 
236 	_UpdatePreviewPanel();
237 	_UpdateFilenameSelection();
238 
239 	CenterOnScreen();
240 	Show();
241 }
242 
243 
244 ScreenshotWindow::~ScreenshotWindow()
245 {
246 	if (fOutputPathPanel)
247 		delete fOutputPathPanel->RefFilter();
248 
249 	delete fOutputPathPanel;
250 	delete fScreenshot;
251 }
252 
253 
254 void
255 ScreenshotWindow::MessageReceived(BMessage* message)
256 {
257 	switch (message->what) {
258 		case kActiveWindow:
259 			fGrabActiveWindow = false;
260 			if (fActiveWindow->Value() == B_CONTROL_ON)
261 				fGrabActiveWindow = true;
262 
263 			fWindowBorder->SetEnabled(fGrabActiveWindow);
264 
265 			delete fScreenshot;
266 			fScreenshot = fUtility.MakeScreenshot(fIncludeCursor,
267 				fGrabActiveWindow, fIncludeBorder);
268 			_UpdatePreviewPanel();
269 			break;
270 
271 		case kIncludeBorder:
272 			fIncludeBorder = (fWindowBorder->Value() == B_CONTROL_ON);
273 			delete fScreenshot;
274 			fScreenshot = fUtility.MakeScreenshot(fIncludeCursor,
275 				fGrabActiveWindow, fIncludeBorder);
276 			_UpdatePreviewPanel();
277 			break;
278 
279 		case kIncludeCursor:
280 			fIncludeCursor = (fShowCursor->Value() == B_CONTROL_ON);
281 			delete fScreenshot;
282 			fScreenshot = fUtility.MakeScreenshot(fIncludeCursor,
283 				fGrabActiveWindow, fIncludeBorder);
284 			_UpdatePreviewPanel();
285 			break;
286 
287 		case kNewScreenshot:
288 			fDelay = (atoi(fDelayControl->Text()) * 1000000) + 50000;
289 			_NewScreenshot();
290 			break;
291 
292 		case kImageFormat:
293 			message->FindInt32("be:type", &fImageFileType);
294 			fNameControl->SetText(_FindValidFileName(
295 				fNameControl->Text()).String());
296 			_UpdateFilenameSelection();
297 			_ShowSettings(false);
298 			break;
299 
300 		case kLocationChanged:
301 		{
302 			void* source = NULL;
303 			if (message->FindPointer("source", &source) == B_OK)
304 				fLastSelectedPath = static_cast<BMenuItem*> (source);
305 
306 			fNameControl->SetText(_FindValidFileName(
307 				fNameControl->Text()).String());
308 
309 			_UpdateFilenameSelection();
310 			break;
311 		}
312 
313 		case kChooseLocation:
314 		{
315 			if (!fOutputPathPanel) {
316 				BMessenger target(this);
317 				fOutputPathPanel = new BFilePanel(B_OPEN_PANEL, &target, NULL,
318 					B_DIRECTORY_NODE, false, NULL, new DirectoryRefFilter());
319 				fOutputPathPanel->Window()->SetTitle(
320 					B_TRANSLATE("Choose folder"));
321 				fOutputPathPanel->SetButtonLabel(B_DEFAULT_BUTTON,
322 					B_TRANSLATE("Select"));
323 				fOutputPathPanel->SetButtonLabel(B_CANCEL_BUTTON,
324 					B_TRANSLATE("Cancel"));
325 			}
326 			fOutputPathPanel->Show();
327 			break;
328 		}
329 
330 		case B_REFS_RECEIVED:
331 		{
332 			entry_ref ref;
333 			if (message->FindRef("refs", &ref) == B_OK) {
334 				BEntry entry(&ref, true);
335 				BPath path;
336 				entry.GetPath(&path);
337 				BString label(path.Path());
338 				_AddItemToPathMenu(path.Path(), label, 3, true);
339 			}
340 			break;
341 		}
342 
343 		case B_CANCEL:
344 			fLastSelectedPath->SetMarked(true);
345 			break;
346 
347 		case kSaveScreenshot:
348 			if (_SaveScreenshot() == B_OK)
349 				be_app->PostMessage(B_QUIT_REQUESTED);
350 			break;
351 
352 		case B_COPY:
353 			fUtility.CopyToClipboard(fScreenshot);
354 			break;
355 
356 		case kSettings:
357 			_ShowSettings(true);
358 			break;
359 
360 		case kCloseTranslatorSettings:
361 			fSettingsWindow->Lock();
362 			fSettingsWindow->Quit();
363 			fSettingsWindow = NULL;
364 			break;
365 
366 		default:
367 			BWindow::MessageReceived(message);
368 			break;
369 	}
370 }
371 
372 
373 void
374 ScreenshotWindow::Quit()
375 {
376 	if (fUtility.wholeScreen != NULL)
377 		_WriteSettings();
378 	BWindow::Quit();
379 }
380 
381 
382 void
383 ScreenshotWindow::_NewScreenshot(bool silent, bool clipboard)
384 {
385 	BMessage message(B_ARGV_RECEIVED);
386 	int32 argc = 3;
387 	BString delay;
388 	delay << fDelay / 1000000;
389 	message.AddString("argv", "screenshot");
390 	message.AddString("argv", "--delay");
391 	message.AddString("argv", delay);
392 
393 	if (silent || clipboard) {
394 		if (silent) {
395 			argc++;
396 			message.AddString("argv", "--silent");
397 		}
398 		if (clipboard) {
399 			argc++;
400 			message.AddString("argv", "--clipboard");
401 		}
402 		if (fIncludeBorder) {
403 			argc++;
404 			message.AddString("argv", "--border");
405 		}
406 		if (fIncludeCursor) {
407 			argc++;
408 			message.AddString("argv", "--mouse-pointer");
409 		}
410 		if (fGrabActiveWindow) {
411 			argc++;
412 			message.AddString("argv", "--window");
413 		}
414 		if (fLastSelectedPath) {
415 			BPath path(_GetDirectory());
416 			if (path != NULL) {
417 				path.Append(fNameControl->Text());
418 				argc++;
419 				message.AddString("argv", path.Path());
420 			}
421 		}
422 	}
423 	message.AddInt32("argc", argc);
424 
425 	be_roster->Launch("application/x-vnd.haiku-screenshot-cli", &message);
426 	be_app->PostMessage(B_QUIT_REQUESTED);
427 }
428 
429 
430 void
431 ScreenshotWindow::_UpdatePreviewPanel()
432 {
433 	float height = 150.0f;
434 
435 	float width = (fScreenshot->Bounds().Width()
436 		/ fScreenshot->Bounds().Height()) * height;
437 
438 	// to prevent a preview way too wide
439 	if (width > 400.0f) {
440 		width = 400.0f;
441 		height = (fScreenshot->Bounds().Height()
442 			/ fScreenshot->Bounds().Width()) * width;
443 	}
444 
445 	fPreview->SetExplicitMinSize(BSize(width, height));
446 
447 	fPreview->ClearViewBitmap();
448 	fPreview->SetViewBitmap(fScreenshot, fScreenshot->Bounds(),
449 		fPreview->Bounds(), B_FOLLOW_ALL, B_FILTER_BITMAP_BILINEAR);
450 }
451 
452 
453 void
454 ScreenshotWindow::_DisallowChar(BTextView* textView)
455 {
456 	for (uint32 i = 0; i < '0'; ++i)
457 		textView->DisallowChar(i);
458 
459 	for (uint32 i = '9' + 1; i < 255; ++i)
460 		textView->DisallowChar(i);
461 }
462 
463 
464 void
465 ScreenshotWindow::_SetupOutputPathMenu(const BMessage& settings)
466 {
467 	fOutputPathMenu->SetLabelFromMarked(true);
468 
469 	BString lastSelectedPath;
470 	settings.FindString("lastSelectedPath", &lastSelectedPath);
471 
472 	BPath path;
473 	find_directory(B_USER_DIRECTORY, &path);
474 
475 	BString label(B_TRANSLATE("Home folder"));
476 	_AddItemToPathMenu(path.Path(), label, 0,
477 		(path.Path() == lastSelectedPath));
478 
479 	path.Append("Desktop");
480 	label.SetTo(B_TRANSLATE("Desktop"));
481 	_AddItemToPathMenu(path.Path(), label, 0, (
482 		path.Path() == lastSelectedPath));
483 
484 	find_directory(B_BEOS_ETC_DIRECTORY, &path);
485 	path.Append("artwork");
486 
487 	label.SetTo(B_TRANSLATE("Artwork folder"));
488 	_AddItemToPathMenu(path.Path(), label, 2,
489 		(path.Path() == lastSelectedPath));
490 
491 	int32 i = 0;
492 	BString userPath;
493 	while (settings.FindString("path", ++i, &userPath) == B_OK) {
494 		_AddItemToPathMenu(userPath.String(), userPath, 3,
495 			(userPath == lastSelectedPath));
496 	}
497 
498 	if (!fLastSelectedPath) {
499 		if (settings.IsEmpty() || lastSelectedPath.Length() == 0) {
500 			fOutputPathMenu->ItemAt(1)->SetMarked(true);
501 			fLastSelectedPath = fOutputPathMenu->ItemAt(1);
502 		} else
503 			_AddItemToPathMenu(lastSelectedPath.String(), lastSelectedPath, 3,
504 				true);
505 	}
506 
507 	fOutputPathMenu->AddItem(new BSeparatorItem());
508 	fOutputPathMenu->AddItem(new BMenuItem(B_TRANSLATE("Choose folder..."),
509 		new BMessage(kChooseLocation)));
510 }
511 
512 
513 void
514 ScreenshotWindow::_AddItemToPathMenu(const char* path, BString& label,
515 	int32 index, bool markItem)
516 {
517 	/* Make sure that item won't be a duplicata of an existing one */
518 	for (int32 i = fOutputPathMenu->CountItems(); i > 0; --i) {
519 		BMenuItem* menuItem = fOutputPathMenu->ItemAt(i - 1);
520 		BMessage* message = menuItem->Message();
521 		const char* pathFromItem;
522 		if (message != NULL && message->what == kLocationChanged) {
523 			if (message->FindString("path", &pathFromItem) == B_OK) {
524 				if (!strcmp(path, pathFromItem)) {
525 					if (markItem) {
526 						fOutputPathMenu->ItemAt(i - 1)->SetMarked(true);
527 						fLastSelectedPath = fOutputPathMenu->ItemAt(i - 1);
528 					}
529 					return;
530 				}
531 			}
532 		}
533 	}
534 
535 	BMessage* message = new BMessage(kLocationChanged);
536 	message->AddString("path", path);
537 
538 	fOutputPathMenu->TruncateString(&label, B_TRUNCATE_MIDDLE,
539 		fOutputPathMenu->StringWidth("SomethingLongHere"));
540 
541 	fOutputPathMenu->AddItem(new BMenuItem(label.String(), message), index);
542 
543 	if (markItem) {
544 		fOutputPathMenu->ItemAt(index)->SetMarked(true);
545 		fLastSelectedPath = fOutputPathMenu->ItemAt(index);
546 	}
547 }
548 
549 
550 void
551 ScreenshotWindow::_UpdateFilenameSelection()
552 {
553 	fNameControl->MakeFocus(true);
554 	fNameControl->TextView()->Select(0,	fNameControl->TextView()->TextLength()
555 		- fExtension.Length());
556 
557 	fNameControl->TextView()->ScrollToSelection();
558 }
559 
560 
561 void
562 ScreenshotWindow::_SetupTranslatorMenu()
563 {
564 	BMessage message(kImageFormat);
565 	fTranslatorMenu = new BMenu("Please select");
566 	BTranslationUtils::AddTranslationItems(fTranslatorMenu, B_TRANSLATOR_BITMAP,
567 		&message, NULL, NULL, NULL);
568 
569 	fTranslatorMenu->SetLabelFromMarked(true);
570 
571 	if (fTranslatorMenu->ItemAt(0))
572 		fTranslatorMenu->ItemAt(0)->SetMarked(true);
573 
574 	int32 imageFileType;
575 	for (int32 i = 0; i < fTranslatorMenu->CountItems(); ++i) {
576 		BMenuItem* item = fTranslatorMenu->ItemAt(i);
577 		if (item && item->Message()) {
578 			item->Message()->FindInt32("be:type", &imageFileType);
579 			if (fImageFileType == imageFileType) {
580 				item->SetMarked(true);
581 				MessageReceived(item->Message());
582 				break;
583 			}
584 		}
585 	}
586 }
587 
588 
589 status_t
590 ScreenshotWindow::_SaveScreenshot()
591 {
592 	if (!fScreenshot || !fLastSelectedPath)
593 		return B_ERROR;
594 
595 	BPath path(_GetDirectory());
596 
597 	if (path == NULL)
598 		return B_ERROR;
599 
600 	path.Append(fNameControl->Text());
601 
602 	BEntry entry;
603 	entry.SetTo(path.Path());
604 
605 	if (entry.Exists()) {
606 		BAlert* overwriteAlert = new BAlert(
607 			B_TRANSLATE("overwrite"),
608 			B_TRANSLATE("This file already exists.\n Are you sure would "
609 				"you like to overwrite it?"),
610 			B_TRANSLATE("Cancel"),
611 			B_TRANSLATE("Overwrite"),
612 			NULL, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
613 
614 			overwriteAlert->SetShortcut(0, B_ESCAPE);
615 
616 			if (overwriteAlert->Go() == 0)
617 				return B_CANCELED;
618 	}
619 
620 	return fUtility.Save(&fScreenshot, path.Path(), fImageFileType);
621 }
622 
623 
624 void
625 ScreenshotWindow::_ShowSettings(bool activate)
626 {
627 	if (!fSettingsWindow && !activate)
628 		return;
629 
630 	// Find a translator
631 	translator_id translator = 0;
632 	BTranslatorRoster *roster = BTranslatorRoster::Default();
633 	translator_id* translators = NULL;
634 	int32 numTranslators = 0;
635 	if (roster->GetAllTranslators(&translators, &numTranslators) != B_OK)
636 		return;
637 	bool foundTranslator = false;
638 	for (int32 x = 0; x < numTranslators; x++) {
639 		const translation_format* formats = NULL;
640 		int32 numFormats;
641 		if (roster->GetOutputFormats(translators[x], &formats,
642 			&numFormats) == B_OK) {
643 			for (int32 i = 0; i < numFormats; ++i) {
644 				if (formats[i].type == static_cast<uint32>(fImageFileType)) {
645 					translator = translators[x];
646 					foundTranslator = true;
647 					break;
648 				}
649 			}
650 		}
651 		if (foundTranslator)
652 			break;
653 	}
654 	delete [] translators;
655 	if (!foundTranslator)
656 		return;
657 
658 	// Create a window with a configuration view
659 	BView *view;
660 	BRect rect(0, 0, 239, 239);
661 
662 	status_t err = roster->MakeConfigurationView(translator, NULL, &view,
663 		&rect);
664 	if (err < B_OK || view == NULL) {
665 		BAlert *alert = new BAlert(NULL, strerror(err), "OK");
666 		alert->Go();
667 	} else {
668 		if (fSettingsWindow) {
669 			fSettingsWindow->RemoveChild(fSettingsWindow->ChildAt(0));
670 			float width, height;
671 			view->GetPreferredSize(&width, &height);
672 			fSettingsWindow->ResizeTo(width, height);
673 			fSettingsWindow->AddChild(view);
674 			if (activate)
675 				fSettingsWindow->Activate();
676 		} else {
677 			fSettingsWindow = new BWindow(rect,
678 				B_TRANSLATE("Translator Settings"),
679 				B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
680 				B_NOT_ZOOMABLE | B_NOT_RESIZABLE);
681 			fSettingsWindow->AddFilter(new QuitMessageFilter(this));
682 			fSettingsWindow->AddChild(view);
683 			fSettingsWindow->CenterOnScreen();
684 			fSettingsWindow->Show();
685 		}
686 	}
687 }
688 
689 
690 BString
691 ScreenshotWindow::_FindValidFileName(const char* name)
692 {
693 	BString baseName(name);
694 
695 	if (fExtension.Compare(""))
696 		baseName.RemoveLast(fExtension);
697 
698 	if (!fLastSelectedPath)
699 		return baseName;
700 
701 	BPath orgPath(_GetDirectory());
702 	if (orgPath == NULL)
703 		return baseName;
704 
705 	fExtension = BString(fUtility.GetFileNameExtension(fImageFileType));
706 
707 	BPath outputPath = orgPath;
708 	BString fileName;
709 	fileName << baseName << fExtension;
710 	outputPath.Append(fileName);
711 
712 	if (!BEntry(outputPath.Path()).Exists())
713 		return fileName;
714 
715 	if (baseName.FindFirst(B_TRANSLATE_NOCOLLECT(
716 			fUtility.sDefaultFileNameBase)) == 0)
717 		baseName.SetTo(fUtility.sDefaultFileNameBase);
718 
719 	BEntry entry;
720 	int32 index = 1;
721 
722 	do {
723 		fileName = "";
724 		fileName << baseName << index++ << fExtension;
725 		outputPath.SetTo(orgPath.Path());
726 		outputPath.Append(fileName);
727 		entry.SetTo(outputPath.Path());
728 	} while (entry.Exists());
729 
730 	return fileName;
731 }
732 
733 
734 BPath
735 ScreenshotWindow::_GetDirectory()
736 {
737 	BPath path;
738 
739 	BMessage* message = fLastSelectedPath->Message();
740 	const char* stringPath;
741 	if (message && message->FindString("path", &stringPath) == B_OK)
742 		path.SetTo(stringPath);
743 
744 	return path;
745 }
746 
747 
748 void
749 ScreenshotWindow::_ReadSettings()
750 {
751 	BMessage settings;
752 
753 	BPath settingsPath;
754 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath) != B_OK)
755 		return;
756 
757 	settingsPath.Append("Screenshot_settings");
758 
759 	BFile file(settingsPath.Path(), B_READ_ONLY);
760 	if (file.InitCheck() == B_OK)
761 		settings.Unflatten(&file);
762 
763 	if (settings.FindInt32("type", &fImageFileType) != B_OK)
764 		fImageFileType = B_PNG_FORMAT;
765 	settings.FindBool("includeBorder", &fIncludeBorder);
766 	settings.FindBool("includeCursor", &fIncludeCursor);
767 	settings.FindBool("grabActiveWindow", &fGrabActiveWindow);
768 	settings.FindInt64("delay", &fDelay);
769 	settings.FindString("outputFilename", &fOutputFilename);
770 
771 	_SetupOutputPathMenu(settings);
772 }
773 
774 
775 void
776 ScreenshotWindow::_WriteSettings()
777 {
778 	if (fDelayControl)
779 		fDelay = (atoi(fDelayControl->Text()) * 1000000) + 50000;
780 
781 	BMessage settings;
782 
783 	settings.AddInt32("type", fImageFileType);
784 	settings.AddBool("includeBorder", fIncludeBorder);
785 	settings.AddBool("includeCursor", fIncludeCursor);
786 	settings.AddBool("grabActiveWindow", fGrabActiveWindow);
787 	settings.AddInt64("delay", fDelay);
788 	settings.AddString("outputFilename", fOutputFilename);
789 
790 	BString path;
791 	int32 count = fOutputPathMenu->CountItems();
792 	if (count > 5) {
793 		for (int32 i = count - 3; i > count - 8 && i > 2; --i) {
794 			BMenuItem* item = fOutputPathMenu->ItemAt(i);
795 			if (item) {
796 				BMessage* msg = item->Message();
797 				if (msg && msg->FindString("path", &path) == B_OK)
798 					settings.AddString("path", path.String());
799 			}
800 		}
801 	}
802 
803 	if (fLastSelectedPath) {
804 		BMessage* msg = fLastSelectedPath->Message();
805 		if (msg && msg->FindString("path", &path) == B_OK)
806 			settings.AddString("lastSelectedPath", path.String());
807 	}
808 
809 	BPath settingsPath;
810 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath) != B_OK)
811 		return;
812 	settingsPath.Append("Screenshot_settings");
813 
814 	BFile file(settingsPath.Path(), B_CREATE_FILE | B_ERASE_FILE
815 		| B_WRITE_ONLY);
816 	if (file.InitCheck() == B_OK) {
817 		ssize_t size;
818 		settings.Flatten(&file, &size);
819 	}
820 }
821