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