xref: /haiku/src/preferences/locale/FormatSettingsView.cpp (revision e0ef64750f3169cd634bb2f7a001e22488b05231)
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 #include "Locale.h"
9 
10 #include <Alert.h>
11 #include <Application.h>
12 #include <Catalog.h>
13 #include <CheckBox.h>
14 #include <ControlLook.h>
15 #include <Country.h>
16 #include <GroupLayout.h>
17 #include <GroupLayoutBuilder.h>
18 #include <LayoutBuilder.h>
19 #include <Locale.h>
20 #include <MutableLocaleRoster.h>
21 #include <Message.h>
22 #include <Menu.h>
23 #include <MenuField.h>
24 #include <MenuItem.h>
25 #include <PopUpMenu.h>
26 #include <RadioButton.h>
27 #include <ScrollView.h>
28 #include <ScrollBar.h>
29 #include <SeparatorView.h>
30 #include <String.h>
31 #include <StringView.h>
32 #include <TextControl.h>
33 #include <Window.h>
34 
35 
36 using BPrivate::gMutableLocaleRoster;
37 
38 
39 #undef B_TRANSLATE_CONTEXT
40 #define B_TRANSLATE_CONTEXT "TimeFormatSettings"
41 
42 
43 class DateMenuItem: public BMenuItem {
44 public:
45 	DateMenuItem(const char* label, const char* code, BMenuField* field)
46 		:
47 		BMenuItem(label, _MenuMessage(code, field))
48 	{
49 		fIcuCode = code;
50 	}
51 
52 	const BString& ICUCode() const
53 	{
54 		return fIcuCode;
55 	}
56 
57 private:
58 	static BMessage* _MenuMessage(const char* format, BMenuField* field)
59 	{
60 		BMessage* msg = new BMessage(kMenuMessage);
61 		msg->AddPointer("dest", field);
62 		msg->AddString("format", format);
63 
64 		return msg;
65 	}
66 
67 private:
68 	BString			fIcuCode;
69 };
70 
71 
72 void
73 CreateDateMenu(BMenuField** field, bool longFormat = true)
74 {
75 	BMenu* menu = new BMenu("");
76 	*field = new BMenuField("", menu);
77 
78 	BPopUpMenu* dayMenu = new BPopUpMenu(B_TRANSLATE("Day"));
79 	// Not all available ICU settings are listed here. It's possible to add some
80 	// other things if you ever need.
81 	menu->AddItem(dayMenu);
82 		dayMenu->AddItem(new DateMenuItem(
83 			B_TRANSLATE("Day in month"), "d", *field));
84 		dayMenu->AddItem(new DateMenuItem(
85 			B_TRANSLATE("Day in month (2 digits)"), "dd", *field));
86 		/*
87 		dayMenu->AddItem(new DateMenuItem(B_TRANSLATE("Day in year"),
88 			"D", *field));
89 		dayMenu->AddItem(new DateMenuItem(B_TRANSLATE("Day in year (2 digits)"),
90 			 "DD", *field));
91 		dayMenu->AddItem(new DateMenuItem(B_TRANSLATE("Day in year (3 digits)"),
92 			"DDD", *field));
93 		*/
94 		dayMenu->AddItem(new DateMenuItem(
95 			B_TRANSLATE("Day of week"), "e", *field));
96 		// dayMenu->AddItem(new DateMenuItem("Day of week (short text)", "eee",
97 		//	*field));
98 		// dayMenu->AddItem(new DateMenuItem("Day of week (full text)", "eeee",
99 		//	*field));
100 		dayMenu->AddItem(new DateMenuItem(
101 			B_TRANSLATE("Day of week (short name)"), "E", *field));
102 		dayMenu->AddItem(new DateMenuItem(
103 			B_TRANSLATE("Day of week (name)"), "EEEE", *field));
104 		dayMenu->AddItem(new DateMenuItem(
105 			B_TRANSLATE("Day of week in month"), "F", *field));
106 		// dayMenu->AddItem(new DateMenuItem(
107 		//	B_TRANSLATE("julian day"), "g", *field));
108 		// dayMenu->AddItem(new BMenuItem("c", msg));
109 	BPopUpMenu* monthMenu = new BPopUpMenu(B_TRANSLATE("Month"));
110 	menu->AddItem(monthMenu);
111 		monthMenu->AddItem(new DateMenuItem(
112 			B_TRANSLATE("Month number"), "M", *field));
113 		monthMenu->AddItem(new DateMenuItem(
114 			B_TRANSLATE("Month number (2 digits)"), "MM", *field));
115 		monthMenu->AddItem(new DateMenuItem(
116 			B_TRANSLATE("Month name"), "MMMM", *field));
117 		// monthMenu->AddItem(new DateMenuItem("L", "L", *field));
118 	BPopUpMenu* yearMenu = new BPopUpMenu(B_TRANSLATE("Year"));
119 	menu->AddItem(yearMenu);
120 		// And here is some ICU kludge... sorry about that.
121 		if (longFormat)
122 			yearMenu->AddItem(new DateMenuItem(
123 				B_TRANSLATE("Year"), "y", *field));
124 		else {
125 			yearMenu->AddItem(new DateMenuItem(
126 				B_TRANSLATE("Year (4 digits)"), "yyyy", *field));
127 		}
128 		yearMenu->AddItem(new DateMenuItem(
129 			B_TRANSLATE("Year (2 digits)"), "yy", *field));
130 		// yearMenu->AddItem(new DateMenuItem("Y", "Y", *field));
131 		// yearMenu->AddItem(new DateMenuItem("u", "u", *field));
132 }
133 
134 
135 bool
136 IsSpecialDateChar(char charToTest)
137 {
138 	static const char* specials = "dDeEFgMLyYu";
139 	for (int i = 0; i < 11; i++)
140 		if (charToTest == specials[i])
141 			return true;
142 	return false;
143 }
144 
145 // #pragma mark -
146 
147 
148 FormatView::FormatView(const BLocale& locale)
149 	:
150 	BView("WindowsSettingsView", B_FRAME_EVENTS),
151 	fLocale(locale)
152 {
153 	fLongDateExampleView = new BStringView("", "");
154 
155 	for (int i = 0; i < 4; i++) {
156 		CreateDateMenu(&fLongDateMenu[i]);
157 		fLongDateSeparator[i] = new BTextControl("", "", "",
158 			new BMessage(kSettingsContentsModified));
159 		fLongDateSeparator[i]->SetModificationMessage(
160 			new BMessage(kSettingsContentsModified));
161 	}
162 
163 	fShortDateExampleView = new BStringView("", "");
164 
165 	for (int i = 0; i < 3; i++) {
166 		CreateDateMenu(&fDateMenu[i], false);
167 	}
168 
169 	BPopUpMenu* menu = new BPopUpMenu(B_TRANSLATE("Separator"));
170 	menu->AddItem(new BMenuItem(B_TRANSLATE("None"),
171 		new BMessage(kSettingsContentsModified)));
172 	menu->AddItem(new BMenuItem(B_TRANSLATE("Space"),
173 		new BMessage(kSettingsContentsModified)));
174 	menu->AddItem(new BMenuItem("-", new BMessage(kSettingsContentsModified)));
175 	menu->AddItem(new BMenuItem("/", new BMessage(kSettingsContentsModified)));
176 	menu->AddItem(new BMenuItem("\\", new BMessage(kSettingsContentsModified)));
177 	menu->AddItem(new BMenuItem(".", new BMessage(kSettingsContentsModified)));
178 
179 	fSeparatorMenuField = new BMenuField(B_TRANSLATE("Separator:"), menu);
180 
181 	f24HrRadioButton = new BRadioButton("", B_TRANSLATE("24 hour"),
182 		new BMessage(kClockFormatChange));
183 
184 	f12HrRadioButton = new BRadioButton("", B_TRANSLATE("12 hour"),
185 		new BMessage(kClockFormatChange));
186 
187 	fLocale.GetTimeFormat(fOriginalTimeFormat, false);
188 	fLocale.GetTimeFormat(fOriginalLongTimeFormat, true);
189 	if (fOriginalTimeFormat.FindFirst("a") != B_ERROR) {
190 		f12HrRadioButton->SetValue(B_CONTROL_ON);
191 		fLocaleIs24Hr = false;
192 	} else {
193 		f24HrRadioButton->SetValue(B_CONTROL_ON);
194 		fLocaleIs24Hr = true;
195 	}
196 
197 	float spacing = be_control_look->DefaultItemSpacing();
198 
199 	fLongTimeExampleView = new BStringView("", "");
200 	fShortTimeExampleView = new BStringView("", "");
201 
202 	fNumberFormatExampleView = new BStringView("", "");
203 
204 	BTextControl* numberThousand = new BTextControl("",
205 		B_TRANSLATE("Thousand separator: "), "",
206 		new BMessage(kSettingsContentsModified));
207 	BTextControl* numberDecimal = new BTextControl("",
208 		B_TRANSLATE("Decimal separator: "),	"",
209 		new BMessage(kSettingsContentsModified));
210 	// TODO number of decimal digits (spinbox ?)
211 	BCheckBox* numberLeadingZero = new BCheckBox("", B_TRANSLATE("Leading 0"),
212 		new BMessage(kSettingsContentsModified));
213 	BTextControl* numberList = new BTextControl("",
214 		B_TRANSLATE("List separator: "), "",
215 		new BMessage(kSettingsContentsModified));
216 	// Unit system (US/Metric) (radio)
217 
218 	BTextControl* currencySymbol = new BTextControl("",
219 		B_TRANSLATE("Currency symbol:"), "",
220 		new BMessage(kSettingsContentsModified));
221 	menu = new BPopUpMenu(B_TRANSLATE("Negative marker"));
222 	menu->AddItem(new BMenuItem("-", new BMessage(kSettingsContentsModified)));
223 	menu->AddItem(new BMenuItem("()", new BMessage(kSettingsContentsModified)));
224 
225 	BMenuField* currencyNegative = new BMenuField(
226 		B_TRANSLATE("Negative marker:"), menu);
227 
228 	BTextControl* currencyDecimal = new BTextControl("",
229 		B_TRANSLATE("Decimal separator: "), "",
230 		new BMessage(kSettingsContentsModified));
231 	BCheckBox* currencyLeadingZero = new BCheckBox("",
232 		B_TRANSLATE("Leading 0"), new BMessage(kSettingsContentsModified));
233 
234 	BBox* formatBox = new BBox("Symbol position");
235 	formatBox->SetLabel(B_TRANSLATE("Symbol position"));
236 
237 	BRadioButton* beforeRadioButton = new BRadioButton("",
238 		B_TRANSLATE("Before"), new BMessage(kSettingsContentsModified));
239 
240 	BRadioButton* afterRadioButton = new BRadioButton("",
241 		B_TRANSLATE("After"), new BMessage(kSettingsContentsModified));
242 
243 	formatBox->AddChild(BGroupLayoutBuilder(B_VERTICAL)
244 		.Add(beforeRadioButton)
245 		.Add(afterRadioButton)
246 		.SetInsets(spacing, 0, spacing, 0)
247 		.TopView());
248 
249 	_UpdateExamples();
250 	_ParseDateFormat();
251 
252 	fDateBox = new BBox(B_TRANSLATE("Date"));
253 	fTimeBox = new BBox(B_TRANSLATE("Time"));
254 	fNumbersBox = new BBox(B_TRANSLATE("Numbers"));
255 	fCurrencyBox = new BBox(B_TRANSLATE("Currency"));
256 
257 	fDateBox->SetLabel(B_TRANSLATE("Date"));
258 	fTimeBox->SetLabel(B_TRANSLATE("Time"));
259 	fNumbersBox->SetLabel(B_TRANSLATE("Numbers"));
260 	fCurrencyBox->SetLabel(B_TRANSLATE("Currency"));
261 
262 	fDateBox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing / 2)
263 		.SetInsets(spacing, spacing, spacing, spacing)
264 		.AddGroup(B_HORIZONTAL, spacing)
265 			.Add(new BStringView("", B_TRANSLATE("Long format:")))
266 			.Add(fLongDateExampleView)
267 			.AddGlue()
268 			.End()
269 		.AddGroup(B_HORIZONTAL, spacing)
270 			.Add(fLongDateMenu[0])
271 			.Add(fLongDateSeparator[0])
272 			.End()
273 		.AddGroup(B_HORIZONTAL, spacing)
274 			.Add(fLongDateMenu[1])
275 			.Add(fLongDateSeparator[1])
276 			.End()
277 		.AddGroup(B_HORIZONTAL, spacing)
278 			.Add(fLongDateMenu[2])
279 			.Add(fLongDateSeparator[2])
280 			.End()
281 		.AddGroup(B_HORIZONTAL, spacing)
282 			.Add(fLongDateMenu[3])
283 			.Add(fLongDateSeparator[3])
284 			.End()
285 		.AddGroup(B_HORIZONTAL, spacing)
286 			.Add(new BStringView("", B_TRANSLATE("Short format:")))
287 			.Add(fShortDateExampleView)
288 			.AddGlue()
289 			.End()
290 		.Add(fDateMenu[0])
291 		.Add(fDateMenu[1])
292 		.Add(fDateMenu[2])
293 		.View());
294 
295 	fTimeBox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing / 2)
296 		.SetInsets(spacing, spacing, spacing, spacing)
297 		.AddGroup(B_HORIZONTAL, spacing)
298 			.Add(new BStringView("", B_TRANSLATE("Long format:")))
299 			.Add(fLongTimeExampleView)
300 			.AddGlue()
301 			.End()
302 		.AddGroup(B_HORIZONTAL, spacing)
303 			.Add(new BStringView("", B_TRANSLATE("Short format:")))
304 			.Add(fShortTimeExampleView)
305 			.AddGlue()
306 			.End()
307 		.AddGroup(B_HORIZONTAL, spacing)
308 			.Add(f24HrRadioButton)
309 			.Add(f12HrRadioButton)
310 			.AddGlue()
311 			.End()
312 		.View());
313 
314 	fNumbersBox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing / 2)
315 		.SetInsets(spacing, spacing, spacing, spacing)
316 			.AddGroup(B_HORIZONTAL, spacing)
317 				.Add(new BStringView("", B_TRANSLATE("Example:")))
318 				.Add(fNumberFormatExampleView)
319 				.AddGlue()
320 				.End()
321 			.Add(numberThousand)
322 			.Add(numberDecimal)
323 			.Add(numberLeadingZero)
324 			.Add(numberList)
325 			.View());
326 
327 	fCurrencyBox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing / 2)
328 		.SetInsets(spacing, spacing, spacing, spacing)
329 		.Add(currencySymbol)
330 		.Add(currencyNegative)
331 		.Add(currencyDecimal)
332 		.Add(currencyLeadingZero)
333 		.AddGroup(B_HORIZONTAL, spacing)
334 			.Add(formatBox)
335 			.AddGlue()
336 			.End()
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 	BLocale defaultLocale;
507 	be_locale_roster->GetDefaultLocale(&defaultLocale);
508 	fLocale = defaultLocale;
509 		// We work on a copy of the default country and set the changes when
510 		// closing the preflet
511 	_UpdateExamples();
512 	_SendNotices();
513 }
514 
515 
516 bool
517 FormatView::IsDefaultable() const
518 {
519 	/*
520 	TrackerSettings settings;
521 
522 	return settings.TimeFormatSeparator() != kSlashSeparator
523 		|| settings.DateOrderFormat() != kMDYFormat
524 		|| settings.ClockIs24Hr() != false;
525 	*/
526 	return true;
527 }
528 
529 
530 void
531 FormatView::Revert()
532 {
533 	/*
534 	TrackerSettings settings;
535 
536 	settings.SetTimeFormatSeparator(fSeparator);
537 	settings.SetDateOrderFormat(fFormat);
538 	settings.SetClockTo24Hr(f24HrClock);
539 	*/
540 
541 	// ShowCurrentSettings();
542 	_SendNotices();
543 }
544 
545 
546 void
547 FormatView::SetLocale(const BLocale& locale)
548 {
549 	fLocale = locale;
550 
551 	fLocale.GetTimeFormat(fOriginalTimeFormat, false);
552 	fLocale.GetTimeFormat(fOriginalLongTimeFormat, true);
553 
554 	if (fOriginalTimeFormat.FindFirst("a") != B_ERROR) {
555 		f12HrRadioButton->SetValue(B_CONTROL_ON);
556 		fLocaleIs24Hr = false;
557 	} else {
558 		f24HrRadioButton->SetValue(B_CONTROL_ON);
559 		fLocaleIs24Hr = true;
560 	}
561 
562 	/*
563 	FormatSeparator separator = settings.TimeFormatSeparator();
564 
565 	if (separator >= kNoSeparator && separator < kSeparatorsEnd)
566 		fSeparatorMenuField->Menu()->ItemAt((int32)separator)->SetMarked(true);
567 	*/
568 	_UpdateExamples();
569 	_ParseDateFormat();
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 //! Get the date format from ICU and set the date fields accordingly
655 void
656 FormatView::_ParseDateFormat()
657 {
658 	// TODO parse the short date too
659 	BString dateFormatString;
660 	fLocale.GetDateFormat(dateFormatString, true);
661 	const char* dateFormat = dateFormatString.String();
662 
663 	// Travel through the string and parse it
664 	const char* parsePointer = dateFormat;
665 	const char* fieldBegin = dateFormat;
666 
667 	for (int i = 0; i < 4; i++)
668 	{
669 		fieldBegin = parsePointer;
670 		while (*parsePointer == *(parsePointer + 1)) parsePointer++ ;
671 		parsePointer++;
672 		BString str;
673 		str.Append(fieldBegin, parsePointer - fieldBegin);
674 
675 		fLongDateString[i] = str;
676 
677 		BMenu* subMenu;
678 		bool isFound = false;
679 		for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
680 			subMenu = fLongDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
681 			BMenuItem* item;
682 			for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
683 					itemIndex++) {
684 				if (static_cast<DateMenuItem*>(item)->ICUCode() == str) {
685 					item->SetMarked(true);
686 					fLongDateMenu[i]->MenuItem()->SetLabel(item->Label());
687 					isFound = true;
688 				} else
689 					item->SetMarked(false);
690 			}
691 		}
692 
693 		if (!isFound)
694 			fLongDateMenu[i]->MenuItem()->SetLabel(str.Append("*"));
695 
696 		fieldBegin = parsePointer;
697 		while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0'
698 				&& *(parsePointer - 1) >= 0) {
699 			if (*parsePointer == '\'') {
700 				parsePointer++;
701 				while (*parsePointer != '\'') parsePointer++;
702 			}
703 			parsePointer++;
704 		}
705 		str.Truncate(0);
706 		str.Append(fieldBegin, parsePointer - fieldBegin);
707 		fLongDateSeparator[i]->SetText(str);
708 	}
709 
710 	// Short date is a bit more tricky, we want to extract the separator
711 	fLocale.GetDateFormat(dateFormatString, false);
712 	dateFormat = dateFormatString.String();
713 
714 	// Travel trough the string and parse it
715 	parsePointer = dateFormat;
716 	fieldBegin = dateFormat;
717 
718 	for (int i = 0; i < 3; i++) {
719 		fieldBegin = parsePointer;
720 		while (*parsePointer == *(parsePointer + 1)) parsePointer++ ;
721 		parsePointer++;
722 		BString str;
723 		str.Append(fieldBegin, parsePointer - fieldBegin);
724 
725 		fLongDateString[i] = str;
726 
727 		BMenu* subMenu;
728 		bool isFound = false;
729 		for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
730 			subMenu = fDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
731 			BMenuItem* item;
732 			for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
733 					itemIndex++) {
734 				if (static_cast<DateMenuItem*>(item)->ICUCode() == str) {
735 					item->SetMarked(true);
736 					fDateMenu[i]->MenuItem()->SetLabel(item->Label());
737 					isFound = true;
738 				} else
739 					item->SetMarked(false);
740 			}
741 		}
742 
743 		if (!isFound) {
744 			fDateMenu[i]->MenuItem()->SetLabel(
745 				str.Append(B_TRANSLATE(" (unknown format)")));
746 		}
747 
748 		fieldBegin = parsePointer;
749 		while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0'
750 				&& *(parsePointer - 1) >= 0) {
751 			if (*parsePointer == '\'') {
752 				parsePointer++;
753 				while (*parsePointer != '\'') parsePointer++;
754 			}
755 			parsePointer++;
756 		}
757 		if (parsePointer - fieldBegin > 0) {
758 			str.Truncate(0);
759 			str.Append(fieldBegin, parsePointer - fieldBegin);
760 			fSeparatorMenuField->MenuItem()->SetLabel(str);
761 		}
762 	}
763 }
764 
765 
766 void
767 FormatView::_UpdateLongDateFormatString()
768 {
769 	BString newDateFormat;
770 
771 	for (int i = 0; i < 4; i++) {
772 		newDateFormat.Append(fLongDateString[i]);
773 		newDateFormat.Append(fLongDateSeparator[i]->Text());
774 	}
775 
776 	// TODO save this in the settings preflet and make the roster load it back
777 	fLocale.SetDateFormat(newDateFormat.String());
778 
779 	newDateFormat.Truncate(0);
780 
781 	newDateFormat.Append(fDateString[0]);
782 	newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
783 	newDateFormat.Append(fDateString[1]);
784 	newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
785 	newDateFormat.Append(fDateString[2]);
786 
787 	// TODO save this in the settings preflet and make the roster load it back
788 	fLocale.SetDateFormat(newDateFormat.String(), false);
789 }
790