From 87c42c3354cf957823955110edde33772f18e0d6 Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Sun, 19 Apr 2015 18:17:23 +0200 Subject: [PATCH 01/28] Update version to 1.2.0-SNAPSHOT to begin next dev cycle --- examples/mvvmfx-books-example/pom.xml | 2 +- examples/mvvmfx-cdi-starter/pom.xml | 2 +- examples/mvvmfx-complex-example/pom.xml | 2 +- examples/mvvmfx-contacts/pom.xml | 2 +- examples/mvvmfx-fx-root-example/pom.xml | 2 +- examples/mvvmfx-guice-starter/pom.xml | 2 +- examples/mvvmfx-helloworld-without-fxml/pom.xml | 2 +- examples/mvvmfx-helloworld/pom.xml | 2 +- examples/mvvmfx-synchronizefx/pom.xml | 2 +- examples/mvvmfx-todomvc/pom.xml | 2 +- examples/pom.xml | 2 +- mvvmfx-archetype/pom.xml | 2 +- mvvmfx-cdi/pom.xml | 2 +- mvvmfx-guice/pom.xml | 2 +- mvvmfx-testing-utils/pom.xml | 2 +- mvvmfx-utils/pom.xml | 2 +- mvvmfx/pom.xml | 2 +- pom.xml | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/mvvmfx-books-example/pom.xml b/examples/mvvmfx-books-example/pom.xml index d6973bcae..60b157c29 100644 --- a/examples/mvvmfx-books-example/pom.xml +++ b/examples/mvvmfx-books-example/pom.xml @@ -5,7 +5,7 @@ mvvmfx-examples de.saxsys - 1.1.0 + 1.2.0-SNAPSHOT 4.0.0 diff --git a/examples/mvvmfx-cdi-starter/pom.xml b/examples/mvvmfx-cdi-starter/pom.xml index df39f83f6..6b1d727ca 100644 --- a/examples/mvvmfx-cdi-starter/pom.xml +++ b/examples/mvvmfx-cdi-starter/pom.xml @@ -12,7 +12,7 @@ de.saxsys mvvmfx-examples - 1.1.0 + 1.2.0-SNAPSHOT diff --git a/examples/mvvmfx-complex-example/pom.xml b/examples/mvvmfx-complex-example/pom.xml index 96742d5b4..10b2f45c5 100644 --- a/examples/mvvmfx-complex-example/pom.xml +++ b/examples/mvvmfx-complex-example/pom.xml @@ -7,7 +7,7 @@ de.saxsys mvvmfx-examples - 1.1.0 + 1.2.0-SNAPSHOT UTF-8 diff --git a/examples/mvvmfx-contacts/pom.xml b/examples/mvvmfx-contacts/pom.xml index 36979565e..1b7d42376 100644 --- a/examples/mvvmfx-contacts/pom.xml +++ b/examples/mvvmfx-contacts/pom.xml @@ -6,7 +6,7 @@ mvvmfx-examples de.saxsys - 1.1.0 + 1.2.0-SNAPSHOT mvvmfx-contacts diff --git a/examples/mvvmfx-fx-root-example/pom.xml b/examples/mvvmfx-fx-root-example/pom.xml index e0d937162..648c89adf 100644 --- a/examples/mvvmfx-fx-root-example/pom.xml +++ b/examples/mvvmfx-fx-root-example/pom.xml @@ -7,7 +7,7 @@ de.saxsys mvvmfx-examples - 1.1.0 + 1.2.0-SNAPSHOT diff --git a/examples/mvvmfx-guice-starter/pom.xml b/examples/mvvmfx-guice-starter/pom.xml index c7f638b35..6a4f7b2c4 100644 --- a/examples/mvvmfx-guice-starter/pom.xml +++ b/examples/mvvmfx-guice-starter/pom.xml @@ -12,7 +12,7 @@ de.saxsys mvvmfx-examples - 1.1.0 + 1.2.0-SNAPSHOT UTF-8 diff --git a/examples/mvvmfx-helloworld-without-fxml/pom.xml b/examples/mvvmfx-helloworld-without-fxml/pom.xml index 25405f948..17f498898 100644 --- a/examples/mvvmfx-helloworld-without-fxml/pom.xml +++ b/examples/mvvmfx-helloworld-without-fxml/pom.xml @@ -7,7 +7,7 @@ de.saxsys mvvmfx-examples - 1.1.0 + 1.2.0-SNAPSHOT diff --git a/examples/mvvmfx-helloworld/pom.xml b/examples/mvvmfx-helloworld/pom.xml index 3ddaf16d8..52ac5e6b4 100644 --- a/examples/mvvmfx-helloworld/pom.xml +++ b/examples/mvvmfx-helloworld/pom.xml @@ -6,7 +6,7 @@ de.saxsys mvvmfx-examples - 1.1.0 + 1.2.0-SNAPSHOT UTF-8 diff --git a/examples/mvvmfx-synchronizefx/pom.xml b/examples/mvvmfx-synchronizefx/pom.xml index 35dd05c12..f491419f7 100644 --- a/examples/mvvmfx-synchronizefx/pom.xml +++ b/examples/mvvmfx-synchronizefx/pom.xml @@ -6,7 +6,7 @@ de.saxsys mvvmfx-examples - 1.1.0 + 1.2.0-SNAPSHOT UTF-8 diff --git a/examples/mvvmfx-todomvc/pom.xml b/examples/mvvmfx-todomvc/pom.xml index bd26ad217..54aa9668d 100644 --- a/examples/mvvmfx-todomvc/pom.xml +++ b/examples/mvvmfx-todomvc/pom.xml @@ -5,7 +5,7 @@ mvvmfx-examples de.saxsys - 1.1.0 + 1.2.0-SNAPSHOT 4.0.0 diff --git a/examples/pom.xml b/examples/pom.xml index 0de3d42b4..5bf530277 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ de.saxsys mvvmfx-parent - 1.1.0 + 1.2.0-SNAPSHOT mvvmfx-examples diff --git a/mvvmfx-archetype/pom.xml b/mvvmfx-archetype/pom.xml index a000fdd2a..bd2e00edc 100644 --- a/mvvmfx-archetype/pom.xml +++ b/mvvmfx-archetype/pom.xml @@ -5,7 +5,7 @@ de.saxsys mvvmfx-parent - 1.1.0 + 1.2.0-SNAPSHOT diff --git a/mvvmfx-cdi/pom.xml b/mvvmfx-cdi/pom.xml index a8770c37c..f15a6b65d 100644 --- a/mvvmfx-cdi/pom.xml +++ b/mvvmfx-cdi/pom.xml @@ -20,7 +20,7 @@ de.saxsys mvvmfx-parent - 1.1.0 + 1.2.0-SNAPSHOT mvvmfx-cdi diff --git a/mvvmfx-guice/pom.xml b/mvvmfx-guice/pom.xml index e3286cff9..732637005 100644 --- a/mvvmfx-guice/pom.xml +++ b/mvvmfx-guice/pom.xml @@ -20,7 +20,7 @@ de.saxsys mvvmfx-parent - 1.1.0 + 1.2.0-SNAPSHOT mvvmfx-guice diff --git a/mvvmfx-testing-utils/pom.xml b/mvvmfx-testing-utils/pom.xml index 883a3dd80..8312eb0c1 100644 --- a/mvvmfx-testing-utils/pom.xml +++ b/mvvmfx-testing-utils/pom.xml @@ -5,7 +5,7 @@ mvvmfx-parent de.saxsys - 1.1.0 + 1.2.0-SNAPSHOT 4.0.0 diff --git a/mvvmfx-utils/pom.xml b/mvvmfx-utils/pom.xml index 0dba16603..3a0f3385f 100644 --- a/mvvmfx-utils/pom.xml +++ b/mvvmfx-utils/pom.xml @@ -5,7 +5,7 @@ mvvmfx-parent de.saxsys - 1.1.0 + 1.2.0-SNAPSHOT 4.0.0 diff --git a/mvvmfx/pom.xml b/mvvmfx/pom.xml index 67508b864..f01e3b514 100644 --- a/mvvmfx/pom.xml +++ b/mvvmfx/pom.xml @@ -20,7 +20,7 @@ de.saxsys mvvmfx-parent - 1.1.0 + 1.2.0-SNAPSHOT mvvmfx diff --git a/pom.xml b/pom.xml index 582fbb308..1d361d430 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ de.saxsys mvvmfx-parent pom - 1.1.0 + 1.2.0-SNAPSHOT mvvmFX parent Application Framework for MVVM with JavaFX. http://www.saxsys.de From e16963ff7f979da96edb305f3fb2a99789f2678d Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Tue, 21 Apr 2015 12:21:48 +0200 Subject: [PATCH 02/28] Books example now uses the new command feature --- .../saxsys/mvvmfx/examples/books/MainView.java | 5 ++++- .../mvvmfx/examples/books/MainViewModel.java | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainView.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainView.java index d06af259d..33d6abb79 100644 --- a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainView.java +++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainView.java @@ -55,9 +55,12 @@ public void initialize() { viewModel.selectedBookProperty().bind(bookList.getSelectionModel().selectedItemProperty()); errorLabel.textProperty().bind(viewModel.errorProperty()); + + searchButton.disableProperty().bind(viewModel.getSearchCommand().executableProperty().not()); + } public void searchButtonPressed() { - viewModel.search(); + viewModel.getSearchCommand().execute(); } } diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java index 96028b276..41cda68b4 100644 --- a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java +++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java @@ -4,11 +4,10 @@ import de.saxsys.mvvmfx.examples.books.backend.Book; import de.saxsys.mvvmfx.examples.books.backend.Error; import de.saxsys.mvvmfx.examples.books.backend.LibraryService; +import de.saxsys.mvvmfx.utils.commands.Command; +import de.saxsys.mvvmfx.utils.commands.DelegateCommand; import eu.lestard.advanced_bindings.api.ObjectBindings; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; +import javafx.beans.property.*; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -32,17 +31,24 @@ public class MainViewModel implements ViewModel { private ObjectProperty selectedBook = new SimpleObjectProperty<>(); private StringProperty error = new SimpleStringProperty(); + + private Command seachCommand; public MainViewModel(LibraryService libraryService) { this.libraryService = libraryService; + + seachCommand = new DelegateCommand(this::search); bookTitle.bind(ObjectBindings.map(selectedBook, bookItem -> bookItem.getBook().getTitle())); bookAuthor.bind(ObjectBindings.map(selectedBook, bookItem -> bookItem.getBook().getAuthor())); bookDescription.bind(ObjectBindings.map(selectedBook, bookItem -> bookItem.getBook().getDesc())); } - - public void search() { + public Command getSearchCommand() { + return seachCommand; + } + + void search() { Consumer errorHandler = err -> error.set(err.getMessage()); final List result = libraryService.search(searchString.get(), errorHandler); From 2e416a5a6beeafb245f0ffade83543396a795a2e Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Tue, 21 Apr 2015 12:43:38 +0200 Subject: [PATCH 03/28] add test case that describes the target for this issue --- .../mvvmfx/utils/mapping/ExampleModel.java | 102 ++++++++++++++++++ .../mvvmfx/utils/mapping/ReturnTypeTest.java | 71 ++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java new file mode 100644 index 000000000..caa4b85d9 --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java @@ -0,0 +1,102 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import javafx.beans.property.*; + +public class ExampleModel { + + private IntegerProperty integerProperty = new SimpleIntegerProperty(); + private DoubleProperty doubleProperty = new SimpleDoubleProperty(); + private FloatProperty floatProperty = new SimpleFloatProperty(); + private LongProperty longProperty = new SimpleLongProperty(); + + private StringProperty stringProperty = new SimpleStringProperty(); + + private ObjectProperty objectProperty = new SimpleObjectProperty<>(); + + private BooleanProperty booleanProperty = new SimpleBooleanProperty(); + + + public int getInteger() { + return integerProperty.get(); + } + + public IntegerProperty integerProperty() { + return integerProperty; + } + + public void setInteger(int integerProperty) { + this.integerProperty.set(integerProperty); + } + + public double getDouble() { + return doubleProperty.get(); + } + + public DoubleProperty doubleProperty() { + return doubleProperty; + } + + public void setDouble(double doubleProperty) { + this.doubleProperty.set(doubleProperty); + } + + public float getFloat() { + return floatProperty.get(); + } + + public FloatProperty floatProperty() { + return floatProperty; + } + + public void setFloat(float floatProperty) { + this.floatProperty.set(floatProperty); + } + + public long getLong() { + return longProperty.get(); + } + + public LongProperty longProperty() { + return longProperty; + } + + public void setLong(long longProperty) { + this.longProperty.set(longProperty); + } + + public String getString() { + return stringProperty.get(); + } + + public StringProperty stringProperty() { + return stringProperty; + } + + public void setString(String stringProperty) { + this.stringProperty.set(stringProperty); + } + + public Person getObject() { + return objectProperty.get(); + } + + public ObjectProperty objectProperty() { + return objectProperty; + } + + public void setObject(Person objectProperty) { + this.objectProperty.set(objectProperty); + } + + public boolean getBoolean() { + return booleanProperty.get(); + } + + public BooleanProperty booleanProperty() { + return booleanProperty; + } + + public void setBoolean(boolean booleanProperty) { + this.booleanProperty.set(booleanProperty); + } +} diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java new file mode 100644 index 000000000..3b39f0ef8 --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java @@ -0,0 +1,71 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import org.junit.Before; + +/** + * This test is used to check the return values when fields are mapped. + * See Isseu 211 https://github.com/sialcasa/mvvmFX/issues/211 + */ +public class ReturnTypeTest { + + private ModelWrapper wrapper; + + private ExampleModel model; + + @Before + public void setup(){ + wrapper = new ModelWrapper<>(); + model = new ExampleModel(); + } + + + // The following code is commented out because it doesn't compile at the moment + // Its a target description on how we would like the API to be. + +// @Test +// public void integerProperty(){ +// final IntegerProperty beanField = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger); +// final IntegerProperty fxField = wrapper.field(ExampleModel::integerProperty); +// } +// +// @Test +// public void doubleProperty(){ +// final DoubleProperty beanField = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble); +// final DoubleProperty fxField = wrapper.field(ExampleModel::doubleProperty); +// } +// +// +// @Test +// public void longProperty(){ +// final LongProperty beanField = wrapper.field(ExampleModel::getLong, ExampleModel::setLong); +// final LongProperty fxField = wrapper.field(ExampleModel::longProperty); +// } +// +// +// @Test +// public void floatProperty(){ +// final FloatProperty beanField = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat); +// final FloatProperty fxField = wrapper.field(ExampleModel::floatProperty); +// } +// +// +// @Test +// public void booleanProperty(){ +// final BooleanProperty beanField = wrapper.field(ExampleModel::getBoolean, ExampleModel::setBoolean); +// final BooleanProperty fxField = wrapper.field(ExampleModel::booleanProperty); +// } +// +// +// @Test +// public void stringProperty(){ +// final StringProperty beanField = wrapper.field(ExampleModel::getString, ExampleModel::setString); +// final StringProperty fxField = wrapper.field(ExampleModel::stringProperty); +// } +// +// @Test +// public void objectProperty(){ +// final ObjectProperty beanField = wrapper.field(ExampleModel::getObject, ExampleModel::setObject); +// final ObjectProperty fxField = wrapper.field(ExampleModel::objectProperty); +// } + +} From d52c21f331cedb44007dab98489454d5f32a9594 Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Wed, 22 Apr 2015 14:14:23 +0200 Subject: [PATCH 04/28] #211 first attempt for better return types --- .../ui/contactform/ContactFormViewModel.java | 16 +- .../mvvmfx/utils/mapping/BooleanGetter.java | 6 + .../mapping/BooleanPropertyAccessor.java | 8 + .../mvvmfx/utils/mapping/BooleanSetter.java | 6 + .../mvvmfx/utils/mapping/DoubleGetter.java | 6 + .../utils/mapping/DoublePropertyAccessor.java | 8 + .../mvvmfx/utils/mapping/DoubleSetter.java | 6 + .../mvvmfx/utils/mapping/FloatGetter.java | 6 + .../utils/mapping/FloatPropertyAccessor.java | 8 + .../mvvmfx/utils/mapping/FloatSetter.java | 6 + .../mvvmfx/utils/mapping/IntGetter.java | 6 + .../utils/mapping/IntPropertyAccessor.java | 8 + .../mvvmfx/utils/mapping/IntSetter.java | 6 + .../mvvmfx/utils/mapping/LongGetter.java | 6 + .../utils/mapping/LongPropertyAccessor.java | 8 + .../mvvmfx/utils/mapping/LongSetter.java | 6 + .../mvvmfx/utils/mapping/ModelWrapper.java | 711 +++++++++++------- .../mvvmfx/utils/mapping/ObjectGetter.java | 6 + .../utils/mapping/ObjectPropertyAccessor.java | 8 + .../mvvmfx/utils/mapping/ObjectSetter.java | 6 + .../mvvmfx/utils/mapping/StringGetter.java | 6 + .../utils/mapping/StringPropertyAccessor.java | 8 + .../mvvmfx/utils/mapping/StringSetter.java | 6 + .../utils/mapping/ModelWrapperTest.java | 29 +- .../mvvmfx/utils/mapping/ReturnTypeTest.java | 97 ++- 25 files changed, 631 insertions(+), 362 deletions(-) create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoublePropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringSetter.java diff --git a/examples/mvvmfx-contacts/src/main/java/de/saxsys/mvvmfx/contacts/ui/contactform/ContactFormViewModel.java b/examples/mvvmfx-contacts/src/main/java/de/saxsys/mvvmfx/contacts/ui/contactform/ContactFormViewModel.java index b494c7125..a8a9d9a8f 100644 --- a/examples/mvvmfx-contacts/src/main/java/de/saxsys/mvvmfx/contacts/ui/contactform/ContactFormViewModel.java +++ b/examples/mvvmfx-contacts/src/main/java/de/saxsys/mvvmfx/contacts/ui/contactform/ContactFormViewModel.java @@ -78,23 +78,23 @@ public ReadOnlyBooleanProperty validProperty() { - public Property firstnameProperty() { + public StringProperty firstnameProperty() { return contactWrapper.field("firstname", Contact::getFirstname, Contact::setFirstname); } - public Property titleProperty() { + public StringProperty titleProperty() { return contactWrapper.field("title", Contact::getTitle, Contact::setTitle); } - public Property lastnameProperty() { + public StringProperty lastnameProperty() { return contactWrapper.field("lastname", Contact::getLastname, Contact::setLastname); } - public Property roleProperty() { + public StringProperty roleProperty() { return contactWrapper.field("role", Contact::getRole, Contact::setRole); } - public Property departmentProperty() { + public StringProperty departmentProperty() { return contactWrapper.field("department", Contact::getDepartment, Contact::setDepartment); } @@ -102,15 +102,15 @@ public Property birthdayProperty() { return contactWrapper.field("birthday", Contact::getBirthday, Contact::setBirthday); } - public Property emailProperty() { + public StringProperty emailProperty() { return contactWrapper.field("email", Contact::getEmailAddress, Contact::setEmailAddress); } - public Property mobileNumberProperty() { + public StringProperty mobileNumberProperty() { return contactWrapper.field("mobileNumber", Contact::getMobileNumber, Contact::setMobileNumber); } - public Property phoneNumberProperty() { + public StringProperty phoneNumberProperty() { return contactWrapper.field("phoneNumber", Contact::getPhoneNumber, Contact::setPhoneNumber); } } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanGetter.java new file mode 100644 index 000000000..8e8ecdcd2 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanGetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.Function; + +public interface BooleanGetter extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanPropertyAccessor.java new file mode 100644 index 000000000..7f4ab16d9 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanPropertyAccessor.java @@ -0,0 +1,8 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import javafx.beans.property.Property; + +import java.util.function.Function; + +public interface BooleanPropertyAccessor extends Function> { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanSetter.java new file mode 100644 index 000000000..6a5f22f88 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanSetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.BiConsumer; + +public interface BooleanSetter extends BiConsumer { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleGetter.java new file mode 100644 index 000000000..96bcc6efc --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleGetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.Function; + +public interface DoubleGetter extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoublePropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoublePropertyAccessor.java new file mode 100644 index 000000000..b82abef50 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoublePropertyAccessor.java @@ -0,0 +1,8 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import javafx.beans.property.DoubleProperty; + +import java.util.function.Function; + +public interface DoublePropertyAccessor extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleSetter.java new file mode 100644 index 000000000..5c6c9cd90 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleSetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.BiConsumer; + +public interface DoubleSetter extends BiConsumer { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatGetter.java new file mode 100644 index 000000000..4148bdc69 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatGetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.Function; + +public interface FloatGetter extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatPropertyAccessor.java new file mode 100644 index 000000000..410f9db89 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatPropertyAccessor.java @@ -0,0 +1,8 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import javafx.beans.property.FloatProperty; + +import java.util.function.Function; + +public interface FloatPropertyAccessor extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatSetter.java new file mode 100644 index 000000000..6718e733d --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatSetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.BiConsumer; + +public interface FloatSetter extends BiConsumer { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntGetter.java new file mode 100644 index 000000000..1832cf8ad --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntGetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.Function; + +public interface IntGetter extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntPropertyAccessor.java new file mode 100644 index 000000000..cb0e6affb --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntPropertyAccessor.java @@ -0,0 +1,8 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import javafx.beans.property.IntegerProperty; + +import java.util.function.Function; + +public interface IntPropertyAccessor extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntSetter.java new file mode 100644 index 000000000..5aadd5e5e --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntSetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.BiConsumer; + +public interface IntSetter extends BiConsumer{ +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongGetter.java new file mode 100644 index 000000000..b5d07ba85 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongGetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.Function; + +public interface LongGetter extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongPropertyAccessor.java new file mode 100644 index 000000000..d61d6dacb --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongPropertyAccessor.java @@ -0,0 +1,8 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import javafx.beans.property.LongProperty; + +import java.util.function.Function; + +public interface LongPropertyAccessor extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongSetter.java new file mode 100644 index 000000000..2e2222762 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongSetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.BiConsumer; + +public interface LongSetter extends BiConsumer { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java index a42a62db3..3ba7fa955 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java @@ -1,10 +1,7 @@ package de.saxsys.mvvmfx.utils.mapping; import eu.lestard.doc.Beta; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.Property; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.WritableValue; +import javafx.beans.property.*; import java.util.HashMap; import java.util.HashSet; @@ -12,6 +9,7 @@ import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Function; +import java.util.function.Supplier; /** @@ -193,14 +191,14 @@ public class ModelWrapper { * @param * @param */ - private interface PropertyField { + private interface PropertyField> { void commit(M wrappedObject); void reload(M wrappedObject); void resetToDefault(); - Property getProperty(); + R getProperty(); } /** @@ -209,25 +207,26 @@ private interface PropertyField { * * @param */ - private class FxPropertyField implements PropertyField { + private class FxPropertyField> implements PropertyField { private final T defaultValue; - private final Function> accessor; - private final ObjectProperty targetProperty; + private final Function> accessor; + private final R targetProperty; - public FxPropertyField(Function> accessor) { - this(accessor, null); + public FxPropertyField(Function> accessor, Supplier> propertySupplier) { + this(accessor, null, propertySupplier); } - - public FxPropertyField(Function> accessor, T defaultValue) { + + @SuppressWarnings("unchecked") + public FxPropertyField(Function> accessor, T defaultValue, Supplier> propertySupplier) { this.accessor = accessor; this.defaultValue = defaultValue; - this.targetProperty = new SimpleObjectProperty<>(); + this.targetProperty = (R)propertySupplier.get(); } @Override public void commit(M wrappedObject) { - accessor.apply(wrappedObject).setValue(targetProperty.get()); + accessor.apply(wrappedObject).setValue(targetProperty.getValue()); } @Override @@ -241,7 +240,7 @@ public void resetToDefault() { } @Override - public Property getProperty() { + public R getProperty() { return targetProperty; } } @@ -252,30 +251,30 @@ public Property getProperty() { * * @param */ - private class BeanPropertyField implements PropertyField { + private class BeanPropertyField> implements PropertyField { - private final ObjectProperty targetProperty; + private final R targetProperty; private final T defaultValue; private final Function getter; private final BiConsumer setter; public BeanPropertyField(Function getter, - BiConsumer setter) { - this(getter, setter, null); + BiConsumer setter, Supplier propertySupplier) { + this(getter, setter, null, propertySupplier); } public BeanPropertyField(Function getter, - BiConsumer setter, T defaultValue) { + BiConsumer setter, T defaultValue, Supplier propertySupplier) { this.defaultValue = defaultValue; this.getter = getter; this.setter = setter; - this.targetProperty = new SimpleObjectProperty<>(); + this.targetProperty = propertySupplier.get(); } @Override public void commit(M wrappedObject) { - setter.accept(wrappedObject, targetProperty.get()); + setter.accept(wrappedObject, targetProperty.getValue()); } @Override @@ -289,14 +288,14 @@ public void resetToDefault() { } @Override - public Property getProperty() { + public R getProperty() { return targetProperty; } } - private Set> fields = new HashSet<>(); - private Map> identifiedFields = new HashMap<>(); + private Set> fields = new HashSet<>(); + private Map> identifiedFields = new HashMap<>(); private M model; @@ -374,274 +373,412 @@ public void reload() { fields.forEach(field -> field.reload(model)); } } - - /** - * Add a new field to this instance of the wrapper. This method is used for model elements that are following the - * enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties. - *

- * Example: - *

- * - *

-	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-	 *     
-	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.nameProperty());
-	 *     
-	 *     // or with a method reference
-	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::nameProperty);
-	 * 
-	 * 
- * - * - * @param accessor - * a function that returns the property for a given model instance. Typically you will use a method - * reference to the javafx-property accessor method. - * - * @param - * the type of the field. - * - * @return The wrapped property instance. - */ - public Property field(Function> accessor) { - return add(new FxPropertyField<>(accessor)); + + public BooleanProperty field(BooleanGetter getter, BooleanSetter setter) { + return add(new BeanPropertyField<>(getter, setter, SimpleBooleanProperty::new)); } - - /** - * Add a new field to this instance of the wrapper. This method is used for model elements that are following the - * enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties. - *

- * Additionally you can define a default value that is used as when {@link #reset()} is invoked. - * - *

- * - * Example: - *

- * - *

-	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-	 * 
-	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.nameProperty(), "empty");
-	 * 
-	 *     // or with a method reference
-	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::nameProperty, "empty");
-	 *
-	 * 
- * - * - * @param accessor - * a function that returns the property for a given model instance. Typically you will use a method - * reference to the javafx-property accessor method. - * @param defaultValue - * the default value for the field. - * @param - * the type of the field. - * - * @return The wrapped property instance. - */ - public Property field(Function> accessor, T defaultValue) { - return add(new FxPropertyField<>(accessor, defaultValue)); + + public BooleanProperty field(BooleanPropertyAccessor accessor) { + return add(new FxPropertyField<>(accessor, SimpleBooleanProperty::new)); } - - /** - * Add a new field to this instance of the wrapper. This method is used for model elements that are following the - * normal Java-Beans-standard i.e. the model fields are only available via getter and setter methods and not as - * JavaFX Properties. - * - *

- * - * Example: - *

- * - *

-	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-	 * 
-	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value) -> person.setName(value), "empty");
-	 * 
-	 *     // or with a method reference
-	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
-	 *
-	 * 
- * - * - * @param getter - * a function that returns the current value of the field for a given model element. Typically you will - * use a method reference to the getter method of the model element. - * @param setter - * a function that sets the given value to the given model element. Typically you will use a method - * reference to the setter method of the model element. - * @param - * the type of the field. - * - * @return The wrapped property instance. - */ - public Property field(Function getter, BiConsumer setter) { - return add(new BeanPropertyField<>(getter, setter)); + + public BooleanProperty field(String identifier, BooleanGetter getter, BooleanSetter setter) { + return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleBooleanProperty::new)); } - - /** - * Add a new field to this instance of the wrapper. This method is used for model elements that are following the - * normal Java-Beans-standard i.e. the model fields are only available via getter and setter methods and not as - * JavaFX Properties. - *

- * Additionally you can define a default value that is used as when {@link #reset()} is invoked. - * - *

- * - * Example: - *

- * - *

-	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-	 * 
-	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value) -> person.setName(value), "empty");
-	 * 
-	 *     // or with a method reference
-	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
-	 *
-	 * 
- * - * - * @param getter - * a function that returns the current value of the field for a given model element. Typically you will - * use a method reference to the getter method of the model element. - * @param setter - * a function that sets the given value to the given model element. Typically you will use a method - * reference to the setter method of the model element. - * @param defaultValue - * the default value for the field. - * @param - * the type of the field. - * - * @return The wrapped property instance. - */ - public Property field(Function getter, BiConsumer setter, T defaultValue) { - return add(new BeanPropertyField<>(getter, setter, defaultValue)); + + public BooleanProperty field(String identifier, BooleanPropertyAccessor accessor) { + return addIdentified(identifier, new FxPropertyField<>(accessor, SimpleBooleanProperty::new)); } - - - /** - * Add a new field to this instance of the wrapper that is identified by the given string. This method is basically - * the same as {@link #field(Function)} with one difference: This method can be invoked multiply times but will only - * create a single field instance for every given string identifier. This means that the returned property will be - * the same instance for each call with the same identifier. - *

- * This behaviour can be useful when you don't keep a reference to the returned property but directly call this - * method in a property accessor method in your viewModel. This way only a single field wrapping will be defined - * even when the accessor method is called multiple times. See the following example of a typical use case: - *

- * - *

-	 * 
-	 *     public class PersonViewModel extends ViewModel {
-	 *         
-	 *         // you only need a reference to the model wrapper itself but no additional references to each wrapped property.
-	 *         private ModelWrapper{@code} wrapper = new ModelWrapper{@code<>}();
-	 *         
-	 *         
-	 *         // This method will be used from the view. 
-	 *         // The view can call this method multiple times but will always get the same property instance.
-	 *         public Property{@code} nameProperty() {
-	 *              return wrapper.field("name", Person::nameProperty);
-	 *         }
-	 *     }
-	 * 
- * - * - * @param fieldName - * the identifier for this field. Typically you will use the name of the field in the model. - * @param accessor - * a function that returns the property for a given model instance. Typically you will use a method - * reference to the javafx-property accessor method. - * @param - * the type of the field. - * @return The wrapped property instance. - */ - public Property field(String fieldName, Function> accessor) { - return addIdentified(fieldName, new FxPropertyField<>(accessor)); + + + public DoubleProperty field(DoubleGetter getter, DoubleSetter setter) { + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), SimpleDoubleProperty::new)); } - - /** - * See {@link #field(String, Function)}. The difference is that this method accepts an additional parameter to - * define the default value that will be used when {@link #reset()} is invoked. - * - * @param fieldName - * the identifier for this field. Typically you will use the name of the field in the model. - * @param accessor - * a function that returns the property for a given model instance. Typically you will use a method - * reference to the javafx-property accessor method. - * @param - * the type of the field. - * @return The wrapped property instance. - */ - public Property field(String fieldName, Function> accessor, T defaultValue) { - return addIdentified(fieldName, new FxPropertyField<>(accessor, defaultValue)); + + public DoubleProperty field(DoublePropertyAccessor accessor) { + return add(new FxPropertyField<>(accessor::apply, SimpleDoubleProperty::new)); } - - /** - * Add a new field to this instance of the wrapper that is identified by the given string. This method is basically - * the same as {@link #field(Function, BiConsumer)} with one difference: This method can be invoked multiply times - * but will only create a single field instance for every given string identifier. This means that the returned - * property will be the same instance for each call with the same identifier. - *

- * This behaviour can be useful when you don't keep a reference to the returned property but directly call this - * method in a property accessor method in your viewModel. This way only a single field wrapping will be defined - * even when the accessor method is called multiple times. See the following example of a typical use case: - *

- * - *

-	 *
-	 *     public class PersonViewModel extends ViewModel {
-	 * 
-	 *         // you only need a reference to the model wrapper itself but no additional references to each wrapped property.
-	 *         private ModelWrapper{@code} wrapper = new ModelWrapper{@code<>}();
-	 * 
-	 * 
-	 *         // This method will be used from the view. 
-	 *         // The view can call this method multiple times but will always get the same property instance.
-	 *         public Property{@code} nameProperty() {
-	 *              return wrapper.field("name", Person::getName, Person::setName);
-	 *         }
-	 *     }
-	 * 
- * - * - * @param fieldName - * the identifier for this field. Typically you will use the name of the field in the model. - * @param getter - * a function that returns the current value of the field for a given model element. Typically you will - * use a method reference to the getter method of the model element. - * @param setter - * a function that sets the given value to the given model element. Typically you will use a method - * reference to the setter method of the model element. - * @param - * the type of the field. - * @return The wrapped property instance. - */ - public Property field(String fieldName, Function getter, BiConsumer setter) { - return addIdentified(fieldName, new BeanPropertyField<>(getter, setter)); + + public DoubleProperty field(String identifier, DoubleGetter getter, DoubleSetter setter) { + return addIdentified(identifier, new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), SimpleDoubleProperty::new)); } - - /** - * See {@link #field(String, Function, BiConsumer)}. The difference is that this method accepts an additional - * parameter to define the default value that will be used when {@link #reset()} is invoked. - * - * @param fieldName - * the identifier for this field. Typically you will use the name of the field in the model. - * @param getter - * a function that returns the current value of the field for a given model element. Typically you will - * use a method reference to the getter method of the model element. - * @param setter - * a function that sets the given value to the given model element. Typically you will use a method - * reference to the setter method of the model element. - * @param - * the type of the field. - * @return The wrapped property instance. - */ - public Property field(String fieldName, Function getter, BiConsumer setter, T defaultValue) { - return addIdentified(fieldName, new BeanPropertyField<>(getter, setter, defaultValue)); + + public DoubleProperty field(String identifier, DoublePropertyAccessor accessor) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleDoubleProperty::new)); + } + + + + + + + public FloatProperty field(FloatGetter getter, FloatSetter setter) { + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), SimpleFloatProperty::new)); + } + + public FloatProperty field(FloatPropertyAccessor accessor) { + return add(new FxPropertyField<>(accessor::apply, SimpleFloatProperty::new)); + } + + public FloatProperty field(String identifier, FloatGetter getter, FloatSetter setter) { + return addIdentified(identifier, new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), SimpleFloatProperty::new)); + } + + public FloatProperty field(String identifier, FloatPropertyAccessor accessor) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleFloatProperty::new)); + } + + + + + public IntegerProperty field(IntGetter getter, IntSetter setter) { + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), SimpleIntegerProperty::new)); + } + + public IntegerProperty field(IntPropertyAccessor accessor) { + return add(new FxPropertyField<>(accessor::apply, SimpleIntegerProperty::new)); } + + public IntegerProperty field(String identifier, IntGetter getter, IntSetter setter) { + return addIdentified(identifier, new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), SimpleIntegerProperty::new)); + } + + public IntegerProperty field(String identifier, IntPropertyAccessor accessor) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleIntegerProperty::new)); + } + + + + + public LongProperty field(LongGetter getter, LongSetter setter) { + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()), SimpleLongProperty::new)); + } + + public LongProperty field(LongPropertyAccessor accessor) { + return add(new FxPropertyField<>(accessor::apply, SimpleLongProperty::new)); + } + + public LongProperty field(String identifier, LongGetter getter, LongSetter setter) { + return addIdentified(identifier, new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()), SimpleLongProperty::new)); + } + + public LongProperty field(String identifier, LongPropertyAccessor accessor) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleLongProperty::new)); + } + + + + + + public ObjectProperty field(ObjectGetter getter, ObjectSetter setter) { + return add(new BeanPropertyField<>(getter, setter, SimpleObjectProperty::new)); + } + + public ObjectProperty field(ObjectPropertyAccessor accessor) { + return add(new FxPropertyField<>(accessor::apply, SimpleObjectProperty::new)); + } + + public ObjectProperty field(String identifier, ObjectGetter getter, ObjectSetter setter) { + return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleObjectProperty::new)); + } + + public ObjectProperty field(String identifier, ObjectPropertyAccessor accessor) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleObjectProperty::new)); + } + + + + + + public StringProperty field(StringGetter getter, StringSetter setter) { + return add(new BeanPropertyField<>(getter, setter, SimpleStringProperty::new)); + } + + public StringProperty field(StringPropertyAccessor accessor) { + return add(new FxPropertyField<>(accessor::apply, SimpleStringProperty::new)); + } + + public StringProperty field(String identifier, StringGetter getter, StringSetter setter) { + return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleStringProperty::new)); + } + + public StringProperty field(String identifier, StringPropertyAccessor accessor) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleStringProperty::new)); + } + + +// +// /** +// * Add a new field to this instance of the wrapper. This method is used for model elements that are following the +// * enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties. +// *

+// * Example: +// *

+// * +// *

+//	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
+//	 *
+//	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.nameProperty());
+//	 *
+//	 *     // or with a method reference
+//	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::nameProperty);
+//	 *
+//	 * 
+// * +// * +// * @param accessor +// * a function that returns the property for a given model instance. Typically you will use a method +// * reference to the javafx-property accessor method. +// * +// * @param +// * the type of the field. +// * +// * @return The wrapped property instance. +// */ +// public Property field(Function> accessor) { +// return add(new FxPropertyField<>(accessor)); +// } +// +// /** +// * Add a new field to this instance of the wrapper. This method is used for model elements that are following the +// * enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties. +// *

+// * Additionally you can define a default value that is used as when {@link #reset()} is invoked. +// * +// *

+// * +// * Example: +// *

+// * +// *

+//	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
+//	 *
+//	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.nameProperty(), "empty");
+//	 *
+//	 *     // or with a method reference
+//	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::nameProperty, "empty");
+//	 *
+//	 * 
+// * +// * +// * @param accessor +// * a function that returns the property for a given model instance. Typically you will use a method +// * reference to the javafx-property accessor method. +// * @param defaultValue +// * the default value for the field. +// * @param +// * the type of the field. +// * +// * @return The wrapped property instance. +// */ +// public Property field(Function> accessor, T defaultValue) { +// return add(new FxPropertyField<>(accessor, defaultValue)); +// } +// +// /** +// * Add a new field to this instance of the wrapper. This method is used for model elements that are following the +// * normal Java-Beans-standard i.e. the model fields are only available via getter and setter methods and not as +// * JavaFX Properties. +// * +// *

+// * +// * Example: +// *

+// * +// *

+//	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
+//	 *
+//	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value) -> person.setName(value), "empty");
+//	 *
+//	 *     // or with a method reference
+//	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
+//	 *
+//	 * 
+// * +// * +// * @param getter +// * a function that returns the current value of the field for a given model element. Typically you will +// * use a method reference to the getter method of the model element. +// * @param setter +// * a function that sets the given value to the given model element. Typically you will use a method +// * reference to the setter method of the model element. +// * @param +// * the type of the field. +// * +// * @return The wrapped property instance. +// */ +// public Property field(Function getter, BiConsumer setter) { +// return add(new BeanPropertyField<>(getter, setter)); +// } +// +// +// +// +// +// /** +// * Add a new field to this instance of the wrapper. This method is used for model elements that are following the +// * normal Java-Beans-standard i.e. the model fields are only available via getter and setter methods and not as +// * JavaFX Properties. +// *

+// * Additionally you can define a default value that is used as when {@link #reset()} is invoked. +// * +// *

+// * +// * Example: +// *

+// * +// *

+//	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
+//	 *
+//	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value) -> person.setName(value), "empty");
+//	 *
+//	 *     // or with a method reference
+//	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
+//	 *
+//	 * 
+// * +// * +// * @param getter +// * a function that returns the current value of the field for a given model element. Typically you will +// * use a method reference to the getter method of the model element. +// * @param setter +// * a function that sets the given value to the given model element. Typically you will use a method +// * reference to the setter method of the model element. +// * @param defaultValue +// * the default value for the field. +// * @param +// * the type of the field. +// * +// * @return The wrapped property instance. +// */ +// public Property field(Function getter, BiConsumer setter, T defaultValue) { +// return add(new BeanPropertyField<>(getter, setter, defaultValue)); +// } +// +// +// /** +// * Add a new field to this instance of the wrapper that is identified by the given string. This method is basically +// * the same as {@link #field(Function)} with one difference: This method can be invoked multiply times but will only +// * create a single field instance for every given string identifier. This means that the returned property will be +// * the same instance for each call with the same identifier. +// *

+// * This behaviour can be useful when you don't keep a reference to the returned property but directly call this +// * method in a property accessor method in your viewModel. This way only a single field wrapping will be defined +// * even when the accessor method is called multiple times. See the following example of a typical use case: +// *

+// * +// *

+//	 *
+//	 *     public class PersonViewModel extends ViewModel {
+//	 *
+//	 *         // you only need a reference to the model wrapper itself but no additional references to each wrapped property.
+//	 *         private ModelWrapper{@code} wrapper = new ModelWrapper{@code<>}();
+//	 *
+//	 *
+//	 *         // This method will be used from the view.
+//	 *         // The view can call this method multiple times but will always get the same property instance.
+//	 *         public Property{@code} nameProperty() {
+//	 *              return wrapper.field("name", Person::nameProperty);
+//	 *         }
+//	 *     }
+//	 * 
+// * +// * +// * @param fieldName +// * the identifier for this field. Typically you will use the name of the field in the model. +// * @param accessor +// * a function that returns the property for a given model instance. Typically you will use a method +// * reference to the javafx-property accessor method. +// * @param +// * the type of the field. +// * @return The wrapped property instance. +// */ +// public Property field(String fieldName, Function> accessor) { +// return addIdentified(fieldName, new FxPropertyField<>(accessor)); +// } +// +// /** +// * See {@link #field(String, Function)}. The difference is that this method accepts an additional parameter to +// * define the default value that will be used when {@link #reset()} is invoked. +// * +// * @param fieldName +// * the identifier for this field. Typically you will use the name of the field in the model. +// * @param accessor +// * a function that returns the property for a given model instance. Typically you will use a method +// * reference to the javafx-property accessor method. +// * @param +// * the type of the field. +// * @return The wrapped property instance. +// */ +// public Property field(String fieldName, Function> accessor, T defaultValue) { +// return addIdentified(fieldName, new FxPropertyField<>(accessor, defaultValue)); +// } +// +// /** +// * Add a new field to this instance of the wrapper that is identified by the given string. This method is basically +// * the same as {@link #field(Function, BiConsumer)} with one difference: This method can be invoked multiply times +// * but will only create a single field instance for every given string identifier. This means that the returned +// * property will be the same instance for each call with the same identifier. +// *

+// * This behaviour can be useful when you don't keep a reference to the returned property but directly call this +// * method in a property accessor method in your viewModel. This way only a single field wrapping will be defined +// * even when the accessor method is called multiple times. See the following example of a typical use case: +// *

+// * +// *

+//	 *
+//	 *     public class PersonViewModel extends ViewModel {
+//	 *
+//	 *         // you only need a reference to the model wrapper itself but no additional references to each wrapped property.
+//	 *         private ModelWrapper{@code} wrapper = new ModelWrapper{@code<>}();
+//	 *
+//	 *
+//	 *         // This method will be used from the view.
+//	 *         // The view can call this method multiple times but will always get the same property instance.
+//	 *         public Property{@code} nameProperty() {
+//	 *              return wrapper.field("name", Person::getName, Person::setName);
+//	 *         }
+//	 *     }
+//	 * 
+// * +// * +// * @param fieldName +// * the identifier for this field. Typically you will use the name of the field in the model. +// * @param getter +// * a function that returns the current value of the field for a given model element. Typically you will +// * use a method reference to the getter method of the model element. +// * @param setter +// * a function that sets the given value to the given model element. Typically you will use a method +// * reference to the setter method of the model element. +// * @param +// * the type of the field. +// * @return The wrapped property instance. +// */ +// public Property field(String fieldName, Function getter, BiConsumer setter) { +// return addIdentified(fieldName, new BeanPropertyField<>(getter, setter)); +// } +// +// /** +// * See {@link #field(String, Function, BiConsumer)}. The difference is that this method accepts an additional +// * parameter to define the default value that will be used when {@link #reset()} is invoked. +// * +// * @param fieldName +// * the identifier for this field. Typically you will use the name of the field in the model. +// * @param getter +// * a function that returns the current value of the field for a given model element. Typically you will +// * use a method reference to the getter method of the model element. +// * @param setter +// * a function that sets the given value to the given model element. Typically you will use a method +// * reference to the setter method of the model element. +// * @param +// * the type of the field. +// * @return The wrapped property instance. +// */ +// public Property field(String fieldName, Function getter, BiConsumer setter, T defaultValue) { +// return addIdentified(fieldName, new BeanPropertyField<>(getter, setter, defaultValue)); +// } - private Property add(PropertyField field) { + private > R add(PropertyField field) { fields.add(field); if (model != null) { field.reload(model); @@ -650,10 +787,10 @@ private Property add(PropertyField field) { } @SuppressWarnings("unchecked") - private Property addIdentified(String fieldName, PropertyField field) { + private > R addIdentified(String fieldName, PropertyField field) { if (identifiedFields.containsKey(fieldName)) { final Property property = identifiedFields.get(fieldName).getProperty(); - return (Property) property; + return (R) property; } else { identifiedFields.put(fieldName, field); return add(field); diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectGetter.java new file mode 100644 index 000000000..8234bbc1d --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectGetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.Function; + +public interface ObjectGetter extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectPropertyAccessor.java new file mode 100644 index 000000000..3baa5700e --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectPropertyAccessor.java @@ -0,0 +1,8 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import javafx.beans.property.Property; + +import java.util.function.Function; + +public interface ObjectPropertyAccessor extends Function> { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectSetter.java new file mode 100644 index 000000000..ae0747056 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectSetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.BiConsumer; + +public interface ObjectSetter extends BiConsumer { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringGetter.java new file mode 100644 index 000000000..241740f0f --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringGetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.Function; + +public interface StringGetter extends Function { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringPropertyAccessor.java new file mode 100644 index 000000000..7ab9a5fc4 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringPropertyAccessor.java @@ -0,0 +1,8 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import javafx.beans.property.Property; + +import java.util.function.Function; + +public interface StringPropertyAccessor extends Function> { +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringSetter.java new file mode 100644 index 000000000..ce38958e8 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringSetter.java @@ -0,0 +1,6 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import java.util.function.BiConsumer; + +public interface StringSetter extends BiConsumer { +} diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java index 0d2a334df..9394cbbac 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java @@ -1,14 +1,7 @@ package de.saxsys.mvvmfx.utils.mapping; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.binding.IntegerBinding; -import javafx.beans.binding.IntegerExpression; -import javafx.beans.binding.NumberBinding; import javafx.beans.property.IntegerProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.Property; -import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.StringProperty; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -24,8 +17,8 @@ public void testWithGetterAndSetter(){ ModelWrapper personWrapper = new ModelWrapper<>(person); - final Property nameProperty = personWrapper.field(Person::getName, Person::setName); - final Property ageProperty = personWrapper.field(Person::getAge, Person::setAge); + final StringProperty nameProperty = personWrapper.field(Person::getName, Person::setName); + final IntegerProperty ageProperty = personWrapper.field(Person::getAge, Person::setAge); assertThat(nameProperty.getValue()).isEqualTo("horst"); assertThat(ageProperty.getValue()).isEqualTo(32); @@ -53,7 +46,7 @@ public void testWithGetterAndSetter(){ personWrapper.reset(); assertThat(nameProperty.getValue()).isEqualTo(null); - assertThat(ageProperty.getValue()).isEqualTo(null); + assertThat(ageProperty.getValue()).isEqualTo(0); // the wrapped object has still the values from the last commit. assertThat(person.getName()).isEqualTo("hugo"); @@ -101,8 +94,8 @@ public void testWithJavaFXPropertiesField() { ModelWrapper personWrapper = new ModelWrapper<>(person); - final Property nameProperty = personWrapper.field(PersonFX::nameProperty); - final Property ageProperty = personWrapper.field(PersonFX::ageProperty); + final StringProperty nameProperty = personWrapper.field(PersonFX::nameProperty); + final IntegerProperty ageProperty = personWrapper.field(PersonFX::ageProperty); assertThat(nameProperty.getValue()).isEqualTo("horst"); assertThat(ageProperty.getValue()).isEqualTo(32); @@ -130,7 +123,7 @@ public void testWithJavaFXPropertiesField() { personWrapper.reset(); assertThat(nameProperty.getValue()).isEqualTo(null); - assertThat(ageProperty.getValue()).isEqualTo(null); + assertThat(ageProperty.getValue()).isEqualTo(0); // the wrapped object has still the values from the last commit. assertThat(person.getName()).isEqualTo("hugo"); @@ -175,12 +168,12 @@ public void testIdentifiedFields(){ ModelWrapper personWrapper = new ModelWrapper<>(); - final Property nameProperty = personWrapper.field("name", Person::getName, Person::setName); - final Property ageProperty = personWrapper.field("age", Person::getAge, Person::setAge); + final StringProperty nameProperty = personWrapper.field("name", Person::getName, Person::setName); + final IntegerProperty ageProperty = personWrapper.field("age", Person::getAge, Person::setAge); - final Property nameProperty2 = personWrapper.field("name", Person::getName, Person::setName); - final Property ageProperty2 = personWrapper.field("age", Person::getAge, Person::setAge); + final StringProperty nameProperty2 = personWrapper.field("name", Person::getName, Person::setName); + final IntegerProperty ageProperty2 = personWrapper.field("age", Person::getAge, Person::setAge); assertThat(nameProperty).isSameAs(nameProperty2); diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java index 3b39f0ef8..00bf5c990 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java @@ -1,10 +1,12 @@ package de.saxsys.mvvmfx.utils.mapping; +import javafx.beans.property.*; import org.junit.Before; +import org.junit.Test; /** * This test is used to check the return values when fields are mapped. - * See Isseu 211 https://github.com/sialcasa/mvvmFX/issues/211 + * See Issue 211 https://github.com/sialcasa/mvvmFX/issues/211 */ public class ReturnTypeTest { @@ -19,53 +21,50 @@ public void setup(){ } - // The following code is commented out because it doesn't compile at the moment - // Its a target description on how we would like the API to be. - -// @Test -// public void integerProperty(){ -// final IntegerProperty beanField = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger); -// final IntegerProperty fxField = wrapper.field(ExampleModel::integerProperty); -// } -// -// @Test -// public void doubleProperty(){ -// final DoubleProperty beanField = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble); -// final DoubleProperty fxField = wrapper.field(ExampleModel::doubleProperty); -// } -// -// -// @Test -// public void longProperty(){ -// final LongProperty beanField = wrapper.field(ExampleModel::getLong, ExampleModel::setLong); -// final LongProperty fxField = wrapper.field(ExampleModel::longProperty); -// } -// -// -// @Test -// public void floatProperty(){ -// final FloatProperty beanField = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat); -// final FloatProperty fxField = wrapper.field(ExampleModel::floatProperty); -// } -// -// -// @Test -// public void booleanProperty(){ -// final BooleanProperty beanField = wrapper.field(ExampleModel::getBoolean, ExampleModel::setBoolean); -// final BooleanProperty fxField = wrapper.field(ExampleModel::booleanProperty); -// } -// -// -// @Test -// public void stringProperty(){ -// final StringProperty beanField = wrapper.field(ExampleModel::getString, ExampleModel::setString); -// final StringProperty fxField = wrapper.field(ExampleModel::stringProperty); -// } -// -// @Test -// public void objectProperty(){ -// final ObjectProperty beanField = wrapper.field(ExampleModel::getObject, ExampleModel::setObject); -// final ObjectProperty fxField = wrapper.field(ExampleModel::objectProperty); -// } + @Test + public void integerProperty(){ + final IntegerProperty beanField = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger); + final IntegerProperty fxField = wrapper.field(ExampleModel::integerProperty); + } + + @Test + public void doubleProperty(){ + final DoubleProperty beanField = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble); + final DoubleProperty fxField = wrapper.field(ExampleModel::doubleProperty); + } + + + @Test + public void longProperty(){ + final LongProperty beanField = wrapper.field(ExampleModel::getLong, ExampleModel::setLong); + final LongProperty fxField = wrapper.field(ExampleModel::longProperty); + } + + + @Test + public void floatProperty(){ + final FloatProperty beanField = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat); + final FloatProperty fxField = wrapper.field(ExampleModel::floatProperty); + } + + + @Test + public void booleanProperty(){ + final BooleanProperty beanField = wrapper.field(ExampleModel::getBoolean, ExampleModel::setBoolean); + final BooleanProperty fxField = wrapper.field(ExampleModel::booleanProperty); + } + + + @Test + public void stringProperty(){ + final StringProperty beanField = wrapper.field(ExampleModel::getString, ExampleModel::setString); + final StringProperty fxField = wrapper.field(ExampleModel::stringProperty); + } + + @Test + public void objectProperty(){ + final ObjectProperty beanField = wrapper.field(ExampleModel::getObject, ExampleModel::setObject); + final ObjectProperty fxField = wrapper.field(ExampleModel::objectProperty); + } } From 8b68a239974e098002f28c6294023e48da7d444b Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Fri, 24 Apr 2015 19:57:14 +0200 Subject: [PATCH 05/28] -Lazy implemented: -- Negated Property for .runningProperty() -> .notRunningProperty() -- Negated Property for .executableProperty() -> .not executableProperty() -Made running / executable getters / setters in CommandBase final -Modified Example https://github.com/sialcasa/mvvmFX/issues/210 --- .../view/personlogin/PersonLoginView.java | 2 +- .../saxsys/mvvmfx/utils/commands/Command.java | 29 ++++++++- .../mvvmfx/utils/commands/CommandBase.java | 47 +++++++++++--- .../utils/commands/CompositeCommandTest.java | 64 +++++++++++++++---- .../utils/commands/DelegateCommandTest.java | 12 ++++ 5 files changed, 130 insertions(+), 24 deletions(-) diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java index 5a2918746..ed3b8f5a3 100644 --- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java +++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java @@ -43,7 +43,7 @@ public void initialize(URL url, ResourceBundle resourceBundle) { loginCommand = getViewModel().getLoginCommand(); initChoiceBox(); loginButton.disableProperty() - .bind(loginCommand.executableProperty().not()); + .bind(loginCommand.notExecutableProperty()); loginProgressIndicator.visibleProperty().bind(loginCommand.runningProperty()); } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Command.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Command.java index 55b565ac5..66c98b70c 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Command.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Command.java @@ -15,8 +15,8 @@ ******************************************************************************/ package de.saxsys.mvvmfx.utils.commands; -import eu.lestard.doc.Beta; import javafx.beans.property.ReadOnlyBooleanProperty; +import eu.lestard.doc.Beta; /** * The {@link Command} encapsulates logic in the {@link #execute()} method which will be called later. This can be used @@ -50,6 +50,18 @@ public interface Command { */ ReadOnlyBooleanProperty executableProperty(); + /** + * Determines whether the command can not execute in it's current state. + * + * @return true if the {@link Command} can not execute, otherwise false. + */ + boolean isNotExecutable(); + + /** + * @see #isNotExecutable() + */ + ReadOnlyBooleanProperty notExecutableProperty(); + /** * Signals whether the command is currently executing. This can be useful especially for commands that are executed @@ -64,4 +76,19 @@ public interface Command { */ ReadOnlyBooleanProperty runningProperty(); + /** + * Signals whether the command is currently not executing. This can be useful especially for commands that are + * executed asynchronously. + * + * @return true if the {@link Command} is not running, otherwise false. + */ + boolean isNotRunning(); + + /** + * @see #isNotRunning() + */ + ReadOnlyBooleanProperty notRunningProperty(); + + + } \ No newline at end of file diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CommandBase.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CommandBase.java index 331af0f61..a81b04344 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CommandBase.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CommandBase.java @@ -32,24 +32,55 @@ public abstract class CommandBase implements Command { protected final ReadOnlyBooleanWrapper executable = new ReadOnlyBooleanWrapper(true); protected final ReadOnlyBooleanWrapper running = new ReadOnlyBooleanWrapper(false); + protected ReadOnlyBooleanWrapper notExecutable; + protected ReadOnlyBooleanWrapper notRunning; + + @Override + public final ReadOnlyBooleanProperty executableProperty() { + return executable.getReadOnlyProperty(); + } + + @Override + public final boolean isExecutable() { + return executableProperty().get(); + } + + @Override + public final ReadOnlyBooleanProperty notExecutableProperty() { + if (notExecutable == null) { + notExecutable = new ReadOnlyBooleanWrapper(); + notExecutable.bind(executableProperty().not()); + } + return notExecutable.getReadOnlyProperty(); + } + + @Override + public final boolean isNotExecutable() { + return notExecutableProperty().get(); + } + @Override - public ReadOnlyBooleanProperty executableProperty() { - return this.executable.getReadOnlyProperty(); + public final ReadOnlyBooleanProperty runningProperty() { + return running.getReadOnlyProperty(); } @Override - public boolean isExecutable() { - return this.executableProperty().get(); + public final boolean isRunning() { + return running.get(); } @Override - public ReadOnlyBooleanProperty runningProperty() { - return this.running.getReadOnlyProperty(); + public final ReadOnlyBooleanProperty notRunningProperty() { + if (notRunning == null) { + notRunning = new ReadOnlyBooleanWrapper(); + notRunning.bind(runningProperty().not()); + } + return notRunning.getReadOnlyProperty(); } @Override - public boolean isRunning() { - return this.running.get(); + public final boolean isNotRunning() { + return notRunningProperty().get(); } @Override diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java index 8f1edd66a..75f2ff223 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java @@ -1,19 +1,21 @@ package de.saxsys.mvvmfx.utils.commands; -import de.saxsys.mvvmfx.testingutils.GCVerifier; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; + import org.junit.Before; import org.junit.Test; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import de.saxsys.mvvmfx.testingutils.GCVerifier; public class CompositeCommandTest { @@ -42,22 +44,27 @@ public void executable() throws Exception { GCVerifier.forceGC(); assertTrue(compositeCommand.isExecutable()); + assertFalse(compositeCommand.isNotExecutable()); condition1.set(false); assertFalse(compositeCommand.isExecutable()); + assertTrue(compositeCommand.isNotExecutable()); condition2.set(false); assertFalse(compositeCommand.isExecutable()); + assertTrue(compositeCommand.isNotExecutable()); condition1.set(true); assertFalse(compositeCommand.isExecutable()); + assertTrue(compositeCommand.isNotExecutable()); condition2.set(true); assertTrue(compositeCommand.isExecutable()); + assertFalse(compositeCommand.isNotExecutable()); } @Test @@ -67,28 +74,35 @@ public void executable2() throws Exception { assertThat(compositeCommand.isExecutable()).isTrue(); + assertThat(compositeCommand.isNotExecutable()).isFalse(); compositeCommand.register(delegateCommand1); GCVerifier.forceGC(); assertThat(compositeCommand.isExecutable()).isTrue(); + assertThat(compositeCommand.isNotExecutable()).isFalse(); condition1.setValue(false); assertThat(compositeCommand.isExecutable()).isFalse(); + assertThat(compositeCommand.isNotExecutable()).isTrue(); condition1.setValue(true); assertThat(compositeCommand.isExecutable()).isTrue(); + assertThat(compositeCommand.isNotExecutable()).isFalse(); condition2.setValue(false); assertThat(compositeCommand.isExecutable()).isTrue(); + assertThat(compositeCommand.isNotExecutable()).isFalse(); compositeCommand.register(delegateCommand2); GCVerifier.forceGC(); assertThat(compositeCommand.isExecutable()).isFalse(); + assertThat(compositeCommand.isNotExecutable()).isTrue(); compositeCommand.unregister(delegateCommand2); GCVerifier.forceGC(); assertThat(compositeCommand.isExecutable()).isTrue(); + assertThat(compositeCommand.isNotExecutable()).isFalse(); } @Test @@ -97,12 +111,17 @@ public void register() throws Exception { CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1); assertTrue(compositeCommand.isExecutable()); + assertFalse(compositeCommand.isNotExecutable()); // prepare delegateCommand2 condition2.set(false); + compositeCommand.register(delegateCommand2); assertFalse(compositeCommand.isExecutable()); + assertTrue(compositeCommand.isNotExecutable()); + compositeCommand.unregister(delegateCommand2); assertTrue(compositeCommand.isExecutable()); + assertFalse(compositeCommand.isNotExecutable()); } @Test @@ -114,10 +133,14 @@ public void running() throws Exception { // We have to check the running Property with this mechanism, because it is processed synchronously and we can't // hook between the state changes. compositeCommand.runningProperty().addListener((ChangeListener) (observable, oldValue, newValue) -> { - if (!oldValue && newValue) + if (!oldValue && newValue) { run.set(true); - if (oldValue && !newValue) + assertTrue(compositeCommand.runningProperty().get()); + } + if (oldValue && !newValue) { finished.set(true); + assertFalse(compositeCommand.runningProperty().get()); + } }); compositeCommand.execute(); @@ -127,10 +150,11 @@ public void running() throws Exception { } @Test - public void allCommandsAreUnregistered() throws Exception{ + public void allCommandsAreUnregistered() throws Exception { // UncaughtExceptionHandler is defined to be able to detect exception from listeners. - Thread.currentThread().setUncaughtExceptionHandler((thread, exception) -> fail("Exception was thrown", exception)); + Thread.currentThread().setUncaughtExceptionHandler( + (thread, exception) -> fail("Exception was thrown", exception)); CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1, delegateCommand2); @@ -156,13 +180,17 @@ public void longRunningAsyncComposite() throws Exception { }, condition, false); CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1, delegateCommand2, delegateCommand3); - + GCVerifier.forceGC(); - + assertFalse(compositeCommand.runningProperty().get()); assertFalse(delegateCommand1.runningProperty().get()); assertFalse(delegateCommand2.runningProperty().get()); assertFalse(delegateCommand3.runningProperty().get()); + assertTrue(compositeCommand.notRunningProperty().get()); + assertTrue(delegateCommand1.notRunningProperty().get()); + assertTrue(delegateCommand2.notRunningProperty().get()); + assertTrue(delegateCommand3.notRunningProperty().get()); compositeCommand.execute(); @@ -170,6 +198,10 @@ public void longRunningAsyncComposite() throws Exception { assertTrue(delegateCommand1.runningProperty().get()); assertTrue(delegateCommand2.runningProperty().get()); assertFalse(delegateCommand3.runningProperty().get()); + assertFalse(compositeCommand.notRunningProperty().get()); + assertFalse(delegateCommand1.notRunningProperty().get()); + assertFalse(delegateCommand2.notRunningProperty().get()); + assertTrue(delegateCommand3.notRunningProperty().get()); future.get(3, TimeUnit.SECONDS); @@ -177,6 +209,10 @@ public void longRunningAsyncComposite() throws Exception { assertFalse(delegateCommand1.runningProperty().get()); assertFalse(delegateCommand2.runningProperty().get()); assertFalse(delegateCommand3.runningProperty().get()); + assertTrue(compositeCommand.notRunningProperty().get()); + assertTrue(delegateCommand1.notRunningProperty().get()); + assertTrue(delegateCommand2.notRunningProperty().get()); + assertTrue(delegateCommand3.notRunningProperty().get()); } private void sleep(long millis) { diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java index 27d7e9491..f3288a0fa 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java @@ -23,14 +23,17 @@ public void executable() { }, condition); assertTrue(delegateCommand.isExecutable()); + assertFalse(delegateCommand.isNotExecutable()); condition.set(false); assertFalse(delegateCommand.isExecutable()); + assertTrue(delegateCommand.isNotExecutable()); condition.set(true); assertTrue(delegateCommand.isExecutable()); + assertFalse(delegateCommand.isNotExecutable()); } @Test @@ -69,9 +72,11 @@ public void running() throws Exception { delegateCommand.runningProperty().addListener((ChangeListener) (observable, oldValue, newValue) -> { if (!oldValue && newValue) { run.set(true); + assertFalse(delegateCommand.notRunningProperty().get()); } if (oldValue && !newValue) { finished.set(true); + assertTrue(delegateCommand.notRunningProperty().get()); } }); @@ -97,12 +102,19 @@ public void longRunningAsync() throws Exception { }, condition, true); assertFalse(delegateCommand.runningProperty().get()); + assertTrue(delegateCommand.notRunningProperty().get()); delegateCommand.execute(); + assertTrue(delegateCommand.runningProperty().get()); + assertFalse(delegateCommand.notRunningProperty().get()); assertFalse(delegateCommand.executableProperty().get()); + assertTrue(delegateCommand.notExecutableProperty().get()); + future.get(3, TimeUnit.SECONDS); assertFalse(delegateCommand.runningProperty().get()); + assertTrue(delegateCommand.notRunningProperty().get()); assertTrue(delegateCommand.executableProperty().get()); + assertFalse(delegateCommand.notExecutableProperty().get()); } } From e766855c608999697e6532cc0b5af7f7e427ffe2 Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Sat, 25 Apr 2015 20:15:49 +0200 Subject: [PATCH 06/28] First implementation + Test --- .../main/java/de/saxsys/mvvmfx/ViewModel.java | 13 ++ .../DefaultNotificationCenter.java | 117 ++++++++++++++---- .../notifications/NotificationCenter.java | 15 +++ .../DefaultNotificationCenterTest.java | 29 +++++ 4 files changed, 151 insertions(+), 23 deletions(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java index 5c6d60260..91550ca61 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java @@ -17,6 +17,7 @@ import de.saxsys.mvvmfx.internal.viewloader.View; import de.saxsys.mvvmfx.utils.notifications.NotificationCenter; +import de.saxsys.mvvmfx.utils.notifications.NotificationObserver; /** *

@@ -33,4 +34,16 @@ * */ public interface ViewModel { + + default void publish(ViewModel viewModel, String notificationId, Object... args) { + MvvmFX.getNotificationCenter().publish(this, notificationId, args); + } + + default void publish(String notificationId, Object... args) { + publish(this, notificationId, args); + } + + default void subscribe(String message, NotificationObserver observer) { + MvvmFX.getNotificationCenter().subscribe(this, message, observer); + } } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java index 11faa8592..b7f0962d8 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java @@ -20,7 +20,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; + +import de.saxsys.mvvmfx.ViewModel; /** * Default implementation of {@link NotificationCenter}. @@ -33,51 +34,121 @@ class DefaultNotificationCenter implements NotificationCenter { DefaultNotificationCenter() { } - private final Map> observersForName = new HashMap>(); + private final ObserverMap globalObservers = new ObserverMap(); + private final ViewModelObservers viewModelObservers = new ViewModelObservers(); @Override public void subscribe(String messageName, NotificationObserver observer) { - List observers = this.observersForName.get(messageName); - if (observers == null) { - this.observersForName.put(messageName, new ArrayList()); - } - observers = this.observersForName.get(messageName); - observers.add(observer); + addObserver(messageName, observer, globalObservers); } @Override public void unsubscribe(String messageName, NotificationObserver observer) { - List observers = this.observersForName.get(messageName); - observers.remove(observer); - if (observers.size() == 0) { - this.observersForName.remove(messageName); - } + removeObserversForMessageName(messageName, observer, globalObservers); } @Override public void unsubscribe(NotificationObserver observer) { - Iterator iterator = this.observersForName.keySet().iterator(); + removeAllObserver(observer, globalObservers); + } + + @Override + public void publish(String messageName, Object... payload) { + publish(messageName, payload, globalObservers); + } + + @Override + public void publish(ViewModel viewModel, String messageName, Object[] payload) { + ObserverMap observerMap = viewModelObservers.get(viewModel); + if (observerMap != null) { + publish(messageName, payload, observerMap); + } + } + + + @Override + public void subscribe(ViewModel view, String messageName, NotificationObserver observer) { + ObserverMap observerMap = viewModelObservers.get(view); + if (observerMap == null) { + observerMap = new ObserverMap(); + viewModelObservers.put(view, observerMap); + } + addObserver(messageName, observer, observerMap); + } + + @Override + public void unsubscribe(ViewModel view, String messageName, NotificationObserver observer) { + ObserverMap observerMap = viewModelObservers.get(view); + if (observerMap != null) { + removeObserversForMessageName(messageName, observer, observerMap); + } + } + + + @Override + public void unsubscribe(ViewModel view, NotificationObserver observer) { + ObserverMap observerMap = viewModelObservers.get(view); + + removeAllObserver(observer, observerMap); + + } + + /* + * Helper + */ + + private void publish(String messageName, Object[] payload, ObserverMap observerMap) { + Collection notificationReceivers = observerMap.get(messageName); + if (notificationReceivers != null) { + for (NotificationObserver observer : notificationReceivers) { + observer.receivedNotification(messageName, payload); + } + } + } + + private void addObserver(String messageName, NotificationObserver observer, ObserverMap observerMap) { + List observers = observerMap.get(messageName); + if (observers == null) { + observerMap.put(messageName, new ArrayList()); + } + observers = observerMap.get(messageName); + observers.add(observer); + } + + + + private void removeAllObserver(NotificationObserver observer, ObserverMap observerMap) { + Iterator iterator = observerMap.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); - Iterator iterator2 = this.observersForName.get(key).iterator(); + Iterator iterator2 = observerMap.get(key).iterator(); while (iterator2.hasNext()) { NotificationObserver actualObserver = iterator2.next(); if (actualObserver == observer) { - this.observersForName.remove(key); + observerMap.remove(key); break; } } } } - @Override - public void publish(String messageName, Object... payload) { - Collection notificationReceivers = observersForName.get(messageName); - if (notificationReceivers != null) { - for (NotificationObserver observer : notificationReceivers) { - observer.receivedNotification(messageName, payload); - } + private void removeObserversForMessageName(String messageName, NotificationObserver observer, + ObserverMap observerMap) { + List observers = observerMap.get(messageName); + observers.remove(observer); + if (observers.size() == 0) { + observerMap.remove(messageName); } } + @SuppressWarnings("serial") + private class ObserverMap extends HashMap> { + } + + @SuppressWarnings("serial") + private class ViewModelObservers extends HashMap { + } + + + } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java index c996645cf..1cfb45088 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java @@ -15,6 +15,8 @@ ******************************************************************************/ package de.saxsys.mvvmfx.utils.notifications; +import de.saxsys.mvvmfx.ViewModel; + /** * Central component to provide a notification mechanism. You can add observers by using keys to get notifications for @@ -71,4 +73,17 @@ void unsubscribe(String messageName, */ void publish(String messageName, Object... payload); + + + void publish(ViewModel viewModel, String messageName, Object[] payload); + + void subscribe(ViewModel view, String messageName, + NotificationObserver observer); + + void unsubscribe(ViewModel view, String messageName, + NotificationObserver observer); + + void unsubscribe(ViewModel view, + NotificationObserver observer); + } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java index 3a352632f..d9588872c 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java @@ -16,10 +16,18 @@ package de.saxsys.mvvmfx.utils.notifications; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import de.saxsys.mvvmfx.ViewModel; + public class DefaultNotificationCenterTest { private static final String TEST_NOTIFICATION = "test_notification"; @@ -84,6 +92,27 @@ public void addAndRemoveObserverForNameToDefaultNotificationCenterAndPostNotific Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION); } + @Test + public void addViewModelObserverToDefaultNotificationCenterAndPostNotificationToView() throws Exception { + + StringProperty receivedMessageId = new SimpleStringProperty(); + ObjectProperty receivedPayload = new SimpleObjectProperty<>(); + + ViewModel viewModel = new ViewModel() { + }; + + viewModel.subscribe(TEST_NOTIFICATION, (key, payload) -> { + receivedPayload.set(payload); + receivedMessageId.set(key); + }); + + viewModel.publish(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); + + Assert.assertEquals(TEST_NOTIFICATION, receivedMessageId.get()); + Assert.assertArrayEquals(OBJECT_ARRAY_FOR_NOTIFICATION, receivedPayload.get()); + + } + private class DummyNotificationObserver implements NotificationObserver { @Override public void receivedNotification(String key, Object... payload) { From fe7638c29c835b399303cb7b046e979e4ad3950c Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Sat, 25 Apr 2015 20:42:02 +0200 Subject: [PATCH 07/28] -unsubscription -refactoring of tests -fixed bug in defaultnotificationcenter --- .../main/java/de/saxsys/mvvmfx/ViewModel.java | 8 ++ .../DefaultNotificationCenter.java | 14 ++-- .../java/de/saxsys/mvvmfx/ViewModelTest.java | 82 +++++++++++++++++++ .../DefaultNotificationCenterTest.java | 32 +------- 4 files changed, 99 insertions(+), 37 deletions(-) create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/ViewModelTest.java diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java index 91550ca61..b86591463 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java @@ -46,4 +46,12 @@ default void publish(String notificationId, Object... args) { default void subscribe(String message, NotificationObserver observer) { MvvmFX.getNotificationCenter().subscribe(this, message, observer); } + + default void unsubscribe(String message, NotificationObserver observer) { + MvvmFX.getNotificationCenter().unsubscribe(this, message, observer); + } + + default void unsubscribe(NotificationObserver observer) { + MvvmFX.getNotificationCenter().unsubscribe(this, observer); + } } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java index b7f0962d8..cd4d5c4a7 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java @@ -49,7 +49,7 @@ public void unsubscribe(String messageName, NotificationObserver observer) { @Override public void unsubscribe(NotificationObserver observer) { - removeAllObserver(observer, globalObservers); + removeObserverFromObserverMap(observer, globalObservers); } @Override @@ -86,11 +86,9 @@ public void unsubscribe(ViewModel view, String messageName, NotificationObserver @Override - public void unsubscribe(ViewModel view, NotificationObserver observer) { - ObserverMap observerMap = viewModelObservers.get(view); - - removeAllObserver(observer, observerMap); - + public void unsubscribe(ViewModel viewModel, NotificationObserver observer) { + ObserverMap observerMap = viewModelObservers.get(viewModel); + removeObserverFromObserverMap(observer, observerMap); } /* @@ -117,7 +115,7 @@ private void addObserver(String messageName, NotificationObserver observer, Obse - private void removeAllObserver(NotificationObserver observer, ObserverMap observerMap) { + private void removeObserverFromObserverMap(NotificationObserver observer, ObserverMap observerMap) { Iterator iterator = observerMap.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); @@ -125,7 +123,7 @@ private void removeAllObserver(NotificationObserver observer, ObserverMap observ while (iterator2.hasNext()) { NotificationObserver actualObserver = iterator2.next(); if (actualObserver == observer) { - observerMap.remove(key); + observerMap.get(key).remove(actualObserver); break; } } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/ViewModelTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/ViewModelTest.java new file mode 100644 index 000000000..1224e2250 --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/ViewModelTest.java @@ -0,0 +1,82 @@ +package de.saxsys.mvvmfx; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import de.saxsys.mvvmfx.utils.notifications.NotificationObserver; + +public class ViewModelTest { + + private static final String TEST_NOTIFICATION = "test_notification"; + private static final Object[] OBJECT_ARRAY_FOR_NOTIFICATION = new String[] { "test" }; + + ViewModel viewModel; + DummyNotificationObserver observer1; + DummyNotificationObserver observer2; + DummyNotificationObserver observer3; + + @Before + public void init() { + observer1 = Mockito.mock(DummyNotificationObserver.class); + observer2 = Mockito.mock(DummyNotificationObserver.class); + observer3 = Mockito.mock(DummyNotificationObserver.class); + viewModel = new ViewModel() { + }; + } + + @Test + public void addObserverAndPublish() throws Exception { + viewModel.subscribe(TEST_NOTIFICATION, observer1); + viewModel.publish(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); + Mockito.verify(observer1).receivedNotification(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); + } + + @Test + public void addAndRemoveObserverAndPublish() throws Exception { + viewModel.subscribe(TEST_NOTIFICATION, observer1); + viewModel.unsubscribe(observer1); + viewModel.publish(TEST_NOTIFICATION); + Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION); + + viewModel.subscribe(TEST_NOTIFICATION, observer1); + viewModel.unsubscribe(TEST_NOTIFICATION, observer1); + viewModel.publish(TEST_NOTIFICATION); + Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION); + } + + @Test + public void addMultipleObserverAndPublish() throws Exception { + viewModel.subscribe(TEST_NOTIFICATION, observer1); + viewModel.subscribe(TEST_NOTIFICATION, observer2); + viewModel.subscribe(TEST_NOTIFICATION, observer3); + viewModel.publish(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); + Mockito.verify(observer1).receivedNotification(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); + Mockito.verify(observer2).receivedNotification(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); + Mockito.verify(observer3).receivedNotification(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); + } + + + @Test + public void addMultipleObserverAndRemoveOneAndPublish() throws Exception { + viewModel.subscribe(TEST_NOTIFICATION, observer1); + viewModel.subscribe(TEST_NOTIFICATION, observer2); + viewModel.subscribe(TEST_NOTIFICATION, observer3); + viewModel.unsubscribe(observer1); + viewModel.publish(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); + + Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION, + OBJECT_ARRAY_FOR_NOTIFICATION); + Mockito.verify(observer2).receivedNotification(TEST_NOTIFICATION, + OBJECT_ARRAY_FOR_NOTIFICATION); + Mockito.verify(observer3).receivedNotification(TEST_NOTIFICATION, + OBJECT_ARRAY_FOR_NOTIFICATION); + } + + private class DummyNotificationObserver implements NotificationObserver { + @Override + public void receivedNotification(String key, Object... payload) { + + } + } +} diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java index d9588872c..2cac321fd 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java @@ -16,18 +16,10 @@ package de.saxsys.mvvmfx.utils.notifications; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; - -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -import de.saxsys.mvvmfx.ViewModel; - public class DefaultNotificationCenterTest { private static final String TEST_NOTIFICATION = "test_notification"; @@ -68,8 +60,11 @@ public void addAndRemoveObserverToDefaultNotificationCenterAndPostNotification() defaultCenter.subscribe(TEST_NOTIFICATION, observer2); defaultCenter.subscribe(TEST_NOTIFICATION, observer3); defaultCenter.unsubscribe(observer1); + defaultCenter.unsubscribe(observer2); defaultCenter.publish(TEST_NOTIFICATION); Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION); + Mockito.verify(observer2, Mockito.never()).receivedNotification(TEST_NOTIFICATION); + Mockito.verify(observer3).receivedNotification(TEST_NOTIFICATION); } @Test @@ -92,27 +87,6 @@ public void addAndRemoveObserverForNameToDefaultNotificationCenterAndPostNotific Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION); } - @Test - public void addViewModelObserverToDefaultNotificationCenterAndPostNotificationToView() throws Exception { - - StringProperty receivedMessageId = new SimpleStringProperty(); - ObjectProperty receivedPayload = new SimpleObjectProperty<>(); - - ViewModel viewModel = new ViewModel() { - }; - - viewModel.subscribe(TEST_NOTIFICATION, (key, payload) -> { - receivedPayload.set(payload); - receivedMessageId.set(key); - }); - - viewModel.publish(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION); - - Assert.assertEquals(TEST_NOTIFICATION, receivedMessageId.get()); - Assert.assertArrayEquals(OBJECT_ARRAY_FOR_NOTIFICATION, receivedPayload.get()); - - } - private class DummyNotificationObserver implements NotificationObserver { @Override public void receivedNotification(String key, Object... payload) { From 16a7930cf8997adce7dc7cf7f04adb21f501f8dd Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Sat, 25 Apr 2015 20:57:14 +0200 Subject: [PATCH 08/28] Publish in UI Thread, because the target is the view --- mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java index b86591463..c1a491f7e 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java @@ -15,6 +15,7 @@ ******************************************************************************/ package de.saxsys.mvvmfx; +import javafx.application.Platform; import de.saxsys.mvvmfx.internal.viewloader.View; import de.saxsys.mvvmfx.utils.notifications.NotificationCenter; import de.saxsys.mvvmfx.utils.notifications.NotificationObserver; @@ -40,7 +41,11 @@ default void publish(ViewModel viewModel, String notificationId, Object... args) } default void publish(String notificationId, Object... args) { - publish(this, notificationId, args); + if (!Platform.isFxApplicationThread()) { + Platform.runLater(() -> publish(ViewModel.this, notificationId, args)); + } else { + publish(this, notificationId, args); + } } default void subscribe(String message, NotificationObserver observer) { From 5d60e29851bf25a15c9dd3e4a9996c3be7f39e3c Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Sat, 25 Apr 2015 20:57:29 +0200 Subject: [PATCH 09/28] Example of usage --- .../view/personlogin/PersonLoginView.java | 11 +++++++++++ .../viewmodel/personlogin/PersonLoginViewModel.java | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java index 5a2918746..706bc4eb0 100644 --- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java +++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java @@ -7,10 +7,13 @@ import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.ChoiceBox; import javafx.scene.control.ProgressIndicator; import de.saxsys.jfx.exampleapplication.viewmodel.personlogin.PersonLoginViewModel; +import de.saxsys.jfx.exampleapplication.viewmodel.personlogin.PersonLoginViewModelNotifications; import de.saxsys.mvvmfx.FxmlView; import de.saxsys.mvvmfx.InjectViewModel; import de.saxsys.mvvmfx.utils.commands.Command; @@ -45,6 +48,14 @@ public void initialize(URL url, ResourceBundle resourceBundle) { loginButton.disableProperty() .bind(loginCommand.executableProperty().not()); loginProgressIndicator.visibleProperty().bind(loginCommand.runningProperty()); + + viewModel.subscribe(PersonLoginViewModelNotifications.OK.getId(), (key, payload) -> { + String message = (String) payload[0]; + Alert alert = new Alert(AlertType.INFORMATION); + alert.setTitle(message); + alert.setContentText(message); + alert.show(); + }); } @FXML diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java index 36a0e8de6..b1a3b7ea9 100644 --- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java +++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java @@ -88,6 +88,6 @@ private void performLogin() { Platform.runLater(() -> { loggedInPersonId.set(selectablePersons.getSelectedItem().getId()); }); + publish(PersonLoginViewModelNotifications.OK.getId(), PersonLoginViewModelNotifications.OK.getMessage()); } - } From 116649c14c152ac1e132a1fd384f8b24835a140b Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Sat, 25 Apr 2015 21:35:32 +0200 Subject: [PATCH 10/28] -Fixed Example -Removed a subscribe method in VM - Javadoc --- .../view/personlogin/PersonLoginView.java | 1 + .../PersonLoginViewModelNotifications.java | 19 +++++++ .../main/java/de/saxsys/mvvmfx/ViewModel.java | 49 ++++++++++++++----- .../notifications/NotificationCenter.java | 34 ++++++++++++- 4 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModelNotifications.java diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java index 706bc4eb0..98a847ec0 100644 --- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java +++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personlogin/PersonLoginView.java @@ -56,6 +56,7 @@ public void initialize(URL url, ResourceBundle resourceBundle) { alert.setContentText(message); alert.show(); }); + } @FXML diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModelNotifications.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModelNotifications.java new file mode 100644 index 000000000..da892f95f --- /dev/null +++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModelNotifications.java @@ -0,0 +1,19 @@ +package de.saxsys.jfx.exampleapplication.viewmodel.personlogin; + +public enum PersonLoginViewModelNotifications { + OK("Das Einloggen war erfolgreich"); + + private String message; + + PersonLoginViewModelNotifications(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public String getId() { + return toString(); + } +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java index c1a491f7e..216796212 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java @@ -36,26 +36,53 @@ */ public interface ViewModel { - default void publish(ViewModel viewModel, String notificationId, Object... args) { - MvvmFX.getNotificationCenter().publish(this, notificationId, args); - } - - default void publish(String notificationId, Object... args) { + /** + * Publishes a notification to the subscribers of the notificationId. This notification will be send to the + * UI-Thread. + * + * @param messageName + * of the notification + * @param payload + * to be send + */ + default void publish(String messageName, Object... payload) { if (!Platform.isFxApplicationThread()) { - Platform.runLater(() -> publish(ViewModel.this, notificationId, args)); + MvvmFX.getNotificationCenter().publish(this, messageName, payload); } else { - publish(this, notificationId, args); + MvvmFX.getNotificationCenter().publish(this, messageName, payload); } } - default void subscribe(String message, NotificationObserver observer) { - MvvmFX.getNotificationCenter().subscribe(this, message, observer); + /** + * Subscribe to a notification with a given {@link NotificationObserver}. + * + * @param messageName + * of the Notification + * @param observer + * which should execute when the notification occurs + */ + default void subscribe(String messageName, NotificationObserver observer) { + MvvmFX.getNotificationCenter().subscribe(this, messageName, observer); } - default void unsubscribe(String message, NotificationObserver observer) { - MvvmFX.getNotificationCenter().unsubscribe(this, message, observer); + /** + * Remove the observer for a specific notification by a given messageName. + * + * @param messageName + * of the notification for that the observer should be removed + * @param observer + * to remove + */ + default void unsubscribe(String messageName, NotificationObserver observer) { + MvvmFX.getNotificationCenter().unsubscribe(this, messageName, observer); } + /** + * Removes the observer for all messages. + * + * @param observer + * to be removed + */ default void unsubscribe(NotificationObserver observer) { MvvmFX.getNotificationCenter().unsubscribe(this, observer); } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java index 1cfb45088..69a7b9192 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java @@ -74,15 +74,45 @@ void unsubscribe(String messageName, void publish(String messageName, Object... payload); - + /** + * Publishes a notification to the {@link ViewModel}-subscribers for the given notificationId. + * + * @param messageName + * of the notification + * @param payload + * to be send + */ void publish(ViewModel viewModel, String messageName, Object[] payload); + /** + * Subscribe to a {@link ViewModel}-notification with a given {@link NotificationObserver}. + * + * @param viewModel + * + * @param messageName + * of the Notification + * @param observer + * which should execute when the notification occurs + */ void subscribe(ViewModel view, String messageName, NotificationObserver observer); - void unsubscribe(ViewModel view, String messageName, + /** + * Removes a {@link NotificationObserver} for a given messageName. + * + * @param viewModel + * @param messageName + * @param observer + */ + void unsubscribe(ViewModel viewModel, String messageName, NotificationObserver observer); + /** + * Removes a {@link NotificationObserver} for all messageName. + * + * @param viewModel + * @param observer + */ void unsubscribe(ViewModel view, NotificationObserver observer); From dd585bfe027d91671640fac1a17cf37003ed46ee Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Sat, 25 Apr 2015 22:16:47 +0200 Subject: [PATCH 11/28] Update .travis.yml --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index efa218ffb..3c1baf29b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,15 @@ language: java +sudo: required + jdk: -- oraclejdk8 + - oraclejdk8 + +install: true + +script: + - sudo apt-get update && sudo apt-get install oracle-java8-installer + - java -version before_install: - export DISPLAY=:99.0 From c54499574b83769e5c64c6565bb262df90cfffd0 Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Sun, 26 Apr 2015 12:27:40 +0200 Subject: [PATCH 12/28] JavaDoc --- mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java index 216796212..83c137462 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/ViewModel.java @@ -22,7 +22,15 @@ /** *

- * Marker interface for a View Model. Some additional hints to this layer: + * Interface for a View Model. + *

+ *

+ * You can use a notification mechanism by using the {@link #publish(String, Object...)} method. In the View you can + * subscribe to this notifications by using viewModel. + * {@link #subscribe(String messageName, NotificationObserver observer)}. + *

+ *

+ * Some additional hints to this layer: *

* *

From a6c7b09cab31eb43029ac9ecad52e10e174d2acb Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Mon, 27 Apr 2015 15:54:55 +0200 Subject: [PATCH 13/28] #203 move ViewModelTest into notifications package, refactor loop from iterator-style to foreach-style. --- .../notifications/DefaultNotificationCenter.java | 10 +++------- .../{ => utils/notifications}/ViewModelTest.java | 13 ++++++++++++- 2 files changed, 15 insertions(+), 8 deletions(-) rename mvvmfx/src/test/java/de/saxsys/mvvmfx/{ => utils/notifications}/ViewModelTest.java (88%) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java index cd4d5c4a7..8a12b1828 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java @@ -116,13 +116,9 @@ private void addObserver(String messageName, NotificationObserver observer, Obse private void removeObserverFromObserverMap(NotificationObserver observer, ObserverMap observerMap) { - Iterator iterator = observerMap.keySet().iterator(); - while (iterator.hasNext()) { - String key = iterator.next(); - Iterator iterator2 = observerMap.get(key).iterator(); - while (iterator2.hasNext()) { - NotificationObserver actualObserver = iterator2.next(); - if (actualObserver == observer) { + for (String key : observerMap.keySet()) { + for (NotificationObserver actualObserver : observerMap.get(key)) { + if (actualObserver.equals(observer)) { observerMap.get(key).remove(actualObserver); break; } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/ViewModelTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/ViewModelTest.java similarity index 88% rename from mvvmfx/src/test/java/de/saxsys/mvvmfx/ViewModelTest.java rename to mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/ViewModelTest.java index 1224e2250..8ef1bafe9 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/ViewModelTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/ViewModelTest.java @@ -1,5 +1,7 @@ -package de.saxsys.mvvmfx; +package de.saxsys.mvvmfx.utils.notifications; +import de.saxsys.mvvmfx.MvvmFX; +import de.saxsys.mvvmfx.ViewModel; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; @@ -24,6 +26,15 @@ public void init() { viewModel = new ViewModel() { }; } + + + @Test + public void observerFromOutsideDoesNotReceiveNotifications() { + MvvmFX.getNotificationCenter().subscribe(TEST_NOTIFICATION, observer1); + viewModel.publish(TEST_NOTIFICATION); + + Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION); + } @Test public void addObserverAndPublish() throws Exception { From 0a6cc46a16cab0057a888a9b1aec08bcafb3f203 Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Mon, 27 Apr 2015 16:10:44 +0200 Subject: [PATCH 14/28] #223 add test case to reproduce the bug --- .../DefaultNotificationCenterTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java index 2cac321fd..0bf2d1b36 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java @@ -17,6 +17,7 @@ package de.saxsys.mvvmfx.utils.notifications; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.mockito.Mockito; @@ -86,6 +87,29 @@ public void addAndRemoveObserverForNameToDefaultNotificationCenterAndPostNotific defaultCenter.publish(TEST_NOTIFICATION); Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION); } + + @Test + @Ignore("remove when bug is fixed") + public void subscribeSameObserverMultipleTimes() { + defaultCenter.subscribe(TEST_NOTIFICATION, observer1); + defaultCenter.subscribe(TEST_NOTIFICATION, observer1); + + defaultCenter.publish(TEST_NOTIFICATION); + Mockito.verify(observer1, Mockito.times(1)).receivedNotification(TEST_NOTIFICATION); + } + + @Test + @Ignore("remove when bug is fixed") + public void unsubscribeObserverThatWasSubscribedMultipleTimes() { + defaultCenter.subscribe(TEST_NOTIFICATION, observer1); + defaultCenter.subscribe(TEST_NOTIFICATION, observer1); + defaultCenter.subscribe(TEST_NOTIFICATION, observer1); + + defaultCenter.unsubscribe(observer1); + + defaultCenter.publish(TEST_NOTIFICATION); + Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION); + } private class DummyNotificationObserver implements NotificationObserver { @Override From 3e60cd0876a6840819331e33ce09ab197e0597e9 Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Mon, 27 Apr 2015 16:52:43 +0200 Subject: [PATCH 15/28] #223 fix notification center bug --- .../DefaultNotificationCenter.java | 24 ++++++++++++++----- .../notifications/NotificationCenter.java | 5 ++++ .../DefaultNotificationCenterTest.java | 4 +--- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java index 8a12b1828..4eba99b6c 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenter.java @@ -20,8 +20,11 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.stream.Collectors; import de.saxsys.mvvmfx.ViewModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Default implementation of {@link NotificationCenter}. @@ -31,6 +34,8 @@ */ class DefaultNotificationCenter implements NotificationCenter { + private static final Logger LOG = LoggerFactory.getLogger(DefaultNotificationCenter.class); + DefaultNotificationCenter() { } @@ -110,6 +115,11 @@ private void addObserver(String messageName, NotificationObserver observer, Obse observerMap.put(messageName, new ArrayList()); } observers = observerMap.get(messageName); + + if(observers.contains(observer)) { + LOG.warn("Subscribe the observer ["+ observer + "] for the message [" + messageName + + "], but the same observer was already added for this message in the past."); + } observers.add(observer); } @@ -117,12 +127,14 @@ private void addObserver(String messageName, NotificationObserver observer, Obse private void removeObserverFromObserverMap(NotificationObserver observer, ObserverMap observerMap) { for (String key : observerMap.keySet()) { - for (NotificationObserver actualObserver : observerMap.get(key)) { - if (actualObserver.equals(observer)) { - observerMap.get(key).remove(actualObserver); - break; - } - } + final List observers = observerMap.get(key); + + final List observersToBeRemoved = observers + .stream() + .filter(actualObserver -> actualObserver.equals(observer)) + .collect(Collectors.toList()); + + observers.removeAll(observersToBeRemoved); } } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java index 69a7b9192..4724860b3 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationCenter.java @@ -34,6 +34,11 @@ public interface NotificationCenter { /** * Add an observer to the NotificationCenter which gets notifications for the given String. * + * Please note: It is possible (but yet untypical) to add the same observer for the same message multiple times. + * In this case the observer will be invoked multiple times too. + * As this behaviour is unusual, the default notification center will log a warning message when the same observer + * is added multiple times for the same message. + * * @param messageName * key of the notification to listen * @param observer diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java index 0bf2d1b36..c0c72cc63 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/DefaultNotificationCenterTest.java @@ -89,17 +89,15 @@ public void addAndRemoveObserverForNameToDefaultNotificationCenterAndPostNotific } @Test - @Ignore("remove when bug is fixed") public void subscribeSameObserverMultipleTimes() { defaultCenter.subscribe(TEST_NOTIFICATION, observer1); defaultCenter.subscribe(TEST_NOTIFICATION, observer1); defaultCenter.publish(TEST_NOTIFICATION); - Mockito.verify(observer1, Mockito.times(1)).receivedNotification(TEST_NOTIFICATION); + Mockito.verify(observer1, Mockito.times(2)).receivedNotification(TEST_NOTIFICATION); } @Test - @Ignore("remove when bug is fixed") public void unsubscribeObserverThatWasSubscribedMultipleTimes() { defaultCenter.subscribe(TEST_NOTIFICATION, observer1); defaultCenter.subscribe(TEST_NOTIFICATION, observer1); From e6e80506019839cd5f883b4a4e1f09410ecbf075 Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Mon, 27 Apr 2015 20:57:51 +0200 Subject: [PATCH 16/28] first approach --- .../utils/commands/DelegateCommand.java | 72 +++++++++++-------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java index 82210e9b6..61e132a39 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java @@ -15,23 +15,26 @@ ******************************************************************************/ package de.saxsys.mvvmfx.utils.commands; -import javafx.application.Platform; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.beans.value.ObservableBooleanValue; +import javafx.concurrent.Task; import eu.lestard.doc.Beta; /** - * A {@link Command} implementation that encapsulates an action ({@link Runnable}). It is possible to define that the + * A {@link Command} implementation that encapsulates an action ({@link Task}). It is possible to define that the * action should be executed in the background (not on the JavaFX thread) so that long running actions can be * implemented that aren't blocking the ui thread. * * @author alexander.casall */ @Beta -public class DelegateCommand extends CommandBase { +public abstract class DelegateCommand extends Task implements Command { - private final Runnable action; private boolean inBackground = false; + + /** * Creates a command without a condition about the executability. The command will perform in the thread which * executes the {@link Command}. @@ -39,8 +42,8 @@ public class DelegateCommand extends CommandBase { * @param action * which should execute */ - public DelegateCommand(Runnable action) { - this(action, null, false); + public DelegateCommand() { + this(null, false); } /** @@ -48,7 +51,7 @@ public DelegateCommand(Runnable action) { * inBackground parameter to run the {@link Command} in a background thread. * * IF YOU USE THE BACKGROUND THREAD: Your provided action will perform in a background thread. If you - * manipulate data in your action, which will be propagated to the UI, use {@link Platform#runLater(Runnable)} for + * manipulate data in your action, which will be propagated to the UI, use {@link Platform#runLater(Task)} for * this manipulation, otherwise you get an Exception. * * @param action @@ -56,8 +59,8 @@ public DelegateCommand(Runnable action) { * @param inBackground * defines whether the execution {@link #execute()} is performed in a background thread or not */ - public DelegateCommand(Runnable action, boolean inBackground) { - this(action, null, inBackground); + public DelegateCommand(boolean inBackground) { + this(null, inBackground); } /** @@ -69,16 +72,16 @@ public DelegateCommand(Runnable action, boolean inBackground) { * @param executableBinding * which defines whether the {@link Command} can execute */ - public DelegateCommand(Runnable action, ObservableBooleanValue executableBinding) { - this(action, executableBinding, false); + public DelegateCommand(ObservableBooleanValue executableBinding) { + this(executableBinding, false); } /** * Creates a command with a condition about the executability by using the #executableBinding parameter. Pass a * true to the #inBackground parameter to run the {@link Command} in a background thread. * - * IF YOU USE THE BACKGROUND THREAD: don't forget to return to the UI-thread by using - * {@link Platform#runLater(Runnable)}, otherwise you get an Exception. + * IF YOU USE THE BACKGROUND THREAD: don't forget to return to the UI-thread by using {@link + * Platform#runLater(Task)}, otherwise you get an Exception. * * @param action * which should execute @@ -87,40 +90,51 @@ public DelegateCommand(Runnable action, ObservableBooleanValue executableBinding * @param inBackground * defines whether the execution {@link #execute()} is performed in a background thread or not */ - public DelegateCommand(Runnable action, ObservableBooleanValue executableBinding, boolean inBackground) { - this.action = action; + public DelegateCommand(ObservableBooleanValue executableBinding, boolean inBackground) { this.inBackground = inBackground; if (executableBinding != null) { executable.bind(runningProperty().not().and(executableBinding)); } } + /** * @see de.saxsys.mvvmfx.utils.commands.Command#execute */ @Override public void execute() { - - final boolean callerOnUIThread = Platform.isFxApplicationThread(); - if (!isExecutable()) { throw new RuntimeException("The execute()-method of the command was called while it wasn't executable."); } else { - running.set(true); if (inBackground) { - new Thread(() -> { - action.run(); - if (callerOnUIThread) { - Platform.runLater(() -> running.set(false)); - } else { - running.set(false); - } - }).start(); + new Service(this).start(); } else { - action.run(); - running.set(false); + try { + this.action(); + } catch (Exception e) { + e.printStackTrace(); + } } } } + protected final ReadOnlyBooleanWrapper executable = new ReadOnlyBooleanWrapper(true); + + @Override + public ReadOnlyBooleanProperty executableProperty() { + return this.executable.getReadOnlyProperty(); + } + + @Override + public boolean isExecutable() { + return this.executableProperty().get(); + } + + @Override + protected Void call() throws Exception { + action(); + return null; + } + + protected abstract void action() throws Exception; } From b5a281f668690202593397ae535a5547de882151 Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Mon, 27 Apr 2015 22:22:57 +0200 Subject: [PATCH 17/28] Tests --- .../personlogin/PersonLoginViewModel.java | 7 +- .../utils/commands/DelegateCommand.java | 51 ++++++- .../utils/commands/CompositeCommandTest.java | 141 ++++++++++-------- .../utils/commands/DelegateCommandTest.java | 105 +++++++------ 4 files changed, 187 insertions(+), 117 deletions(-) diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java index b1a3b7ea9..52bdc469d 100644 --- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java +++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java @@ -73,7 +73,12 @@ public ReadOnlyIntegerProperty loggedInPersonIdProperty() { public Command getLoginCommand() { if (loginCommand == null) { - loginCommand = new DelegateCommand(() -> performLogin(), createLoginPossibleBinding(), true); + loginCommand = new DelegateCommand(createLoginPossibleBinding(), true) { + @Override + protected void action() throws Exception { + performLogin(); + } + }; } return loginCommand; } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java index 61e132a39..99740f8bc 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java @@ -18,13 +18,14 @@ import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.beans.value.ObservableBooleanValue; +import javafx.concurrent.Service; import javafx.concurrent.Task; import eu.lestard.doc.Beta; /** * A {@link Command} implementation that encapsulates an action ({@link Task}). It is possible to define that the * action should be executed in the background (not on the JavaFX thread) so that long running actions can be - * implemented that aren't blocking the ui thread. + * implemented that aren't blocking the UI-Thread. * * @author alexander.casall */ @@ -32,6 +33,9 @@ public abstract class DelegateCommand extends Task implements Command { private boolean inBackground = false; + protected final ReadOnlyBooleanWrapper executable = new ReadOnlyBooleanWrapper(true); + protected ReadOnlyBooleanWrapper notExecutable; + protected ReadOnlyBooleanWrapper notRunning; @@ -95,8 +99,15 @@ public DelegateCommand(ObservableBooleanValue executableBinding, boolean inBackg if (executableBinding != null) { executable.bind(runningProperty().not().and(executableBinding)); } + } + /** + * The action which will called if the {@link #execute()} method is called. + * + * @throws Exception + */ + protected abstract void action() throws Exception; /** * @see de.saxsys.mvvmfx.utils.commands.Command#execute @@ -107,7 +118,12 @@ public void execute() { throw new RuntimeException("The execute()-method of the command was called while it wasn't executable."); } else { if (inBackground) { - new Service(this).start(); + new Service() { + @Override + protected Task createTask() { + return DelegateCommand.this; + } + }.start(); } else { try { this.action(); @@ -118,13 +134,12 @@ public void execute() { } } - protected final ReadOnlyBooleanWrapper executable = new ReadOnlyBooleanWrapper(true); - @Override public ReadOnlyBooleanProperty executableProperty() { return this.executable.getReadOnlyProperty(); } + @Override public boolean isExecutable() { return this.executableProperty().get(); @@ -136,5 +151,31 @@ protected Void call() throws Exception { return null; } - protected abstract void action() throws Exception; + @Override + public final ReadOnlyBooleanProperty notExecutableProperty() { + if (notExecutable == null) { + notExecutable = new ReadOnlyBooleanWrapper(); + notExecutable.bind(executableProperty().not()); + } + return notExecutable.getReadOnlyProperty(); + } + + @Override + public final boolean isNotExecutable() { + return notExecutableProperty().get(); + } + + @Override + public final ReadOnlyBooleanProperty notRunningProperty() { + if (notRunning == null) { + notRunning = new ReadOnlyBooleanWrapper(); + notRunning.bind(runningProperty().not()); + } + return notRunning.getReadOnlyProperty(); + } + + @Override + public final boolean isNotRunning() { + return notRunningProperty().get(); + } } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java index 75f2ff223..1bba38405 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java @@ -8,15 +8,20 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import de.saxsys.javafx.test.JfxRunner; import de.saxsys.mvvmfx.testingutils.GCVerifier; +@RunWith(JfxRunner.class) public class CompositeCommandTest { private BooleanProperty condition1; @@ -30,11 +35,22 @@ public class CompositeCommandTest { public void init() { condition1 = new SimpleBooleanProperty(true); called1 = new SimpleBooleanProperty(); - delegateCommand1 = new DelegateCommand(() -> called1.set(true), condition1); + delegateCommand1 = new DelegateCommand(condition1) { + + @Override + protected void action() throws Exception { + called1.set(true); + } + }; condition2 = new SimpleBooleanProperty(true); called2 = new SimpleBooleanProperty(); - delegateCommand2 = new DelegateCommand(() -> called2.set(true), condition2); + delegateCommand2 = new DelegateCommand(condition2) { + @Override + protected void action() throws Exception { + called2.set(true); + } + }; } @Test @@ -124,31 +140,6 @@ public void register() throws Exception { assertFalse(compositeCommand.isNotExecutable()); } - @Test - public void running() throws Exception { - BooleanProperty run = new SimpleBooleanProperty(); - BooleanProperty finished = new SimpleBooleanProperty(); - CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1, delegateCommand2); - - // We have to check the running Property with this mechanism, because it is processed synchronously and we can't - // hook between the state changes. - compositeCommand.runningProperty().addListener((ChangeListener) (observable, oldValue, newValue) -> { - if (!oldValue && newValue) { - run.set(true); - assertTrue(compositeCommand.runningProperty().get()); - } - if (oldValue && !newValue) { - finished.set(true); - assertFalse(compositeCommand.runningProperty().get()); - } - }); - - compositeCommand.execute(); - - assertTrue(run.get()); - assertTrue(finished.get()); - } - @Test public void allCommandsAreUnregistered() throws Exception { @@ -166,53 +157,79 @@ public void allCommandsAreUnregistered() throws Exception { public void longRunningAsyncComposite() throws Exception { BooleanProperty condition = new SimpleBooleanProperty(true); - + CompletableFuture commandStarted = new CompletableFuture<>(); + CompletableFuture commandCompleted = new CompletableFuture<>(); CompletableFuture future = new CompletableFuture<>(); - DelegateCommand delegateCommand1 = new DelegateCommand(() -> sleep(500), condition, true); + DelegateCommand delegateCommand1 = new DelegateCommand(condition, true) { + + @Override + protected void action() throws Exception { + sleep(500); + } + }; - DelegateCommand delegateCommand2 = new DelegateCommand(() -> { - sleep(1000); - future.complete(null); - }, condition, true); + DelegateCommand delegateCommand2 = new DelegateCommand(condition, true) { + @Override + protected void action() throws Exception { + sleep(1000); + future.complete(null); + } + }; - DelegateCommand delegateCommand3 = new DelegateCommand(() -> { - }, condition, false); + DelegateCommand delegateCommand3 = new DelegateCommand(condition, true) { + + @Override + protected void action() throws Exception { + } + }; CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1, delegateCommand2, delegateCommand3); GCVerifier.forceGC(); - assertFalse(compositeCommand.runningProperty().get()); - assertFalse(delegateCommand1.runningProperty().get()); - assertFalse(delegateCommand2.runningProperty().get()); - assertFalse(delegateCommand3.runningProperty().get()); - assertTrue(compositeCommand.notRunningProperty().get()); - assertTrue(delegateCommand1.notRunningProperty().get()); - assertTrue(delegateCommand2.notRunningProperty().get()); - assertTrue(delegateCommand3.notRunningProperty().get()); + compositeCommand.runningProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { + if (newValue && !oldValue) { + Platform.runLater(new Runnable() { + @Override + public void run() { + assertTrue(compositeCommand.runningProperty().get()); + assertTrue(delegateCommand1.runningProperty().get()); + assertTrue(delegateCommand2.runningProperty().get()); + assertTrue(delegateCommand3.runningProperty().get()); + assertFalse(compositeCommand.notRunningProperty().get()); + assertFalse(delegateCommand1.notRunningProperty().get()); + assertFalse(delegateCommand2.notRunningProperty().get()); + assertFalse(delegateCommand3.notRunningProperty().get()); + commandCompleted.complete(null); + } + }); + } + if (oldValue && !newValue) { + Platform.runLater(new Runnable() { + @Override + public void run() { + assertFalse(compositeCommand.runningProperty().get()); + assertFalse(delegateCommand1.runningProperty().get()); + assertFalse(delegateCommand2.runningProperty().get()); + assertFalse(delegateCommand3.runningProperty().get()); + assertTrue(compositeCommand.notRunningProperty().get()); + assertTrue(delegateCommand1.notRunningProperty().get()); + assertTrue(delegateCommand2.notRunningProperty().get()); + assertTrue(delegateCommand3.notRunningProperty().get()); + commandStarted.complete(null); + } + }); + } + } + }); compositeCommand.execute(); - - assertTrue(compositeCommand.runningProperty().get()); - assertTrue(delegateCommand1.runningProperty().get()); - assertTrue(delegateCommand2.runningProperty().get()); - assertFalse(delegateCommand3.runningProperty().get()); - assertFalse(compositeCommand.notRunningProperty().get()); - assertFalse(delegateCommand1.notRunningProperty().get()); - assertFalse(delegateCommand2.notRunningProperty().get()); - assertTrue(delegateCommand3.notRunningProperty().get()); - + commandStarted.get(3, TimeUnit.SECONDS); future.get(3, TimeUnit.SECONDS); - - assertFalse(compositeCommand.runningProperty().get()); - assertFalse(delegateCommand1.runningProperty().get()); - assertFalse(delegateCommand2.runningProperty().get()); - assertFalse(delegateCommand3.runningProperty().get()); - assertTrue(compositeCommand.notRunningProperty().get()); - assertTrue(delegateCommand1.notRunningProperty().get()); - assertTrue(delegateCommand2.notRunningProperty().get()); - assertTrue(delegateCommand3.notRunningProperty().get()); + commandCompleted.get(4, TimeUnit.SECONDS); } private void sleep(long millis) { diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java index f3288a0fa..b080e8268 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java @@ -9,18 +9,27 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; import org.junit.Test; +import org.junit.runner.RunWith; +import de.saxsys.javafx.test.JfxRunner; + +@RunWith(JfxRunner.class) public class DelegateCommandTest { @Test public void executable() { BooleanProperty condition = new SimpleBooleanProperty(true); - DelegateCommand delegateCommand = new DelegateCommand(() -> { - }, condition); + DelegateCommand delegateCommand = new DelegateCommand(condition) { + + @Override + protected void action() throws Exception { + } + }; assertTrue(delegateCommand.isExecutable()); assertFalse(delegateCommand.isNotExecutable()); @@ -41,7 +50,12 @@ public void firePositive() { BooleanProperty condition = new SimpleBooleanProperty(true); BooleanProperty called = new SimpleBooleanProperty(); - DelegateCommand delegateCommand = new DelegateCommand(() -> called.set(true), condition); + DelegateCommand delegateCommand = new DelegateCommand(condition) { + @Override + protected void action() throws Exception { + called.set(true); + } + }; assertFalse(called.get()); delegateCommand.execute(); @@ -52,38 +66,13 @@ public void firePositive() { public void fireNegative() { BooleanProperty condition = new SimpleBooleanProperty(false); - DelegateCommand delegateCommand = new DelegateCommand(() -> { - }, condition); - - delegateCommand.execute(); - } - - - @Test - public void running() throws Exception { - BooleanProperty run = new SimpleBooleanProperty(); - BooleanProperty finished = new SimpleBooleanProperty(); - - BooleanProperty condition = new SimpleBooleanProperty(true); - - DelegateCommand delegateCommand = new DelegateCommand(() -> { - }, condition); - - delegateCommand.runningProperty().addListener((ChangeListener) (observable, oldValue, newValue) -> { - if (!oldValue && newValue) { - run.set(true); - assertFalse(delegateCommand.notRunningProperty().get()); - } - if (oldValue && !newValue) { - finished.set(true); - assertTrue(delegateCommand.notRunningProperty().get()); + DelegateCommand delegateCommand = new DelegateCommand(condition) { + @Override + protected void action() throws Exception { } - }); + }; delegateCommand.execute(); - - assertTrue(run.get()); - assertTrue(finished.get()); } @@ -91,30 +80,48 @@ public void running() throws Exception { public void longRunningAsync() throws Exception { BooleanProperty condition = new SimpleBooleanProperty(true); - CompletableFuture future = new CompletableFuture<>(); - DelegateCommand delegateCommand = new DelegateCommand(() -> { - try { - Thread.sleep(1000); - future.complete(null); - } catch (Exception e) { + CompletableFuture commandStarted = new CompletableFuture<>(); + CompletableFuture commandCompleted = new CompletableFuture<>(); + + DelegateCommand delegateCommand = new DelegateCommand(condition, true) { + @Override + protected void action() throws Exception { + try { + Thread.sleep(1000); + } catch (Exception e) { + } } - }, condition, true); + }; assertFalse(delegateCommand.runningProperty().get()); assertTrue(delegateCommand.notRunningProperty().get()); - delegateCommand.execute(); - assertTrue(delegateCommand.runningProperty().get()); - assertFalse(delegateCommand.notRunningProperty().get()); - assertFalse(delegateCommand.executableProperty().get()); - assertTrue(delegateCommand.notExecutableProperty().get()); + delegateCommand.runningProperty().addListener(new ChangeListener() { + + @Override + public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { + if (newValue) { + assertTrue(delegateCommand.runningProperty().get()); + assertFalse(delegateCommand.notRunningProperty().get()); + assertFalse(delegateCommand.executableProperty().get()); + assertTrue(delegateCommand.notExecutableProperty().get()); + commandStarted.complete(null); + } + if (!newValue && oldValue) { + assertFalse(delegateCommand.runningProperty().get()); + assertTrue(delegateCommand.notRunningProperty().get()); + assertTrue(delegateCommand.executableProperty().get()); + assertFalse(delegateCommand.notExecutableProperty().get()); + commandCompleted.complete(null); + } + + } + }); - future.get(3, TimeUnit.SECONDS); - assertFalse(delegateCommand.runningProperty().get()); - assertTrue(delegateCommand.notRunningProperty().get()); - assertTrue(delegateCommand.executableProperty().get()); - assertFalse(delegateCommand.notExecutableProperty().get()); + delegateCommand.execute(); + commandStarted.get(3, TimeUnit.SECONDS); + commandCompleted.get(4, TimeUnit.SECONDS); } } From a9ee9a32489c783e8beeb212c9cddfe47a5e8bea Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Mon, 27 Apr 2015 23:02:12 +0200 Subject: [PATCH 18/28] made commands reusable --- .../utils/commands/DelegateCommand.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java index 99740f8bc..824729645 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java @@ -30,7 +30,7 @@ * @author alexander.casall */ @Beta -public abstract class DelegateCommand extends Task implements Command { +public abstract class DelegateCommand extends Service implements Command { private boolean inBackground = false; protected final ReadOnlyBooleanWrapper executable = new ReadOnlyBooleanWrapper(true); @@ -118,12 +118,10 @@ public void execute() { throw new RuntimeException("The execute()-method of the command was called while it wasn't executable."); } else { if (inBackground) { - new Service() { - @Override - protected Task createTask() { - return DelegateCommand.this; - } - }.start(); + if (!super.isRunning()) { + reset(); + start(); + } } else { try { this.action(); @@ -134,6 +132,17 @@ protected Task createTask() { } } + @Override + protected Task createTask() { + return new Task() { + @Override + protected Void call() throws Exception { + action(); + return null; + } + }; + } + @Override public ReadOnlyBooleanProperty executableProperty() { return this.executable.getReadOnlyProperty(); @@ -145,12 +154,6 @@ public boolean isExecutable() { return this.executableProperty().get(); } - @Override - protected Void call() throws Exception { - action(); - return null; - } - @Override public final ReadOnlyBooleanProperty notExecutableProperty() { if (notExecutable == null) { From 1543be245115ebaf7d434573bd125ebac07deee0 Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Mon, 27 Apr 2015 23:05:33 +0200 Subject: [PATCH 19/28] Progress --- .../saxsys/mvvmfx/utils/commands/Command.java | 13 +++++ .../utils/commands/CompositeCommand.java | 58 +++++++++++++++++-- .../utils/commands/CompositeCommandTest.java | 7 +++ 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Command.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Command.java index 66c98b70c..31a58e292 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Command.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Command.java @@ -16,6 +16,7 @@ package de.saxsys.mvvmfx.utils.commands; import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyDoubleProperty; import eu.lestard.doc.Beta; /** @@ -89,6 +90,18 @@ public interface Command { */ ReadOnlyBooleanProperty notRunningProperty(); + /** + * Gets a double between 0.0 and 1.0 which represents the progress. + * + * @return progress + */ + double getProgress(); + + /** + * @see #getProgress() + */ + ReadOnlyDoubleProperty progressProperty(); + } \ No newline at end of file diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CompositeCommand.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CompositeCommand.java index a36cd72ca..3ee99bbf8 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CompositeCommand.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CompositeCommand.java @@ -15,12 +15,14 @@ ******************************************************************************/ package de.saxsys.mvvmfx.utils.commands; -import eu.lestard.doc.Beta; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; +import eu.lestard.doc.Beta; /** * CompositeCommand is an aggregation of other commands - a list of {@link Command} references internally. @@ -48,6 +50,8 @@ public class CompositeCommand extends CommandBase { private final ObservableList registeredCommands = FXCollections.observableArrayList(); + ReadOnlyDoubleWrapper progress = new ReadOnlyDoubleWrapper(); + /** * Creates a {@link CompositeCommand} with given commands. * @@ -83,17 +87,21 @@ public void unregister(Command command) { private void initRegisteredCommandsListener() { this.registeredCommands.addListener((ListChangeListener) c -> { while (c.next()) { - if(registeredCommands.isEmpty()) { + if (registeredCommands.isEmpty()) { executable.unbind(); running.unbind(); + progress.unbind(); } else { BooleanBinding executableBinding = null; BooleanBinding runningBinding = null; - + + ReadOnlyBooleanProperty[] allRunnings = new ReadOnlyBooleanProperty[registeredCommands.size()]; + + for (int i = 0; i < registeredCommands.size(); i++) { ReadOnlyBooleanProperty currentExecutable = registeredCommands.get(i).executableProperty(); ReadOnlyBooleanProperty currentRunning = registeredCommands.get(i).runningProperty(); - + allRunnings[i] = registeredCommands.get(i).runningProperty(); if (i == 0) { executableBinding = currentExecutable.and(currentExecutable); runningBinding = currentRunning.or(currentRunning); @@ -104,18 +112,56 @@ private void initRegisteredCommandsListener() { } executable.bind(executableBinding); running.bind(runningBinding); - } + + // TODO Improve Implementation + // progress.unbind(); + // progress.bind(Bindings.createDoubleBinding(new Callable() { + // @Override + // public Double call() throws Exception { + // Stream filter = FXCollections.observableArrayList(allRunnings) + // .stream().filter( + // new Predicate() { + // @Override + // public boolean test(ReadOnlyBooleanProperty t) { + // return t.get(); + // } + // }); + // + // long count = filter.count(); + // double result = count / (double) allRunnings.length; + // double oldValue = progress.get(); + // + // if (result > oldValue) { + // return result; + // } + // + // return oldValue; + // } + // }, allRunnings)); } - }); + } + }) ; } @Override public void execute() { + progress.set(0.0); if (!isExecutable()) { throw new RuntimeException("Not executable"); } else { registeredCommands.forEach(t -> t.execute()); + progress.set(1.0); } } + @Override + public double getProgress() { + return progressProperty().get(); + } + + @Override + public ReadOnlyDoubleProperty progressProperty() { + return progress; + } + } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java index 1bba38405..f07e4f353 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java @@ -186,6 +186,13 @@ protected void action() throws Exception { CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1, delegateCommand2, delegateCommand3); + // compositeCommand.progressProperty().addListener(new ChangeListener() { + // + // @Override + // public void changed(ObservableValue observable, Number oldValue, Number newValue) { + // } + // }); + GCVerifier.forceGC(); compositeCommand.runningProperty().addListener(new ChangeListener() { From 04b8e9fe2e04a2008ccf4cde2fdc4efde0bcead5 Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Tue, 28 Apr 2015 14:42:22 +0200 Subject: [PATCH 20/28] #211 additional wrapper methods for default values. Enhanced tests and JavaDoc --- .../mvvmfx/utils/mapping/BooleanGetter.java | 6 - .../mapping/BooleanPropertyAccessor.java | 8 - .../mvvmfx/utils/mapping/BooleanSetter.java | 6 - .../mvvmfx/utils/mapping/DoubleGetter.java | 6 - .../utils/mapping/DoublePropertyAccessor.java | 8 - .../mvvmfx/utils/mapping/DoubleSetter.java | 6 - .../mvvmfx/utils/mapping/FloatGetter.java | 6 - .../utils/mapping/FloatPropertyAccessor.java | 8 - .../mvvmfx/utils/mapping/FloatSetter.java | 6 - .../mvvmfx/utils/mapping/IntGetter.java | 6 - .../utils/mapping/IntPropertyAccessor.java | 8 - .../mvvmfx/utils/mapping/IntSetter.java | 6 - .../mvvmfx/utils/mapping/LongGetter.java | 6 - .../utils/mapping/LongPropertyAccessor.java | 8 - .../mvvmfx/utils/mapping/LongSetter.java | 6 - .../mvvmfx/utils/mapping/ModelWrapper.java | 673 +++++++++--------- .../mvvmfx/utils/mapping/ObjectGetter.java | 6 - .../utils/mapping/ObjectPropertyAccessor.java | 8 - .../mvvmfx/utils/mapping/ObjectSetter.java | 6 - .../mvvmfx/utils/mapping/StringGetter.java | 6 - .../utils/mapping/StringPropertyAccessor.java | 8 - .../mvvmfx/utils/mapping/StringSetter.java | 6 - .../accessorfunctions/BooleanGetter.java | 19 + .../BooleanPropertyAccessor.java | 20 + .../accessorfunctions/BooleanSetter.java | 19 + .../accessorfunctions/DoubleGetter.java | 19 + .../DoublePropertyAccessor.java | 23 + .../accessorfunctions/DoubleSetter.java | 19 + .../accessorfunctions/FloatGetter.java | 19 + .../FloatPropertyAccessor.java | 22 + .../accessorfunctions/FloatSetter.java | 19 + .../mapping/accessorfunctions/IntGetter.java | 19 + .../IntPropertyAccessor.java | 22 + .../mapping/accessorfunctions/IntSetter.java | 19 + .../mapping/accessorfunctions/LongGetter.java | 19 + .../LongPropertyAccessor.java | 22 + .../mapping/accessorfunctions/LongSetter.java | 19 + .../accessorfunctions/ObjectGetter.java | 22 + .../ObjectPropertyAccessor.java | 25 + .../accessorfunctions/ObjectSetter.java | 23 + .../accessorfunctions/StringGetter.java | 19 + .../StringPropertyAccessor.java | 22 + .../accessorfunctions/StringSetter.java | 20 + .../accessorfunctions/package-info.java | 11 + .../mvvmfx/utils/mapping/ReturnTypeTest.java | 53 +- 45 files changed, 829 insertions(+), 478 deletions(-) delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanGetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanPropertyAccessor.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanSetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleGetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoublePropertyAccessor.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleSetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatGetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatPropertyAccessor.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatSetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntGetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntPropertyAccessor.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntSetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongGetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongPropertyAccessor.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongSetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectGetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectPropertyAccessor.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectSetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringGetter.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringPropertyAccessor.java delete mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoublePropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringGetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringPropertyAccessor.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringSetter.java create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/package-info.java diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanGetter.java deleted file mode 100644 index 8e8ecdcd2..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanGetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.Function; - -public interface BooleanGetter extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanPropertyAccessor.java deleted file mode 100644 index 7f4ab16d9..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanPropertyAccessor.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import javafx.beans.property.Property; - -import java.util.function.Function; - -public interface BooleanPropertyAccessor extends Function> { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanSetter.java deleted file mode 100644 index 6a5f22f88..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BooleanSetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.BiConsumer; - -public interface BooleanSetter extends BiConsumer { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleGetter.java deleted file mode 100644 index 96bcc6efc..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleGetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.Function; - -public interface DoubleGetter extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoublePropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoublePropertyAccessor.java deleted file mode 100644 index b82abef50..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoublePropertyAccessor.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import javafx.beans.property.DoubleProperty; - -import java.util.function.Function; - -public interface DoublePropertyAccessor extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleSetter.java deleted file mode 100644 index 5c6c9cd90..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/DoubleSetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.BiConsumer; - -public interface DoubleSetter extends BiConsumer { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatGetter.java deleted file mode 100644 index 4148bdc69..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatGetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.Function; - -public interface FloatGetter extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatPropertyAccessor.java deleted file mode 100644 index 410f9db89..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatPropertyAccessor.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import javafx.beans.property.FloatProperty; - -import java.util.function.Function; - -public interface FloatPropertyAccessor extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatSetter.java deleted file mode 100644 index 6718e733d..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FloatSetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.BiConsumer; - -public interface FloatSetter extends BiConsumer { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntGetter.java deleted file mode 100644 index 1832cf8ad..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntGetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.Function; - -public interface IntGetter extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntPropertyAccessor.java deleted file mode 100644 index cb0e6affb..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntPropertyAccessor.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import javafx.beans.property.IntegerProperty; - -import java.util.function.Function; - -public interface IntPropertyAccessor extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntSetter.java deleted file mode 100644 index 5aadd5e5e..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/IntSetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.BiConsumer; - -public interface IntSetter extends BiConsumer{ -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongGetter.java deleted file mode 100644 index b5d07ba85..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongGetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.Function; - -public interface LongGetter extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongPropertyAccessor.java deleted file mode 100644 index d61d6dacb..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongPropertyAccessor.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import javafx.beans.property.LongProperty; - -import java.util.function.Function; - -public interface LongPropertyAccessor extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongSetter.java deleted file mode 100644 index 2e2222762..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/LongSetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.BiConsumer; - -public interface LongSetter extends BiConsumer { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java index 3ba7fa955..2894eeaa2 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java @@ -1,5 +1,26 @@ package de.saxsys.mvvmfx.utils.mapping; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.BooleanGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.BooleanPropertyAccessor; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.BooleanSetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.DoubleGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.DoublePropertyAccessor; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.DoubleSetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.FloatGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.FloatPropertyAccessor; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.FloatSetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.IntGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.IntPropertyAccessor; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.IntSetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.LongGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.LongPropertyAccessor; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.LongSetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.ObjectGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.ObjectPropertyAccessor; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.ObjectSetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.StringGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.StringPropertyAccessor; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.StringSetter; import eu.lestard.doc.Beta; import javafx.beans.property.*; @@ -156,15 +177,15 @@ * } * } * - * public Property{@code} nameProperty(){ + * public StringProperty nameProperty(){ * return wrapper.field("name", Person::getName, Person::setName, ""); * } * - * public Property{@code} familyNameProperty(){ + * public StringProperty familyNameProperty(){ * return wrapper.field("familyName", Person::getFamilyName, Person::setFamilyName, ""); * } * - * public Property{@code} ageProperty() { + * public IntegerProperty ageProperty() { * return wrapper.field("age", Person::getAge, Person::setAge, 0); * } * } @@ -179,6 +200,10 @@ * ViewModel that would need an update when the structure of the model changes. * * + * + * + * + * * @param * the type of the model class. */ @@ -216,12 +241,12 @@ private class FxPropertyField> implements PropertyField public FxPropertyField(Function> accessor, Supplier> propertySupplier) { this(accessor, null, propertySupplier); } - + @SuppressWarnings("unchecked") public FxPropertyField(Function> accessor, T defaultValue, Supplier> propertySupplier) { this.accessor = accessor; this.defaultValue = defaultValue; - this.targetProperty = (R)propertySupplier.get(); + this.targetProperty = (R) propertySupplier.get(); } @Override @@ -374,409 +399,383 @@ public void reload() { } } + + + /** Field type String **/ + + /** + * Add a new field of type String to this instance of the wrapper. This method is used for model elements that are + * following the normal Java-Beans-standard i.e. the model fields are only available via getter and setter methods + * and not as JavaFX Properties. + * + *

+ * + * Example: + *

+ * + *

+	 * ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
+	 *
+	 * StringProperty wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value)
+	 * 	 -> person.setName(value), "empty");
+	 *
+	 * // or with a method reference
+	 * StringProperty wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
+	 *
+	 * 
+ * + * + * @param getter + * a function that returns the current value of the field for a given model element. Typically you will + * use a method reference to the getter method of the model element. + * @param setter + * a function that sets the given value to the given model element. Typically you will use a method + * reference to the setter method of the model element. + * + * @return The wrapped property instance. + */ + public StringProperty field(StringGetter getter, StringSetter setter) { + return add(new BeanPropertyField<>(getter, setter, SimpleStringProperty::new)); + } + + /** + * Add a new field of type String to this instance of the wrapper. See {@link #field(StringGetter, StringSetter)}. + * This method additionally has a parameter to define the default value that is used when the {@link #reset()} method is used. + * + * + * @param getter + * a function that returns the current value of the field for a given model element. Typically you will + * use a method reference to the getter method of the model element. + * @param setter + * a function that sets the given value to the given model element. Typically you will use a method + * reference to the setter method of the model element. + * @param defaultValue + * the default value that is used when {@link #reset()} is invoked. + * + * @return The wrapped property instance. + */ + public StringProperty field(StringGetter getter, StringSetter setter, String defaultValue) { + return add(new BeanPropertyField<>(getter, setter, defaultValue, SimpleStringProperty::new)); + } + + /** + * Add a new field of type {@link String} to this instance of the wrapper. This method is used for model elements + * that are following the enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties. + *

+ * + * Example: + *

+ * + *

+	 * ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
+	 *
+	 * StringProperty wrappedNameProperty = personWrapper.field(person -> person.nameProperty());
+	 *
+	 * // or with a method reference
+	 * StringProperty wrappedNameProperty = personWrapper.field(Person::nameProperty);
+	 *
+	 * 
+ * + * @param accessor + * a function that returns the property for a given model instance. Typically you will use a method + * reference to the javafx-property accessor method. + * + * @return The wrapped property instance. + */ + public StringProperty field(StringPropertyAccessor accessor) { + return add(new FxPropertyField<>(accessor::apply, SimpleStringProperty::new)); + } + + /** + * Add a new field of type String to this instance of the wrapper. See {@link #field(StringGetter, StringSetter)}. + * This method additionally has a parameter to define the default value that is used when the {@link #reset()} method is used. + * @param accessor + * a function that returns the property for a given model instance. Typically you will use a method + * reference to the javafx-property accessor method. + * @param defaultValue + * the default value that is used when {@link #reset()} is invoked. + * @return The wrapped property instance. + */ + public StringProperty field(StringPropertyAccessor accessor, String defaultValue) { + return add(new FxPropertyField<>(accessor::apply, SimpleStringProperty::new)); + } + + + + + /** + * Add a new field of type String to this instance of the wrapper. See {@link #field(StringGetter, StringSetter)}. + * This method additionally takes a string identifier as first parameter. + * + * This identifier is used to return the same property instance even when the method is invoked multiple times. + * + * @param identifier + * an identifier for the field. + * @param getter + * a function that returns the current value of the field for a given model element. Typically you will + * use a method reference to the getter method of the model element. + * @param setter + * a function that sets the given value to the given model element. Typically you will use a method + * reference to the setter method of the model element. + * @return The wrapped property instance. + */ + public StringProperty field(String identifier, StringGetter getter, StringSetter setter) { + return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleStringProperty::new)); + } + + public StringProperty field(String identifier, StringGetter getter, StringSetter setter, String defaultValue) { + return addIdentified(identifier, new BeanPropertyField<>(getter, setter, defaultValue, SimpleStringProperty::new)); + } + + /** + * Add a new field of type String to this instance of the wrapper. See {@link #field(StringPropertyAccessor)}. This + * method additionally takes a string identifier as first parameter. + * + * This identifier is used to return the same property instance even when the method is invoked multiple times. + * + * @param identifier + * an identifier for the field. + * + * @param accessor + * a function that returns the property for a given model instance. Typically you will use a method + * reference to the javafx-property accessor method. + * @return The wrapped property instance. + */ + public StringProperty field(String identifier, StringPropertyAccessor accessor) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleStringProperty::new)); + } + + public StringProperty field(String identifier, StringPropertyAccessor accessor, String defaultValue) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleStringProperty::new)); + } + + /** Field type Boolean **/ + public BooleanProperty field(BooleanGetter getter, BooleanSetter setter) { return add(new BeanPropertyField<>(getter, setter, SimpleBooleanProperty::new)); } - + public BooleanProperty field(BooleanGetter getter, BooleanSetter setter, boolean defaultValue) { + return add(new BeanPropertyField<>(getter, setter, defaultValue, SimpleBooleanProperty::new)); + } + public BooleanProperty field(BooleanPropertyAccessor accessor) { return add(new FxPropertyField<>(accessor, SimpleBooleanProperty::new)); } - + public BooleanProperty field(BooleanPropertyAccessor accessor, boolean defaultValue) { + return add(new FxPropertyField<>(accessor, defaultValue, SimpleBooleanProperty::new)); + } + public BooleanProperty field(String identifier, BooleanGetter getter, BooleanSetter setter) { return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleBooleanProperty::new)); } - + public BooleanProperty field(String identifier, BooleanGetter getter, BooleanSetter setter, boolean defaultValue) { + return addIdentified(identifier, new BeanPropertyField<>(getter, setter,defaultValue, SimpleBooleanProperty::new)); + } + public BooleanProperty field(String identifier, BooleanPropertyAccessor accessor) { return addIdentified(identifier, new FxPropertyField<>(accessor, SimpleBooleanProperty::new)); } - - + public BooleanProperty field(String identifier, BooleanPropertyAccessor accessor, boolean defaultValue) { + return addIdentified(identifier, new FxPropertyField<>(accessor, defaultValue, SimpleBooleanProperty::new)); + } + + + + /** Field type Double **/ + + public DoubleProperty field(DoubleGetter getter, DoubleSetter setter) { - return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), SimpleDoubleProperty::new)); + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), + SimpleDoubleProperty::new)); } - + public DoubleProperty field(DoubleGetter getter, DoubleSetter setter, double defaultValue) { + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), defaultValue, + SimpleDoubleProperty::new)); + } + public DoubleProperty field(DoublePropertyAccessor accessor) { return add(new FxPropertyField<>(accessor::apply, SimpleDoubleProperty::new)); } - + public DoubleProperty field(DoublePropertyAccessor accessor, double defaultValue) { + return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleDoubleProperty::new)); + } + public DoubleProperty field(String identifier, DoubleGetter getter, DoubleSetter setter) { - return addIdentified(identifier, new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), SimpleDoubleProperty::new)); + return addIdentified(identifier, + new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), + SimpleDoubleProperty::new)); } - + public DoubleProperty field(String identifier, DoubleGetter getter, DoubleSetter setter, double defaultValue) { + return addIdentified(identifier, + new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), defaultValue, + SimpleDoubleProperty::new)); + } + public DoubleProperty field(String identifier, DoublePropertyAccessor accessor) { return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleDoubleProperty::new)); } - - - - - - + public DoubleProperty field(String identifier, DoublePropertyAccessor accessor, double defaultValue) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleDoubleProperty::new)); + } + + + + + /** Field type Float **/ + public FloatProperty field(FloatGetter getter, FloatSetter setter) { - return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), SimpleFloatProperty::new)); + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), + SimpleFloatProperty::new)); } - + public FloatProperty field(FloatGetter getter, FloatSetter setter, float defaultValue) { + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), defaultValue, + SimpleFloatProperty::new)); + } + public FloatProperty field(FloatPropertyAccessor accessor) { return add(new FxPropertyField<>(accessor::apply, SimpleFloatProperty::new)); } - + public FloatProperty field(FloatPropertyAccessor accessor, float defaultValue) { + return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleFloatProperty::new)); + } + public FloatProperty field(String identifier, FloatGetter getter, FloatSetter setter) { - return addIdentified(identifier, new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), SimpleFloatProperty::new)); + return addIdentified(identifier, + new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), + SimpleFloatProperty::new)); } - + public FloatProperty field(String identifier, FloatGetter getter, FloatSetter setter, float defaultValue) { + return addIdentified(identifier, + new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), defaultValue, + SimpleFloatProperty::new)); + } + public FloatProperty field(String identifier, FloatPropertyAccessor accessor) { return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleFloatProperty::new)); } - - - - + public FloatProperty field(String identifier, FloatPropertyAccessor accessor, float defaultValue ) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleFloatProperty::new)); + } + + + /** Field type Integer **/ + + public IntegerProperty field(IntGetter getter, IntSetter setter) { - return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), SimpleIntegerProperty::new)); + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), + SimpleIntegerProperty::new)); } - + public IntegerProperty field(IntGetter getter, IntSetter setter, int defaultValue) { + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), defaultValue, + SimpleIntegerProperty::new)); + } + + public IntegerProperty field(IntPropertyAccessor accessor) { return add(new FxPropertyField<>(accessor::apply, SimpleIntegerProperty::new)); } - + public IntegerProperty field(IntPropertyAccessor accessor, int defaultValue) { + return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleIntegerProperty::new)); + } + public IntegerProperty field(String identifier, IntGetter getter, IntSetter setter) { - return addIdentified(identifier, new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), SimpleIntegerProperty::new)); + return addIdentified(identifier, + new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), + SimpleIntegerProperty::new)); } + public IntegerProperty field(String identifier, IntGetter getter, IntSetter setter, int defaultValue) { + return addIdentified(identifier, + new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), defaultValue, + SimpleIntegerProperty::new)); + } + public IntegerProperty field(String identifier, IntPropertyAccessor accessor) { return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleIntegerProperty::new)); } - - - - + public IntegerProperty field(String identifier, IntPropertyAccessor accessor, int defaultValue) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleIntegerProperty::new)); + } + + + + /** Field type Long **/ + public LongProperty field(LongGetter getter, LongSetter setter) { - return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()), SimpleLongProperty::new)); + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()), + SimpleLongProperty::new)); } - + public LongProperty field(LongGetter getter, LongSetter setter, long defaultValue) { + return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()), + defaultValue, + SimpleLongProperty::new)); + } + public LongProperty field(LongPropertyAccessor accessor) { return add(new FxPropertyField<>(accessor::apply, SimpleLongProperty::new)); } - + public LongProperty field(LongPropertyAccessor accessor, long defaultValue) { + return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleLongProperty::new)); + } + + public LongProperty field(String identifier, LongGetter getter, LongSetter setter) { - return addIdentified(identifier, new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()), SimpleLongProperty::new)); + return addIdentified(identifier, + new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()), + SimpleLongProperty::new)); } - + public LongProperty field(String identifier, LongGetter getter, LongSetter setter, long defaultValue) { + return addIdentified(identifier, + new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()), + defaultValue, + SimpleLongProperty::new)); + } + public LongProperty field(String identifier, LongPropertyAccessor accessor) { return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleLongProperty::new)); } - - - - + public LongProperty field(String identifier, LongPropertyAccessor accessor, long defaultValue) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleLongProperty::new)); + } + + + + /** Field type generic **/ + + public ObjectProperty field(ObjectGetter getter, ObjectSetter setter) { return add(new BeanPropertyField<>(getter, setter, SimpleObjectProperty::new)); } + public ObjectProperty field(ObjectGetter getter, ObjectSetter setter, T defaultValue) { + return add(new BeanPropertyField<>(getter, setter, defaultValue, SimpleObjectProperty::new)); + } + public ObjectProperty field(ObjectPropertyAccessor accessor) { return add(new FxPropertyField<>(accessor::apply, SimpleObjectProperty::new)); } + public ObjectProperty field(ObjectPropertyAccessor accessor, T defaultValue) { + return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleObjectProperty::new)); + } + + public ObjectProperty field(String identifier, ObjectGetter getter, ObjectSetter setter) { return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleObjectProperty::new)); } + public ObjectProperty field(String identifier, ObjectGetter getter, ObjectSetter setter, T defaultValue) { + return addIdentified(identifier, new BeanPropertyField<>(getter, setter, defaultValue, SimpleObjectProperty::new)); + } + public ObjectProperty field(String identifier, ObjectPropertyAccessor accessor) { return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleObjectProperty::new)); } - - - - - public StringProperty field(StringGetter getter, StringSetter setter) { - return add(new BeanPropertyField<>(getter, setter, SimpleStringProperty::new)); - } - - public StringProperty field(StringPropertyAccessor accessor) { - return add(new FxPropertyField<>(accessor::apply, SimpleStringProperty::new)); - } - - public StringProperty field(String identifier, StringGetter getter, StringSetter setter) { - return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleStringProperty::new)); + public ObjectProperty field(String identifier, ObjectPropertyAccessor accessor, T defaultValue) { + return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleObjectProperty::new)); } - - public StringProperty field(String identifier, StringPropertyAccessor accessor) { - return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleStringProperty::new)); - } - - -// -// /** -// * Add a new field to this instance of the wrapper. This method is used for model elements that are following the -// * enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties. -// *

-// * Example: -// *

-// * -// *

-//	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-//	 *
-//	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.nameProperty());
-//	 *
-//	 *     // or with a method reference
-//	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::nameProperty);
-//	 *
-//	 * 
-// * -// * -// * @param accessor -// * a function that returns the property for a given model instance. Typically you will use a method -// * reference to the javafx-property accessor method. -// * -// * @param -// * the type of the field. -// * -// * @return The wrapped property instance. -// */ -// public Property field(Function> accessor) { -// return add(new FxPropertyField<>(accessor)); -// } -// -// /** -// * Add a new field to this instance of the wrapper. This method is used for model elements that are following the -// * enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties. -// *

-// * Additionally you can define a default value that is used as when {@link #reset()} is invoked. -// * -// *

-// * -// * Example: -// *

-// * -// *

-//	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-//	 *
-//	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.nameProperty(), "empty");
-//	 *
-//	 *     // or with a method reference
-//	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::nameProperty, "empty");
-//	 *
-//	 * 
-// * -// * -// * @param accessor -// * a function that returns the property for a given model instance. Typically you will use a method -// * reference to the javafx-property accessor method. -// * @param defaultValue -// * the default value for the field. -// * @param -// * the type of the field. -// * -// * @return The wrapped property instance. -// */ -// public Property field(Function> accessor, T defaultValue) { -// return add(new FxPropertyField<>(accessor, defaultValue)); -// } -// -// /** -// * Add a new field to this instance of the wrapper. This method is used for model elements that are following the -// * normal Java-Beans-standard i.e. the model fields are only available via getter and setter methods and not as -// * JavaFX Properties. -// * -// *

-// * -// * Example: -// *

-// * -// *

-//	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-//	 *
-//	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value) -> person.setName(value), "empty");
-//	 *
-//	 *     // or with a method reference
-//	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
-//	 *
-//	 * 
-// * -// * -// * @param getter -// * a function that returns the current value of the field for a given model element. Typically you will -// * use a method reference to the getter method of the model element. -// * @param setter -// * a function that sets the given value to the given model element. Typically you will use a method -// * reference to the setter method of the model element. -// * @param -// * the type of the field. -// * -// * @return The wrapped property instance. -// */ -// public Property field(Function getter, BiConsumer setter) { -// return add(new BeanPropertyField<>(getter, setter)); -// } -// -// -// -// -// -// /** -// * Add a new field to this instance of the wrapper. This method is used for model elements that are following the -// * normal Java-Beans-standard i.e. the model fields are only available via getter and setter methods and not as -// * JavaFX Properties. -// *

-// * Additionally you can define a default value that is used as when {@link #reset()} is invoked. -// * -// *

-// * -// * Example: -// *

-// * -// *

-//	 *     ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-//	 *
-//	 *     Property{@code} wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value) -> person.setName(value), "empty");
-//	 *
-//	 *     // or with a method reference
-//	 *     Property{@code} wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
-//	 *
-//	 * 
-// * -// * -// * @param getter -// * a function that returns the current value of the field for a given model element. Typically you will -// * use a method reference to the getter method of the model element. -// * @param setter -// * a function that sets the given value to the given model element. Typically you will use a method -// * reference to the setter method of the model element. -// * @param defaultValue -// * the default value for the field. -// * @param -// * the type of the field. -// * -// * @return The wrapped property instance. -// */ -// public Property field(Function getter, BiConsumer setter, T defaultValue) { -// return add(new BeanPropertyField<>(getter, setter, defaultValue)); -// } -// -// -// /** -// * Add a new field to this instance of the wrapper that is identified by the given string. This method is basically -// * the same as {@link #field(Function)} with one difference: This method can be invoked multiply times but will only -// * create a single field instance for every given string identifier. This means that the returned property will be -// * the same instance for each call with the same identifier. -// *

-// * This behaviour can be useful when you don't keep a reference to the returned property but directly call this -// * method in a property accessor method in your viewModel. This way only a single field wrapping will be defined -// * even when the accessor method is called multiple times. See the following example of a typical use case: -// *

-// * -// *

-//	 *
-//	 *     public class PersonViewModel extends ViewModel {
-//	 *
-//	 *         // you only need a reference to the model wrapper itself but no additional references to each wrapped property.
-//	 *         private ModelWrapper{@code} wrapper = new ModelWrapper{@code<>}();
-//	 *
-//	 *
-//	 *         // This method will be used from the view.
-//	 *         // The view can call this method multiple times but will always get the same property instance.
-//	 *         public Property{@code} nameProperty() {
-//	 *              return wrapper.field("name", Person::nameProperty);
-//	 *         }
-//	 *     }
-//	 * 
-// * -// * -// * @param fieldName -// * the identifier for this field. Typically you will use the name of the field in the model. -// * @param accessor -// * a function that returns the property for a given model instance. Typically you will use a method -// * reference to the javafx-property accessor method. -// * @param -// * the type of the field. -// * @return The wrapped property instance. -// */ -// public Property field(String fieldName, Function> accessor) { -// return addIdentified(fieldName, new FxPropertyField<>(accessor)); -// } -// -// /** -// * See {@link #field(String, Function)}. The difference is that this method accepts an additional parameter to -// * define the default value that will be used when {@link #reset()} is invoked. -// * -// * @param fieldName -// * the identifier for this field. Typically you will use the name of the field in the model. -// * @param accessor -// * a function that returns the property for a given model instance. Typically you will use a method -// * reference to the javafx-property accessor method. -// * @param -// * the type of the field. -// * @return The wrapped property instance. -// */ -// public Property field(String fieldName, Function> accessor, T defaultValue) { -// return addIdentified(fieldName, new FxPropertyField<>(accessor, defaultValue)); -// } -// -// /** -// * Add a new field to this instance of the wrapper that is identified by the given string. This method is basically -// * the same as {@link #field(Function, BiConsumer)} with one difference: This method can be invoked multiply times -// * but will only create a single field instance for every given string identifier. This means that the returned -// * property will be the same instance for each call with the same identifier. -// *

-// * This behaviour can be useful when you don't keep a reference to the returned property but directly call this -// * method in a property accessor method in your viewModel. This way only a single field wrapping will be defined -// * even when the accessor method is called multiple times. See the following example of a typical use case: -// *

-// * -// *

-//	 *
-//	 *     public class PersonViewModel extends ViewModel {
-//	 *
-//	 *         // you only need a reference to the model wrapper itself but no additional references to each wrapped property.
-//	 *         private ModelWrapper{@code} wrapper = new ModelWrapper{@code<>}();
-//	 *
-//	 *
-//	 *         // This method will be used from the view.
-//	 *         // The view can call this method multiple times but will always get the same property instance.
-//	 *         public Property{@code} nameProperty() {
-//	 *              return wrapper.field("name", Person::getName, Person::setName);
-//	 *         }
-//	 *     }
-//	 * 
-// * -// * -// * @param fieldName -// * the identifier for this field. Typically you will use the name of the field in the model. -// * @param getter -// * a function that returns the current value of the field for a given model element. Typically you will -// * use a method reference to the getter method of the model element. -// * @param setter -// * a function that sets the given value to the given model element. Typically you will use a method -// * reference to the setter method of the model element. -// * @param -// * the type of the field. -// * @return The wrapped property instance. -// */ -// public Property field(String fieldName, Function getter, BiConsumer setter) { -// return addIdentified(fieldName, new BeanPropertyField<>(getter, setter)); -// } -// -// /** -// * See {@link #field(String, Function, BiConsumer)}. The difference is that this method accepts an additional -// * parameter to define the default value that will be used when {@link #reset()} is invoked. -// * -// * @param fieldName -// * the identifier for this field. Typically you will use the name of the field in the model. -// * @param getter -// * a function that returns the current value of the field for a given model element. Typically you will -// * use a method reference to the getter method of the model element. -// * @param setter -// * a function that sets the given value to the given model element. Typically you will use a method -// * reference to the setter method of the model element. -// * @param -// * the type of the field. -// * @return The wrapped property instance. -// */ -// public Property field(String fieldName, Function getter, BiConsumer setter, T defaultValue) { -// return addIdentified(fieldName, new BeanPropertyField<>(getter, setter, defaultValue)); -// } private > R add(PropertyField field) { fields.add(field); diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectGetter.java deleted file mode 100644 index 8234bbc1d..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectGetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.Function; - -public interface ObjectGetter extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectPropertyAccessor.java deleted file mode 100644 index 3baa5700e..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectPropertyAccessor.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import javafx.beans.property.Property; - -import java.util.function.Function; - -public interface ObjectPropertyAccessor extends Function> { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectSetter.java deleted file mode 100644 index ae0747056..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ObjectSetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.BiConsumer; - -public interface ObjectSetter extends BiConsumer { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringGetter.java deleted file mode 100644 index 241740f0f..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringGetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.Function; - -public interface StringGetter extends Function { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringPropertyAccessor.java deleted file mode 100644 index 7ab9a5fc4..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringPropertyAccessor.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import javafx.beans.property.Property; - -import java.util.function.Function; - -public interface StringPropertyAccessor extends Function> { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringSetter.java deleted file mode 100644 index ce38958e8..000000000 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/StringSetter.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.saxsys.mvvmfx.utils.mapping; - -import java.util.function.BiConsumer; - -public interface StringSetter extends BiConsumer { -} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanGetter.java new file mode 100644 index 000000000..3c0ebb40c --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanGetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.Function; + +/** + * A functional interface to define a getter method of type {@link Boolean}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface BooleanGetter extends Function { + + /** + * @param model the model instance. + * @return the value of the field. + */ + @Override + Boolean apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanPropertyAccessor.java new file mode 100644 index 000000000..ae7aa5321 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanPropertyAccessor.java @@ -0,0 +1,20 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import javafx.beans.property.Property; + +import java.util.function.Function; + +/** + * A functional interface to define an accessor method for a property of type {@link Boolean}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface BooleanPropertyAccessor extends Function> { + /** + * @param model the model instance. + * @return the property field of the model. + */ + @Override + Property apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanSetter.java new file mode 100644 index 000000000..d788f53a9 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanSetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.BiConsumer; + +/** + * A functional interface to define a setter method of type {@link Boolean}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface BooleanSetter extends BiConsumer { + + /** + * @param model the model instance. + * @param value the new value to be set. + */ + @Override + void accept(M model, Boolean value); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleGetter.java new file mode 100644 index 000000000..1a62359ee --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleGetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.Function; + +/** + * A functional interface to define a getter method of type {@link Double}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface DoubleGetter extends Function { + + /** + * @param model the model instance. + * @return the value of the field. + */ + @Override + Double apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoublePropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoublePropertyAccessor.java new file mode 100644 index 000000000..565304488 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoublePropertyAccessor.java @@ -0,0 +1,23 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.Function; + +import javafx.beans.property.DoubleProperty; + +/** + * A functional interface to define an accessor method for a property of type {@link Double}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface DoublePropertyAccessor extends Function { + + /** + * @param model + * the model instance. + * @return the property field of the model. + */ + @Override + DoubleProperty apply(M model); + +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleSetter.java new file mode 100644 index 000000000..7535a853d --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleSetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.BiConsumer; + +/** + * A functional interface to define a setter method of type {@link Double}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface DoubleSetter extends BiConsumer { + + /** + * @param model the model instance. + * @param value the new value to be set. + */ + @Override + void accept(M model, Double value); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatGetter.java new file mode 100644 index 000000000..140b70837 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatGetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.Function; + +/** + * A functional interface to define a getter method of type {@link Float}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface FloatGetter extends Function { + + /** + * @param model the model instance. + * @return the value of the field. + */ + @Override + Float apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatPropertyAccessor.java new file mode 100644 index 000000000..e085827a1 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatPropertyAccessor.java @@ -0,0 +1,22 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import javafx.beans.property.FloatProperty; + +import java.util.function.Function; + +/** + * A functional interface to define an accessor method for a property of type {@link Float}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface FloatPropertyAccessor extends Function { + + /** + * @param model + * the model instance. + * @return the property field of the model. + */ + @Override + FloatProperty apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatSetter.java new file mode 100644 index 000000000..b8aa9b554 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatSetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.BiConsumer; + +/** + * A functional interface to define a setter method of type {@link Float}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface FloatSetter extends BiConsumer { + + /** + * @param model the model instance. + * @param value the new value to be set. + */ + @Override + void accept(M model, Float value); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntGetter.java new file mode 100644 index 000000000..2c56290e4 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntGetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.Function; + +/** + * A functional interface to define a getter method of type {@link Integer}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface IntGetter extends Function { + + /** + * @param model the model instance. + * @return the value of the field. + */ + @Override + Integer apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntPropertyAccessor.java new file mode 100644 index 000000000..d6f9d62ec --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntPropertyAccessor.java @@ -0,0 +1,22 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import javafx.beans.property.IntegerProperty; + +import java.util.function.Function; + +/** + * A functional interface to define an accessor method for a property of type {@link Integer}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface IntPropertyAccessor extends Function { + + /** + * @param model + * the model instance. + * @return the property field of the model. + */ + @Override + IntegerProperty apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntSetter.java new file mode 100644 index 000000000..199eddd83 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntSetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.BiConsumer; + +/** + * A functional interface to define a setter method of type {@link Integer}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface IntSetter extends BiConsumer{ + + /** + * @param model the model instance. + * @param value the new value to be set. + */ + @Override + void accept(M model, Integer value); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongGetter.java new file mode 100644 index 000000000..4b29362f4 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongGetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.Function; + +/** + * A functional interface to define a getter method of type {@link Long}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface LongGetter extends Function { + + /** + * @param model the model instance. + * @return the value of the field. + */ + @Override + Long apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongPropertyAccessor.java new file mode 100644 index 000000000..2dd6f8c9b --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongPropertyAccessor.java @@ -0,0 +1,22 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import javafx.beans.property.LongProperty; + +import java.util.function.Function; + +/** + * A functional interface to define an accessor method for a property of type {@link Long}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface LongPropertyAccessor extends Function { + + /** + * @param model + * the model instance. + * @return the property field of the model. + */ + @Override + LongProperty apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongSetter.java new file mode 100644 index 000000000..7ec985427 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongSetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.BiConsumer; + +/** + * A functional interface to define a setter method of type {@link Long}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface LongSetter extends BiConsumer { + + /** + * @param model the model instance. + * @param value the new value to be set. + */ + @Override + void accept(M model, Long value); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectGetter.java new file mode 100644 index 000000000..bdb5f577a --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectGetter.java @@ -0,0 +1,22 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.Function; + +/** + * A functional interface to define a getter method of a generic type. + * + * @param + * the generic type of the model. + * @param + * the generic type of the field. + */ +@FunctionalInterface +public interface ObjectGetter extends Function { + + /** + * @param model the model instance. + * @return the value of the field. + */ + @Override + T apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectPropertyAccessor.java new file mode 100644 index 000000000..5deca65ba --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectPropertyAccessor.java @@ -0,0 +1,25 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import javafx.beans.property.Property; + +import java.util.function.Function; + +/** + * A functional interface to define an accessor method for a property of a generic type. + * + * @param + * the generic type of the model. + * @param + * the generic type of the field. + */ +@FunctionalInterface +public interface ObjectPropertyAccessor extends Function> { + + /** + * @param model + * the model instance. + * @return the property field of the model. + */ + @Override + Property apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectSetter.java new file mode 100644 index 000000000..bf2553faa --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectSetter.java @@ -0,0 +1,23 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.BiConsumer; + + +/** + * A functional interface to define a setter method of a generic type. + * + * @param + * the generic type of the model. + * @param + * the generic type of the field. + */ +@FunctionalInterface +public interface ObjectSetter extends BiConsumer { + + /** + * @param model the model instance. + * @param value the new value to be set. + */ + @Override + void accept(M model, T value); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringGetter.java new file mode 100644 index 000000000..cf3e9dc63 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringGetter.java @@ -0,0 +1,19 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.Function; + +/** + * A functional interface to define a getter method of type {@link String}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface StringGetter extends Function { + + /** + * @param model the model instance. + * @return the value of the field. + */ + @Override + String apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringPropertyAccessor.java new file mode 100644 index 000000000..ddfbc27b9 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringPropertyAccessor.java @@ -0,0 +1,22 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import javafx.beans.property.Property; + +import java.util.function.Function; + +/** + * A functional interface to define an accessor method for a property of type {@link String}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface StringPropertyAccessor extends Function> { + + /** + * @param model + * the model instance. + * @return the property field of the model. + */ + @Override + Property apply(M model); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringSetter.java new file mode 100644 index 000000000..9b6dec207 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringSetter.java @@ -0,0 +1,20 @@ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.function.BiConsumer; + + +/** + * A functional interface to define a setter method of type {@link String}. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface StringSetter extends BiConsumer { + + /** + * @param model the model instance. + * @param value the new value to be set. + */ + @Override + void accept(M model, String value); +} diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/package-info.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/package-info.java new file mode 100644 index 000000000..8167f3d89 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/package-info.java @@ -0,0 +1,11 @@ +/** + * + * This package contains functional interfaces to define accessors of different types. + * These are used to define a mapping with the {@link de.saxsys.mvvmfx.utils.mapping.ModelWrapper}. + * + * We need these explicit interfaces to support Java with the type deduction when using method references + * of the getter/setter methods of the mapped model class. + * + * @author manuel.mauky + */ +package de.saxsys.mvvmfx.utils.mapping.accessorfunctions; \ No newline at end of file diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java index 00bf5c990..adfb68976 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java @@ -25,12 +25,28 @@ public void setup(){ public void integerProperty(){ final IntegerProperty beanField = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger); final IntegerProperty fxField = wrapper.field(ExampleModel::integerProperty); + final IntegerProperty beanFieldDefault = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger, 5); + final IntegerProperty fxFieldDefault = wrapper.field(ExampleModel::integerProperty, 5); + + final IntegerProperty idBeanField = wrapper.field("int1",ExampleModel::getInteger, ExampleModel::setInteger); + final IntegerProperty idFxField = wrapper.field("int2",ExampleModel::integerProperty); + final IntegerProperty idBeanFieldDefault = wrapper.field("int3",ExampleModel::getInteger, ExampleModel::setInteger, 5); + final IntegerProperty idFxFieldDefault = wrapper.field("int4",ExampleModel::integerProperty, 5); + + } @Test public void doubleProperty(){ final DoubleProperty beanField = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble); final DoubleProperty fxField = wrapper.field(ExampleModel::doubleProperty); + final DoubleProperty beanFieldDefault = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble, 5.1); + final DoubleProperty fxFieldDefault = wrapper.field(ExampleModel::doubleProperty, 5.1); + + final DoubleProperty idBeanField = wrapper.field("double1",ExampleModel::getDouble, ExampleModel::setDouble); + final DoubleProperty idFxField = wrapper.field("double2",ExampleModel::doubleProperty); + final DoubleProperty idBeanFieldDefault = wrapper.field("double3",ExampleModel::getDouble, ExampleModel::setDouble, 5.1); + final DoubleProperty idFxFieldDefault = wrapper.field("double4",ExampleModel::doubleProperty, 5.1); } @@ -38,6 +54,13 @@ public void doubleProperty(){ public void longProperty(){ final LongProperty beanField = wrapper.field(ExampleModel::getLong, ExampleModel::setLong); final LongProperty fxField = wrapper.field(ExampleModel::longProperty); + final LongProperty beanFieldDefault = wrapper.field(ExampleModel::getLong, ExampleModel::setLong, 5l); + final LongProperty fxFieldDefault = wrapper.field(ExampleModel::longProperty,5l); + + final LongProperty idBeanField = wrapper.field("long1",ExampleModel::getLong, ExampleModel::setLong); + final LongProperty idFxField = wrapper.field("long2",ExampleModel::longProperty); + final LongProperty idBeanFieldDefault = wrapper.field("long3",ExampleModel::getLong, ExampleModel::setLong, 5l); + final LongProperty idFxFieldDefault = wrapper.field("long4",ExampleModel::longProperty,5l); } @@ -45,6 +68,13 @@ public void longProperty(){ public void floatProperty(){ final FloatProperty beanField = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat); final FloatProperty fxField = wrapper.field(ExampleModel::floatProperty); + final FloatProperty beanFieldDefault = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat, 5.1f); + final FloatProperty fxFieldDefault = wrapper.field(ExampleModel::floatProperty, 5.1f); + + final FloatProperty idBeanField = wrapper.field("float1",ExampleModel::getFloat, ExampleModel::setFloat); + final FloatProperty idFxField = wrapper.field("float2",ExampleModel::floatProperty); + final FloatProperty idBeanFieldDefault = wrapper.field("float3",ExampleModel::getFloat, ExampleModel::setFloat, 5.1f); + final FloatProperty idFxFieldDefault = wrapper.field("float4",ExampleModel::floatProperty, 5.1f); } @@ -52,6 +82,13 @@ public void floatProperty(){ public void booleanProperty(){ final BooleanProperty beanField = wrapper.field(ExampleModel::getBoolean, ExampleModel::setBoolean); final BooleanProperty fxField = wrapper.field(ExampleModel::booleanProperty); + final BooleanProperty beanFieldDefault = wrapper.field(ExampleModel::getBoolean, ExampleModel::setBoolean, true); + final BooleanProperty fxFieldDefault = wrapper.field(ExampleModel::booleanProperty, true); + + final BooleanProperty idBeanField = wrapper.field("bool1",ExampleModel::getBoolean, ExampleModel::setBoolean); + final BooleanProperty idFxField = wrapper.field("bool2",ExampleModel::booleanProperty); + final BooleanProperty idBeanFieldDefault = wrapper.field("bool3",ExampleModel::getBoolean, ExampleModel::setBoolean, true); + final BooleanProperty idFxFieldDefault = wrapper.field("bool4",ExampleModel::booleanProperty, true); } @@ -59,12 +96,26 @@ public void booleanProperty(){ public void stringProperty(){ final StringProperty beanField = wrapper.field(ExampleModel::getString, ExampleModel::setString); final StringProperty fxField = wrapper.field(ExampleModel::stringProperty); + final StringProperty beanFieldDefault = wrapper.field(ExampleModel::getString, ExampleModel::setString, "test"); + final StringProperty fxFieldDefault = wrapper.field(ExampleModel::stringProperty, "test"); + + final StringProperty idBeanField = wrapper.field("string1", ExampleModel::getString, ExampleModel::setString); + final StringProperty idFxField = wrapper.field("string2",ExampleModel::stringProperty); + final StringProperty idBeanFieldDefault = wrapper.field("string3",ExampleModel::getString, ExampleModel::setString, "test"); + final StringProperty idFxFieldDefault = wrapper.field("string4",ExampleModel::stringProperty, "test"); } @Test public void objectProperty(){ final ObjectProperty beanField = wrapper.field(ExampleModel::getObject, ExampleModel::setObject); - final ObjectProperty fxField = wrapper.field(ExampleModel::objectProperty); + final ObjectProperty fxField =wrapper.field(ExampleModel::objectProperty); + final ObjectProperty beanFieldDefault = wrapper.field(ExampleModel::getObject, ExampleModel::setObject, new Person()); + final ObjectProperty fxFieldDefault = wrapper.field(ExampleModel::objectProperty, new Person()); + + final ObjectProperty idBeanField = wrapper.field("obj1",ExampleModel::getObject, ExampleModel::setObject); + final ObjectProperty idFxField =wrapper.field("obj2",ExampleModel::objectProperty); + final ObjectProperty idBeanFieldDefault = wrapper.field("obj3",ExampleModel::getObject, ExampleModel::setObject, new Person()); + final ObjectProperty idFxFieldDefault = wrapper.field("obj4",ExampleModel::objectProperty, new Person()); } } From 14842189b9eb2c7dec69ecfc457a854ef65a7d21 Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Tue, 28 Apr 2015 14:48:45 +0200 Subject: [PATCH 21/28] #211 fix formatting --- .../mvvmfx/utils/mapping/ModelWrapper.java | 125 ++++--- .../accessorfunctions/BooleanGetter.java | 10 +- .../BooleanPropertyAccessor.java | 8 +- .../accessorfunctions/BooleanSetter.java | 13 +- .../accessorfunctions/DoubleGetter.java | 10 +- .../DoublePropertyAccessor.java | 9 +- .../accessorfunctions/DoubleSetter.java | 13 +- .../accessorfunctions/FloatGetter.java | 12 +- .../FloatPropertyAccessor.java | 7 +- .../accessorfunctions/FloatSetter.java | 13 +- .../mapping/accessorfunctions/IntGetter.java | 10 +- .../IntPropertyAccessor.java | 7 +- .../mapping/accessorfunctions/IntSetter.java | 15 +- .../mapping/accessorfunctions/LongGetter.java | 10 +- .../LongPropertyAccessor.java | 7 +- .../mapping/accessorfunctions/LongSetter.java | 13 +- .../accessorfunctions/ObjectGetter.java | 5 +- .../accessorfunctions/ObjectSetter.java | 10 +- .../accessorfunctions/StringGetter.java | 10 +- .../StringPropertyAccessor.java | 7 +- .../accessorfunctions/StringSetter.java | 13 +- .../mvvmfx/utils/mapping/ExampleModel.java | 192 +++++----- .../utils/mapping/ModelWrapperTest.java | 346 +++++++++--------- .../saxsys/mvvmfx/utils/mapping/Person.java | 40 +- .../saxsys/mvvmfx/utils/mapping/PersonFX.java | 56 +-- .../mvvmfx/utils/mapping/ReturnTypeTest.java | 233 ++++++------ 26 files changed, 641 insertions(+), 553 deletions(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java index 2894eeaa2..e7c5e045f 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java @@ -398,11 +398,11 @@ public void reload() { fields.forEach(field -> field.reload(model)); } } - - - + + + /** Field type String **/ - + /** * Add a new field of type String to this instance of the wrapper. This method is used for model elements that are * following the normal Java-Beans-standard i.e. the model fields are only available via getter and setter methods @@ -415,10 +415,10 @@ public void reload() { * *
 	 * ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-	 *
+	 * 
 	 * StringProperty wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value)
 	 * 	 -> person.setName(value), "empty");
-	 *
+	 * 
 	 * // or with a method reference
 	 * StringProperty wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
 	 *
@@ -437,10 +437,11 @@ public void reload() {
 	public StringProperty field(StringGetter getter, StringSetter setter) {
 		return add(new BeanPropertyField<>(getter, setter, SimpleStringProperty::new));
 	}
-
+	
 	/**
 	 * Add a new field of type String to this instance of the wrapper. See {@link #field(StringGetter, StringSetter)}.
-	 * This method additionally has a parameter to define the default value that is used when the {@link #reset()} method is used.
+	 * This method additionally has a parameter to define the default value that is used when the {@link #reset()}
+	 * method is used.
 	 *
 	 *
 	 * @param getter
@@ -457,7 +458,7 @@ public StringProperty field(StringGetter getter, StringSetter setter) {
 	public StringProperty field(StringGetter getter, StringSetter setter, String defaultValue) {
 		return add(new BeanPropertyField<>(getter, setter, defaultValue, SimpleStringProperty::new));
 	}
-
+	
 	/**
 	 * Add a new field of type {@link String} to this instance of the wrapper. This method is used for model elements
 	 * that are following the enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties.
@@ -468,9 +469,9 @@ public StringProperty field(StringGetter getter, StringSetter setter, Stri
 	 *
 	 * 
 	 * ModelWrapper{@code} personWrapper = new ModelWrapper{@code<>}();
-	 *
+	 * 
 	 * StringProperty wrappedNameProperty = personWrapper.field(person -> person.nameProperty());
-	 *
+	 * 
 	 * // or with a method reference
 	 * StringProperty wrappedNameProperty = personWrapper.field(Person::nameProperty);
 	 *
@@ -485,10 +486,12 @@ public StringProperty field(StringGetter getter, StringSetter setter, Stri
 	public StringProperty field(StringPropertyAccessor accessor) {
 		return add(new FxPropertyField<>(accessor::apply, SimpleStringProperty::new));
 	}
-
+	
 	/**
-	 *  Add a new field of type String to this instance of the wrapper. See {@link #field(StringGetter, StringSetter)}.
-	 * This method additionally has a parameter to define the default value that is used when the {@link #reset()} method is used.
+	 * Add a new field of type String to this instance of the wrapper. See {@link #field(StringGetter, StringSetter)}.
+	 * This method additionally has a parameter to define the default value that is used when the {@link #reset()}
+	 * method is used.
+	 * 
 	 * @param accessor
 	 *            a function that returns the property for a given model instance. Typically you will use a method
 	 *            reference to the javafx-property accessor method.
@@ -499,10 +502,10 @@ public StringProperty field(StringPropertyAccessor accessor) {
 	public StringProperty field(StringPropertyAccessor accessor, String defaultValue) {
 		return add(new FxPropertyField<>(accessor::apply, SimpleStringProperty::new));
 	}
-
-
-
-
+	
+	
+	
+	
 	/**
 	 * Add a new field of type String to this instance of the wrapper. See {@link #field(StringGetter, StringSetter)}.
 	 * This method additionally takes a string identifier as first parameter.
@@ -522,11 +525,12 @@ public StringProperty field(StringPropertyAccessor accessor, String defaultVa
 	public StringProperty field(String identifier, StringGetter getter, StringSetter setter) {
 		return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleStringProperty::new));
 	}
-
+	
 	public StringProperty field(String identifier, StringGetter getter, StringSetter setter, String defaultValue) {
-		return addIdentified(identifier, new BeanPropertyField<>(getter, setter, defaultValue, SimpleStringProperty::new));
+		return addIdentified(identifier, new BeanPropertyField<>(getter, setter, defaultValue,
+				SimpleStringProperty::new));
 	}
-
+	
 	/**
 	 * Add a new field of type String to this instance of the wrapper. See {@link #field(StringPropertyAccessor)}. This
 	 * method additionally takes a string identifier as first parameter.
@@ -544,9 +548,10 @@ public StringProperty field(String identifier, StringGetter getter, StringSet
 	public StringProperty field(String identifier, StringPropertyAccessor accessor) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleStringProperty::new));
 	}
-
+	
 	public StringProperty field(String identifier, StringPropertyAccessor accessor, String defaultValue) {
-		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleStringProperty::new));
+		return addIdentified(identifier,
+				new FxPropertyField<>(accessor::apply, defaultValue, SimpleStringProperty::new));
 	}
 	
 	/** Field type Boolean **/
@@ -554,6 +559,7 @@ public StringProperty field(String identifier, StringPropertyAccessor accesso
 	public BooleanProperty field(BooleanGetter getter, BooleanSetter setter) {
 		return add(new BeanPropertyField<>(getter, setter, SimpleBooleanProperty::new));
 	}
+	
 	public BooleanProperty field(BooleanGetter getter, BooleanSetter setter, boolean defaultValue) {
 		return add(new BeanPropertyField<>(getter, setter, defaultValue, SimpleBooleanProperty::new));
 	}
@@ -561,6 +567,7 @@ public BooleanProperty field(BooleanGetter getter, BooleanSetter setter, b
 	public BooleanProperty field(BooleanPropertyAccessor accessor) {
 		return add(new FxPropertyField<>(accessor, SimpleBooleanProperty::new));
 	}
+	
 	public BooleanProperty field(BooleanPropertyAccessor accessor, boolean defaultValue) {
 		return add(new FxPropertyField<>(accessor, defaultValue, SimpleBooleanProperty::new));
 	}
@@ -568,13 +575,17 @@ public BooleanProperty field(BooleanPropertyAccessor accessor, boolean defaul
 	public BooleanProperty field(String identifier, BooleanGetter getter, BooleanSetter setter) {
 		return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleBooleanProperty::new));
 	}
-	public BooleanProperty field(String identifier, BooleanGetter getter, BooleanSetter setter, boolean defaultValue) {
-		return addIdentified(identifier, new BeanPropertyField<>(getter, setter,defaultValue, SimpleBooleanProperty::new));
+	
+	public BooleanProperty field(String identifier, BooleanGetter getter, BooleanSetter setter,
+			boolean defaultValue) {
+		return addIdentified(identifier, new BeanPropertyField<>(getter, setter, defaultValue,
+				SimpleBooleanProperty::new));
 	}
 	
 	public BooleanProperty field(String identifier, BooleanPropertyAccessor accessor) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor, SimpleBooleanProperty::new));
 	}
+	
 	public BooleanProperty field(String identifier, BooleanPropertyAccessor accessor, boolean defaultValue) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor, defaultValue, SimpleBooleanProperty::new));
 	}
@@ -588,14 +599,17 @@ public DoubleProperty field(DoubleGetter getter, DoubleSetter setter) {
 		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()),
 				SimpleDoubleProperty::new));
 	}
+	
 	public DoubleProperty field(DoubleGetter getter, DoubleSetter setter, double defaultValue) {
-		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), defaultValue,
+		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()),
+				defaultValue,
 				SimpleDoubleProperty::new));
 	}
 	
 	public DoubleProperty field(DoublePropertyAccessor accessor) {
 		return add(new FxPropertyField<>(accessor::apply, SimpleDoubleProperty::new));
 	}
+	
 	public DoubleProperty field(DoublePropertyAccessor accessor, double defaultValue) {
 		return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleDoubleProperty::new));
 	}
@@ -605,17 +619,21 @@ public DoubleProperty field(String identifier, DoubleGetter getter, DoubleSet
 				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()),
 						SimpleDoubleProperty::new));
 	}
+	
 	public DoubleProperty field(String identifier, DoubleGetter getter, DoubleSetter setter, double defaultValue) {
 		return addIdentified(identifier,
-				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()), defaultValue,
+				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.doubleValue()),
+						defaultValue,
 						SimpleDoubleProperty::new));
 	}
 	
 	public DoubleProperty field(String identifier, DoublePropertyAccessor accessor) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleDoubleProperty::new));
 	}
+	
 	public DoubleProperty field(String identifier, DoublePropertyAccessor accessor, double defaultValue) {
-		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleDoubleProperty::new));
+		return addIdentified(identifier,
+				new FxPropertyField<>(accessor::apply, defaultValue, SimpleDoubleProperty::new));
 	}
 	
 	
@@ -627,14 +645,17 @@ public FloatProperty field(FloatGetter getter, FloatSetter setter) {
 		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()),
 				SimpleFloatProperty::new));
 	}
+	
 	public FloatProperty field(FloatGetter getter, FloatSetter setter, float defaultValue) {
-		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), defaultValue,
+		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()),
+				defaultValue,
 				SimpleFloatProperty::new));
 	}
 	
 	public FloatProperty field(FloatPropertyAccessor accessor) {
 		return add(new FxPropertyField<>(accessor::apply, SimpleFloatProperty::new));
 	}
+	
 	public FloatProperty field(FloatPropertyAccessor accessor, float defaultValue) {
 		return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleFloatProperty::new));
 	}
@@ -644,16 +665,19 @@ public FloatProperty field(String identifier, FloatGetter getter, FloatSetter
 				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()),
 						SimpleFloatProperty::new));
 	}
+	
 	public FloatProperty field(String identifier, FloatGetter getter, FloatSetter setter, float defaultValue) {
 		return addIdentified(identifier,
-				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()), defaultValue,
+				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.floatValue()),
+						defaultValue,
 						SimpleFloatProperty::new));
 	}
 	
 	public FloatProperty field(String identifier, FloatPropertyAccessor accessor) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleFloatProperty::new));
 	}
-	public FloatProperty field(String identifier, FloatPropertyAccessor accessor, float defaultValue ) {
+	
+	public FloatProperty field(String identifier, FloatPropertyAccessor accessor, float defaultValue) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleFloatProperty::new));
 	}
 	
@@ -665,8 +689,10 @@ public IntegerProperty field(IntGetter getter, IntSetter setter) {
 		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()),
 				SimpleIntegerProperty::new));
 	}
+	
 	public IntegerProperty field(IntGetter getter, IntSetter setter, int defaultValue) {
-		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), defaultValue,
+		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()),
+				defaultValue,
 				SimpleIntegerProperty::new));
 	}
 	
@@ -674,6 +700,7 @@ public IntegerProperty field(IntGetter getter, IntSetter setter, int defau
 	public IntegerProperty field(IntPropertyAccessor accessor) {
 		return add(new FxPropertyField<>(accessor::apply, SimpleIntegerProperty::new));
 	}
+	
 	public IntegerProperty field(IntPropertyAccessor accessor, int defaultValue) {
 		return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleIntegerProperty::new));
 	}
@@ -683,18 +710,22 @@ public IntegerProperty field(String identifier, IntGetter getter, IntSetter(getter::apply, (m, number) -> setter.accept(m, number.intValue()),
 						SimpleIntegerProperty::new));
 	}
+	
 	public IntegerProperty field(String identifier, IntGetter getter, IntSetter setter, int defaultValue) {
 		return addIdentified(identifier,
-				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()), defaultValue,
+				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.intValue()),
+						defaultValue,
 						SimpleIntegerProperty::new));
 	}
-
-
+	
+	
 	public IntegerProperty field(String identifier, IntPropertyAccessor accessor) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleIntegerProperty::new));
 	}
+	
 	public IntegerProperty field(String identifier, IntPropertyAccessor accessor, int defaultValue) {
-		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleIntegerProperty::new));
+		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue,
+				SimpleIntegerProperty::new));
 	}
 	
 	
@@ -705,6 +736,7 @@ public LongProperty field(LongGetter getter, LongSetter setter) {
 		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()),
 				SimpleLongProperty::new));
 	}
+	
 	public LongProperty field(LongGetter getter, LongSetter setter, long defaultValue) {
 		return add(new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()),
 				defaultValue,
@@ -714,6 +746,7 @@ public LongProperty field(LongGetter getter, LongSetter setter, long defau
 	public LongProperty field(LongPropertyAccessor accessor) {
 		return add(new FxPropertyField<>(accessor::apply, SimpleLongProperty::new));
 	}
+	
 	public LongProperty field(LongPropertyAccessor accessor, long defaultValue) {
 		return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleLongProperty::new));
 	}
@@ -724,6 +757,7 @@ public LongProperty field(String identifier, LongGetter getter, LongSetter
 				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()),
 						SimpleLongProperty::new));
 	}
+	
 	public LongProperty field(String identifier, LongGetter getter, LongSetter setter, long defaultValue) {
 		return addIdentified(identifier,
 				new BeanPropertyField<>(getter::apply, (m, number) -> setter.accept(m, number.longValue()),
@@ -734,7 +768,7 @@ public LongProperty field(String identifier, LongGetter getter, LongSetter
 	public LongProperty field(String identifier, LongPropertyAccessor accessor) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleLongProperty::new));
 	}
-
+	
 	public LongProperty field(String identifier, LongPropertyAccessor accessor, long defaultValue) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleLongProperty::new));
 	}
@@ -747,7 +781,7 @@ public LongProperty field(String identifier, LongPropertyAccessor accessor, l
 	public  ObjectProperty field(ObjectGetter getter, ObjectSetter setter) {
 		return add(new BeanPropertyField<>(getter, setter, SimpleObjectProperty::new));
 	}
-
+	
 	public  ObjectProperty field(ObjectGetter getter, ObjectSetter setter, T defaultValue) {
 		return add(new BeanPropertyField<>(getter, setter, defaultValue, SimpleObjectProperty::new));
 	}
@@ -755,7 +789,7 @@ public  ObjectProperty field(ObjectGetter getter, ObjectSetter
 	public  ObjectProperty field(ObjectPropertyAccessor accessor) {
 		return add(new FxPropertyField<>(accessor::apply, SimpleObjectProperty::new));
 	}
-
+	
 	public  ObjectProperty field(ObjectPropertyAccessor accessor, T defaultValue) {
 		return add(new FxPropertyField<>(accessor::apply, defaultValue, SimpleObjectProperty::new));
 	}
@@ -764,17 +798,20 @@ public  ObjectProperty field(ObjectPropertyAccessor accessor, T defa
 	public  ObjectProperty field(String identifier, ObjectGetter getter, ObjectSetter setter) {
 		return addIdentified(identifier, new BeanPropertyField<>(getter, setter, SimpleObjectProperty::new));
 	}
-
-	public  ObjectProperty field(String identifier, ObjectGetter getter, ObjectSetter setter, T defaultValue) {
-		return addIdentified(identifier, new BeanPropertyField<>(getter, setter, defaultValue, SimpleObjectProperty::new));
+	
+	public  ObjectProperty field(String identifier, ObjectGetter getter, ObjectSetter setter,
+			T defaultValue) {
+		return addIdentified(identifier, new BeanPropertyField<>(getter, setter, defaultValue,
+				SimpleObjectProperty::new));
 	}
 	
 	public  ObjectProperty field(String identifier, ObjectPropertyAccessor accessor) {
 		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, SimpleObjectProperty::new));
 	}
-
+	
 	public  ObjectProperty field(String identifier, ObjectPropertyAccessor accessor, T defaultValue) {
-		return addIdentified(identifier, new FxPropertyField<>(accessor::apply, defaultValue, SimpleObjectProperty::new));
+		return addIdentified(identifier,
+				new FxPropertyField<>(accessor::apply, defaultValue, SimpleObjectProperty::new));
 	}
 	
 	private > R add(PropertyField field) {
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanGetter.java
index 3c0ebb40c..639e3daee 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanGetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanGetter.java
@@ -3,15 +3,17 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define a getter method of type {@link Boolean}. 
+ * A functional interface to define a getter method of type {@link Boolean}.
  * 
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface BooleanGetter extends Function {
-
+	
 	/**
-	 * @param model the model instance.
+	 * @param model
+	 *            the model instance.
 	 * @return the value of the field.
 	 */
 	@Override
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanPropertyAccessor.java
index ae7aa5321..f36e7aa18 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanPropertyAccessor.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanPropertyAccessor.java
@@ -5,14 +5,16 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define an accessor method for a property of type {@link Boolean}. 
+ * A functional interface to define an accessor method for a property of type {@link Boolean}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface BooleanPropertyAccessor extends Function> {
 	/**
-	 * @param model the model instance.
+	 * @param model
+	 *            the model instance.
 	 * @return the property field of the model.
 	 */
 	@Override
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanSetter.java
index d788f53a9..05ad65113 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanSetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/BooleanSetter.java
@@ -3,16 +3,19 @@
 import java.util.function.BiConsumer;
 
 /**
- * A functional interface to define a setter method of type {@link Boolean}. 
+ * A functional interface to define a setter method of type {@link Boolean}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface BooleanSetter extends BiConsumer {
-
+	
 	/**
-	 * @param model the model instance.
-	 * @param value the new value to be set.
+	 * @param model
+	 *            the model instance.
+	 * @param value
+	 *            the new value to be set.
 	 */
 	@Override
 	void accept(M model, Boolean value);
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleGetter.java
index 1a62359ee..32c33c75c 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleGetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleGetter.java
@@ -3,15 +3,17 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define a getter method of type {@link Double}. 
+ * A functional interface to define a getter method of type {@link Double}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface DoubleGetter extends Function {
-
+	
 	/**
-	 * @param model the model instance.
+	 * @param model
+	 *            the model instance.
 	 * @return the value of the field.
 	 */
 	@Override
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoublePropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoublePropertyAccessor.java
index 565304488..ecfadcfed 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoublePropertyAccessor.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoublePropertyAccessor.java
@@ -5,13 +5,14 @@
 import javafx.beans.property.DoubleProperty;
 
 /**
- * A functional interface to define an accessor method for a property of type {@link Double}. 
+ * A functional interface to define an accessor method for a property of type {@link Double}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface DoublePropertyAccessor extends Function {
-
+	
 	/**
 	 * @param model
 	 *            the model instance.
@@ -19,5 +20,5 @@ public interface DoublePropertyAccessor extends Function {
 	 */
 	@Override
 	DoubleProperty apply(M model);
-
+	
 }
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleSetter.java
index 7535a853d..74c8376b4 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleSetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/DoubleSetter.java
@@ -3,16 +3,19 @@
 import java.util.function.BiConsumer;
 
 /**
- * A functional interface to define a setter method of type {@link Double}. 
+ * A functional interface to define a setter method of type {@link Double}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface DoubleSetter extends BiConsumer {
-
+	
 	/**
-	 * @param model the model instance.
-	 * @param value the new value to be set.
+	 * @param model
+	 *            the model instance.
+	 * @param value
+	 *            the new value to be set.
 	 */
 	@Override
 	void accept(M model, Double value);
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatGetter.java
index 140b70837..c04f95055 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatGetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatGetter.java
@@ -3,15 +3,17 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define a getter method of type {@link Float}. 
+ * A functional interface to define a getter method of type {@link Float}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
-public interface FloatGetter  extends Function {
-
+public interface FloatGetter extends Function {
+	
 	/**
-	 * @param model the model instance.
+	 * @param model
+	 *            the model instance.
 	 * @return the value of the field.
 	 */
 	@Override
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatPropertyAccessor.java
index e085827a1..09c914913 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatPropertyAccessor.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatPropertyAccessor.java
@@ -5,13 +5,14 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define an accessor method for a property of type {@link Float}. 
+ * A functional interface to define an accessor method for a property of type {@link Float}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface FloatPropertyAccessor extends Function {
-
+	
 	/**
 	 * @param model
 	 *            the model instance.
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatSetter.java
index b8aa9b554..68199b5f0 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatSetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/FloatSetter.java
@@ -3,16 +3,19 @@
 import java.util.function.BiConsumer;
 
 /**
- * A functional interface to define a setter method of type {@link Float}. 
+ * A functional interface to define a setter method of type {@link Float}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface FloatSetter extends BiConsumer {
-
+	
 	/**
-	 * @param model the model instance.
-	 * @param value the new value to be set.
+	 * @param model
+	 *            the model instance.
+	 * @param value
+	 *            the new value to be set.
 	 */
 	@Override
 	void accept(M model, Float value);
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntGetter.java
index 2c56290e4..c413c3379 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntGetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntGetter.java
@@ -3,15 +3,17 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define a getter method of type {@link Integer}. 
+ * A functional interface to define a getter method of type {@link Integer}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface IntGetter extends Function {
-
+	
 	/**
-	 * @param model the model instance.
+	 * @param model
+	 *            the model instance.
 	 * @return the value of the field.
 	 */
 	@Override
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntPropertyAccessor.java
index d6f9d62ec..ceeeda826 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntPropertyAccessor.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntPropertyAccessor.java
@@ -5,13 +5,14 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define an accessor method for a property of type {@link Integer}. 
+ * A functional interface to define an accessor method for a property of type {@link Integer}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface IntPropertyAccessor extends Function {
-
+	
 	/**
 	 * @param model
 	 *            the model instance.
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntSetter.java
index 199eddd83..654f321f3 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntSetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/IntSetter.java
@@ -3,16 +3,19 @@
 import java.util.function.BiConsumer;
 
 /**
- * A functional interface to define a setter method of type {@link Integer}. 
+ * A functional interface to define a setter method of type {@link Integer}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
-public interface IntSetter extends BiConsumer{
-
+public interface IntSetter extends BiConsumer {
+	
 	/**
-	 * @param model the model instance.
-	 * @param value the new value to be set.
+	 * @param model
+	 *            the model instance.
+	 * @param value
+	 *            the new value to be set.
 	 */
 	@Override
 	void accept(M model, Integer value);
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongGetter.java
index 4b29362f4..85d3f6a60 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongGetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongGetter.java
@@ -3,15 +3,17 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define a getter method of type {@link Long}. 
+ * A functional interface to define a getter method of type {@link Long}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface LongGetter extends Function {
-
+	
 	/**
-	 * @param model the model instance.
+	 * @param model
+	 *            the model instance.
 	 * @return the value of the field.
 	 */
 	@Override
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongPropertyAccessor.java
index 2dd6f8c9b..145d20f34 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongPropertyAccessor.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongPropertyAccessor.java
@@ -5,13 +5,14 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define an accessor method for a property of type {@link Long}. 
+ * A functional interface to define an accessor method for a property of type {@link Long}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface LongPropertyAccessor extends Function {
-
+	
 	/**
 	 * @param model
 	 *            the model instance.
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongSetter.java
index 7ec985427..d53d0613d 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongSetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/LongSetter.java
@@ -3,16 +3,19 @@
 import java.util.function.BiConsumer;
 
 /**
- * A functional interface to define a setter method of type {@link Long}. 
+ * A functional interface to define a setter method of type {@link Long}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface LongSetter extends BiConsumer {
-
+	
 	/**
-	 * @param model the model instance.
-	 * @param value the new value to be set.
+	 * @param model
+	 *            the model instance.
+	 * @param value
+	 *            the new value to be set.
 	 */
 	@Override
 	void accept(M model, Long value);
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectGetter.java
index bdb5f577a..e035ff01b 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectGetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectGetter.java
@@ -12,9 +12,10 @@
  */
 @FunctionalInterface
 public interface ObjectGetter extends Function {
-
+	
 	/**
-	 * @param model the model instance.
+	 * @param model
+	 *            the model instance.
 	 * @return the value of the field.
 	 */
 	@Override
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectSetter.java
index bf2553faa..aff8be60a 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectSetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/ObjectSetter.java
@@ -12,11 +12,13 @@
  *            the generic type of the field.
  */
 @FunctionalInterface
-public interface ObjectSetter extends BiConsumer {
-
+public interface ObjectSetter extends BiConsumer {
+	
 	/**
-	 * @param model the model instance.
-	 * @param value the new value to be set.
+	 * @param model
+	 *            the model instance.
+	 * @param value
+	 *            the new value to be set.
 	 */
 	@Override
 	void accept(M model, T value);
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringGetter.java
index cf3e9dc63..8c9838892 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringGetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringGetter.java
@@ -3,15 +3,17 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define a getter method of type {@link String}. 
+ * A functional interface to define a getter method of type {@link String}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface StringGetter extends Function {
-
+	
 	/**
-	 * @param model the model instance.
+	 * @param model
+	 *            the model instance.
 	 * @return the value of the field.
 	 */
 	@Override
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringPropertyAccessor.java
index ddfbc27b9..3fd6772ba 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringPropertyAccessor.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringPropertyAccessor.java
@@ -5,13 +5,14 @@
 import java.util.function.Function;
 
 /**
- * A functional interface to define an accessor method for a property of type {@link String}. 
+ * A functional interface to define an accessor method for a property of type {@link String}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface StringPropertyAccessor extends Function> {
-
+	
 	/**
 	 * @param model
 	 *            the model instance.
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringSetter.java
index 9b6dec207..0fa709647 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringSetter.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/StringSetter.java
@@ -4,16 +4,19 @@
 
 
 /**
- * A functional interface to define a setter method of type {@link String}. 
+ * A functional interface to define a setter method of type {@link String}.
  *
- * @param  the generic type of the model.
+ * @param 
+ *            the generic type of the model.
  */
 @FunctionalInterface
 public interface StringSetter extends BiConsumer {
-
+	
 	/**
-	 * @param model the model instance.
-	 * @param value the new value to be set.
+	 * @param model
+	 *            the model instance.
+	 * @param value
+	 *            the new value to be set.
 	 */
 	@Override
 	void accept(M model, String value);
diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java
index caa4b85d9..bd5b556f6 100644
--- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java
+++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java
@@ -3,100 +3,100 @@
 import javafx.beans.property.*;
 
 public class ExampleModel {
-
-    private IntegerProperty integerProperty = new SimpleIntegerProperty();
-    private DoubleProperty doubleProperty = new SimpleDoubleProperty();
-    private FloatProperty floatProperty = new SimpleFloatProperty();
-    private LongProperty longProperty = new SimpleLongProperty();
-
-    private StringProperty stringProperty = new SimpleStringProperty();
-
-    private ObjectProperty objectProperty = new SimpleObjectProperty<>();
-
-    private BooleanProperty booleanProperty = new SimpleBooleanProperty();
-
-
-    public int getInteger() {
-        return integerProperty.get();
-    }
-
-    public IntegerProperty integerProperty() {
-        return integerProperty;
-    }
-
-    public void setInteger(int integerProperty) {
-        this.integerProperty.set(integerProperty);
-    }
-
-    public double getDouble() {
-        return doubleProperty.get();
-    }
-
-    public DoubleProperty doubleProperty() {
-        return doubleProperty;
-    }
-
-    public void setDouble(double doubleProperty) {
-        this.doubleProperty.set(doubleProperty);
-    }
-
-    public float getFloat() {
-        return floatProperty.get();
-    }
-
-    public FloatProperty floatProperty() {
-        return floatProperty;
-    }
-
-    public void setFloat(float floatProperty) {
-        this.floatProperty.set(floatProperty);
-    }
-
-    public long getLong() {
-        return longProperty.get();
-    }
-
-    public LongProperty longProperty() {
-        return longProperty;
-    }
-
-    public void setLong(long longProperty) {
-        this.longProperty.set(longProperty);
-    }
-
-    public String getString() {
-        return stringProperty.get();
-    }
-
-    public StringProperty stringProperty() {
-        return stringProperty;
-    }
-
-    public void setString(String stringProperty) {
-        this.stringProperty.set(stringProperty);
-    }
-
-    public Person getObject() {
-        return objectProperty.get();
-    }
-
-    public ObjectProperty objectProperty() {
-        return objectProperty;
-    }
-
-    public void setObject(Person objectProperty) {
-        this.objectProperty.set(objectProperty);
-    }
-
-    public boolean getBoolean() {
-        return booleanProperty.get();
-    }
-
-    public BooleanProperty booleanProperty() {
-        return booleanProperty;
-    }
-
-    public void setBoolean(boolean booleanProperty) {
-        this.booleanProperty.set(booleanProperty);
-    }
+	
+	private IntegerProperty integerProperty = new SimpleIntegerProperty();
+	private DoubleProperty doubleProperty = new SimpleDoubleProperty();
+	private FloatProperty floatProperty = new SimpleFloatProperty();
+	private LongProperty longProperty = new SimpleLongProperty();
+	
+	private StringProperty stringProperty = new SimpleStringProperty();
+	
+	private ObjectProperty objectProperty = new SimpleObjectProperty<>();
+	
+	private BooleanProperty booleanProperty = new SimpleBooleanProperty();
+	
+	
+	public int getInteger() {
+		return integerProperty.get();
+	}
+	
+	public IntegerProperty integerProperty() {
+		return integerProperty;
+	}
+	
+	public void setInteger(int integerProperty) {
+		this.integerProperty.set(integerProperty);
+	}
+	
+	public double getDouble() {
+		return doubleProperty.get();
+	}
+	
+	public DoubleProperty doubleProperty() {
+		return doubleProperty;
+	}
+	
+	public void setDouble(double doubleProperty) {
+		this.doubleProperty.set(doubleProperty);
+	}
+	
+	public float getFloat() {
+		return floatProperty.get();
+	}
+	
+	public FloatProperty floatProperty() {
+		return floatProperty;
+	}
+	
+	public void setFloat(float floatProperty) {
+		this.floatProperty.set(floatProperty);
+	}
+	
+	public long getLong() {
+		return longProperty.get();
+	}
+	
+	public LongProperty longProperty() {
+		return longProperty;
+	}
+	
+	public void setLong(long longProperty) {
+		this.longProperty.set(longProperty);
+	}
+	
+	public String getString() {
+		return stringProperty.get();
+	}
+	
+	public StringProperty stringProperty() {
+		return stringProperty;
+	}
+	
+	public void setString(String stringProperty) {
+		this.stringProperty.set(stringProperty);
+	}
+	
+	public Person getObject() {
+		return objectProperty.get();
+	}
+	
+	public ObjectProperty objectProperty() {
+		return objectProperty;
+	}
+	
+	public void setObject(Person objectProperty) {
+		this.objectProperty.set(objectProperty);
+	}
+	
+	public boolean getBoolean() {
+		return booleanProperty.get();
+	}
+	
+	public BooleanProperty booleanProperty() {
+		return booleanProperty;
+	}
+	
+	public void setBoolean(boolean booleanProperty) {
+		this.booleanProperty.set(booleanProperty);
+	}
 }
diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java
index 9394cbbac..45f1448e8 100644
--- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java
+++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java
@@ -7,177 +7,177 @@
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class ModelWrapperTest {
-    
-
-    @Test
-    public void testWithGetterAndSetter(){
-        Person person = new Person();
-        person.setName("horst");
-        person.setAge(32);
-
-        ModelWrapper personWrapper = new ModelWrapper<>(person);
-        
-        final StringProperty nameProperty = personWrapper.field(Person::getName, Person::setName);
-        final IntegerProperty ageProperty = personWrapper.field(Person::getAge, Person::setAge);
-        
-        assertThat(nameProperty.getValue()).isEqualTo("horst");
-        assertThat(ageProperty.getValue()).isEqualTo(32);
-
-
-        nameProperty.setValue("hugo");
-        ageProperty.setValue(33);
-
-        // still the old values
-        assertThat(person.getName()).isEqualTo("horst");
-        assertThat(person.getAge()).isEqualTo(32);
-
-
-        personWrapper.commit();
-
-        // now the new values are reflected in the wrapped person
-        assertThat(person.getName()).isEqualTo("hugo");
-        assertThat(person.getAge()).isEqualTo(33);
-
-
-
-        nameProperty.setValue("luise");
-        ageProperty.setValue(15);
-
-        personWrapper.reset();
-
-        assertThat(nameProperty.getValue()).isEqualTo(null);
-        assertThat(ageProperty.getValue()).isEqualTo(0);
-
-        // the wrapped object has still the values from the last commit.
-        assertThat(person.getName()).isEqualTo("hugo");
-        assertThat(person.getAge()).isEqualTo(33);
-
-
-        personWrapper.reload();
-        // now the properties have the values from the wrapped object
-        assertThat(nameProperty.getValue()).isEqualTo("hugo");
-        assertThat(ageProperty.getValue()).isEqualTo(33);
-
-
-        Person otherPerson = new Person();
-        otherPerson.setName("gisela");
-        otherPerson.setAge(23);
-
-        personWrapper.set(otherPerson);
-        personWrapper.reload();
-
-        assertThat(nameProperty.getValue()).isEqualTo("gisela");
-        assertThat(ageProperty.getValue()).isEqualTo(23);
-
-        nameProperty.setValue("georg");
-        ageProperty.setValue(24);
-
-        personWrapper.commit();
-
-        // old person has still the old values
-        assertThat(person.getName()).isEqualTo("hugo");
-        assertThat(person.getAge()).isEqualTo(33);
-
-        // new person has the new values
-        assertThat(otherPerson.getName()).isEqualTo("georg");
-        assertThat(otherPerson.getAge()).isEqualTo(24);
-
-    }
-
-
-    @Test
-    public void testWithJavaFXPropertiesField() {
-        PersonFX person = new PersonFX();
-        person.setName("horst");
-        person.setAge(32);
-
-        ModelWrapper personWrapper = new ModelWrapper<>(person);
-
-
-        final StringProperty nameProperty = personWrapper.field(PersonFX::nameProperty);
-        final IntegerProperty ageProperty = personWrapper.field(PersonFX::ageProperty);
-
-        assertThat(nameProperty.getValue()).isEqualTo("horst");
-        assertThat(ageProperty.getValue()).isEqualTo(32);
-
-
-        nameProperty.setValue("hugo");
-        ageProperty.setValue(33);
-
-        // still the old values
-        assertThat(person.getName()).isEqualTo("horst");
-        assertThat(person.getAge()).isEqualTo(32);
-
-
-        personWrapper.commit();
-
-        // now the new values are reflected in the wrapped person
-        assertThat(person.getName()).isEqualTo("hugo");
-        assertThat(person.getAge()).isEqualTo(33);
-
-
-
-        nameProperty.setValue("luise");
-        ageProperty.setValue(15);
-
-        personWrapper.reset();
-
-        assertThat(nameProperty.getValue()).isEqualTo(null);
-        assertThat(ageProperty.getValue()).isEqualTo(0);
-
-        // the wrapped object has still the values from the last commit.
-        assertThat(person.getName()).isEqualTo("hugo");
-        assertThat(person.getAge()).isEqualTo(33);
-
-
-        personWrapper.reload();
-        // now the properties have the values from the wrapped object
-        assertThat(nameProperty.getValue()).isEqualTo("hugo");
-        assertThat(ageProperty.getValue()).isEqualTo(33);
-
-
-        PersonFX otherPerson = new PersonFX();
-        otherPerson.setName("gisela");
-        otherPerson.setAge(23);
-
-        personWrapper.set(otherPerson);
-        personWrapper.reload();
-
-        assertThat(nameProperty.getValue()).isEqualTo("gisela");
-        assertThat(ageProperty.getValue()).isEqualTo(23);
-
-        nameProperty.setValue("georg");
-        ageProperty.setValue(24);
-
-        personWrapper.commit();
-
-        // old person has still the old values
-        assertThat(person.getName()).isEqualTo("hugo");
-        assertThat(person.getAge()).isEqualTo(33);
-
-        // new person has the new values
-        assertThat(otherPerson.getName()).isEqualTo("georg");
-        assertThat(otherPerson.getAge()).isEqualTo(24);
-    }
-
-    @Test
-    public void testIdentifiedFields(){
-        Person person = new Person();
-        person.setName("horst");
-        person.setAge(32);
-
-        ModelWrapper personWrapper = new ModelWrapper<>();
-
-        final StringProperty nameProperty = personWrapper.field("name", Person::getName, Person::setName);
-        final IntegerProperty ageProperty = personWrapper.field("age", Person::getAge, Person::setAge);
-
-
-        final StringProperty nameProperty2 = personWrapper.field("name", Person::getName, Person::setName);
-        final IntegerProperty ageProperty2 = personWrapper.field("age", Person::getAge, Person::setAge);
-
-
-        assertThat(nameProperty).isSameAs(nameProperty2);
-        assertThat(ageProperty).isSameAs(ageProperty2);
-    }
-
+	
+	
+	@Test
+	public void testWithGetterAndSetter() {
+		Person person = new Person();
+		person.setName("horst");
+		person.setAge(32);
+		
+		ModelWrapper personWrapper = new ModelWrapper<>(person);
+		
+		final StringProperty nameProperty = personWrapper.field(Person::getName, Person::setName);
+		final IntegerProperty ageProperty = personWrapper.field(Person::getAge, Person::setAge);
+		
+		assertThat(nameProperty.getValue()).isEqualTo("horst");
+		assertThat(ageProperty.getValue()).isEqualTo(32);
+		
+		
+		nameProperty.setValue("hugo");
+		ageProperty.setValue(33);
+		
+		// still the old values
+		assertThat(person.getName()).isEqualTo("horst");
+		assertThat(person.getAge()).isEqualTo(32);
+		
+		
+		personWrapper.commit();
+		
+		// now the new values are reflected in the wrapped person
+		assertThat(person.getName()).isEqualTo("hugo");
+		assertThat(person.getAge()).isEqualTo(33);
+		
+		
+		
+		nameProperty.setValue("luise");
+		ageProperty.setValue(15);
+		
+		personWrapper.reset();
+		
+		assertThat(nameProperty.getValue()).isEqualTo(null);
+		assertThat(ageProperty.getValue()).isEqualTo(0);
+		
+		// the wrapped object has still the values from the last commit.
+		assertThat(person.getName()).isEqualTo("hugo");
+		assertThat(person.getAge()).isEqualTo(33);
+		
+		
+		personWrapper.reload();
+		// now the properties have the values from the wrapped object
+		assertThat(nameProperty.getValue()).isEqualTo("hugo");
+		assertThat(ageProperty.getValue()).isEqualTo(33);
+		
+		
+		Person otherPerson = new Person();
+		otherPerson.setName("gisela");
+		otherPerson.setAge(23);
+		
+		personWrapper.set(otherPerson);
+		personWrapper.reload();
+		
+		assertThat(nameProperty.getValue()).isEqualTo("gisela");
+		assertThat(ageProperty.getValue()).isEqualTo(23);
+		
+		nameProperty.setValue("georg");
+		ageProperty.setValue(24);
+		
+		personWrapper.commit();
+		
+		// old person has still the old values
+		assertThat(person.getName()).isEqualTo("hugo");
+		assertThat(person.getAge()).isEqualTo(33);
+		
+		// new person has the new values
+		assertThat(otherPerson.getName()).isEqualTo("georg");
+		assertThat(otherPerson.getAge()).isEqualTo(24);
+		
+	}
+	
+	
+	@Test
+	public void testWithJavaFXPropertiesField() {
+		PersonFX person = new PersonFX();
+		person.setName("horst");
+		person.setAge(32);
+		
+		ModelWrapper personWrapper = new ModelWrapper<>(person);
+		
+		
+		final StringProperty nameProperty = personWrapper.field(PersonFX::nameProperty);
+		final IntegerProperty ageProperty = personWrapper.field(PersonFX::ageProperty);
+		
+		assertThat(nameProperty.getValue()).isEqualTo("horst");
+		assertThat(ageProperty.getValue()).isEqualTo(32);
+		
+		
+		nameProperty.setValue("hugo");
+		ageProperty.setValue(33);
+		
+		// still the old values
+		assertThat(person.getName()).isEqualTo("horst");
+		assertThat(person.getAge()).isEqualTo(32);
+		
+		
+		personWrapper.commit();
+		
+		// now the new values are reflected in the wrapped person
+		assertThat(person.getName()).isEqualTo("hugo");
+		assertThat(person.getAge()).isEqualTo(33);
+		
+		
+		
+		nameProperty.setValue("luise");
+		ageProperty.setValue(15);
+		
+		personWrapper.reset();
+		
+		assertThat(nameProperty.getValue()).isEqualTo(null);
+		assertThat(ageProperty.getValue()).isEqualTo(0);
+		
+		// the wrapped object has still the values from the last commit.
+		assertThat(person.getName()).isEqualTo("hugo");
+		assertThat(person.getAge()).isEqualTo(33);
+		
+		
+		personWrapper.reload();
+		// now the properties have the values from the wrapped object
+		assertThat(nameProperty.getValue()).isEqualTo("hugo");
+		assertThat(ageProperty.getValue()).isEqualTo(33);
+		
+		
+		PersonFX otherPerson = new PersonFX();
+		otherPerson.setName("gisela");
+		otherPerson.setAge(23);
+		
+		personWrapper.set(otherPerson);
+		personWrapper.reload();
+		
+		assertThat(nameProperty.getValue()).isEqualTo("gisela");
+		assertThat(ageProperty.getValue()).isEqualTo(23);
+		
+		nameProperty.setValue("georg");
+		ageProperty.setValue(24);
+		
+		personWrapper.commit();
+		
+		// old person has still the old values
+		assertThat(person.getName()).isEqualTo("hugo");
+		assertThat(person.getAge()).isEqualTo(33);
+		
+		// new person has the new values
+		assertThat(otherPerson.getName()).isEqualTo("georg");
+		assertThat(otherPerson.getAge()).isEqualTo(24);
+	}
+	
+	@Test
+	public void testIdentifiedFields() {
+		Person person = new Person();
+		person.setName("horst");
+		person.setAge(32);
+		
+		ModelWrapper personWrapper = new ModelWrapper<>();
+		
+		final StringProperty nameProperty = personWrapper.field("name", Person::getName, Person::setName);
+		final IntegerProperty ageProperty = personWrapper.field("age", Person::getAge, Person::setAge);
+		
+		
+		final StringProperty nameProperty2 = personWrapper.field("name", Person::getName, Person::setName);
+		final IntegerProperty ageProperty2 = personWrapper.field("age", Person::getAge, Person::setAge);
+		
+		
+		assertThat(nameProperty).isSameAs(nameProperty2);
+		assertThat(ageProperty).isSameAs(ageProperty2);
+	}
+	
 }
diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/Person.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/Person.java
index 89d8cda80..3dc4d6297 100644
--- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/Person.java
+++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/Person.java
@@ -1,24 +1,24 @@
 package de.saxsys.mvvmfx.utils.mapping;
 
 public class Person {
-
-    private String name;
-
-    private int age;
-
-    public int getAge() {
-        return age;
-    }
-
-    public void setAge(int age) {
-        this.age = age;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
+	
+	private String name;
+	
+	private int age;
+	
+	public int getAge() {
+		return age;
+	}
+	
+	public void setAge(int age) {
+		this.age = age;
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
 }
diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonFX.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonFX.java
index 06f5366cb..445c0a512 100644
--- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonFX.java
+++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonFX.java
@@ -6,32 +6,32 @@
 import javafx.beans.property.StringProperty;
 
 public class PersonFX {
-
-    private StringProperty name = new SimpleStringProperty();
-
-    private IntegerProperty age = new SimpleIntegerProperty();
-
-    public String getName() {
-        return name.get();
-    }
-
-    public StringProperty nameProperty() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name.set(name);
-    }
-
-    public int getAge() {
-        return age.get();
-    }
-
-    public IntegerProperty ageProperty() {
-        return age;
-    }
-
-    public void setAge(int age) {
-        this.age.set(age);
-    }
+	
+	private StringProperty name = new SimpleStringProperty();
+	
+	private IntegerProperty age = new SimpleIntegerProperty();
+	
+	public String getName() {
+		return name.get();
+	}
+	
+	public StringProperty nameProperty() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name.set(name);
+	}
+	
+	public int getAge() {
+		return age.get();
+	}
+	
+	public IntegerProperty ageProperty() {
+		return age;
+	}
+	
+	public void setAge(int age) {
+		this.age.set(age);
+	}
 }
diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java
index adfb68976..f55777e09 100644
--- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java
+++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ReturnTypeTest.java
@@ -5,117 +5,128 @@
 import org.junit.Test;
 
 /**
- * This test is used to check the return values when fields are mapped.
- * See Issue 211 https://github.com/sialcasa/mvvmFX/issues/211
+ * This test is used to check the return values when fields are mapped. See Issue 211 https://github.com/sialcasa/mvvmFX/issues/211
  */
 public class ReturnTypeTest {
-
-    private ModelWrapper wrapper;
-
-    private ExampleModel model;
-
-    @Before
-    public void setup(){
-        wrapper = new ModelWrapper<>();
-        model = new ExampleModel();
-    }
-
-
-    @Test
-    public void integerProperty(){
-        final IntegerProperty beanField = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger);
-        final IntegerProperty fxField = wrapper.field(ExampleModel::integerProperty);
-        final IntegerProperty beanFieldDefault = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger, 5);
-        final IntegerProperty fxFieldDefault = wrapper.field(ExampleModel::integerProperty, 5);
-
-        final IntegerProperty idBeanField = wrapper.field("int1",ExampleModel::getInteger, ExampleModel::setInteger);
-        final IntegerProperty idFxField = wrapper.field("int2",ExampleModel::integerProperty);
-        final IntegerProperty idBeanFieldDefault = wrapper.field("int3",ExampleModel::getInteger, ExampleModel::setInteger, 5);
-        final IntegerProperty idFxFieldDefault = wrapper.field("int4",ExampleModel::integerProperty, 5);
-
-
-    }
-
-    @Test
-    public void doubleProperty(){
-        final DoubleProperty beanField = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble);
-        final DoubleProperty fxField = wrapper.field(ExampleModel::doubleProperty);
-        final DoubleProperty beanFieldDefault = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble, 5.1);
-        final DoubleProperty fxFieldDefault = wrapper.field(ExampleModel::doubleProperty, 5.1);
-
-        final DoubleProperty idBeanField = wrapper.field("double1",ExampleModel::getDouble, ExampleModel::setDouble);
-        final DoubleProperty idFxField = wrapper.field("double2",ExampleModel::doubleProperty);
-        final DoubleProperty idBeanFieldDefault = wrapper.field("double3",ExampleModel::getDouble, ExampleModel::setDouble, 5.1);
-        final DoubleProperty idFxFieldDefault = wrapper.field("double4",ExampleModel::doubleProperty, 5.1);
-    }
-
-
-    @Test
-    public void longProperty(){
-        final LongProperty beanField = wrapper.field(ExampleModel::getLong, ExampleModel::setLong);
-        final LongProperty fxField = wrapper.field(ExampleModel::longProperty);
-        final LongProperty beanFieldDefault = wrapper.field(ExampleModel::getLong, ExampleModel::setLong, 5l);
-        final LongProperty fxFieldDefault = wrapper.field(ExampleModel::longProperty,5l);
-
-        final LongProperty idBeanField = wrapper.field("long1",ExampleModel::getLong, ExampleModel::setLong);
-        final LongProperty idFxField = wrapper.field("long2",ExampleModel::longProperty);
-        final LongProperty idBeanFieldDefault = wrapper.field("long3",ExampleModel::getLong, ExampleModel::setLong, 5l);
-        final LongProperty idFxFieldDefault = wrapper.field("long4",ExampleModel::longProperty,5l);
-    }
-
-
-    @Test
-    public void floatProperty(){
-        final FloatProperty beanField = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat);
-        final FloatProperty fxField = wrapper.field(ExampleModel::floatProperty);
-        final FloatProperty beanFieldDefault = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat, 5.1f);
-        final FloatProperty fxFieldDefault = wrapper.field(ExampleModel::floatProperty, 5.1f);
-
-        final FloatProperty idBeanField = wrapper.field("float1",ExampleModel::getFloat, ExampleModel::setFloat);
-        final FloatProperty idFxField = wrapper.field("float2",ExampleModel::floatProperty);
-        final FloatProperty idBeanFieldDefault = wrapper.field("float3",ExampleModel::getFloat, ExampleModel::setFloat, 5.1f);
-        final FloatProperty idFxFieldDefault = wrapper.field("float4",ExampleModel::floatProperty, 5.1f);
-    }
-
-
-    @Test
-    public void booleanProperty(){
-        final BooleanProperty beanField = wrapper.field(ExampleModel::getBoolean, ExampleModel::setBoolean);
-        final BooleanProperty fxField = wrapper.field(ExampleModel::booleanProperty);
-        final BooleanProperty beanFieldDefault = wrapper.field(ExampleModel::getBoolean, ExampleModel::setBoolean, true);
-        final BooleanProperty fxFieldDefault = wrapper.field(ExampleModel::booleanProperty, true);
-
-        final BooleanProperty idBeanField = wrapper.field("bool1",ExampleModel::getBoolean, ExampleModel::setBoolean);
-        final BooleanProperty idFxField = wrapper.field("bool2",ExampleModel::booleanProperty);
-        final BooleanProperty idBeanFieldDefault = wrapper.field("bool3",ExampleModel::getBoolean, ExampleModel::setBoolean, true);
-        final BooleanProperty idFxFieldDefault = wrapper.field("bool4",ExampleModel::booleanProperty, true);
-    }
-
-
-    @Test
-    public void stringProperty(){
-        final StringProperty beanField = wrapper.field(ExampleModel::getString, ExampleModel::setString);
-        final StringProperty fxField = wrapper.field(ExampleModel::stringProperty);
-        final StringProperty beanFieldDefault = wrapper.field(ExampleModel::getString, ExampleModel::setString, "test");
-        final StringProperty fxFieldDefault = wrapper.field(ExampleModel::stringProperty, "test");
-
-        final StringProperty idBeanField = wrapper.field("string1", ExampleModel::getString, ExampleModel::setString);
-        final StringProperty idFxField = wrapper.field("string2",ExampleModel::stringProperty);
-        final StringProperty idBeanFieldDefault = wrapper.field("string3",ExampleModel::getString, ExampleModel::setString, "test");
-        final StringProperty idFxFieldDefault = wrapper.field("string4",ExampleModel::stringProperty, "test");
-    }
-
-    @Test
-    public void objectProperty(){
-        final ObjectProperty beanField = wrapper.field(ExampleModel::getObject, ExampleModel::setObject);
-        final ObjectProperty fxField =wrapper.field(ExampleModel::objectProperty);
-        final ObjectProperty beanFieldDefault = wrapper.field(ExampleModel::getObject, ExampleModel::setObject, new Person());
-        final ObjectProperty fxFieldDefault = wrapper.field(ExampleModel::objectProperty, new Person());
-
-        final ObjectProperty idBeanField = wrapper.field("obj1",ExampleModel::getObject, ExampleModel::setObject);
-        final ObjectProperty idFxField =wrapper.field("obj2",ExampleModel::objectProperty);
-        final ObjectProperty idBeanFieldDefault = wrapper.field("obj3",ExampleModel::getObject, ExampleModel::setObject, new Person());
-        final ObjectProperty idFxFieldDefault = wrapper.field("obj4",ExampleModel::objectProperty, new Person());
-    }
-
+	
+	private ModelWrapper wrapper;
+	
+	private ExampleModel model;
+	
+	@Before
+	public void setup() {
+		wrapper = new ModelWrapper<>();
+		model = new ExampleModel();
+	}
+	
+	
+	@Test
+	public void integerProperty() {
+		final IntegerProperty beanField = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger);
+		final IntegerProperty fxField = wrapper.field(ExampleModel::integerProperty);
+		final IntegerProperty beanFieldDefault = wrapper.field(ExampleModel::getInteger, ExampleModel::setInteger, 5);
+		final IntegerProperty fxFieldDefault = wrapper.field(ExampleModel::integerProperty, 5);
+		
+		final IntegerProperty idBeanField = wrapper.field("int1", ExampleModel::getInteger, ExampleModel::setInteger);
+		final IntegerProperty idFxField = wrapper.field("int2", ExampleModel::integerProperty);
+		final IntegerProperty idBeanFieldDefault = wrapper.field("int3", ExampleModel::getInteger,
+				ExampleModel::setInteger, 5);
+		final IntegerProperty idFxFieldDefault = wrapper.field("int4", ExampleModel::integerProperty, 5);
+		
+		
+	}
+	
+	@Test
+	public void doubleProperty() {
+		final DoubleProperty beanField = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble);
+		final DoubleProperty fxField = wrapper.field(ExampleModel::doubleProperty);
+		final DoubleProperty beanFieldDefault = wrapper.field(ExampleModel::getDouble, ExampleModel::setDouble, 5.1);
+		final DoubleProperty fxFieldDefault = wrapper.field(ExampleModel::doubleProperty, 5.1);
+		
+		final DoubleProperty idBeanField = wrapper.field("double1", ExampleModel::getDouble, ExampleModel::setDouble);
+		final DoubleProperty idFxField = wrapper.field("double2", ExampleModel::doubleProperty);
+		final DoubleProperty idBeanFieldDefault = wrapper.field("double3", ExampleModel::getDouble,
+				ExampleModel::setDouble, 5.1);
+		final DoubleProperty idFxFieldDefault = wrapper.field("double4", ExampleModel::doubleProperty, 5.1);
+	}
+	
+	
+	@Test
+	public void longProperty() {
+		final LongProperty beanField = wrapper.field(ExampleModel::getLong, ExampleModel::setLong);
+		final LongProperty fxField = wrapper.field(ExampleModel::longProperty);
+		final LongProperty beanFieldDefault = wrapper.field(ExampleModel::getLong, ExampleModel::setLong, 5l);
+		final LongProperty fxFieldDefault = wrapper.field(ExampleModel::longProperty, 5l);
+		
+		final LongProperty idBeanField = wrapper.field("long1", ExampleModel::getLong, ExampleModel::setLong);
+		final LongProperty idFxField = wrapper.field("long2", ExampleModel::longProperty);
+		final LongProperty idBeanFieldDefault = wrapper
+				.field("long3", ExampleModel::getLong, ExampleModel::setLong, 5l);
+		final LongProperty idFxFieldDefault = wrapper.field("long4", ExampleModel::longProperty, 5l);
+	}
+	
+	
+	@Test
+	public void floatProperty() {
+		final FloatProperty beanField = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat);
+		final FloatProperty fxField = wrapper.field(ExampleModel::floatProperty);
+		final FloatProperty beanFieldDefault = wrapper.field(ExampleModel::getFloat, ExampleModel::setFloat, 5.1f);
+		final FloatProperty fxFieldDefault = wrapper.field(ExampleModel::floatProperty, 5.1f);
+		
+		final FloatProperty idBeanField = wrapper.field("float1", ExampleModel::getFloat, ExampleModel::setFloat);
+		final FloatProperty idFxField = wrapper.field("float2", ExampleModel::floatProperty);
+		final FloatProperty idBeanFieldDefault = wrapper.field("float3", ExampleModel::getFloat,
+				ExampleModel::setFloat, 5.1f);
+		final FloatProperty idFxFieldDefault = wrapper.field("float4", ExampleModel::floatProperty, 5.1f);
+	}
+	
+	
+	@Test
+	public void booleanProperty() {
+		final BooleanProperty beanField = wrapper.field(ExampleModel::getBoolean, ExampleModel::setBoolean);
+		final BooleanProperty fxField = wrapper.field(ExampleModel::booleanProperty);
+		final BooleanProperty beanFieldDefault = wrapper
+				.field(ExampleModel::getBoolean, ExampleModel::setBoolean, true);
+		final BooleanProperty fxFieldDefault = wrapper.field(ExampleModel::booleanProperty, true);
+		
+		final BooleanProperty idBeanField = wrapper.field("bool1", ExampleModel::getBoolean, ExampleModel::setBoolean);
+		final BooleanProperty idFxField = wrapper.field("bool2", ExampleModel::booleanProperty);
+		final BooleanProperty idBeanFieldDefault = wrapper.field("bool3", ExampleModel::getBoolean,
+				ExampleModel::setBoolean, true);
+		final BooleanProperty idFxFieldDefault = wrapper.field("bool4", ExampleModel::booleanProperty, true);
+	}
+	
+	
+	@Test
+	public void stringProperty() {
+		final StringProperty beanField = wrapper.field(ExampleModel::getString, ExampleModel::setString);
+		final StringProperty fxField = wrapper.field(ExampleModel::stringProperty);
+		final StringProperty beanFieldDefault = wrapper.field(ExampleModel::getString, ExampleModel::setString, "test");
+		final StringProperty fxFieldDefault = wrapper.field(ExampleModel::stringProperty, "test");
+		
+		final StringProperty idBeanField = wrapper.field("string1", ExampleModel::getString, ExampleModel::setString);
+		final StringProperty idFxField = wrapper.field("string2", ExampleModel::stringProperty);
+		final StringProperty idBeanFieldDefault = wrapper.field("string3", ExampleModel::getString,
+				ExampleModel::setString, "test");
+		final StringProperty idFxFieldDefault = wrapper.field("string4", ExampleModel::stringProperty, "test");
+	}
+	
+	@Test
+	public void objectProperty() {
+		final ObjectProperty beanField = wrapper.field(ExampleModel::getObject, ExampleModel::setObject);
+		final ObjectProperty fxField = wrapper.field(ExampleModel::objectProperty);
+		final ObjectProperty beanFieldDefault = wrapper.field(ExampleModel::getObject, ExampleModel::setObject,
+				new Person());
+		final ObjectProperty fxFieldDefault = wrapper.field(ExampleModel::objectProperty, new Person());
+		
+		final ObjectProperty idBeanField = wrapper.field("obj1", ExampleModel::getObject,
+				ExampleModel::setObject);
+		final ObjectProperty idFxField = wrapper.field("obj2", ExampleModel::objectProperty);
+		final ObjectProperty idBeanFieldDefault = wrapper.field("obj3", ExampleModel::getObject,
+				ExampleModel::setObject, new Person());
+		final ObjectProperty idFxFieldDefault = wrapper.field("obj4", ExampleModel::objectProperty,
+				new Person());
+	}
+	
 }

From 996022f88f5c4bb2854870107658efd20b6a8538 Mon Sep 17 00:00:00 2001
From: Alexander Casall 
Date: Tue, 28 Apr 2015 23:05:24 +0200
Subject: [PATCH 22/28] changed implementation slightly to make the
 updateProgress of task accessible

---
 .../saxsys/mvvmfx/utils/commands/Action.java  | 15 ++++++++++
 .../utils/commands/DelegateCommand.java       | 28 ++++++++-----------
 .../utils/commands/CompositeCommandTest.java  | 21 +++++++-------
 .../utils/commands/DelegateCommandTest.java   | 28 ++++++++-----------
 4 files changed, 50 insertions(+), 42 deletions(-)
 create mode 100644 mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Action.java

diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Action.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Action.java
new file mode 100644
index 000000000..797a5c43b
--- /dev/null
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/Action.java
@@ -0,0 +1,15 @@
+package de.saxsys.mvvmfx.utils.commands;
+
+import javafx.concurrent.Task;
+
+public abstract class Action extends Task {
+	
+	@Override
+	protected Void call() throws Exception {
+		action();
+		return null;
+	}
+	
+	protected abstract void action() throws Exception;
+	
+}
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java
index 824729645..b2c0fb179 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java
@@ -30,8 +30,9 @@
  * @author alexander.casall
  */
 @Beta
-public abstract class DelegateCommand extends Service implements Command {
+public class DelegateCommand extends Service implements Command {
 	
+	private final Action action;
 	private boolean inBackground = false;
 	protected final ReadOnlyBooleanWrapper executable = new ReadOnlyBooleanWrapper(true);
 	protected ReadOnlyBooleanWrapper notExecutable;
@@ -39,6 +40,7 @@ public abstract class DelegateCommand extends Service implements Command {
 	
 	
 	
+	
 	/**
 	 * Creates a command without a condition about the executability. The command will perform in the thread which
 	 * executes the {@link Command}.
@@ -46,7 +48,7 @@ public abstract class DelegateCommand extends Service implements Command {
 	 * @param action
 	 *            which should execute
 	 */
-	public DelegateCommand() {
+	public DelegateCommand(Action action) {
 		this(null, false);
 	}
 	
@@ -63,8 +65,8 @@ public DelegateCommand() {
 	 * @param inBackground
 	 *            defines whether the execution {@link #execute()} is performed in a background thread or not
 	 */
-	public DelegateCommand(boolean inBackground) {
-		this(null, inBackground);
+	public DelegateCommand(Action action, boolean inBackground) {
+		this(action, null, inBackground);
 	}
 	
 	/**
@@ -76,8 +78,8 @@ public DelegateCommand(boolean inBackground) {
 	 * @param executableBinding
 	 *            which defines whether the {@link Command} can execute
 	 */
-	public DelegateCommand(ObservableBooleanValue executableBinding) {
-		this(executableBinding, false);
+	public DelegateCommand(Action action, ObservableBooleanValue executableBinding) {
+		this(action, executableBinding, false);
 	}
 	
 	/**
@@ -94,7 +96,8 @@ public DelegateCommand(ObservableBooleanValue executableBinding) {
 	 * @param inBackground
 	 *            defines whether the execution {@link #execute()} is performed in a background thread or not
 	 */
-	public DelegateCommand(ObservableBooleanValue executableBinding, boolean inBackground) {
+	public DelegateCommand(Action action, ObservableBooleanValue executableBinding, boolean inBackground) {
+		this.action = action;
 		this.inBackground = inBackground;
 		if (executableBinding != null) {
 			executable.bind(runningProperty().not().and(executableBinding));
@@ -102,13 +105,6 @@ public DelegateCommand(ObservableBooleanValue executableBinding, boolean inBackg
 		
 	}
 	
-	/**
-	 * The action which will called if the {@link #execute()} method is called.
-	 * 
-	 * @throws Exception
-	 */
-	protected abstract void action() throws Exception;
-	
 	/**
 	 * @see de.saxsys.mvvmfx.utils.commands.Command#execute
 	 */
@@ -124,7 +120,7 @@ public void execute() {
 				}
 			} else {
 				try {
-					this.action();
+					action.action();
 				} catch (Exception e) {
 					e.printStackTrace();
 				}
@@ -137,7 +133,7 @@ protected Task createTask() {
 		return new Task() {
 			@Override
 			protected Void call() throws Exception {
-				action();
+				action.action();
 				return null;
 			}
 		};
diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java
index f07e4f353..31b06c9ac 100644
--- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java
+++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java
@@ -35,22 +35,22 @@ public class CompositeCommandTest {
 	public void init() {
 		condition1 = new SimpleBooleanProperty(true);
 		called1 = new SimpleBooleanProperty();
-		delegateCommand1 = new DelegateCommand(condition1) {
+		delegateCommand1 = new DelegateCommand(new Action() {
 			
 			@Override
 			protected void action() throws Exception {
 				called1.set(true);
 			}
-		};
+		}, condition1);
 		
 		condition2 = new SimpleBooleanProperty(true);
 		called2 = new SimpleBooleanProperty();
-		delegateCommand2 = new DelegateCommand(condition2) {
+		delegateCommand2 = new DelegateCommand(new Action() {
 			@Override
 			protected void action() throws Exception {
 				called2.set(true);
 			}
-		};
+		}, condition2);
 	}
 	
 	@Test
@@ -161,28 +161,29 @@ public void longRunningAsyncComposite() throws Exception {
 		CompletableFuture commandCompleted = new CompletableFuture<>();
 		CompletableFuture future = new CompletableFuture<>();
 		
-		DelegateCommand delegateCommand1 = new DelegateCommand(condition, true) {
+		DelegateCommand delegateCommand1 = new DelegateCommand(new Action() {
 			
 			@Override
 			protected void action() throws Exception {
 				sleep(500);
 			}
-		};
+		}, condition, true);
 		
-		DelegateCommand delegateCommand2 = new DelegateCommand(condition, true) {
+		DelegateCommand delegateCommand2 = new DelegateCommand(new Action() {
+			
 			@Override
 			protected void action() throws Exception {
 				sleep(1000);
 				future.complete(null);
 			}
-		};
+		}, condition, true);
 		
-		DelegateCommand delegateCommand3 = new DelegateCommand(condition, true) {
+		DelegateCommand delegateCommand3 = new DelegateCommand(new Action() {
 			
 			@Override
 			protected void action() throws Exception {
 			}
-		};
+		}, condition, true);
 		
 		CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1, delegateCommand2, delegateCommand3);
 		
diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java
index b080e8268..bfb29df56 100644
--- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java
+++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java
@@ -24,12 +24,11 @@ public class DelegateCommandTest {
 	public void executable() {
 		BooleanProperty condition = new SimpleBooleanProperty(true);
 		
-		DelegateCommand delegateCommand = new DelegateCommand(condition) {
-			
+		DelegateCommand delegateCommand = new DelegateCommand(new Action() {
 			@Override
-			protected void action() throws Exception {
+			protected void action() {
 			}
-		};
+		}, condition);
 		
 		assertTrue(delegateCommand.isExecutable());
 		assertFalse(delegateCommand.isNotExecutable());
@@ -50,12 +49,12 @@ public void firePositive() {
 		BooleanProperty condition = new SimpleBooleanProperty(true);
 		BooleanProperty called = new SimpleBooleanProperty();
 		
-		DelegateCommand delegateCommand = new DelegateCommand(condition) {
+		DelegateCommand delegateCommand = new DelegateCommand(new Action() {
 			@Override
-			protected void action() throws Exception {
+			protected void action() {
 				called.set(true);
 			}
-		};
+		}, condition);
 		
 		assertFalse(called.get());
 		delegateCommand.execute();
@@ -66,11 +65,11 @@ protected void action() throws Exception {
 	public void fireNegative() {
 		BooleanProperty condition = new SimpleBooleanProperty(false);
 		
-		DelegateCommand delegateCommand = new DelegateCommand(condition) {
+		DelegateCommand delegateCommand = new DelegateCommand(new Action() {
 			@Override
-			protected void action() throws Exception {
+			protected void action() {
 			}
-		};
+		}, condition);
 		
 		delegateCommand.execute();
 	}
@@ -84,15 +83,12 @@ public void longRunningAsync() throws Exception {
 		CompletableFuture commandStarted = new CompletableFuture<>();
 		CompletableFuture commandCompleted = new CompletableFuture<>();
 		
-		DelegateCommand delegateCommand = new DelegateCommand(condition, true) {
+		DelegateCommand delegateCommand = new DelegateCommand(new Action() {
 			@Override
 			protected void action() throws Exception {
-				try {
-					Thread.sleep(1000);
-				} catch (Exception e) {
-				}
+				Thread.sleep(1000);
 			}
-		};
+		}, condition, true);
 		
 		assertFalse(delegateCommand.runningProperty().get());
 		assertTrue(delegateCommand.notRunningProperty().get());

From 65e11acf5dbfcdb470dfc9affa4cb23859fa3e02 Mon Sep 17 00:00:00 2001
From: Manuel Mauky 
Date: Wed, 29 Apr 2015 16:43:50 +0200
Subject: [PATCH 23/28] #225 change signature of delegate command, implemented
 progress property

- the DelegateCommand now takes a Supplier function that creates new Tasks as argument. This way for every execution a new task of the given type is created.
- the progressProperty of the CompositeCommand is now an aggregation of all child commands.
- added a simple JavaFX app that demonstrates the commands with the progress.
---
 .../mvvmfx/examples/books/MainViewModel.java  |  12 +-
 .../personlogin/PersonLoginViewModel.java     |   5 +-
 mvvmfx/pom.xml                                |   7 ++
 .../utils/commands/CompositeCommand.java      | 109 ++++++++++--------
 .../utils/commands/DelegateCommand.java       |  57 +++++----
 .../utils/commands/CompositeCommandTest.java  |  37 +++---
 .../utils/commands/DelegateCommandTest.java   |  87 ++++++++++++--
 .../mvvmfx/utils/commands/testapp/App.java    |  27 +++++
 .../utils/commands/testapp/MainView.java      |  65 +++++++++++
 .../utils/commands/testapp/MainViewModel.java |  38 ++++++
 .../utils/commands/testapp/Service.java       |  24 ++++
 .../utils/commands/testapp/SubView.java       |  60 ++++++++++
 .../utils/commands/testapp/SubViewModel.java  |  60 ++++++++++
 13 files changed, 482 insertions(+), 106 deletions(-)
 create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/App.java
 create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/MainView.java
 create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/MainViewModel.java
 create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/Service.java
 create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/SubView.java
 create mode 100644 mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/SubViewModel.java

diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java
index 41cda68b4..bab3f2d42 100644
--- a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java
@@ -4,6 +4,7 @@
 import de.saxsys.mvvmfx.examples.books.backend.Book;
 import de.saxsys.mvvmfx.examples.books.backend.Error;
 import de.saxsys.mvvmfx.examples.books.backend.LibraryService;
+import de.saxsys.mvvmfx.utils.commands.Action;
 import de.saxsys.mvvmfx.utils.commands.Command;
 import de.saxsys.mvvmfx.utils.commands.DelegateCommand;
 import eu.lestard.advanced_bindings.api.ObjectBindings;
@@ -32,12 +33,17 @@ public class MainViewModel implements ViewModel {
 	
 	private StringProperty error = new SimpleStringProperty();
 
-	private Command seachCommand;
+	private Command searchCommand;
 	
 	public MainViewModel(LibraryService libraryService) {
 		this.libraryService = libraryService;
 
-		seachCommand = new DelegateCommand(this::search);
+		searchCommand = new DelegateCommand(() -> new Action() {
+			@Override
+			protected void action() throws Exception {
+				search();
+			}
+		});
 		
 		bookTitle.bind(ObjectBindings.map(selectedBook, bookItem -> bookItem.getBook().getTitle()));
 		bookAuthor.bind(ObjectBindings.map(selectedBook, bookItem -> bookItem.getBook().getAuthor()));
@@ -45,7 +51,7 @@ public MainViewModel(LibraryService libraryService) {
 	}
 	
 	public Command getSearchCommand() {
-		return seachCommand;
+		return searchCommand;
 	}
 
 	void search() {
diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java
index 52bdc469d..cf08bbcee 100644
--- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java
+++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personlogin/PersonLoginViewModel.java
@@ -1,5 +1,6 @@
 package de.saxsys.jfx.exampleapplication.viewmodel.personlogin;
 
+import de.saxsys.mvvmfx.utils.commands.Action;
 import javafx.application.Platform;
 import javafx.beans.binding.BooleanBinding;
 import javafx.beans.property.ReadOnlyIntegerProperty;
@@ -73,12 +74,12 @@ public ReadOnlyIntegerProperty loggedInPersonIdProperty() {
 	
 	public Command getLoginCommand() {
 		if (loginCommand == null) {
-			loginCommand = new DelegateCommand(createLoginPossibleBinding(), true) {
+			loginCommand = new DelegateCommand(()-> new Action() {
 				@Override
 				protected void action() throws Exception {
 					performLogin();
 				}
-			};
+			}, createLoginPossibleBinding(), true);
 		}
 		return loginCommand;
 	}
diff --git a/mvvmfx/pom.xml b/mvvmfx/pom.xml
index f01e3b514..25833f7bf 100644
--- a/mvvmfx/pom.xml
+++ b/mvvmfx/pom.xml
@@ -83,6 +83,13 @@
 			test
 		
 
+		
+			com.cedarsoft.commons
+			test-utils
+			6.1.1
+			test
+		
+
 	
 
 
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CompositeCommand.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CompositeCommand.java
index 3ee99bbf8..18ad8622a 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CompositeCommand.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/CompositeCommand.java
@@ -15,15 +15,22 @@
  ******************************************************************************/
 package de.saxsys.mvvmfx.utils.commands;
 
+import javafx.beans.binding.Bindings;
 import javafx.beans.binding.BooleanBinding;
+import javafx.beans.binding.DoubleBinding;
+import javafx.beans.binding.DoubleExpression;
 import javafx.beans.property.ReadOnlyBooleanProperty;
 import javafx.beans.property.ReadOnlyDoubleProperty;
 import javafx.beans.property.ReadOnlyDoubleWrapper;
+import javafx.beans.value.ObservableDoubleValue;
 import javafx.collections.FXCollections;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
 import eu.lestard.doc.Beta;
 
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+
 /**
  * CompositeCommand is an aggregation of other commands - a list of {@link Command} references internally.
  * 

@@ -92,68 +99,58 @@ private void initRegisteredCommandsListener() { running.unbind(); progress.unbind(); } else { - BooleanBinding executableBinding = null; - BooleanBinding runningBinding = null; - - ReadOnlyBooleanProperty[] allRunnings = new ReadOnlyBooleanProperty[registeredCommands.size()]; - - - for (int i = 0; i < registeredCommands.size(); i++) { - ReadOnlyBooleanProperty currentExecutable = registeredCommands.get(i).executableProperty(); - ReadOnlyBooleanProperty currentRunning = registeredCommands.get(i).runningProperty(); - allRunnings[i] = registeredCommands.get(i).runningProperty(); - if (i == 0) { - executableBinding = currentExecutable.and(currentExecutable); - runningBinding = currentRunning.or(currentRunning); - } else { - executableBinding = executableBinding.and(currentExecutable); - runningBinding = runningBinding.or(currentRunning); - } + BooleanBinding executableBinding = constantOf(true); + BooleanBinding runningBinding = constantOf(false); + + for (Command registeredCommand : registeredCommands) { + ReadOnlyBooleanProperty currentExecutable = registeredCommand.executableProperty(); + ReadOnlyBooleanProperty currentRunning = registeredCommand.runningProperty(); + executableBinding = executableBinding.and(currentExecutable); + runningBinding = runningBinding.or(currentRunning); } executable.bind(executableBinding); running.bind(runningBinding); - - // TODO Improve Implementation - // progress.unbind(); - // progress.bind(Bindings.createDoubleBinding(new Callable() { - // @Override - // public Double call() throws Exception { - // Stream filter = FXCollections.observableArrayList(allRunnings) - // .stream().filter( - // new Predicate() { - // @Override - // public boolean test(ReadOnlyBooleanProperty t) { - // return t.get(); - // } - // }); - // - // long count = filter.count(); - // double result = count / (double) allRunnings.length; - // double oldValue = progress.get(); - // - // if (result > oldValue) { - // return result; - // } - // - // return oldValue; - // } - // }, allRunnings)); + + initProgressBinding(); + } } + }); + } + + private void initProgressBinding() { + DoubleExpression tmp = constantOf(0); + + for (Command command : registeredCommands) { + final ReadOnlyDoubleProperty progressProperty = command.progressProperty(); + + /** + * When the progress of a command is "undefined", the progress property has a value of -1. + * But in our use case we like to have a value of 0 in this case. + * Therefore we create a custom binding here. + */ + final DoubleBinding normalizedProgress = Bindings + .createDoubleBinding(() -> (progressProperty.get() == -1) ? 0.0 : progressProperty.get(), + progressProperty); + + tmp = tmp.add(normalizedProgress); } - }) ; + + int divisor = registeredCommands.isEmpty() ? 1 : registeredCommands.size(); + progress.bind(Bindings.divide(tmp, divisor)); } @Override public void execute() { - progress.set(0.0); if (!isExecutable()) { throw new RuntimeException("Not executable"); } else { - registeredCommands.forEach(t -> t.execute()); - progress.set(1.0); + if (!registeredCommands.isEmpty()) { + registeredCommands.forEach(t -> t.execute()); + } } } + @Override public double getProgress() { return progressProperty().get(); @@ -164,4 +161,22 @@ public ReadOnlyDoubleProperty progressProperty() { return progress; } + private BooleanBinding constantOf(boolean defaultValue) { + return new BooleanBinding() { + @Override + protected boolean computeValue() { + return defaultValue; + } + }; + } + + private DoubleBinding constantOf(double defaultValue) { + return new DoubleBinding() { + @Override + protected double computeValue() { + return defaultValue; + } + }; + } + } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java index b2c0fb179..943ccaea9 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java @@ -15,6 +15,7 @@ ******************************************************************************/ package de.saxsys.mvvmfx.utils.commands; +import javafx.application.Platform; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.beans.value.ObservableBooleanValue; @@ -22,6 +23,8 @@ import javafx.concurrent.Task; import eu.lestard.doc.Beta; +import java.util.function.Supplier; + /** * A {@link Command} implementation that encapsulates an action ({@link Task}). It is possible to define that the * action should be executed in the background (not on the JavaFX thread) so that long running actions can be @@ -32,7 +35,7 @@ @Beta public class DelegateCommand extends Service implements Command { - private final Action action; + private final Supplier actionSupplier; private boolean inBackground = false; protected final ReadOnlyBooleanWrapper executable = new ReadOnlyBooleanWrapper(true); protected ReadOnlyBooleanWrapper notExecutable; @@ -45,11 +48,11 @@ public class DelegateCommand extends Service implements Command { * Creates a command without a condition about the executability. The command will perform in the thread which * executes the {@link Command}. * - * @param action - * which should execute + * @param actionSupplier + * a function that returns a new Action which should be executed */ - public DelegateCommand(Action action) { - this(null, false); + public DelegateCommand(final Supplier actionSupplier) { + this(actionSupplier, false); } /** @@ -57,29 +60,29 @@ public DelegateCommand(Action action) { * inBackground parameter to run the {@link Command} in a background thread. * * IF YOU USE THE BACKGROUND THREAD: Your provided action will perform in a background thread. If you - * manipulate data in your action, which will be propagated to the UI, use {@link Platform#runLater(Task)} for + * manipulate data in your action, which will be propagated to the UI, use {@link Platform#runLater(Runnable)} for * this manipulation, otherwise you get an Exception. - * - * @param action - * which should execute + * + * @param actionSupplier + * a function that returns a new Action which should be executed * @param inBackground * defines whether the execution {@link #execute()} is performed in a background thread or not */ - public DelegateCommand(Action action, boolean inBackground) { - this(action, null, inBackground); + public DelegateCommand(final Supplier actionSupplier, boolean inBackground) { + this(actionSupplier, null, inBackground); } /** * Creates a command with a condition about the executability by using the #executableBinding parameter. The command * will perform in the thread which executes the {@link Command}. - * - * @param action - * which should execute + * + * @param actionSupplier + * a function that returns a new Action which should be executed * @param executableBinding * which defines whether the {@link Command} can execute */ - public DelegateCommand(Action action, ObservableBooleanValue executableBinding) { - this(action, executableBinding, false); + public DelegateCommand(final Supplier actionSupplier, ObservableBooleanValue executableBinding) { + this(actionSupplier, executableBinding, false); } /** @@ -87,17 +90,17 @@ public DelegateCommand(Action action, ObservableBooleanValue executableBinding) * true to the #inBackground parameter to run the {@link Command} in a background thread. * * IF YOU USE THE BACKGROUND THREAD: don't forget to return to the UI-thread by using {@link - * Platform#runLater(Task)}, otherwise you get an Exception. - * - * @param action - * which should execute + * Platform#runLater(Runnable)}, otherwise you get an Exception. + * + * @param actionSupplier + * a function that returns a new Action which should be executed * @param executableBinding * which defines whether the {@link Command} can execute * @param inBackground * defines whether the execution {@link #execute()} is performed in a background thread or not */ - public DelegateCommand(Action action, ObservableBooleanValue executableBinding, boolean inBackground) { - this.action = action; + public DelegateCommand(final Supplier actionSupplier, ObservableBooleanValue executableBinding, boolean inBackground) { + this.actionSupplier = actionSupplier; this.inBackground = inBackground; if (executableBinding != null) { executable.bind(runningProperty().not().and(executableBinding)); @@ -120,7 +123,7 @@ public void execute() { } } else { try { - action.action(); + actionSupplier.get().action(); } catch (Exception e) { e.printStackTrace(); } @@ -130,13 +133,7 @@ public void execute() { @Override protected Task createTask() { - return new Task() { - @Override - protected Void call() throws Exception { - action.action(); - return null; - } - }; + return actionSupplier.get(); } @Override diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java index 31b06c9ac..56e4ba9a0 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/CompositeCommandTest.java @@ -8,6 +8,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import com.cedarsoft.test.utils.CatchAllExceptionsRule; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -15,6 +16,7 @@ import javafx.beans.value.ObservableValue; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -23,7 +25,12 @@ @RunWith(JfxRunner.class) public class CompositeCommandTest { - + + // Rule to get exceptions from the JavaFX Thread into the JUnit thread + @Rule + public CatchAllExceptionsRule catchAllExceptionsRule = new CatchAllExceptionsRule(); + + private BooleanProperty condition1; private BooleanProperty called1; private DelegateCommand delegateCommand1; @@ -35,7 +42,7 @@ public class CompositeCommandTest { public void init() { condition1 = new SimpleBooleanProperty(true); called1 = new SimpleBooleanProperty(); - delegateCommand1 = new DelegateCommand(new Action() { + delegateCommand1 = new DelegateCommand(() -> new Action() { @Override protected void action() throws Exception { @@ -45,7 +52,7 @@ protected void action() throws Exception { condition2 = new SimpleBooleanProperty(true); called2 = new SimpleBooleanProperty(); - delegateCommand2 = new DelegateCommand(new Action() { + delegateCommand2 = new DelegateCommand(() -> new Action() { @Override protected void action() throws Exception { called2.set(true); @@ -142,11 +149,6 @@ public void register() throws Exception { @Test public void allCommandsAreUnregistered() throws Exception { - - // UncaughtExceptionHandler is defined to be able to detect exception from listeners. - Thread.currentThread().setUncaughtExceptionHandler( - (thread, exception) -> fail("Exception was thrown", exception)); - CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1, delegateCommand2); compositeCommand.unregister(delegateCommand1); @@ -161,7 +163,7 @@ public void longRunningAsyncComposite() throws Exception { CompletableFuture commandCompleted = new CompletableFuture<>(); CompletableFuture future = new CompletableFuture<>(); - DelegateCommand delegateCommand1 = new DelegateCommand(new Action() { + DelegateCommand delegateCommand1 = new DelegateCommand(() -> new Action() { @Override protected void action() throws Exception { @@ -169,7 +171,7 @@ protected void action() throws Exception { } }, condition, true); - DelegateCommand delegateCommand2 = new DelegateCommand(new Action() { + DelegateCommand delegateCommand2 = new DelegateCommand(() -> new Action() { @Override protected void action() throws Exception { @@ -178,7 +180,7 @@ protected void action() throws Exception { } }, condition, true); - DelegateCommand delegateCommand3 = new DelegateCommand(new Action() { + DelegateCommand delegateCommand3 = new DelegateCommand(() -> new Action() { @Override protected void action() throws Exception { @@ -187,12 +189,12 @@ protected void action() throws Exception { CompositeCommand compositeCommand = new CompositeCommand(delegateCommand1, delegateCommand2, delegateCommand3); - // compositeCommand.progressProperty().addListener(new ChangeListener() { - // - // @Override - // public void changed(ObservableValue observable, Number oldValue, Number newValue) { - // } - // }); + compositeCommand.progressProperty().addListener(new ChangeListener() { + + @Override + public void changed(ObservableValue observable, Number oldValue, Number newValue) { + } + }); GCVerifier.forceGC(); @@ -240,6 +242,7 @@ public void run() { commandCompleted.get(4, TimeUnit.SECONDS); } + private void sleep(long millis) { try { Thread.sleep(millis); diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java index bfb29df56..6a6930391 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java @@ -1,30 +1,46 @@ package de.saxsys.mvvmfx.utils.commands; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.offset; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import com.cedarsoft.test.utils.CatchAllExceptionsRule; +import de.saxsys.javafx.test.TestInJfxThread; +import javafx.application.Application; +import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import de.saxsys.javafx.test.JfxRunner; +import org.junit.runners.JUnit4; @RunWith(JfxRunner.class) public class DelegateCommandTest { - + + // Rule to get exceptions from the JavaFX Thread into the JUnit thread + @Rule + public CatchAllExceptionsRule catchAllExceptionsRule = new CatchAllExceptionsRule(); + + + @Test public void executable() { BooleanProperty condition = new SimpleBooleanProperty(true); - DelegateCommand delegateCommand = new DelegateCommand(new Action() { + DelegateCommand delegateCommand = new DelegateCommand(() -> new Action() { @Override protected void action() { } @@ -49,7 +65,7 @@ public void firePositive() { BooleanProperty condition = new SimpleBooleanProperty(true); BooleanProperty called = new SimpleBooleanProperty(); - DelegateCommand delegateCommand = new DelegateCommand(new Action() { + DelegateCommand delegateCommand = new DelegateCommand(() -> new Action() { @Override protected void action() { called.set(true); @@ -65,7 +81,7 @@ protected void action() { public void fireNegative() { BooleanProperty condition = new SimpleBooleanProperty(false); - DelegateCommand delegateCommand = new DelegateCommand(new Action() { + DelegateCommand delegateCommand = new DelegateCommand(() -> new Action() { @Override protected void action() { } @@ -83,7 +99,7 @@ public void longRunningAsync() throws Exception { CompletableFuture commandStarted = new CompletableFuture<>(); CompletableFuture commandCompleted = new CompletableFuture<>(); - DelegateCommand delegateCommand = new DelegateCommand(new Action() { + DelegateCommand delegateCommand = new DelegateCommand(() -> new Action() { @Override protected void action() throws Exception { Thread.sleep(1000); @@ -94,7 +110,7 @@ protected void action() throws Exception { assertTrue(delegateCommand.notRunningProperty().get()); delegateCommand.runningProperty().addListener(new ChangeListener() { - + @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { if (newValue) { @@ -111,7 +127,7 @@ public void changed(ObservableValue observable, Boolean oldVa assertFalse(delegateCommand.notExecutableProperty().get()); commandCompleted.complete(null); } - + } }); @@ -120,4 +136,61 @@ public void changed(ObservableValue observable, Boolean oldVa commandCompleted.get(4, TimeUnit.SECONDS); } + + @Test + public void progressProperty() throws Exception { + + CompletableFuture stepOne = new CompletableFuture<>(); + CompletableFuture stepTwo = new CompletableFuture<>(); + CompletableFuture stepThree = new CompletableFuture<>(); + CompletableFuture stepFour = new CompletableFuture<>(); + + DelegateCommand command = new DelegateCommand(()-> new Action() { + @Override + protected void action() throws Exception { + updateProgress(0, 3); + stepOne.complete(null); + sleep(500); + updateProgress(1, 3); + stepTwo.complete(null); + sleep(500); + updateProgress(2, 3); + stepThree.complete(null); + sleep(500); + updateProgress(3, 3); + stepFour.complete(null); + } + }, true); + + command.execute(); + + stepOne.get(1, TimeUnit.SECONDS); + Platform.runLater(() -> + assertThat(command.getProgress()).isEqualTo(0.0)); + + stepTwo.get(1, TimeUnit.SECONDS); + Platform.runLater(() -> + assertThat(command.getProgress()).isEqualTo(0.3, offset(0.1))); + + stepThree.get(1, TimeUnit.SECONDS); + Platform.runLater(() -> + assertThat(command.getProgress()).isEqualTo(0.6, offset(0.1))); + + stepFour.get(1, TimeUnit.SECONDS); + Platform.runLater(() -> + assertThat(command.getProgress()).isEqualTo(10, offset(0.1))); + + // sleep to prevent the Junit thread from exiting + // before eventual assertion errors from the JavaFX Thread are detected + sleep(500); + } + + + private void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/App.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/App.java new file mode 100644 index 000000000..347eec114 --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/App.java @@ -0,0 +1,27 @@ +package de.saxsys.mvvmfx.utils.commands.testapp; + +/** + * @author manuel.mauky + */ + +import de.saxsys.mvvmfx.FluentViewLoader; +import javafx.application.Application; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; + +public class App extends Application { + + public static void main(String[] args) { + launch(args); + } + + @Override + public void start(Stage primaryStage) { + + final Parent view = FluentViewLoader.javaView(MainView.class).load().getView(); + + primaryStage.setScene(new Scene(view)); + primaryStage.show(); + } +} diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/MainView.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/MainView.java new file mode 100644 index 000000000..9b062e2ea --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/MainView.java @@ -0,0 +1,65 @@ +package de.saxsys.mvvmfx.utils.commands.testapp; + +import de.saxsys.mvvmfx.FluentViewLoader; +import de.saxsys.mvvmfx.InjectViewModel; +import de.saxsys.mvvmfx.JavaView; +import de.saxsys.mvvmfx.ViewTuple; +import de.saxsys.mvvmfx.utils.commands.Command; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.ProgressBar; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + +/** + * @author manuel.mauky + */ +public class MainView extends VBox implements JavaView { + + private HBox container = new HBox(); + private Button rollAllDicesButton = new Button("Roll all Dices"); + private ProgressBar progressBar = new ProgressBar(); + + @InjectViewModel + private MainViewModel viewModel; + + public MainView(){ + this.getChildren().add(container); + + HBox footer = new HBox(); + footer.setSpacing(5); + footer.getChildren().addAll(rollAllDicesButton, progressBar); + progressBar.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(progressBar, Priority.ALWAYS); + + this.getChildren().add(footer); + this.setPadding(new Insets(5)); + this.setSpacing(5); + } + + public void initialize() { + final ViewTuple subViewTupleOne = FluentViewLoader.javaView(SubView.class).load(); + viewModel.setChildOne(subViewTupleOne.getViewModel()); + container.getChildren().add(subViewTupleOne.getView()); + + final ViewTuple subViewTupleTwo = FluentViewLoader.javaView(SubView.class).load(); + viewModel.setChildTwo(subViewTupleTwo.getViewModel()); + container.getChildren().add(subViewTupleTwo.getView()); + + final ViewTuple subViewTupleThree = FluentViewLoader.javaView(SubView.class).load(); + viewModel.setChildThree(subViewTupleThree.getViewModel()); + container.getChildren().add(subViewTupleThree.getView()); + + viewModel.init(); + + + final Command command = viewModel.getRollAllDicesCommand(); + + rollAllDicesButton.setOnAction(event -> command.execute()); + rollAllDicesButton.disableProperty().bind(command.notExecutableProperty()); + progressBar.progressProperty().bind(command.progressProperty()); + + } + +} diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/MainViewModel.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/MainViewModel.java new file mode 100644 index 000000000..ee37c39ec --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/MainViewModel.java @@ -0,0 +1,38 @@ +package de.saxsys.mvvmfx.utils.commands.testapp; + +import de.saxsys.mvvmfx.ViewModel; +import de.saxsys.mvvmfx.utils.commands.Command; +import de.saxsys.mvvmfx.utils.commands.CompositeCommand; + +/** + * @author manuel.mauky + */ +public class MainViewModel implements ViewModel { + + private SubViewModel childOne; + private SubViewModel childTwo; + private SubViewModel childThree; + + + private Command rollAllDicesCommand; + + public void init(){ + rollAllDicesCommand = new CompositeCommand(childOne.getRollDiceCommand(), childTwo.getRollDiceCommand(), childThree.getRollDiceCommand()); + } + + public Command getRollAllDicesCommand() { + return rollAllDicesCommand; + } + + public void setChildOne(SubViewModel childOne) { + this.childOne = childOne; + } + + public void setChildTwo(SubViewModel childTwo) { + this.childTwo = childTwo; + } + + public void setChildThree(SubViewModel childThree) { + this.childThree = childThree; + } +} diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/Service.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/Service.java new file mode 100644 index 000000000..c43959097 --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/Service.java @@ -0,0 +1,24 @@ +package de.saxsys.mvvmfx.utils.commands.testapp; + +import java.util.Random; + +/** + * @author manuel.mauky + */ +public class Service { + + + + public int longRunningService() { + try { + int waitTime = (new Random().nextInt(3) + 1) * 1000; // between 1 and 3 seconds + + Thread.sleep(waitTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + return new Random().nextInt(6)+1; + } + +} diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/SubView.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/SubView.java new file mode 100644 index 000000000..f46c84e6f --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/SubView.java @@ -0,0 +1,60 @@ +package de.saxsys.mvvmfx.utils.commands.testapp; + +import de.saxsys.mvvmfx.InjectViewModel; +import de.saxsys.mvvmfx.JavaView; +import de.saxsys.mvvmfx.utils.commands.Command; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ListView; +import javafx.scene.control.ProgressBar; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + + +/** + * @author manuel.mauky + */ +public class SubView extends VBox implements JavaView { + + private ListView numbers = new ListView<>(); + private Button rollDiceButton = new Button("Roll the Dice"); + private CheckBox activeCheckBox = new CheckBox(); + + private ProgressBar progressBar = new ProgressBar(); + + @InjectViewModel + private SubViewModel viewModel; + + public SubView(){ + this.getChildren().add(numbers); + HBox footer = new HBox(); + footer.getChildren().add(activeCheckBox); + footer.getChildren().add(rollDiceButton); + footer.getChildren().add(progressBar); + footer.setSpacing(5); + progressBar.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(progressBar, Priority.ALWAYS); + + this.getChildren().add(footer); + + this.setPadding(new Insets(5)); + this.setSpacing(5); + } + + public void initialize(){ + activeCheckBox.selectedProperty().bindBidirectional(viewModel.activeProperty()); + + numbers.setItems(viewModel.numbersProperty()); + + final Command rollDiceCommand = viewModel.getRollDiceCommand(); + rollDiceButton.setOnAction(event -> { + rollDiceCommand.execute(); + }); + rollDiceButton.disableProperty().bind(rollDiceCommand.notExecutableProperty()); + progressBar.progressProperty().bind(rollDiceCommand.progressProperty()); + } + + +} diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/SubViewModel.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/SubViewModel.java new file mode 100644 index 000000000..80e15b1a2 --- /dev/null +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/testapp/SubViewModel.java @@ -0,0 +1,60 @@ +package de.saxsys.mvvmfx.utils.commands.testapp; + +import de.saxsys.mvvmfx.ViewModel; +import de.saxsys.mvvmfx.utils.commands.Action; +import de.saxsys.mvvmfx.utils.commands.Command; +import de.saxsys.mvvmfx.utils.commands.DelegateCommand; +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import java.util.stream.IntStream; + +/** + * @author manuel.mauky + */ +public class SubViewModel implements ViewModel { + + private static final int NUMBERS = 10; + + private ObservableList numbers = FXCollections.observableArrayList(); + + private Command rollDiceCommand; + + private BooleanProperty active = new SimpleBooleanProperty(true); + + public SubViewModel(){ + + Service service = new Service(); + + rollDiceCommand = new DelegateCommand(() -> new Action() { + @Override + protected void action() throws Exception { + updateProgress(0, NUMBERS); + Platform.runLater(numbers::clear); + for (int i = 0; i < NUMBERS; i++) { + final int newNumber = service.longRunningService(); + + updateProgress(i + 1, NUMBERS); + Platform.runLater(() -> numbers.add(newNumber)); + } + } + }, active, true); + + + } + + public Command getRollDiceCommand(){ + return rollDiceCommand; + } + + public ObservableList numbersProperty(){ + return numbers; + } + + public BooleanProperty activeProperty(){ + return active; + } +} From bfade6a0a96a82df59061bd372936effc1a4ed81 Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Wed, 29 Apr 2015 16:50:13 +0200 Subject: [PATCH 24/28] fix builder breaker due to wrong assertion value --- .../de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java index 6a6930391..2e4d3346d 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/commands/DelegateCommandTest.java @@ -178,7 +178,7 @@ protected void action() throws Exception { stepFour.get(1, TimeUnit.SECONDS); Platform.runLater(() -> - assertThat(command.getProgress()).isEqualTo(10, offset(0.1))); + assertThat(command.getProgress()).isEqualTo(1, offset(0.1))); // sleep to prevent the Junit thread from exiting // before eventual assertion errors from the JavaFX Thread are detected From d11f410dc1026ffa234e9652555fb0475547867b Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Thu, 30 Apr 2015 13:35:17 +0200 Subject: [PATCH 25/28] #222 contacts example now shows usage of ModelWrapper for table items. --- .../ui/master/MasterTableViewModel.java | 115 ++++-------------- .../ui/master/MasterTableViewModelTest.java | 2 +- 2 files changed, 24 insertions(+), 93 deletions(-) diff --git a/examples/mvvmfx-contacts/src/main/java/de/saxsys/mvvmfx/contacts/ui/master/MasterTableViewModel.java b/examples/mvvmfx-contacts/src/main/java/de/saxsys/mvvmfx/contacts/ui/master/MasterTableViewModel.java index 7d7822f47..12a18ec8c 100644 --- a/examples/mvvmfx-contacts/src/main/java/de/saxsys/mvvmfx/contacts/ui/master/MasterTableViewModel.java +++ b/examples/mvvmfx-contacts/src/main/java/de/saxsys/mvvmfx/contacts/ui/master/MasterTableViewModel.java @@ -2,6 +2,9 @@ import de.saxsys.mvvmfx.contacts.model.Contact; import de.saxsys.mvvmfx.contacts.util.CentralClock; +import de.saxsys.mvvmfx.utils.mapping.ModelWrapper; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.StringGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.StringSetter; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.ReadOnlyStringWrapper; @@ -13,31 +16,17 @@ import java.time.temporal.ChronoUnit; public class MasterTableViewModel { - - private ReadOnlyStringWrapper id = new ReadOnlyStringWrapper(); - private StringProperty firstname = new SimpleStringProperty(); - private StringProperty lastname = new SimpleStringProperty(); - private StringProperty title = new SimpleStringProperty(); - - private StringProperty emailAddress = new SimpleStringProperty(); + private final String id; private IntegerProperty age = new SimpleIntegerProperty(); - - private StringProperty city = new SimpleStringProperty(); - private StringProperty street = new SimpleStringProperty(); - private StringProperty postalCode = new SimpleStringProperty(); + private ModelWrapper contactWrapper = new ModelWrapper<>(); public MasterTableViewModel(Contact contact) { - id.set(contact.getId()); - setFirstname(contact.getFirstname()); - setLastname(contact.getLastname()); - setTitle(contact.getTitle()); - setEmailAddress(contact.getEmailAddress()); - setCity(contact.getAddress().getCity()); - setStreet(contact.getAddress().getStreet()); - setPostalCode(contact.getAddress().getPostalcode()); + id = contact.getId(); + contactWrapper.set(contact); + contactWrapper.reload(); if (contact.getBirthday() != null) { - setAge((int) ChronoUnit.YEARS.between(contact.getBirthday(), LocalDate.now(CentralClock.getClock()))); + age.set((int) ChronoUnit.YEARS.between(contact.getBirthday(), LocalDate.now(CentralClock.getClock()))); } } @@ -68,106 +57,48 @@ public int hashCode() { } public String getId() { - return id.get(); - } - - public ReadOnlyStringProperty idProperty() { - return id.getReadOnlyProperty(); - } - - public String getFirstname() { - return firstname.get(); + return id; } public StringProperty firstnameProperty() { - return firstname; + return contactWrapper.field("firstname", Contact::getFirstname, Contact::setFirstname); } - public void setFirstname(String firstname) { - this.firstname.set(firstname); - } - - public String getLastname() { - return lastname.get(); - } public StringProperty lastnameProperty() { - return lastname; - } - - public void setLastname(String lastname) { - this.lastname.set(lastname); + return contactWrapper.field("lastname", Contact::getLastname, Contact::setLastname); } - public String getTitle() { - return title.get(); - } public StringProperty titleProperty() { - return title; - } - - public void setTitle(String title) { - this.title.set(title); - } - - public String getEmailAddress() { - return emailAddress.get(); + return contactWrapper.field("title", Contact::getTitle, Contact::setTitle); } public StringProperty emailAddressProperty() { - return emailAddress; - } - - public void setEmailAddress(String emailAddress) { - this.emailAddress.set(emailAddress); - } - - public int getAge() { - return age.get(); + return contactWrapper.field("emailAddress", Contact::getEmailAddress, Contact::setEmailAddress); } public IntegerProperty ageProperty() { return age; } - public void setAge(int age) { - this.age.set(age); - } - - public String getCity() { - return city.get(); - } - public StringProperty cityProperty() { - return city; + return contactWrapper.field("city", + (StringGetter) model -> model.getAddress().getCity(), + (model, value) -> model.getAddress().setCity(value)); } - public void setCity(String city) { - this.city.set(city); - } - - public String getStreet() { - return street.get(); - } public StringProperty streetProperty() { - return street; - } - - public void setStreet(String street) { - this.street.set(street); + return contactWrapper.field("street", + (StringGetter) model -> model.getAddress().getStreet(), + (model, value) -> model.getAddress().setStreet(value)); } - public String getPostalCode() { - return postalCode.get(); - } public StringProperty postalCodeProperty() { - return postalCode; - } - - public void setPostalCode(String postalCode) { - this.postalCode.set(postalCode); + return contactWrapper.field("postalcode", + (StringGetter) model -> model.getAddress().getPostalcode(), + (model, value) -> model.getAddress().setPostalcode(value)); } } diff --git a/examples/mvvmfx-contacts/src/test/java/de/saxsys/mvvmfx/contacts/ui/master/MasterTableViewModelTest.java b/examples/mvvmfx-contacts/src/test/java/de/saxsys/mvvmfx/contacts/ui/master/MasterTableViewModelTest.java index 856292b44..c92d40074 100644 --- a/examples/mvvmfx-contacts/src/test/java/de/saxsys/mvvmfx/contacts/ui/master/MasterTableViewModelTest.java +++ b/examples/mvvmfx-contacts/src/test/java/de/saxsys/mvvmfx/contacts/ui/master/MasterTableViewModelTest.java @@ -30,7 +30,7 @@ public void testCalculationOfAge() { MasterTableViewModel tableViewModel = new MasterTableViewModel(contact); - assertThat(tableViewModel.getAge()).isEqualTo(22); + assertThat(tableViewModel.ageProperty().get()).isEqualTo(22); } } From 3643cd420e423591abacf7cf2df564dc5899c603 Mon Sep 17 00:00:00 2001 From: Alexander Casall Date: Fri, 1 May 2015 16:45:38 +0200 Subject: [PATCH 26/28] javadoc --- .../utils/commands/DelegateCommand.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java index 943ccaea9..ac476b06e 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/commands/DelegateCommand.java @@ -15,6 +15,8 @@ ******************************************************************************/ package de.saxsys.mvvmfx.utils.commands; +import java.util.function.Supplier; + import javafx.application.Platform; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; @@ -23,12 +25,12 @@ import javafx.concurrent.Task; import eu.lestard.doc.Beta; -import java.util.function.Supplier; - /** - * A {@link Command} implementation that encapsulates an action ({@link Task}). It is possible to define that the - * action should be executed in the background (not on the JavaFX thread) so that long running actions can be - * implemented that aren't blocking the UI-Thread. + * A {@link Command} implementation of a {@link Service} that encapsulates an {@link Action} ({@link Task}) + * which can be called from the UI - for example after a button click. If the {@link Action} is a long running + * operation, which would block your UI, you can pass a parameter to perform the {@link Action} in a background thread. + * You can bind to the {@link #isRunning()} property while the action is executing. This can be used for a loading + * indication in the UI. * * @author alexander.casall */ @@ -45,8 +47,7 @@ public class DelegateCommand extends Service implements Command { /** - * Creates a command without a condition about the executability. The command will perform in the thread which - * executes the {@link Command}. + * Creates a command without a condition about the executability. * * @param actionSupplier * a function that returns a new Action which should be executed @@ -61,7 +62,7 @@ public DelegateCommand(final Supplier actionSupplier) { * * IF YOU USE THE BACKGROUND THREAD: Your provided action will perform in a background thread. If you * manipulate data in your action, which will be propagated to the UI, use {@link Platform#runLater(Runnable)} for - * this manipulation, otherwise you get an Exception. + * this manipulation, otherwise you get an Exception by JavaFX. * * @param actionSupplier * a function that returns a new Action which should be executed @@ -73,8 +74,7 @@ public DelegateCommand(final Supplier actionSupplier, boolean inBackgrou } /** - * Creates a command with a condition about the executability by using the #executableBinding parameter. The command - * will perform in the thread which executes the {@link Command}. + * Creates a command with a condition about the executability by using the #executableBinding parameter. * * @param actionSupplier * a function that returns a new Action which should be executed @@ -89,8 +89,8 @@ public DelegateCommand(final Supplier actionSupplier, ObservableBooleanV * Creates a command with a condition about the executability by using the #executableBinding parameter. Pass a * true to the #inBackground parameter to run the {@link Command} in a background thread. * - * IF YOU USE THE BACKGROUND THREAD: don't forget to return to the UI-thread by using {@link - * Platform#runLater(Runnable)}, otherwise you get an Exception. + * IF YOU USE THE BACKGROUND THREAD: don't forget to return to the UI-thread by using + * {@link Platform#runLater(Runnable)}, otherwise you get an Exception. * * @param actionSupplier * a function that returns a new Action which should be executed @@ -99,7 +99,8 @@ public DelegateCommand(final Supplier actionSupplier, ObservableBooleanV * @param inBackground * defines whether the execution {@link #execute()} is performed in a background thread or not */ - public DelegateCommand(final Supplier actionSupplier, ObservableBooleanValue executableBinding, boolean inBackground) { + public DelegateCommand(final Supplier actionSupplier, ObservableBooleanValue executableBinding, + boolean inBackground) { this.actionSupplier = actionSupplier; this.inBackground = inBackground; if (executableBinding != null) { From 74a07de4d7e3ccdd9f134622ed2373daa32e62f2 Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Mon, 4 May 2015 12:47:26 +0200 Subject: [PATCH 27/28] #229 update version to 1.2.0 --- README.md | 14 +++++++------- examples/mvvmfx-books-example/pom.xml | 2 +- examples/mvvmfx-cdi-starter/pom.xml | 2 +- examples/mvvmfx-complex-example/pom.xml | 2 +- examples/mvvmfx-contacts/pom.xml | 2 +- examples/mvvmfx-fx-root-example/pom.xml | 2 +- examples/mvvmfx-guice-starter/pom.xml | 2 +- examples/mvvmfx-helloworld-without-fxml/pom.xml | 2 +- examples/mvvmfx-helloworld/pom.xml | 2 +- examples/mvvmfx-synchronizefx/pom.xml | 2 +- examples/mvvmfx-todomvc/pom.xml | 2 +- examples/pom.xml | 2 +- mvvmfx-archetype/pom.xml | 2 +- mvvmfx-cdi/pom.xml | 2 +- mvvmfx-guice/pom.xml | 2 +- mvvmfx-testing-utils/pom.xml | 2 +- mvvmfx-utils/pom.xml | 2 +- mvvmfx/pom.xml | 2 +- pom.xml | 2 +- 19 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 34771b3ee..d018d895e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ __MVVM__ is the enhanced version of the [Presentation Model](http://martinfowler de.saxsys mvvmfx - 1.1.0 + 1.2.0 ``` @@ -24,7 +24,7 @@ __MVVM__ is the enhanced version of the [Presentation Model](http://martinfowler de.saxsys mvvmfx - 1.2.0-SNAPSHOT + 1.3.0-SNAPSHOT ``` @@ -36,9 +36,9 @@ If you need help you can use the forums on [Google Groups](https://groups.google ### Links - [Project Page](http://sialcasa.github.io/mvvmFX/) -- [javadoc mvvmfx core](http://sialcasa.github.io/mvvmFX/javadoc/1.1.0/mvvmfx/) -- [javadoc mvvmfx-cdi](http://sialcasa.github.io/mvvmFX/javadoc/1.1.0/mvvmfx-cdi/) -- [javadoc mvvmfx-guice](http://sialcasa.github.io/mvvmFX/javadoc/1.1.0/mvvmfx-guice/) -- [javadoc mvvmfx-utils](http://sialcasa.github.io/mvvmFX/javadoc/1.1.0/mvvmfx-utils/) -- [javadoc mvvmfx-testing-utils](http://sialcasa.github.io/mvvmFX/javadoc/1.1.0/mvvmfx-testing-utils/) +- [javadoc mvvmfx core](http://sialcasa.github.io/mvvmFX/javadoc/1.2.0/mvvmfx/) +- [javadoc mvvmfx-cdi](http://sialcasa.github.io/mvvmFX/javadoc/1.2.0/mvvmfx-cdi/) +- [javadoc mvvmfx-guice](http://sialcasa.github.io/mvvmFX/javadoc/1.2.0/mvvmfx-guice/) +- [javadoc mvvmfx-utils](http://sialcasa.github.io/mvvmFX/javadoc/1.2.0/mvvmfx-utils/) +- [javadoc mvvmfx-testing-utils](http://sialcasa.github.io/mvvmFX/javadoc/1.2.0/mvvmfx-testing-utils/) diff --git a/examples/mvvmfx-books-example/pom.xml b/examples/mvvmfx-books-example/pom.xml index 60b157c29..d59e0149f 100644 --- a/examples/mvvmfx-books-example/pom.xml +++ b/examples/mvvmfx-books-example/pom.xml @@ -5,7 +5,7 @@ mvvmfx-examples de.saxsys - 1.2.0-SNAPSHOT + 1.2.0 4.0.0 diff --git a/examples/mvvmfx-cdi-starter/pom.xml b/examples/mvvmfx-cdi-starter/pom.xml index 6b1d727ca..da6dace02 100644 --- a/examples/mvvmfx-cdi-starter/pom.xml +++ b/examples/mvvmfx-cdi-starter/pom.xml @@ -12,7 +12,7 @@ de.saxsys mvvmfx-examples - 1.2.0-SNAPSHOT + 1.2.0 diff --git a/examples/mvvmfx-complex-example/pom.xml b/examples/mvvmfx-complex-example/pom.xml index 10b2f45c5..aff2b8ec5 100644 --- a/examples/mvvmfx-complex-example/pom.xml +++ b/examples/mvvmfx-complex-example/pom.xml @@ -7,7 +7,7 @@ de.saxsys mvvmfx-examples - 1.2.0-SNAPSHOT + 1.2.0 UTF-8 diff --git a/examples/mvvmfx-contacts/pom.xml b/examples/mvvmfx-contacts/pom.xml index 1b7d42376..b776e347b 100644 --- a/examples/mvvmfx-contacts/pom.xml +++ b/examples/mvvmfx-contacts/pom.xml @@ -6,7 +6,7 @@ mvvmfx-examples de.saxsys - 1.2.0-SNAPSHOT + 1.2.0 mvvmfx-contacts diff --git a/examples/mvvmfx-fx-root-example/pom.xml b/examples/mvvmfx-fx-root-example/pom.xml index 648c89adf..ee648822d 100644 --- a/examples/mvvmfx-fx-root-example/pom.xml +++ b/examples/mvvmfx-fx-root-example/pom.xml @@ -7,7 +7,7 @@ de.saxsys mvvmfx-examples - 1.2.0-SNAPSHOT + 1.2.0 diff --git a/examples/mvvmfx-guice-starter/pom.xml b/examples/mvvmfx-guice-starter/pom.xml index 6a4f7b2c4..f5126ec63 100644 --- a/examples/mvvmfx-guice-starter/pom.xml +++ b/examples/mvvmfx-guice-starter/pom.xml @@ -12,7 +12,7 @@ de.saxsys mvvmfx-examples - 1.2.0-SNAPSHOT + 1.2.0 UTF-8 diff --git a/examples/mvvmfx-helloworld-without-fxml/pom.xml b/examples/mvvmfx-helloworld-without-fxml/pom.xml index 17f498898..46e096cd8 100644 --- a/examples/mvvmfx-helloworld-without-fxml/pom.xml +++ b/examples/mvvmfx-helloworld-without-fxml/pom.xml @@ -7,7 +7,7 @@ de.saxsys mvvmfx-examples - 1.2.0-SNAPSHOT + 1.2.0 diff --git a/examples/mvvmfx-helloworld/pom.xml b/examples/mvvmfx-helloworld/pom.xml index 52ac5e6b4..b5b24a092 100644 --- a/examples/mvvmfx-helloworld/pom.xml +++ b/examples/mvvmfx-helloworld/pom.xml @@ -6,7 +6,7 @@ de.saxsys mvvmfx-examples - 1.2.0-SNAPSHOT + 1.2.0 UTF-8 diff --git a/examples/mvvmfx-synchronizefx/pom.xml b/examples/mvvmfx-synchronizefx/pom.xml index f491419f7..0e2412f60 100644 --- a/examples/mvvmfx-synchronizefx/pom.xml +++ b/examples/mvvmfx-synchronizefx/pom.xml @@ -6,7 +6,7 @@ de.saxsys mvvmfx-examples - 1.2.0-SNAPSHOT + 1.2.0 UTF-8 diff --git a/examples/mvvmfx-todomvc/pom.xml b/examples/mvvmfx-todomvc/pom.xml index 54aa9668d..0f28d7b91 100644 --- a/examples/mvvmfx-todomvc/pom.xml +++ b/examples/mvvmfx-todomvc/pom.xml @@ -5,7 +5,7 @@ mvvmfx-examples de.saxsys - 1.2.0-SNAPSHOT + 1.2.0 4.0.0 diff --git a/examples/pom.xml b/examples/pom.xml index 5bf530277..48faffef9 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ de.saxsys mvvmfx-parent - 1.2.0-SNAPSHOT + 1.2.0 mvvmfx-examples diff --git a/mvvmfx-archetype/pom.xml b/mvvmfx-archetype/pom.xml index bd2e00edc..c44914fdd 100644 --- a/mvvmfx-archetype/pom.xml +++ b/mvvmfx-archetype/pom.xml @@ -5,7 +5,7 @@ de.saxsys mvvmfx-parent - 1.2.0-SNAPSHOT + 1.2.0 diff --git a/mvvmfx-cdi/pom.xml b/mvvmfx-cdi/pom.xml index f15a6b65d..235c2d365 100644 --- a/mvvmfx-cdi/pom.xml +++ b/mvvmfx-cdi/pom.xml @@ -20,7 +20,7 @@ de.saxsys mvvmfx-parent - 1.2.0-SNAPSHOT + 1.2.0 mvvmfx-cdi diff --git a/mvvmfx-guice/pom.xml b/mvvmfx-guice/pom.xml index 732637005..2197def1d 100644 --- a/mvvmfx-guice/pom.xml +++ b/mvvmfx-guice/pom.xml @@ -20,7 +20,7 @@ de.saxsys mvvmfx-parent - 1.2.0-SNAPSHOT + 1.2.0 mvvmfx-guice diff --git a/mvvmfx-testing-utils/pom.xml b/mvvmfx-testing-utils/pom.xml index 8312eb0c1..e9ac21324 100644 --- a/mvvmfx-testing-utils/pom.xml +++ b/mvvmfx-testing-utils/pom.xml @@ -5,7 +5,7 @@ mvvmfx-parent de.saxsys - 1.2.0-SNAPSHOT + 1.2.0 4.0.0 diff --git a/mvvmfx-utils/pom.xml b/mvvmfx-utils/pom.xml index 3a0f3385f..2e610e4f7 100644 --- a/mvvmfx-utils/pom.xml +++ b/mvvmfx-utils/pom.xml @@ -5,7 +5,7 @@ mvvmfx-parent de.saxsys - 1.2.0-SNAPSHOT + 1.2.0 4.0.0 diff --git a/mvvmfx/pom.xml b/mvvmfx/pom.xml index 25833f7bf..f67c9800c 100644 --- a/mvvmfx/pom.xml +++ b/mvvmfx/pom.xml @@ -20,7 +20,7 @@ de.saxsys mvvmfx-parent - 1.2.0-SNAPSHOT + 1.2.0 mvvmfx diff --git a/pom.xml b/pom.xml index 1d361d430..3968249e7 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ de.saxsys mvvmfx-parent pom - 1.2.0-SNAPSHOT + 1.2.0 mvvmFX parent Application Framework for MVVM with JavaFX. http://www.saxsys.de From a7eb6228ab47954b39e0716381f0f6a4eb93954f Mon Sep 17 00:00:00 2001 From: Manuel Mauky Date: Mon, 4 May 2015 13:27:09 +0200 Subject: [PATCH 28/28] fix missing maven plugin versions --- mvvmfx-archetype/pom.xml | 3 ++- mvvmfx-cdi/pom.xml | 1 + mvvmfx-guice/pom.xml | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mvvmfx-archetype/pom.xml b/mvvmfx-archetype/pom.xml index c44914fdd..021d9e68c 100644 --- a/mvvmfx-archetype/pom.xml +++ b/mvvmfx-archetype/pom.xml @@ -18,7 +18,7 @@ - ${parent.version} + ${project.parent.version} @@ -43,6 +43,7 @@ maven-resources-plugin + 2.7 \ diff --git a/mvvmfx-cdi/pom.xml b/mvvmfx-cdi/pom.xml index 235c2d365..498d7d798 100644 --- a/mvvmfx-cdi/pom.xml +++ b/mvvmfx-cdi/pom.xml @@ -34,6 +34,7 @@ maven-surefire-plugin + 2.18.1 always diff --git a/mvvmfx-guice/pom.xml b/mvvmfx-guice/pom.xml index 2197def1d..23d621070 100644 --- a/mvvmfx-guice/pom.xml +++ b/mvvmfx-guice/pom.xml @@ -33,6 +33,7 @@ maven-surefire-plugin + 2.18.1 always