Skip to content
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

Merged
merged 12 commits into from
Feb 24, 2022

Conversation

jperedadnr
Copy link
Collaborator

Fixes #50
For now, only size is exposed. Later on we could even expose the list of commands to undo/redo.

@abhinayagarwal
Copy link
Collaborator

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?

@jperedadnr
Copy link
Collaborator Author

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.

@jperedadnr
Copy link
Collaborator Author

@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 ...

Copy link
Collaborator

@abhinayagarwal abhinayagarwal left a 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.

eugener
eugener previously approved these changes Feb 22, 2022
@@ -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());
Copy link
Collaborator

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.

Copy link
Collaborator Author

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?

Copy link
Collaborator

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.

Copy link
Collaborator Author

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

Copy link
Collaborator Author

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.

Copy link
Collaborator

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this conversation to either #59 or #60

@jperedadnr
Copy link
Collaborator Author

@abhinayagarwal I've added a test

Comment on lines 94 to 97
private void update() {
emptyUndo.set(commander.isUndoStackEmpty());
emptyRedo.set(commander.isRedoStackEmpty());
}
Copy link
Collaborator

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.

Copy link
Collaborator Author

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

Copy link
Collaborator

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() {
Copy link
Collaborator

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:

  1. Execute TestCommand and assert the size of both the stacks using the new methods.
  2. Execute TestCommand followed by a undo. Assert the size of stacks.
  3. Execute TestCommand. Fire undo followed by a redo. Assert the size of stacks.

Copy link
Collaborator Author

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());
   }

Copy link
Collaborator

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.

@DisplayName("runnable called when redo is executed")
public void runnableIsCalledWhenRedoIsExecuted() {
StringBuilder text = new StringBuilder("Text");
AtomicBoolean aBoolean = new AtomicBoolean();
Copy link
Collaborator

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.

Copy link
Collaborator Author

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed

abhinayagarwal
abhinayagarwal previously approved these changes Feb 24, 2022
Copy link
Collaborator

@abhinayagarwal abhinayagarwal left a 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());
Copy link
Collaborator

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")
Copy link
Collaborator

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

@jperedadnr jperedadnr merged commit 0989e1a into gluonhq:master Feb 24, 2022
@jperedadnr jperedadnr deleted the 50-stack branch February 24, 2022 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

API to find out if undo/redo are available
3 participants