Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
import org.fxmisc.richtext.RichTextFXTestBase;
import org.fxmisc.richtext.StyledTextArea;
import org.fxmisc.richtext.model.SimpleEditableStyledDocument;
import org.fxmisc.richtext.model.RichTextChange;
import org.fxmisc.richtext.model.TextChange;
import org.fxmisc.richtext.util.UndoUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.reactfx.SuspendableYes;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand Down Expand Up @@ -174,6 +176,20 @@ public void testForBug904() {
interact( area::undo ); // should not throw Unexpected change received exception
}

@Test
public void suspendable_UndoManager_skips_style_check() {

SuspendableYes suspendUndo = new SuspendableYes();
area.setUndoManager( UndoUtils.richTextSuspendableUndoManager( area, suspendUndo ) );
write( "some text\n" );
interact( () -> suspendUndo.suspendWhile( () -> area.setStyle( 5, 9, "-fx-font-weight: bold;" ) ) );
write( "new line" );
interact( area::undo ); // should not throw Unexpected change received exception

area.setUndoManager( UndoUtils.defaultUndoManager( area ) );
RichTextChange.skipStyleComparison( false );
}

}

public class UsingStyledTextArea extends RichTextFXTestBase {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,31 @@ public final PlainTextChange toPlainTextChange() {
public final boolean isPlainTextIdentity() {
return removed.getText().equals(inserted.getText());
}

private static boolean skipStyleComparison = false;

public static void skipStyleComparison( boolean value )
{
skipStyleComparison = value;
}

/*
* This gets used, by the default UndoManagers supplied by UndoUtils,
* to check that a submitted undo/redo matches the change reported.
*/
public boolean equals( Object other )
{
if( skipStyleComparison && other instanceof RichTextChange )
{
PlainTextChange otherChange = ((RichTextChange) other).toPlainTextChange();
boolean matches = toPlainTextChange().equals( otherChange );
if ( ! matches ) System.err.println(
"Plain text comparison mismatch caused by text change"
+" during undo manager suspension (styling ignored)."
);
return matches;
}

return super.equals( other );
}
}
35 changes: 35 additions & 0 deletions richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import org.fxmisc.richtext.model.TextChange;
import org.fxmisc.undo.UndoManager;
import org.fxmisc.undo.UndoManagerFactory;
import org.fxmisc.undo.impl.MultiChangeUndoManagerImpl;
import org.fxmisc.undo.impl.UnlimitedChangeQueue;
import org.reactfx.SuspendableYes;
import org.reactfx.value.Val;

import javafx.beans.value.ObservableBooleanValue;
Expand Down Expand Up @@ -121,6 +124,38 @@ public static <PS, SEG, S> UndoManager<List<RichTextChange<PS, SEG, S>>> richTex
preventMergeDelay);
};

/**
* Returns an UndoManager with an unlimited history that can undo/redo {@link RichTextChange}s. New changes
* emitted from the stream will not be merged with the previous change after {@link #DEFAULT_PREVENT_MERGE_DELAY}
* <p><b>Note</b>: that <u>only styling changes</u> may occur <u>during suspension</u> of the undo manager.
*/
public static <PS, SEG, S> UndoManager<List<RichTextChange<PS, SEG, S>>> richTextSuspendableUndoManager(
GenericStyledArea<PS, SEG, S> area, SuspendableYes suspendUndo) {
return richTextSuspendableUndoManager(area, DEFAULT_PREVENT_MERGE_DELAY, suspendUndo);
}

/**
* Returns an UndoManager with an unlimited history that can undo/redo {@link RichTextChange}s. New changes
* emitted from the stream will not be merged with the previous change after {@code preventMergeDelay}.
* <p><b>Note</b>: that <u>only styling changes</u> may occur <u>during suspension</u> of the undo manager.
*/
public static <PS, SEG, S> UndoManager<List<RichTextChange<PS, SEG, S>>> richTextSuspendableUndoManager(
GenericStyledArea<PS, SEG, S> area, Duration preventMergeDelay, SuspendableYes suspendUndo) {

RichTextChange.skipStyleComparison( true );

return new MultiChangeUndoManagerImpl<>
(
new UnlimitedChangeQueue<>(),
TextChange::invert,
applyMultiRichTextChange(area),
TextChange::mergeWith,
TextChange::isIdentity,
area.multiRichChanges().conditionOn(suspendUndo),
preventMergeDelay
);
};

/**
* Returns an UndoManager with an unlimited history that can undo/redo {@link PlainTextChange}s. New changes
* emitted from the stream will not be merged with the previous change
Expand Down