mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-23 06:25:19 -07:00
Merge branch 'master' of https://github.com/microsoft/calculator into Updateto2012release
This commit is contained in:
commit
ee774b3549
24 changed files with 545 additions and 83 deletions
|
@ -24,7 +24,7 @@ static constexpr uint32_t OPTIMALDIGITSALLOWED = 7U;
|
||||||
static constexpr wchar_t LEFTESCAPECHAR = L'{';
|
static constexpr wchar_t LEFTESCAPECHAR = L'{';
|
||||||
static constexpr wchar_t RIGHTESCAPECHAR = L'}';
|
static constexpr wchar_t RIGHTESCAPECHAR = L'}';
|
||||||
|
|
||||||
static const double OPTIMALDECIMALALLOWED = 1e-6; // pow(10, -1 * (OPTIMALDIGITSALLOWED - 1));
|
static const double OPTIMALDECIMALALLOWED = 1e-6; // pow(10, -1 * (OPTIMALDIGITSALLOWED - 1));
|
||||||
static const double MINIMUMDECIMALALLOWED = 1e-14; // pow(10, -1 * (MAXIMUMDIGITSALLOWED - 1));
|
static const double MINIMUMDECIMALALLOWED = 1e-14; // pow(10, -1 * (MAXIMUMDIGITSALLOWED - 1));
|
||||||
|
|
||||||
unordered_map<wchar_t, wstring> quoteConversions;
|
unordered_map<wchar_t, wstring> quoteConversions;
|
||||||
|
@ -149,6 +149,11 @@ void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_fromType != fromType)
|
||||||
|
{
|
||||||
|
m_switchedActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
m_fromType = fromType;
|
m_fromType = fromType;
|
||||||
m_toType = toType;
|
m_toType = toType;
|
||||||
Calculate();
|
Calculate();
|
||||||
|
@ -191,6 +196,11 @@ void UnitConverter::SwitchActive(const wstring& newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UnitConversionManager::UnitConverter::IsSwitchedActive() const
|
||||||
|
{
|
||||||
|
return m_switchedActive;
|
||||||
|
}
|
||||||
|
|
||||||
wstring UnitConverter::CategoryToString(const Category& c, wstring_view delimiter)
|
wstring UnitConverter::CategoryToString(const Category& c, wstring_view delimiter)
|
||||||
{
|
{
|
||||||
return Quote(std::to_wstring(c.id))
|
return Quote(std::to_wstring(c.id))
|
||||||
|
|
|
@ -223,6 +223,7 @@ namespace UnitConversionManager
|
||||||
virtual Category GetCurrentCategory() = 0;
|
virtual Category GetCurrentCategory() = 0;
|
||||||
virtual void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) = 0;
|
virtual void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) = 0;
|
||||||
virtual void SwitchActive(const std::wstring& newValue) = 0;
|
virtual void SwitchActive(const std::wstring& newValue) = 0;
|
||||||
|
virtual bool IsSwitchedActive() const = 0;
|
||||||
virtual std::wstring SaveUserPreferences() = 0;
|
virtual std::wstring SaveUserPreferences() = 0;
|
||||||
virtual void RestoreUserPreferences(_In_ std::wstring_view userPreferences) = 0;
|
virtual void RestoreUserPreferences(_In_ std::wstring_view userPreferences) = 0;
|
||||||
virtual void SendCommand(Command command) = 0;
|
virtual void SendCommand(Command command) = 0;
|
||||||
|
@ -246,6 +247,7 @@ namespace UnitConversionManager
|
||||||
Category GetCurrentCategory() override;
|
Category GetCurrentCategory() override;
|
||||||
void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) override;
|
void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) override;
|
||||||
void SwitchActive(const std::wstring& newValue) override;
|
void SwitchActive(const std::wstring& newValue) override;
|
||||||
|
bool IsSwitchedActive() const override;
|
||||||
std::wstring SaveUserPreferences() override;
|
std::wstring SaveUserPreferences() override;
|
||||||
void RestoreUserPreferences(std::wstring_view userPreference) override;
|
void RestoreUserPreferences(std::wstring_view userPreference) override;
|
||||||
void SendCommand(Command command) override;
|
void SendCommand(Command command) override;
|
||||||
|
|
|
@ -502,23 +502,32 @@ ULONG32 CopyPasteManager::StandardScientificOperandLength(Platform::String ^ ope
|
||||||
{
|
{
|
||||||
auto operandWstring = wstring(operand->Data());
|
auto operandWstring = wstring(operand->Data());
|
||||||
const bool hasDecimal = operandWstring.find('.') != wstring::npos;
|
const bool hasDecimal = operandWstring.find('.') != wstring::npos;
|
||||||
|
auto length = operandWstring.length();
|
||||||
|
|
||||||
if (hasDecimal)
|
if (hasDecimal)
|
||||||
{
|
{
|
||||||
if (operandWstring.length() >= 2)
|
if (length >= 2)
|
||||||
{
|
{
|
||||||
if ((operandWstring[0] == L'0') && (operandWstring[1] == L'.'))
|
if ((operandWstring[0] == L'0') && (operandWstring[1] == L'.'))
|
||||||
{
|
{
|
||||||
return static_cast<ULONG32>(operandWstring.length() - 2);
|
length -= 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return static_cast<ULONG32>(operandWstring.length() - 1);
|
length -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<ULONG32>(operandWstring.length());
|
auto exponentPos = operandWstring.find('e');
|
||||||
|
const bool hasExponent = exponentPos != wstring::npos;
|
||||||
|
if (hasExponent)
|
||||||
|
{
|
||||||
|
auto expLength = operandWstring.substr(exponentPos).length();
|
||||||
|
length -= expLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<ULONG32>(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG32 CopyPasteManager::ProgrammerOperandLength(Platform::String ^ operand, NumberBase numberBase)
|
ULONG32 CopyPasteManager::ProgrammerOperandLength(Platform::String ^ operand, NumberBase numberBase)
|
||||||
|
|
|
@ -134,7 +134,6 @@ UnitConverterViewModel::UnitConverterViewModel(const shared_ptr<UCM::IUnitConver
|
||||||
m_currencyFormatter->IsGrouped = true;
|
m_currencyFormatter->IsGrouped = true;
|
||||||
m_currencyFormatter->Mode = CurrencyFormatterMode::UseCurrencyCode;
|
m_currencyFormatter->Mode = CurrencyFormatterMode::UseCurrencyCode;
|
||||||
m_currencyFormatter->ApplyRoundingForCurrency(RoundingAlgorithm::RoundHalfDown);
|
m_currencyFormatter->ApplyRoundingForCurrency(RoundingAlgorithm::RoundHalfDown);
|
||||||
m_currencyMaxFractionDigits = m_currencyFormatter->FractionDigits;
|
|
||||||
|
|
||||||
auto resourceLoader = AppResourceProvider::GetInstance();
|
auto resourceLoader = AppResourceProvider::GetInstance();
|
||||||
m_localizedValueFromFormat = resourceLoader->GetResourceString(UnitConverterResourceKeys::ValueFromFormat);
|
m_localizedValueFromFormat = resourceLoader->GetResourceString(UnitConverterResourceKeys::ValueFromFormat);
|
||||||
|
@ -228,7 +227,9 @@ void UnitConverterViewModel::OnUnitChanged(Object ^ parameter)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateCurrencyFormatter();
|
||||||
m_model->SetCurrentUnitTypes(UnitFrom->GetModelUnit(), UnitTo->GetModelUnit());
|
m_model->SetCurrentUnitTypes(UnitFrom->GetModelUnit(), UnitTo->GetModelUnit());
|
||||||
|
|
||||||
if (m_supplementaryResultsTimer != nullptr)
|
if (m_supplementaryResultsTimer != nullptr)
|
||||||
{
|
{
|
||||||
// End timer to show results immediately
|
// End timer to show results immediately
|
||||||
|
@ -246,7 +247,7 @@ void UnitConverterViewModel::OnSwitchActive(Platform::Object ^ unused)
|
||||||
if (m_relocalizeStringOnSwitch)
|
if (m_relocalizeStringOnSwitch)
|
||||||
{
|
{
|
||||||
// clean up any ill-formed strings that were in progress before the switch
|
// 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();
|
SwitchConversionParameters();
|
||||||
|
@ -269,9 +270,11 @@ void UnitConverterViewModel::OnSwitchActive(Platform::Object ^ unused)
|
||||||
|
|
||||||
m_isInputBlocked = false;
|
m_isInputBlocked = false;
|
||||||
m_model->SwitchActive(m_valueFromUnlocalized);
|
m_model->SwitchActive(m_valueFromUnlocalized);
|
||||||
|
|
||||||
|
UpdateIsDecimalEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings)
|
String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings, CurrencyFormatterParameter cfp)
|
||||||
{
|
{
|
||||||
Platform::String ^ result;
|
Platform::String ^ result;
|
||||||
|
|
||||||
|
@ -280,10 +283,33 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CurrencyFormatter ^ currencyFormatter;
|
||||||
|
|
||||||
|
switch (cfp)
|
||||||
|
{
|
||||||
|
case CurrencyFormatterParameter::ForValue1:
|
||||||
|
currencyFormatter = m_currencyFormatter1;
|
||||||
|
break;
|
||||||
|
case CurrencyFormatterParameter::ForValue2:
|
||||||
|
currencyFormatter = m_currencyFormatter2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
currencyFormatter = m_currencyFormatter;
|
||||||
|
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->IsDecimalPointAlwaysDisplayed = false;
|
||||||
m_decimalFormatter->FractionDigits = 0;
|
m_decimalFormatter->FractionDigits = 0;
|
||||||
m_currencyFormatter->IsDecimalPointAlwaysDisplayed = false;
|
currencyFormatter->IsDecimalPointAlwaysDisplayed = false;
|
||||||
m_currencyFormatter->FractionDigits = 0;
|
currencyFormatter->FractionDigits = 0;
|
||||||
|
|
||||||
wstring::size_type posOfE = stringToLocalize.find(L'e');
|
wstring::size_type posOfE = stringToLocalize.find(L'e');
|
||||||
if (posOfE != wstring::npos)
|
if (posOfE != wstring::npos)
|
||||||
|
@ -293,7 +319,8 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st
|
||||||
std::wstring significandStr(stringToLocalize.substr(0, posOfE));
|
std::wstring significandStr(stringToLocalize.substr(0, posOfE));
|
||||||
std::wstring exponentStr(stringToLocalize.substr(posOfSign + 1, stringToLocalize.length() - posOfSign));
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -304,7 +331,7 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st
|
||||||
|
|
||||||
if (hasDecimal)
|
if (hasDecimal)
|
||||||
{
|
{
|
||||||
if (allowPartialStrings)
|
if (allowPartialStrings && lastCurrencyFractionDigits > 0)
|
||||||
{
|
{
|
||||||
// allow "in progress" strings, like "3." that occur during the composition of
|
// allow "in progress" strings, like "3." that occur during the composition of
|
||||||
// a final number. Without this, when typing the three characters in "3.2"
|
// a final number. Without this, when typing the three characters in "3.2"
|
||||||
|
@ -312,18 +339,18 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st
|
||||||
// typed a post-decimal digit.
|
// typed a post-decimal digit.
|
||||||
|
|
||||||
m_decimalFormatter->IsDecimalPointAlwaysDisplayed = true;
|
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.
|
// force post-decimal digits so that trailing zeroes entered by the user aren't suddenly cut off.
|
||||||
m_decimalFormatter->FractionDigits = static_cast<int>(stringToLocalize.length() - (posOfDecimal + 1));
|
m_decimalFormatter->FractionDigits = static_cast<int>(stringToLocalize.length() - (posOfDecimal + 1));
|
||||||
m_currencyFormatter->FractionDigits = m_currencyMaxFractionDigits;
|
currencyFormatter->FractionDigits = lastCurrencyFractionDigits;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsCurrencyCurrentCategory)
|
if (IsCurrencyCurrentCategory)
|
||||||
{
|
{
|
||||||
wstring currencyResult = m_currencyFormatter->Format(stod(stringToLocalize))->Data();
|
wstring currencyResult = currencyFormatter->Format(stod(stringToLocalize))->Data();
|
||||||
wstring currencyCode = m_currencyFormatter->Currency->Data();
|
wstring currencyCode = currencyFormatter->Currency->Data();
|
||||||
|
|
||||||
// CurrencyFormatter always includes LangCode or Symbol. Make it include LangCode
|
// CurrencyFormatter always includes LangCode or Symbol. Make it include LangCode
|
||||||
// because this includes a non-breaking space. Remove the LangCode.
|
// because this includes a non-breaking space. Remove the LangCode.
|
||||||
|
@ -381,6 +408,10 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st
|
||||||
}
|
}
|
||||||
result = L"-" + result;
|
result = L"-" + result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore the original fraction digits
|
||||||
|
currencyFormatter->FractionDigits = lastCurrencyFractionDigits;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,9 +425,9 @@ void UnitConverterViewModel::DisplayPasteError()
|
||||||
|
|
||||||
void UnitConverterViewModel::UpdateDisplay(const wstring& from, const wstring& to)
|
void UnitConverterViewModel::UpdateDisplay(const wstring& from, const wstring& to)
|
||||||
{
|
{
|
||||||
String ^ fromStr = this->ConvertToLocalizedString(from, true);
|
String ^ fromStr = this->ConvertToLocalizedString(from, true, CurrencyFormatterParameterFrom);
|
||||||
UpdateInputBlocked(from);
|
UpdateInputBlocked(from);
|
||||||
String ^ toStr = this->ConvertToLocalizedString(to, true);
|
String ^ toStr = this->ConvertToLocalizedString(to, true, CurrencyFormatterParameterTo);
|
||||||
|
|
||||||
bool updatedValueFrom = ValueFrom != fromStr;
|
bool updatedValueFrom = ValueFrom != fromStr;
|
||||||
bool updatedValueTo = ValueTo != toStr;
|
bool updatedValueTo = ValueTo != toStr;
|
||||||
|
@ -473,14 +504,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,
|
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 &&
|
// input should be allowed if user just switches active, because we will clear values in such cases
|
||||||
command != UCM::Command::Backspace)
|
if (m_isInputBlocked && !m_model->IsSwitchedActive() && command != UCM::Command::Clear && command != UCM::Command::Backspace)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_model->SendCommand(command);
|
m_model->SendCommand(command);
|
||||||
|
|
||||||
TraceLogger::GetInstance()->LogConverterInputReceived(Mode);
|
TraceLogger::GetInstance()->LogConverterInputReceived(Mode);
|
||||||
}
|
}
|
||||||
|
@ -755,8 +786,8 @@ void UnitConverterViewModel::RefreshSupplementaryResults()
|
||||||
|
|
||||||
for (tuple<wstring, UCM::Unit> suggestedValue : m_cachedSuggestedValues)
|
for (tuple<wstring, UCM::Unit> suggestedValue : m_cachedSuggestedValues)
|
||||||
{
|
{
|
||||||
SupplementaryResult ^ result =
|
SupplementaryResult ^ result = ref new SupplementaryResult(
|
||||||
ref new SupplementaryResult(this->ConvertToLocalizedString(get<0>(suggestedValue), false), ref new Unit(get<1>(suggestedValue)));
|
this->ConvertToLocalizedString(get<0>(suggestedValue), false, CurrencyFormatterParameter::Default), ref new Unit(get<1>(suggestedValue)));
|
||||||
if (result->IsWhimsical())
|
if (result->IsWhimsical())
|
||||||
{
|
{
|
||||||
whimsicals.push_back(result);
|
whimsicals.push_back(result);
|
||||||
|
@ -803,10 +834,46 @@ void UnitConverterViewModel::UpdateInputBlocked(_In_ const wstring& currencyInpu
|
||||||
m_isInputBlocked = false;
|
m_isInputBlocked = false;
|
||||||
if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory)
|
if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory)
|
||||||
{
|
{
|
||||||
m_isInputBlocked = (posOfDecimal + static_cast<size_t>(m_currencyMaxFractionDigits) + 1 == currencyInput.length());
|
m_isInputBlocked = (posOfDecimal + static_cast<size_t>(CurrencyFormatterFrom->FractionDigits) + 1 == currencyInput.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring TruncateFractionDigits(const std::wstring& n, int digitCount)
|
||||||
|
{
|
||||||
|
auto i = n.find('.');
|
||||||
|
if (i == std::wstring::npos)
|
||||||
|
return n;
|
||||||
|
size_t actualDigitCount = n.size() - i - 1;
|
||||||
|
return n.substr(0, n.size() - (actualDigitCount - digitCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
UpdateIsDecimalEnabled();
|
||||||
|
|
||||||
|
OnPaste(ref new String(TruncateFractionDigits(m_valueFromUnlocalized, CurrencyFormatterFrom->FractionDigits).data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnitConverterViewModel::UpdateIsDecimalEnabled()
|
||||||
|
{
|
||||||
|
if (!IsCurrencyCurrentCategory || CurrencyFormatterFrom == nullptr)
|
||||||
|
return;
|
||||||
|
IsDecimalEnabled = CurrencyFormatterFrom->FractionDigits > 0;
|
||||||
|
}
|
||||||
|
|
||||||
NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate)
|
NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate)
|
||||||
{
|
{
|
||||||
static_assert(NumbersAndOperatorsEnum::Zero < NumbersAndOperatorsEnum::One, "NumbersAndOperatorsEnum order is invalid");
|
static_assert(NumbersAndOperatorsEnum::Zero < NumbersAndOperatorsEnum::One, "NumbersAndOperatorsEnum order is invalid");
|
||||||
|
@ -934,14 +1001,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;
|
String ^ valueToLocalize = displayvalue;
|
||||||
if (displayvalue == ValueFrom && Utils::IsLastCharacterTarget(m_valueFromUnlocalized, m_decimalSeparator))
|
if (displayvalue == ValueFrom && Utils::IsLastCharacterTarget(m_valueFromUnlocalized, m_decimalSeparator))
|
||||||
{
|
{
|
||||||
// Need to compute a second localized value for the automation
|
// Need to compute a second localized value for the automation
|
||||||
// name that does not include the decimal separator.
|
// name that does not include the decimal separator.
|
||||||
displayvalue = ConvertToLocalizedString(m_valueFromUnlocalized, false /*allowTrailingDecimal*/);
|
displayvalue = ConvertToLocalizedString(m_valueFromUnlocalized, false /*allowTrailingDecimal*/, cfp);
|
||||||
format = m_localizedValueFromDecimalFormat;
|
format = m_localizedValueFromDecimalFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -962,7 +1034,7 @@ void UnitConverterViewModel::UpdateValue1AutomationName()
|
||||||
{
|
{
|
||||||
if (Unit1)
|
if (Unit1)
|
||||||
{
|
{
|
||||||
Value1AutomationName = GetLocalizedAutomationName(Value1, Unit1->AccessibleName, m_localizedValueFromFormat);
|
Value1AutomationName = GetLocalizedAutomationName(Value1, Unit1->AccessibleName, m_localizedValueFromFormat, CurrencyFormatterParameter::ForValue1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,7 +1042,7 @@ void UnitConverterViewModel::UpdateValue2AutomationName()
|
||||||
{
|
{
|
||||||
if (Unit2)
|
if (Unit2)
|
||||||
{
|
{
|
||||||
Value2AutomationName = GetLocalizedAutomationName(Value2, Unit2->AccessibleName, m_localizedValueToFormat);
|
Value2AutomationName = GetLocalizedAutomationName(Value2, Unit2->AccessibleName, m_localizedValueToFormat, CurrencyFormatterParameter::ForValue1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -227,8 +227,19 @@ namespace CalculatorApp
|
||||||
void OnCopyCommand(Platform::Object ^ parameter);
|
void OnCopyCommand(Platform::Object ^ parameter);
|
||||||
void OnPasteCommand(Platform::Object ^ parameter);
|
void OnPasteCommand(Platform::Object ^ parameter);
|
||||||
|
|
||||||
|
enum class CurrencyFormatterParameter
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
ForValue1,
|
||||||
|
ForValue2,
|
||||||
|
};
|
||||||
|
|
||||||
Platform::String
|
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
|
Platform::String
|
||||||
^ GetLocalizedConversionResultStringFormat(
|
^ GetLocalizedConversionResultStringFormat(
|
||||||
_In_ Platform::String ^ fromValue,
|
_In_ Platform::String ^ fromValue,
|
||||||
|
@ -276,11 +287,13 @@ namespace CalculatorApp
|
||||||
void SupplementaryResultsTimerCancel(Windows::System::Threading::ThreadPoolTimer ^ timer);
|
void SupplementaryResultsTimerCancel(Windows::System::Threading::ThreadPoolTimer ^ timer);
|
||||||
void RefreshSupplementaryResults();
|
void RefreshSupplementaryResults();
|
||||||
void UpdateInputBlocked(_In_ const std::wstring& currencyInput);
|
void UpdateInputBlocked(_In_ const std::wstring& currencyInput);
|
||||||
|
void UpdateCurrencyFormatter();
|
||||||
|
void UpdateIsDecimalEnabled();
|
||||||
bool UnitsAreValid();
|
bool UnitsAreValid();
|
||||||
void ResetCategory();
|
void ResetCategory();
|
||||||
|
|
||||||
void OnButtonPressed(Platform::Object ^ parameter);
|
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<UnitConversionManager::IUnitConverter> m_model;
|
std::shared_ptr<UnitConversionManager::IUnitConverter> m_model;
|
||||||
wchar_t m_decimalSeparator;
|
wchar_t m_decimalSeparator;
|
||||||
|
@ -290,6 +303,34 @@ namespace CalculatorApp
|
||||||
Source,
|
Source,
|
||||||
Target
|
Target
|
||||||
} m_value1cp;
|
} 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
|
property Platform::String^ ValueFrom
|
||||||
{
|
{
|
||||||
Platform::String^ get() { return m_value1cp == ConversionParameter::Source ? Value1 : Value2; }
|
Platform::String^ get() { return m_value1cp == ConversionParameter::Source ? Value1 : Value2; }
|
||||||
|
@ -323,7 +364,8 @@ namespace CalculatorApp
|
||||||
std::mutex m_cacheMutex;
|
std::mutex m_cacheMutex;
|
||||||
Windows::Globalization::NumberFormatting::DecimalFormatter ^ m_decimalFormatter;
|
Windows::Globalization::NumberFormatting::DecimalFormatter ^ m_decimalFormatter;
|
||||||
Windows::Globalization::NumberFormatting::CurrencyFormatter ^ m_currencyFormatter;
|
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_valueFromUnlocalized;
|
||||||
std::wstring m_valueToUnlocalized;
|
std::wstring m_valueToUnlocalized;
|
||||||
bool m_relocalizeStringOnSwitch;
|
bool m_relocalizeStringOnSwitch;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
@ -72,5 +73,21 @@
|
||||||
Click="FeedbackButton_Click"/>
|
Click="FeedbackButton_Click"/>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<RichTextBlock x:Name="AboutFlyoutContribute"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Margin="12,18,12,6"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||||
|
FontSize="{ThemeResource BodyFontSize}"
|
||||||
|
TextWrapping="Wrap">
|
||||||
|
<Paragraph>
|
||||||
|
<Run x:Name="ContributeRunBeforeLink"/><Hyperlink NavigateUri="https://go.microsoft.com/fwlink/?linkid=2099939"
|
||||||
|
TextDecorations="None"
|
||||||
|
ToolTipService.ToolTip="https://go.microsoft.com/fwlink/?linkid=2099939">
|
||||||
|
<Run x:Name="ContributeRunLink"/>
|
||||||
|
</Hyperlink><Run x:Name="ContributeRunAfterLink"/>
|
||||||
|
</Paragraph>
|
||||||
|
</RichTextBlock>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -40,6 +40,8 @@ AboutFlyout::AboutFlyout()
|
||||||
auto copyrightText =
|
auto copyrightText =
|
||||||
LocalizationStringUtil::GetLocalizedString(resourceLoader->GetResourceString("AboutControlCopyright"), StringReference(to_wstring(BUILD_YEAR).c_str()));
|
LocalizationStringUtil::GetLocalizedString(resourceLoader->GetResourceString("AboutControlCopyright"), StringReference(to_wstring(BUILD_YEAR).c_str()));
|
||||||
AboutControlCopyrightRun->Text = copyrightText;
|
AboutControlCopyrightRun->Text = copyrightText;
|
||||||
|
|
||||||
|
InitializeContributeTextBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AboutFlyout::FeedbackButton_Click(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e)
|
void AboutFlyout::FeedbackButton_Click(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e)
|
||||||
|
@ -61,3 +63,30 @@ void AboutFlyout::SetDefaultFocus()
|
||||||
{
|
{
|
||||||
AboutFlyoutEULA->Focus(::FocusState::Programmatic);
|
AboutFlyoutEULA->Focus(::FocusState::Programmatic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AboutFlyout::InitializeContributeTextBlock()
|
||||||
|
{
|
||||||
|
auto resProvider = AppResourceProvider::GetInstance();
|
||||||
|
std::wstring contributeHyperlinkText = resProvider->GetResourceString(L"AboutFlyoutContribute")->Data();
|
||||||
|
|
||||||
|
// The resource string has the 'GitHub' hyperlink wrapped with '%HL%'.
|
||||||
|
// Break the string and assign pieces appropriately.
|
||||||
|
static const std::wstring delimiter{ L"%HL%" };
|
||||||
|
static const size_t delimiterLength{ delimiter.length() };
|
||||||
|
|
||||||
|
// Find the delimiters.
|
||||||
|
size_t firstSplitPosition = contributeHyperlinkText.find(delimiter, 0);
|
||||||
|
assert(firstSplitPosition != std::wstring::npos);
|
||||||
|
size_t secondSplitPosition = contributeHyperlinkText.find(delimiter, firstSplitPosition + 1);
|
||||||
|
assert(secondSplitPosition != std::wstring::npos);
|
||||||
|
size_t hyperlinkTextLength = secondSplitPosition - (firstSplitPosition + delimiterLength);
|
||||||
|
|
||||||
|
// Assign pieces.
|
||||||
|
auto contributeTextBeforeHyperlink = ref new String(contributeHyperlinkText.substr(0, firstSplitPosition).c_str());
|
||||||
|
auto contributeTextLink = ref new String(contributeHyperlinkText.substr(firstSplitPosition + delimiterLength, hyperlinkTextLength).c_str());
|
||||||
|
auto contributeTextAfterHyperlink = ref new String(contributeHyperlinkText.substr(secondSplitPosition + delimiterLength).c_str());
|
||||||
|
|
||||||
|
ContributeRunBeforeLink->Text = contributeTextBeforeHyperlink;
|
||||||
|
ContributeRunLink->Text = contributeTextLink;
|
||||||
|
ContributeRunAfterLink->Text = contributeTextAfterHyperlink;
|
||||||
|
}
|
||||||
|
|
|
@ -18,5 +18,6 @@ public
|
||||||
private:
|
private:
|
||||||
void FeedbackButton_Click(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
|
void FeedbackButton_Click(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
|
||||||
void SetVersionString();
|
void SetVersionString();
|
||||||
|
void InitializeContributeTextBlock();
|
||||||
};
|
};
|
||||||
} /* namespace CalculatorApp */
|
} /* namespace CalculatorApp */
|
||||||
|
|
|
@ -2717,6 +2717,10 @@
|
||||||
<value>© %1 Microsoft. All rights reserved.</value>
|
<value>© %1 Microsoft. All rights reserved.</value>
|
||||||
<comment>{Locked="%1"}. Copyright statement, displayed on the About panel. %1 = the current year (4 digits)</comment>
|
<comment>{Locked="%1"}. Copyright statement, displayed on the About panel. %1 = the current year (4 digits)</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="AboutFlyoutContribute" xml:space="preserve">
|
||||||
|
<value>To learn how you can contribute to Windows Calculator, check out the project on %HL%GitHub%HL%.</value>
|
||||||
|
<comment>{Locked="%HL%GitHub%HL%"}. GitHub link, Displayed on the About panel</comment>
|
||||||
|
</data>
|
||||||
<data name="AboutButton.Content" xml:space="preserve">
|
<data name="AboutButton.Content" xml:space="preserve">
|
||||||
<value>About</value>
|
<value>About</value>
|
||||||
<comment>The text that shows in the dropdown navigation control to open About panel</comment>
|
<comment>The text that shows in the dropdown navigation control to open About panel</comment>
|
||||||
|
|
|
@ -3392,15 +3392,15 @@
|
||||||
<comment>Error displayed when parity is cannot be determined</comment>
|
<comment>Error displayed when parity is cannot be determined</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="KGFParityEven" xml:space="preserve">
|
<data name="KGFParityEven" xml:space="preserve">
|
||||||
<value>此函数为偶数。</value>
|
<value>此函数为偶函数。</value>
|
||||||
<comment>Message displayed with the function parity is even</comment>
|
<comment>Message displayed with the function parity is even</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="KGFParityNeither" xml:space="preserve">
|
<data name="KGFParityNeither" xml:space="preserve">
|
||||||
<value>此函数既不是偶数也不是奇数。</value>
|
<value>此函数既不是偶函数也不是奇函数。</value>
|
||||||
<comment>Message displayed with the function parity is neither even nor odd</comment>
|
<comment>Message displayed with the function parity is neither even nor odd</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="KGFParityOdd" xml:space="preserve">
|
<data name="KGFParityOdd" xml:space="preserve">
|
||||||
<value>函数为奇数。</value>
|
<value>此函数为奇函数。</value>
|
||||||
<comment>Message displayed with the function parity is odd</comment>
|
<comment>Message displayed with the function parity is odd</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="KGFParityUnknown" xml:space="preserve">
|
<data name="KGFParityUnknown" xml:space="preserve">
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<Style x:Key="AboutFlyoutPresenterStyle" TargetType="FlyoutPresenter">
|
<Style x:Key="AboutFlyoutPresenterStyle" TargetType="FlyoutPresenter">
|
||||||
<Setter Property="IsTabStop" Value="False"/>
|
<Setter Property="IsTabStop" Value="False"/>
|
||||||
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw"/>
|
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw"/>
|
||||||
|
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="NavViewItemStyle" TargetType="muxc:NavigationViewItem">
|
<Style x:Key="NavViewItemStyle" TargetType="muxc:NavigationViewItem">
|
||||||
<Setter Property="KeyTipPlacementMode" Value="Right"/>
|
<Setter Property="KeyTipPlacementMode" Value="Right"/>
|
||||||
|
@ -174,18 +175,18 @@
|
||||||
|
|
||||||
<muxc:NavigationView.PaneFooter>
|
<muxc:NavigationView.PaneFooter>
|
||||||
<muxc:NavigationViewItem x:Name="AboutButton"
|
<muxc:NavigationViewItem x:Name="AboutButton"
|
||||||
x:Uid="AboutButton"
|
x:Uid="AboutButton"
|
||||||
Style="{StaticResource NavViewItemStyle}"
|
Style="{StaticResource NavViewItemStyle}"
|
||||||
Tapped="OnAboutButtonClick">
|
Tapped="OnAboutButtonClick">
|
||||||
<muxc:NavigationViewItem.Icon>
|
<muxc:NavigationViewItem.Icon>
|
||||||
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph=""/>
|
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph=""/>
|
||||||
</muxc:NavigationViewItem.Icon>
|
</muxc:NavigationViewItem.Icon>
|
||||||
<FlyoutBase.AttachedFlyout>
|
<FlyoutBase.AttachedFlyout>
|
||||||
<Flyout x:Name="AboutPageFlyout"
|
<Flyout x:Name="AboutPageFlyout"
|
||||||
x:Uid="AboutPageFlyout"
|
x:Uid="AboutPageFlyout"
|
||||||
Closed="OnAboutFlyoutClosed"
|
Closed="OnAboutFlyoutClosed"
|
||||||
FlyoutPresenterStyle="{StaticResource AboutFlyoutPresenterStyle}"
|
FlyoutPresenterStyle="{StaticResource AboutFlyoutPresenterStyle}"
|
||||||
Opened="OnAboutFlyoutOpened">
|
Opened="OnAboutFlyoutOpened">
|
||||||
<local:AboutFlyout x:Name="AboutPage" x:Load="False"/>
|
<local:AboutFlyout x:Name="AboutPage" x:Load="False"/>
|
||||||
</Flyout>
|
</Flyout>
|
||||||
</FlyoutBase.AttachedFlyout>
|
</FlyoutBase.AttachedFlyout>
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
<Grid x:Name="BackgroundElement"
|
<Grid x:Name="BackgroundElement"
|
||||||
Height="32"
|
|
||||||
Background="Transparent">
|
Background="Transparent">
|
||||||
<TextBlock x:Name="AppName"
|
<TextBlock x:Name="AppName"
|
||||||
x:Uid="AppName"
|
x:Uid="AppName"
|
||||||
|
@ -36,7 +35,6 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{ThemeResource TitleBarForegroundBaseHighBrush}"
|
Foreground="{ThemeResource TitleBarForegroundBaseHighBrush}"
|
||||||
FontSize="12"
|
FontSize="12"
|
||||||
TextAlignment="Left"
|
|
||||||
TextTrimming="CharacterEllipsis"/>
|
TextTrimming="CharacterEllipsis"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Button x:Name="ExitAlwaysOnTopButton"
|
<Button x:Name="ExitAlwaysOnTopButton"
|
||||||
|
|
|
@ -11,6 +11,7 @@ using namespace Platform;
|
||||||
using namespace Windows::ApplicationModel;
|
using namespace Windows::ApplicationModel;
|
||||||
using namespace Windows::ApplicationModel::Core;
|
using namespace Windows::ApplicationModel::Core;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
|
using namespace Windows::System::Profile;
|
||||||
using namespace Windows::UI;
|
using namespace Windows::UI;
|
||||||
using namespace Windows::UI::Core;
|
using namespace Windows::UI::Core;
|
||||||
using namespace Windows::UI::ViewManagement;
|
using namespace Windows::UI::ViewManagement;
|
||||||
|
@ -45,13 +46,13 @@ namespace CalculatorApp
|
||||||
|
|
||||||
void TitleBar::OnLoaded(_In_ Object ^ /*sender*/, _In_ RoutedEventArgs ^ /*e*/)
|
void TitleBar::OnLoaded(_In_ Object ^ /*sender*/, _In_ RoutedEventArgs ^ /*e*/)
|
||||||
{
|
{
|
||||||
|
auto that(this);
|
||||||
// Register events
|
// Register events
|
||||||
m_visibilityChangedToken = m_coreTitleBar->IsVisibleChanged += ref new TypedEventHandler<CoreApplicationViewTitleBar ^, Object ^>(
|
m_visibilityChangedToken = m_coreTitleBar->IsVisibleChanged += ref new TypedEventHandler<CoreApplicationViewTitleBar ^, Object ^>(
|
||||||
[this](CoreApplicationViewTitleBar ^ cTitleBar, Object ^) { this->SetTitleBarVisibility(); });
|
[that](CoreApplicationViewTitleBar ^ cTitleBar, Object ^) { that->SetTitleBarVisibility(false); });
|
||||||
m_layoutChangedToken = m_coreTitleBar->LayoutMetricsChanged +=
|
m_layoutChangedToken = m_coreTitleBar->LayoutMetricsChanged +=
|
||||||
ref new TypedEventHandler<CoreApplicationViewTitleBar ^, Object ^>([this](CoreApplicationViewTitleBar ^ cTitleBar, Object ^) {
|
ref new TypedEventHandler<CoreApplicationViewTitleBar ^, Object ^>([that](CoreApplicationViewTitleBar ^ cTitleBar, Object ^) {
|
||||||
this->SetTitleBarHeight();
|
that->SetTitleBarHeightAndPadding();
|
||||||
this->SetTitleBarPadding();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
m_colorValuesChangedToken = m_uiSettings->ColorValuesChanged += ref new TypedEventHandler<UISettings ^, Object ^>(this, &TitleBar::ColorValuesChanged);
|
m_colorValuesChangedToken = m_uiSettings->ColorValuesChanged += ref new TypedEventHandler<UISettings ^, Object ^>(this, &TitleBar::ColorValuesChanged);
|
||||||
|
@ -60,10 +61,15 @@ namespace CalculatorApp
|
||||||
m_windowActivatedToken = Window::Current->Activated +=
|
m_windowActivatedToken = Window::Current->Activated +=
|
||||||
ref new Windows::UI::Xaml::WindowActivatedEventHandler(this, &CalculatorApp::TitleBar::OnWindowActivated);
|
ref new Windows::UI::Xaml::WindowActivatedEventHandler(this, &CalculatorApp::TitleBar::OnWindowActivated);
|
||||||
// Set properties
|
// Set properties
|
||||||
this->SetTitleBarHeight();
|
SetTitleBarControlColors();
|
||||||
this->SetTitleBarControlColors();
|
SetTitleBarHeightAndPadding();
|
||||||
this->SetTitleBarVisibility();
|
|
||||||
this->SetTitleBarPadding();
|
// As of Windows 10 1903: when an app runs on a PC (without Tablet mode activated)
|
||||||
|
// properties of CoreApplicationViewTitleBar aren't initialized during the first seconds after launch.
|
||||||
|
auto forceDisplay = AnalyticsInfo::VersionInfo->DeviceFamily == L"Windows.Desktop"
|
||||||
|
&& UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Mouse;
|
||||||
|
|
||||||
|
SetTitleBarVisibility(forceDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleBar::OnUnloaded(_In_ Object ^ /*sender*/, _In_ RoutedEventArgs ^ /*e*/)
|
void TitleBar::OnUnloaded(_In_ Object ^ /*sender*/, _In_ RoutedEventArgs ^ /*e*/)
|
||||||
|
@ -81,18 +87,20 @@ namespace CalculatorApp
|
||||||
m_windowActivatedToken.Value = 0;
|
m_windowActivatedToken.Value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleBar::SetTitleBarVisibility()
|
void TitleBar::SetTitleBarVisibility(bool forceDisplay)
|
||||||
{
|
{
|
||||||
this->LayoutRoot->Visibility = m_coreTitleBar->IsVisible || IsAlwaysOnTopMode ? ::Visibility::Visible : ::Visibility::Collapsed;
|
this->LayoutRoot->Visibility =
|
||||||
|
forceDisplay || m_coreTitleBar->IsVisible || IsAlwaysOnTopMode ? ::Visibility::Visible : ::Visibility::Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleBar::SetTitleBarHeight()
|
void TitleBar::SetTitleBarHeightAndPadding()
|
||||||
{
|
{
|
||||||
this->LayoutRoot->Height = m_coreTitleBar->Height;
|
if (m_coreTitleBar->Height == 0)
|
||||||
}
|
{
|
||||||
|
// The titlebar isn't init
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void TitleBar::SetTitleBarPadding()
|
|
||||||
{
|
|
||||||
double leftAddition = 0;
|
double leftAddition = 0;
|
||||||
double rightAddition = 0;
|
double rightAddition = 0;
|
||||||
|
|
||||||
|
@ -108,11 +116,13 @@ namespace CalculatorApp
|
||||||
}
|
}
|
||||||
|
|
||||||
this->LayoutRoot->Padding = Thickness(leftAddition, 0, rightAddition, 0);
|
this->LayoutRoot->Padding = Thickness(leftAddition, 0, rightAddition, 0);
|
||||||
|
this->LayoutRoot->Height = m_coreTitleBar->Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleBar::ColorValuesChanged(_In_ UISettings ^ /*sender*/, _In_ Object ^ /*e*/)
|
void TitleBar::ColorValuesChanged(_In_ UISettings ^ /*sender*/, _In_ Object ^ /*e*/)
|
||||||
{
|
{
|
||||||
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this]() { SetTitleBarControlColors(); }));
|
auto that(this);
|
||||||
|
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([that]() { that->SetTitleBarControlColors(); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleBar::SetTitleBarControlColors()
|
void TitleBar::SetTitleBarControlColors()
|
||||||
|
@ -164,9 +174,10 @@ namespace CalculatorApp
|
||||||
|
|
||||||
void TitleBar::OnHighContrastChanged(_In_ AccessibilitySettings ^ /*sender*/, _In_ Object ^ /*args*/)
|
void TitleBar::OnHighContrastChanged(_In_ AccessibilitySettings ^ /*sender*/, _In_ Object ^ /*args*/)
|
||||||
{
|
{
|
||||||
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this]() {
|
auto that(this);
|
||||||
SetTitleBarControlColors();
|
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([that]() {
|
||||||
SetTitleBarVisibility();
|
that->SetTitleBarControlColors();
|
||||||
|
that->SetTitleBarVisibility(false);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +189,7 @@ namespace CalculatorApp
|
||||||
|
|
||||||
void TitleBar::OnIsAlwaysOnTopModePropertyChanged(bool /*oldValue*/, bool newValue)
|
void TitleBar::OnIsAlwaysOnTopModePropertyChanged(bool /*oldValue*/, bool newValue)
|
||||||
{
|
{
|
||||||
SetTitleBarVisibility();
|
SetTitleBarVisibility(false);
|
||||||
VisualStateManager::GoToState(this, newValue ? "AOTMiniState" : "AOTNormalState", false);
|
VisualStateManager::GoToState(this, newValue ? "AOTMiniState" : "AOTNormalState", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,8 @@ public
|
||||||
void OnLoaded(_In_ Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
|
void OnLoaded(_In_ Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
|
||||||
void OnUnloaded(_In_ Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
|
void OnUnloaded(_In_ Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
|
||||||
|
|
||||||
void SetTitleBarVisibility();
|
void SetTitleBarVisibility(bool forceDisplay);
|
||||||
void SetTitleBarHeight();
|
void SetTitleBarHeightAndPadding();
|
||||||
void SetTitleBarPadding();
|
|
||||||
void SetTitleBarControlColors();
|
void SetTitleBarControlColors();
|
||||||
void ColorValuesChanged(_In_ Windows::UI::ViewManagement::UISettings ^ sender, _In_ Platform::Object ^ e);
|
void ColorValuesChanged(_In_ Windows::UI::ViewManagement::UISettings ^ sender, _In_ Platform::Object ^ e);
|
||||||
void OnHighContrastChanged(Windows::UI::ViewManagement::AccessibilitySettings ^ sender, Platform::Object ^ args);
|
void OnHighContrastChanged(Windows::UI::ViewManagement::AccessibilitySettings ^ sender, Platform::Object ^ args);
|
||||||
|
|
|
@ -35,6 +35,14 @@ namespace CalculatorUITestFramework
|
||||||
AppName.Click();
|
AppName.Click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Click the window (to lose focus on components)
|
||||||
|
/// </summary>
|
||||||
|
public static void ClickOnWindow()
|
||||||
|
{
|
||||||
|
Window.Click();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If the the Dock Panel for the History and Memory lists is not displayed, resize the window
|
/// If the the Dock Panel for the History and Memory lists is not displayed, resize the window
|
||||||
/// Two attempts are made, the the lable is not found a "not found" exception is thrown
|
/// Two attempts are made, the the lable is not found a "not found" exception is thrown
|
||||||
|
|
|
@ -13,5 +13,7 @@ namespace CalculatorUITestFramework
|
||||||
public NumberPad NumberPad = new NumberPad();
|
public NumberPad NumberPad = new NumberPad();
|
||||||
public WindowsElement ClearButton => this.session.TryFindElementByAccessibilityId("ClearEntryButtonPos0");
|
public WindowsElement ClearButton => this.session.TryFindElementByAccessibilityId("ClearEntryButtonPos0");
|
||||||
public WindowsElement BackSpaceButton => this.session.TryFindElementByAccessibilityId("BackSpaceButtonSmall");
|
public WindowsElement BackSpaceButton => this.session.TryFindElementByAccessibilityId("BackSpaceButtonSmall");
|
||||||
|
public WindowsElement Units1 => this.session.TryFindElementByAccessibilityId("Units1");
|
||||||
|
public WindowsElement Units2 => this.session.TryFindElementByAccessibilityId("Units2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,5 +64,44 @@ namespace CalculatorUITestFramework
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensure Units1 and Units2 are the same
|
||||||
|
/// </summary>
|
||||||
|
public void EnsureSameUnitsAreSelected()
|
||||||
|
{
|
||||||
|
CalculatorApp.ClickOnWindow();
|
||||||
|
UnitConverterOperators.Units1.SendKeys(OpenQA.Selenium.Keys.Home);
|
||||||
|
UnitConverterOperators.Units1.SendKeys(OpenQA.Selenium.Keys.Enter);
|
||||||
|
|
||||||
|
CalculatorApp.ClickOnWindow();
|
||||||
|
UnitConverterOperators.Units2.SendKeys(OpenQA.Selenium.Keys.Home);
|
||||||
|
UnitConverterOperators.Units2.SendKeys(OpenQA.Selenium.Keys.Enter);
|
||||||
|
|
||||||
|
CalculatorApp.ClickOnWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Select value in Units1 ComboBox
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value in ComboBox Units1</param>
|
||||||
|
public void SelectUnits1(string value)
|
||||||
|
{
|
||||||
|
CalculatorApp.ClickOnWindow();
|
||||||
|
UnitConverterOperators.Units1.SendKeys(value);
|
||||||
|
UnitConverterOperators.Units1.SendKeys(OpenQA.Selenium.Keys.Enter);
|
||||||
|
CalculatorApp.ClickOnWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Select value in Units2 ComboBox
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value in ComboBox Units2</param>
|
||||||
|
public void SelectUnits2(string value)
|
||||||
|
{
|
||||||
|
CalculatorApp.ClickOnWindow();
|
||||||
|
UnitConverterOperators.Units2.SendKeys(value);
|
||||||
|
UnitConverterOperators.Units2.SendKeys(OpenQA.Selenium.Keys.Enter);
|
||||||
|
CalculatorApp.ClickOnWindow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,5 +8,7 @@
|
||||||
</DataCollectionRunSettings>
|
</DataCollectionRunSettings>
|
||||||
<TestRunParameters>
|
<TestRunParameters>
|
||||||
<Parameter Name="AppId" Value="Microsoft.WindowsCalculator.Dev_8wekyb3d8bbwe!App" />
|
<Parameter Name="AppId" Value="Microsoft.WindowsCalculator.Dev_8wekyb3d8bbwe!App" />
|
||||||
|
<Parameter Name="CurrencyWith3FractionalDigits" Value="Test Fractional Digits - Test Fractional Digits" />
|
||||||
|
<Parameter Name="CurrencyWithoutFractionalDigits" Value="Test No Fractional Digits - Test No Fractional Digits" />
|
||||||
</TestRunParameters>
|
</TestRunParameters>
|
||||||
</RunSettings>
|
</RunSettings>
|
||||||
|
|
|
@ -8,5 +8,7 @@
|
||||||
</DataCollectionRunSettings>
|
</DataCollectionRunSettings>
|
||||||
<TestRunParameters>
|
<TestRunParameters>
|
||||||
<Parameter Name="AppId" Value="Microsoft.WindowsCalculator_8wekyb3d8bbwe!App" />
|
<Parameter Name="AppId" Value="Microsoft.WindowsCalculator_8wekyb3d8bbwe!App" />
|
||||||
|
<Parameter Name="CurrencyWith3FractionalDigits" Value="Jordan - Dinar" />
|
||||||
|
<Parameter Name="CurrencyWithoutFractionalDigits" Value="Japan - Yen" />
|
||||||
</TestRunParameters>
|
</TestRunParameters>
|
||||||
</RunSettings>
|
</RunSettings>
|
||||||
|
|
|
@ -12,6 +12,8 @@ namespace CalculatorUITests
|
||||||
{
|
{
|
||||||
private static UnitConverterPage page = new UnitConverterPage();
|
private static UnitConverterPage page = new UnitConverterPage();
|
||||||
|
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the WinAppDriver web driver session.
|
/// Initializes the WinAppDriver web driver session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -42,6 +44,7 @@ namespace CalculatorUITests
|
||||||
CalculatorApp.EnsureCalculatorHasFocus();
|
CalculatorApp.EnsureCalculatorHasFocus();
|
||||||
page.EnsureCalculatorIsCurrencyMode();
|
page.EnsureCalculatorIsCurrencyMode();
|
||||||
page.EnsureCalculatorResultTextIsZero();
|
page.EnsureCalculatorResultTextIsZero();
|
||||||
|
page.EnsureSameUnitsAreSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCleanup]
|
[TestCleanup]
|
||||||
|
@ -50,6 +53,23 @@ namespace CalculatorUITests
|
||||||
page.ClearAll();
|
page.ClearAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string NormalizeCurrencyText(string realValue, int fractionDigits)
|
||||||
|
{
|
||||||
|
if (!realValue.Contains('.')) return realValue;
|
||||||
|
|
||||||
|
var parts = realValue.Split('.');
|
||||||
|
if (parts[1].Length < fractionDigits)
|
||||||
|
{
|
||||||
|
parts[1] += new string('0', fractionDigits - parts[1].Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parts[1] = parts[1].Substring(0, fractionDigits);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{parts[0]}.{parts[1]}".TrimEnd('.');
|
||||||
|
}
|
||||||
|
|
||||||
#region Basic UI Functionality via Mouse Input Tests
|
#region Basic UI Functionality via Mouse Input Tests
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// These automated tests verify clicking each of the buttons in the Calculator UI and getting an expected result
|
/// These automated tests verify clicking each of the buttons in the Calculator UI and getting an expected result
|
||||||
|
@ -129,6 +149,153 @@ namespace CalculatorUITests
|
||||||
Assert.AreEqual("0", page.UnitConverterResults.GetCalculationResult2Text()); //verifies Backspace button clicks
|
Assert.AreEqual("0", page.UnitConverterResults.GetCalculationResult2Text()); //verifies Backspace button clicks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// These automated tests verify the currency has been formatted to 3 fractional digits
|
||||||
|
/// Via mouse input, all basic UI functionality is checked
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
[Priority(0)]
|
||||||
|
public void MouseInput_SelectCurrencyWith3FractionalDigitsEnterInputAndCheckTheFormat()
|
||||||
|
{
|
||||||
|
var currency = (string)TestContext.Properties["CurrencyWith3FractionalDigits"];
|
||||||
|
var fractionDigits = 3;
|
||||||
|
|
||||||
|
//Verifies fraction digits in given currency
|
||||||
|
page.SelectUnits1(currency);
|
||||||
|
Assert.AreEqual(currency.Replace(" - ", " "), page.UnitConverterOperators.Units1.Text); // Text is the AccessibleName of Unit
|
||||||
|
page.UnitConverterOperators.NumberPad.Num2Button.Click();
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("2", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies 2 button
|
||||||
|
page.UnitConverterOperators.NumberPad.DecimalButton.Click();
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("2.", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies decimal button
|
||||||
|
page.UnitConverterOperators.NumberPad.Num4Button.Click();
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("2.4", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies 4 button
|
||||||
|
page.UnitConverterOperators.NumberPad.Num3Button.Click();
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("2.43", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies 3 button
|
||||||
|
page.UnitConverterOperators.NumberPad.Num5Button.Click();
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("2.435", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies 5 button
|
||||||
|
page.UnitConverterOperators.NumberPad.Num6Button.Click();
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("2.4356", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies 6 button
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// These automated tests verify the currency has been formatted to no fractional digit
|
||||||
|
/// Via mouse input, all basic UI functionality is checked
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
[Priority(0)]
|
||||||
|
public void MouseInput_SelectCurrencyWithoutFractionalDigitEnterInputAndCheckTheFormat()
|
||||||
|
{
|
||||||
|
var currency = (string)TestContext.Properties["CurrencyWithoutFractionalDigits"];
|
||||||
|
var fractionDigits = 0;
|
||||||
|
|
||||||
|
//Verifies fraction digits in given currency
|
||||||
|
page.SelectUnits1(currency);
|
||||||
|
Assert.AreEqual(currency.Replace(" - ", " "), page.UnitConverterOperators.Units1.Text); // Text is the AccessibleName of Unit
|
||||||
|
page.UnitConverterOperators.NumberPad.Num2Button.Click();
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("2", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies 2 button
|
||||||
|
page.UnitConverterOperators.NumberPad.DecimalButton.Click(); // It should be disabled, so no decimal will be displayed
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("2", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies decimal button
|
||||||
|
page.UnitConverterOperators.NumberPad.Num4Button.Click(); // As decimal is disabled, 4 won't be part of fraction digits
|
||||||
|
Assert.AreEqual(NormalizeCurrencyText("24", fractionDigits), page.UnitConverterResults.GetCalculationResult1Text()); //verifies 4 button
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// These automated tests verify the currency format is updated after switching
|
||||||
|
/// Via mouse input, all basic UI functionality is checked
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
[Priority(0)]
|
||||||
|
public void MouseInput_SwitchCurrencyWithDifferentFractionalDigitsAndCheckTheFormat()
|
||||||
|
{
|
||||||
|
var currencyWith3FractionalDigits = (string)TestContext.Properties["CurrencyWith3FractionalDigits"];
|
||||||
|
var currencyWithoutFractionalDigits = (string)TestContext.Properties["CurrencyWithoutFractionalDigits"];
|
||||||
|
|
||||||
|
//Verifies fraction digits in given currency
|
||||||
|
page.SelectUnits1(currencyWith3FractionalDigits);
|
||||||
|
page.UnitConverterOperators.NumberPad.Num2Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.DecimalButton.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num4Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num3Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num5Button.Click();
|
||||||
|
Assert.AreEqual("2.435", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
|
||||||
|
page.SelectUnits1(currencyWithoutFractionalDigits);
|
||||||
|
Assert.AreEqual("2", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
|
||||||
|
// The digits will be truncated forever, even if swiching back
|
||||||
|
page.SelectUnits1(currencyWith3FractionalDigits);
|
||||||
|
Assert.AreEqual("2", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// These automated tests verify input is not blocked after swiching to currency with less fractional digits
|
||||||
|
/// Via mouse input, all basic UI functionality is checked
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
[Priority(0)]
|
||||||
|
public void MouseInput_SwitchCurrencyWithLessFractionalDigitsAndEnterInput()
|
||||||
|
{
|
||||||
|
var currencyWith3FractionalDigits = (string)TestContext.Properties["CurrencyWith3FractionalDigits"];
|
||||||
|
var currencyWithoutFractionalDigits = (string)TestContext.Properties["CurrencyWithoutFractionalDigits"];
|
||||||
|
|
||||||
|
//Verifies fraction digits in given currency
|
||||||
|
page.SelectUnits1(currencyWith3FractionalDigits);
|
||||||
|
page.UnitConverterOperators.NumberPad.Num2Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.DecimalButton.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num4Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num3Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num5Button.Click();
|
||||||
|
Assert.AreEqual("2.435", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
|
||||||
|
page.SelectUnits1(currencyWithoutFractionalDigits);
|
||||||
|
Assert.AreEqual("2", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
|
||||||
|
page.UnitConverterOperators.NumberPad.Num4Button.Click(); // Enter new number will replace the previous value
|
||||||
|
Assert.AreEqual("4", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
|
||||||
|
page.SelectUnits1(currencyWith3FractionalDigits);
|
||||||
|
Assert.AreEqual("4", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// These automated tests verify the result consists after swiching currency
|
||||||
|
/// Via mouse input, all basic UI functionality is checked
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
[Priority(0)]
|
||||||
|
public void MouseInput_SwitchCurrencyWithLessFractionalDigitsAndCheckIfTheResultIsConsistent()
|
||||||
|
{
|
||||||
|
var currencyWith3FractionalDigits = (string)TestContext.Properties["CurrencyWith3FractionalDigits"];
|
||||||
|
var currencyWithoutFractionalDigits = (string)TestContext.Properties["CurrencyWithoutFractionalDigits"];
|
||||||
|
|
||||||
|
page.SelectUnits1(currencyWith3FractionalDigits);
|
||||||
|
page.SelectUnits2(currencyWith3FractionalDigits);
|
||||||
|
|
||||||
|
page.UnitConverterOperators.NumberPad.Num2Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num0Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num0Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.DecimalButton.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num9Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num9Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num9Button.Click();
|
||||||
|
|
||||||
|
Assert.AreEqual("200.999", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
Assert.AreEqual("200.999", page.UnitConverterResults.GetCalculationResult2Text());
|
||||||
|
|
||||||
|
page.SelectUnits1(currencyWithoutFractionalDigits);
|
||||||
|
Assert.AreEqual("200", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
var result = page.UnitConverterResults.GetCalculationResult2Text();
|
||||||
|
|
||||||
|
page.UnitConverterOperators.ClearButton.Click();
|
||||||
|
|
||||||
|
page.UnitConverterOperators.NumberPad.Num2Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num0Button.Click();
|
||||||
|
page.UnitConverterOperators.NumberPad.Num0Button.Click();
|
||||||
|
|
||||||
|
Assert.AreEqual("200", page.UnitConverterResults.GetCalculationResult1Text());
|
||||||
|
Assert.AreEqual(result, page.UnitConverterResults.GetCalculationResult2Text());
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -825,9 +825,13 @@ namespace CalculatorUnitTests
|
||||||
L"12^2",
|
L"12^2",
|
||||||
L"-12.12^-2",
|
L"-12.12^-2",
|
||||||
L"61%99"
|
L"61%99"
|
||||||
L"-6.1%99" };
|
L"-6.1%99",
|
||||||
|
L"1.1111111111111111111111111111111e+1142" };
|
||||||
String
|
String
|
||||||
^ negativeInput[] = { L"abcdef", L"xyz", L"ABab", L"e+234", L"123456789123456781234567890123456" /*boundary condition: greater than 32 digits*/,
|
^ negativeInput[] = { L"abcdef", L"xyz", L"ABab", L"e+234", L"123456789123456781234567890123456" /*boundary condition: greater than 32 digits*/,
|
||||||
|
L"11.1111111111111111111111111111111e+1142",
|
||||||
|
L"1.1e+10001", /*boundary condition: exponent greater than 5 digits*/
|
||||||
|
L"0.11111111111111111111111111111111111e+111111" /*boundary condition: both exponent and non exponent exceed limits*/
|
||||||
L"SIN(2)", L"2+2==", L"2=+2" };
|
L"SIN(2)", L"2+2==", L"2=+2" };
|
||||||
|
|
||||||
ASSERT_POSITIVE_TESTCASES(ValidateScientificPasteExpression, positiveInput);
|
ASSERT_POSITIVE_TESTCASES(ValidateScientificPasteExpression, positiveInput);
|
||||||
|
|
|
@ -685,7 +685,7 @@ TEST_METHOD(InitializeMultipleConverterTest)
|
||||||
viewModels[i] = ref new UnitConverterViewModel(unitConverterMocks[i]);
|
viewModels[i] = ref new UnitConverterViewModel(unitConverterMocks[i]);
|
||||||
IObservableVector<Category ^> ^ cats = viewModels[i]->Categories;
|
IObservableVector<Category ^> ^ cats = viewModels[i]->Categories;
|
||||||
VERIFY_ARE_EQUAL((UINT)1, unitConverterMocks[i]->m_getCategoriesCallCount);
|
VERIFY_ARE_EQUAL((UINT)1, unitConverterMocks[i]->m_getCategoriesCallCount);
|
||||||
VERIFY_ARE_EQUAL((UINT)3, cats->Size);
|
VERIFY_ARE_EQUAL((UINT)4, cats->Size);
|
||||||
// Verify that we match current category
|
// Verify that we match current category
|
||||||
VERIFY_IS_TRUE(CAT2 == viewModels[i]->CurrentCategory->GetModelCategory());
|
VERIFY_IS_TRUE(CAT2 == viewModels[i]->CurrentCategory->GetModelCategory());
|
||||||
}
|
}
|
||||||
|
@ -697,7 +697,7 @@ TEST_METHOD(InitializeMultipleConverterTest)
|
||||||
// Verify that the instance properties were set independently
|
// Verify that the instance properties were set independently
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
VERIFY_ARE_EQUAL((UINT)3, viewModels[i]->Categories->Size);
|
VERIFY_ARE_EQUAL((UINT)4, viewModels[i]->Categories->Size);
|
||||||
VERIFY_ARE_EQUAL((UINT)3, viewModels[i]->Units->Size);
|
VERIFY_ARE_EQUAL((UINT)3, viewModels[i]->Units->Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,7 @@ vector<UCM::Category> UnitConverterMock::GetCategories()
|
||||||
cats.push_back(CAT1);
|
cats.push_back(CAT1);
|
||||||
cats.push_back(CAT2);
|
cats.push_back(CAT2);
|
||||||
cats.push_back(CAT3);
|
cats.push_back(CAT3);
|
||||||
|
cats.push_back(CAT_CURRENCY);
|
||||||
|
|
||||||
m_curCategory = CAT2;
|
m_curCategory = CAT2;
|
||||||
|
|
||||||
|
@ -174,6 +175,10 @@ UCM::CategorySelectionInitializer UnitConverterMock::SetCurrentCategory(const UC
|
||||||
units.push_back(UNIT9);
|
units.push_back(UNIT9);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CURRENCY_ID:
|
||||||
|
units.push_back(UNITJPY);
|
||||||
|
units.push_back(UNITJOD);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -215,10 +220,15 @@ void UnitConverterMock::SwitchActive(const std::wstring& newValue)
|
||||||
m_curValue = newValue;
|
m_curValue = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring UnitConverterMock::SaveUserPreferences()
|
bool UnitConverterMock::IsSwitchedActive() const
|
||||||
{
|
{
|
||||||
return L"TEST";
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
std::wstring UnitConverterMock::SaveUserPreferences()
|
||||||
|
{
|
||||||
|
return L"TEST";
|
||||||
|
};
|
||||||
|
|
||||||
void UnitConverterMock::RestoreUserPreferences(_In_ std::wstring_view /*userPreferences*/){};
|
void UnitConverterMock::RestoreUserPreferences(_In_ std::wstring_view /*userPreferences*/){};
|
||||||
|
|
||||||
|
@ -341,7 +351,7 @@ TEST_METHOD(TestUnitConverterLoadSetsUpCategories)
|
||||||
VM::UnitConverterViewModel vm(mock);
|
VM::UnitConverterViewModel vm(mock);
|
||||||
IObservableVector<VM::Category ^> ^ cats = vm.Categories;
|
IObservableVector<VM::Category ^> ^ cats = vm.Categories;
|
||||||
VERIFY_ARE_EQUAL((UINT)1, mock->m_getCategoriesCallCount);
|
VERIFY_ARE_EQUAL((UINT)1, mock->m_getCategoriesCallCount);
|
||||||
VERIFY_ARE_EQUAL((UINT)3, cats->Size);
|
VERIFY_ARE_EQUAL((UINT)4, cats->Size);
|
||||||
// Verify that we match current category
|
// Verify that we match current category
|
||||||
VERIFY_IS_TRUE(CAT2 == vm.CurrentCategory->GetModelCategory());
|
VERIFY_IS_TRUE(CAT2 == vm.CurrentCategory->GetModelCategory());
|
||||||
}
|
}
|
||||||
|
@ -935,6 +945,33 @@ TEST_METHOD(TestDecimalFormattingLogic)
|
||||||
VERIFY_IS_TRUE(vm.Value1 == L"3");
|
VERIFY_IS_TRUE(vm.Value1 == L"3");
|
||||||
VERIFY_IS_TRUE(vm.Value2 == L"2.50");
|
VERIFY_IS_TRUE(vm.Value2 == L"2.50");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(TestCurrencyFormattingLogic)
|
||||||
|
{
|
||||||
|
// verify that currency fraction digits is formatted per currency type
|
||||||
|
|
||||||
|
shared_ptr<UnitConverterMock> mock = make_shared<UnitConverterMock>();
|
||||||
|
VM::UnitConverterViewModel vm(mock);
|
||||||
|
|
||||||
|
// Establish base condition
|
||||||
|
vm.CurrentCategory = vm.Categories->GetAt(3); // Currency
|
||||||
|
vm.Unit1 = vm.Units->GetAt(0); // JPY
|
||||||
|
vm.Unit2 = vm.Units->GetAt(1); // JOD
|
||||||
|
vm.UnitChanged->Execute(nullptr);
|
||||||
|
|
||||||
|
const WCHAR *vFrom = L"1.2340", *vTo = L"0.0070";
|
||||||
|
vm.UpdateDisplay(vFrom, vTo);
|
||||||
|
|
||||||
|
VERIFY_IS_TRUE(vm.Value1 == L"1");
|
||||||
|
VERIFY_IS_TRUE(vm.Value2 == L"0.007");
|
||||||
|
vm.SwitchActive->Execute(nullptr);
|
||||||
|
VERIFY_IS_TRUE(vm.Value1 == L"1");
|
||||||
|
VERIFY_IS_TRUE(vm.Value2 == L"0.007");
|
||||||
|
vm.SwitchActive->Execute(nullptr);
|
||||||
|
VERIFY_IS_TRUE(vm.Value1 == L"1");
|
||||||
|
VERIFY_IS_TRUE(vm.Value2 == L"0.007");
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that when we switch the active field and get display
|
// Tests that when we switch the active field and get display
|
||||||
// updates, the correct automation names are are being updated.
|
// updates, the correct automation names are are being updated.
|
||||||
TEST_METHOD(TestValue1AndValue2AutomationNameChanges)
|
TEST_METHOD(TestValue1AndValue2AutomationNameChanges)
|
||||||
|
|
|
@ -9,6 +9,8 @@ namespace UCM = UnitConversionManager;
|
||||||
|
|
||||||
namespace CalculatorUnitTests
|
namespace CalculatorUnitTests
|
||||||
{
|
{
|
||||||
|
static constexpr int CURRENCY_ID = 16;
|
||||||
|
|
||||||
static UCM::Unit UNIT1 = { 1, L"UNIT1", L"U1", true, false, false };
|
static UCM::Unit UNIT1 = { 1, L"UNIT1", L"U1", true, false, false };
|
||||||
static UCM::Unit UNIT2 = { 2, L"UNIT2", L"U2", false, true, false };
|
static UCM::Unit UNIT2 = { 2, L"UNIT2", L"U2", false, true, false };
|
||||||
static UCM::Unit UNIT3 = { 3, L"UNIT3", L"U3", false, false, false };
|
static UCM::Unit UNIT3 = { 3, L"UNIT3", L"U3", false, false, false };
|
||||||
|
@ -19,10 +21,13 @@ namespace CalculatorUnitTests
|
||||||
static UCM::Unit UNIT8 = { 8, L"UNIT8", L"U8", false, false, false };
|
static UCM::Unit UNIT8 = { 8, L"UNIT8", L"U8", false, false, false };
|
||||||
static UCM::Unit UNIT9 = { 9, L"UNIT9", L"U9", true, false, false };
|
static UCM::Unit UNIT9 = { 9, L"UNIT9", L"U9", true, false, false };
|
||||||
static UCM::Unit UNITWHIMSY = { 10, L"Whimsy", L"UW", true, false, true };
|
static UCM::Unit UNITWHIMSY = { 10, L"Whimsy", L"UW", true, false, true };
|
||||||
|
static UCM::Unit UNITJPY = { 11, L"Japan - Yen", L"JPY", true, true, false };
|
||||||
|
static UCM::Unit UNITJOD = { 12, L"Jordan - Dinar", L"JOD", true, true, false };
|
||||||
|
|
||||||
static UCM::Category CAT1 = { 1, L"CAT1", false }; // contains Unit1 - Unit3
|
static UCM::Category CAT1 = { 1, L"CAT1", false }; // contains Unit1 - Unit3
|
||||||
static UCM::Category CAT2 = { 2, L"CAT2", false }; // contains Unit4 - Unit6
|
static UCM::Category CAT2 = { 2, L"CAT2", false }; // contains Unit4 - Unit6
|
||||||
static UCM::Category CAT3 = { 3, L"CAT3", false }; // contains Unit7 - Unit9
|
static UCM::Category CAT3 = { 3, L"CAT3", false }; // contains Unit7 - Unit9
|
||||||
|
static UCM::Category CAT_CURRENCY = { CURRENCY_ID, L"Currency", false }; // contains UnitJPY and UnitJOD
|
||||||
|
|
||||||
class UnitConverterMock : public UnitConversionManager::IUnitConverter
|
class UnitConverterMock : public UnitConversionManager::IUnitConverter
|
||||||
{
|
{
|
||||||
|
@ -33,7 +38,8 @@ namespace CalculatorUnitTests
|
||||||
UCM::CategorySelectionInitializer SetCurrentCategory(const UCM::Category& input) override;
|
UCM::CategorySelectionInitializer SetCurrentCategory(const UCM::Category& input) override;
|
||||||
UCM::Category GetCurrentCategory();
|
UCM::Category GetCurrentCategory();
|
||||||
void SetCurrentUnitTypes(const UCM::Unit& fromType, const UCM::Unit& toType) override;
|
void SetCurrentUnitTypes(const UCM::Unit& fromType, const UCM::Unit& toType) override;
|
||||||
void SwitchActive(const std::wstring& newValue);
|
void SwitchActive(const std::wstring& newValue) override;
|
||||||
|
bool IsSwitchedActive() const override;
|
||||||
std::wstring SaveUserPreferences() override;
|
std::wstring SaveUserPreferences() override;
|
||||||
void RestoreUserPreferences(_In_ std::wstring_view userPreferences) override;
|
void RestoreUserPreferences(_In_ std::wstring_view userPreferences) override;
|
||||||
void SendCommand(UCM::Command command) override;
|
void SendCommand(UCM::Command command) override;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue