diff --git a/src/CalcViewModel/UnitConverterViewModel.cpp b/src/CalcViewModel/UnitConverterViewModel.cpp index a159cf7f..5ae0dc67 100644 --- a/src/CalcViewModel/UnitConverterViewModel.cpp +++ b/src/CalcViewModel/UnitConverterViewModel.cpp @@ -134,7 +134,6 @@ UnitConverterViewModel::UnitConverterViewModel(const shared_ptrIsGrouped = true; m_currencyFormatter->Mode = CurrencyFormatterMode::UseCurrencyCode; m_currencyFormatter->ApplyRoundingForCurrency(RoundingAlgorithm::RoundHalfDown); - m_currencyMaxFractionDigits = m_currencyFormatter->FractionDigits; auto resourceLoader = AppResourceProvider::GetInstance(); m_localizedValueFromFormat = resourceLoader->GetResourceString(UnitConverterResourceKeys::ValueFromFormat); @@ -228,6 +227,8 @@ void UnitConverterViewModel::OnUnitChanged(Object ^ parameter) return; } + UpdateCurrencyFormatter(); + m_model->SetCurrentUnitTypes(UnitFrom->GetModelUnit(), UnitTo->GetModelUnit()); if (m_supplementaryResultsTimer != nullptr) { @@ -246,7 +247,7 @@ void UnitConverterViewModel::OnSwitchActive(Platform::Object ^ unused) if (m_relocalizeStringOnSwitch) { // clean up any ill-formed strings that were in progress before the switch - ValueFrom = ConvertToLocalizedString(m_valueFromUnlocalized, false); + ValueFrom = ConvertToLocalizedString(m_valueFromUnlocalized, false, CurrencyFormatterParameterFrom); } SwitchConversionParameters(); @@ -271,7 +272,7 @@ void UnitConverterViewModel::OnSwitchActive(Platform::Object ^ unused) m_model->SwitchActive(m_valueFromUnlocalized); } -String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings) +String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings, CurrencyFormatterParameter cfp) { Platform::String ^ result; @@ -280,10 +281,33 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st return result; } + CurrencyFormatter ^ currencyFormatter; + + switch (cfp) + { + case CurrencyFormatterParameter::Default: + currencyFormatter = m_currencyFormatter; + break; + case CurrencyFormatterParameter::ForValue1: + currencyFormatter = m_currencyFormatter1; + break; + case CurrencyFormatterParameter::ForValue2: + currencyFormatter = m_currencyFormatter2; + break; + } + + // If unit hasn't been set, currencyFormatter1/2 is nullptr. Fallback to default. + if (currencyFormatter == nullptr) + { + currencyFormatter = m_currencyFormatter; + } + + int lastCurrencyFractionDigits = currencyFormatter->FractionDigits; + m_decimalFormatter->IsDecimalPointAlwaysDisplayed = false; m_decimalFormatter->FractionDigits = 0; - m_currencyFormatter->IsDecimalPointAlwaysDisplayed = false; - m_currencyFormatter->FractionDigits = 0; + currencyFormatter->IsDecimalPointAlwaysDisplayed = false; + currencyFormatter->FractionDigits = 0; wstring::size_type posOfE = stringToLocalize.find(L'e'); if (posOfE != wstring::npos) @@ -293,7 +317,8 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st std::wstring significandStr(stringToLocalize.substr(0, posOfE)); std::wstring exponentStr(stringToLocalize.substr(posOfSign + 1, stringToLocalize.length() - posOfSign)); - result += ConvertToLocalizedString(significandStr, allowPartialStrings) + "e" + signOfE + ConvertToLocalizedString(exponentStr, allowPartialStrings); + result += ConvertToLocalizedString(significandStr, allowPartialStrings, cfp) + "e" + signOfE + + ConvertToLocalizedString(exponentStr, allowPartialStrings, cfp); } else { @@ -312,18 +337,18 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st // typed a post-decimal digit. m_decimalFormatter->IsDecimalPointAlwaysDisplayed = true; - m_currencyFormatter->IsDecimalPointAlwaysDisplayed = true; + currencyFormatter->IsDecimalPointAlwaysDisplayed = true; } // force post-decimal digits so that trailing zeroes entered by the user aren't suddenly cut off. m_decimalFormatter->FractionDigits = static_cast(stringToLocalize.length() - (posOfDecimal + 1)); - m_currencyFormatter->FractionDigits = m_currencyMaxFractionDigits; + currencyFormatter->FractionDigits = lastCurrencyFractionDigits; } if (IsCurrencyCurrentCategory) { - wstring currencyResult = m_currencyFormatter->Format(stod(stringToLocalize))->Data(); - wstring currencyCode = m_currencyFormatter->Currency->Data(); + wstring currencyResult = currencyFormatter->Format(stod(stringToLocalize))->Data(); + wstring currencyCode = currencyFormatter->Currency->Data(); // CurrencyFormatter always includes LangCode or Symbol. Make it include LangCode // because this includes a non-breaking space. Remove the LangCode. @@ -370,6 +395,8 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st // Copy back the edited string to the result result = ref new String(resultWithDecimal.c_str()); } + + currencyFormatter->FractionDigits = lastCurrencyFractionDigits; } wstring resultHolder = wstring(result->Data()); @@ -394,9 +421,9 @@ void UnitConverterViewModel::DisplayPasteError() void UnitConverterViewModel::UpdateDisplay(const wstring& from, const wstring& to) { - String ^ fromStr = this->ConvertToLocalizedString(from, true); + String ^ fromStr = this->ConvertToLocalizedString(from, true, CurrencyFormatterParameterFrom); UpdateInputBlocked(from); - String ^ toStr = this->ConvertToLocalizedString(to, true); + String ^ toStr = this->ConvertToLocalizedString(to, true, CurrencyFormatterParameterTo); bool updatedValueFrom = ValueFrom != fromStr; bool updatedValueTo = ValueTo != toStr; @@ -473,14 +500,14 @@ void UnitConverterViewModel::OnButtonPressed(Platform::Object ^ parameter) } static constexpr UCM::Command OPERANDS[] = { UCM::Command::Zero, UCM::Command::One, UCM::Command::Two, UCM::Command::Three, UCM::Command::Four, - UCM::Command::Five, UCM::Command::Six, UCM::Command::Seven, UCM::Command::Eight, UCM::Command::Nine }; + UCM::Command::Five, UCM::Command::Six, UCM::Command::Seven, UCM::Command::Eight, UCM::Command::Nine }; if (m_isInputBlocked && command != UCM::Command::Clear && command != UCM::Command::Backspace) - { - return; - } - m_model->SendCommand(command); + { + return; + } + m_model->SendCommand(command); TraceLogger::GetInstance()->LogConverterInputReceived(Mode); } @@ -755,8 +782,8 @@ void UnitConverterViewModel::RefreshSupplementaryResults() for (tuple suggestedValue : m_cachedSuggestedValues) { - SupplementaryResult ^ result = - ref new SupplementaryResult(this->ConvertToLocalizedString(get<0>(suggestedValue), false), ref new Unit(get<1>(suggestedValue))); + SupplementaryResult ^ result = ref new SupplementaryResult( + this->ConvertToLocalizedString(get<0>(suggestedValue), false, CurrencyFormatterParameter::Default), ref new Unit(get<1>(suggestedValue))); if (result->IsWhimsical()) { whimsicals.push_back(result); @@ -803,10 +830,26 @@ void UnitConverterViewModel::UpdateInputBlocked(_In_ const wstring& currencyInpu m_isInputBlocked = false; if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory) { - m_isInputBlocked = (posOfDecimal + static_cast(m_currencyMaxFractionDigits) + 1 == currencyInput.length()); + m_isInputBlocked = (posOfDecimal + static_cast(CurrencyFormatterFrom->FractionDigits) + 1 == currencyInput.length()); } } +void UnitConverterViewModel::UpdateCurrencyFormatter() +{ + if (!IsCurrencyCurrentCategory || m_Unit1->Abbreviation->IsEmpty() || m_Unit2->Abbreviation->IsEmpty()) + return; + + m_currencyFormatter1 = ref new CurrencyFormatter(m_Unit1->Abbreviation); + m_currencyFormatter1->IsGrouped = true; + m_currencyFormatter1->Mode = CurrencyFormatterMode::UseCurrencyCode; + m_currencyFormatter1->ApplyRoundingForCurrency(RoundingAlgorithm::RoundHalfDown); + + m_currencyFormatter2 = ref new CurrencyFormatter(m_Unit2->Abbreviation); + m_currencyFormatter2->IsGrouped = true; + m_currencyFormatter2->Mode = CurrencyFormatterMode::UseCurrencyCode; + m_currencyFormatter2->ApplyRoundingForCurrency(RoundingAlgorithm::RoundHalfDown); +} + NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate) { static_assert(NumbersAndOperatorsEnum::Zero < NumbersAndOperatorsEnum::One, "NumbersAndOperatorsEnum order is invalid"); @@ -934,14 +977,19 @@ void UnitConverterViewModel::OnPaste(String ^ stringToPaste) } } -String ^ UnitConverterViewModel::GetLocalizedAutomationName(_In_ String ^ displayvalue, _In_ String ^ unitname, _In_ String ^ format) +String + ^ UnitConverterViewModel::GetLocalizedAutomationName( + _In_ String ^ displayvalue, + _In_ String ^ unitname, + _In_ String ^ format, + _In_ CurrencyFormatterParameter cfp) { String ^ valueToLocalize = displayvalue; if (displayvalue == ValueFrom && Utils::IsLastCharacterTarget(m_valueFromUnlocalized, m_decimalSeparator)) { // Need to compute a second localized value for the automation // name that does not include the decimal separator. - displayvalue = ConvertToLocalizedString(m_valueFromUnlocalized, false /*allowTrailingDecimal*/); + displayvalue = ConvertToLocalizedString(m_valueFromUnlocalized, false /*allowTrailingDecimal*/, cfp); format = m_localizedValueFromDecimalFormat; } @@ -962,7 +1010,7 @@ void UnitConverterViewModel::UpdateValue1AutomationName() { if (Unit1) { - Value1AutomationName = GetLocalizedAutomationName(Value1, Unit1->AccessibleName, m_localizedValueFromFormat); + Value1AutomationName = GetLocalizedAutomationName(Value1, Unit1->AccessibleName, m_localizedValueFromFormat, CurrencyFormatterParameter::ForValue1); } } @@ -970,7 +1018,7 @@ void UnitConverterViewModel::UpdateValue2AutomationName() { if (Unit2) { - Value2AutomationName = GetLocalizedAutomationName(Value2, Unit2->AccessibleName, m_localizedValueToFormat); + Value2AutomationName = GetLocalizedAutomationName(Value2, Unit2->AccessibleName, m_localizedValueToFormat, CurrencyFormatterParameter::ForValue1); } } diff --git a/src/CalcViewModel/UnitConverterViewModel.h b/src/CalcViewModel/UnitConverterViewModel.h index a5287e45..e85b56f5 100644 --- a/src/CalcViewModel/UnitConverterViewModel.h +++ b/src/CalcViewModel/UnitConverterViewModel.h @@ -227,8 +227,19 @@ namespace CalculatorApp void OnCopyCommand(Platform::Object ^ parameter); void OnPasteCommand(Platform::Object ^ parameter); + enum class CurrencyFormatterParameter + { + Default, + ForValue1, + ForValue2, + }; + Platform::String - ^ GetLocalizedAutomationName(_In_ Platform::String ^ displayvalue, _In_ Platform::String ^ unitname, _In_ Platform::String ^ format); + ^ GetLocalizedAutomationName( + _In_ Platform::String ^ displayvalue, + _In_ Platform::String ^ unitname, + _In_ Platform::String ^ format, + _In_ CurrencyFormatterParameter cfp); Platform::String ^ GetLocalizedConversionResultStringFormat( _In_ Platform::String ^ fromValue, @@ -276,11 +287,12 @@ namespace CalculatorApp void SupplementaryResultsTimerCancel(Windows::System::Threading::ThreadPoolTimer ^ timer); void RefreshSupplementaryResults(); void UpdateInputBlocked(_In_ const std::wstring& currencyInput); + void UpdateCurrencyFormatter(); bool UnitsAreValid(); void ResetCategory(); void OnButtonPressed(Platform::Object ^ parameter); - Platform::String ^ ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings); + Platform::String ^ ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings, CurrencyFormatterParameter cfp); std::shared_ptr m_model; wchar_t m_decimalSeparator; @@ -290,6 +302,34 @@ namespace CalculatorApp Source, Target } m_value1cp; + property CurrencyFormatterParameter CurrencyFormatterParameterFrom + { + CurrencyFormatterParameter get() + { + return m_value1cp == ConversionParameter::Source ? CurrencyFormatterParameter::ForValue1 : CurrencyFormatterParameter::ForValue2; + } + } + property CurrencyFormatterParameter CurrencyFormatterParameterTo + { + CurrencyFormatterParameter get() + { + return m_value1cp == ConversionParameter::Target ? CurrencyFormatterParameter::ForValue1 : CurrencyFormatterParameter::ForValue2; + } + } + property Windows::Globalization::NumberFormatting::CurrencyFormatter^ CurrencyFormatterFrom + { + Windows::Globalization::NumberFormatting::CurrencyFormatter^ get() + { + return m_value1cp == ConversionParameter::Source ? m_currencyFormatter1 : m_currencyFormatter2; + } + } + property Windows::Globalization::NumberFormatting::CurrencyFormatter^ CurrencyFormatterTo + { + Windows::Globalization::NumberFormatting::CurrencyFormatter^ get() + { + return m_value1cp == ConversionParameter::Target ? m_currencyFormatter1 : m_currencyFormatter2; + } + } property Platform::String^ ValueFrom { Platform::String^ get() { return m_value1cp == ConversionParameter::Source ? Value1 : Value2; } @@ -323,7 +363,8 @@ namespace CalculatorApp std::mutex m_cacheMutex; Windows::Globalization::NumberFormatting::DecimalFormatter ^ m_decimalFormatter; Windows::Globalization::NumberFormatting::CurrencyFormatter ^ m_currencyFormatter; - int m_currencyMaxFractionDigits; + Windows::Globalization::NumberFormatting::CurrencyFormatter ^ m_currencyFormatter1; + Windows::Globalization::NumberFormatting::CurrencyFormatter ^ m_currencyFormatter2; std::wstring m_valueFromUnlocalized; std::wstring m_valueToUnlocalized; bool m_relocalizeStringOnSwitch;