Skip to content

Allow multiple portions of an area's document to be updated in one call#695

Merged
JordanMartinez merged 6 commits intoFXMisc:masterfrom
JordanMartinez:multiTextChange
Mar 6, 2018
Merged

Allow multiple portions of an area's document to be updated in one call#695
JordanMartinez merged 6 commits intoFXMisc:masterfrom
JordanMartinez:multiTextChange

Conversation

@JordanMartinez
Copy link
Copy Markdown
Contributor

@JordanMartinez JordanMartinez commented Feb 28, 2018

Resolves #574.

@JordanMartinez
Copy link
Copy Markdown
Contributor Author

The issue in my custom UndoManager is that an undo change must be applied differently than a redo change. Whereas an undo might use a relative replace from MultiChangeBuilder, the redo must use an absolute replace. Thus, UndoFX needs to provide more flexibility in its underlying UndoManager.

@JFormDesigner
Copy link
Copy Markdown
Contributor

@JordanMartinez many thx for implementing this 👍

I tried it in Markdown Writer FX and ran into an issue in undo.

Here is a test case (for MultiChangeTest):

    @Test
    public void committing_relative_change_backtofront_works() {
        interact(() -> {
            String text = area.getText();
            String hello = "hello";
            String world = "world";
            area.createMultiChange(2)
                    .insertText(6, world)
                    .insertText(0, hello)
                    .commit();

            assertEquals(hello + text + world, area.getText());

            area.undo();
            assertEquals(text, area.getText());
        });
    }

Test output:

java.lang.IllegalArgumentException: Unexpected change received.
Expected:
[RichTextChange{
	position: 0
	removed: Par[; StyledSegment(segment=hello style=)]
	inserted: Par[; StyledSegment(segment= style=)]
}, RichTextChange{
	position: 6
	removed: Par[; StyledSegment(segment=world style=)]
	inserted: Par[; StyledSegment(segment= style=)]
}]
Received:
[RichTextChange{
	position: 0
	removed: Par[; StyledSegment(segment=hello style=)]
	inserted: Par[; StyledSegment(segment= style=)]
}, RichTextChange{
	position: 1
	removed: Par[; StyledSegment(segment=text) style=)]
	inserted: Par[; StyledSegment(segment= style=)]
}]
	org.fxmisc.undo.impl.UndoManagerImpl.changeObserved(UndoManagerImpl.java:255)
	org.reactfx.util.QueuingStreamNotifications.lambda$head$0(NotificationAccumulator.java:217)
	org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:68)
	org.reactfx.SuspendableBase.resume(SuspendableBase.java:64)
	org.reactfx.CloseableOnceGuard.close(Guard.java:49)
	org.reactfx.MultiGuard.close(Guard.java:83)
	org.reactfx.Suspendable$1.resumeSource(Suspendable.java:118)
	org.reactfx.Suspendable$1.suspendSource(Suspendable.java:104)
	org.reactfx.util.NonAccumulativeStreamNotifications.lambda$head$0(NotificationAccumulator.java:134)
	org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:68)
	org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:57)
	org.reactfx.ProperEventStream.emit(ProperEventStream.java:18)
	org.reactfx.EventStreams$3.lambda$observeInputs$0(EventStreams.java:105)
	org.reactfx.value.ChangeListenerWrapper.accept(Val.java:786)
	org.reactfx.util.AbstractReducingStreamNotifications.lambda$head$0(NotificationAccumulator.java:248)
	org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:68)
	org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:57)
	org.reactfx.value.ValBase.invalidate(ValBase.java:32)
	org.reactfx.SuspendableBoolean.release(SuspendableBoolean.java:24)
	org.reactfx.CloseableOnceGuard.close(Guard.java:49)
	org.reactfx.Suspendable.suspendWhile(Suspendable.java:49)
	org.fxmisc.richtext.model.GenericEditableStyledDocumentBase.updateMulti(GenericEditableStyledDocumentBase.java:215)
	org.reactfx.util.Tuple3.exec(Tuple3.java:43)
	org.fxmisc.richtext.model.GenericEditableStyledDocumentBase.replaceMulti(GenericEditableStyledDocumentBase.java:137)
	org.fxmisc.richtext.model.SimpleEditableStyledDocument.replaceMulti(SimpleEditableStyledDocument.java:1)
	org.fxmisc.richtext.GenericStyledArea.replaceMulti(GenericStyledArea.java:1202)
	org.fxmisc.richtext.MultiChangeBuilder.commit(MultiChangeBuilder.java:364)
	org.fxmisc.richtext.util.UndoUtils.lambda$10(UndoUtils.java:196)
	org.fxmisc.undo.impl.UndoManagerImpl.lambda$performChange$3(UndoManagerImpl.java:240)
	org.reactfx.Suspendable.suspendWhile(Suspendable.java:49)
	org.fxmisc.undo.impl.UndoManagerImpl.performChange(UndoManagerImpl.java:240)
	org.fxmisc.undo.impl.UndoManagerImpl.undo(UndoManagerImpl.java:152)
	org.fxmisc.richtext.UndoActions.undo(UndoActions.java:22)
	org.fxmisc.richtext.api.MultiChangeTest.lambda$2(MultiChangeTest.java:70)
	java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

@JordanMartinez
Copy link
Copy Markdown
Contributor Author

@JFormDesigner Thanks for reporting that. I'm looking into it now. I'd guess that it has to do with using a relative replace in MultiChangeBuilder when undoing a change rather than an absolute replace.

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.

2 participants