[apps/code] Fix MenuController::willExitResponderChain

It called textFieldDidAbortEditing, which called setFirstResponder,
which could clash with another setFirstResponder higher in the call
tree.

Scenario: build with an update popup, create a new script, edit its name
with an unvalid name and press the Power key while editing. When
powering on the device again, the first responder is not the popup even
though it is displayed, and pressing OK does not dismiss it.
This commit is contained in:
Léa Saviot
2019-01-14 14:00:55 +01:00
committed by LeaNumworks
parent c7a585cae8
commit 0a5290d5a6
2 changed files with 40 additions and 30 deletions

View File

@@ -49,7 +49,7 @@ void MenuController::willExitResponderChain(Responder * nextFirstResponder) {
TextField * tf = static_cast<ScriptNameCell *>(m_selectableTableView.selectedCell())->textField();
if (tf->isEditing()) {
tf->setEditing(false, false);
textFieldDidAbortEditing(tf);
privateTextFieldDidAbortEditing(tf, false);
}
}
}
@@ -346,34 +346,6 @@ bool MenuController::textFieldDidFinishEditing(TextField * textField, const char
return false;
}
bool MenuController::textFieldDidAbortEditing(TextField * textField) {
Script script = m_scriptStore->scriptAtIndex(m_selectableTableView.selectedRow());
const char * scriptName = script.fullName();
if (strlen(scriptName) <= 1 + strlen(ScriptStore::k_scriptExtension)) {
// The previous text was an empty name. Use a numbered default script name.
char numberedDefaultName[Script::k_defaultScriptNameMaxSize];
bool foundDefaultName = Script::DefaultName(numberedDefaultName, Script::k_defaultScriptNameMaxSize);
if (!foundDefaultName) {
// If we did not find a default name, delete the script
deleteScript(script);
return true;
}
Script::ErrorStatus error = script.setBaseNameWithExtension(numberedDefaultName, ScriptStore::k_scriptExtension);
scriptName = m_scriptStore->scriptAtIndex(m_selectableTableView.selectedRow()).fullName();
/* Because we use the numbered default name, the name should not be
* already taken. Plus, the script could be added only if the storage has
* enough available space to add a script named 'script99.py' */
(void) error; // Silence the "variable unused" warning if assertions are not enabled
assert(error == Script::ErrorStatus::None);
updateAddScriptRowDisplay();
}
textField->setText(scriptName);
m_selectableTableView.selectCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
app()->setFirstResponder(&m_selectableTableView);
static_cast<AppsContainer *>(const_cast<Container *>(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default);
return true;
}
bool MenuController::textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textSizeDidChange) {
int scriptExtensionLength = 1 + strlen(ScriptStore::k_scriptExtension);
if (textField->isEditing() && textField->cursorLocation() > textField->draftTextLength() - scriptExtensionLength) {
@@ -411,4 +383,39 @@ void MenuController::updateAddScriptRowDisplay() {
m_selectableTableView.reloadData();
}
bool MenuController::privateTextFieldDidAbortEditing(TextField * textField, bool menuControllerStaysInResponderChain) {
/* If menuControllerStaysInResponderChain is false, we do not want to use
* methods that might call setFirstResponder, because we might be in the
* middle of another setFirstResponder call. */
Script script = m_scriptStore->scriptAtIndex(m_selectableTableView.selectedRow());
const char * scriptName = script.fullName();
if (strlen(scriptName) <= 1 + strlen(ScriptStore::k_scriptExtension)) {
// The previous text was an empty name. Use a numbered default script name.
char numberedDefaultName[Script::k_defaultScriptNameMaxSize];
bool foundDefaultName = Script::DefaultName(numberedDefaultName, Script::k_defaultScriptNameMaxSize);
if (!foundDefaultName) {
// If we did not find a default name, delete the script
deleteScript(script);
return true;
}
Script::ErrorStatus error = script.setBaseNameWithExtension(numberedDefaultName, ScriptStore::k_scriptExtension);
scriptName = m_scriptStore->scriptAtIndex(m_selectableTableView.selectedRow()).fullName();
/* Because we use the numbered default name, the name should not be
* already taken. Plus, the script could be added only if the storage has
* enough available space to add a script named 'script99.py' */
(void) error; // Silence the "variable unused" warning if assertions are not enabled
assert(error == Script::ErrorStatus::None);
if (menuControllerStaysInResponderChain) {
updateAddScriptRowDisplay();
}
}
textField->setText(scriptName);
if (menuControllerStaysInResponderChain) {
m_selectableTableView.selectCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
app()->setFirstResponder(&m_selectableTableView);
}
static_cast<AppsContainer *>(const_cast<Container *>(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default);
return true;
}
}