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

org.fxmisc.richtext.model.TextChange Maven / Gradle / Ivy

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

import java.util.Objects;
import java.util.Optional;

/**
 * Base change class for style changes ({@link RichTextChange}) and non-style changes ({@link PlainTextChange})
 * in a {@link org.fxmisc.richtext.TextEditingArea}.
 *
 * @param  type of data that was removed and inserted in the {@link org.fxmisc.richtext.TextEditingArea}.
 * @param  a subclass of TextChange
 */
public abstract class TextChange> {

    protected final int position;
    protected final S removed;
    protected final S inserted;

    public TextChange(int position, S removed, S inserted) {
        this.position = position;
        this.removed = removed;
        this.inserted = inserted;
    }

    /**
     * Gets the start position of where the replacement happened
     */
    public int getPosition() { return position; };

    public S getRemoved() { return removed; }
    public S getInserted() { return inserted; }

    /**
     * Returns a new subclass of {@link TextChange} that makes the {@code inserted} the removed object and
     * the {@code removed} the inserted object
     */
    public Self invert() { return create(position, inserted, removed); }

    /** Returns the position where the removal ends (e.g. {@code position + removedLength())} */
    public int getRemovalEnd() { return position + removedLength(); }

    /** Returns the position where the inserted ends (e.g. {@code position + insertedLength())} */
    public int getInsertionEnd() { return position + insertedLength(); }

    /**
     * Gets the net length of this change (i.e., {@code insertedLength() - removedLength()})
     */
    public int getNetLength() { return insertedLength() - removedLength(); }

    protected abstract int removedLength();
    protected abstract int insertedLength();
    protected abstract S concat(S a, S b);
    protected abstract S sub(S s, int from, int to);
    protected abstract Self create(int position, S removed, S inserted);

    /**
     * Returns true if this change is an identity change: applying it does nothing as it removes what it inserts.
     * See also {@link java.util.function.Function#identity()}
     */
    public final boolean isIdentity() {
        return removed.equals(inserted);
    }

    /**
     * Merges this change with the given change, if possible.
     * This change is considered to be the former and the given
     * change is considered to be the latter.
     * Changes can be merged if either
     * 
    *
  • the latter's start matches the former's added text end; or
  • *
  • the latter's removed text end matches the former's added text end.
  • *
* @param latter change to merge with this change. * @return a new merged change if changes can be merged, * {@code null} otherwise. */ public Optional mergeWith(Self latter) { if(latter.position == this.position + this.insertedLength()) { S removedText = concat(this.removed, latter.removed); S addedText = concat(this.inserted, latter.inserted); return Optional.of(create(this.position, removedText, addedText)); } else if(latter.position + latter.removedLength() == this.position + this.insertedLength()) { if(this.position <= latter.position) { S addedText = concat(sub(this.inserted, 0, latter.position - this.position), latter.inserted); return Optional.of(create(this.position, this.removed, addedText)); } else { S removedText = concat(sub(latter.removed, 0, this.position - latter.position), this.removed); return Optional.of(create(latter.position, removedText, latter.inserted)); } } else { return Optional.empty(); } } @Override public boolean equals(Object other) { if(other instanceof TextChange) { TextChange that = (TextChange) other; return Objects.equals(this.position, that.position) && Objects.equals(this.removed, that.removed ) && Objects.equals(this.inserted, that.inserted); } else { return false; } } @Override public int hashCode() { return Objects.hash(position, removed, inserted); } @Override public final String toString() { return this.getClass().getSimpleName() + "{\n" + "\tposition: " + position + "\n" + "\tremoved: " + removed + "\n" + "\tinserted: " + inserted + "\n" + "}"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy