Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ubertakter authored Dec 13, 2017
1 parent b5110b8 commit 5b465ff
Show file tree
Hide file tree
Showing 7 changed files with 460 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/combinedeventstreamtest/ChangeA.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package combinedeventstreamtest;

import java.util.Optional;
import org.reactfx.Change;

/**
*
* @author bwhitworth
*/
public class ChangeA extends ChangeBase<Double> {

public ChangeA(DataModel model, double oldVal, double newVal) {
super(model, oldVal, newVal);
}

public ChangeA(DataModel model, Change<Number> c) {
super(model, (Double)c.getOldValue(), (Double)c.getNewValue());
}

@Override
public ChangeBase<Double> invert() {
System.out.println("ChangeA invert "+this);
return new ChangeA(this.model, this.newValue, this.oldValue);
}

@Override
public void redo() {
System.out.println("ChangeA redo "+this);
this.model.setA(this.newValue);
}

@Override
public Optional<UndoChange> mergeWith(UndoChange other) {
System.out.print("ChangeA attempting merge with "+other+"... ");
if(other instanceof ChangeA) {
System.out.println("merged");
return Optional.of(new ChangeA(this.model, this.oldValue, ((ChangeA) other).newValue));
}
System.out.println("did not merge");
return Optional.empty();
}
}
48 changes: 48 additions & 0 deletions src/combinedeventstreamtest/ChangeB.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package combinedeventstreamtest;

import java.util.Optional;
import org.reactfx.Change;

/**
*
* @author bwhitworth
*/
public class ChangeB extends ChangeBase<Double> {

public ChangeB(DataModel model, double oldVal, double newVal) {
super(model, oldVal, newVal);
}

public ChangeB(DataModel model, Change<Number> c) {
super(model, (Double)c.getOldValue(), (Double)c.getNewValue());
}

@Override
public ChangeBase<Double> invert() {
System.out.println("ChangeB invert "+this);
return new ChangeB(this.model, this.newValue, this.oldValue);
}

@Override
public void redo() {
System.out.println("ChangeB redo "+this);
this.model.setB(this.newValue);
}

@Override
public Optional<UndoChange> mergeWith(UndoChange other) {
System.out.print("ChangeB attempting merge with "+other+"... ");
if(other instanceof ChangeB) {
System.out.println("merged");
return Optional.of(new ChangeB(this.model, this.oldValue, ((ChangeB) other).newValue));
}
System.out.println("did not merge");
return Optional.empty();
}

}
61 changes: 61 additions & 0 deletions src/combinedeventstreamtest/ChangeBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package combinedeventstreamtest;

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

/**
*
* @author bwhitworth
*/
public abstract class ChangeBase<T> implements UndoChange {
protected final T oldValue, newValue;
protected final DataModel model;

protected ChangeBase(DataModel model, T oldValue, T newValue) {
this.model = model;
this.oldValue = oldValue;
this.newValue = newValue;
}

public abstract ChangeBase<T> invert();
public abstract void redo();

public Optional<ChangeBase<?>> mergeWith(ChangeBase<?> other) {
return Optional.empty();
}

@Override
public int hashCode() {
return Objects.hash(this.oldValue, this.newValue);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ChangeBase<?> other = (ChangeBase<?>) obj;
if (!Objects.equals(this.oldValue, other.oldValue)) {
return false;
}
if (!Objects.equals(this.newValue, other.newValue)) {
return false;
}
if (!Objects.equals(this.model, other.model)) {
return false;
}
return true;
}

}
93 changes: 93 additions & 0 deletions src/combinedeventstreamtest/ChangeBoth.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package combinedeventstreamtest;

import java.util.Objects;
import java.util.Optional;
import org.reactfx.util.Tuple2;

/**
*
* @author bwhitworth
*/
public class ChangeBoth implements UndoChange {

private final ChangeA aChange;
private final ChangeB bChange;

public ChangeBoth(ChangeA ac, ChangeB bc) {
this.aChange = ac;
this.bChange = bc;
}

public ChangeBoth(Tuple2<UndoChange, UndoChange> tuple) {
this.aChange = ((ChangeBoth)tuple.get1()).aChange;
this.bChange = ((ChangeBoth)tuple.get2()).bChange;
}

@Override
public UndoChange invert() {
System.out.println("ChangeBoth invert "+this);
return new ChangeBoth(new ChangeA(this.aChange.model, this.aChange.newValue, this.aChange.oldValue),
new ChangeB(this.bChange.model, this.bChange.newValue, this.bChange.oldValue));
}

@Override
public void redo() {
System.out.println("ChangeBoth redo "+this);
DataModel model = this.aChange.model;
model.setA(this.aChange.newValue);
model.setB(this.bChange.newValue);
}

@Override
public Optional<UndoChange> mergeWith(UndoChange other) {
System.out.print("ChangeBoth attempting merge with "+other+"... ");
if(other instanceof ChangeBoth) {
System.out.println("merged");
ChangeBoth cb = (ChangeBoth)other;
ChangeA ac = (cb.aChange == null) ? this.aChange : cb.aChange;
ChangeB bc = (cb.bChange == null) ? this.bChange : cb.bChange;
return Optional.of(
new ChangeBoth(
new ChangeA(this.aChange.model, this.aChange.oldValue, ac.newValue),
new ChangeB(this.bChange.model, this.bChange.oldValue, bc.newValue)
)
);
}
System.out.println("did not merge");
return Optional.empty();
}

@Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + Objects.hashCode(this.aChange);
hash = 17 * hash + Objects.hashCode(this.bChange);
return hash;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ChangeBoth other = (ChangeBoth) obj;
if (!Objects.equals(this.aChange, other.aChange)) {
return false;
}
if (!Objects.equals(this.bChange, other.bChange)) {
return false;
}
return true;
}
}
118 changes: 118 additions & 0 deletions src/combinedeventstreamtest/CombinedEventStreamTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package combinedeventstreamtest;

import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import org.fxmisc.undo.UndoManager;
import org.fxmisc.undo.UndoManagerFactory;
import org.reactfx.Change;
import org.reactfx.EventStream;
import org.reactfx.EventStreams;

/**
*
* @author bwhitworth
*/
public class CombinedEventStreamTest extends Application {

@Override
public void start(Stage primaryStage) {
//a data model
DataModel model = new DataModel();
//event streams of property changes
EventStream<UndoChange> changeAStream = EventStreams.changesOf(model.aProperty())
.hook(c -> System.out.println("Change in A stream"))
.map(c -> new ChangeA(model, (Change<Number>)c));
EventStream<UndoChange> changeBStream = EventStreams.changesOf(model.bProperty())
.hook(c -> System.out.println("Change in B stream"))
.map(c -> new ChangeB(model, (Change<Number>)c));
//combine event streams
EventStream<UndoChange> bothStream = EventStreams.merge(changeAStream, changeBStream);

// EventStream<UndoChange> bothStream = EventStreams.combine(changeAStream, changeBStream)
// .hook(c -> System.out.println("Change in Both stream"))
// .map(ChangeBoth::new);

//undo manager
UndoManager<UndoChange> um = UndoManagerFactory.unlimitedHistoryUndoManager(
bothStream,
c -> c.invert(),
c -> c.redo(),
(c1, c2) -> c1.mergeWith(c2)
);

//generate new A
Button aButton = new Button();
aButton.setText("A change");
aButton.setOnAction((ActionEvent event) -> {
System.out.print(model+"\t->\t");
model.setA(Math.random()*10.0);
System.out.println(model);
});

//generate new B
Button bButton = new Button();
bButton.setText("B change");
bButton.setOnAction((ActionEvent event) -> {
System.out.print(model+"\t->\t");
model.setB(Math.random()*10.0);
System.out.println(model);
});

//generate new A and B
Button bothButton = new Button("A and B change");
bothButton.setOnAction(event -> {
System.out.print(model+"\t->\t");
model.setA(Math.random()*10.0);
model.setB(Math.random()*10.0);
System.out.println(model);
});

//undo/redo buttons
Button undoButton = new Button("Undo");
Button redoButton = new Button("Redo");
undoButton.disableProperty().bind(um.undoAvailableProperty().map(x -> !x));
redoButton.disableProperty().bind(um.redoAvailableProperty().map(x -> !x));
undoButton.setOnAction(event -> {
System.out.print("undo "+model+"\t->\t");
um.undo();
System.out.println(model);
});
redoButton.setOnAction(event -> {
System.out.print("redo "+model+"\t->\t");
um.redo();
System.out.println(model);
});

FlowPane root = new FlowPane();
root.setHgap(5);
root.setVgap(5);
root.getChildren().addAll(aButton, bButton, bothButton, undoButton, redoButton);

Scene scene = new Scene(root, 300, 250);

primaryStage.setTitle("Combined stream test");
primaryStage.setScene(scene);
primaryStage.show();
}

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}

}
Loading

0 comments on commit 5b465ff

Please sign in to comment.