Closed marker5a closed 3 years ago
I'm not sure how feasible it is to use, but QT5 does have an undo framework that might be worth looking at: http://doc.qt.io/qt-5/qundo.html
I like that idea of not having to build a new datatype... would be much nicer to use the built in framework for the heavy lifting. I need to dig into it further to understand the scope of what it can do, but it sounds promising!
In any case, I'm still going through the code to find a common way to handle different transactions. For instance, removing an item from the Fermentables table is a different type of operation than changing the name of a recipe. One thought I have is to fill up the stack (or QUndo) with callback functions to undo the task. Along with this would be a set of argument for the callback to perform it's function.
For instance, deleting a row in the fermentables table would push to the stack a callback for adding a fermentable with the arguments that would be needed to complete that transaction identically. Same would go for if someone renamed a recipe... you would just push a callback pointer to changing the recipe name and it's argument would be the old recipe name.
FYI I am working on an implementation of this, using the QT5 undo framework as suggested above. I have simple cases working (edit a value). Adding/removing fermentables etc will be a bit more fun, but should be doable.
Making progress on this. I have undo/redo pretty much working for adding/removing ingredients, which turned out to require touching a lot of different places in the codebase. Need to check a few edge cases and tidy up a couple of things but hope to have a pull request in the not too distant future.
Just out of curiosity, have you tested this against postgres as well? Since I am the only person who likely uses it, "No" is a perfectly acceptable answer.
I haven't explicitly tested it with postgres, but I would be very hopeful that it would work fine. Rather than poke the database directly, I've tried to do things via the object model - eg undoable actions pass through MainWindow (which has the Undo/Redo controls), then MainWindow asks, say, the Recipe to add or remove a specific Fermentable, and then let Recipe make the necessary requests to the Database class.
OK, I now have a pull request for the implementation of this: https://github.com/Brewtarget/brewtarget/pull/499 This is extensive (but not, I hope, any more complicated than it needs to be!) because (a) we have to touch every place in the code that makes a change the user would want to be able to undo/redo and (b) being able to undo/redo add and remove in a clean way required some light refactoring of the current functions - partly because when we say 'add' what's often really happening under the covers is 'copy and then add'.
@mikfire Would greatly appreciate feedback and code review as and when you have time.
As a user, when formulating recipes, it can be easy to to accidentally make a change to a recipe unintentionally. At the moment, there is no good way, that I can see, to undo or redo the change. When I make a mistake to a recipe, I generally use the clunkier approach of just restarting the program and risk losing unsaved changes to the recipe.
It seems that it might be nice to track changes made in a stack (or stacks for redo and undo) datatype and store "transactions" in these LIFO buffers. This is a potentially larger task as it would require user actions to be distilled into a transactional datatype to be placed in the LIFO.
Any ideas or suggestions? I'd like to work on this task, but would like to get some feedback from users as to the feasibility and/or how useful this would even be to other users.