xref: /haiku/src/preferences/locale/FormatSettingsView.cpp (revision 9c274ccd098ee3b2674efde2d1582d4e0c68d878)
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 
44 using BPrivate::MutableLocaleRoster;
45 
46 
47 #undef B_TRANSLATION_CONTEXT
48 #define B_TRANSLATION_CONTEXT "TimeFormatSettings"
49 
50 
51 // #pragma mark -
52 
53 
54 FormatSettingsView::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 
251 FormatSettingsView::~FormatSettingsView()
252 {
253 }
254 
255 
256 void
257 FormatSettingsView::AttachedToWindow()
258 {
259 	fFilesystemTranslationCheckbox->SetTarget(Window());
260 	fUseLanguageStringsCheckBox->SetTarget(this);
261 	f24HourRadioButton->SetTarget(this);
262 	f12HourRadioButton->SetTarget(this);
263 }
264 
265 
266 void
267 FormatSettingsView::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 
320 void
321 FormatSettingsView::Revert()
322 {
323 	MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
324 		fInitialConventions);
325 
326 	fFilesystemTranslationCheckbox->SetValue(fInitialTranslateNames);
327 
328 	_UpdateExamples();
329 }
330 
331 
332 void
333 FormatSettingsView::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)
361 bool
362 FormatSettingsView::IsReversible() const
363 {
364 	BFormattingConventions conventions;
365 	BLocale::Default()->GetFormattingConventions(&conventions);
366 
367 	return (conventions != fInitialConventions)
368 		|| (fFilesystemTranslationCheckbox->Value() != fInitialTranslateNames);
369 }
370 
371 
372 void
373 FormatSettingsView::_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