diff --git a/apps/graph/base.de.i18n b/apps/graph/base.de.i18n index e2c98ce08..fd22fa05a 100644 --- a/apps/graph/base.de.i18n +++ b/apps/graph/base.de.i18n @@ -20,3 +20,5 @@ NoIntersectionFound = "Kein Schnittpunkt gefunden" DerivativeFunctionColumn = "Spalte der Ableitungsfunktion" HideDerivativeColumn = "Ableitungsfunktion ausblenden" AllowedCharactersAZaz09 = "Erlaubte Zeichen: A-Z, a-z, 0-9, _" +ReservedName = "Nom réservé" +NameCannotStartWithNumber = "Un nom ne peut pas commencer par un chiffre" diff --git a/apps/graph/base.en.i18n b/apps/graph/base.en.i18n index 9c65251df..36f2820dd 100644 --- a/apps/graph/base.en.i18n +++ b/apps/graph/base.en.i18n @@ -20,3 +20,5 @@ NoIntersectionFound = "No intersection found" DerivativeFunctionColumn = "Derivative function column" HideDerivativeColumn = "Hide the derivative function" AllowedCharactersAZaz09 = "Allowed characters: A-Z, a-z, 0-9, _" +ReservedName = "Reserved name" +NameCannotStartWithNumber = "A name cannot start with a number" diff --git a/apps/graph/base.es.i18n b/apps/graph/base.es.i18n index 9d3c4d2ed..6386083e2 100644 --- a/apps/graph/base.es.i18n +++ b/apps/graph/base.es.i18n @@ -20,3 +20,5 @@ NoIntersectionFound = "Ninguna intersección encontrada" DerivativeFunctionColumn = "Columna de la derivada" HideDerivativeColumn = "Ocultar la derivada" AllowedCharactersAZaz09 = "Caracteres permitidos : A-Z, a-z, 0-9, _" +ReservedName = "Nombre reservado" +NameCannotStartWithNumber = "Un nombre no puede empezar con un número" diff --git a/apps/graph/base.fr.i18n b/apps/graph/base.fr.i18n index a5fb461a9..b27e0ee06 100644 --- a/apps/graph/base.fr.i18n +++ b/apps/graph/base.fr.i18n @@ -20,3 +20,5 @@ NoIntersectionFound = "Aucune intersection trouvée" DerivativeFunctionColumn = "Colonne de la fonction derivee" HideDerivativeColumn = "Masquer la fonction derivee" AllowedCharactersAZaz09 = "Caractères autorisés : A-Z, a-z, 0-9, _" +ReservedName = "Nom réservé" +NameCannotStartWithNumber = "Un nom ne peut pas commencer par un chiffre" diff --git a/apps/graph/base.pt.i18n b/apps/graph/base.pt.i18n index 4917fa369..1c702aee8 100644 --- a/apps/graph/base.pt.i18n +++ b/apps/graph/base.pt.i18n @@ -20,3 +20,5 @@ NoIntersectionFound = "Nenhuma interseção encontrada" DerivativeFunctionColumn = "Coluna da funcao derivada" HideDerivativeColumn = "Esconder funcao derivada" AllowedCharactersAZaz09 = "Caracteres permitidos : A-Z, a-z, 0-9, _" +ReservedName = "Nome reservado" +NameCannotStartWithNumber = "Um nome não pode começar com um número" diff --git a/apps/graph/list/storage_list_controller.cpp b/apps/graph/list/storage_list_controller.cpp index ea29df9ec..9cdbbec20 100644 --- a/apps/graph/list/storage_list_controller.cpp +++ b/apps/graph/list/storage_list_controller.cpp @@ -58,7 +58,8 @@ bool StorageListController::textFieldDidFinishEditing(TextField * textField, con GlobalContext::DestroyRecordsBaseNamedWithoutExtension(baseName, GlobalContext::funcExtension /*TODO store elsewhere?*/); // Set the name - Ion::Storage::Record::ErrorStatus error = StorageFunction::BaseNameCompliant(baseName) ? modelStore()->recordAtIndex(m_selectableTableView.selectedRow()).setBaseNameWithExtension(baseName, GlobalContext::funcExtension /*TODO store elsewhere?*/) : Ion::Storage::Record::ErrorStatus::NonCompliantName; + StorageFunction::NameNotCompliantError nameError = StorageFunction::NameNotCompliantError::None; + Ion::Storage::Record::ErrorStatus error = StorageFunction::BaseNameCompliant(baseName, &nameError) ? modelStore()->recordAtIndex(m_selectableTableView.selectedRow()).setBaseNameWithExtension(baseName, GlobalContext::funcExtension /*TODO store elsewhere?*/) : Ion::Storage::Record::ErrorStatus::NonCompliantName; // Handle any error if (error == Ion::Storage::Record::ErrorStatus::None) { @@ -85,7 +86,15 @@ bool StorageListController::textFieldDidFinishEditing(TextField * textField, con } else if (error == Ion::Storage::Record::ErrorStatus::NameTaken) { app()->displayWarning(I18n::Message::NameTaken); } else if (error == Ion::Storage::Record::ErrorStatus::NonCompliantName) { - app()->displayWarning(I18n::Message::AllowedCharactersAZaz09); + assert(nameError != StorageFunction::NameNotCompliantError::None); + if (nameError == StorageFunction::NameNotCompliantError::CharacterNotAllowed) { + app()->displayWarning(I18n::Message::AllowedCharactersAZaz09); + } else if (nameError == StorageFunction::NameNotCompliantError::NameCannotStartWithNumber) { + app()->displayWarning(I18n::Message::NameCannotStartWithNumber); + } else { + assert(nameError == StorageFunction::NameNotCompliantError::ReservedName); + app()->displayWarning(I18n::Message::ReservedName); + } } else { assert(error == Ion::Storage::Record::ErrorStatus::NotEnoughSpaceAvailable); app()->displayWarning(I18n::Message::NameTooLong); @@ -106,6 +115,13 @@ bool StorageListController::textFieldShouldFinishEditing(TextField * textField, return event == Ion::Events::Up || event == Ion::Events::Down || Shared::TextFieldDelegate::textFieldShouldFinishEditing(textField, event); } +bool StorageListController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) { + if (textField->isEditing() && textField->shouldFinishEditing(event)) { + return false; + } + return Shared::TextFieldDelegate::textFieldDidReceiveEvent(textField, event); +} + StorageListParameterController * StorageListController::parameterController() { return &m_parameterController; } diff --git a/apps/graph/list/storage_list_controller.h b/apps/graph/list/storage_list_controller.h index 7ae7ef527..eabe0c52f 100644 --- a/apps/graph/list/storage_list_controller.h +++ b/apps/graph/list/storage_list_controller.h @@ -20,6 +20,7 @@ public: bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; bool textFieldDidAbortEditing(TextField * textField) override; bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; + bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; private: constexpr static int k_maxNumberOfDisplayableRows = 5; Shared::StorageListParameterController * parameterController() override; diff --git a/apps/shared/storage_function.cpp b/apps/shared/storage_function.cpp index 11f8cb0df..a2e4d403c 100644 --- a/apps/shared/storage_function.cpp +++ b/apps/shared/storage_function.cpp @@ -11,11 +11,16 @@ namespace Shared { char StorageFunction::k_parenthesedArgument[]("(x)"); -bool StorageFunction::BaseNameCompliant(const char * baseName) { - if (baseName[0] == 0 || (baseName[0] >= '0' && baseName[0] <= '9')) { - // The name cannot be empty nor start with a number +bool StorageFunction::BaseNameCompliant(const char * baseName, NameNotCompliantError * error) { + assert(baseName[0] != 0); + if (baseName[0] >= '0' && baseName[0] <= '9') { + // The name cannot start with a number + if (error != nullptr) { + *error = NameNotCompliantError::NameCannotStartWithNumber; + } return false; } + const char * currentChar = baseName; // The name should only have allowed characters @@ -23,7 +28,11 @@ bool StorageFunction::BaseNameCompliant(const char * baseName) { if (!((*currentChar >= 'A' && *currentChar <= 'Z') || (*currentChar >= 'a' && *currentChar <= 'z') || (*currentChar >= '0' && *currentChar <= '9') - || *currentChar == '_')) { + || *currentChar == '_')) + { + if (error != nullptr) { + *error = NameNotCompliantError::CharacterNotAllowed; + } return false; } currentChar++; @@ -31,6 +40,9 @@ bool StorageFunction::BaseNameCompliant(const char * baseName) { // The name should not be a reserved name if (Parser::IsReservedName(baseName, strlen(baseName))) { + if (error != nullptr) { + *error = NameNotCompliantError::ReservedName; + } return false; } return true; diff --git a/apps/shared/storage_function.h b/apps/shared/storage_function.h index 858adc1f2..18a3591f6 100644 --- a/apps/shared/storage_function.h +++ b/apps/shared/storage_function.h @@ -8,10 +8,16 @@ namespace Shared { class StorageFunction : public StorageExpressionModel { public: + enum class NameNotCompliantError { + None = 0, + CharacterNotAllowed, + NameCannotStartWithNumber, + ReservedName + }; constexpr static int k_parenthesedArgumentLength = 3; static char k_parenthesedArgument[k_parenthesedArgumentLength+1]; constexpr static int k_maxNameWithArgumentSize = Poincare::SymbolAbstract::k_maxNameSize + k_parenthesedArgumentLength; /* Function name and null-terminating char + "(x)" */; - static bool BaseNameCompliant(const char * baseName); + static bool BaseNameCompliant(const char * baseName, NameNotCompliantError * error = nullptr); // Constructors StorageFunction(Ion::Storage::Record record) : StorageExpressionModel(record){}