All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fxmisc.undo.UndoManagerFactory Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
package org.fxmisc.undo;

import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

import org.fxmisc.undo.impl.ChangeQueue;
import org.fxmisc.undo.impl.FixedSizeChangeQueue;
import org.fxmisc.undo.impl.MultiChangeUndoManagerImpl;
import org.fxmisc.undo.impl.UndoManagerImpl;
import org.fxmisc.undo.impl.UnlimitedChangeQueue;
import org.fxmisc.undo.impl.ZeroSizeChangeQueue;
import org.reactfx.EventStream;

public interface UndoManagerFactory {

    /* ******************************* *
     * Single Change                   *
     * ******************************* */

    /**
     * Creates an {@link UndoManager} that tracks changes emitted from {@code changeStream}.
     *
     * @param  representation of a change
     * @param invert Inverts a change, so that applying the inverted change ({@code apply.accept(invert.apply(c))})
     *               has the effect of undoing the original change ({@code c}). Inverting a change twice should
     *               result in the original change ({@code invert.apply(invert.apply(c)).equals(c)}).
     * @param apply Used to apply a change. From the point of view of {@code apply}, {@code C}
     *              describes an action to be performed. Calling {@code apply.accept(c)}
     *              must cause {@code c} to be emitted from {@code changeStream}.
     */
    default  UndoManager createSingleChangeUM(
            EventStream changeStream,
            Function invert,
            Consumer apply) {
        return createSingleChangeUM(changeStream, invert, apply, (c1, c2) -> Optional.empty());
    }

    /**
     * Creates an {@link UndoManager} that tracks and optionally merges changes emitted from {@code changeStream}.
     *
     * @param  representation of a change
     * @param invert Inverts a change, so that applying the inverted change ({@code apply.accept(invert.apply(c))})
     *               has the effect of undoing the original change ({@code c}). Inverting a change twice should
     *               result in the original change ({@code invert.apply(invert.apply(c)).equals(c)}).
     * @param apply Used to apply a change. From the point of view of {@code apply}, {@code C}
     *              describes an action to be performed. Calling {@code apply.accept(c)}
     *              must cause {@code c} to be emitted from {@code changeStream}.
     * @param merge Used to merge two subsequent changes into one.
     *              Returns an empty {@linkplain Optional} when the changes cannot or should not be merged.
     */
    default  UndoManager createSingleChangeUM(
            EventStream changeStream,
            Function invert,
            Consumer apply,
            BiFunction> merge) {
        return createSingleChangeUM(changeStream, invert, apply, merge, c -> false);
    }

    /**
     * Creates an {@link UndoManager} that tracks and optionally merges changes emitted from {@code changeStream}.
     *
     * @param  representation of a change
     * @param invert Inverts a change, so that applying the inverted change ({@code apply.accept(invert.apply(c))})
     *               has the effect of undoing the original change ({@code c}). Inverting a change twice should
     *               result in the original change ({@code invert.apply(invert.apply(c)).equals(c)}).
     * @param apply Used to apply a change. From the point of view of {@code apply}, {@code C}
     *              describes an action to be performed. Calling {@code apply.accept(c)}
     *              must cause {@code c} to be emitted from {@code changeStream}.
     * @param merge Used to merge two subsequent changes into one.
     *              Returns an empty {@linkplain Optional} when the changes cannot or should not be merged.
     *              If two changes "annihilate" (i.e. {@code merge.apply(c1, c2).isPresen()} and
     *              {@code isIdentity.test(merge.apply(c1, c2).get())} are both {@code true}), it should
     *              be the case that one is inverse of the other ({@code invert.apply(c1).equals(c2)}).
     * @param isIdentity returns true for changes whose application would have no effect, thereby equivalent
     *                   to an identity function ({@link Function#identity()}) on the underlying model.
     */
    default   UndoManager createSingleChangeUM(
            EventStream changeStream,
            Function invert,
            Consumer apply,
            BiFunction> merge,
            Predicate isIdentity) {
        return createSingleChangeUM(changeStream, invert, apply, merge, isIdentity, Duration.ZERO);
    }

    /**
     * Creates an {@link UndoManager} that tracks and optionally merges changes emitted from {@code changeStream}.
     *
     * @param  representation of a change
     * @param invert Inverts a change, so that applying the inverted change ({@code apply.accept(invert.apply(c))})
     *               has the effect of undoing the original change ({@code c}). Inverting a change twice should
     *               result in the original change ({@code invert.apply(invert.apply(c)).equals(c)}).
     * @param apply Used to apply a change. From the point of view of {@code apply}, {@code C}
     *              describes an action to be performed. Calling {@code apply.accept(c)}
     *              must cause {@code c} to be emitted from {@code changeStream}.
     * @param merge Used to merge two subsequent changes into one.
     *              Returns an empty {@linkplain Optional} when the changes cannot or should not be merged.
     *              If two changes "annihilate" (i.e. {@code merge.apply(c1, c2).isPresen()} and
     *              {@code isIdentity.test(merge.apply(c1, c2).get())} are both {@code true}), it should
     *              be the case that one is inverse of the other ({@code invert.apply(c1).equals(c2)}).
     * @param isIdentity returns true for changes whose application would have no effect, thereby equivalent
     *                   to an identity function ({@link Function#identity()}) on the underlying model.
     * @param preventMergeDelay the amount by which to wait before calling {@link UndoManager#preventMerge()}.
     *                          Helpful when one wants to prevent merges after a period of inactivity (the
     *                          {@code changeStream} doesn't emit an event after the given duration). Passing in
     *                          a negative or zero duration will never call {@link UndoManager#preventMerge()}.
     */
     UndoManager createSingleChangeUM(
            EventStream changeStream,
            Function invert,
            Consumer apply,
            BiFunction> merge,
            Predicate isIdentity,
            Duration preventMergeDelay);

    /* ******************************* *
     * Single Change Implementations   *
     * ******************************* */

    /**
     * Creates an {@link UndoManager} with unlimited history.
     *
     * For description of parameters, see
     * {@link #createSingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.
     */
    public static  UndoManager unlimitedHistorySingleChangeUM(
            EventStream changeStream,
            Function invert,
            Consumer apply) {
        return unlimitedHistorySingleChangeUM(changeStream, invert, apply, (c1, c2) -> Optional.empty());
    }

    /**
     * Creates an {@link UndoManager} with unlimited history.
     *
     * For description of parameters, see
     * {@link #createSingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.
     */
    public static  UndoManager unlimitedHistorySingleChangeUM(
            EventStream changeStream,
            Function invert,
            Consumer apply,
            BiFunction> merge) {
        return unlimitedHistorySingleChangeUM(changeStream, invert, apply, merge, c -> false, Duration.ZERO);
    }

    /**
     * Creates an {@link UndoManager} with unlimited history.
     *
     * For description of parameters, see
     * {@link #createSingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.
     */
    public static  UndoManager unlimitedHistorySingleChangeUM(
            EventStream changeStream,
            Function invert,
            Consumer apply,
            BiFunction> merge,
            Predicate isIdentity) {
        return unlimitedHistorySingleChangeUM(changeStream, invert, apply, merge, isIdentity, Duration.ZERO);
    }

    /**
     * Creates an {@link UndoManager} with unlimited history.
     *
     * For description of parameters, see
     * {@link #createSingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.
     */
    public static  UndoManager unlimitedHistorySingleChangeUM(
            EventStream changeStream,
            Function invert,
            Consumer apply,
            BiFunction> merge,
            Predicate isIdentity,
            Duration preventMergeDelay) {
        ChangeQueue queue = new UnlimitedChangeQueue();
        return new UndoManagerImpl<>(queue, invert, apply, merge, isIdentity, changeStream, preventMergeDelay);
    }

    /**
     * Creates an {@link UndoManager} with bounded history.
     * When at full capacity, a new change will cause the oldest change to be forgotten.
     *
     * 

For description of the remaining parameters, see * {@link #createSingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.

* * @param capacity maximum number of changes the returned UndoManager can store */ public static UndoManager fixedSizeHistorySingleChangeUM( EventStream changeStream, Function invert, Consumer apply, int capacity) { return fixedSizeHistorySingleChangeUM(changeStream, invert, apply, (c1, c2) -> Optional.empty(), capacity); } /** * Creates an {@link UndoManager} with bounded history. * When at full capacity, a new change will cause the oldest change to be forgotten. * *

For description of the remaining parameters, see * {@link #createSingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.

* * @param capacity maximum number of changes the returned UndoManager can store */ public static UndoManager fixedSizeHistorySingleChangeUM( EventStream changeStream, Function invert, Consumer apply, BiFunction> merge, int capacity) { return fixedSizeHistorySingleChangeUM(changeStream, invert, apply, merge, c -> false, Duration.ZERO, capacity); } /** * Creates an {@link UndoManager} with bounded history. * When at full capacity, a new change will cause the oldest change to be forgotten. * *

For description of the remaining parameters, see * {@link #createSingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.

* * @param capacity maximum number of changes the returned UndoManager can store */ public static UndoManager fixedSizeHistorySingleChangeUM( EventStream changeStream, Function invert, Consumer apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay, int capacity) { ChangeQueue queue = new FixedSizeChangeQueue(capacity); return new UndoManagerImpl<>(queue, invert, apply, merge, isIdentity, changeStream, preventMergeDelay); } /** * Creates an {@link UndoManager} with no history: all changes emitted from {@code changeStream} will be * immediately forgotten. Therefore, the returned {@linkplain UndoManager} will never be able to undo/redo * any change emitted from {@code changeStream}. * However, the (imaginary) current position will keep advancing, so that one can still use * {@link UndoManager#atMarkedPositionProperty()} to determine whether any change has occurred since the last * {@link UndoManager#mark()} (e.g. since the last save). */ public static UndoManager zeroHistorySingleChangeUM(EventStream changeStream) { ChangeQueue queue = new ZeroSizeChangeQueue<>(); return new UndoManagerImpl<>(queue, c -> c, c -> {}, (c1, c2) -> Optional.empty(), c -> false, changeStream); } /* ******************************* * * Multi Change * * ******************************* */ /** * Creates an {@link UndoManager} that tracks lists of changes emitted from {@code changeStream}. * * @param representation of a change * @param invert Inverts a change, so that applying the inverted change ({@code apply.accept(invert.apply(c))}) * has the effect of undoing the original change ({@code c}). Inverting a change twice should * result in the original change ({@code invert.apply(invert.apply(c)).equals(c)}). * @param apply Used to apply a list of changes. {@code list} describes a list of actions to be performed. * Calling {@code apply.accept(list)} must cause {@code list} to be emitted from * the {@code changeStream}. */ default UndoManager> createMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply) { return createMultiChangeUM(changeStream, invert, apply, (c1, c2) -> Optional.empty()); } /** * Creates an {@link UndoManager} that tracks and optionally merges lists of changes * emitted from {@code changeStream}. * * @param representation of a change * @param invert Inverts a change, so that applying the inverted change ({@code apply.accept(invert.apply(c))}) * has the effect of undoing the original change ({@code c}). Inverting a change twice should * result in the original change ({@code invert.apply(invert.apply(c)).equals(c)}). * @param apply Used to apply a list of changes. {@code list} describes a list of actions to be performed. * Calling {@code apply.accept(list)} must cause {@code list} to be emitted from * the {@code changeStream}. * @param merge Used to merge two subsequent changes into one. * Returns an empty {@linkplain Optional} when the changes cannot or should not be merged. */ default UndoManager> createMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge) { return createMultiChangeUM(changeStream, invert, apply, merge, c -> false); } /** * Creates an {@link UndoManager} that tracks and optionally merges lists of changes * emitted from {@code changeStream}. * * @param representation of a change * @param invert Inverts a change, so that applying the inverted change ({@code apply.accept(invert.apply(c))}) * has the effect of undoing the original change ({@code c}). Inverting a change twice should * result in the original change ({@code invert.apply(invert.apply(c)).equals(c)}). * @param apply Used to apply a list of changes. {@code list} describes a list of actions to be performed. * Calling {@code apply.accept(list)} must cause {@code list} to be emitted from * the {@code changeStream}. * @param merge Used to merge two subsequent changes into one. * Returns an empty {@linkplain Optional} when the changes cannot or should not be merged. * If two changes "annihilate" (i.e. {@code merge.apply(c1, c2).isPresen()} and * {@code isIdentity.test(merge.apply(c1, c2).get())} are both {@code true}), it should * be the case that one is inverse of the other ({@code invert.apply(c1).equals(c2)}). * @param isIdentity returns true for changes whose application would have no effect, thereby equivalent * to an identity function ({@link Function#identity()}) on the underlying model. */ default UndoManager> createMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, Predicate isIdentity) { return createMultiChangeUM(changeStream, invert, apply, merge, isIdentity, Duration.ZERO); } /** * Creates an {@link UndoManager} that tracks and optionally merges lists of changes * emitted from {@code changeStream}. * * @param representation of a change * @param invert Inverts a change, so that applying the inverted change ({@code apply.accept(invert.apply(c))}) * has the effect of undoing the original change ({@code c}). Inverting a change twice should * result in the original change ({@code invert.apply(invert.apply(c)).equals(c)}). * @param apply Used to apply a list of changes. {@code list} describes a list of actions to be performed. * Calling {@code apply.accept(list)} must cause {@code list} to be emitted from * the {@code changeStream}. * @param merge Used to merge two subsequent changes into one. * Returns an empty {@linkplain Optional} when the changes cannot or should not be merged. * If two changes "annihilate" (i.e. {@code merge.apply(c1, c2).isPresen()} and * {@code isIdentity.test(merge.apply(c1, c2).get())} are both {@code true}), it should * be the case that one is inverse of the other ({@code invert.apply(c1).equals(c2)}). * @param isIdentity returns true for changes whose application would have no effect, thereby equivalent * to an identity function ({@link Function#identity()}) on the underlying model. * @param preventMergeDelay the amount by which to wait before calling {@link UndoManager#preventMerge()}. * Helpful when one wants to prevent merges after a period of inactivity (the * {@code changeStream} doesn't emit an event after the given duration). Passing in * a negative or zero duration will never call {@link UndoManager#preventMerge()}. */ UndoManager> createMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay); /* ******************************* * * Multi Change Implementations * * ******************************* */ /** * Creates an {@link UndoManager} with unlimited history. * * For description of parameters, see * {@link #createMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}. */ public static UndoManager> unlimitedHistoryMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply) { return unlimitedHistoryMultiChangeUM(changeStream, invert, apply, (c1, c2) -> Optional.empty()); } /** * Creates an {@link UndoManager} with unlimited history. * * For description of parameters, see * {@link #createMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}. */ public static UndoManager> unlimitedHistoryMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge) { return unlimitedHistoryMultiChangeUM(changeStream, invert, apply, merge, c -> false, Duration.ZERO); } /** * Creates an {@link UndoManager} with unlimited history. * * For description of parameters, see * {@link #createMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}. */ public static UndoManager> unlimitedHistoryMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, Predicate isIdentity) { return unlimitedHistoryMultiChangeUM(changeStream, invert, apply, merge, isIdentity, Duration.ZERO); } /** * Creates an {@link UndoManager} with unlimited history. * * For description of parameters, see * {@link #createMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}. */ public static UndoManager> unlimitedHistoryMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay) { ChangeQueue> queue = new UnlimitedChangeQueue<>(); return new MultiChangeUndoManagerImpl<>(queue, invert, apply, merge, isIdentity, changeStream, preventMergeDelay); } /** * Creates an {@link UndoManager} with bounded history. * When at full capacity, a new change will cause the oldest change to be forgotten. * *

For description of the remaining parameters, see * {@link #createMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.

* * @param capacity maximum number of changes the returned UndoManager can store */ public static UndoManager> fixedSizeHistoryMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, int capacity) { return fixedSizeHistoryMultiChangeUM(changeStream, invert, apply, (c1, c2) -> Optional.empty(), capacity); } /** * Creates an {@link UndoManager} with bounded history. * When at full capacity, a new change will cause the oldest change to be forgotten. * *

For description of the remaining parameters, see * {@link #createMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.

* * @param capacity maximum number of changes the returned UndoManager can store */ public static UndoManager> fixedSizeHistoryMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, int capacity) { return fixedSizeHistoryMultiChangeUM(changeStream, invert, apply, merge, c -> false, Duration.ZERO, capacity); } /** * Creates an {@link UndoManager} with bounded history. * When at full capacity, a new change will cause the oldest change to be forgotten. * *

For description of the remaining parameters, see * {@link #createMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration)}.

* * @param capacity maximum number of changes the returned UndoManager can store */ public static UndoManager> fixedSizeHistoryMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay, int capacity) { ChangeQueue> queue = new FixedSizeChangeQueue<>(capacity); return new MultiChangeUndoManagerImpl<>(queue, invert, apply, merge, isIdentity, changeStream, preventMergeDelay); } /** * Creates an {@link UndoManager} with no history: all changes emitted from {@code changeStream} will be * immediately forgotten. Therefore, the returned {@linkplain UndoManager} will never be able to undo/redo * any change emitted from {@code changeStream}. * However, the (imaginary) current position will keep advancing, so that one can still use * {@link UndoManager#atMarkedPositionProperty()} to determine whether any change has occurred since the last * {@link UndoManager#mark()} (e.g. since the last save). */ public static UndoManager> zeroHistoryMultiChangeUM(EventStream> changeStream) { ChangeQueue> queue = new ZeroSizeChangeQueue<>(); Consumer> doNothingForUndoAndRedo = c -> {}; return new MultiChangeUndoManagerImpl<>(queue, c -> c, doNothingForUndoAndRedo, (c1, c2) -> Optional.empty(), c -> false, changeStream); } /* ******************************* * * Factories * * ******************************* */ /** * Creates a factory for {@link UndoManager}s with unlimited history. * * @see #unlimitedHistorySingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration) * @see #unlimitedHistoryMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration) */ public static UndoManagerFactory unlimitedHistoryFactory() { return new UndoManagerFactory() { @Override public UndoManager createSingleChangeUM( EventStream changeStream, Function invert, Consumer apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay) { return unlimitedHistorySingleChangeUM(changeStream, invert, apply, merge, isIdentity, preventMergeDelay); } @Override public UndoManager> createMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay) { return unlimitedHistoryMultiChangeUM(changeStream, invert, apply, merge, isIdentity, preventMergeDelay); } }; } /** * Creates a factory for {@link UndoManager}s with bounded history. * When at full capacity, a new change will cause the oldest change to be forgotten. * * @see #fixedSizeHistorySingleChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration, int) * @see #fixedSizeHistoryMultiChangeUM(EventStream, Function, Consumer, BiFunction, Predicate, Duration, int) */ public static UndoManagerFactory fixedSizeHistoryFactory(int capacity) { return new UndoManagerFactory() { @Override public UndoManager createSingleChangeUM( EventStream changeStream, Function invert, Consumer apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay) { return fixedSizeHistorySingleChangeUM(changeStream, invert, apply, merge, isIdentity, preventMergeDelay, capacity); } @Override public UndoManager> createMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay) { return fixedSizeHistoryMultiChangeUM(changeStream, invert, apply, merge, isIdentity, preventMergeDelay, capacity); } }; } /** * Creates a factory for {@link UndoManager}s with no history. * * @see #zeroHistorySingleChangeUM(EventStream) * @see #zeroHistoryMultiChangeUM(EventStream) */ public static UndoManagerFactory zeroHistoryFactory() { return new UndoManagerFactory() { @Override public UndoManager createSingleChangeUM( EventStream changeStream, Function invert, Consumer apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay) { return zeroHistorySingleChangeUM(changeStream); } @Override public UndoManager> createMultiChangeUM( EventStream> changeStream, Function invert, Consumer> apply, BiFunction> merge, Predicate isIdentity, Duration preventMergeDelay) { return zeroHistoryMultiChangeUM(changeStream); } }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy