fix #97106: crash on undo after save with courtesy keysig #3154
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The crash is actually an assertion failure, removing a keysig from a segment that doesn't contain one. The cause seems to be the layout that is forced at the end of the save (to update $m macro in header/footer), because it happens while not in undo mode. Generated elements get added and removed during layout, and doing this while not in undo mode confuses the undo stack a bit. I can't say I understand exactly what goes wrong in this case, but I am pretty confident this is the problem.
Assuming we want to keep the layout operation at the end of the save, the solution seems to be to do so in the context of startCmd()/endCmd(). This puts an extra macro on the stack, so I remove it afterwards. Because endCmd() does an update() anyhow, I removed that, but I call setLayoutAll() first to make sure all linked scores get updated. Finally, I moved this bit of code to before the undo()->setClean() just to be sure we are in a clean state after the save.
This fixes the crash and doesn't introduce any null undo steps or other artifacts that I can see. It also fixes another small bug in the original code, where $m macros in headers/footers would only get updated on save if the score has parts. That's because there was no setLayoutAll() call before the update(), and unless there were parts, _updateAll would generally not be set at that point.