1/*
2 * Copyright 2009, Adrien Destugues, pulkomandy@gmail.com. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "FormatSettingsView.h"
8
9#include <stdlib.h>
10
11#include <Alert.h>
12#include <Application.h>
13#include <Catalog.h>
14#include <CheckBox.h>
15#include <ControlLook.h>
16#include <DateFormat.h>
17#include <GridLayout.h>
18#include <GridLayoutBuilder.h>
19#include <GroupLayout.h>
20#include <GroupLayoutBuilder.h>
21#include <LayoutBuilder.h>
22#include <Locale.h>
23#include <MutableLocaleRoster.h>
24#include <Message.h>
25#include <Menu.h>
26#include <MenuField.h>
27#include <MenuItem.h>
28#include <NumberFormat.h>
29#include <PopUpMenu.h>
30#include <RadioButton.h>
31#include <ScrollView.h>
32#include <ScrollBar.h>
33#include <SeparatorView.h>
34#include <SpaceLayoutItem.h>
35#include <String.h>
36#include <StringView.h>
37#include <TextControl.h>
38#include <TimeFormat.h>
39#include <Window.h>
40
41#include "LocalePreflet.h"
42
43
44using BPrivate::MutableLocaleRoster;
45
46
47#undef B_TRANSLATION_CONTEXT
48#define B_TRANSLATION_CONTEXT "TimeFormatSettings"
49
50
51// #pragma mark -
52
53
54FormatSettingsView::FormatSettingsView()
55	:
56	BView("WindowsSettingsView", B_FRAME_EVENTS)
57{
58	fUseLanguageStringsCheckBox = new BCheckBox(
59		B_TRANSLATE("Use month/day-names from preferred language"),
60		new BMessage(kStringsLanguageChange));
61
62	fFilesystemTranslationCheckbox = new BCheckBox("filesystemTranslation",
63		B_TRANSLATE("Translate application and folder names"),
64		new BMessage(kMsgFilesystemTranslationChanged));
65	fFilesystemTranslationCheckbox->SetValue(
66		BLocaleRoster::Default()->IsFilesystemTranslationPreferred());
67
68	BStringView* fullDateLabel
69		= new BStringView("", B_TRANSLATE("Full format:"));
70	fullDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
71		B_ALIGN_VERTICAL_UNSET));
72	BStringView* longDateLabel
73		= new BStringView("", B_TRANSLATE("Long format:"));
74	longDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
75		B_ALIGN_VERTICAL_UNSET));
76	BStringView* mediumDateLabel
77		= new BStringView("", B_TRANSLATE("Medium format:"));
78	mediumDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
79		B_ALIGN_VERTICAL_UNSET));
80	BStringView* shortDateLabel
81		= new BStringView("", B_TRANSLATE("Short format:"));
82	shortDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
83		B_ALIGN_VERTICAL_UNSET));
84
85	fFullDateExampleView = new BStringView("", "");
86	fFullDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
87		B_ALIGN_VERTICAL_UNSET));
88	fLongDateExampleView = new BStringView("", "");
89	fLongDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
90		B_ALIGN_VERTICAL_UNSET));
91	fMediumDateExampleView = new BStringView("", "");
92	fMediumDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
93		B_ALIGN_VERTICAL_UNSET));
94	fShortDateExampleView = new BStringView("", "");
95	fShortDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
96		B_ALIGN_VERTICAL_UNSET));
97
98	f24HourRadioButton = new BRadioButton("", B_TRANSLATE("24 hour"),
99		new BMessage(kClockFormatChange));
100	f12HourRadioButton = new BRadioButton("", B_TRANSLATE("12 hour"),
101		new BMessage(kClockFormatChange));
102
103	float spacing = be_control_look->DefaultItemSpacing();
104
105	BStringView* fullTimeLabel
106		= new BStringView("", B_TRANSLATE("Full format:"));
107	fullTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
108		B_ALIGN_VERTICAL_UNSET));
109	BStringView* longTimeLabel
110		= new BStringView("", B_TRANSLATE("Long format:"));
111	longTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
112		B_ALIGN_VERTICAL_UNSET));
113	BStringView* mediumTimeLabel
114		= new BStringView("", B_TRANSLATE("Medium format:"));
115	mediumTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
116		B_ALIGN_VERTICAL_UNSET));
117	BStringView* shortTimeLabel
118		= new BStringView("", B_TRANSLATE("Short format:"));
119	shortTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
120		B_ALIGN_VERTICAL_UNSET));
121
122	fFullTimeExampleView = new BStringView("", "");
123	fFullTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
124		B_ALIGN_VERTICAL_UNSET));
125	fLongTimeExampleView = new BStringView("", "");
126	fLongTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
127		B_ALIGN_VERTICAL_UNSET));
128	fMediumTimeExampleView = new BStringView("", "");
129	fMediumTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
130		B_ALIGN_VERTICAL_UNSET));
131	fShortTimeExampleView = new BStringView("", "");
132	fShortTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
133		B_ALIGN_VERTICAL_UNSET));
134
135	BStringView* positiveNumberLabel
136		= new BStringView("", B_TRANSLATE("Positive:"));
137	positiveNumberLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
138		B_ALIGN_VERTICAL_UNSET));
139	BStringView* negativeNumberLabel
140		= new BStringView("", B_TRANSLATE("Negative:"));
141	negativeNumberLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
142		B_ALIGN_VERTICAL_UNSET));
143
144	fPositiveNumberExampleView = new BStringView("", "");
145	fPositiveNumberExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
146		B_ALIGN_VERTICAL_UNSET));
147	fNegativeNumberExampleView = new BStringView("", "");
148	fNegativeNumberExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
149		B_ALIGN_VERTICAL_UNSET));
150
151	BStringView* positiveMonetaryLabel
152		= new BStringView("", B_TRANSLATE("Positive:"));
153	positiveMonetaryLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
154		B_ALIGN_VERTICAL_UNSET));
155	BStringView* negativeMonetaryLabel
156		= new BStringView("", B_TRANSLATE("Negative:"));
157	negativeMonetaryLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
158		B_ALIGN_VERTICAL_UNSET));
159
160	fPositiveMonetaryExampleView = new BStringView("", "");
161	fPositiveMonetaryExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
162		B_ALIGN_VERTICAL_UNSET));
163	fNegativeMonetaryExampleView = new BStringView("", "");
164	fNegativeMonetaryExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
165		B_ALIGN_VERTICAL_UNSET));
166
167	Refresh(true);
168
169	fDateBox = new BBox(B_TRANSLATE("Date"));
170	fTimeBox = new BBox(B_TRANSLATE("Time"));
171	fNumberBox = new BBox(B_TRANSLATE("Numbers"));
172	fMonetaryBox = new BBox(B_TRANSLATE("Currency"));
173
174	fDateBox->SetLabel(B_TRANSLATE("Date"));
175	fTimeBox->SetLabel(B_TRANSLATE("Time"));
176	fNumberBox->SetLabel(B_TRANSLATE("Numbers"));
177	fMonetaryBox->SetLabel(B_TRANSLATE("Currency"));
178
179	fDateBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
180		.SetInsets(spacing, spacing, spacing, spacing)
181		.Add(fullDateLabel, 0, 0)
182		.Add(fFullDateExampleView, 1, 0)
183		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
184		.Add(longDateLabel, 0, 1)
185		.Add(fLongDateExampleView, 1, 1)
186		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
187		.Add(mediumDateLabel, 0, 2)
188		.Add(fMediumDateExampleView, 1, 2)
189		.Add(BSpaceLayoutItem::CreateGlue(), 2, 2)
190		.Add(shortDateLabel, 0, 3)
191		.Add(fShortDateExampleView, 1, 3)
192		.Add(BSpaceLayoutItem::CreateGlue(), 2, 3)
193		.View());
194
195	fTimeBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
196		.SetInsets(spacing, spacing, spacing, spacing)
197		.AddGroup(B_HORIZONTAL, spacing, 0, 0, 2)
198			.Add(f24HourRadioButton, 0)
199			.Add(f12HourRadioButton, 0)
200			.AddGlue()
201			.End()
202		.Add(fullTimeLabel, 0, 1)
203		.Add(fFullTimeExampleView, 1, 1)
204		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
205		.Add(longTimeLabel, 0, 2)
206		.Add(fLongTimeExampleView, 1, 2)
207		.Add(BSpaceLayoutItem::CreateGlue(), 2, 2)
208		.Add(mediumTimeLabel, 0, 3)
209		.Add(fMediumTimeExampleView, 1, 3)
210		.Add(BSpaceLayoutItem::CreateGlue(), 2, 3)
211		.Add(shortTimeLabel, 0, 4)
212		.Add(fShortTimeExampleView, 1, 4)
213		.Add(BSpaceLayoutItem::CreateGlue(), 2, 4)
214		.View());
215
216	fNumberBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
217		.SetInsets(spacing, spacing, spacing, spacing)
218		.Add(positiveNumberLabel, 0, 0)
219		.Add(fPositiveNumberExampleView, 1, 0)
220		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
221		.Add(negativeNumberLabel, 0, 1)
222		.Add(fNegativeNumberExampleView, 1, 1)
223		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
224		.View());
225
226	fMonetaryBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
227		.SetInsets(spacing, spacing, spacing, spacing)
228		.Add(positiveMonetaryLabel, 0, 0)
229		.Add(fPositiveMonetaryExampleView, 1, 0)
230		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
231		.Add(negativeMonetaryLabel, 0, 1)
232		.Add(fNegativeMonetaryExampleView, 1, 1)
233		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
234		.View());
235
236	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
237
238	BLayoutBuilder::Group<>(this, B_VERTICAL)
239		.Add(fFilesystemTranslationCheckbox)
240		.Add(fUseLanguageStringsCheckBox)
241		.Add(fDateBox)
242		.Add(fTimeBox)
243		.AddGroup(B_HORIZONTAL, spacing)
244			.Add(fNumberBox)
245			.Add(fMonetaryBox)
246			.End()
247		.AddGlue();
248}
249
250
251FormatSettingsView::~FormatSettingsView()
252{
253}
254
255
256void
257FormatSettingsView::AttachedToWindow()
258{
259	fFilesystemTranslationCheckbox->SetTarget(Window());
260	fUseLanguageStringsCheckBox->SetTarget(this);
261	f24HourRadioButton->SetTarget(this);
262	f12HourRadioButton->SetTarget(this);
263}
264
265
266void
267FormatSettingsView::MessageReceived(BMessage* message)
268{
269	switch (message->what) {
270		case B_LOCALE_CHANGED:
271		{
272			// Time updated 12/24 hour clock
273			BFormattingConventions conventions;
274			BLocale::Default()->GetFormattingConventions(&conventions);
275			if (conventions.Use24HourClock())
276				f24HourRadioButton->SetValue(B_CONTROL_ON);
277			else
278				f12HourRadioButton->SetValue(B_CONTROL_ON);
279
280			_UpdateExamples();
281			Window()->PostMessage(kMsgSettingsChanged);
282			break;
283		}
284
285		case kClockFormatChange:
286		{
287			BFormattingConventions conventions;
288			BLocale::Default()->GetFormattingConventions(&conventions);
289			conventions.SetExplicitUse24HourClock(
290				f24HourRadioButton->Value() == B_CONTROL_ON);
291			MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
292				conventions);
293
294			_UpdateExamples();
295			Window()->PostMessage(kMsgSettingsChanged);
296			break;
297		}
298
299		case kStringsLanguageChange:
300		{
301			BFormattingConventions conventions;
302			BLocale::Default()->GetFormattingConventions(&conventions);
303			conventions.SetUseStringsFromPreferredLanguage(
304				fUseLanguageStringsCheckBox->Value() ? true : false);
305			MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
306				conventions);
307
308			_UpdateExamples();
309
310			Window()->PostMessage(kMsgSettingsChanged);
311			break;
312		}
313
314		default:
315			BView::MessageReceived(message);
316	}
317}
318
319
320void
321FormatSettingsView::Revert()
322{
323	MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
324		fInitialConventions);
325
326	fFilesystemTranslationCheckbox->SetValue(fInitialTranslateNames);
327
328	_UpdateExamples();
329}
330
331
332void
333FormatSettingsView::Refresh(bool setInitial)
334{
335	BFormattingConventions conventions;
336	BLocale::Default()->GetFormattingConventions(&conventions);
337	if (setInitial) {
338		fInitialConventions = conventions;
339		fInitialTranslateNames
340			= BLocaleRoster::Default()->IsFilesystemTranslationPreferred();
341	}
342
343	if (!conventions.Use24HourClock()) {
344		f12HourRadioButton->SetValue(B_CONTROL_ON);
345		fLocaleIs24Hour = false;
346	} else {
347		f24HourRadioButton->SetValue(B_CONTROL_ON);
348		fLocaleIs24Hour = true;
349	}
350
351	fUseLanguageStringsCheckBox->SetValue(
352		conventions.UseStringsFromPreferredLanguage()
353			? B_CONTROL_ON : B_CONTROL_OFF);
354
355	_UpdateExamples();
356}
357
358
359// Return true if the Revert button should be enabled (i.e. something has been
360// changed)
361bool
362FormatSettingsView::IsReversible() const
363{
364	BFormattingConventions conventions;
365	BLocale::Default()->GetFormattingConventions(&conventions);
366
367	return (conventions != fInitialConventions)
368		|| (fFilesystemTranslationCheckbox->Value() != fInitialTranslateNames);
369}
370
371
372void
373FormatSettingsView::_UpdateExamples()
374{
375	time_t timeValue = (time_t)time(NULL);
376	BString result;
377
378	// Do NOT make these class members. We do want to recreate it everytime, as
379	// to get the updated settings from the locale roster.
380	BDateFormat dateFormat;
381	BNumberFormat numberFormat;
382	BString errorString = B_TRANSLATE("ERROR");
383	BTimeFormat timeFormat;
384
385	dateFormat.Format(result, timeValue, B_FULL_DATE_FORMAT);
386	fFullDateExampleView->SetText(result);
387
388	dateFormat.Format(result, timeValue, B_LONG_DATE_FORMAT);
389	fLongDateExampleView->SetText(result);
390
391	dateFormat.Format(result, timeValue, B_MEDIUM_DATE_FORMAT);
392	fMediumDateExampleView->SetText(result);
393
394	dateFormat.Format(result, timeValue, B_SHORT_DATE_FORMAT);
395	fShortDateExampleView->SetText(result);
396
397	timeFormat.Format(result, timeValue, B_FULL_TIME_FORMAT);
398	fFullTimeExampleView->SetText(result);
399
400	timeFormat.Format(result, timeValue, B_LONG_TIME_FORMAT);
401	fLongTimeExampleView->SetText(result);
402
403	timeFormat.Format(result, timeValue, B_MEDIUM_TIME_FORMAT);
404	fMediumTimeExampleView->SetText(result);
405
406	timeFormat.Format(result, timeValue, B_SHORT_TIME_FORMAT);
407	fShortTimeExampleView->SetText(result);
408
409	status_t status = numberFormat.Format(result, 1234.56);
410	if (status == B_OK)
411		fPositiveNumberExampleView->SetText(result);
412	else
413		fPositiveNumberExampleView->SetText(errorString);
414
415	status = numberFormat.Format(result, -1234.56);
416	if (status == B_OK)
417		fNegativeNumberExampleView->SetText(result);
418	else
419		fNegativeNumberExampleView->SetText(errorString);
420
421	status = numberFormat.FormatMonetary(result, 1234.56);
422	if (status == B_OK)
423		fPositiveMonetaryExampleView->SetText(result);
424	else
425		fPositiveMonetaryExampleView->SetText(errorString);
426
427	status = numberFormat.FormatMonetary(result, -1234.56);
428	if (status == B_OK)
429		fNegativeMonetaryExampleView->SetText(result);
430	else
431		fNegativeMonetaryExampleView->SetText(errorString);
432}
433