From ca15f05227836915940e499da0db2086423801aa Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Fri, 15 Mar 2019 17:20:33 -0700 Subject: [PATCH 01/28] DateDiff: Optimize how we build the string used when we calculate the difference between 2 dates (#195) Optimize how we build the result of GetDateDiffString and GetDateDiffStringInDays, using std::wstring (mutuable) instead of Platform::String (immutable) --- src/CalcViewModel/DateCalculatorViewModel.cpp | 53 ++++++++++--------- src/CalcViewModel/DateCalculatorViewModel.h | 2 +- .../DateCalculatorUnitTests.cpp | 40 +++++++++++++- 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/CalcViewModel/DateCalculatorViewModel.cpp b/src/CalcViewModel/DateCalculatorViewModel.cpp index e705c983..ab3e384b 100644 --- a/src/CalcViewModel/DateCalculatorViewModel.cpp +++ b/src/CalcViewModel/DateCalculatorViewModel.cpp @@ -73,7 +73,7 @@ DateCalculatorViewModel::DateCalculatorViewModel() : // Initialize the list separator delimiter appended with a space at the end, e.g. ", " // This will be used for date difference formatting: Y years, M months, W weeks, D days - m_listSeparator = ref new String((localizationSettings.GetListSeparator() + L" ").c_str()); + m_listSeparator = localizationSettings.GetListSeparator() + L" "; // Initialize the output results UpdateDisplayResult(); @@ -181,8 +181,8 @@ void DateCalculatorViewModel::UpdateDisplayResult() StrDateDiffResult = AppResourceProvider::GetInstance().GetResourceString(L"Date_SameDates"); } else if ((m_dateDiffResult.year == 0) && - (m_dateDiffResult.month == 0) && - (m_dateDiffResult.week == 0)) + (m_dateDiffResult.month == 0) && + (m_dateDiffResult.week == 0)) { IsDiffInDays = true; StrDateDiffResultInDays = L""; @@ -245,22 +245,23 @@ void DateCalculatorViewModel::InitializeDateOutputFormats(_In_ String^ calendarI String^ DateCalculatorViewModel::GetDateDiffString() const { - String^ result = L""; + wstring result; bool addDelimiter = false; AppResourceProvider resourceLoader = AppResourceProvider::GetInstance(); auto yearCount = m_dateDiffResult.year; if (yearCount > 0) { - result = String::Concat(GetLocalizedNumberString(yearCount), L" "); + result += GetLocalizedNumberString(yearCount)->Data(); + result += L" "; if (yearCount > 1) { - result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Years")); + result += resourceLoader.GetResourceString(L"Date_Years")->Data(); } else { - result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Year")); + result += resourceLoader.GetResourceString(L"Date_Year")->Data(); } // set the flags to add a delimiter whenever the next unit is added @@ -272,22 +273,23 @@ String^ DateCalculatorViewModel::GetDateDiffString() const { if (addDelimiter) { - result = String::Concat(result, m_listSeparator); + result += m_listSeparator; } else { addDelimiter = true; } - result = String::Concat(result, String::Concat(GetLocalizedNumberString(monthCount), L" ")); + result += GetLocalizedNumberString(monthCount)->Data(); + result += L" "; if (monthCount > 1) { - result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Months")); + result += resourceLoader.GetResourceString(L"Date_Months")->Data(); } else { - result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Month")); + result += resourceLoader.GetResourceString(L"Date_Month")->Data(); } } @@ -296,22 +298,23 @@ String^ DateCalculatorViewModel::GetDateDiffString() const { if (addDelimiter) { - result = String::Concat(result, m_listSeparator); + result += m_listSeparator; } else { addDelimiter = true; } - result = String::Concat(result, String::Concat(GetLocalizedNumberString(weekCount), L" ")); + result += GetLocalizedNumberString(weekCount)->Data(); + result += L" "; if (weekCount > 1) { - result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Weeks")); + result += resourceLoader.GetResourceString(L"Date_Weeks")->Data(); } else { - result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Week")); + result += resourceLoader.GetResourceString(L"Date_Week")->Data(); } } @@ -320,43 +323,45 @@ String^ DateCalculatorViewModel::GetDateDiffString() const { if (addDelimiter) { - result = String::Concat(result, m_listSeparator); + result += m_listSeparator; } else { addDelimiter = true; } - result = String::Concat(result, String::Concat(GetLocalizedNumberString(dayCount), L" ")); + result += GetLocalizedNumberString(dayCount)->Data(); + result += L" "; if (dayCount > 1) { - result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Days")); + result += resourceLoader.GetResourceString(L"Date_Days")->Data(); } else { - result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Day")); + result += resourceLoader.GetResourceString(L"Date_Day")->Data(); } } - return result; + return ref new String(result.data()); } String^ DateCalculatorViewModel::GetDateDiffStringInDays() const { - String^ strDateUnit; + wstring result = GetLocalizedNumberString(m_dateDiffResultInDays.day)->Data(); + result += L" "; // Display the result as '1 day' or 'N days' if (m_dateDiffResultInDays.day > 1) { - strDateUnit = AppResourceProvider::GetInstance().GetResourceString(L"Date_Days"); + result += AppResourceProvider::GetInstance().GetResourceString(L"Date_Days")->Data(); } else { - strDateUnit = AppResourceProvider::GetInstance().GetResourceString(L"Date_Day"); + result += AppResourceProvider::GetInstance().GetResourceString(L"Date_Day")->Data(); } - return String::Concat(GetLocalizedNumberString(m_dateDiffResultInDays.day), String::Concat(L" ", strDateUnit)); + return ref new String(result.data()); } void DateCalculatorViewModel::OnCopyCommand(Platform::Object^ parameter) diff --git a/src/CalcViewModel/DateCalculatorViewModel.h b/src/CalcViewModel/DateCalculatorViewModel.h index f2fe7ebf..b7d8d0ef 100644 --- a/src/CalcViewModel/DateCalculatorViewModel.h +++ b/src/CalcViewModel/DateCalculatorViewModel.h @@ -146,7 +146,7 @@ namespace CalculatorApp CalculatorApp::Common::DateCalculation::DateUnit m_daysOutputFormat; CalculatorApp::Common::DateCalculation::DateUnit m_allDateUnitsOutputFormat; Windows::Globalization::DateTimeFormatting::DateTimeFormatter^ m_dateTimeFormatter; - Platform::String^ m_listSeparator; + std::wstring m_listSeparator; }; } } diff --git a/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp b/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp index 7371a26d..2516db27 100644 --- a/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp +++ b/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -494,6 +494,26 @@ namespace DateCalculationUnitTests } } + TEST_METHOD(DateCalcViewModelDateDiffIgnoreSignTest) + { + auto viewModel = ref new DateCalculatorViewModel(); + + viewModel->IsDateDiffMode = true; + VERIFY_IS_TRUE(viewModel->IsDateDiffMode); + + viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[10]); + viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[6]); + + VERIFY_IS_FALSE(viewModel->IsDiffInDays); + VERIFY_ARE_EQUAL(StringReference(L"305 days"), viewModel->StrDateDiffResultInDays); + VERIFY_ARE_EQUAL(StringReference(L"10 months"), viewModel->StrDateDiffResult); + viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[6]); + viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[10]); + VERIFY_IS_FALSE(viewModel->IsDiffInDays); + VERIFY_ARE_EQUAL(StringReference(L"305 days"), viewModel->StrDateDiffResultInDays); + VERIFY_ARE_EQUAL(StringReference(L"10 months"), viewModel->StrDateDiffResult); + } + TEST_METHOD(DateCalcViewModelDateDiffTest) { // TODO - MSFT 10331900, fix this test @@ -516,7 +536,23 @@ namespace DateCalculationUnitTests //VERIFY_ARE_EQUAL(StringReference(L"8398 years, 11 months, 4 weeks, 2 days"), viewModel->StrDateDiffResult); } - TEST_METHOD(DateCalcViewModelDateDiffResultInDaysTest) + TEST_METHOD(DateCalcViewModelDateDiffResultInPositiveDaysTest) + { + auto viewModel = ref new DateCalculatorViewModel(); + + viewModel->IsDateDiffMode = true; + VERIFY_IS_TRUE(viewModel->IsDateDiffMode); + + viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[1]); + viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[0]); + + // Assert for the result + VERIFY_IS_TRUE(viewModel->IsDiffInDays); + VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult); + VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays); + } + + TEST_METHOD(DateCalcViewModelDateDiffFromDateHigherThanToDate) { auto viewModel = ref new DateCalculatorViewModel(); From 4a41e37c878fbd21ad0ce126c1b886b8793a6c5c Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 15 Mar 2019 17:45:49 -0700 Subject: [PATCH 02/28] Added support for pasting of monetary values (#176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #52 Description of the changes: Added support for pasting of prefix currency symbols supported by the Windows keyboard. yen or yuan (¥) unspecified currency sign (¤) Ghanaian cedi (₵) dollar or peso ($) colón (₡) won (₩) shekel (₪) naira (₦) Indian rupee (₹) pound (£) euro (€) How changes were validated: Manually tested each prefix currency symbol supported by the Windows keyboard and ran unit tests. --- src/CalcViewModel/Common/CopyPasteManager.cpp | 20 +++++++++++++- src/CalcViewModel/Common/CopyPasteManager.h | 1 + src/CalcViewModel/Common/Utils.cpp | 11 ++------ src/CalcViewModel/Common/Utils.h | 1 - .../CopyPasteManagerTest.cpp | 27 +++++++++++++++++++ 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/CalcViewModel/Common/CopyPasteManager.cpp b/src/CalcViewModel/Common/CopyPasteManager.cpp index c11630c4..00f13b52 100644 --- a/src/CalcViewModel/Common/CopyPasteManager.cpp +++ b/src/CalcViewModel/Common/CopyPasteManager.cpp @@ -139,7 +139,7 @@ String^ CopyPasteManager::ValidatePasteExpression(String^ pastedText, ViewMode m String^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pasteExpression); // Removing the spaces, comma separator from the pasteExpression to allow pasting of expressions like 1 + 2+1,333 - pasteExpression = Utils::RemoveUnwantedCharsFromWstring(englishString->Data()); + pasteExpression = RemoveUnwantedCharsFromWstring(englishString->Data()); // If the last character is an = sign, remove it from the pasteExpression to allow evaluating the result on paste. if (!pasteExpression.empty() && pasteExpression.back() == L'=') @@ -567,3 +567,21 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num return len; } + +// return wstring after removing characters like space, comma, double quotes, and monetary prefix currency symbols supported by the Windows keyboard: +// yen or yuan(¥) - 165 +// unspecified currency sign(¤) - 164 +// Ghanaian cedi(₵) - 8373 +// dollar or peso($) - 36 +// colón(₡) - 8353 +// won(₩) - 8361 +// shekel(₪) - 8362 +// naira(₦) - 8358 +// Indian rupee(₹) - 8377 +// pound(£) - 163 +// euro(€) - 8364 +wstring CopyPasteManager::RemoveUnwantedCharsFromWstring(const wstring& input) +{ + wchar_t unWantedChars[] = { L' ', L',', L'"', 165, 164, 8373, 36, 8353, 8361, 8362, 8358, 8377, 163, 8364, 8234, 8235, 8236, 8237 }; + return Utils::RemoveUnwantedCharsFromWstring(input, unWantedChars, 18); +} diff --git a/src/CalcViewModel/Common/CopyPasteManager.h b/src/CalcViewModel/Common/CopyPasteManager.h index 1da4af4e..9a886154 100644 --- a/src/CalcViewModel/Common/CopyPasteManager.h +++ b/src/CalcViewModel/Common/CopyPasteManager.h @@ -58,6 +58,7 @@ namespace CalculatorApp static size_t OperandLength(std::wstring operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1); static size_t StandardScientificOperandLength(std::wstring operand); static size_t ProgrammerOperandLength(const std::wstring& operand, int numberBase); + static std::wstring RemoveUnwantedCharsFromWstring(const std::wstring& input); static constexpr size_t MaxStandardOperandLength = 16; static constexpr size_t MaxScientificOperandLength = 32; diff --git a/src/CalcViewModel/Common/Utils.cpp b/src/CalcViewModel/Common/Utils.cpp index 0ab05b1d..6aad5f52 100644 --- a/src/CalcViewModel/Common/Utils.cpp +++ b/src/CalcViewModel/Common/Utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // @@ -86,14 +86,7 @@ bool Utils::IsLastCharacterTarget(_In_ wstring const &input, _In_ wchar_t target return !input.empty() && input.back() == target; } -// Returns wstring after removing characters like space, comma, and double quotes -wstring Utils::RemoveUnwantedCharsFromWstring(wstring input) -{ - wchar_t unWantedChars[] = { L' ', L',', L'"', 8234, 8235, 8236, 8237 }; - return RemoveUnwantedCharsFromWstring(input, unWantedChars, 6); -} - -// Returns wstring after removing characters specified by unwantedChars array +// Return wstring after removing characters specified by unwantedChars array wstring Utils::RemoveUnwantedCharsFromWstring(wstring input, wchar_t* unwantedChars, unsigned int size) { for (unsigned int i = 0; i < size; ++i) diff --git a/src/CalcViewModel/Common/Utils.h b/src/CalcViewModel/Common/Utils.h index 37d6c6ba..03a4c72a 100644 --- a/src/CalcViewModel/Common/Utils.h +++ b/src/CalcViewModel/Common/Utils.h @@ -280,7 +280,6 @@ namespace Utils Platform::String^ GetStringValue(Platform::String^ input); bool IsLastCharacterTarget(std::wstring const &input, wchar_t target); std::wstring RemoveUnwantedCharsFromWstring(std::wstring inputString, wchar_t* unwantedChars, unsigned int size); - std::wstring RemoveUnwantedCharsFromWstring(std::wstring input); double GetDoubleFromWstring(std::wstring input); int GetWindowId(); void RunOnUIThreadNonblocking(std::function&& function, _In_ Windows::UI::Core::CoreDispatcher^ currentDispatcher); diff --git a/src/CalculatorUnitTests/CopyPasteManagerTest.cpp b/src/CalculatorUnitTests/CopyPasteManagerTest.cpp index 4e53dff1..aac0e010 100644 --- a/src/CalculatorUnitTests/CopyPasteManagerTest.cpp +++ b/src/CalculatorUnitTests/CopyPasteManagerTest.cpp @@ -193,6 +193,33 @@ namespace CalculatorUnitTests VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"______1234___"), L"1234"); }; + // Using unicode literals here until the encoding issues get figured out + TEST_METHOD(ValidatePrefixCurrencySymbols) + { + // ¥5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u00A5\u0035"), L"5"); + // ¤5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u00A4\u0035"), L"5"); + // ₵5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u20B5\u0035"), L"5"); + // $5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u0024\u0035"), L"5"); + // ₡5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u20A1\u0035"), L"5"); + // ₩5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u20A9\u0035"), L"5"); + // ₪5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u20AA\u0035"), L"5"); + // ₦5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u20A6\u0035"), L"5"); + // ₹5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u20B9\u0035"), L"5"); + // £5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u00A3\u0035"), L"5"); + // €5 + VERIFY_ARE_EQUAL(m_CopyPasteManager.RemoveUnwantedCharsFromWstring(L"\u20AC\u0035"), L"5"); + }; + TEST_METHOD(ValidateTryOperandToULL) { unsigned long long int result = 0; From e40791d7ad94ff17dc1f9e672e0fd32097ecbdc4 Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Fri, 15 Mar 2019 21:21:30 -0700 Subject: [PATCH 03/28] Fix compilation issues due to unsigned/signed warnings treated as errors (#317) --- src/CalcManager/CEngine/scicomm.cpp | 4 ++-- src/CalcManager/CEngine/sciset.cpp | 4 ++-- src/CalcViewModel/StandardCalculatorViewModel.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/CalcManager/CEngine/scicomm.cpp b/src/CalcManager/CEngine/scicomm.cpp index cf23cf66..a99397da 100644 --- a/src/CalcManager/CEngine/scicomm.cpp +++ b/src/CalcManager/CEngine/scicomm.cpp @@ -36,7 +36,7 @@ namespace { static BYTE rgbPrec[] = { 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1, IDC_ADD,2, IDC_SUB,2, IDC_RSHF,3, IDC_LSHF,3, IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4, IDC_ROOT, 4 }; - int iPrec; + unsigned int iPrec; iPrec = 0; while ((iPrec < size(rgbPrec)) && (nopCode != rgbPrec[iPrec])) @@ -947,7 +947,7 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE // Try to lookup the ID in the UFNE table int ids = 0; int iufne = nOpCode - IDC_UNARYFIRST; - if (iufne >= 0 && iufne < size(rgUfne)) + if (iufne >= 0 && (size_t)iufne < size(rgUfne)) { if (fInv) { diff --git a/src/CalcManager/CEngine/sciset.cpp b/src/CalcManager/CEngine/sciset.cpp index 99f0b0b6..95451dc9 100644 --- a/src/CalcManager/CEngine/sciset.cpp +++ b/src/CalcManager/CEngine/sciset.cpp @@ -56,7 +56,7 @@ LONG CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/) static constexpr int nBitMax[] = { 64, 32, 16, 8 }; LONG wmax = nBitMax[0]; - if (m_numwidth >= 0 && m_numwidth < size(nBitMax)) + if (m_numwidth >= 0 && (size_t)m_numwidth < size(nBitMax)) { wmax = nBitMax[m_numwidth]; } @@ -69,7 +69,7 @@ uint32_t CCalcEngine::NRadixFromRadixType(RADIX_TYPE radixtype) uint32_t radix = 10; // convert special bases into symbolic values - if (radixtype >= 0 && radixtype < size(rgnRadish)) + if (radixtype >= 0 && (size_t)radixtype < size(rgnRadish)) { radix = rgnRadish[radixtype]; } diff --git a/src/CalcViewModel/StandardCalculatorViewModel.cpp b/src/CalcViewModel/StandardCalculatorViewModel.cpp index 7f4b6332..26604558 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.cpp +++ b/src/CalcViewModel/StandardCalculatorViewModel.cpp @@ -1648,7 +1648,7 @@ bool StandardCalculatorViewModel::IsOpnd(int nOpCode) Command::CommandPNT }; - for (int i = 0; i < size(opnd); i++) + for (unsigned int i = 0; i < size(opnd); i++) { if (nOpCode == static_cast(opnd[i])) { @@ -1679,7 +1679,7 @@ bool StandardCalculatorViewModel::IsUnaryOp(int nOpCode) Command::CommandCUB }; - for (int i = 0; i < size(unaryOp); i++) + for (unsigned int i = 0; i < size(unaryOp); i++) { if (nOpCode == static_cast(unaryOp[i])) { @@ -1706,7 +1706,7 @@ bool StandardCalculatorViewModel::IsTrigOp(int nOpCode) Command::CommandATAN }; - for (int i = 0; i < size(trigOp); i++) + for (unsigned int i = 0; i < size(trigOp); i++) { if (nOpCode == static_cast(trigOp[i])) { @@ -1729,7 +1729,7 @@ bool StandardCalculatorViewModel::IsBinOp(int nOpCode) Command::CommandPWR }; - for (int i = 0; i < size(binOp); i++) + for (unsigned int i = 0; i < size(binOp); i++) { if (nOpCode == static_cast(binOp[i])) { @@ -1763,7 +1763,7 @@ bool StandardCalculatorViewModel::IsRecoverableCommand(int nOpCode) Command::CommandF }; - for (int i = 0; i < size(recoverableCommands); i++) + for (unsigned int i = 0; i < size(recoverableCommands); i++) { if (nOpCode == static_cast(recoverableCommands[i])) { From cd7c266a6b06bccff05a1c62298cd6710e6cb484 Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Mon, 18 Mar 2019 11:22:32 -0700 Subject: [PATCH 04/28] Fix issue with Date diff when it includes a Daylight Saving Time (#193) The application uses local time to calculate the number of days between 2 dates. If a Daylight Saving Time takes place during this period of time (only Clocks Forward 2am->3am), the application will miss 1 day and fail to calculate the number of days/weeks/months between the 2 dates. image Description of the changes: DateCalculationEngine uses local time to modify dates, however, AddDays, AddWeeks,... won't add 24 hours or 7 days if DST happens between the 2 dates, but instead add ~23.9/24.1 hours or ~6.9/7.1 days (depends if it's the DST clock backward or clock forward). When the DST is clock forward, DateCalculationEngine will miss one day. Solution use UTC dates to calculate date difference. Extra Fix: use calendar->FirstPeriodInThisDay and calendar->FirstHourInThisPeriod in ClipTime (else it will set the time to 12PM (noon) in some regions. replace OBSERVABLE_PROPERTY_RW by OBSERVABLE_PROPERTY_R when possible. remove the definition of CheckClipTimeSameDay (implementation missing) How changes were validated: Tested manually with different regions (FR, US, ES, JP). Fixes #178 --- src/CalcViewModel/Common/DateCalculator.cpp | 1 + src/CalcViewModel/DateCalculatorViewModel.cpp | 34 ++++------- src/CalcViewModel/DateCalculatorViewModel.h | 16 +++--- .../DateCalculatorUnitTests.cpp | 57 +++++++++++++++++++ 4 files changed, 76 insertions(+), 32 deletions(-) diff --git a/src/CalcViewModel/Common/DateCalculator.cpp b/src/CalcViewModel/Common/DateCalculator.cpp index f00ae3c1..63efcdd0 100644 --- a/src/CalcViewModel/Common/DateCalculator.cpp +++ b/src/CalcViewModel/Common/DateCalculator.cpp @@ -12,6 +12,7 @@ using namespace CalculatorApp::Common::DateCalculation; DateCalculationEngine::DateCalculationEngine(_In_ String^ calendarIdentifier) { m_calendar = ref new Calendar(); + m_calendar->ChangeTimeZone("UTC"); m_calendar->ChangeCalendarSystem(calendarIdentifier); } diff --git a/src/CalcViewModel/DateCalculatorViewModel.cpp b/src/CalcViewModel/DateCalculatorViewModel.cpp index ab3e384b..e581a55a 100644 --- a/src/CalcViewModel/DateCalculatorViewModel.cpp +++ b/src/CalcViewModel/DateCalculatorViewModel.cpp @@ -43,11 +43,7 @@ DateCalculatorViewModel::DateCalculatorViewModel() : m_StrDateDiffResultAutomationName(L""), m_StrDateDiffResultInDays(L""), m_StrDateResult(L""), - m_StrDateResultAutomationName(L""), - m_fromDate({ 0 }), - m_toDate({ 0 }), - m_startDate({ 0 }), - m_dateResult({ 0 }) + m_StrDateResultAutomationName(L"") { const auto& localizationSettings = LocalizationSettings::GetInstance(); @@ -56,19 +52,19 @@ DateCalculatorViewModel::DateCalculatorViewModel() : // Initialize Date Calc engine m_dateCalcEngine = make_shared(localizationSettings.GetCalendarIdentifier()); - // Initialize dates of DatePicker controls to today's date auto calendar = ref new Calendar(); + // We force the timezone to UTC, in order to avoid being affected by Daylight Saving Time + // when we calculate the difference between 2 dates. + calendar->ChangeTimeZone("UTC"); auto today = calendar->GetDateTime(); // FromDate and ToDate should be clipped (adjusted to a consistent hour in UTC) - m_fromDate = today; - m_toDate = today; - FromDate = ClipTime(today); - ToDate = ClipTime(today); + m_fromDate = ClipTime(today); + m_toDate = ClipTime(today); // StartDate should not be clipped - StartDate = today; + m_startDate = today; m_dateResult = today; // Initialize the list separator delimiter appended with a space at the end, e.g. ", " @@ -86,15 +82,6 @@ DateCalculatorViewModel::DateCalculatorViewModel() : m_offsetValues->Append(ref new String(numberStr.c_str())); } - /* In the ClipTime function, we used to change timezone to UTC before clipping the time. - The comment from the previous developers said this was done to eliminate the effects of - Daylight Savings Time. We can't think of a good reason why this change in timezone is - necessary and did find bugs related to the change, therefore, we have removed the - change. Just in case, we will see if the clipped time is ever a different day from the - original day, which would hopefully indicate the change in timezone was actually - necessary. We will collect telemetry if we find this case. If we don't see any - telemetry events after the application has been used for some time, we will feel safe - and can remove this function. */ DayOfWeek trueDayOfWeek = calendar->DayOfWeek; DateTime clippedTime = ClipTime(today); @@ -383,13 +370,14 @@ String^ DateCalculatorViewModel::GetLocalizedNumberString(int value) const return ref new String(numberStr.c_str()); } -// Adjusts the given DateTime to 12AM of the same day +// Adjusts the given DateTime to 12AM (UTC) of the same day DateTime DateCalculatorViewModel::ClipTime(DateTime dateTime) { auto calendar = ref new Calendar(); + calendar->ChangeTimeZone("UTC"); calendar->SetDateTime(dateTime); - calendar->Period = 1; - calendar->Hour = 12; + calendar->Period = calendar->FirstPeriodInThisDay; + calendar->Hour = calendar->FirstHourInThisPeriod; calendar->Minute = 0; calendar->Second = 0; calendar->Nanosecond = 0; diff --git a/src/CalcViewModel/DateCalculatorViewModel.h b/src/CalcViewModel/DateCalculatorViewModel.h index b7d8d0ef..2fffa1cc 100644 --- a/src/CalcViewModel/DateCalculatorViewModel.h +++ b/src/CalcViewModel/DateCalculatorViewModel.h @@ -23,8 +23,8 @@ namespace CalculatorApp // Input Properties OBSERVABLE_PROPERTY_RW(bool, IsDateDiffMode); OBSERVABLE_PROPERTY_RW(bool, IsAddMode); - OBSERVABLE_PROPERTY_RW(bool, IsDiffInDays); // If diff is only in days or the dates are the same, - // then show only one result and avoid redundancy + OBSERVABLE_PROPERTY_R(bool, IsDiffInDays); // If diff is only in days or the dates are the same, + // then show only one result and avoid redundancy OBSERVABLE_PROPERTY_RW(int, DaysOffset); OBSERVABLE_PROPERTY_RW(int, MonthsOffset); @@ -82,11 +82,11 @@ namespace CalculatorApp } // Output Properties - OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResult); - OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResultAutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResultInDays); - OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateResult); - OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateResultAutomationName); + OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResult); + OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResultAutomationName); + OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResultInDays); + OBSERVABLE_PROPERTY_R(Platform::String^, StrDateResult); + OBSERVABLE_PROPERTY_R(Platform::String^, StrDateResultAutomationName); COMMAND_FOR_METHOD(CopyCommand, DateCalculatorViewModel::OnCopyCommand); @@ -104,8 +104,6 @@ namespace CalculatorApp Platform::String^ GetLocalizedNumberString(int value) const; static Windows::Foundation::DateTime ClipTime(Windows::Foundation::DateTime dateTime); - static void CheckClipTimeSameDay(Windows::Globalization::Calendar^ reference); - property bool IsOutOfBound { bool get() { return m_isOutOfBound; } diff --git a/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp b/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp index 2516db27..9bb98fab 100644 --- a/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp +++ b/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp @@ -387,6 +387,63 @@ namespace DateCalculationUnitTests VERIFY_IS_TRUE(StringReference(L"") != viewModel->StrDateResult); } + TEST_METHOD(DateCalcViewModelDateDiffDaylightSavingTimeTest) + { + auto viewModel = ref new DateCalculatorViewModel(); + + viewModel->IsDateDiffMode = true; + VERIFY_IS_TRUE(viewModel->IsDateDiffMode); + + // 29.02.2008 + viewModel->FromDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[5].startDate); + // 31.03.2008 + viewModel->ToDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[5].endDate); + + //// Assert for the result + VERIFY_IS_FALSE(viewModel->IsDiffInDays); + VERIFY_ARE_EQUAL(StringReference(L"31 days"), viewModel->StrDateDiffResultInDays); + VERIFY_ARE_EQUAL(StringReference(L"1 month, 2 days"), viewModel->StrDateDiffResult); + + // Daylight Saving Time - Clock Forward + // 10.03.2019 + SYSTEMTIME startDate; + startDate.wYear = 2019; + startDate.wMonth = 03; + startDate.wDay = 10; + startDate.wDayOfWeek = 0; + startDate.wHour = startDate.wMinute = 0; + startDate.wSecond = startDate.wMilliseconds = 0; + viewModel->FromDate = DateUtils::SystemTimeToDateTime(startDate); + // 11.03.2019 + SYSTEMTIME endDate; + endDate.wYear = 2019; + endDate.wMonth = 03; + endDate.wDay = 11; + endDate.wDayOfWeek = 0; + endDate.wHour = endDate.wMinute = 0; + endDate.wSecond = endDate.wMilliseconds = 0; + viewModel->ToDate = DateUtils::SystemTimeToDateTime(endDate); + VERIFY_IS_TRUE(viewModel->IsDiffInDays); + VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult); + + endDate.wDay += 6; + viewModel->ToDate = DateUtils::SystemTimeToDateTime(endDate); + VERIFY_IS_FALSE(viewModel->IsDiffInDays); + VERIFY_ARE_EQUAL(StringReference(L"1 week"), viewModel->StrDateDiffResult); + + // Daylight Saving Time - Clock Backward + // 03.11.2019 + startDate.wMonth = 11; + startDate.wDay = 03; + viewModel->FromDate = DateUtils::SystemTimeToDateTime(startDate); + // 04.11.2019 + endDate.wMonth = 11; + endDate.wDay = 04; + viewModel->ToDate = DateUtils::SystemTimeToDateTime(endDate); + VERIFY_IS_TRUE(viewModel->IsDiffInDays); + VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult); + } + TEST_METHOD(DateCalcViewModelAddTest) { // TODO - MSFT 10331900, fix this test From b8b0fdf86bd6959d10bc388e95c039c266dcc946 Mon Sep 17 00:00:00 2001 From: Cyril Date: Mon, 18 Mar 2019 20:31:04 +0100 Subject: [PATCH 05/28] Improving code style : verbosity, indentation levels (#200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixing some nested if() statements and reducing indentation levels. Making some sections less verbose, e.g: if (a == 1) { b = true; } else { b = false; } ↓ b = (a == 1) --- src/CalcManager/CEngine/History.cpp | 48 +- src/CalcManager/CalculatorManager.cpp | 138 +++--- src/CalcManager/UnitConverter.cpp | 609 +++++++++++++------------- 3 files changed, 406 insertions(+), 389 deletions(-) diff --git a/src/CalcManager/CEngine/History.cpp b/src/CalcManager/CEngine/History.cpp index 8dda170e..e5bb746b 100644 --- a/src/CalcManager/CEngine/History.cpp +++ b/src/CalcManager/CEngine/History.cpp @@ -136,7 +136,7 @@ void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool fNoRepetition) } // This is expected to be called when a binary op in the last say 1+2+ is changing to another one say 1+2* (+ changed to *) -// It needs to know by this change a Precedence inversion happened. i.e. previous op was lower or equal to its previous op, but the new +// It needs to know by this change a Precedence inversion happened. i.e. previous op was lower or equal to its previous op, but the new // one isn't. (Eg. 1*2* to 1*2^). It can add explicit brackets to ensure the precedence is inverted. (Eg. (1*2) ^) void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher) { @@ -203,7 +203,7 @@ bool CHistoryCollector::FOpndAddedToHistory() // AddUnaryOpToHistory // -// This is does the postfix to prefix translation of the input and adds the text to the history. Eg. doing 2 + 4 (sqrt), +// This is does the postfix to prefix translation of the input and adds the text to the history. Eg. doing 2 + 4 (sqrt), // this routine will ensure the last sqrt call unary operator, actually goes back in history and wraps 4 in sqrt(4) // void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE angletype) @@ -297,7 +297,7 @@ void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE a } // Called after = with the result of the equation -// Responsible for clearing the top line of current running history display, as well as adding yet another element to +// Responsible for clearing the top line of current running history display, as well as adding yet another element to // history of equations void CHistoryCollector::CompleteHistoryLine(wstring_view numStr) { @@ -413,37 +413,39 @@ int CHistoryCollector::AddCommand(_In_ const std::shared_ptr return nCommands - 1; } -// To Update the operands in the Expression according to the current Radix +// To Update the operands in the Expression according to the current Radix void CHistoryCollector::UpdateHistoryExpression(uint32_t radix, int32_t precision) { - if (m_spTokens != nullptr) + if (m_spTokens == nullptr) { - unsigned int size; - IFT(m_spTokens->GetSize(&size)); + return; + } - for (unsigned int i = 0; i < size; ++i) + unsigned int size; + IFT(m_spTokens->GetSize(&size)); + + for (unsigned int i = 0; i < size; ++i) + { + std::pair token; + IFT(m_spTokens->GetAt(i, &token)); + int commandPosition = token.second; + if (commandPosition != -1) { - std::pair token; - IFT(m_spTokens->GetAt(i, &token)); - int commandPosition = token.second; - if (commandPosition != -1) + std::shared_ptr expCommand; + IFT(m_spCommands->GetAt(commandPosition, &expCommand)); + if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType()) { - std::shared_ptr expCommand; - IFT(m_spCommands->GetAt(commandPosition, &expCommand)); - if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType()) + std::shared_ptr opndCommand = std::static_pointer_cast(expCommand); + if (opndCommand != nullptr) { - std::shared_ptr opndCommand = std::static_pointer_cast(expCommand); - if (opndCommand != nullptr) - { - token.first = opndCommand->GetString(radix, precision); - IFT(m_spTokens->SetAt(i, token)); - opndCommand->SetCommands(GetOperandCommandsFromString(token.first)); - } + token.first = opndCommand->GetString(radix, precision); + IFT(m_spTokens->SetAt(i, token)); + opndCommand->SetCommands(GetOperandCommandsFromString(token.first)); } } } - SetExpressionDisplay(); } + SetExpressionDisplay(); } void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol) diff --git a/src/CalcManager/CalculatorManager.cpp b/src/CalcManager/CalculatorManager.cpp index 0f6ccd49..4d13c4a0 100644 --- a/src/CalcManager/CalculatorManager.cpp +++ b/src/CalcManager/CalculatorManager.cpp @@ -490,22 +490,25 @@ namespace CalculationManager void CalculatorManager::MemorizeNumber() { m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber)); - if (!(m_currentCalculatorEngine->FInErrorState())) + + if (m_currentCalculatorEngine->FInErrorState()) { - m_currentCalculatorEngine->ProcessCommand(IDC_STORE); - - auto memoryObjectPtr = m_currentCalculatorEngine->PersistedMemObject(); - if (memoryObjectPtr != nullptr) - { - m_memorizedNumbers.insert(m_memorizedNumbers.begin(), *memoryObjectPtr); - } - - if (m_memorizedNumbers.size() > m_maximumMemorySize) - { - m_memorizedNumbers.resize(m_maximumMemorySize); - } - this->SetMemorizedNumbersString(); + return; } + + m_currentCalculatorEngine->ProcessCommand(IDC_STORE); + + auto memoryObjectPtr = m_currentCalculatorEngine->PersistedMemObject(); + if (memoryObjectPtr != nullptr) + { + m_memorizedNumbers.insert(m_memorizedNumbers.begin(), *memoryObjectPtr); + } + + if (m_memorizedNumbers.size() > m_maximumMemorySize) + { + m_memorizedNumbers.resize(m_maximumMemorySize); + } + this->SetMemorizedNumbersString(); } /// @@ -516,11 +519,14 @@ namespace CalculationManager void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory) { SaveMemoryCommand(MemoryCommand::MemorizedNumberLoad, indexOfMemory); - if (!(m_currentCalculatorEngine->FInErrorState())) + + if (m_currentCalculatorEngine->FInErrorState()) { - this->MemorizedNumberSelect(indexOfMemory); - m_currentCalculatorEngine->ProcessCommand(IDC_RECALL); + return; } + + this->MemorizedNumberSelect(indexOfMemory); + m_currentCalculatorEngine->ProcessCommand(IDC_RECALL); } /// @@ -532,24 +538,27 @@ namespace CalculationManager void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory) { SaveMemoryCommand(MemoryCommand::MemorizedNumberAdd, indexOfMemory); - if (!(m_currentCalculatorEngine->FInErrorState())) + + if (m_currentCalculatorEngine->FInErrorState()) { - if (m_memorizedNumbers.empty()) - { - this->MemorizeNumber(); - } - else - { - this->MemorizedNumberSelect(indexOfMemory); - m_currentCalculatorEngine->ProcessCommand(IDC_MPLUS); - - this->MemorizedNumberChanged(indexOfMemory); - - this->SetMemorizedNumbersString(); - } - - m_displayCallback->MemoryItemChanged(indexOfMemory); + return; } + + if (m_memorizedNumbers.empty()) + { + this->MemorizeNumber(); + } + else + { + this->MemorizedNumberSelect(indexOfMemory); + m_currentCalculatorEngine->ProcessCommand(IDC_MPLUS); + + this->MemorizedNumberChanged(indexOfMemory); + + this->SetMemorizedNumbersString(); + } + + m_displayCallback->MemoryItemChanged(indexOfMemory); } void CalculatorManager::MemorizedNumberClear(_In_ unsigned int indexOfMemory) @@ -570,27 +579,30 @@ namespace CalculationManager void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory) { SaveMemoryCommand(MemoryCommand::MemorizedNumberSubtract, indexOfMemory); - if (!(m_currentCalculatorEngine->FInErrorState())) + + if (m_currentCalculatorEngine->FInErrorState()) { - // To add negative of the number on display to the memory -x = x - 2x - if (m_memorizedNumbers.empty()) - { - this->MemorizeNumber(); - this->MemorizedNumberSubtract(0); - this->MemorizedNumberSubtract(0); - } - else - { - this->MemorizedNumberSelect(indexOfMemory); - m_currentCalculatorEngine->ProcessCommand(IDC_MMINUS); - - this->MemorizedNumberChanged(indexOfMemory); - - this->SetMemorizedNumbersString(); - } - - m_displayCallback->MemoryItemChanged(indexOfMemory); + return; } + + // To add negative of the number on display to the memory -x = x - 2x + if (m_memorizedNumbers.empty()) + { + this->MemorizeNumber(); + this->MemorizedNumberSubtract(0); + this->MemorizedNumberSubtract(0); + } + else + { + this->MemorizedNumberSelect(indexOfMemory); + m_currentCalculatorEngine->ProcessCommand(IDC_MMINUS); + + this->MemorizedNumberChanged(indexOfMemory); + + this->SetMemorizedNumbersString(); + } + + m_displayCallback->MemoryItemChanged(indexOfMemory); } /// @@ -613,11 +625,13 @@ namespace CalculationManager /// Index of the target memory void CalculatorManager::MemorizedNumberSelect(_In_ unsigned int indexOfMemory) { - if (!(m_currentCalculatorEngine->FInErrorState())) + if (m_currentCalculatorEngine->FInErrorState()) { - auto memoryObject = m_memorizedNumbers.at(indexOfMemory); - m_currentCalculatorEngine->PersistedMemObject(memoryObject); + return; } + + auto memoryObject = m_memorizedNumbers.at(indexOfMemory); + m_currentCalculatorEngine->PersistedMemObject(memoryObject); } /// @@ -627,13 +641,15 @@ namespace CalculationManager /// Index of the target memory void CalculatorManager::MemorizedNumberChanged(_In_ unsigned int indexOfMemory) { - if (!(m_currentCalculatorEngine->FInErrorState())) + if (m_currentCalculatorEngine->FInErrorState()) { - auto memoryObject = m_currentCalculatorEngine->PersistedMemObject(); - if (memoryObject != nullptr) - { - m_memorizedNumbers.at(indexOfMemory) = *memoryObject; - } + return; + } + + auto memoryObject = m_currentCalculatorEngine->PersistedMemObject(); + if (memoryObject != nullptr) + { + m_memorizedNumbers.at(indexOfMemory) = *memoryObject; } } diff --git a/src/CalcManager/UnitConverter.cpp b/src/CalcManager/UnitConverter.cpp index bb1df9d6..0548719a 100644 --- a/src/CalcManager/UnitConverter.cpp +++ b/src/CalcManager/UnitConverter.cpp @@ -109,22 +109,8 @@ CategorySelectionInitializer UnitConverter::SetCurrentCategory(const Category& i vector& unitVector = m_categoryToUnits[m_currentCategory]; for (unsigned int i = 0; i < unitVector.size(); i++) { - if (unitVector[i].id == m_fromType.id) - { - unitVector[i].isConversionSource = true; - } - else - { - unitVector[i].isConversionSource = false; - } - if (unitVector[i].id == m_toType.id) - { - unitVector[i].isConversionTarget = true; - } - else - { - unitVector[i].isConversionTarget = false; - } + unitVector[i].isConversionSource = (unitVector[i].id == m_fromType.id); + unitVector[i].isConversionTarget = (unitVector[i].id == m_toType.id); } m_currentCategory = input; if (!m_currentCategory.supportsNegative && m_currentDisplay.front() == L'-') @@ -156,15 +142,17 @@ Category UnitConverter::GetCurrentCategory() /// Unit struct we are converting to void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) { - if (CheckLoad()) + if (!CheckLoad()) { - m_fromType = fromType; - m_toType = toType; - Calculate(); - - UpdateCurrencySymbols(); - UpdateViewModel(); + return; } + + m_fromType = fromType; + m_toType = toType; + Calculate(); + + UpdateCurrencySymbols(); + UpdateViewModel(); } /// @@ -181,22 +169,24 @@ void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType /// void UnitConverter::SwitchActive(const wstring& newValue) { - if (CheckLoad()) + if (!CheckLoad()) { - swap(m_fromType, m_toType); - swap(m_currentHasDecimal, m_returnHasDecimal); - m_returnDisplay = m_currentDisplay; - m_currentDisplay = newValue; - m_currentHasDecimal = (m_currentDisplay.find(L'.') != m_currentDisplay.npos); - m_switchedActive = true; + return; + } - if (m_currencyDataLoader != nullptr && m_vmCurrencyCallback != nullptr) - { - shared_ptr currencyDataLoader = GetCurrencyConverterDataLoader(); - const pair currencyRatios = currencyDataLoader->GetCurrencyRatioEquality(m_fromType, m_toType); + swap(m_fromType, m_toType); + swap(m_currentHasDecimal, m_returnHasDecimal); + m_returnDisplay = m_currentDisplay; + m_currentDisplay = newValue; + m_currentHasDecimal = (m_currentDisplay.find(L'.') != m_currentDisplay.npos); + m_switchedActive = true; - m_vmCurrencyCallback->CurrencyRatiosCallback(currencyRatios.first, currencyRatios.second); - } + if (m_currencyDataLoader != nullptr && m_vmCurrencyCallback != nullptr) + { + shared_ptr currencyDataLoader = GetCurrencyConverterDataLoader(); + const pair currencyRatios = currencyDataLoader->GetCurrencyRatioEquality(m_fromType, m_toType); + + m_vmCurrencyCallback->CurrencyRatiosCallback(currencyRatios.first, currencyRatios.second); } } @@ -291,55 +281,53 @@ wstring UnitConverter::ConversionDataToString(ConversionData d, const wchar_t * /// wstring UnitConverter::Serialize() { - if (CheckLoad()) - { - wstringstream out(wstringstream::out); - const wchar_t * delimiter = L";"; - - out << UnitToString(m_fromType, delimiter) << "|"; - out << UnitToString(m_toType, delimiter) << "|"; - out << CategoryToString(m_currentCategory, delimiter) << "|"; - out << std::to_wstring(m_currentHasDecimal) << delimiter << std::to_wstring(m_returnHasDecimal) << delimiter << std::to_wstring(m_switchedActive) << delimiter; - out << m_currentDisplay << delimiter << m_returnDisplay << delimiter << "|"; - wstringstream categoryString(wstringstream::out); - wstringstream categoryToUnitString(wstringstream::out); - wstringstream unitToUnitToDoubleString(wstringstream::out); - for (const Category& c : m_categories) - { - categoryString << CategoryToString(c, delimiter) << ","; - } - - for (const auto& cur : m_categoryToUnits) - { - categoryToUnitString << CategoryToString(cur.first, delimiter) << "["; - for (const Unit& u : cur.second) - { - categoryToUnitString << UnitToString(u, delimiter) << ","; - } - categoryToUnitString << "[" << "]"; - } - - for (const auto& cur : m_ratioMap) - { - unitToUnitToDoubleString << UnitToString(cur.first, delimiter) << "["; - for (const auto& curConversion : cur.second) - { - unitToUnitToDoubleString << UnitToString(curConversion.first, delimiter) << ":"; - unitToUnitToDoubleString << ConversionDataToString(curConversion.second, delimiter) << ":,"; - } - unitToUnitToDoubleString << "[" << "]"; - } - - out << categoryString.str() << "|"; - out << categoryToUnitString.str() << "|"; - out << unitToUnitToDoubleString.str() << "|"; - wstring test = out.str(); - return test; - } - else + if (!CheckLoad()) { return wstring(); } + + wstringstream out(wstringstream::out); + const wchar_t * delimiter = L";"; + + out << UnitToString(m_fromType, delimiter) << "|"; + out << UnitToString(m_toType, delimiter) << "|"; + out << CategoryToString(m_currentCategory, delimiter) << "|"; + out << std::to_wstring(m_currentHasDecimal) << delimiter << std::to_wstring(m_returnHasDecimal) << delimiter << std::to_wstring(m_switchedActive) << delimiter; + out << m_currentDisplay << delimiter << m_returnDisplay << delimiter << "|"; + wstringstream categoryString(wstringstream::out); + wstringstream categoryToUnitString(wstringstream::out); + wstringstream unitToUnitToDoubleString(wstringstream::out); + for (const Category& c : m_categories) + { + categoryString << CategoryToString(c, delimiter) << ","; + } + + for (const auto& cur : m_categoryToUnits) + { + categoryToUnitString << CategoryToString(cur.first, delimiter) << "["; + for (const Unit& u : cur.second) + { + categoryToUnitString << UnitToString(u, delimiter) << ","; + } + categoryToUnitString << "[" << "]"; + } + + for (const auto& cur : m_ratioMap) + { + unitToUnitToDoubleString << UnitToString(cur.first, delimiter) << "["; + for (const auto& curConversion : cur.second) + { + unitToUnitToDoubleString << UnitToString(curConversion.first, delimiter) << ":"; + unitToUnitToDoubleString << ConversionDataToString(curConversion.second, delimiter) << ":,"; + } + unitToUnitToDoubleString << "[" << "]"; + } + + out << categoryString.str() << "|"; + out << categoryToUnitString.str() << "|"; + out << unitToUnitToDoubleString.str() << "|"; + wstring test = out.str(); + return test; } /// @@ -349,55 +337,58 @@ wstring UnitConverter::Serialize() void UnitConverter::DeSerialize(const wstring& serializedData) { Reset(); - if (!serializedData.empty()) + + if (serializedData.empty()) { - vector outerTokens = StringToVector(serializedData, L"|"); - assert(outerTokens.size() == EXPECTEDSERIALIZEDTOKENCOUNT); - m_fromType = StringToUnit(outerTokens[0]); - m_toType = StringToUnit(outerTokens[1]); - m_currentCategory = StringToCategory(outerTokens[2]); - vector stateDataTokens = StringToVector(outerTokens[3], L";"); - assert(stateDataTokens.size() == EXPECTEDSTATEDATATOKENCOUNT); - m_currentHasDecimal = (stateDataTokens[0].compare(L"1") == 0); - m_returnHasDecimal = (stateDataTokens[1].compare(L"1") == 0); - m_switchedActive = (stateDataTokens[2].compare(L"1") == 0); - m_currentDisplay = stateDataTokens[3]; - m_returnDisplay = stateDataTokens[4]; - vector categoryListTokens = StringToVector(outerTokens[4], L","); - for (wstring token : categoryListTokens) - { - m_categories.push_back(StringToCategory(token)); - } - vector unitVectorTokens = StringToVector(outerTokens[5], L"]"); - for (wstring unitVector : unitVectorTokens) - { - vector mapcomponents = StringToVector(unitVector, L"["); - assert(mapcomponents.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT); - Category key = StringToCategory(mapcomponents[0]); - vector units = StringToVector(mapcomponents[1], L","); - for (wstring unit : units) - { - m_categoryToUnits[key].push_back(StringToUnit(unit)); - } - } - vector ratioMapTokens = StringToVector(outerTokens[6], L"]"); - for (wstring token : ratioMapTokens) - { - vector ratioMapComponentTokens = StringToVector(token, L"["); - assert(ratioMapComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT); - Unit key = StringToUnit(ratioMapComponentTokens[0]); - vector ratioMapList = StringToVector(ratioMapComponentTokens[1], L","); - for (wstring subtoken : ratioMapList) - { - vector ratioMapSubComponentTokens = StringToVector(subtoken, L":"); - assert(ratioMapSubComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT); - Unit subkey = StringToUnit(ratioMapSubComponentTokens[0]); - ConversionData conversion = StringToConversionData(ratioMapSubComponentTokens[1]); - m_ratioMap[key][subkey] = conversion; - } - } - UpdateViewModel(); + return; } + + vector outerTokens = StringToVector(serializedData, L"|"); + assert(outerTokens.size() == EXPECTEDSERIALIZEDTOKENCOUNT); + m_fromType = StringToUnit(outerTokens[0]); + m_toType = StringToUnit(outerTokens[1]); + m_currentCategory = StringToCategory(outerTokens[2]); + vector stateDataTokens = StringToVector(outerTokens[3], L";"); + assert(stateDataTokens.size() == EXPECTEDSTATEDATATOKENCOUNT); + m_currentHasDecimal = (stateDataTokens[0].compare(L"1") == 0); + m_returnHasDecimal = (stateDataTokens[1].compare(L"1") == 0); + m_switchedActive = (stateDataTokens[2].compare(L"1") == 0); + m_currentDisplay = stateDataTokens[3]; + m_returnDisplay = stateDataTokens[4]; + vector categoryListTokens = StringToVector(outerTokens[4], L","); + for (wstring token : categoryListTokens) + { + m_categories.push_back(StringToCategory(token)); + } + vector unitVectorTokens = StringToVector(outerTokens[5], L"]"); + for (wstring unitVector : unitVectorTokens) + { + vector mapcomponents = StringToVector(unitVector, L"["); + assert(mapcomponents.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT); + Category key = StringToCategory(mapcomponents[0]); + vector units = StringToVector(mapcomponents[1], L","); + for (wstring unit : units) + { + m_categoryToUnits[key].push_back(StringToUnit(unit)); + } + } + vector ratioMapTokens = StringToVector(outerTokens[6], L"]"); + for (wstring token : ratioMapTokens) + { + vector ratioMapComponentTokens = StringToVector(token, L"["); + assert(ratioMapComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT); + Unit key = StringToUnit(ratioMapComponentTokens[0]); + vector ratioMapList = StringToVector(ratioMapComponentTokens[1], L","); + for (wstring subtoken : ratioMapList) + { + vector ratioMapSubComponentTokens = StringToVector(subtoken, L":"); + assert(ratioMapSubComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT); + Unit subkey = StringToUnit(ratioMapSubComponentTokens[0]); + ConversionData conversion = StringToConversionData(ratioMapSubComponentTokens[1]); + m_ratioMap[key][subkey] = conversion; + } + } + UpdateViewModel(); } /// @@ -406,15 +397,17 @@ void UnitConverter::DeSerialize(const wstring& serializedData) /// wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it void UnitConverter::RestoreUserPreferences(const wstring& userPreferences) { - if (!userPreferences.empty()) + if (userPreferences.empty()) { - vector outerTokens = StringToVector(userPreferences, L"|"); - if (outerTokens.size() == 3) - { - m_fromType = StringToUnit(outerTokens[0]); - m_toType = StringToUnit(outerTokens[1]); - m_currentCategory = StringToCategory(outerTokens[2]); - } + return; + } + + vector outerTokens = StringToVector(userPreferences, L"|"); + if (outerTokens.size() == 3) + { + m_fromType = StringToUnit(outerTokens[0]); + m_toType = StringToUnit(outerTokens[1]); + m_currentCategory = StringToCategory(outerTokens[2]); } } @@ -503,144 +496,146 @@ wstring UnitConverter::Unquote(const wstring& s) /// Command enum representing the command that was entered void UnitConverter::SendCommand(Command command) { - if (CheckLoad()) + if (!CheckLoad()) { - // TODO: Localization of characters - bool clearFront = false; - if (m_currentDisplay == L"0") + return; + } + + // TODO: Localization of characters + bool clearFront = false; + if (m_currentDisplay == L"0") + { + clearFront = true; + } + bool clearBack = false; + if ((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED) || (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED)) + { + clearBack = true; + } + if (command != Command::Negate && m_switchedActive) + { + ClearValues(); + m_switchedActive = false; + clearFront = true; + clearBack = false; + } + switch (command) + { + case Command::Zero: + m_currentDisplay += L"0"; + break; + + case Command::One: + m_currentDisplay += L"1"; + break; + + case Command::Two: + m_currentDisplay += L"2"; + break; + + case Command::Three: + m_currentDisplay += L"3"; + break; + + case Command::Four: + m_currentDisplay += L"4"; + break; + + case Command::Five: + m_currentDisplay += L"5"; + break; + + case Command::Six: + m_currentDisplay += L"6"; + break; + + case Command::Seven: + m_currentDisplay += L"7"; + break; + + case Command::Eight: + m_currentDisplay += L"8"; + break; + + case Command::Nine: + m_currentDisplay += L"9"; + break; + + case Command::Decimal: + clearFront = false; + clearBack = false; + if (!m_currentHasDecimal) { - clearFront = true; + m_currentDisplay += L"."; + m_currentHasDecimal = true; } - bool clearBack = false; - if ((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED) || (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED)) + break; + + case Command::Backspace: + clearFront = false; + clearBack = false; + if ((m_currentDisplay.front() != '-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2) { - clearBack = true; - } - if (command != Command::Negate && m_switchedActive) - { - ClearValues(); - m_switchedActive = false; - clearFront = true; - clearBack = false; - } - switch (command) - { - case Command::Zero: - m_currentDisplay += L"0"; - break; - - case Command::One: - m_currentDisplay += L"1"; - break; - - case Command::Two: - m_currentDisplay += L"2"; - break; - - case Command::Three: - m_currentDisplay += L"3"; - break; - - case Command::Four: - m_currentDisplay += L"4"; - break; - - case Command::Five: - m_currentDisplay += L"5"; - break; - - case Command::Six: - m_currentDisplay += L"6"; - break; - - case Command::Seven: - m_currentDisplay += L"7"; - break; - - case Command::Eight: - m_currentDisplay += L"8"; - break; - - case Command::Nine: - m_currentDisplay += L"9"; - break; - - case Command::Decimal: - clearFront = false; - clearBack = false; - if (!m_currentHasDecimal) + if (m_currentDisplay.back() == '.') { - m_currentDisplay += L"."; - m_currentHasDecimal = true; + m_currentHasDecimal = false; } - break; + m_currentDisplay.pop_back(); + } + else + { + m_currentDisplay = L"0"; + m_currentHasDecimal = false; + } + break; - case Command::Backspace: - clearFront = false; - clearBack = false; - if ((m_currentDisplay.front() != '-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2) + case Command::Negate: + clearFront = false; + clearBack = false; + if (m_currentCategory.supportsNegative) + { + if (m_currentDisplay.front() == '-') { - if (m_currentDisplay.back() == '.') - { - m_currentHasDecimal = false; - } - m_currentDisplay.pop_back(); + m_currentDisplay.erase(0, 1); } else { - m_currentDisplay = L"0"; - m_currentHasDecimal = false; + m_currentDisplay.insert(0, 1, '-'); } - break; - - case Command::Negate: - clearFront = false; - clearBack = false; - if (m_currentCategory.supportsNegative) - { - if (m_currentDisplay.front() == '-') - { - m_currentDisplay.erase(0, 1); - } - else - { - m_currentDisplay.insert(0, 1, '-'); - } - } - break; - - case Command::Clear: - clearFront = false; - clearBack = false; - ClearValues(); - break; - - case Command::Reset: - clearFront = false; - clearBack = false; - ClearValues(); - Reset(); - break; - - default: - break; } + break; + case Command::Clear: + clearFront = false; + clearBack = false; + ClearValues(); + break; - if (clearFront) - { - m_currentDisplay.erase(0, 1); - } - if (clearBack) - { - m_currentDisplay.erase(m_currentDisplay.size() - 1, 1); - m_vmCallback->MaxDigitsReached(); - } + case Command::Reset: + clearFront = false; + clearBack = false; + ClearValues(); + Reset(); + break; - Calculate(); - - UpdateViewModel(); + default: + break; } + + + if (clearFront) + { + m_currentDisplay.erase(0, 1); + } + if (clearBack) + { + m_currentDisplay.erase(m_currentDisplay.size() - 1, 1); + m_vmCallback->MaxDigitsReached(); + } + + Calculate(); + + UpdateViewModel(); } /// @@ -844,47 +839,49 @@ void UnitConverter::Reset() ClearValues(); m_switchedActive = false; - if (!m_categories.empty()) + if (m_categories.empty()) { - m_currentCategory = m_categories[0]; + return; + } - m_categoryToUnits.clear(); - m_ratioMap.clear(); - bool readyCategoryFound = false; - for (const Category& category : m_categories) + m_currentCategory = m_categories[0]; + + m_categoryToUnits.clear(); + m_ratioMap.clear(); + bool readyCategoryFound = false; + for (const Category& category : m_categories) + { + shared_ptr activeDataLoader = GetDataLoaderForCategory(category); + if (activeDataLoader == nullptr) { - shared_ptr activeDataLoader = GetDataLoaderForCategory(category); - if (activeDataLoader == nullptr) - { - // The data loader is different depending on the category, e.g. currency data loader - // is different from the static data loader. - // If there is no data loader for this category, continue. - continue; - } - - vector units = activeDataLoader->LoadOrderedUnits(category); - m_categoryToUnits[category] = units; - - // Just because the units are empty, doesn't mean the user can't select this category, - // we just want to make sure we don't let an unready category be the default. - if (!units.empty()) - { - for (Unit u : units) - { - m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u); - } - - if (!readyCategoryFound) - { - m_currentCategory = category; - readyCategoryFound = true; - } - } + // The data loader is different depending on the category, e.g. currency data loader + // is different from the static data loader. + // If there is no data loader for this category, continue. + continue; } - InitializeSelectedUnits(); - Calculate(); + vector units = activeDataLoader->LoadOrderedUnits(category); + m_categoryToUnits[category] = units; + + // Just because the units are empty, doesn't mean the user can't select this category, + // we just want to make sure we don't let an unready category be the default. + if (!units.empty()) + { + for (Unit u : units) + { + m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u); + } + + if (!readyCategoryFound) + { + m_currentCategory = category; + readyCategoryFound = true; + } + } } + + InitializeSelectedUnits(); + Calculate(); } /// @@ -1029,22 +1026,24 @@ void UnitConverter::Calculate() /// wstring to trim void UnitConverter::TrimString(wstring& returnString) { - if (returnString.find(L'.') != m_returnDisplay.npos) + if (returnString.find(L'.') == m_returnDisplay.npos) { - wstring::iterator iter; - for (iter = returnString.end() - 1; ;iter--) + return; + } + + wstring::iterator iter; + for (iter = returnString.end() - 1; ;iter--) + { + if (*iter != L'0') { - if (*iter != L'0') - { - returnString.erase(iter + 1, returnString.end()); - break; - } - } - if (*(returnString.end()-1) == L'.') - { - returnString.erase(returnString.end()-1, returnString.end()); + returnString.erase(iter + 1, returnString.end()); + break; } } + if (*(returnString.end()-1) == L'.') + { + returnString.erase(returnString.end()-1, returnString.end()); + } } /// From 965e36cc5dac5a772d60f4dbadff9992b90c34d3 Mon Sep 17 00:00:00 2001 From: Shamkhal Maharramov <9804406+Maharramoff@users.noreply.github.com> Date: Tue, 19 Mar 2019 00:38:04 +0400 Subject: [PATCH 06/28] Propose minor code-cleanups (#241) Description of the changes: Remove unnecessary 'else', 'continue' statements How changes were validated: Manual. --- src/CalcViewModel/UnitConverterViewModel.cpp | 21 +++++++------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/CalcViewModel/UnitConverterViewModel.cpp b/src/CalcViewModel/UnitConverterViewModel.cpp index 7ae1eb2b..2d4df1c9 100644 --- a/src/CalcViewModel/UnitConverterViewModel.cpp +++ b/src/CalcViewModel/UnitConverterViewModel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -202,12 +202,10 @@ void UnitConverterViewModel::BuildUnitList(const vector& modelUnitLis m_Units->Clear(); for (const UCM::Unit& modelUnit : modelUnitList) { - if (modelUnit.isWhimsical) + if (!modelUnit.isWhimsical) { - continue; + m_Units->Append(ref new Unit(modelUnit)); } - - m_Units->Append(ref new Unit(modelUnit)); } if (m_Units->Size == 0) @@ -643,10 +641,8 @@ String^ UnitConverterViewModel::Serialize() String^ serializedData = ref new String(wstring(out.str()).c_str()); return serializedData; } - else - { - return nullptr; - } + + return nullptr; } void UnitConverterViewModel::Deserialize(Platform::String^ state) @@ -879,14 +875,11 @@ void UnitConverterViewModel::UpdateInputBlocked(_In_ const wstring& currencyInpu { // currencyInput is in en-US and has the default decimal separator, so this is safe to do. auto posOfDecimal = currencyInput.find(L'.'); + m_isInputBlocked = false; if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory) { m_isInputBlocked = (posOfDecimal + static_cast(m_currencyMaxFractionDigits) + 1 == currencyInput.length()); } - else - { - m_isInputBlocked = false; - } } NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId( @@ -988,7 +981,7 @@ void UnitConverterViewModel::OnPaste(String^ stringToPaste, ViewMode mode) } // Negate is only allowed if it's the first legal character, which is handled above. - if (NumbersAndOperatorsEnum::None != op && NumbersAndOperatorsEnum::Negate != op) + if (NumbersAndOperatorsEnum::Negate != op) { UCM::Command cmd = CommandFromButtonId(op); m_model->SendCommand(cmd); From 3d18dd38c2da74f470663fcd25ddbbb9f4d4b6eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Mon, 18 Mar 2019 22:02:02 +0100 Subject: [PATCH 07/28] Add explicit [[fallthrough]] attributes in Ratpack (#323) --- src/CalcManager/Ratpack/conv.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CalcManager/Ratpack/conv.cpp b/src/CalcManager/Ratpack/conv.cpp index ff7b18d5..cfd2ec40 100644 --- a/src/CalcManager/Ratpack/conv.cpp +++ b/src/CalcManager/Ratpack/conv.cpp @@ -612,6 +612,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis break; } // Drop through in the 'e'-as-a-digit case + [[fallthrough]]; default: state = machine[state][NZ]; break; @@ -646,7 +647,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis break; case LD: pnumret->exp++; - // Fall through + [[fallthrough]]; case DD: { curChar = NormalizeCharDigit(curChar, radix); From 62b2fafdd0810110e0164c041c559b7ca10b79f2 Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Mon, 18 Mar 2019 14:09:13 -0700 Subject: [PATCH 08/28] Fix formatting issues with CurrencyConverter and some locales (#242) The ViewModel wrongly assumed that non-breaking spaces were only used between the value and the symbol. It's not the case of all locales using non-breaking spaces as a thousand delimiter (French for example). When it was the case, the function only replaced the first thousand delimiter found and kept the extra space at the end of the string, generating 2 issues: Extra space at the end: #240 Bad formatting of the number: #232 Description of the changes: Replace currencyResult.find(L'\u00a0') by a regex only removing spaces at the end of the string. Fixes #240 and #232 --- src/CalcViewModel/UnitConverterViewModel.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/CalcViewModel/UnitConverterViewModel.cpp b/src/CalcViewModel/UnitConverterViewModel.cpp index 2d4df1c9..1cf478f0 100644 --- a/src/CalcViewModel/UnitConverterViewModel.cpp +++ b/src/CalcViewModel/UnitConverterViewModel.cpp @@ -53,6 +53,8 @@ constexpr size_t SELECTED_TARGET_UNIT = 2; // x millisecond delay before we consider conversion to be final constexpr unsigned int CONVERSION_FINALIZED_DELAY_IN_MS = 1000; +const wregex regexTrimSpacesStart = wregex(L"^\\s+"); +const wregex regexTrimSpacesEnd = wregex(L"\\s+$"); namespace CalculatorApp::ViewModel { @@ -346,10 +348,15 @@ String^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& str if (pos != wstring::npos) { currencyResult.erase(pos, currencyCode.length()); - pos = currencyResult.find(L'\u00a0'); // non-breaking space - if (pos != wstring::npos) + std::wsmatch sm; + if (regex_search(currencyResult, sm, regexTrimSpacesStart)) { - currencyResult.erase(pos, 1); + currencyResult.erase(sm.prefix().length(), sm.length()); + } + + if (regex_search(currencyResult, sm, regexTrimSpacesEnd)) + { + currencyResult.erase(sm.prefix().length(), sm.length()); } } From 21e15c426e35083f5f6d203b86cea597a47bcb57 Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Mon, 18 Mar 2019 14:22:44 -0700 Subject: [PATCH 09/28] hide history button in programmer mode (#327) Description of the changes: Hide the History button when in Programmer mode via VisualState How changes were validated: Open Standard mode Switch to Programmer mode Verify that the History button isn't visible Fixes #326 --- src/Calculator/Views/Calculator.xaml | 1 + src/Calculator/Views/Calculator.xaml.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Calculator/Views/Calculator.xaml b/src/Calculator/Views/Calculator.xaml index b7db10eb..01164b83 100644 --- a/src/Calculator/Views/Calculator.xaml +++ b/src/Calculator/Views/Calculator.xaml @@ -515,6 +515,7 @@ + diff --git a/src/Calculator/Views/Calculator.xaml.cpp b/src/Calculator/Views/Calculator.xaml.cpp index 10858a30..65b3f45e 100644 --- a/src/Calculator/Views/Calculator.xaml.cpp +++ b/src/Calculator/Views/Calculator.xaml.cpp @@ -415,7 +415,7 @@ void Calculator::UpdateHistoryState() SetChildAsHistory(); HistoryButton->Visibility = ::Visibility::Collapsed; - if (m_IsLastFlyoutHistory) + if (!IsProgrammer && m_IsLastFlyoutHistory) { DockPivot->SelectedIndex = 0; } @@ -522,7 +522,7 @@ void Calculator::HistoryFlyout_Closed(_In_ Object ^sender, _In_ Object ^args) AutomationProperties::SetName(HistoryButton, m_openHistoryFlyoutAutomationName); m_fIsHistoryFlyoutOpen = false; EnableControls(true); - if (HistoryButton->IsEnabled) + if (HistoryButton->IsEnabled && HistoryButton->Visibility == ::Visibility::Visible) { HistoryButton->Focus(::FocusState::Programmatic); } From 4b6b8fa8fa9449b6f05aa9e14120dbc18b2a68d9 Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Wed, 20 Mar 2019 09:54:02 -0700 Subject: [PATCH 10/28] Fix auto-scaling of CalculationResult when the current locale displays currency symbols on the right (#246) * Fix auto-scaling of CalculationResult when the current locale displays symbols at the right * Formatting * add padding * modify padding of ValueContainer --- src/Calculator/Views/UnitConverter.xaml | 31 ++++++++++++++++----- src/Calculator/Views/UnitConverter.xaml.cpp | 13 ++------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/Calculator/Views/UnitConverter.xaml b/src/Calculator/Views/UnitConverter.xaml index 05736331..e0f337a4 100644 --- a/src/Calculator/Views/UnitConverter.xaml +++ b/src/Calculator/Views/UnitConverter.xaml @@ -230,19 +230,19 @@ BasedOn="{StaticResource CurrencySymbolBaseStyle}" TargetType="TextBlock"> - +