From 089f7deb08f7f22d07594e5c04f32fceb24ca7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Han=20Zhang=20=F0=9F=91=BE?= Date: Tue, 21 May 2024 07:22:32 +0000 Subject: [PATCH] Merged PR 10790341: [Recall] Update calculator engine with snapshot for further calculations ####What When restoring from snapshot, we need to set calculator engine properly to make further calculations correct. ####How Update calculator engine by a serial of corresponding commands from snapshot. To get the commands for the display area when saving snapshot, 1. If the expression is not from history and the primary display is the result of the expression, `DisplayCommands` of `StandardCalculatorSnapshot` will be empty, and we will use the commands from `ExpressionDisplay` for restoring in the future. 2. If the expression is not from history and the primary display is not the result of the expression, `DisplayCommands` of `StandardCalculatorSnapshot` will be the commands from the history collector in addition to the operand command in the primary display, and it will be used for restoring in the future. 3. If the expression and primary display are from history, `DisplayCommands` will be incomplete with the operand command in the primary display missing as by current design of history, and the commands from `ExpressionDisplay` will be used for restoring in the future. Related work items: #51002745 --- src/CalcManager/CEngine/History.cpp | 102 ++++++++------- src/CalcManager/CEngine/calc.cpp | 10 ++ src/CalcManager/CalculatorManager.cpp | 5 + src/CalcManager/CalculatorManager.h | 1 + src/CalcManager/Header Files/CalcEngine.h | 2 + src/CalcManager/Header Files/History.h | 9 +- src/CalcViewModel/ApplicationViewModel.cpp | 7 + .../StandardCalculatorViewModel.cpp | 120 ++++++++++-------- .../StandardCalculatorViewModel.h | 1 + 9 files changed, 161 insertions(+), 96 deletions(-) diff --git a/src/CalcManager/CEngine/History.cpp b/src/CalcManager/CEngine/History.cpp index f45ff090..e0cb5337 100644 --- a/src/CalcManager/CEngine/History.cpp +++ b/src/CalcManager/CEngine/History.cpp @@ -3,7 +3,6 @@ #include "Header Files/CalcEngine.h" #include "Command.h" -#include "ExpressionCommand.h" #include "winerror_cross_platform.h" constexpr int ASCII_0 = 48; @@ -66,47 +65,7 @@ CHistoryCollector::~CHistoryCollector() void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& rat, bool fRepetition) { - std::shared_ptr> commands = std::make_shared>(); - // Check for negate - bool fNegative = (numStr[0] == L'-'); - bool fSciFmt = false; - bool fDecimal = false; - - for (size_t i = (fNegative ? 1 : 0); i < numStr.length(); i++) - { - if (numStr[i] == m_decimalSymbol) - { - commands->push_back(IDC_PNT); - if (!fSciFmt) - { - fDecimal = true; - } - } - else if (numStr[i] == L'e') - { - commands->push_back(IDC_EXP); - fSciFmt = true; - } - else if (numStr[i] == L'-') - { - commands->push_back(IDC_SIGN); - } - else if (numStr[i] == L'+') - { - // Ignore. - } - // Number - else - { - int num = static_cast(numStr[i]) - ASCII_0; - num += IDC_0; - commands->push_back(num); - } - } - - auto operandCommand = std::make_shared(commands, fNegative, fDecimal, fSciFmt); - operandCommand->Initialize(rat); - int iCommandEnd = AddCommand(operandCommand); + int iCommandEnd = AddCommand(GetOperandCommandsFromString(numStr, rat)); m_lastOpStartIndex = IchAddSzToEquationSz(numStr, iCommandEnd); if (fRepetition) @@ -201,7 +160,7 @@ void CHistoryCollector::EnclosePrecInversionBrackets() IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_CLOSEP), -1); } -bool CHistoryCollector::FOpndAddedToHistory() +bool CHistoryCollector::FOpndAddedToHistory() const { return (-1 != m_lastOpStartIndex); } @@ -465,7 +424,7 @@ void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol) } // Update the commands corresponding to the passed string Number -std::shared_ptr> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) +std::shared_ptr> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) const { std::shared_ptr> commands = std::make_shared>(); // Check for negate @@ -505,3 +464,58 @@ std::shared_ptr> CHistoryCollector::GetOperandCommandsFromStrin } return commands; } + +std::shared_ptr CHistoryCollector::GetOperandCommandsFromString(std::wstring_view numStr, Rational const& rat) const +{ + std::shared_ptr> commands = std::make_shared>(); + // Check for negate + bool fNegative = (numStr[0] == L'-'); + bool fSciFmt = false; + bool fDecimal = false; + + for (size_t i = (fNegative ? 1 : 0); i < numStr.length(); i++) + { + if (numStr[i] == m_decimalSymbol) + { + commands->push_back(IDC_PNT); + if (!fSciFmt) + { + fDecimal = true; + } + } + else if (numStr[i] == L'e') + { + commands->push_back(IDC_EXP); + fSciFmt = true; + } + else if (numStr[i] == L'-') + { + commands->push_back(IDC_SIGN); + } + else if (numStr[i] == L'+') + { + // Ignore. + } + // Number + else + { + int num = static_cast(numStr[i]) - ASCII_0; + num += IDC_0; + commands->push_back(num); + } + } + + auto operandCommand = std::make_shared(commands, fNegative, fDecimal, fSciFmt); + operandCommand->Initialize(rat); + return operandCommand; +} + +std::vector> CHistoryCollector::GetCommands() const +{ + std::vector> commands; + if (m_spCommands != nullptr) + { + commands = *m_spCommands; + } + return commands; +} diff --git a/src/CalcManager/CEngine/calc.cpp b/src/CalcManager/CEngine/calc.cpp index 713a661c..7ef2acb7 100644 --- a/src/CalcManager/CEngine/calc.cpp +++ b/src/CalcManager/CEngine/calc.cpp @@ -202,3 +202,13 @@ wchar_t CCalcEngine::DecimalSeparator() const { return m_decimalSeparator; } + +std::vector> CCalcEngine::GetHistoryCollectorCommandsSnapshot() const +{ + auto commands = m_HistoryCollector.GetCommands(); + if (!m_HistoryCollector.FOpndAddedToHistory() && m_bRecord) + { + commands.push_back(m_HistoryCollector.GetOperandCommandsFromString(m_numberString, m_currentVal)); + } + return commands; +} diff --git a/src/CalcManager/CalculatorManager.cpp b/src/CalcManager/CalculatorManager.cpp index c32a027d..e2d6a802 100644 --- a/src/CalcManager/CalculatorManager.cpp +++ b/src/CalcManager/CalculatorManager.cpp @@ -597,4 +597,9 @@ namespace CalculationManager { m_inHistoryItemLoadMode = isHistoryItemLoadMode; } + + std::vector> CalculatorManager::GetDisplayCommandsSnapshot() const + { + return m_currentCalculatorEngine->GetHistoryCollectorCommandsSnapshot(); + } } diff --git a/src/CalcManager/CalculatorManager.h b/src/CalcManager/CalculatorManager.h index 5db70b65..035c5a64 100644 --- a/src/CalcManager/CalculatorManager.h +++ b/src/CalcManager/CalculatorManager.h @@ -119,5 +119,6 @@ namespace CalculationManager } CalculationManager::Command GetCurrentDegreeMode(); void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode); + std::vector> GetDisplayCommandsSnapshot() const; }; } diff --git a/src/CalcManager/Header Files/CalcEngine.h b/src/CalcManager/Header Files/CalcEngine.h index f387c020..eaa2956b 100644 --- a/src/CalcManager/Header Files/CalcEngine.h +++ b/src/CalcManager/Header Files/CalcEngine.h @@ -89,6 +89,8 @@ public: void UpdateMaxIntDigits(); wchar_t DecimalSeparator() const; + std::vector> GetHistoryCollectorCommandsSnapshot() const; + // Static methods for the instance static void InitialOneTimeOnlySetup(CalculationManager::IResourceProvider& resourceProvider); // Once per load time to call to initialize all shared global variables diff --git a/src/CalcManager/Header Files/History.h b/src/CalcManager/Header Files/History.h index 9eb0bd71..a437a975 100644 --- a/src/CalcManager/Header Files/History.h +++ b/src/CalcManager/Header Files/History.h @@ -4,10 +4,13 @@ #pragma once #include +#include "ExpressionCommand.h" #include "ICalcDisplay.h" #include "IHistoryDisplay.h" #include "Rational.h" +class COpndCommand; + // maximum depth you can get by precedence. It is just an array's size limit. static constexpr size_t MAXPRECDEPTH = 25; @@ -29,13 +32,15 @@ public: void PushLastOpndStart(int ichOpndStart = -1); void PopLastOpndStart(); void EnclosePrecInversionBrackets(); - bool FOpndAddedToHistory(); + bool FOpndAddedToHistory() const; void CompleteHistoryLine(std::wstring_view numStr); void CompleteEquation(std::wstring_view numStr); void ClearHistoryLine(std::wstring_view errStr); int AddCommand(_In_ const std::shared_ptr& spCommand); void UpdateHistoryExpression(uint32_t radix, int32_t precision); void SetDecimalSymbol(wchar_t decimalSymbol); + std::shared_ptr GetOperandCommandsFromString(std::wstring_view numStr, CalcEngine::Rational const& rat) const; + std::vector> GetCommands() const; private: std::shared_ptr m_pHistoryDisplay; @@ -60,5 +65,5 @@ private: void TruncateEquationSzFromIch(int ich); void SetExpressionDisplay(); void InsertSzInEquationSz(std::wstring_view str, int icommandIndex, int ich); - std::shared_ptr> GetOperandCommandsFromString(std::wstring_view numStr); + std::shared_ptr> GetOperandCommandsFromString(std::wstring_view numStr) const; }; diff --git a/src/CalcViewModel/ApplicationViewModel.cpp b/src/CalcViewModel/ApplicationViewModel.cpp index 3b831645..7a54182d 100644 --- a/src/CalcViewModel/ApplicationViewModel.cpp +++ b/src/CalcViewModel/ApplicationViewModel.cpp @@ -63,6 +63,12 @@ namespace { jsonObject->SetNamedValue(L"ExpressionDisplay", SaveSnapshotToJson(*value.ExpressionDisplay)); } + auto commandsJsonArray = ref new Windows::Data::Json::JsonArray(); + for (const auto& command : value.DisplayCommands) + { + commandsJsonArray->Append(SaveSnapshotToJson(command)); + } + jsonObject->SetNamedValue(L"DisplayCommands", commandsJsonArray); return jsonObject; } @@ -270,6 +276,7 @@ namespace return; } } + standardCalculatorSnapshot.DisplayCommands = RestoreExpressionCommandsFromJsonArray(jsonObject->GetNamedArray(L"DisplayCommands")); value = std::move(standardCalculatorSnapshot); } diff --git a/src/CalcViewModel/StandardCalculatorViewModel.cpp b/src/CalcViewModel/StandardCalculatorViewModel.cpp index 42546906..04735680 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.cpp +++ b/src/CalcViewModel/StandardCalculatorViewModel.cpp @@ -42,6 +42,57 @@ namespace StringReference IsBitFlipCheckedPropertyName(L"IsBitFlipChecked"); StringReference CalcAlwaysOnTop(L"CalcAlwaysOnTop"); StringReference CalcBackToFullView(L"CalcBackToFullView"); + + std::vector GetCommandsFromExpressionCommands(const std::vector>& expressionCommands) + { + vector commands; + for (const auto& command : expressionCommands) + { + CommandType commandType = command->GetCommandType(); + + if (commandType == CommandType::UnaryCommand) + { + shared_ptr spCommand = dynamic_pointer_cast(command); + const shared_ptr>& unaryCommands = spCommand->GetCommands(); + + for (int nUCode : *unaryCommands) + { + commands.push_back(nUCode); + } + } + + if (commandType == CommandType::BinaryCommand) + { + shared_ptr spCommand = dynamic_pointer_cast(command); + commands.push_back(spCommand->GetCommand()); + } + + if (commandType == CommandType::Parentheses) + { + shared_ptr spCommand = dynamic_pointer_cast(command); + commands.push_back(spCommand->GetCommand()); + } + + if (commandType == CommandType::OperandCommand) + { + shared_ptr spCommand = dynamic_pointer_cast(command); + const shared_ptr>& opndCommands = spCommand->GetCommands(); + bool fNeedIDCSign = spCommand->IsNegative(); + + for (int nOCode : *opndCommands) + { + commands.push_back(nOCode); + + if (fNeedIDCSign && nOCode != IDC_0) + { + commands.push_back(static_cast(CalculationManager::Command::CommandSIGN)); + fNeedIDCSign = false; + } + } + } + } + return commands; + } } namespace CalculatorResourceKeys @@ -1388,55 +1439,8 @@ void StandardCalculatorViewModel::Recalculate(bool fromHistory) { // Recalculate Command currentDegreeMode = m_standardCalculatorManager.GetCurrentDegreeMode(); - shared_ptr>> savedCommands = make_shared>>(); - vector currentCommands; - - for (const auto& command : *m_commands) - { - savedCommands->push_back(command); - CommandType commandType = command->GetCommandType(); - - if (commandType == CommandType::UnaryCommand) - { - shared_ptr spCommand = dynamic_pointer_cast(command); - const shared_ptr>& unaryCommands = spCommand->GetCommands(); - - for (int nUCode : *unaryCommands) - { - currentCommands.push_back(nUCode); - } - } - - if (commandType == CommandType::BinaryCommand) - { - shared_ptr spCommand = dynamic_pointer_cast(command); - currentCommands.push_back(spCommand->GetCommand()); - } - - if (commandType == CommandType::Parentheses) - { - shared_ptr spCommand = dynamic_pointer_cast(command); - currentCommands.push_back(spCommand->GetCommand()); - } - - if (commandType == CommandType::OperandCommand) - { - shared_ptr spCommand = dynamic_pointer_cast(command); - const shared_ptr>& opndCommands = spCommand->GetCommands(); - bool fNeedIDCSign = spCommand->IsNegative(); - - for (int nOCode : *opndCommands) - { - currentCommands.push_back(nOCode); - - if (fNeedIDCSign && nOCode != IDC_0) - { - currentCommands.push_back(static_cast(CalculationManager::Command::CommandSIGN)); - fNeedIDCSign = false; - } - } - } - } + shared_ptr>> savedCommands = std::make_shared>>(*m_commands); + vector currentCommands = GetCommandsFromExpressionCommands(*m_commands); shared_ptr>> savedTokens = make_shared>>(); @@ -1796,6 +1800,7 @@ StandardCalculatorSnapshot StandardCalculatorViewModel::GetStandardCalculatorSna { snapshot.ExpressionDisplay = { *m_tokens, *m_commands }; } + snapshot.DisplayCommands = m_standardCalculatorManager.GetDisplayCommandsSnapshot(); return snapshot; } @@ -1805,11 +1810,26 @@ void StandardCalculatorViewModel::SetStandardCalculatorSnapshot(const StandardCa { m_standardCalculatorManager.SetHistoryItems(snapshot.CalcManager.HistoryItems.value()); } - SetPrimaryDisplay(snapshot.PrimaryDisplay.DisplayValue, snapshot.PrimaryDisplay.IsError); + + std::vector commands; + if (snapshot.ExpressionDisplay.has_value() && snapshot.ExpressionDisplay->Tokens.back().first == L"=") + { + commands = GetCommandsFromExpressionCommands(snapshot.ExpressionDisplay->Commands); + } + if (commands.empty() && !snapshot.DisplayCommands.empty()) + { + commands = GetCommandsFromExpressionCommands(snapshot.DisplayCommands); + } + for (const auto& command : commands) + { + m_standardCalculatorManager.SendCommand(static_cast(command)); + } + if (snapshot.ExpressionDisplay.has_value()) { SetExpressionDisplay( std::make_shared>>(snapshot.ExpressionDisplay->Tokens), std::make_shared>>(snapshot.ExpressionDisplay->Commands)); } + SetPrimaryDisplay(snapshot.PrimaryDisplay.DisplayValue, snapshot.PrimaryDisplay.IsError); } diff --git a/src/CalcViewModel/StandardCalculatorViewModel.h b/src/CalcViewModel/StandardCalculatorViewModel.h index dd5c102c..160a7fe8 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.h +++ b/src/CalcViewModel/StandardCalculatorViewModel.h @@ -55,6 +55,7 @@ namespace CalculatorApp CalculatorManagerSnapshot CalcManager; PrimaryDisplaySnapshot PrimaryDisplay; std::optional ExpressionDisplay; + std::vector> DisplayCommands; }; [Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged