xref: /haiku/src/preferences/locale/FormatSettingsView.cpp (revision 56187df6ebd9d1fb16bf954fce8df0999e9e3048)
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 			// fall through
418 		}
419 
420 		case kSettingsContentsModified:
421 		{
422 			int32 separator = 0;
423 			BMenuItem* item = fSeparatorMenuField->Menu()->FindMarked();
424 			if (item) {
425 				separator = fSeparatorMenuField->Menu()->IndexOf(item);
426 				if (separator >= 0)
427 					// settings.SetTimeFormatSeparator(
428 					//	(FormatSeparator)separator);
429 					;
430 			}
431 
432 			// Make the notification message and send it to the tracker:
433 			BMessage notificationMessage;
434 			notificationMessage.AddInt32("TimeFormatSeparator", separator);
435 			notificationMessage.AddBool("24HrClock",
436 				f24HrRadioButton->Value() == 1);
437 
438 			_UpdateExamples();
439 
440 			Window()->PostMessage(kSettingsContentsModified);
441 			break;
442 		}
443 
444 		case kClockFormatChange:
445 		{
446 			BMessage newMessage(kMsgSettingsChanged);
447 
448 			BString timeFormat;
449 			timeFormat = fOriginalTimeFormat;
450 			if (f24HrRadioButton->Value() == 1) {
451 				if (!fLocaleIs24Hr) {
452 					timeFormat.ReplaceAll("h", "H");
453 					timeFormat.ReplaceAll("k", "K");
454 					timeFormat.RemoveAll(" a");
455 					timeFormat.RemoveAll("a");
456 				}
457 			} else {
458 				if (fLocaleIs24Hr && timeFormat.FindFirst("a") == B_ERROR) {
459 					timeFormat.ReplaceAll("K", "k");
460 					timeFormat.ReplaceAll("H", "h");
461 					timeFormat.Append(" a");
462 				}
463 			}
464 			fLocale.SetTimeFormat(timeFormat.String(), false);
465 			newMessage.AddString("shortTimeFormat", timeFormat);
466 
467 			timeFormat = fOriginalLongTimeFormat;
468 			if (f24HrRadioButton->Value() == 1) {
469 				if (!fLocaleIs24Hr) {
470 					timeFormat.ReplaceAll("h", "H");
471 					timeFormat.ReplaceAll("k", "K");
472 					timeFormat.RemoveAll(" a");
473 					timeFormat.RemoveAll("a");
474 				}
475 			} else {
476 				if (fLocaleIs24Hr && timeFormat.FindFirst("a") == B_ERROR) {
477 					timeFormat.ReplaceAll("K", "k");
478 					timeFormat.ReplaceAll("H", "h");
479 					timeFormat.Append(" a");
480 				}
481 			}
482 			fLocale.SetTimeFormat(timeFormat.String(), true);
483 			newMessage.AddString("longTimeFormat", timeFormat);
484 			_UpdateExamples();
485 			Window()->PostMessage(kSettingsContentsModified);
486 			be_app_messenger.SendMessage(&newMessage);
487 			break;
488 		}
489 
490 		default:
491 			BView::MessageReceived(message);
492 	}
493 }
494 
495 
496 void
497 FormatView::Revert()
498 {
499 	/*
500 	TrackerSettings settings;
501 
502 	settings.SetTimeFormatSeparator(fSeparator);
503 	settings.SetDateOrderFormat(fFormat);
504 	settings.SetClockTo24Hr(f24HrClock);
505 	*/
506 
507 	// ShowCurrentSettings();
508 	_SendNotices();
509 }
510 
511 
512 void
513 FormatView::SetLocale(const BLocale& locale)
514 {
515 	fLocale = locale;
516 
517 	fLocale.GetTimeFormat(fOriginalTimeFormat, false);
518 	fLocale.GetTimeFormat(fOriginalLongTimeFormat, true);
519 
520 	if (fOriginalTimeFormat.FindFirst("a") != B_ERROR) {
521 		f12HrRadioButton->SetValue(B_CONTROL_ON);
522 		fLocaleIs24Hr = false;
523 	} else {
524 		f24HrRadioButton->SetValue(B_CONTROL_ON);
525 		fLocaleIs24Hr = true;
526 	}
527 
528 	/*
529 	FormatSeparator separator = settings.TimeFormatSeparator();
530 
531 	if (separator >= kNoSeparator && separator < kSeparatorsEnd)
532 		fSeparatorMenuField->Menu()->ItemAt((int32)separator)->SetMarked(true);
533 	*/
534 
535 	_UpdateExamples();
536 	_ParseDateFormat();
537 	_ParseCurrencyFormat();
538 }
539 
540 
541 void
542 FormatView::RecordRevertSettings()
543 {
544 	/*
545 	f24HrClock = settings.ClockIs24Hr();
546 	fSeparator = settings.TimeFormatSeparator();
547 	fFormat = settings.DateOrderFormat();
548 	*/
549 }
550 
551 
552 // Return true if the Revert button should be enabled (ie some setting was
553 // changed)
554 bool
555 FormatView::IsRevertable() const
556 {
557 	FormatSeparator separator;
558 
559 	BMenuItem* item = fSeparatorMenuField->Menu()->FindMarked();
560 	if (item) {
561 		int32 index = fSeparatorMenuField->Menu()->IndexOf(item);
562 		if (index >= 0)
563 			separator = (FormatSeparator)index;
564 		else
565 			return true;
566 	} else
567 		return true;
568 
569 	// TODO generate ICU string and compare to the initial one
570 	BString dateFormat ;
571 		// fYMDRadioButton->Value() ? kYMDFormat :
572 		//(fDMYRadioButton->Value() ? kDMYFormat : kMDYFormat);
573 
574 	return f24HrClock != (f24HrRadioButton->Value() > 0)
575 		|| separator != fSeparator
576 		|| dateFormat != fDateFormat;
577 }
578 
579 
580 void
581 FormatView::_UpdateExamples()
582 {
583 	time_t timeValue = (time_t)time(NULL);
584 	BString timeFormat;
585 
586 	fLocale.FormatDate(&timeFormat, timeValue, true);
587 	fLongDateExampleView->SetText(timeFormat);
588 
589 	fLocale.FormatDate(&timeFormat, timeValue, false);
590 	fShortDateExampleView->SetText(timeFormat);
591 
592 	fLocale.FormatTime(&timeFormat, timeValue, true);
593 	fLongTimeExampleView->SetText(timeFormat);
594 
595 	fLocale.FormatTime(&timeFormat, timeValue, false);
596 	fShortTimeExampleView->SetText(timeFormat);
597 
598 	status_t Error = fLocale.FormatNumber(&timeFormat, 1234.5678);
599 	if (Error == B_OK)
600 		fNumberFormatExampleView->SetText(timeFormat);
601 	else
602 		fNumberFormatExampleView->SetText("ERROR");
603 }
604 
605 
606 void
607 FormatView::_SendNotices()
608 {
609 	// Make the notification message and send it to the tracker:
610 	/*
611 	BMessage notificationMessage;
612 	notificationMessage.AddInt32("TimeFormatSeparator",
613 		(int32)settings.TimeFormatSeparator());
614 	notificationMessage.AddInt32("DateOrderFormat",
615 		(int32)settings.DateOrderFormat());
616 	notificationMessage.AddBool("24HrClock", settings.ClockIs24Hr());
617 	tracker->SendNotices(kDateFormatChanged, &notificationMessage);
618 	*/
619 }
620 
621 
622 void
623 FormatView::_ParseCurrencyFormat()
624 {
625 	BString currencySample;
626 	int* fieldPos = NULL;
627 	int fieldCount;
628 	BNumberElement* fieldID = NULL;
629 	if (fLocale.FormatMonetary(&currencySample, fieldPos, fieldID, fieldCount,
630 			-1234.56) != B_OK) {
631 		fMonetaryView->SetText("ERROR");
632 		return;
633 	}
634 
635 	fMonetaryView->SetText(currencySample);
636 
637 	for (int i = 0; i < fieldCount; i++) {
638 		BString currentSymbol;
639 		currentSymbol.AppendChars(currencySample.CharAt(fieldPos[i]&0xFFFF),
640 			(fieldPos[i]>>16) - (fieldPos[i]&0xFFFF));
641 		switch (fieldID[i]) {
642 			case B_NUMBER_ELEMENT_CURRENCY:
643 				fCurrencySymbolView->SetText(currentSymbol);
644 				if (i > fieldCount / 2)
645 					fCurrencySymbolAfter->SetValue(1);
646 				else
647 					fCurrencySymbolBefore->SetValue(1);
648 				break;
649 			default:
650 				break;
651 		}
652 	}
653 
654 	free(fieldPos);
655 	free(fieldID);
656 }
657 
658 
659 //! Get the date format from ICU and set the date fields accordingly
660 void
661 FormatView::_ParseDateFormat()
662 {
663 	BString dateFormatString;
664 	fLocale.GetDateFormat(dateFormatString, true);
665 	const char* dateFormat = dateFormatString.String();
666 
667 	// Travel through the string and parse it
668 	const char* parsePointer = dateFormat;
669 	const char* fieldBegin = dateFormat;
670 
671 	for (int i = 0; i < 4; i++)
672 	{
673 		fieldBegin = parsePointer;
674 		while (*parsePointer == *(parsePointer + 1))
675 			parsePointer++;
676 		parsePointer++;
677 		BString str;
678 		str.Append(fieldBegin, parsePointer - fieldBegin);
679 
680 		fLongDateString[i] = str;
681 
682 		BMenu* subMenu;
683 		bool isFound = false;
684 		for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
685 			subMenu = fLongDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
686 			BMenuItem* item;
687 			for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
688 					itemIndex++) {
689 				if (static_cast<DateMenuItem*>(item)->ICUCode() == str) {
690 					item->SetMarked(true);
691 					fLongDateMenu[i]->MenuItem()->SetLabel(item->Label());
692 					isFound = true;
693 				} else
694 					item->SetMarked(false);
695 			}
696 		}
697 
698 		if (!isFound)
699 			fLongDateMenu[i]->MenuItem()->SetLabel(str.Append("*"));
700 
701 		fieldBegin = parsePointer;
702 		while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0') {
703 			if (*parsePointer == '\'') {
704 				parsePointer++;
705 				while (*parsePointer != '\0' && *parsePointer != '\'')
706 					parsePointer++;
707 				if (*parsePointer == '\0')
708 					break;
709 			}
710 			parsePointer++;
711 		}
712 		str.Truncate(0);
713 		str.Append(fieldBegin, parsePointer - fieldBegin);
714 		fLongDateSeparator[i]->SetText(str);
715 	}
716 
717 	// Short date is a bit more tricky, we want to extract the separator
718 	fLocale.GetDateFormat(dateFormatString, false);
719 	dateFormat = dateFormatString.String();
720 
721 	// Travel trough the string and parse it
722 	parsePointer = dateFormat;
723 	fieldBegin = dateFormat;
724 
725 	for (int i = 0; i < 3; i++) {
726 		fieldBegin = parsePointer;
727 		while (*parsePointer == *(parsePointer + 1))
728 			parsePointer++;
729 		parsePointer++;
730 		BString str;
731 		str.Append(fieldBegin, parsePointer - fieldBegin);
732 
733 		fLongDateString[i] = str;
734 
735 		BMenu* subMenu;
736 		bool isFound = false;
737 		for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
738 			subMenu = fDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
739 			BMenuItem* item;
740 			for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
741 					itemIndex++) {
742 				if (static_cast<DateMenuItem*>(item)->ICUCode() == str) {
743 					item->SetMarked(true);
744 					fDateMenu[i]->MenuItem()->SetLabel(item->Label());
745 					isFound = true;
746 				} else
747 					item->SetMarked(false);
748 			}
749 		}
750 
751 		if (!isFound) {
752 			fDateMenu[i]->MenuItem()->SetLabel(
753 				str.Append(B_TRANSLATE(" (unknown format)")));
754 		}
755 
756 		fieldBegin = parsePointer;
757 		while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0') {
758 			if (*parsePointer == '\'') {
759 				parsePointer++;
760 				while (*parsePointer != '\0' && *parsePointer != '\'')
761 					parsePointer++;
762 				if (*parsePointer == '\0')
763 					break;
764 			}
765 			parsePointer++;
766 		}
767 		if (parsePointer - fieldBegin > 0) {
768 			str.Truncate(0);
769 			str.Append(fieldBegin, parsePointer - fieldBegin);
770 			fSeparatorMenuField->MenuItem()->SetLabel(str);
771 		}
772 	}
773 }
774 
775 
776 void
777 FormatView::_UpdateLongDateFormatString()
778 {
779 	BString newDateFormat;
780 
781 	for (int i = 0; i < 4; i++) {
782 		newDateFormat.Append(fLongDateString[i]);
783 		newDateFormat.Append(fLongDateSeparator[i]->Text());
784 	}
785 
786 	// TODO save this in the settings preflet and make the roster load it back
787 	fLocale.SetDateFormat(newDateFormat.String());
788 
789 	newDateFormat.Truncate(0);
790 
791 	newDateFormat.Append(fDateString[0]);
792 	newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
793 	newDateFormat.Append(fDateString[1]);
794 	newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
795 	newDateFormat.Append(fDateString[2]);
796 
797 	// TODO save this in the settings preflet and make the roster load it back
798 	fLocale.SetDateFormat(newDateFormat.String(), false);
799 }
800