From b97046ad67166bc4d5c6b07e0ec58919caa0671b Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Fri, 18 Oct 2019 11:07:51 -0700 Subject: [PATCH] Allow users to paste expressions with ^or % (#682) --- src/CalcViewModel/Common/CopyPasteManager.cpp | 46 ++++++++++++++----- .../StandardCalculatorViewModel.cpp | 14 ++++++ .../CopyPasteManagerTest.cpp | 25 +++++++--- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/CalcViewModel/Common/CopyPasteManager.cpp b/src/CalcViewModel/Common/CopyPasteManager.cpp index 45f4b21..890dc40 100644 --- a/src/CalcViewModel/Common/CopyPasteManager.cpp +++ b/src/CalcViewModel/Common/CopyPasteManager.cpp @@ -17,7 +17,10 @@ using namespace Windows::ApplicationModel::DataTransfer; String ^ CopyPasteManager::supportedFormats[] = { StandardDataFormats::Text }; -static constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" }; +static const wstring c_validBasicCharacterSet = L"0123456789+-.e"; +static const wstring c_validStandardCharacterSet = c_validBasicCharacterSet + L"*/"; +static const wstring c_validScientificCharacterSet = c_validStandardCharacterSet + L"()^%"; +static const wstring c_validProgrammerCharacterSet = c_validStandardCharacterSet + L"()%abcdfABCDEF"; // The below values can not be "constexpr"-ed, // as both wstring_view and wchar[] can not be concatenated @@ -102,8 +105,7 @@ String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode // return "NoOp" if pastedText is invalid else return pastedText -String - ^ CopyPasteManager::ValidatePasteExpression( +String ^ CopyPasteManager::ValidatePasteExpression( String ^ pastedText, ViewMode mode, CategoryGroupType modeType, @@ -165,12 +167,29 @@ vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression bool isPreviousOpenParen = false; bool isPreviousOperator = false; + wstring validCharacterSet; + switch (mode) + { + case ViewMode::Standard: + validCharacterSet = c_validStandardCharacterSet; + break; + case ViewMode::Scientific: + validCharacterSet = c_validScientificCharacterSet; + break; + case ViewMode::Programmer: + validCharacterSet = c_validProgrammerCharacterSet; + break; + default: + validCharacterSet = c_validBasicCharacterSet; + } + // This will have the exponent length size_t expLength = 0; for (size_t i = 0; i < pasteExpression.length(); i++) { + wchar_t currentChar = pasteExpression.at(i); // if the current character is not a valid one don't process it - if (c_validCharacterSet.find(pasteExpression.at(i)) == wstring_view::npos) + if (validCharacterSet.find(currentChar) == wstring_view::npos) { continue; } @@ -182,9 +201,9 @@ vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression return operands; } - if (startExpCounting) + if (currentChar >= L'0' && currentChar <= L'9') { - if ((pasteExpression.at(i) >= L'0') && (pasteExpression.at(i) <= L'9')) + if (startExpCounting) { expLength++; @@ -196,16 +215,19 @@ vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression return operands; } } + isPreviousOperator = false; } - - if ((mode != ViewMode::Programmer) && (pasteExpression.at(i) == L'e')) + else if (currentChar == L'e') { - startExpCounting = true; + if (mode != ViewMode::Programmer) + { + startExpCounting = true; + } + isPreviousOperator = false; } - - if (((pasteExpression.at(i) == L'+') || (pasteExpression.at(i) == L'-') || (pasteExpression.at(i) == L'*') || (pasteExpression.at(i) == L'/'))) + else if (currentChar == L'+' || currentChar == L'-' || currentChar == L'*' || currentChar == L'/' || currentChar == L'^' || currentChar == L'%') { - if ((pasteExpression.at(i) == L'+') || (pasteExpression.at(i) == L'-')) + if (currentChar == L'+' || currentChar == L'-') { // don't break the expression into operands if the encountered character corresponds to sign command(+-) if (isPreviousOpenParen || startOfExpression || isPreviousOperator diff --git a/src/CalcViewModel/StandardCalculatorViewModel.cpp b/src/CalcViewModel/StandardCalculatorViewModel.cpp index c842d20..4a59249 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.cpp +++ b/src/CalcViewModel/StandardCalculatorViewModel.cpp @@ -953,6 +953,20 @@ NumbersAndOperatorsEnum StandardCalculatorViewModel::MapCharacterToButtonId(cons mappedValue = NumbersAndOperatorsEnum::Divide; break; + case '^': + if (IsScientific) + { + mappedValue = NumbersAndOperatorsEnum::XPowerY; + } + break; + + case '%': + if (IsScientific || IsProgrammer) + { + mappedValue = NumbersAndOperatorsEnum::Mod; + } + break; + case '=': mappedValue = NumbersAndOperatorsEnum::Equals; break; diff --git a/src/CalculatorUnitTests/CopyPasteManagerTest.cpp b/src/CalculatorUnitTests/CopyPasteManagerTest.cpp index 2c2a61c..8483e21 100644 --- a/src/CalculatorUnitTests/CopyPasteManagerTest.cpp +++ b/src/CalculatorUnitTests/CopyPasteManagerTest.cpp @@ -630,7 +630,8 @@ namespace CalculatorUnitTests L"xyz", L"ABab", L"e+234", L"12345678912345678" /*boundary condition: greater than 16 digits*/, L"SIN(2)", L"2+2==", - L"2=+2" }; + L"2=+2", L"2%2", + L"10^2" }; ASSERT_POSITIVE_TESTCASES(ValidateStandardPasteExpression, positiveInput); ASSERT_NEGATIVE_TESTCASES(ValidateStandardPasteExpression, negativeInput); @@ -668,7 +669,11 @@ namespace CalculatorUnitTests "-(432+3232)", "-(+(-3213)+(-2312))", "-(-(432+3232))", - L"1.2e23"/*unsigned exponent*/ }; + L"1.2e23"/*unsigned exponent*/, + L"12^2", + L"-12.12^-2", + L"61%99" + L"-6.1%99" }; String ^ negativeInput[] = { L"abcdef", L"xyz", L"ABab", @@ -710,7 +715,10 @@ namespace CalculatorUnitTests L"1234ul", L"1234ULL", L"2+2=", - L"2+2= " }; + L"2+2= ", + L"A4C3%12", + L"1233%AB", + L"FFC1%F2" }; String ^ qwordNegativeInput[] = { L"+123", L"1.23" /*floating number*/, L"1''2", @@ -906,7 +914,8 @@ namespace CalculatorUnitTests L"1234ul", L"1234ULL", L"2+2=", - L"2+2= " }; + L"2+2= ", + L"823%21" }; String ^ qwordNegativeInput[] = { L"1.23", L"1''2", L"'123", @@ -1060,7 +1069,7 @@ namespace CalculatorUnitTests { String ^ qwordPositiveInput[] = { L"123", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"1\"2", L"(123)+(456)", L"0t1234", L"0T1234", L"0o1234", L"0O1234", L"1234u", - L"1234ul", L"1234ULL", L"2+2=", L"2+2= " }; + L"1234ul", L"1234ULL", L"2+2=", L"2+2= ", L"127%71" }; String ^ qwordNegativeInput[] = { L"+123", L"1.23", L"1''2", @@ -1084,7 +1093,8 @@ namespace CalculatorUnitTests L"1234uu", L"1234ulll", L"2+2==", - L"2=+2" }; + L"2=+2", + L"89%12"}; ASSERT_POSITIVE_TESTCASES(ValidateProgrammerOctQwordPasteExpression, qwordPositiveInput); ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerOctQwordPasteExpression, qwordNegativeInput); @@ -1217,7 +1227,8 @@ namespace CalculatorUnitTests L"1111ULL", L"1010101010101010101010101011110110100100101010101001010101001010" /*boundary condition: max allowed digits 64*/, L"1+10=", - L"1+10= " }; + L"1+10= ", + L"1001%10" }; String ^ qwordNegativeInput[] = { L"+10101", L"1.01",