-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add redo/undoStackSize properties to track stack sizes #53
Conversation
Is there an advantage of exposing the entire size of the queues rather than exposing just boolean properties which return the state of the queues? |
Not really. For now all that matters indeed is if the stack is empty or not, and that can be a boolean. Later on we can think of exposing a list of strings with the commands to undo/redo. |
@abhinayagarwal I've updated the PR with boolean instead of integer. I've also realized that the stackEmpty properties are needed on the modelView only, which has another commandManager, and not in the PieceTable. This misunderstanding is what caused #52 ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the PR updates CommandManager
, a few tests with new functionality on CmdManagerTests
would be nice.
src/main/java/com/gluonhq/richtext/viewmodel/RichTextAreaViewModel.java
Outdated
Show resolved
Hide resolved
@@ -91,14 +91,19 @@ public Double fromString(String s) { | |||
CheckBox editableProp = new CheckBox("Editable"); | |||
editableProp.selectedProperty().bindBidirectional(editor.editableProperty()); | |||
|
|||
Button undoButton = actionButton(LineAwesomeSolid.UNDO, editor.getActionFactory().undo()); | |||
undoButton.disableProperty().bind(editor.undoStackEmptyProperty()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this PR... but we should not expose this here. We should have enabled
property on the Action
which we can then bind to control in the demo. That property would be internally controlled by the state of the control. For example, hypothetically, if no selection, text decoration actions will be disabled, disabling related controls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
So far the interface Action
requires the viewModel as an argument for the apply
method, but for the disabled/enabled property it doesn't seem the right approach? Would an abstract class be more practical, given that we could create each action with the viewModel as a constructor argument, that can be later on used by all the action methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very much possible... I was basically trying to create actions without state, i.e. they learn about viewModel only at execution time. Action properties would require state, so passing viewModel would probably be the only choice.
The downside of this is that all actions would have to be recreated, if viewModel changes.
We could probably avoid that if, instead of passing model into it, we bind them somehow. I worry about that simply because, in my view, the model(text) will have to change, since control has to have that functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll file an issue for this so it can be done in a follow-up PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eugener if the viewModel is going to change, then we should have full support for that in the skin.
This also leads to the fact that the control should be able to change the model/original text, and create a new viewModel out of this.
For instance, after a "File->New" (or alike), the model should have an empty original text, or after "File->Open", the model should have the original text and decorations.
I'll file another issue for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure view model has to change if we redesign it a little. Currently it holds the text buffer. But if we can have text buffer as a property, then we can reassign it without changing the viewModel itself. ViewModel will react on text buffer changing, triggering changes in the view.
So... changing a "document" on control will in essence change the text buffer bound to viewModel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abhinayagarwal I've added a test |
private void update() { | ||
emptyUndo.set(commander.isUndoStackEmpty()); | ||
emptyRedo.set(commander.isRedoStackEmpty()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need for this method. All we need to do here is to execute TestCommand
, undo
and redo
. Assert the state of the stacks using the new public methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It actually tests the new constructor with a Runnable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then it needs a separate test :)
|
||
@Test | ||
@DisplayName("Passes multiple redo rules") | ||
public void multipleRedoRules() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This tests needs to be broken into at least 3 different tests:
- Execute
TestCommand
and assert the size of both the stacks using the new methods. - Execute
TestCommand
followed by aundo
. Assert the size of stacks. - Execute
TestCommand
. Fireundo
followed by aredo
. Assert the size of stacks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think I could simply add the asserts to the three existing tests:
public void executionRules() {
...
Assertions.assertEquals( 1, commander.undoStack.size());
Assertions.assertEquals( 0, commander.redoStack.size());
+ Assertions.assertTrue(commander.isUndoStackEmpty());
+ Assertions.assertTrue(commander.isRedoStackEmpty());
Assertions.assertEquals( "Text-redo", commander.context.toString());
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, that's exactly what I was suggesting. Instead of asserting against emptyUndo
and emptyRedo
fields, we can directly assert the new methods which returns the state of the underlying stacks.
5db503f
to
d36b59b
Compare
@DisplayName("runnable called when redo is executed") | ||
public void runnableIsCalledWhenRedoIsExecuted() { | ||
StringBuilder text = new StringBuilder("Text"); | ||
AtomicBoolean aBoolean = new AtomicBoolean(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The AtomicBoolean
can be a AtomicInteger
and we could increment it in every call to the runnable, therefore being able to test the value as 1, 2 and 3 in runnableIsCalledWhenCommandIsExecuted
, runnableIsCalledWhenUndoIsExecuted
and runnableIsCalledWhenRedoIsExecuted
respectively. I leave it for you to decide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, you would be testing that runnable is called on every command operation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall the PR LGTM
commander.execute(new TestCommand()); | ||
Assertions.assertEquals(1, aInteger.get()); | ||
commander.undo(); | ||
Assertions.assertEquals(2, aInteger.get()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpicking here, but Assertion of value 1 and 2 needs to be a part of the two previous tests. We should perform command.execute
, undo
and redo
. Finally, assert the value of aInteger
to 3
} | ||
|
||
@Test | ||
@DisplayName("runnable called when commands are executed") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/command are/redo is
Fixes #50
For now, only size is exposed. Later on we could even expose the list of commands to undo/redo.