xref: /haiku/src/preferences/locale/FormatSettingsView.cpp (revision 7d6915b4d08ffe728cd38af02843d5e98ddfe0db)
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 	BStringView* fullDateLabel
63 		= new BStringView("", B_TRANSLATE("Full format:"));
64 	fullDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
65 		B_ALIGN_VERTICAL_UNSET));
66 	BStringView* longDateLabel
67 		= new BStringView("", B_TRANSLATE("Long format:"));
68 	longDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
69 		B_ALIGN_VERTICAL_UNSET));
70 	BStringView* mediumDateLabel
71 		= new BStringView("", B_TRANSLATE("Medium format:"));
72 	mediumDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
73 		B_ALIGN_VERTICAL_UNSET));
74 	BStringView* shortDateLabel
75 		= new BStringView("", B_TRANSLATE("Short format:"));
76 	shortDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
77 		B_ALIGN_VERTICAL_UNSET));
78 
79 	fFullDateExampleView = new BStringView("", "");
80 	fFullDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
81 		B_ALIGN_VERTICAL_UNSET));
82 	fLongDateExampleView = new BStringView("", "");
83 	fLongDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
84 		B_ALIGN_VERTICAL_UNSET));
85 	fMediumDateExampleView = new BStringView("", "");
86 	fMediumDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
87 		B_ALIGN_VERTICAL_UNSET));
88 	fShortDateExampleView = new BStringView("", "");
89 	fShortDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
90 		B_ALIGN_VERTICAL_UNSET));
91 
92 	f24HourRadioButton = new BRadioButton("", B_TRANSLATE("24 hour"),
93 		new BMessage(kClockFormatChange));
94 	f12HourRadioButton = new BRadioButton("", B_TRANSLATE("12 hour"),
95 		new BMessage(kClockFormatChange));
96 
97 	float spacing = be_control_look->DefaultItemSpacing();
98 
99 	BStringView* fullTimeLabel
100 		= new BStringView("", B_TRANSLATE("Full format:"));
101 	fullTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
102 		B_ALIGN_VERTICAL_UNSET));
103 	BStringView* longTimeLabel
104 		= new BStringView("", B_TRANSLATE("Long format:"));
105 	longTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
106 		B_ALIGN_VERTICAL_UNSET));
107 	BStringView* mediumTimeLabel
108 		= new BStringView("", B_TRANSLATE("Medium format:"));
109 	mediumTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
110 		B_ALIGN_VERTICAL_UNSET));
111 	BStringView* shortTimeLabel
112 		= new BStringView("", B_TRANSLATE("Short format:"));
113 	shortTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
114 		B_ALIGN_VERTICAL_UNSET));
115 
116 	fFullTimeExampleView = new BStringView("", "");
117 	fFullTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
118 		B_ALIGN_VERTICAL_UNSET));
119 	fLongTimeExampleView = new BStringView("", "");
120 	fLongTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
121 		B_ALIGN_VERTICAL_UNSET));
122 	fMediumTimeExampleView = new BStringView("", "");
123 	fMediumTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
124 		B_ALIGN_VERTICAL_UNSET));
125 	fShortTimeExampleView = new BStringView("", "");
126 	fShortTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
127 		B_ALIGN_VERTICAL_UNSET));
128 
129 	BStringView* positiveNumberLabel
130 		= new BStringView("", B_TRANSLATE("Positive:"));
131 	positiveNumberLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
132 		B_ALIGN_VERTICAL_UNSET));
133 	BStringView* negativeNumberLabel
134 		= new BStringView("", B_TRANSLATE("Negative:"));
135 	negativeNumberLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
136 		B_ALIGN_VERTICAL_UNSET));
137 
138 	fPositiveNumberExampleView = new BStringView("", "");
139 	fPositiveNumberExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
140 		B_ALIGN_VERTICAL_UNSET));
141 	fNegativeNumberExampleView = new BStringView("", "");
142 	fNegativeNumberExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
143 		B_ALIGN_VERTICAL_UNSET));
144 
145 	BStringView* positiveMonetaryLabel
146 		= new BStringView("", B_TRANSLATE("Positive:"));
147 	positiveMonetaryLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
148 		B_ALIGN_VERTICAL_UNSET));
149 	BStringView* negativeMonetaryLabel
150 		= new BStringView("", B_TRANSLATE("Negative:"));
151 	negativeMonetaryLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
152 		B_ALIGN_VERTICAL_UNSET));
153 
154 	fPositiveMonetaryExampleView = new BStringView("", "");
155 	fPositiveMonetaryExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
156 		B_ALIGN_VERTICAL_UNSET));
157 	fNegativeMonetaryExampleView = new BStringView("", "");
158 	fNegativeMonetaryExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
159 		B_ALIGN_VERTICAL_UNSET));
160 
161 	Refresh(true);
162 
163 	fDateBox = new BBox(B_TRANSLATE("Date"));
164 	fTimeBox = new BBox(B_TRANSLATE("Time"));
165 	fNumberBox = new BBox(B_TRANSLATE("Numbers"));
166 	fMonetaryBox = new BBox(B_TRANSLATE("Currency"));
167 
168 	fDateBox->SetLabel(B_TRANSLATE("Date"));
169 	fTimeBox->SetLabel(B_TRANSLATE("Time"));
170 	fNumberBox->SetLabel(B_TRANSLATE("Numbers"));
171 	fMonetaryBox->SetLabel(B_TRANSLATE("Currency"));
172 
173 	fDateBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
174 		.SetInsets(spacing, spacing, spacing, spacing)
175 		.Add(fullDateLabel, 0, 0)
176 		.Add(fFullDateExampleView, 1, 0)
177 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
178 		.Add(longDateLabel, 0, 1)
179 		.Add(fLongDateExampleView, 1, 1)
180 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
181 		.Add(mediumDateLabel, 0, 2)
182 		.Add(fMediumDateExampleView, 1, 2)
183 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 2)
184 		.Add(shortDateLabel, 0, 3)
185 		.Add(fShortDateExampleView, 1, 3)
186 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 3)
187 		.View());
188 
189 	fTimeBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
190 		.SetInsets(spacing, spacing, spacing, spacing)
191 		.AddGroup(B_HORIZONTAL, spacing, 0, 0, 2)
192 			.Add(f24HourRadioButton, 0)
193 			.Add(f12HourRadioButton, 0)
194 			.AddGlue()
195 			.End()
196 		.Add(fullTimeLabel, 0, 1)
197 		.Add(fFullTimeExampleView, 1, 1)
198 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
199 		.Add(longTimeLabel, 0, 2)
200 		.Add(fLongTimeExampleView, 1, 2)
201 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 2)
202 		.Add(mediumTimeLabel, 0, 3)
203 		.Add(fMediumTimeExampleView, 1, 3)
204 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 3)
205 		.Add(shortTimeLabel, 0, 4)
206 		.Add(fShortTimeExampleView, 1, 4)
207 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 4)
208 		.View());
209 
210 	fNumberBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
211 		.SetInsets(spacing, spacing, spacing, spacing)
212 		.Add(positiveNumberLabel, 0, 0)
213 		.Add(fPositiveNumberExampleView, 1, 0)
214 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
215 		.Add(negativeNumberLabel, 0, 1)
216 		.Add(fNegativeNumberExampleView, 1, 1)
217 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
218 		.View());
219 
220 	fMonetaryBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
221 		.SetInsets(spacing, spacing, spacing, spacing)
222 		.Add(positiveMonetaryLabel, 0, 0)
223 		.Add(fPositiveMonetaryExampleView, 1, 0)
224 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
225 		.Add(negativeMonetaryLabel, 0, 1)
226 		.Add(fNegativeMonetaryExampleView, 1, 1)
227 		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
228 		.View());
229 
230 	BGroupLayout* rootLayout = new BGroupLayout(B_VERTICAL, spacing);
231 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
232 	SetLayout(rootLayout);
233 	BLayoutBuilder::Group<>(rootLayout)
234 		.Add(fUseLanguageStringsCheckBox)
235 		.Add(fDateBox)
236 		.Add(fTimeBox)
237 		.AddGroup(B_HORIZONTAL, spacing)
238 			.Add(fNumberBox)
239 			.Add(fMonetaryBox)
240 			.AddGlue()
241 			.End()
242 		.AddGlue();
243 }
244 
245 
246 FormatSettingsView::~FormatSettingsView()
247 {
248 }
249 
250 
251 void
252 FormatSettingsView::AttachedToWindow()
253 {
254 	fUseLanguageStringsCheckBox->SetTarget(this);
255 	f24HourRadioButton->SetTarget(this);
256 	f12HourRadioButton->SetTarget(this);
257 }
258 
259 
260 void
261 FormatSettingsView::MessageReceived(BMessage* message)
262 {
263 	switch (message->what) {
264 		case B_LOCALE_CHANGED:
265 		{
266 			// Time updated 12/24 hour clock
267 			BFormattingConventions conventions;
268 			BLocale::Default()->GetFormattingConventions(&conventions);
269 			if (conventions.Use24HourClock())
270 				f24HourRadioButton->SetValue(B_CONTROL_ON);
271 			else
272 				f12HourRadioButton->SetValue(B_CONTROL_ON);
273 
274 			_UpdateExamples();
275 			Window()->PostMessage(kMsgSettingsChanged);
276 			break;
277 		}
278 
279 		case kClockFormatChange:
280 		{
281 			BFormattingConventions conventions;
282 			BLocale::Default()->GetFormattingConventions(&conventions);
283 			conventions.SetExplicitUse24HourClock(
284 				f24HourRadioButton->Value() == B_CONTROL_ON);
285 			MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
286 				conventions);
287 
288 			_UpdateExamples();
289 			Window()->PostMessage(kMsgSettingsChanged);
290 			break;
291 		}
292 
293 		case kStringsLanguageChange:
294 		{
295 			BFormattingConventions conventions;
296 			BLocale::Default()->GetFormattingConventions(&conventions);
297 			conventions.SetUseStringsFromPreferredLanguage(
298 				fUseLanguageStringsCheckBox->Value() ? true : false);
299 			MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
300 				conventions);
301 
302 			_UpdateExamples();
303 
304 			Window()->PostMessage(kMsgSettingsChanged);
305 			break;
306 		}
307 
308 		default:
309 			BView::MessageReceived(message);
310 	}
311 }
312 
313 
314 void
315 FormatSettingsView::Revert()
316 {
317 	MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
318 		fInitialConventions);
319 
320 	_UpdateExamples();
321 }
322 
323 
324 void
325 FormatSettingsView::Refresh(bool setInitial)
326 {
327 	BFormattingConventions conventions;
328 	BLocale::Default()->GetFormattingConventions(&conventions);
329 	if (setInitial)
330 		fInitialConventions = conventions;
331 
332 	if (!conventions.Use24HourClock()) {
333 		f12HourRadioButton->SetValue(B_CONTROL_ON);
334 		fLocaleIs24Hour = false;
335 	} else {
336 		f24HourRadioButton->SetValue(B_CONTROL_ON);
337 		fLocaleIs24Hour = true;
338 	}
339 
340 	fUseLanguageStringsCheckBox->SetValue(
341 		conventions.UseStringsFromPreferredLanguage()
342 			? B_CONTROL_ON : B_CONTROL_OFF);
343 
344 	_UpdateExamples();
345 }
346 
347 
348 // Return true if the Revert button should be enabled (i.e. something has been
349 // changed)
350 bool
351 FormatSettingsView::IsReversible() const
352 {
353 	BFormattingConventions conventions;
354 	BLocale::Default()->GetFormattingConventions(&conventions);
355 
356 	return conventions != fInitialConventions;
357 }
358 
359 
360 void
361 FormatSettingsView::_UpdateExamples()
362 {
363 	time_t timeValue = (time_t)time(NULL);
364 	BString result;
365 
366 	// Do NOT make these class members. We do want to recreate it everytime, as
367 	// to get the updated settings from the locale roster.
368 	BDateFormat dateFormat;
369 	BTimeFormat timeFormat;
370 	BNumberFormat numberFormat;
371 
372 	dateFormat.Format(result, timeValue, B_FULL_DATE_FORMAT);
373 	fFullDateExampleView->SetText(result);
374 
375 	dateFormat.Format(result, timeValue, B_LONG_DATE_FORMAT);
376 	fLongDateExampleView->SetText(result);
377 
378 	dateFormat.Format(result, timeValue, B_MEDIUM_DATE_FORMAT);
379 	fMediumDateExampleView->SetText(result);
380 
381 	dateFormat.Format(result, timeValue, B_SHORT_DATE_FORMAT);
382 	fShortDateExampleView->SetText(result);
383 
384 	timeFormat.Format(result, timeValue, B_FULL_TIME_FORMAT);
385 	fFullTimeExampleView->SetText(result);
386 
387 	timeFormat.Format(result, timeValue, B_LONG_TIME_FORMAT);
388 	fLongTimeExampleView->SetText(result);
389 
390 	timeFormat.Format(result, timeValue, B_MEDIUM_TIME_FORMAT);
391 	fMediumTimeExampleView->SetText(result);
392 
393 	timeFormat.Format(result, timeValue, B_SHORT_TIME_FORMAT);
394 	fShortTimeExampleView->SetText(result);
395 
396 	status_t status = numberFormat.Format(result, 1234.5678);
397 	if (status == B_OK)
398 		fPositiveNumberExampleView->SetText(result);
399 	else
400 		fPositiveNumberExampleView->SetText("ERROR");
401 
402 	status = numberFormat.Format(result, -1234.5678);
403 	if (status == B_OK)
404 		fNegativeNumberExampleView->SetText(result);
405 	else
406 		fNegativeNumberExampleView->SetText("ERROR");
407 
408 	status = numberFormat.FormatMonetary(result, 1234.56);
409 	if (status == B_OK)
410 		fPositiveMonetaryExampleView->SetText(result);
411 	else
412 		fPositiveMonetaryExampleView->SetText("ERROR");
413 
414 	status = numberFormat.FormatMonetary(result, -1234.56);
415 	if (status == B_OK)
416 		fNegativeMonetaryExampleView->SetText(result);
417 	else
418 		fNegativeMonetaryExampleView->SetText("ERROR");
419 }
420