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

org.fxmisc.richtext.util.UndoUtils Maven / Gradle / Ivy

There is a newer version: 0.11.3
Show newest version
package org.fxmisc.richtext.util;

import org.fxmisc.richtext.GenericStyledArea;
import org.fxmisc.richtext.MultiChangeBuilder;
import org.fxmisc.richtext.model.PlainTextChange;
import org.fxmisc.richtext.model.RichTextChange;
import org.fxmisc.richtext.model.TextChange;
import org.fxmisc.undo.UndoManager;
import org.fxmisc.undo.UndoManagerFactory;
import org.reactfx.EventStream;

import java.time.Duration;
import java.util.List;
import java.util.function.Consumer;

/**
 * A class filled with factory methods to help easily construct an {@link UndoManager} for a {@link GenericStyledArea}.
 */
public final class UndoUtils {

    private UndoUtils() {
        throw new IllegalStateException("UndoUtils cannot be instantiated");
    }

    public static final Duration DEFAULT_PREVENT_MERGE_DELAY = Duration.ofMillis(500);

    /**
     * Constructs an UndoManager with an unlimited history:
     * if {@link GenericStyledArea#isPreserveStyle() the area's preserveStyle flag is true}, the returned UndoManager
     * can undo/redo multiple {@link RichTextChange}s; otherwise, it can undo/redo multiple {@link PlainTextChange}s.
     */
    public static  UndoManager defaultUndoManager(GenericStyledArea area) {
        return area.isPreserveStyle()
                ? richTextUndoManager(area)
                : plainTextUndoManager(area);
    }

    /* ********************************************************************** *
     *                                                                        *
     * UndoManager Factory Methods                                            *
     *                                                                        *
     * Code that constructs different kinds of UndoManagers for an area       *
     *                                                                        *
     * ********************************************************************** */

    /**
     * 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}
     */
    public static  UndoManager>> richTextUndoManager(
            GenericStyledArea area) {
        return richTextUndoManager(area, UndoManagerFactory.unlimitedHistoryFactory());
    }

    /**
     * Returns an UndoManager that can undo/redo {@link RichTextChange}s. New changes
     * emitted from the stream will not be merged with the previous change
     * after {@code preventMergeDelay}
     */
    public static  UndoManager>> richTextUndoManager(
            GenericStyledArea area, Duration preventMergeDelay) {
        return richTextUndoManager(area, UndoManagerFactory.unlimitedHistoryFactory(), preventMergeDelay);
    };

    /**
     * Returns an UndoManager 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}
     */
    public static  UndoManager>> richTextUndoManager(
            GenericStyledArea area, UndoManagerFactory factory) {
        return richTextUndoManager(area, factory, DEFAULT_PREVENT_MERGE_DELAY);
    };

    /**
     * Returns an UndoManager that can undo/redo {@link RichTextChange}s. New changes
     * emitted from the stream will not be merged with the previous change
     * after {@code preventMergeDelay}
     */
    public static  UndoManager>> richTextUndoManager(
            GenericStyledArea area, UndoManagerFactory factory, Duration preventMergeDelay) {
        return factory.createMultiChangeUM(area.multiRichChanges(),
                TextChange::invert,
                applyMultiRichTextChange(area),
                TextChange::mergeWith,
                TextChange::isIdentity,
                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
     * after {@link #DEFAULT_PREVENT_MERGE_DELAY}
     */
    public static  UndoManager> plainTextUndoManager(
            GenericStyledArea area) {
        return plainTextUndoManager(area, DEFAULT_PREVENT_MERGE_DELAY);
    }

    /**
     * Returns an UndoManager that can undo/redo {@link PlainTextChange}s. New changes
     * emitted from the stream will not be merged with the previous change
     * after {@code preventMergeDelay}
     */
    public static  UndoManager> plainTextUndoManager(
            GenericStyledArea area, Duration preventMergeDelay) {
        return plainTextUndoManager(area, UndoManagerFactory.unlimitedHistoryFactory(), preventMergeDelay);
    }

    /**
     * Returns an UndoManager that can undo/redo {@link PlainTextChange}s. New changes
     * emitted from the stream will not be merged with the previous change
     * after {@link #DEFAULT_PREVENT_MERGE_DELAY}
     */
    public static  UndoManager> plainTextUndoManager(
            GenericStyledArea area, UndoManagerFactory factory) {
        return plainTextUndoManager(area, factory, DEFAULT_PREVENT_MERGE_DELAY);
    }

    /**
     * Returns an UndoManager that can undo/redo {@link PlainTextChange}s. New changes
     * emitted from the stream will not be merged with the previous change
     * after {@code preventMergeDelay}
     */
    public static  UndoManager> plainTextUndoManager(
            GenericStyledArea area, UndoManagerFactory factory, Duration preventMergeDelay) {
        return factory.createMultiChangeUM(area.multiPlainChanges(),
                TextChange::invert,
                applyMultiPlainTextChange(area),
                TextChange::mergeWith,
                TextChange::isIdentity,
                preventMergeDelay);
    }

    /* ********************************************************************** *
     *                                                                        *
     * Change Appliers                                                        *
     *                                                                        *
     * Code that handles how a change should be applied to the area           *
     *                                                                        *
     * ********************************************************************** */

    /**
     * Applies a {@link PlainTextChange} to the given area when the {@link UndoManager}'s change stream emits an event
     * by {@code area.replaceText(change.getPosition(), change.getRemovalEnd(), change.getInserted()}.
     */
    public static  Consumer applyPlainTextChange(GenericStyledArea area) {
        return change -> area.replaceText(change.getPosition(), change.getRemovalEnd(), change.getInserted());
    }

    /**
     * Applies a {@link RichTextChange} to the given area when the {@link UndoManager}'s change stream emits an event
     * by {@code area.replace(change.getPosition(), change.getRemovalEnd(), change.getInserted()}.
     */
    public static  Consumer> applyRichTextChange(
            GenericStyledArea area) {
        return change -> area.replace(change.getPosition(), change.getRemovalEnd(), change.getInserted());
    }

    /**
     * Applies a list of {@link PlainTextChange}s to the given area when the {@link UndoManager}'s change stream emits
     * an event by {@code area.replaceAbsolutely(change.getPosition(), change.getRemovalEnd(), change.getInserted()}.
     */
    public static  Consumer> applyMultiPlainTextChange(
            GenericStyledArea area) {
        return changeList -> {
            MultiChangeBuilder builder = area.createMultiChange(changeList.size());
            for (PlainTextChange c : changeList) {
                builder.replaceTextAbsolutely(c.getPosition(), c.getRemovalEnd(), c.getInserted());
            }
            builder.commit();
        };
    }

    /**
     * Applies a list of {@link RichTextChange} to the given area when the {@link UndoManager}'s change stream emits
     * an event by {@code area.replaceAbsolutely(change.getPosition(), change.getRemovalEnd(), change.getInserted()}.
     */
    public static  Consumer>> applyMultiRichTextChange(
            GenericStyledArea area) {
        return changeList -> {
            MultiChangeBuilder builder = area.createMultiChange(changeList.size());
            for (RichTextChange c : changeList) {
                builder.replaceAbsolutely(c.getPosition(), c.getRemovalEnd(), c.getInserted());
            }
            builder.commit();
        };
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy