66import org .fxmisc .richtext .model .TextChange ;
77import org .fxmisc .undo .UndoManager ;
88import org .fxmisc .undo .UndoManagerFactory ;
9+ import org .reactfx .EventStream ;
910
11+ import java .time .Duration ;
1012import java .util .function .Consumer ;
1113
1214/**
@@ -18,6 +20,8 @@ private UndoUtils() {
1820 throw new IllegalStateException ("UndoUtils cannot be instantiated" );
1921 }
2022
23+ public static final Duration DEFAULT_PREVENT_MERGE_DELAY = Duration .ofMillis (500 );
24+
2125 /**
2226 * Constructs an UndoManager with an unlimited history:
2327 * if {@link GenericStyledArea#isPreserveStyle() the area's preserveStyle flag is true}, the returned UndoManager
@@ -38,33 +42,91 @@ public static <PS, SEG, S> UndoManager defaultUndoManager(GenericStyledArea<PS,
3842 * ********************************************************************** */
3943
4044 /**
41- * Returns an UndoManager with an unlimited history that can undo/redo {@link RichTextChange}s.
45+ * Returns an UndoManager with an unlimited history that can undo/redo {@link RichTextChange}s. New changes
46+ * emitted from the stream will not be merged with the previous change
47+ * after {@link #DEFAULT_PREVENT_MERGE_DELAY}
4248 */
4349 public static <PS , SEG , S > UndoManager <RichTextChange <PS , SEG , S >> richTextUndoManager (GenericStyledArea <PS , SEG , S > area ) {
4450 return richTextUndoManager (area , UndoManagerFactory .unlimitedHistoryFactory ());
4551 }
4652
4753 /**
48- * Returns an UndoManager that can undo/redo {@link RichTextChange}s.
54+ * Returns an UndoManager that can undo/redo {@link RichTextChange}s. New changes
55+ * emitted from the stream will not be merged with the previous change
56+ * after {@code preventMergeDelay}
4957 */
5058 public static <PS , SEG , S > UndoManager <RichTextChange <PS , SEG , S >> richTextUndoManager (GenericStyledArea <PS , SEG , S > area ,
51- UndoManagerFactory factory ) {
52- return factory . create (area . richChanges (), TextChange :: invert , applyRichTextChange ( area ), TextChange :: mergeWith , TextChange :: isIdentity );
59+ Duration preventMergeDelay ) {
60+ return richTextUndoManager (area , UndoManagerFactory . unlimitedHistoryFactory ( ), preventMergeDelay );
5361 };
5462
5563 /**
56- * Returns an UndoManager with an unlimited history that can undo/redo {@link PlainTextChange}s.
64+ * Returns an UndoManager that can undo/redo {@link RichTextChange}s. New changes
65+ * emitted from the stream will not be merged with the previous change
66+ * after {@link #DEFAULT_PREVENT_MERGE_DELAY}
67+ */
68+ public static <PS , SEG , S > UndoManager <RichTextChange <PS , SEG , S >> richTextUndoManager (GenericStyledArea <PS , SEG , S > area ,
69+ UndoManagerFactory factory ) {
70+ return richTextUndoManager (area , factory , DEFAULT_PREVENT_MERGE_DELAY );
71+ };
72+
73+ /**
74+ * Returns an UndoManager that can undo/redo {@link RichTextChange}s. New changes
75+ * emitted from the stream will not be merged with the previous change
76+ * after {@code preventMergeDelay}
77+ */
78+ public static <PS , SEG , S > UndoManager <RichTextChange <PS , SEG , S >> richTextUndoManager (GenericStyledArea <PS , SEG , S > area ,
79+ UndoManagerFactory factory ,
80+ Duration preventMergeDelay ) {
81+ return wrap (
82+ factory .create (area .richChanges (), TextChange ::invert , applyRichTextChange (area ), TextChange ::mergeWith , TextChange ::isIdentity ),
83+ area .richChanges (),
84+ preventMergeDelay
85+ );
86+ };
87+
88+ /**
89+ * Returns an UndoManager with an unlimited history that can undo/redo {@link PlainTextChange}s. New changes
90+ * emitted from the stream will not be merged with the previous change
91+ * after {@link #DEFAULT_PREVENT_MERGE_DELAY}
5792 */
5893 public static <PS , SEG , S > UndoManager <PlainTextChange > plainTextUndoManager (GenericStyledArea <PS , SEG , S > area ) {
59- return plainTextUndoManager (area , UndoManagerFactory . unlimitedHistoryFactory () );
94+ return plainTextUndoManager (area , DEFAULT_PREVENT_MERGE_DELAY );
6095 }
6196
6297 /**
63- * Returns an UndoManager that can undo/redo {@link PlainTextChange}s.
98+ * Returns an UndoManager that can undo/redo {@link PlainTextChange}s. New changes
99+ * emitted from the stream will not be merged with the previous change
100+ * after {@code preventMergeDelay}
101+ */
102+ public static <PS , SEG , S > UndoManager <PlainTextChange > plainTextUndoManager (GenericStyledArea <PS , SEG , S > area ,
103+ Duration preventMergeDelay ) {
104+ return plainTextUndoManager (area , UndoManagerFactory .unlimitedHistoryFactory (), preventMergeDelay );
105+ }
106+
107+ /**
108+ * Returns an UndoManager that can undo/redo {@link PlainTextChange}s. New changes
109+ * emitted from the stream will not be merged with the previous change
110+ * after {@link #DEFAULT_PREVENT_MERGE_DELAY}
64111 */
65112 public static <PS , SEG , S > UndoManager <PlainTextChange > plainTextUndoManager (GenericStyledArea <PS , SEG , S > area ,
66113 UndoManagerFactory factory ) {
67- return factory .create (area .plainTextChanges (), TextChange ::invert , applyPlainTextChange (area ), TextChange ::mergeWith , TextChange ::isIdentity );
114+ return plainTextUndoManager (area , factory , DEFAULT_PREVENT_MERGE_DELAY );
115+ }
116+
117+ /**
118+ * Returns an UndoManager that can undo/redo {@link PlainTextChange}s. New changes
119+ * emitted from the stream will not be merged with the previous change
120+ * after {@code preventMergeDelay}
121+ */
122+ public static <PS , SEG , S > UndoManager <PlainTextChange > plainTextUndoManager (GenericStyledArea <PS , SEG , S > area ,
123+ UndoManagerFactory factory ,
124+ Duration preventMergeDelay ) {
125+ return wrap (
126+ factory .create (area .plainTextChanges (), TextChange ::invert , applyPlainTextChange (area ), TextChange ::mergeWith , TextChange ::isIdentity ),
127+ area .plainTextChanges (),
128+ preventMergeDelay
129+ );
68130 }
69131
70132 /* ********************************************************************** *
@@ -90,4 +152,12 @@ public static <PS, SEG, S> Consumer<PlainTextChange> applyPlainTextChange(Generi
90152 public static <PS , SEG , S > Consumer <RichTextChange <PS , SEG , S >> applyRichTextChange (GenericStyledArea <PS , SEG , S > area ) {
91153 return change -> area .replace (change .getPosition (), change .getRemovalEnd (), change .getInserted ());
92154 }
155+
156+ /**
157+ * Wraps an {@link UndoManager} and prevents the next emitted change from merging with the previous one are a
158+ * period of inactivity (i.e., the {@code changeStream} has not emitted an event in {@code preventMergeDelay}
159+ */
160+ public static <T > UndoManager <T > wrap (UndoManager <T > undoManager , EventStream <T > changeStream , Duration preventMergeDelay ) {
161+ return new UndoManagerInactivityWrapper <>(undoManager , changeStream , preventMergeDelay );
162+ }
93163}
0 commit comments