⛏️ index : haiku.git

/*
 * Copyright 2009, Adrien Destugues, pulkomandy@gmail.com. All rights reserved.
 * Distributed under the terms of the MIT License.
 */


#include "FormatSettingsView.h"

#include <stdlib.h>

#include <Alert.h>
#include <Application.h>
#include <Catalog.h>
#include <CheckBox.h>
#include <ControlLook.h>
#include <DateFormat.h>
#include <GridLayout.h>
#include <GridLayoutBuilder.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <MutableLocaleRoster.h>
#include <Message.h>
#include <Menu.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <NumberFormat.h>
#include <PopUpMenu.h>
#include <RadioButton.h>
#include <ScrollView.h>
#include <ScrollBar.h>
#include <SeparatorView.h>
#include <SpaceLayoutItem.h>
#include <String.h>
#include <StringView.h>
#include <TextControl.h>
#include <TimeFormat.h>
#include <Window.h>

#include "LocalePreflet.h"


using BPrivate::MutableLocaleRoster;


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "TimeFormatSettings"


// #pragma mark -


FormatSettingsView::FormatSettingsView()
	:
	BView("WindowsSettingsView", B_FRAME_EVENTS)
{
	fUseLanguageStringsCheckBox = new BCheckBox(
		B_TRANSLATE("Use month/day-names from preferred language"),
		new BMessage(kStringsLanguageChange));

	fFilesystemTranslationCheckbox = new BCheckBox("filesystemTranslation",
		B_TRANSLATE("Translate application and folder names"),
		new BMessage(kMsgFilesystemTranslationChanged));
	fFilesystemTranslationCheckbox->SetValue(
		BLocaleRoster::Default()->IsFilesystemTranslationPreferred());

	BStringView* fullDateLabel
		= new BStringView("", B_TRANSLATE("Full format:"));
	fullDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	BStringView* longDateLabel
		= new BStringView("", B_TRANSLATE("Long format:"));
	longDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	BStringView* mediumDateLabel
		= new BStringView("", B_TRANSLATE("Medium format:"));
	mediumDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	BStringView* shortDateLabel
		= new BStringView("", B_TRANSLATE("Short format:"));
	shortDateLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));

	fFullDateExampleView = new BStringView("", "");
	fFullDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	fLongDateExampleView = new BStringView("", "");
	fLongDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	fMediumDateExampleView = new BStringView("", "");
	fMediumDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	fShortDateExampleView = new BStringView("", "");
	fShortDateExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));

	f24HourRadioButton = new BRadioButton("", B_TRANSLATE("24 hour"),
		new BMessage(kClockFormatChange));
	f12HourRadioButton = new BRadioButton("", B_TRANSLATE("12 hour"),
		new BMessage(kClockFormatChange));

	float spacing = be_control_look->DefaultItemSpacing();

	BStringView* fullTimeLabel
		= new BStringView("", B_TRANSLATE("Full format:"));
	fullTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	BStringView* longTimeLabel
		= new BStringView("", B_TRANSLATE("Long format:"));
	longTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	BStringView* mediumTimeLabel
		= new BStringView("", B_TRANSLATE("Medium format:"));
	mediumTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	BStringView* shortTimeLabel
		= new BStringView("", B_TRANSLATE("Short format:"));
	shortTimeLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));

	fFullTimeExampleView = new BStringView("", "");
	fFullTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	fLongTimeExampleView = new BStringView("", "");
	fLongTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	fMediumTimeExampleView = new BStringView("", "");
	fMediumTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	fShortTimeExampleView = new BStringView("", "");
	fShortTimeExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));

	BStringView* positiveNumberLabel
		= new BStringView("", B_TRANSLATE("Positive:"));
	positiveNumberLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	BStringView* negativeNumberLabel
		= new BStringView("", B_TRANSLATE("Negative:"));
	negativeNumberLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));

	fPositiveNumberExampleView = new BStringView("", "");
	fPositiveNumberExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
		B_ALIGN_VERTICAL_UNSET));
	fNegativeNumberExampleView = new BStringView("", "");
	fNegativeNumberExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
		B_ALIGN_VERTICAL_UNSET));

	BStringView* positiveMonetaryLabel
		= new BStringView("", B_TRANSLATE("Positive:"));
	positiveMonetaryLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));
	BStringView* negativeMonetaryLabel
		= new BStringView("", B_TRANSLATE("Negative:"));
	negativeMonetaryLabel->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
		B_ALIGN_VERTICAL_UNSET));

	fPositiveMonetaryExampleView = new BStringView("", "");
	fPositiveMonetaryExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
		B_ALIGN_VERTICAL_UNSET));
	fNegativeMonetaryExampleView = new BStringView("", "");
	fNegativeMonetaryExampleView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
		B_ALIGN_VERTICAL_UNSET));

	Refresh(true);

	fDateBox = new BBox(B_TRANSLATE("Date"));
	fTimeBox = new BBox(B_TRANSLATE("Time"));
	fNumberBox = new BBox(B_TRANSLATE("Numbers"));
	fMonetaryBox = new BBox(B_TRANSLATE("Currency"));

	fDateBox->SetLabel(B_TRANSLATE("Date"));
	fTimeBox->SetLabel(B_TRANSLATE("Time"));
	fNumberBox->SetLabel(B_TRANSLATE("Numbers"));
	fMonetaryBox->SetLabel(B_TRANSLATE("Currency"));

	fDateBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
		.SetInsets(spacing, spacing, spacing, spacing)
		.Add(fullDateLabel, 0, 0)
		.Add(fFullDateExampleView, 1, 0)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
		.Add(longDateLabel, 0, 1)
		.Add(fLongDateExampleView, 1, 1)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
		.Add(mediumDateLabel, 0, 2)
		.Add(fMediumDateExampleView, 1, 2)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 2)
		.Add(shortDateLabel, 0, 3)
		.Add(fShortDateExampleView, 1, 3)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 3)
		.View());

	fTimeBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
		.SetInsets(spacing, spacing, spacing, spacing)
		.AddGroup(B_HORIZONTAL, spacing, 0, 0, 2)
			.Add(f24HourRadioButton, 0)
			.Add(f12HourRadioButton, 0)
			.AddGlue()
			.End()
		.Add(fullTimeLabel, 0, 1)
		.Add(fFullTimeExampleView, 1, 1)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
		.Add(longTimeLabel, 0, 2)
		.Add(fLongTimeExampleView, 1, 2)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 2)
		.Add(mediumTimeLabel, 0, 3)
		.Add(fMediumTimeExampleView, 1, 3)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 3)
		.Add(shortTimeLabel, 0, 4)
		.Add(fShortTimeExampleView, 1, 4)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 4)
		.View());

	fNumberBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
		.SetInsets(spacing, spacing, spacing, spacing)
		.Add(positiveNumberLabel, 0, 0)
		.Add(fPositiveNumberExampleView, 1, 0)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
		.Add(negativeNumberLabel, 0, 1)
		.Add(fNegativeNumberExampleView, 1, 1)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
		.View());

	fMonetaryBox->AddChild(BLayoutBuilder::Grid<>(spacing, spacing / 2)
		.SetInsets(spacing, spacing, spacing, spacing)
		.Add(positiveMonetaryLabel, 0, 0)
		.Add(fPositiveMonetaryExampleView, 1, 0)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 0)
		.Add(negativeMonetaryLabel, 0, 1)
		.Add(fNegativeMonetaryExampleView, 1, 1)
		.Add(BSpaceLayoutItem::CreateGlue(), 2, 1)
		.View());

	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);

	BLayoutBuilder::Group<>(this, B_VERTICAL)
		.Add(fFilesystemTranslationCheckbox)
		.Add(fUseLanguageStringsCheckBox)
		.Add(fDateBox)
		.Add(fTimeBox)
		.AddGroup(B_HORIZONTAL, spacing)
			.Add(fNumberBox)
			.Add(fMonetaryBox)
			.End()
		.AddGlue();
}


FormatSettingsView::~FormatSettingsView()
{
}


void
FormatSettingsView::AttachedToWindow()
{
	fFilesystemTranslationCheckbox->SetTarget(Window());
	fUseLanguageStringsCheckBox->SetTarget(this);
	f24HourRadioButton->SetTarget(this);
	f12HourRadioButton->SetTarget(this);
}


void
FormatSettingsView::MessageReceived(BMessage* message)
{
	switch (message->what) {
		case B_LOCALE_CHANGED:
		{
			// Time updated 12/24 hour clock
			BFormattingConventions conventions;
			BLocale::Default()->GetFormattingConventions(&conventions);
			if (conventions.Use24HourClock())
				f24HourRadioButton->SetValue(B_CONTROL_ON);
			else
				f12HourRadioButton->SetValue(B_CONTROL_ON);

			_UpdateExamples();
			Window()->PostMessage(kMsgSettingsChanged);
			break;
		}

		case kClockFormatChange:
		{
			BFormattingConventions conventions;
			BLocale::Default()->GetFormattingConventions(&conventions);
			conventions.SetExplicitUse24HourClock(
				f24HourRadioButton->Value() == B_CONTROL_ON);
			MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
				conventions);

			_UpdateExamples();
			Window()->PostMessage(kMsgSettingsChanged);
			break;
		}

		case kStringsLanguageChange:
		{
			BFormattingConventions conventions;
			BLocale::Default()->GetFormattingConventions(&conventions);
			conventions.SetUseStringsFromPreferredLanguage(
				fUseLanguageStringsCheckBox->Value() ? true : false);
			MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
				conventions);

			_UpdateExamples();

			Window()->PostMessage(kMsgSettingsChanged);
			break;
		}

		default:
			BView::MessageReceived(message);
	}
}


void
FormatSettingsView::Revert()
{
	MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
		fInitialConventions);

	fFilesystemTranslationCheckbox->SetValue(fInitialTranslateNames);

	_UpdateExamples();
}


void
FormatSettingsView::Refresh(bool setInitial)
{
	BFormattingConventions conventions;
	BLocale::Default()->GetFormattingConventions(&conventions);
	if (setInitial) {
		fInitialConventions = conventions;
		fInitialTranslateNames
			= BLocaleRoster::Default()->IsFilesystemTranslationPreferred();
	}

	if (!conventions.Use24HourClock()) {
		f12HourRadioButton->SetValue(B_CONTROL_ON);
		fLocaleIs24Hour = false;
	} else {
		f24HourRadioButton->SetValue(B_CONTROL_ON);
		fLocaleIs24Hour = true;
	}

	fUseLanguageStringsCheckBox->SetValue(
		conventions.UseStringsFromPreferredLanguage()
			? B_CONTROL_ON : B_CONTROL_OFF);

	_UpdateExamples();
}


// Return true if the Revert button should be enabled (i.e. something has been
// changed)
bool
FormatSettingsView::IsReversible() const
{
	BFormattingConventions conventions;
	BLocale::Default()->GetFormattingConventions(&conventions);

	return (conventions != fInitialConventions)
		|| (fFilesystemTranslationCheckbox->Value() != fInitialTranslateNames);
}


void
FormatSettingsView::_UpdateExamples()
{
	time_t timeValue = (time_t)time(NULL);
	BString result;

	// Do NOT make these class members. We do want to recreate it everytime, as
	// to get the updated settings from the locale roster.
	BDateFormat dateFormat;
	BNumberFormat numberFormat;
	BString errorString = B_TRANSLATE("ERROR");
	BTimeFormat timeFormat;

	dateFormat.Format(result, timeValue, B_FULL_DATE_FORMAT);
	fFullDateExampleView->SetText(result);

	dateFormat.Format(result, timeValue, B_LONG_DATE_FORMAT);
	fLongDateExampleView->SetText(result);

	dateFormat.Format(result, timeValue, B_MEDIUM_DATE_FORMAT);
	fMediumDateExampleView->SetText(result);

	dateFormat.Format(result, timeValue, B_SHORT_DATE_FORMAT);
	fShortDateExampleView->SetText(result);

	timeFormat.Format(result, timeValue, B_FULL_TIME_FORMAT);
	fFullTimeExampleView->SetText(result);

	timeFormat.Format(result, timeValue, B_LONG_TIME_FORMAT);
	fLongTimeExampleView->SetText(result);

	timeFormat.Format(result, timeValue, B_MEDIUM_TIME_FORMAT);
	fMediumTimeExampleView->SetText(result);

	timeFormat.Format(result, timeValue, B_SHORT_TIME_FORMAT);
	fShortTimeExampleView->SetText(result);

	status_t status = numberFormat.Format(result, 1234.56);
	if (status == B_OK)
		fPositiveNumberExampleView->SetText(result);
	else
		fPositiveNumberExampleView->SetText(errorString);

	status = numberFormat.Format(result, -1234.56);
	if (status == B_OK)
		fNegativeNumberExampleView->SetText(result);
	else
		fNegativeNumberExampleView->SetText(errorString);

	status = numberFormat.FormatMonetary(result, 1234.56);
	if (status == B_OK)
		fPositiveMonetaryExampleView->SetText(result);
	else
		fPositiveMonetaryExampleView->SetText(errorString);

	status = numberFormat.FormatMonetary(result, -1234.56);
	if (status == B_OK)
		fNegativeMonetaryExampleView->SetText(result);
	else
		fNegativeMonetaryExampleView->SetText(errorString);
}