xref: /haiku/src/preferences/locale/FormatSettingsView.cpp (revision 675ffabd70492a962f8c0288a32208c22ce5de18)
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 <stdio.h>
10 #include <stdlib.h>
11 
12 #include <Alert.h>
13 #include <Application.h>
14 #include <Catalog.h>
15 #include <CheckBox.h>
16 #include <ControlLook.h>
17 #include <Country.h>
18 #include <GroupLayout.h>
19 #include <GroupLayoutBuilder.h>
20 #include <LayoutBuilder.h>
21 #include <Locale.h>
22 #include <MutableLocaleRoster.h>
23 #include <Message.h>
24 #include <Menu.h>
25 #include <MenuField.h>
26 #include <MenuItem.h>
27 #include <PopUpMenu.h>
28 #include <RadioButton.h>
29 #include <ScrollView.h>
30 #include <ScrollBar.h>
31 #include <SeparatorView.h>
32 #include <String.h>
33 #include <StringView.h>
34 #include <TextControl.h>
35 #include <Window.h>
36 
37 #include "LocalePreflet.h"
38 
39 
40 using BPrivate::gMutableLocaleRoster;
41 
42 
43 #undef B_TRANSLATE_CONTEXT
44 #define B_TRANSLATE_CONTEXT "TimeFormatSettings"
45 
46 
47 class DateMenuItem: public BMenuItem {
48 public:
49 	DateMenuItem(const char* label, const char* code, BMenuField* field)
50 		:
51 		BMenuItem(label, _MenuMessage(code, field))
52 	{
53 		fIcuCode = code;
54 	}
55 
56 	const BString& ICUCode() const
57 	{
58 		return fIcuCode;
59 	}
60 
61 private:
62 	static BMessage* _MenuMessage(const char* format, BMenuField* field)
63 	{
64 		BMessage* msg = new BMessage(kMenuMessage);
65 		msg->AddPointer("dest", field);
66 		msg->AddString("format", format);
67 
68 		return msg;
69 	}
70 
71 private:
72 	BString			fIcuCode;
73 };
74 
75 
76 void
77 CreateDateMenu(BMenuField** field, bool longFormat = true)
78 {
79 	BMenu* menu = new BMenu("");
80 	*field = new BMenuField("", menu);
81 
82 	BPopUpMenu* dayMenu = new BPopUpMenu(B_TRANSLATE("Day"));
83 	// Not all available ICU settings are listed here. It's possible to add some
84 	// other things if you ever need.
85 	menu->AddItem(dayMenu);
86 		dayMenu->AddItem(new DateMenuItem(
87 			B_TRANSLATE("Day in month"), "d", *field));
88 		dayMenu->AddItem(new DateMenuItem(
89 			B_TRANSLATE("Day in month (2 digits)"), "dd", *field));
90 		/*
91 		dayMenu->AddItem(new DateMenuItem(B_TRANSLATE("Day in year"),
92 			"D", *field));
93 		dayMenu->AddItem(new DateMenuItem(B_TRANSLATE("Day in year (2 digits)"),
94 			"DD", *field));
95 		dayMenu->AddItem(new DateMenuItem(B_TRANSLATE("Day in year (3 digits)"),
96 			"DDD", *field));
97 		*/
98 		dayMenu->AddItem(new DateMenuItem(
99 			B_TRANSLATE("Day of week"), "e", *field));
100 		// dayMenu->AddItem(new DateMenuItem("Day of week (short text)", "eee",
101 		//	*field));
102 		// dayMenu->AddItem(new DateMenuItem("Day of week (full text)", "eeee",
103 		//	*field));
104 		dayMenu->AddItem(new DateMenuItem(
105 			B_TRANSLATE("Day of week (short name)"), "E", *field));
106 		dayMenu->AddItem(new DateMenuItem(
107 			B_TRANSLATE("Day of week (name)"), "EEEE", *field));
108 		dayMenu->AddItem(new DateMenuItem(
109 			B_TRANSLATE("Day of week in month"), "F", *field));
110 		// dayMenu->AddItem(new DateMenuItem(
111 		//	B_TRANSLATE("julian day"), "g", *field));
112 		// dayMenu->AddItem(new BMenuItem("c", msg));
113 	BPopUpMenu* monthMenu = new BPopUpMenu(B_TRANSLATE("Month"));
114 	menu->AddItem(monthMenu);
115 		monthMenu->AddItem(new DateMenuItem(
116 			B_TRANSLATE("Month number"), "M", *field));
117 		monthMenu->AddItem(new DateMenuItem(
118 			B_TRANSLATE("Month number (2 digits)"), "MM", *field));
119 		monthMenu->AddItem(new DateMenuItem(
120 			B_TRANSLATE("Month name"), "MMMM", *field));
121 		// monthMenu->AddItem(new DateMenuItem("L", "L", *field));
122 	BPopUpMenu* yearMenu = new BPopUpMenu(B_TRANSLATE("Year"));
123 	menu->AddItem(yearMenu);
124 		// And here is some ICU kludge... sorry about that.
125 		if (longFormat)
126 			yearMenu->AddItem(new DateMenuItem(
127 				B_TRANSLATE("Year"), "y", *field));
128 		else {
129 			yearMenu->AddItem(new DateMenuItem(
130 				B_TRANSLATE("Year (4 digits)"), "yyyy", *field));
131 		}
132 		yearMenu->AddItem(new DateMenuItem(
133 			B_TRANSLATE("Year (2 digits)"), "yy", *field));
134 		// yearMenu->AddItem(new DateMenuItem("Y", "Y", *field));
135 		// yearMenu->AddItem(new DateMenuItem("u", "u", *field));
136 }
137 
138 
139 bool
140 IsSpecialDateChar(char charToTest)
141 {
142 	static const char* specials = "dDeEFgMLyYu";
143 	for (int i = 0; i < 11; i++)
144 		if (charToTest == specials[i])
145 			return true;
146 	return false;
147 }
148 
149 // #pragma mark -
150 
151 
152 FormatView::FormatView(const BLocale& locale)
153 	:
154 	BView("WindowsSettingsView", B_FRAME_EVENTS),
155 	fLocale(locale)
156 {
157 	fLongDateExampleView = new BStringView("", "");
158 
159 	for (int i = 0; i < 4; i++) {
160 		CreateDateMenu(&fLongDateMenu[i]);
161 		fLongDateSeparator[i] = new BTextControl("", "", "",
162 			new BMessage(kSettingsContentsModified));
163 		fLongDateSeparator[i]->SetModificationMessage(
164 			new BMessage(kSettingsContentsModified));
165 	}
166 
167 	fShortDateExampleView = new BStringView("", "");
168 
169 	for (int i = 0; i < 3; i++) {
170 		CreateDateMenu(&fDateMenu[i], false);
171 	}
172 
173 	BPopUpMenu* menu = new BPopUpMenu(B_TRANSLATE("Separator"));
174 	menu->AddItem(new BMenuItem(B_TRANSLATE("None"),
175 		new BMessage(kSettingsContentsModified)));
176 	menu->AddItem(new BMenuItem(B_TRANSLATE("Space"),
177 		new BMessage(kSettingsContentsModified)));
178 	menu->AddItem(new BMenuItem("-", new BMessage(kSettingsContentsModified)));
179 	menu->AddItem(new BMenuItem("/", new BMessage(kSettingsContentsModified)));
180 	menu->AddItem(new BMenuItem("\\", new BMessage(kSettingsContentsModified)));
181 	menu->AddItem(new BMenuItem(".", new BMessage(kSettingsContentsModified)));
182 
183 	fSeparatorMenuField = new BMenuField(B_TRANSLATE("Separator:"), menu);
184 
185 	f24HrRadioButton = new BRadioButton("", B_TRANSLATE("24 hour"),
186 		new BMessage(kClockFormatChange));
187 
188 	f12HrRadioButton = new BRadioButton("", B_TRANSLATE("12 hour"),
189 		new BMessage(kClockFormatChange));
190 
191 	fLocale.GetTimeFormat(fOriginalTimeFormat, false);
192 	fLocale.GetTimeFormat(fOriginalLongTimeFormat, true);
193 	if (fOriginalTimeFormat.FindFirst("a") != B_ERROR) {
194 		f12HrRadioButton->SetValue(B_CONTROL_ON);
195 		fLocaleIs24Hr = false;
196 	} else {
197 		f24HrRadioButton->SetValue(B_CONTROL_ON);
198 		fLocaleIs24Hr = true;
199 	}
200 
201 	float spacing = be_control_look->DefaultItemSpacing();
202 
203 	fLongTimeExampleView = new BStringView("", "");
204 	fShortTimeExampleView = new BStringView("", "");
205 
206 	fNumberFormatExampleView = new BStringView("", "");
207 
208 	BTextControl* numberThousand = new BTextControl("",
209 		B_TRANSLATE("Thousand separator: "), "",
210 		new BMessage(kSettingsContentsModified));
211 	BTextControl* numberDecimal = new BTextControl("",
212 		B_TRANSLATE("Decimal separator: "),	"",
213 		new BMessage(kSettingsContentsModified));
214 	// TODO number of decimal digits (spinbox ?)
215 	BCheckBox* numberLeadingZero = new BCheckBox("", B_TRANSLATE("Leading 0"),
216 		new BMessage(kSettingsContentsModified));
217 	BTextControl* numberList = new BTextControl("",
218 		B_TRANSLATE("List separator: "), "",
219 		new BMessage(kSettingsContentsModified));
220 	// Unit system (US/Metric) (radio)
221 
222 	fCurrencySymbolView = new BTextControl("",
223 		B_TRANSLATE("Currency symbol:"), "",
224 		new BMessage(kSettingsContentsModified));
225 	menu = new BPopUpMenu(B_TRANSLATE("Negative marker"));
226 	menu->AddItem(new BMenuItem("-", new BMessage(kSettingsContentsModified)));
227 	menu->AddItem(new BMenuItem("()", new BMessage(kSettingsContentsModified)));
228 
229 	BMenuField* currencyNegative = new BMenuField(
230 		B_TRANSLATE("Negative marker:"), menu);
231 
232 	BTextControl* currencyDecimal = new BTextControl("",
233 		B_TRANSLATE("Decimal separator: "), "",
234 		new BMessage(kSettingsContentsModified));
235 	BCheckBox* currencyLeadingZero = new BCheckBox("",
236 		B_TRANSLATE("Leading 0"), new BMessage(kSettingsContentsModified));
237 
238 	fCurrencySymbolBefore = new BRadioButton("CurrencySymbolPosition",
239 		B_TRANSLATE("Before"), new BMessage(kSettingsContentsModified));
240 
241 	fCurrencySymbolAfter = new BRadioButton("CurrencySymbolPosition",
242 		B_TRANSLATE("After"), new BMessage(kSettingsContentsModified));
243 
244 	fMonetaryView = new BStringView("", "");
245 
246 	_UpdateExamples();
247 	_ParseDateFormat();
248 	_ParseCurrencyFormat();
249 
250 	fDateBox = new BBox(B_TRANSLATE("Date"));
251 	fTimeBox = new BBox(B_TRANSLATE("Time"));
252 	fNumbersBox = new BBox(B_TRANSLATE("Numbers"));
253 	fCurrencyBox = new BBox(B_TRANSLATE("Currency"));
254 
255 	fDateBox->SetLabel(B_TRANSLATE("Date"));
256 	fTimeBox->SetLabel(B_TRANSLATE("Time"));
257 	fNumbersBox->SetLabel(B_TRANSLATE("Numbers"));
258 	fCurrencyBox->SetLabel(B_TRANSLATE("Currency"));
259 
260 	fDateBox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing / 2)
261 		.SetInsets(spacing, spacing, spacing, spacing)
262 		.AddGroup(B_HORIZONTAL, spacing)
263 			.Add(new BStringView("", B_TRANSLATE("Long format:")))
264 			.Add(fLongDateExampleView)
265 			.AddGlue()
266 			.End()
267 		.AddGroup(B_HORIZONTAL, spacing)
268 			.Add(fLongDateMenu[0])
269 			.Add(fLongDateSeparator[0])
270 			.End()
271 		.AddGroup(B_HORIZONTAL, spacing)
272 			.Add(fLongDateMenu[1])
273 			.Add(fLongDateSeparator[1])
274 			.End()
275 		.AddGroup(B_HORIZONTAL, spacing)
276 			.Add(fLongDateMenu[2])
277 			.Add(fLongDateSeparator[2])
278 			.End()
279 		.AddGroup(B_HORIZONTAL, spacing)
280 			.Add(fLongDateMenu[3])
281 			.Add(fLongDateSeparator[3])
282 			.End()
283 		.AddGroup(B_HORIZONTAL, spacing)
284 			.Add(new BStringView("", B_TRANSLATE("Short format:")))
285 			.Add(fShortDateExampleView)
286 			.AddGlue()
287 			.End()
288 		.Add(fDateMenu[0])
289 		.Add(fDateMenu[1])
290 		.Add(fDateMenu[2])
291 		.View());
292 
293 	fTimeBox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing / 2)
294 		.SetInsets(spacing, spacing, spacing, spacing)
295 		.AddGroup(B_HORIZONTAL, spacing)
296 			.Add(new BStringView("", B_TRANSLATE("Long format:")))
297 			.Add(fLongTimeExampleView)
298 			.AddGlue()
299 			.End()
300 		.AddGroup(B_HORIZONTAL, spacing)
301 			.Add(new BStringView("", B_TRANSLATE("Short format:")))
302 			.Add(fShortTimeExampleView)
303 			.AddGlue()
304 			.End()
305 		.AddGroup(B_HORIZONTAL, spacing)
306 			.Add(f24HrRadioButton)
307 			.Add(f12HrRadioButton)
308 			.AddGlue()
309 			.End()
310 		.View());
311 
312 	fNumbersBox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing / 2)
313 		.SetInsets(spacing, spacing, spacing, spacing)
314 			.AddGroup(B_HORIZONTAL, spacing)
315 				.Add(new BStringView("", B_TRANSLATE("Example:")))
316 				.Add(fNumberFormatExampleView)
317 				.AddGlue()
318 				.End()
319 			.Add(numberThousand)
320 			.Add(numberDecimal)
321 			.Add(numberLeadingZero)
322 			.Add(numberList)
323 			.View());
324 
325 	fCurrencyBox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing / 2)
326 		.SetInsets(spacing, spacing, spacing, spacing)
327 		.Add(fMonetaryView)
328 		.Add(fCurrencySymbolView)
329 		.AddGroup(B_HORIZONTAL, spacing)
330 			.AddGlue()
331 			.Add(fCurrencySymbolBefore)
332 			.Add(fCurrencySymbolAfter)
333 			.End()
334 		.Add(currencyNegative)
335 		.Add(currencyDecimal)
336 		.Add(currencyLeadingZero)
337 		.View());
338 
339 
340 	BGroupLayout* rootLayout = new BGroupLayout(B_HORIZONTAL, spacing);
341 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
342 	SetLayout(rootLayout);
343 	BLayoutBuilder::Group<>(rootLayout)
344 		.AddGroup(B_VERTICAL, spacing)
345 			.Add(fDateBox)
346 			.Add(fTimeBox)
347 			.AddGlue()
348 			.End()
349 		.AddGroup(B_VERTICAL, spacing)
350 			.Add(fNumbersBox)
351 			.Add(fCurrencyBox)
352 			.AddGlue();
353 }
354 
355 
356 FormatView::~FormatView()
357 {
358 	gMutableLocaleRoster->SetDefaultLocale(fLocale);
359 }
360 
361 
362 void
363 FormatView::AttachedToWindow()
364 {
365 	f24HrRadioButton->SetTarget(this);
366 	f12HrRadioButton->SetTarget(this);
367 
368 	for (int j = 0; j < 4; j++) {
369 		for (int i = 0; i < fLongDateMenu[j]->Menu()->CountItems(); i++)
370 			fLongDateMenu[j]->Menu()->SubmenuAt(i)->SetTargetForItems(this);
371 		fLongDateSeparator[j]->SetTarget(this);
372 	}
373 
374 	for (int j = 0; j < 3; j++) {
375 		for (int i = 0; i < fDateMenu[j]->Menu()->CountItems(); i++)
376 			fDateMenu[j]->Menu()->SubmenuAt(i)->SetTargetForItems(this);
377 	}
378 
379 	fSeparatorMenuField->Menu()->SetTargetForItems(this);
380 }
381 
382 
383 void
384 FormatView::MessageReceived(BMessage* message)
385 {
386 	switch (message->what) {
387 		case kMenuMessage:
388 		{
389 			// Update one of the dropdown menus
390 			void* pointerFromMessage;
391 			message->FindPointer("dest", &pointerFromMessage);
392 			BMenuField* menuField
393 			= static_cast<BMenuField*>(pointerFromMessage);
394 			BString format;
395 			message->FindString("format", &format);
396 
397 			for (int i = 0; i < 4; i++) {
398 				if (fLongDateMenu[i]==menuField) {
399 					fLongDateString[i] = format;
400 					break;
401 				}
402 			}
403 
404 			for (int i = 0; i < 3; i++) {
405 				if (fDateMenu[i]==menuField) {
406 					fDateString[i] = format;
407 					break;
408 				}
409 			}
410 
411 			message->FindPointer("source", &pointerFromMessage);
412 			BMenuItem* menuItem = static_cast<BMenuItem*>(pointerFromMessage);
413 
414 			menuField->MenuItem()->SetLabel(menuItem->Label());
415 
416 			_UpdateLongDateFormatString();
417 		}
418 		// pass trough
419 		case kSettingsContentsModified:
420 			{
421 				int32 separator = 0;
422 				BMenuItem* item = fSeparatorMenuField->Menu()->FindMarked();
423 				if (item) {
424 					separator = fSeparatorMenuField->Menu()->IndexOf(item);
425 					if (separator >= 0)
426 						// settings.SetTimeFormatSeparator(
427 						//	(FormatSeparator)separator);
428 						;
429 				}
430 
431 				// Make the notification message and send it to the tracker:
432 				BMessage notificationMessage;
433 				notificationMessage.AddInt32("TimeFormatSeparator", separator);
434 				notificationMessage.AddBool("24HrClock",
435 					f24HrRadioButton->Value() == 1);
436 
437 				_UpdateExamples();
438 
439 				Window()->PostMessage(kSettingsContentsModified);
440 				break;
441 			}
442 
443 		case kClockFormatChange:
444 		{
445 			BMessage newMessage(kMsgSettingsChanged);
446 
447 			BString timeFormat;
448 			timeFormat = fOriginalTimeFormat;
449 			if (f24HrRadioButton->Value() == 1) {
450 				if (!fLocaleIs24Hr) {
451 					timeFormat.ReplaceAll("h", "H");
452 					timeFormat.ReplaceAll("k", "K");
453 					timeFormat.RemoveAll(" a");
454 					timeFormat.RemoveAll("a");
455 				}
456 			} else {
457 				if (fLocaleIs24Hr && timeFormat.FindFirst("a") == B_ERROR) {
458 					timeFormat.ReplaceAll("K", "k");
459 					timeFormat.ReplaceAll("H", "h");
460 					timeFormat.Append(" a");
461 				}
462 			}
463 			fLocale.SetTimeFormat(timeFormat.String(), false);
464 			newMessage.AddString("shortTimeFormat", timeFormat);
465 
466 			timeFormat = fOriginalLongTimeFormat;
467 			if (f24HrRadioButton->Value() == 1) {
468 				if (!fLocaleIs24Hr) {
469 					timeFormat.ReplaceAll("h", "H");
470 					timeFormat.ReplaceAll("k", "K");
471 					timeFormat.RemoveAll(" a");
472 					timeFormat.RemoveAll("a");
473 				}
474 			} else {
475 				if (fLocaleIs24Hr && timeFormat.FindFirst("a") == B_ERROR) {
476 					timeFormat.ReplaceAll("K", "k");
477 					timeFormat.ReplaceAll("H", "h");
478 					timeFormat.Append(" a");
479 				}
480 			}
481 			fLocale.SetTimeFormat(timeFormat.String(), true);
482 			newMessage.AddString("longTimeFormat", timeFormat);
483 			_UpdateExamples();
484 			Window()->PostMessage(kSettingsContentsModified);
485 			be_app_messenger.SendMessage(&newMessage);
486 			break;
487 		}
488 
489 		default:
490 			BView::MessageReceived(message);
491 	}
492 }
493 
494 
495 void
496 FormatView::SetDefaults()
497 {
498 	/*
499 	TrackerSettings settings;
500 
501 	settings.SetTimeFormatSeparator(kSlashSeparator);
502 	settings.SetDateOrderFormat(kMDYFormat);
503 	settings.SetClockTo24Hr(false);
504 	*/
505 
506 	fLocale = *be_locale;
507 		// We work on a copy of the default country and set the changes when
508 		// closing the preflet
509 	_UpdateExamples();
510 	_SendNotices();
511 }
512 
513 
514 bool
515 FormatView::IsDefaultable() const
516 {
517 	/*
518 	TrackerSettings settings;
519 
520 	return settings.TimeFormatSeparator() != kSlashSeparator
521 		|| settings.DateOrderFormat() != kMDYFormat
522 		|| settings.ClockIs24Hr() != false;
523 	*/
524 	return true;
525 }
526 
527 
528 void
529 FormatView::Revert()
530 {
531 	/*
532 	TrackerSettings settings;
533 
534 	settings.SetTimeFormatSeparator(fSeparator);
535 	settings.SetDateOrderFormat(fFormat);
536 	settings.SetClockTo24Hr(f24HrClock);
537 	*/
538 
539 	// ShowCurrentSettings();
540 	_SendNotices();
541 }
542 
543 
544 void
545 FormatView::SetLocale(const BLocale& locale)
546 {
547 	fLocale = locale;
548 
549 	fLocale.GetTimeFormat(fOriginalTimeFormat, false);
550 	fLocale.GetTimeFormat(fOriginalLongTimeFormat, true);
551 
552 	if (fOriginalTimeFormat.FindFirst("a") != B_ERROR) {
553 		f12HrRadioButton->SetValue(B_CONTROL_ON);
554 		fLocaleIs24Hr = false;
555 	} else {
556 		f24HrRadioButton->SetValue(B_CONTROL_ON);
557 		fLocaleIs24Hr = true;
558 	}
559 
560 	/*
561 	FormatSeparator separator = settings.TimeFormatSeparator();
562 
563 	if (separator >= kNoSeparator && separator < kSeparatorsEnd)
564 		fSeparatorMenuField->Menu()->ItemAt((int32)separator)->SetMarked(true);
565 	*/
566 
567 	_UpdateExamples();
568 	_ParseDateFormat();
569 	_ParseCurrencyFormat();
570 }
571 
572 
573 void
574 FormatView::RecordRevertSettings()
575 {
576 	/*
577 	f24HrClock = settings.ClockIs24Hr();
578 	fSeparator = settings.TimeFormatSeparator();
579 	fFormat = settings.DateOrderFormat();
580 	*/
581 }
582 
583 
584 // Return true if the Revert button should be enabled (ie some setting was
585 // changed)
586 bool
587 FormatView::IsRevertable() const
588 {
589 	FormatSeparator separator;
590 
591 	BMenuItem* item = fSeparatorMenuField->Menu()->FindMarked();
592 	if (item) {
593 		int32 index = fSeparatorMenuField->Menu()->IndexOf(item);
594 		if (index >= 0)
595 			separator = (FormatSeparator)index;
596 		else
597 			return true;
598 	} else
599 		return true;
600 
601 	// TODO generate ICU string and compare to the initial one
602 	BString dateFormat ;
603 		// fYMDRadioButton->Value() ? kYMDFormat :
604 		//(fDMYRadioButton->Value() ? kDMYFormat : kMDYFormat);
605 
606 	return f24HrClock != (f24HrRadioButton->Value() > 0)
607 		|| separator != fSeparator
608 		|| dateFormat != fDateFormat;
609 }
610 
611 
612 void
613 FormatView::_UpdateExamples()
614 {
615 	time_t timeValue = (time_t)time(NULL);
616 	BString timeFormat;
617 
618 	fLocale.FormatDate(&timeFormat, timeValue, true);
619 	fLongDateExampleView->SetText(timeFormat);
620 
621 	fLocale.FormatDate(&timeFormat, timeValue, false);
622 	fShortDateExampleView->SetText(timeFormat);
623 
624 	fLocale.FormatTime(&timeFormat, timeValue, true);
625 	fLongTimeExampleView->SetText(timeFormat);
626 
627 	fLocale.FormatTime(&timeFormat, timeValue, false);
628 	fShortTimeExampleView->SetText(timeFormat);
629 
630 	status_t Error = fLocale.FormatNumber(&timeFormat, 1234.5678);
631 	if (Error == B_OK)
632 		fNumberFormatExampleView->SetText(timeFormat);
633 	else
634 		fNumberFormatExampleView->SetText("ERROR");
635 }
636 
637 
638 void
639 FormatView::_SendNotices()
640 {
641 	// Make the notification message and send it to the tracker:
642 	/*
643 	BMessage notificationMessage;
644 	notificationMessage.AddInt32("TimeFormatSeparator",
645 		(int32)settings.TimeFormatSeparator());
646 	notificationMessage.AddInt32("DateOrderFormat",
647 		(int32)settings.DateOrderFormat());
648 	notificationMessage.AddBool("24HrClock", settings.ClockIs24Hr());
649 	tracker->SendNotices(kDateFormatChanged, &notificationMessage);
650 	*/
651 }
652 
653 
654 void
655 FormatView::_ParseCurrencyFormat()
656 {
657 	BString currencySample;
658 	int* fieldPos = NULL;
659 	int fieldCount;
660 	BNumberElement* fieldID = NULL;
661 	if (fLocale.FormatMonetary(&currencySample, fieldPos, fieldID, fieldCount,
662 			-1234.56) != B_OK) {
663 		fMonetaryView->SetText("ERROR");
664 		return;
665 	}
666 
667 	fMonetaryView->SetText(currencySample);
668 
669 	for (int i = 0; i < fieldCount; i++) {
670 		BString currentSymbol;
671 		currentSymbol.AppendChars(currencySample.CharAt(fieldPos[i]&0xFFFF),
672 			(fieldPos[i]>>16) - (fieldPos[i]&0xFFFF));
673 		switch (fieldID[i]) {
674 			case B_NUMBER_ELEMENT_CURRENCY:
675 				fCurrencySymbolView->SetText(currentSymbol);
676 				if (i > fieldCount / 2)
677 					fCurrencySymbolAfter->SetValue(1);
678 				else
679 					fCurrencySymbolBefore->SetValue(1);
680 				break;
681 			default:
682 				break;
683 		}
684 	}
685 
686 	free(fieldPos);
687 	free(fieldID);
688 }
689 
690 
691 //! Get the date format from ICU and set the date fields accordingly
692 void
693 FormatView::_ParseDateFormat()
694 {
695 	// TODO parse the short date too
696 	BString dateFormatString;
697 	fLocale.GetDateFormat(dateFormatString, true);
698 	const char* dateFormat = dateFormatString.String();
699 
700 	// Travel through the string and parse it
701 	const char* parsePointer = dateFormat;
702 	const char* fieldBegin = dateFormat;
703 
704 	for (int i = 0; i < 4; i++)
705 	{
706 		fieldBegin = parsePointer;
707 		while (*parsePointer == *(parsePointer + 1)) parsePointer++ ;
708 		parsePointer++;
709 		BString str;
710 		str.Append(fieldBegin, parsePointer - fieldBegin);
711 
712 		fLongDateString[i] = str;
713 
714 		BMenu* subMenu;
715 		bool isFound = false;
716 		for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
717 			subMenu = fLongDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
718 			BMenuItem* item;
719 			for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
720 					itemIndex++) {
721 				if (static_cast<DateMenuItem*>(item)->ICUCode() == str) {
722 					item->SetMarked(true);
723 					fLongDateMenu[i]->MenuItem()->SetLabel(item->Label());
724 					isFound = true;
725 				} else
726 					item->SetMarked(false);
727 			}
728 		}
729 
730 		if (!isFound)
731 			fLongDateMenu[i]->MenuItem()->SetLabel(str.Append("*"));
732 
733 		fieldBegin = parsePointer;
734 		while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0'
735 				&& *(parsePointer - 1) >= 0) {
736 			if (*parsePointer == '\'') {
737 				parsePointer++;
738 				while (*parsePointer != '\'') parsePointer++;
739 			}
740 			parsePointer++;
741 		}
742 		str.Truncate(0);
743 		str.Append(fieldBegin, parsePointer - fieldBegin);
744 		fLongDateSeparator[i]->SetText(str);
745 	}
746 
747 	// Short date is a bit more tricky, we want to extract the separator
748 	fLocale.GetDateFormat(dateFormatString, false);
749 	dateFormat = dateFormatString.String();
750 
751 	// Travel trough the string and parse it
752 	parsePointer = dateFormat;
753 	fieldBegin = dateFormat;
754 
755 	for (int i = 0; i < 3; i++) {
756 		fieldBegin = parsePointer;
757 		while (*parsePointer == *(parsePointer + 1)) parsePointer++ ;
758 		parsePointer++;
759 		BString str;
760 		str.Append(fieldBegin, parsePointer - fieldBegin);
761 
762 		fLongDateString[i] = str;
763 
764 		BMenu* subMenu;
765 		bool isFound = false;
766 		for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
767 			subMenu = fDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
768 			BMenuItem* item;
769 			for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
770 					itemIndex++) {
771 				if (static_cast<DateMenuItem*>(item)->ICUCode() == str) {
772 					item->SetMarked(true);
773 					fDateMenu[i]->MenuItem()->SetLabel(item->Label());
774 					isFound = true;
775 				} else
776 					item->SetMarked(false);
777 			}
778 		}
779 
780 		if (!isFound) {
781 			fDateMenu[i]->MenuItem()->SetLabel(
782 				str.Append(B_TRANSLATE(" (unknown format)")));
783 		}
784 
785 		fieldBegin = parsePointer;
786 		while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0'
787 				&& *(parsePointer - 1) >= 0) {
788 			if (*parsePointer == '\'') {
789 				parsePointer++;
790 				while (*parsePointer != '\'') parsePointer++;
791 			}
792 			parsePointer++;
793 		}
794 		if (parsePointer - fieldBegin > 0) {
795 			str.Truncate(0);
796 			str.Append(fieldBegin, parsePointer - fieldBegin);
797 			fSeparatorMenuField->MenuItem()->SetLabel(str);
798 		}
799 	}
800 }
801 
802 
803 void
804 FormatView::_UpdateLongDateFormatString()
805 {
806 	BString newDateFormat;
807 
808 	for (int i = 0; i < 4; i++) {
809 		newDateFormat.Append(fLongDateString[i]);
810 		newDateFormat.Append(fLongDateSeparator[i]->Text());
811 	}
812 
813 	// TODO save this in the settings preflet and make the roster load it back
814 	fLocale.SetDateFormat(newDateFormat.String());
815 
816 	newDateFormat.Truncate(0);
817 
818 	newDateFormat.Append(fDateString[0]);
819 	newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
820 	newDateFormat.Append(fDateString[1]);
821 	newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
822 	newDateFormat.Append(fDateString[2]);
823 
824 	// TODO save this in the settings preflet and make the roster load it back
825 	fLocale.SetDateFormat(newDateFormat.String(), false);
826 }
827