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

com.dlsc.preferencesfx.history.Change Maven / Gradle / Ivy

There is a newer version: 2.0.3
Show newest version
package com.dlsc.preferencesfx.history;

import com.dlsc.preferencesfx.model.Setting;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.Callable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyListProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Represents a change, which is comprised of a new and an old value.
 *
 * @param 

the data type of the change, which is reflected in a {@link ListProperty} for a * list change and in a {@link ObjectProperty} for regular changes as well * @author François Martin * @author Marco Sanfratello * @implNote There are two types: List changes and regular changes. Internally, all changes are * saved into a {@link ListProperty} for the old and the new value, regardless of the * type of change. However, if two {@link ObservableList} are used to create a change, a * boolean flags the change as a list change. In case of a regular change, a binding will * also set an {@link ObjectProperty} for easier handling. */ public class Change

{ private static final Logger LOGGER = LoggerFactory.getLogger(Change.class.getName()); protected final Setting setting; private final ListProperty

oldList = new SimpleListProperty<>(); private final ListProperty

newList = new SimpleListProperty<>(); private final ObjectProperty

oldValue = new SimpleObjectProperty<>(); private final ObjectProperty

newValue = new SimpleObjectProperty<>(); private final BooleanProperty listChange = new SimpleBooleanProperty(); private final LocalDateTime timestamp; /** * Constructs a generalized change. * * @param setting the setting that was changed * @param listChange true if this is a list change */ protected Change(Setting setting, boolean listChange) { this.setting = setting; this.listChange.set(listChange); timestamp = LocalDateTime.now(); setupBindings(); } /** * Constructs a list change. * * @param setting the setting that was changed * @param oldList the "before" value(s) of the change * @param newList the "after" value(s) of the change */ public Change(Setting setting, ObservableList

oldList, ObservableList

newList) { this(setting, true); this.oldList.set(FXCollections.observableArrayList(oldList)); this.newList.set(FXCollections.observableArrayList(newList)); } /** * Constructs a regular object change. * * @param setting the setting that was changed * @param oldValue the "before" value of the change * @param newValue the "after" value of the change */ public Change(Setting setting, P oldValue, P newValue) { this(setting, false); this.oldList.set(FXCollections.observableArrayList(Arrays.asList(oldValue))); this.newList.set(FXCollections.observableArrayList(Arrays.asList(newValue))); } private void setupBindings() { // oldValue will represent the object contained in oldList, if this is not a listChange oldValue.bind( Bindings.createObjectBinding(createListToObjectBinding(oldList), oldList, listChange) ); // newValue will represent the object contained in newList, if this is not a listChange newValue.bind( Bindings.createObjectBinding(createListToObjectBinding(newList), newList, listChange) ); } /** * Creates a function, which handles binding between a ListProperty and an ObjectProperty. * *

If this change isn't a list change, oldValue and newValue properties will have the single * element inside of the list, for easier usage. * * @param listProperty to be bound to the object property * @return Callable function, which binds a list to an object property. */ private Callable createListToObjectBinding(ListProperty

listProperty) { return () -> { if (!isListChange() && listProperty.get() != null && listProperty.get().size() != 0) { return listProperty.get().get(0); } return null; }; } /** * Compares newValue and oldValue to see if they are the same. * If this is the case, this change is redundant, since it doesn't represent a true change. * This can happen on compounded changes. * * @return true if redundant, else if otherwise. */ public boolean isRedundant() { if (isListChange()) { return Objects.equals(oldList.get(),newList.get()); } return oldValue.get().equals(newValue.get()); } /** * Undos a change. * Does this by setting the corresponding value of the {@link Setting} to the old value of this * change. */ public void undo() { if (isListChange()) { LOGGER.trace("Undoing list change: " + oldList.get().toString()); setting.valueProperty().setValue(oldList.get()); } else { setting.valueProperty().setValue(oldValue.get()); } } /** * Redos a change. * Does this by setting the corresponding value of the {@link Setting} to the new value of this * change. */ public void redo() { if (isListChange()) { LOGGER.trace("Redoing list change: " + newList.get().toString()); setting.valueProperty().setValue(newList.get()); } else { setting.valueProperty().setValue(newValue.get()); } } public ObservableList

getOldList() { return oldList.get(); } public ObservableList

getNewList() { return newList.get(); } public void setNewList(ObservableList

newList) { LOGGER.trace("Setting new List, old: " + oldList.toString() + " new: " + newList.toString()); this.newList.set(FXCollections.observableArrayList(newList)); } public boolean isListChange() { return listChange.get(); } public ReadOnlyBooleanProperty listChangeProperty() { return listChange; } public P getOldValue() { return oldValue.get(); } public P getNewValue() { return newValue.get(); } public void setNewValue(P newValue) { this.newList.set(FXCollections.observableArrayList(Arrays.asList(newValue))); } public Setting getSetting() { return setting; } public String getTimestamp() { DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM); return timestamp.format(formatter); } public ReadOnlyObjectProperty

oldValueProperty() { return oldValue; } public ReadOnlyObjectProperty

newValueProperty() { return newValue; } public ReadOnlyListProperty

oldListProperty() { return oldList; } public ReadOnlyListProperty

newListProperty() { return newList; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy