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