mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-19 21:03:11 -07:00
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
This commit is contained in:
parent
32597416d0
commit
089f7deb08
9 changed files with 161 additions and 96 deletions
|
@ -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<std::vector<int>> commands = std::make_shared<vector<int>>();
|
||||
// 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<int>(numStr[i]) - ASCII_0;
|
||||
num += IDC_0;
|
||||
commands->push_back(num);
|
||||
}
|
||||
}
|
||||
|
||||
auto operandCommand = std::make_shared<COpndCommand>(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<std::vector<int>> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr)
|
||||
std::shared_ptr<std::vector<int>> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) const
|
||||
{
|
||||
std::shared_ptr<std::vector<int>> commands = std::make_shared<std::vector<int>>();
|
||||
// Check for negate
|
||||
|
@ -505,3 +464,58 @@ std::shared_ptr<std::vector<int>> CHistoryCollector::GetOperandCommandsFromStrin
|
|||
}
|
||||
return commands;
|
||||
}
|
||||
|
||||
std::shared_ptr<COpndCommand> CHistoryCollector::GetOperandCommandsFromString(std::wstring_view numStr, Rational const& rat) const
|
||||
{
|
||||
std::shared_ptr<std::vector<int>> commands = std::make_shared<vector<int>>();
|
||||
// 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<int>(numStr[i]) - ASCII_0;
|
||||
num += IDC_0;
|
||||
commands->push_back(num);
|
||||
}
|
||||
}
|
||||
|
||||
auto operandCommand = std::make_shared<COpndCommand>(commands, fNegative, fDecimal, fSciFmt);
|
||||
operandCommand->Initialize(rat);
|
||||
return operandCommand;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<IExpressionCommand>> CHistoryCollector::GetCommands() const
|
||||
{
|
||||
std::vector<std::shared_ptr<IExpressionCommand>> commands;
|
||||
if (m_spCommands != nullptr)
|
||||
{
|
||||
commands = *m_spCommands;
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
|
|
|
@ -202,3 +202,13 @@ wchar_t CCalcEngine::DecimalSeparator() const
|
|||
{
|
||||
return m_decimalSeparator;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<IExpressionCommand>> 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;
|
||||
}
|
||||
|
|
|
@ -597,4 +597,9 @@ namespace CalculationManager
|
|||
{
|
||||
m_inHistoryItemLoadMode = isHistoryItemLoadMode;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<IExpressionCommand>> CalculatorManager::GetDisplayCommandsSnapshot() const
|
||||
{
|
||||
return m_currentCalculatorEngine->GetHistoryCollectorCommandsSnapshot();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,5 +119,6 @@ namespace CalculationManager
|
|||
}
|
||||
CalculationManager::Command GetCurrentDegreeMode();
|
||||
void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode);
|
||||
std::vector<std::shared_ptr<IExpressionCommand>> GetDisplayCommandsSnapshot() const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -89,6 +89,8 @@ public:
|
|||
void UpdateMaxIntDigits();
|
||||
wchar_t DecimalSeparator() const;
|
||||
|
||||
std::vector<std::shared_ptr<IExpressionCommand>> 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
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#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<IExpressionCommand>& spCommand);
|
||||
void UpdateHistoryExpression(uint32_t radix, int32_t precision);
|
||||
void SetDecimalSymbol(wchar_t decimalSymbol);
|
||||
std::shared_ptr<COpndCommand> GetOperandCommandsFromString(std::wstring_view numStr, CalcEngine::Rational const& rat) const;
|
||||
std::vector<std::shared_ptr<IExpressionCommand>> GetCommands() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<IHistoryDisplay> 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<std::vector<int>> GetOperandCommandsFromString(std::wstring_view numStr);
|
||||
std::shared_ptr<std::vector<int>> GetOperandCommandsFromString(std::wstring_view numStr) const;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,57 @@ namespace
|
|||
StringReference IsBitFlipCheckedPropertyName(L"IsBitFlipChecked");
|
||||
StringReference CalcAlwaysOnTop(L"CalcAlwaysOnTop");
|
||||
StringReference CalcBackToFullView(L"CalcBackToFullView");
|
||||
|
||||
std::vector<int> GetCommandsFromExpressionCommands(const std::vector<std::shared_ptr<IExpressionCommand>>& expressionCommands)
|
||||
{
|
||||
vector<int> commands;
|
||||
for (const auto& command : expressionCommands)
|
||||
{
|
||||
CommandType commandType = command->GetCommandType();
|
||||
|
||||
if (commandType == CommandType::UnaryCommand)
|
||||
{
|
||||
shared_ptr<IUnaryCommand> spCommand = dynamic_pointer_cast<IUnaryCommand>(command);
|
||||
const shared_ptr<vector<int>>& unaryCommands = spCommand->GetCommands();
|
||||
|
||||
for (int nUCode : *unaryCommands)
|
||||
{
|
||||
commands.push_back(nUCode);
|
||||
}
|
||||
}
|
||||
|
||||
if (commandType == CommandType::BinaryCommand)
|
||||
{
|
||||
shared_ptr<IBinaryCommand> spCommand = dynamic_pointer_cast<IBinaryCommand>(command);
|
||||
commands.push_back(spCommand->GetCommand());
|
||||
}
|
||||
|
||||
if (commandType == CommandType::Parentheses)
|
||||
{
|
||||
shared_ptr<IParenthesisCommand> spCommand = dynamic_pointer_cast<IParenthesisCommand>(command);
|
||||
commands.push_back(spCommand->GetCommand());
|
||||
}
|
||||
|
||||
if (commandType == CommandType::OperandCommand)
|
||||
{
|
||||
shared_ptr<IOpndCommand> spCommand = dynamic_pointer_cast<IOpndCommand>(command);
|
||||
const shared_ptr<vector<int>>& 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<int>(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<vector<shared_ptr<IExpressionCommand>>> savedCommands = make_shared<vector<shared_ptr<IExpressionCommand>>>();
|
||||
vector<int> currentCommands;
|
||||
|
||||
for (const auto& command : *m_commands)
|
||||
{
|
||||
savedCommands->push_back(command);
|
||||
CommandType commandType = command->GetCommandType();
|
||||
|
||||
if (commandType == CommandType::UnaryCommand)
|
||||
{
|
||||
shared_ptr<IUnaryCommand> spCommand = dynamic_pointer_cast<IUnaryCommand>(command);
|
||||
const shared_ptr<vector<int>>& unaryCommands = spCommand->GetCommands();
|
||||
|
||||
for (int nUCode : *unaryCommands)
|
||||
{
|
||||
currentCommands.push_back(nUCode);
|
||||
}
|
||||
}
|
||||
|
||||
if (commandType == CommandType::BinaryCommand)
|
||||
{
|
||||
shared_ptr<IBinaryCommand> spCommand = dynamic_pointer_cast<IBinaryCommand>(command);
|
||||
currentCommands.push_back(spCommand->GetCommand());
|
||||
}
|
||||
|
||||
if (commandType == CommandType::Parentheses)
|
||||
{
|
||||
shared_ptr<IParenthesisCommand> spCommand = dynamic_pointer_cast<IParenthesisCommand>(command);
|
||||
currentCommands.push_back(spCommand->GetCommand());
|
||||
}
|
||||
|
||||
if (commandType == CommandType::OperandCommand)
|
||||
{
|
||||
shared_ptr<IOpndCommand> spCommand = dynamic_pointer_cast<IOpndCommand>(command);
|
||||
const shared_ptr<vector<int>>& 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<int>(CalculationManager::Command::CommandSIGN));
|
||||
fNeedIDCSign = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shared_ptr<vector<shared_ptr<IExpressionCommand>>> savedCommands = std::make_shared<std::vector<shared_ptr<IExpressionCommand>>>(*m_commands);
|
||||
vector<int> currentCommands = GetCommandsFromExpressionCommands(*m_commands);
|
||||
|
||||
shared_ptr<vector<pair<wstring, int>>> savedTokens = make_shared<vector<pair<wstring, int>>>();
|
||||
|
||||
|
@ -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<int> 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>(command));
|
||||
}
|
||||
|
||||
if (snapshot.ExpressionDisplay.has_value())
|
||||
{
|
||||
SetExpressionDisplay(
|
||||
std::make_shared<std::vector<std::pair<std::wstring, int>>>(snapshot.ExpressionDisplay->Tokens),
|
||||
std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>(snapshot.ExpressionDisplay->Commands));
|
||||
}
|
||||
SetPrimaryDisplay(snapshot.PrimaryDisplay.DisplayValue, snapshot.PrimaryDisplay.IsError);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ namespace CalculatorApp
|
|||
CalculatorManagerSnapshot CalcManager;
|
||||
PrimaryDisplaySnapshot PrimaryDisplay;
|
||||
std::optional<ExpressionDisplaySnapshot> ExpressionDisplay;
|
||||
std::vector<std::shared_ptr<IExpressionCommand>> DisplayCommands;
|
||||
};
|
||||
|
||||
[Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue