diff --git a/.travis.yml b/.travis.yml
index 1103c8581..efa218ffb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,4 +13,4 @@ env:
- secure: Bm0zIwBo4saIBlfr9YDvNqd8UN50FeT2hZyum3RFDmJqaXiUqwxw7sCz/lRjUwTfQrvGJXQ1I8le7zE4OVQdvpn4/LwwTJIjLY2jZNjzs4mZhkHzsM5IcGcL3lukR6soVYrGloQwmw63Okw2kZxces+1fveisPIKDlVaU1RTtMQ=
after_success:
- - "[[ $TRAVIS_BRANCH == \"develop\" ]] && { python addServer.py; mvn clean deploy -DskipTests=true --settings ~/.m2/mySettings.xml; };"
+ - "[[ $TRAVIS_BRANCH == \"develop\" ]] && { python addServer.py; mvn clean deploy -pl 'mvvmfx,mvvmfx-cdi,mvvmfx-guice,mvvmfx-archetype' -am -DskipTests=true --settings ~/.m2/mySettings.xml; };"
diff --git a/README.md b/README.md
index 97711482c..4b2880dcd 100644
--- a/README.md
+++ b/README.md
@@ -4,28 +4,39 @@ __mvvm(fx)__ is an application framework which provides you necessary components
__MVVM__ is the enhanced version of the [Presentation Model](http://martinfowler.com/eaaDev/PresentationModel.html "Presentation Model") pattern and was created by Microsoft engineers for [WPF](http://msdn.microsoft.com/en-us/library/ms754130.aspx "WPF") . JavaFX and WPF does have similarities like Databinding and descriptive UI declaration (FXML/XAML). Because of this fact we aptopt best practices of the development with the Microsoft technology.
+[![Build Status](https://travis-ci.org/sialcasa/mvvmFX.svg?branch=develop)](https://travis-ci.org/sialcasa/mvvmFX)
+
###[Howto](../../wiki "Howto")###
-###Maven dependency###
+### Maven dependency###
+
+#### Stable Release
+```
+
+ de.saxsys
+ mvvmfx
+ 1.0.0
+
+```
+#### Development Snapshot
```
de.saxsys
- mvvmFX
- 0.4.0
+ mvvmfx
+ 1.1.0-SNAPSHOT
```
+
### Get Help
If you need help you can use the forums on [Google Groups](https://groups.google.com/forum/#!forum/mvvmfx-dev) for asking questions and interacting with the mvvmFX developers. Additionally you can create issues, report bugs and add feature requests on the issue tracker at [github](https://github.com/sialcasa/mvvmFX/issues).
### Links
-[javadoc mvvmfx core](http://sialcasa.github.io/mvvmFX/javadoc/0.4.0/mvvmfx/)
+- [Project Page](http://sialcasa.github.io/mvvmFX/)
+- [javadoc mvvmfx core](http://sialcasa.github.io/mvvmFX/javadoc/1.0.0/mvvmfx/)
+- [javadoc mvvmfx-cdi](http://sialcasa.github.io/mvvmFX/javadoc/1.0.0/mvvmfx-cdi/)
+- [javadoc mvvmfx-guice](http://sialcasa.github.io/mvvmFX/javadoc/1.0.0/mvvmfx-guice/)
-[javadoc mvvmfx-cdi](http://sialcasa.github.io/mvvmFX/javadoc/0.4.0/mvvmfx-cdi/)
-
-[javadoc mvvmfx-guice](http://sialcasa.github.io/mvvmFX/javadoc/0.4.0/mvvmfx-guice/)
-
-[![Build Status](https://travis-ci.org/sialcasa/mvvmFX.svg?branch=develop)](https://travis-ci.org/sialcasa/mvvmFX)
diff --git a/deploy_release.sh b/deploy_release.sh
new file mode 100755
index 000000000..4a16a4e56
--- /dev/null
+++ b/deploy_release.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Script for the deployment of releases to maven central
+#
+# Expecting a "settings-mvvmfx.xml" file in maven_home with the authentication configuration for the central repository.
+#
+# The settings file should look something like this:
+#
+#
+#
+#
+#
+# sonatype-nexus-snapshots
+# YOUR USERNAME
+# YOUR PASSWORD
+#
+#
+# sonatype-nexus-staging
+# YOUR USERNAME
+# YOUR PASSWORD
+#
+#
+#
+
+mvn clean deploy -pl 'mvvmfx,mvvmfx-cdi,mvvmfx-guice,mvvmfx-archetype' -am -DskipTests=true -Pdeploy-release --settings ~/.m2/settings-mvvmfx.xml
diff --git a/examples/README.md b/examples/README.md
index ed4bfc10e..91e20c9b9 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -11,3 +11,7 @@ as dependency injection framework.
- **mvvmfx-fx-root-example**: contains a small custom control that uses the fx:root element together with mvvmfx.
- **mvvmfx-helloworld-example**: A simple hello world view. This example is used in the [Getting Started/Step-by-Step tutorial](/../../wiki/Getting-Started-HelloWorld-%28deutsch%29).
- **mvvmfx-helloworld-without-fxml**: A hello world example that shows hot to use MvvmFX with a view implemented in pure Java and not with FXML.
+- **mvvmfx-contacts**: A contact management application. This example shows a master-detail view, dialogs and the usage of CDI including CDI-Events.
+This example also integrates some other JavaFX community libraries.
+- **mvvmfx-synchronizefx**: This example uses the library [SynchronizeFX](https://github.com/saxsys/SynchronizeFX) to create a distributed ViewModel.
+This way the state of the UI of different instances of the App (on different JVM's, on different computers) is always synchronized between the apps.
\ No newline at end of file
diff --git a/examples/mvvmfx-books-example/README.md b/examples/mvvmfx-books-example/README.md
new file mode 100644
index 000000000..369cae281
--- /dev/null
+++ b/examples/mvvmfx-books-example/README.md
@@ -0,0 +1,24 @@
+# MvvmFX Books Example
+
+This example app is a client for a library REST service. You can search for books and view the
+details of found books in a master-detail view.
+
+![screenshot](screenshot.png)
+
+This example was used for [a talk](http://www.jug-gr.de/2014/12/03/model-view-star.html) at the
+[JavaUserGroup Görlitz](http://www.jug-gr.de) on [UI-Design patterns](https://github.com/lestard/model-view-star).
+
+Originally [this app](https://github.com/sbley/hypermedia-library-client/tree/javafx) was created by [Stefan Bley](https://github.com/sbley) and
+[Alexander Casall](https://github.com/sialcasa) for a talk on Hypermedia-APIs.
+To run the app you need to have the [Hypermedia-API server](https://github.com/sbley/hypermedia-library-server)
+up and running on `localhost` so that the client can make the necessary REST-Requests.
+
+
+The app uses the following libraries (among others):
+
+- [FontAwesomeFX](https://bitbucket.org/Jerady/fontawesomefx) // Icons
+- [FlatterFX](http://www.guigarage.com/javafx-themes/flatter/) // Styling
+- [Advanced-Bindings](https://github.com/lestard/advanced-bindings) // Binding-Utils
+- [EasyDI](https://github.com/lestard/EasyDI) // Dependency-Injection
+- [AssertJ-JavaFX](https://github.com/lestard/assertj-javafx) // Testing
+- [HALBuilder](https://github.com/HalBuilder) // REST-Client
\ No newline at end of file
diff --git a/examples/mvvmfx-books-example/pom.xml b/examples/mvvmfx-books-example/pom.xml
new file mode 100644
index 000000000..b2e6b008a
--- /dev/null
+++ b/examples/mvvmfx-books-example/pom.xml
@@ -0,0 +1,102 @@
+
+
+
+ mvvmfx-examples
+ de.saxsys
+ 1.0.0
+
+ 4.0.0
+
+ mvvmfx-library-example
+
+
+ UTF-8
+ 1.8
+ 1.8
+
+
+
+
+ de.saxsys
+ mvvmfx
+ ${project.parent.version}
+
+
+ eu.lestard
+ easy-di
+ 0.1.0
+
+
+ de.jensd
+ fontawesomefx
+ 8.0.10
+
+
+ com.guigarage
+ flatter
+ 0.7
+
+
+ eu.lestard
+ advanced-bindings
+ 0.2.0
+
+
+
+
+ com.theoryinpractise
+ halbuilder-json
+ 4.0.2
+
+
+ com.theoryinpractise
+ halbuilder-jaxrs
+ 1.1.1
+
+
+ org.jboss.resteasy
+ resteasy-client
+ 3.0.9.Final
+
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+ ch.qos.logback
+ logback-classic
+ 1.1.2
+
+
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+ eu.lestard
+ assertj-javafx
+ 0.2.0
+ test
+
+
+ org.mockito
+ mockito-all
+ test
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/mvvmfx-books-example/screenshot.png b/examples/mvvmfx-books-example/screenshot.png
new file mode 100644
index 000000000..b38fad33d
Binary files /dev/null and b/examples/mvvmfx-books-example/screenshot.png differ
diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/App.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/App.java
new file mode 100644
index 000000000..8e03ea484
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/App.java
@@ -0,0 +1,40 @@
+package de.saxsys.mvvmfx.examples.books;
+
+import com.guigarage.flatterfx.FlatterFX;
+import com.guigarage.flatterfx.FlatterInputType;
+import de.saxsys.mvvmfx.FluentViewLoader;
+import de.saxsys.mvvmfx.MvvmFX;
+import de.saxsys.mvvmfx.examples.books.backend.LibraryService;
+import de.saxsys.mvvmfx.examples.books.backend.LibraryServiceImpl;
+import eu.lestard.easydi.EasyDI;
+import javafx.application.Application;
+import javafx.scene.Scene;
+import javafx.scene.paint.Color;
+import javafx.stage.Stage;
+
+public class App extends Application {
+
+ public static void main(String[] args) {
+ launch(args);
+ }
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ EasyDI context = new EasyDI();
+ context.bindInterface(LibraryService.class, LibraryServiceImpl.class);
+ MvvmFX.setCustomDependencyInjector(context::getInstance);
+
+ primaryStage.setTitle("Library JavaFX");
+ primaryStage.setMinWidth(1200);
+ primaryStage.setMaxWidth(1200);
+ primaryStage.setMinHeight(700);
+
+ Scene scene = new Scene(FluentViewLoader.fxmlView(MainView.class).load().getView(), 1200, 700);
+
+ scene.setFill(Color.TRANSPARENT);
+ primaryStage.setScene(scene);
+ primaryStage.show();
+ FlatterFX.style(FlatterInputType.DEFAULT);
+ }
+}
+
diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/BookViewModel.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/BookViewModel.java
new file mode 100644
index 000000000..7d25474ef
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/BookViewModel.java
@@ -0,0 +1,30 @@
+package de.saxsys.mvvmfx.examples.books;
+
+
+import de.saxsys.mvvmfx.examples.books.backend.Book;
+
+public class BookViewModel {
+
+ private final Book book;
+
+ public BookViewModel(Book book){
+ this.book = book;
+ }
+
+ public String getTitle(){
+ return book.getTitle();
+ }
+
+ public String getAuthor(){
+ return book.getAuthor();
+ }
+
+ public String getDescription(){
+ return book.getDesc();
+ }
+
+ @Override
+ public String toString() {
+ return getTitle();
+ }
+}
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
new file mode 100644
index 000000000..bc0a0dd6d
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainView.java
@@ -0,0 +1,53 @@
+package de.saxsys.mvvmfx.examples.books;
+
+import de.saxsys.mvvmfx.FxmlView;
+import de.saxsys.mvvmfx.InjectViewModel;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ListView;
+import javafx.scene.control.TextField;
+
+public class MainView implements FxmlView {
+
+
+ @FXML
+ private Label titleLabel;
+
+ @FXML
+ private Label authorLabel;
+
+ @FXML
+ private TextField searchTextField;
+
+ @FXML
+ private Button searchButton;
+
+ @FXML
+ private Label descriptionLabel;
+
+ @FXML
+ private ListView bookList;
+
+ @FXML
+ private Label errorLabel;
+
+ @InjectViewModel
+ private MainViewModel viewModel;
+
+ public void initialize(){
+ searchTextField.textProperty().bindBidirectional(viewModel.searchStringProperty());
+ titleLabel.textProperty().bind(viewModel.bookTitleProperty());
+ authorLabel.textProperty().bind(viewModel.bookAuthorProperty());
+ descriptionLabel.textProperty().bind(viewModel.bookDescriptionProperty());
+
+ bookList.setItems(viewModel.booksProperty());
+
+ viewModel.selectedBookProperty().bind(bookList.getSelectionModel().selectedItemProperty());
+ errorLabel.textProperty().bind(viewModel.errorProperty());
+ }
+
+ public void searchButtonPressed() {
+ viewModel.search();
+ }
+}
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
new file mode 100644
index 000000000..37c177d6a
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/MainViewModel.java
@@ -0,0 +1,86 @@
+package de.saxsys.mvvmfx.examples.books;
+
+import de.saxsys.mvvmfx.ViewModel;
+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 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.collections.FXCollections;
+import javafx.collections.ObservableList;
+
+import javax.inject.Singleton;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+@Singleton
+public class MainViewModel implements ViewModel {
+
+ private final LibraryService libraryService;
+ private StringProperty searchString = new SimpleStringProperty("");
+
+ private StringProperty bookTitle = new SimpleStringProperty();
+ private StringProperty bookAuthor = new SimpleStringProperty();
+ private StringProperty bookDescription = new SimpleStringProperty();
+
+ private ObservableList books = FXCollections.observableArrayList();
+
+ private ObjectProperty selectedBook = new SimpleObjectProperty<>();
+
+ private StringProperty error = new SimpleStringProperty();
+
+ public MainViewModel(LibraryService libraryService){
+ this.libraryService = libraryService;
+
+ bookTitle.bind(ObjectBindings.map(selectedBook, BookViewModel::getTitle));
+ bookAuthor.bind(ObjectBindings.map(selectedBook, BookViewModel::getAuthor));
+ bookDescription.bind(ObjectBindings.map(selectedBook, BookViewModel::getDescription));
+ }
+
+
+ public void search(){
+ Consumer errorHandler = err -> error.set(err.getMessage());
+
+ final List result = libraryService.search(searchString.get(), errorHandler);
+
+ books.clear();
+ books.addAll(result
+ .stream()
+ .map(bookWithoutDescription -> libraryService.showDetails(bookWithoutDescription, errorHandler))
+ .map(BookViewModel::new)
+ .collect(Collectors.toList()));
+ }
+
+
+ public StringProperty searchStringProperty() {
+ return searchString;
+ }
+
+ public StringProperty bookTitleProperty() {
+ return bookTitle;
+ }
+
+ public StringProperty bookAuthorProperty() {
+ return bookAuthor;
+ }
+
+ public StringProperty bookDescriptionProperty() {
+ return bookDescription;
+ }
+
+ public ObservableList booksProperty(){
+ return books;
+ }
+
+ public ObjectProperty selectedBookProperty(){
+ return selectedBook;
+ }
+
+ public StringProperty errorProperty(){
+ return error;
+ }
+}
diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/Book.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/Book.java
new file mode 100644
index 000000000..564b0eeda
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/Book.java
@@ -0,0 +1,76 @@
+package de.saxsys.mvvmfx.examples.books.backend;
+
+import com.theoryinpractise.halbuilder.api.Link;
+
+public class Book {
+
+ private final String href;
+ private final String title;
+ private String author;
+ private String desc;
+ private Integer borrower;
+ private final Link relLend;
+ private final Link relReturn;
+
+ public Book(String href, String title, String author, String desc, Link relLend, Link relReturn) {
+ super();
+ this.href = href;
+ this.title = title;
+ this.author = author;
+ this.desc = desc;
+ this.relLend = relLend;
+ this.relReturn = relReturn;
+ }
+
+ public String getHref() {
+ return href;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public Integer getBorrower() {
+ return borrower;
+ }
+
+ public void setBorrower(Integer borrower) {
+ this.borrower = borrower;
+ }
+
+ public Link getRelLend() {
+ return relLend;
+ }
+
+ public Link getRelReturn() {
+ return relReturn;
+ }
+
+ public boolean isLent() {
+ return borrower != null;
+ }
+
+ public boolean isAvailable() {
+ return null != relLend;
+ }
+
+ public boolean isReturnable() {
+ return null != relReturn;
+ }
+}
diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/Error.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/Error.java
new file mode 100644
index 000000000..1dd344300
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/Error.java
@@ -0,0 +1,25 @@
+package de.saxsys.mvvmfx.examples.books.backend;
+
+public class Error {
+
+ private final String message;
+
+ private final String details;
+
+ public static Error error(String message, String details){
+ return new Error(message, details);
+ }
+
+ private Error(String message, String details){
+ this.message = message;
+ this.details = details;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getDetails() {
+ return details;
+ }
+}
diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/HalUtil.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/HalUtil.java
new file mode 100644
index 000000000..fed74d273
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/HalUtil.java
@@ -0,0 +1,16 @@
+package de.saxsys.mvvmfx.examples.books.backend;
+
+public class HalUtil {
+
+ public static String replaceParam(String href, String param) {
+ return href.replaceFirst("\\{.+\\}", param);
+ }
+
+ public static Integer toInt(Object value) {
+ if (value.getClass().isAssignableFrom(String.class)) {
+ String valueStr = (String) value;
+ return Integer.valueOf(valueStr);
+ }
+ return null;
+ }
+}
diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/LibraryService.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/LibraryService.java
new file mode 100644
index 000000000..f3ff47e79
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/LibraryService.java
@@ -0,0 +1,14 @@
+package de.saxsys.mvvmfx.examples.books.backend;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+public interface LibraryService {
+ List search(String query, Consumer errorCallback);
+
+ Book showDetails(Book book, Consumer errorCallback);
+
+ Book lend(String lendTo, Book detailBook, Consumer errorCallback);
+
+ Book takeBack(Book detailBook, Consumer errorCallback);
+}
diff --git a/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/LibraryServiceImpl.java b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/LibraryServiceImpl.java
new file mode 100644
index 000000000..87b59087c
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/java/de/saxsys/mvvmfx/examples/books/backend/LibraryServiceImpl.java
@@ -0,0 +1,156 @@
+package de.saxsys.mvvmfx.examples.books.backend;
+
+import com.theoryinpractise.halbuilder.api.ContentRepresentation;
+import com.theoryinpractise.halbuilder.api.Link;
+import com.theoryinpractise.halbuilder.api.ReadableRepresentation;
+import com.theoryinpractise.halbuilder.jaxrs.JaxRsHalBuilderReaderSupport;
+import org.jboss.resteasy.client.jaxrs.cache.BrowserCacheFeature;
+import org.jboss.resteasy.plugins.interceptors.encoding.AcceptEncodingGZIPFilter;
+import org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Response;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Consumer;
+
+import static com.theoryinpractise.halbuilder.api.RepresentationFactory.*;
+
+public class LibraryServiceImpl implements Serializable, LibraryService {
+
+ private static final long serialVersionUID = 1L;
+ private static final String BASE_URL = "http://localhost:8080/rest";
+ private static final Logger LOGGER = LoggerFactory.getLogger(LibraryServiceImpl.class);
+
+ private Client apiClient;
+
+ public LibraryServiceImpl(){
+ apiClient =
+ ClientBuilder.newClient()
+ .register(JaxRsHalBuilderReaderSupport.class)
+ .register(BrowserCacheFeature.class)
+ .register(GZIPDecodingInterceptor.class)
+ .register(AcceptEncodingGZIPFilter.class);
+ }
+
+ @Override
+ public List search(String query, Consumer errorCallback) {
+ try {
+ // home
+ Response responseHome = apiClient.target(BASE_URL).request(HAL_JSON).get();
+ ContentRepresentation repHome = responseHome.readEntity(ContentRepresentation.class);
+ // search
+ Link searchLink = repHome.getLinkByRel("lib:search");
+ String href = HalUtil.replaceParam(searchLink.getHref(), query);
+ Response responseSearch = apiClient.target(href).request(HAL_JSON).get();
+ ContentRepresentation repSearch =
+ responseSearch.readEntity(ContentRepresentation.class);
+ Collection resultSet =
+ repSearch.getResourceMap().get("lib:book");
+ List books = new ArrayList<>();
+ if (null != resultSet) {
+ for (ReadableRepresentation rep : resultSet) {
+ Book book = toBook(rep);
+ if (null == book.getTitle() || null == book.getAuthor()) {
+ // get book
+ Response response =
+ apiClient.target(book.getHref()).request(HAL_JSON).get();
+ ContentRepresentation repBook =
+ response.readEntity(ContentRepresentation.class);
+ book = toBook(repBook);
+ }
+ books.add(book);
+ }
+ }
+ return books;
+ } catch (Throwable e) {
+ LOGGER.error("Error during search", e);
+ errorCallback.accept(Error.error("Error during search", e.getMessage()));
+ return new ArrayList<>();
+ }
+ }
+
+ @Override
+ public Book showDetails(Book book, Consumer errorCallback) {
+ LOGGER.debug("Show details for book at {}", book.getHref());
+ try {
+ Response response = apiClient.target(book.getHref()).request(HAL_JSON).get();
+ ContentRepresentation rep = response.readEntity(ContentRepresentation.class);
+ return toBook(rep);
+ } catch (Exception e) {
+ LOGGER.error("Error retrieving book", e);
+ errorCallback.accept(Error.error("Error retrieving book", e.getMessage()));
+ return null;
+ }
+ }
+
+ @Override
+ public Book lend(String lendTo, Book detailBook, Consumer errorCallback) {
+ LOGGER.debug("Lend book {} to member {}", detailBook.getTitle(), lendTo);
+ try {
+ Integer.valueOf(lendTo);
+ } catch (NumberFormatException e) {
+ errorCallback.accept(Error.error("Invalid MemberID", "MemberID is not a number"));
+ return null;
+ }
+ Response response =
+ apiClient.target(detailBook.getRelLend().getHref())
+ .request(HAL_JSON)
+ .put(Entity.json("{\"memberId\":" + lendTo + "}"));
+ ContentRepresentation rep = response.readEntity(ContentRepresentation.class);
+ if (response.getStatus() >= 400) {
+ String message = (String) rep.getValue("title");
+ String detail = (String) rep.getValue("detail", null);
+ LOGGER.error("{} {} {}", response.getStatus(), message, detail);
+ errorCallback.accept(Error.error(message, detail));
+ return null;
+ } else {
+ detailBook = toBook(rep);
+ LOGGER.debug("Book {} lent to member {}", detailBook.getTitle(),
+ detailBook.getBorrower());
+ return detailBook;
+ }
+ }
+
+ @Override
+ public Book takeBack(Book detailBook, Consumer errorCallback) {
+ LOGGER.debug("Return book {} from member {}", detailBook.getTitle(),
+ detailBook.getBorrower());
+ Response response =
+ apiClient.target(
+ HalUtil.replaceParam(detailBook.getRelReturn().getHref(), detailBook.getBorrower()
+ .toString()))
+ .request(HAL_JSON)
+ .delete();
+ ContentRepresentation rep = response.readEntity(ContentRepresentation.class);
+ if (response.getStatus() >= 400) {
+ String message = (String) rep.getValue("title");
+ String detail = (String) rep.getValue("detail", null);
+ LOGGER.error("{} {}", message, detail);
+ errorCallback.accept(Error.error(message, detail));
+ return null;
+ } else {
+ LOGGER.debug("Book {} returned", detailBook.getTitle());
+ return toBook(rep);
+ }
+ }
+
+ private Book toBook(ReadableRepresentation rep) {
+ Book book =
+ new Book(
+ rep.getResourceLink().getHref(), (String) rep.getValue("title", null),
+ (String) rep.getValue("author", null), (String) rep.getValue("description",
+ null), rep.getLinkByRel("lib:lend"), rep.getLinkByRel("lib:return"));
+ // add borrower if available
+ List extends ReadableRepresentation> borrowerResource = rep.getResourcesByRel("borrower");
+ if (1 == borrowerResource.size())
+ book.setBorrower(Integer.valueOf((String) borrowerResource.get(0).getValue("id")));
+ return book;
+ }
+}
diff --git a/examples/mvvmfx-books-example/src/main/resources/de/saxsys/mvvmfx/examples/books/MainView.fxml b/examples/mvvmfx-books-example/src/main/resources/de/saxsys/mvvmfx/examples/books/MainView.fxml
new file mode 100644
index 000000000..a36d0e1b6
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/resources/de/saxsys/mvvmfx/examples/books/MainView.fxml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/mvvmfx-books-example/src/main/resources/de/saxsys/mvvmfx/examples/books/style.css b/examples/mvvmfx-books-example/src/main/resources/de/saxsys/mvvmfx/examples/books/style.css
new file mode 100644
index 000000000..16fef4bfb
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/resources/de/saxsys/mvvmfx/examples/books/style.css
@@ -0,0 +1,26 @@
+.container {
+
+}
+
+.label
+{
+ -fx-text-fill: black;
+}
+
+.title1{
+ -fx-font-size:50;
+}
+
+.title2{
+ -fx-font-size:40;
+ -fx-text-fill: gray;
+}
+
+.errorLabel{
+ -fx-font-size:20;
+ -fx-text-fill: red;
+}
+
+.split-pane *.split-pane-divider {
+ -fx-padding: 0 1 0 1;
+}
diff --git a/examples/mvvmfx-books-example/src/main/resources/logback.xml b/examples/mvvmfx-books-example/src/main/resources/logback.xml
new file mode 100644
index 000000000..e449b89cf
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/main/resources/logback.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ %d{"HH:mm:ss,SSS"} %-5level [%-35logger{35}] %msg%n
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/mvvmfx-books-example/src/test/java/de/saxsys/mvvmfx/examples/books/MainViewModelTest.java b/examples/mvvmfx-books-example/src/test/java/de/saxsys/mvvmfx/examples/books/MainViewModelTest.java
new file mode 100644
index 000000000..76b1f5257
--- /dev/null
+++ b/examples/mvvmfx-books-example/src/test/java/de/saxsys/mvvmfx/examples/books/MainViewModelTest.java
@@ -0,0 +1,137 @@
+package de.saxsys.mvvmfx.examples.books;
+
+import de.saxsys.mvvmfx.examples.books.backend.Error;
+import de.saxsys.mvvmfx.examples.books.backend.Book;
+import de.saxsys.mvvmfx.examples.books.backend.LibraryService;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.function.Consumer;
+
+import static org.assertj.core.api.Assertions.*;
+import static eu.lestard.assertj.javafx.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+public class MainViewModelTest {
+
+ private MainViewModel viewModel;
+ private LibraryService libraryService;
+
+ @Before
+ public void setup(){
+ libraryService = mock(LibraryService.class);
+
+ viewModel = new MainViewModel(libraryService);
+ }
+
+
+ @Test
+ public void testSelectionOfBooks(){
+ // given
+ Book book1 = createBook("Das Leben des Horst", "Horst", "Eine geschichte über Horst");
+ Book book2 = createBook("Die Verwandlung", "Franz Kafka", "Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte...");
+
+ final BookViewModel bookViewModel1 = new BookViewModel(book1);
+ final BookViewModel bookViewModel2 = new BookViewModel(book2);
+
+ viewModel.booksProperty().add(bookViewModel1);
+ viewModel.booksProperty().add(bookViewModel2);
+
+ assertThat(viewModel.bookTitleProperty()).hasNullValue();
+ assertThat(viewModel.bookAuthorProperty()).hasNullValue();
+ assertThat(viewModel.bookDescriptionProperty()).hasNullValue();
+
+ // when
+ viewModel.selectedBookProperty().set(bookViewModel1);
+
+ // then
+ assertThat(viewModel.bookTitleProperty()).hasValue("Das Leben des Horst");
+ assertThat(viewModel.bookAuthorProperty()).hasValue("Horst");
+ assertThat(viewModel.bookDescriptionProperty()).hasValue("Eine geschichte über Horst");
+
+ // when
+ viewModel.selectedBookProperty().set(bookViewModel2);
+
+ // then
+ assertThat(viewModel.bookTitleProperty()).hasValue("Die Verwandlung");
+ assertThat(viewModel.bookAuthorProperty()).hasValue("Franz Kafka");
+ assertThat(viewModel.bookDescriptionProperty()).hasValue("Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte...");
+ }
+
+ @Test
+ public void testSearch(){
+ // given
+ assertThat(viewModel.booksProperty()).isEmpty();
+ assertThat(viewModel.searchStringProperty()).hasValue("");
+
+ Book book1 = createBook("a book starting with a", "some author", null);
+ Book book1WithDescription = createBook("a book starting with a", "some author", "some description 1");
+ Book book2 = createBook("another book starting with a", "some author", null);
+ Book book2WithDescription = createBook("another book starting with a", "some author", "some description 2");
+ Book book3 = createBook("book starting with b", "some author", null);
+ Book book3WithDescription = createBook("book starting with b", "some author", "some description 3");
+
+ when(libraryService.search(eq("a"), any())).thenReturn(Arrays.asList(book1, book2));
+ when(libraryService.search(eq("b"), any())).thenReturn(Arrays.asList(book3));
+ when(libraryService.search(eq(""), any())).thenReturn(Collections.emptyList());
+
+ when(libraryService.showDetails(eq(book1), any())).thenReturn(book1WithDescription);
+ when(libraryService.showDetails(eq(book2), any())).thenReturn(book2WithDescription);
+ when(libraryService.showDetails(eq(book3), any())).thenReturn(book3WithDescription);
+
+ // when
+ viewModel.searchStringProperty().set("a");
+ viewModel.search();
+
+
+ // then
+ assertThat(viewModel.booksProperty()).hasSize(2);
+ assertThat(viewModel.booksProperty().get(0).getTitle()).isEqualTo("a book starting with a");
+ assertThat(viewModel.booksProperty().get(0).getDescription()).isEqualTo("some description 1");
+ assertThat(viewModel.booksProperty().get(1).getTitle()).isEqualTo("another book starting with a");
+ assertThat(viewModel.booksProperty().get(1).getDescription()).isEqualTo("some description 2");
+
+
+ // when
+ viewModel.searchStringProperty().set("b");
+ viewModel.search();
+
+ // then
+ assertThat(viewModel.booksProperty()).hasSize(1);
+ assertThat(viewModel.booksProperty().get(0).getTitle()).isEqualTo("book starting with b");
+ assertThat(viewModel.booksProperty().get(0).getDescription()).isEqualTo("some description 3");
+
+
+ // when
+ viewModel.searchStringProperty().set("");
+ viewModel.search();
+
+ assertThat(viewModel.booksProperty()).isEmpty();
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testErrors(){
+ assertThat(viewModel.errorProperty()).hasNullValue();
+ when(libraryService.search(any(), any())).thenAnswer(invocation -> {
+
+ final Consumer errorHandler = (Consumer)invocation.getArguments()[1];
+ errorHandler.accept(Error.error("error message", "description"));
+ return Collections.emptyList();
+ });
+
+
+ viewModel.searchStringProperty().set("a");
+ viewModel.search();
+
+ assertThat(viewModel.booksProperty()).isEmpty();
+ assertThat(viewModel.errorProperty()).hasValue("error message");
+ }
+
+ private Book createBook(String title, String author, String desc){
+ return new Book(null, title, author, desc, null, null);
+ }
+
+}
diff --git a/examples/mvvmfx-cdi-starter/pom.xml b/examples/mvvmfx-cdi-starter/pom.xml
index 60f5990af..13cbeff97 100644
--- a/examples/mvvmfx-cdi-starter/pom.xml
+++ b/examples/mvvmfx-cdi-starter/pom.xml
@@ -11,8 +11,8 @@
de.saxsys
- mvvmFX-examples
- 0.4.0
+ mvvmfx-examples
+ 1.0.0
@@ -41,12 +41,12 @@
de.saxsys
- mvvmFX
+ mvvmfx
${project.parent.version}
de.saxsys
- mvvmFX-cdi
+ mvvmfx-cdi
${project.parent.version}
diff --git a/examples/mvvmfx-complex-example/pom.xml b/examples/mvvmfx-complex-example/pom.xml
index 4a5ab86dc..aa7aed35e 100644
--- a/examples/mvvmfx-complex-example/pom.xml
+++ b/examples/mvvmfx-complex-example/pom.xml
@@ -6,8 +6,8 @@
de.saxsys
- mvvmFX-examples
- 0.4.0
+ mvvmfx-examples
+ 1.0.0
UTF-8
@@ -45,7 +45,7 @@
de.saxsys
- mvvmFX
+ mvvmfx
${project.parent.version}
diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Gender.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Gender.java
new file mode 100644
index 000000000..23e9824ea
--- /dev/null
+++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Gender.java
@@ -0,0 +1,13 @@
+package de.saxsys.jfx.exampleapplication.model;
+
+/**
+ * Enum of possible gender information.
+ * If a person doesn't like to provide a gender, the value {@link #NOT_SPECIFIED} can be used.
+ */
+public enum Gender {
+
+ MALE,
+ FEMALE,
+ NOT_SPECIFIED
+
+}
diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Person.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Person.java
index 14c0dd5a1..53b62801a 100644
--- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Person.java
+++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Person.java
@@ -1,11 +1,12 @@
package de.saxsys.jfx.exampleapplication.model;
-import java.util.Random;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
+import java.util.Random;
+
/**
* The class represents a Person with a firstname and a lastname. It provides access with JavaFX Properties.
*
@@ -17,7 +18,7 @@ public class Person {
private int technicalID;
private final StringProperty firstName = new SimpleStringProperty();
private final StringProperty lastName = new SimpleStringProperty();
- private final BooleanProperty male = new SimpleBooleanProperty();
+ private final ObjectProperty gender = new SimpleObjectProperty<>();
/**
* Creates a person with given name.
@@ -26,11 +27,13 @@ public class Person {
* of person
* @param lastName
* of person
+ * @param gender
+ * of person
*/
- public Person(final String firstName, final String lastName, final boolean isMale) {
+ public Person(final String firstName, final String lastName, Gender gender) {
this.firstName.set(firstName);
this.lastName.set(lastName);
- this.male.set(isMale);
+ this.gender.set(gender);
}
/**
@@ -46,12 +49,13 @@ public StringProperty firstNameProperty() {
public StringProperty lastNameProperty() {
return lastName;
}
-
+
+
/**
- * @return male as {@link BooleanProperty}
+ * @return the gender of the person as {@link javafx.beans.property.ObjectProperty}.
*/
- public BooleanProperty maleProperty() {
- return male;
+ public ObjectProperty genderProperty() {
+ return gender;
}
/**
@@ -84,20 +88,19 @@ public void setLastName(final String lastName) {
}
/**
- * @return male as boolean
+ * @return the gender of the person as {@link String}
*/
- public boolean isMale() {
- return male.get();
+ public Gender getGender() {
+ return gender.get();
}
-
+
/**
- * @see #isMale()
- * @param male
- * whether the person is male
+ * @see #getGender()
*/
- public void setMale(boolean male) {
- this.male.set(male);
+ public void setGender(Gender gender){
+ this.gender.set(gender);
}
+
/**
* Gets the technical id.
diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Repository.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Repository.java
index af6ba43a4..3fe5c1cbd 100644
--- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Repository.java
+++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/model/Repository.java
@@ -1,9 +1,9 @@
package de.saxsys.jfx.exampleapplication.model;
+import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
-import javax.inject.Singleton;
/**
* Service class for providing some dummy data.
@@ -19,11 +19,12 @@ public class Repository {
* Creates the Repo.
*/
public Repository() {
- persons.add(new Person("Alexander", "Casall", true));
- persons.add(new Person("Bernd", "Grams", true));
- persons.add(new Person("Anna", "Schulze", false));
+ persons.add(new Person("Alexander", "Casall", Gender.MALE));
+ persons.add(new Person("Bernd", "Grams", Gender.MALE));
+ persons.add(new Person("Anna", "Schulze", Gender.FEMALE));
+ persons.add(new Person("Andy", "Mueller", Gender.NOT_SPECIFIED));
}
-
+
/**
* @return available {@link Person}s
*/
diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/maincontainer/MainContainerView.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/maincontainer/MainContainerView.java
index ef5bf4b7d..92e97816e 100644
--- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/maincontainer/MainContainerView.java
+++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/maincontainer/MainContainerView.java
@@ -9,7 +9,6 @@
import de.saxsys.mvvmfx.InjectViewModel;
import de.saxsys.mvvmfx.ViewTuple;
import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
-import de.saxsys.mvvmfx.utils.notifications.NotificationObserver;
import de.saxsys.mvvmfx.utils.viewlist.ViewListCellFactory;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
@@ -57,16 +56,12 @@ public class MainContainerView implements FxmlView, Init
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// Listen for close notifications
- notificationCenter.addObserverForName("hidePersonWelcome",
- new NotificationObserver() {
- @Override
- public void receivedNotification(String key,
- Object... objects) {
- int personIdToHide = (int) objects[0];
- viewModel.displayedPersonsProperty().remove(
- new Integer(personIdToHide));
- }
- });
+ notificationCenter.subscribe("hidePersonWelcome",
+ (key, payload) -> {
+ int personIdToHide = (int) payload[0];
+ viewModel.displayedPersonsProperty().remove(
+ new Integer(personIdToHide));
+ });
// When the login button of the loginView, the pickedPersonProperty is
// going to have the index of the selected person
diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personwelcome/PersonWelcomeView.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personwelcome/PersonWelcomeView.java
index d0778f069..aae528f11 100644
--- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personwelcome/PersonWelcomeView.java
+++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/view/personwelcome/PersonWelcomeView.java
@@ -1,19 +1,17 @@
package de.saxsys.jfx.exampleapplication.view.personwelcome;
-import java.net.URL;
-import java.util.ResourceBundle;
-
+import de.saxsys.jfx.exampleapplication.viewmodel.personwelcome.PersonWelcomeViewModel;
+import de.saxsys.mvvmfx.FxmlView;
+import de.saxsys.mvvmfx.InjectViewModel;
+import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javax.inject.Inject;
-
-import de.saxsys.jfx.exampleapplication.viewmodel.personwelcome.PersonWelcomeViewModel;
-import de.saxsys.mvvmfx.FxmlView;
-import de.saxsys.mvvmfx.InjectViewModel;
-import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
+import java.net.URL;
+import java.util.ResourceBundle;
/**
* Code behind the fxml for visualization of the PersonWelcomeViewModel. The view binds to the property of the
@@ -38,7 +36,7 @@ public class PersonWelcomeView implements FxmlView, Init
// Handler for Button[Button[id=null, styleClass=button]] onAction
public void closeApplicationButtonPressed(ActionEvent event) {
// MainContainerView.java will handle it
- notificationCenter.postNotification("hidePersonWelcome", viewModel
+ notificationCenter.publish("hidePersonWelcome", viewModel
.getPersonId());
}
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 1bc59144f..d6aa10d47 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,17 +1,16 @@
package de.saxsys.jfx.exampleapplication.viewmodel.personlogin;
-import javafx.beans.property.IntegerProperty;
-import javafx.beans.property.SimpleIntegerProperty;
-import javafx.collections.FXCollections;
-
-import javax.inject.Inject;
-
import de.saxsys.jfx.exampleapplication.model.Person;
import de.saxsys.jfx.exampleapplication.model.Repository;
import de.saxsys.mvvmfx.ViewModel;
import de.saxsys.mvvmfx.utils.itemlist.ModelToStringFunction;
import de.saxsys.mvvmfx.utils.itemlist.SelectableItemList;
import de.saxsys.mvvmfx.utils.itemlist.SelectableStringList;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.collections.FXCollections;
+
+import javax.inject.Inject;
/**
* ViewModel for a login view for the persons. It provides the data which should be visualized in the frontend e.g. the
@@ -31,12 +30,7 @@ public class PersonLoginViewModel implements ViewModel {
@Inject
public PersonLoginViewModel(Repository repository) {
- ModelToStringFunction personMapper = new ModelToStringFunction() {
- @Override
- public String apply(Person person) {
- return person.getFirstName() + " " + person.getLastName();
- }
- };
+ ModelToStringFunction personMapper = person -> person.getFirstName() + " " + person.getLastName();
selectablePersons = new SelectableItemList(
FXCollections.observableArrayList(repository.getPersons()),
personMapper);
diff --git a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personwelcome/PersonWelcomeViewModel.java b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personwelcome/PersonWelcomeViewModel.java
index 3421d861a..f78b1b47d 100644
--- a/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personwelcome/PersonWelcomeViewModel.java
+++ b/examples/mvvmfx-complex-example/src/main/java/de/saxsys/jfx/exampleapplication/viewmodel/personwelcome/PersonWelcomeViewModel.java
@@ -1,5 +1,9 @@
package de.saxsys.jfx.exampleapplication.viewmodel.personwelcome;
+import de.saxsys.jfx.exampleapplication.model.Gender;
+import de.saxsys.jfx.exampleapplication.model.Person;
+import de.saxsys.jfx.exampleapplication.model.Repository;
+import de.saxsys.mvvmfx.ViewModel;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.SimpleStringProperty;
@@ -7,10 +11,6 @@
import javax.inject.Inject;
-import de.saxsys.jfx.exampleapplication.model.Person;
-import de.saxsys.jfx.exampleapplication.model.Repository;
-import de.saxsys.mvvmfx.ViewModel;
-
/**
* ViewModel for a welcome view for a person. It provides the data which should be visualized in the frontend. The tests
* for it can be written first. Have a look on PersonWelcomeViewModelTest.
@@ -55,7 +55,15 @@ public StringProperty welcomeStringProperty() {
*/
public void setPersonId(int personId) {
person = repository.getPersonById(personId);
- StringBinding salutationBinding = Bindings.when(person.maleProperty()).then("Herr ").otherwise("Frau ");
+
+ StringBinding salutationBinding =
+ Bindings.when(person.genderProperty().isEqualTo(Gender.NOT_SPECIFIED))
+ .then("Herr/Frau/* ")
+ .otherwise(
+ Bindings.when(person.genderProperty().isEqualTo(Gender.MALE))
+ .then("Herr ").otherwise("Frau "));
+
+ welcomeString.unbind();
welcomeString.bind(Bindings.concat("Willkommen ", salutationBinding,
person.lastNameProperty(), ", oder wollen Sie ",
person.firstNameProperty(), " genannt werden?"));
diff --git a/examples/mvvmfx-complex-example/src/test/java/de/saxsys/jfx/viewmodel/personwelcome/PersonWelcomeViewModelTest.java b/examples/mvvmfx-complex-example/src/test/java/de/saxsys/jfx/viewmodel/personwelcome/PersonWelcomeViewModelTest.java
index c09fb0145..e65f1d3b8 100644
--- a/examples/mvvmfx-complex-example/src/test/java/de/saxsys/jfx/viewmodel/personwelcome/PersonWelcomeViewModelTest.java
+++ b/examples/mvvmfx-complex-example/src/test/java/de/saxsys/jfx/viewmodel/personwelcome/PersonWelcomeViewModelTest.java
@@ -1,13 +1,13 @@
package de.saxsys.jfx.viewmodel.personwelcome;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Before;
-import org.junit.Test;
-
+import de.saxsys.jfx.exampleapplication.model.Gender;
import de.saxsys.jfx.exampleapplication.model.Person;
import de.saxsys.jfx.exampleapplication.model.Repository;
import de.saxsys.jfx.exampleapplication.viewmodel.personwelcome.PersonWelcomeViewModel;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
public class PersonWelcomeViewModelTest {
@@ -70,7 +70,7 @@ public void changeLastNameOfPersonIsReflectedInViewModel() throws Exception {
public void changeGenderOfPersonIsReflectedInViewModel() throws Exception {
final Person person = repository.getPersons().get(0);
personWelcomeViewModel.setPersonId(person.getId());
- person.setMale(false);
+ person.setGender(Gender.FEMALE);
assertEquals(
"Willkommen Frau Casall, oder wollen Sie Alexander genannt werden?",
personWelcomeViewModel.welcomeStringProperty().get());
diff --git a/examples/mvvmfx-contacts/pom.xml b/examples/mvvmfx-contacts/pom.xml
index af8b4d44f..fef1a5bc9 100644
--- a/examples/mvvmfx-contacts/pom.xml
+++ b/examples/mvvmfx-contacts/pom.xml
@@ -4,9 +4,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- mvvmFX-examples
+ mvvmfx-examples
de.saxsys
- 0.4.0
+ 1.0.0
mvvmfx-contacts
@@ -32,13 +32,13 @@
de.saxsys
- mvvmFX
- 0.4.0
+ mvvmfx
+ 1.0.0
de.saxsys
- mvvmFX-cdi
- 0.4.0
+ mvvmfx-cdi
+ 1.0.0
ch.qos.logback
diff --git a/examples/mvvmfx-fx-root-example/pom.xml b/examples/mvvmfx-fx-root-example/pom.xml
index 150b03aa9..1e2e8e9dd 100644
--- a/examples/mvvmfx-fx-root-example/pom.xml
+++ b/examples/mvvmfx-fx-root-example/pom.xml
@@ -6,8 +6,8 @@
de.saxsys
- mvvmFX-examples
- 0.4.0
+ mvvmfx-examples
+ 1.0.0
@@ -20,8 +20,8 @@
de.saxsys
- mvvmFX
- 0.4.0
+ mvvmfx
+ 1.0.0
diff --git a/examples/mvvmfx-guice-starter/pom.xml b/examples/mvvmfx-guice-starter/pom.xml
index 3650095c8..066c6bb81 100644
--- a/examples/mvvmfx-guice-starter/pom.xml
+++ b/examples/mvvmfx-guice-starter/pom.xml
@@ -11,8 +11,8 @@
de.saxsys
- mvvmFX-examples
- 0.4.0
+ mvvmfx-examples
+ 1.0.0
UTF-8
@@ -45,12 +45,12 @@
de.saxsys
- mvvmFX
+ mvvmfx
${project.parent.version}
de.saxsys
- mvvmFX-guice
+ mvvmfx-guice
${project.parent.version}
diff --git a/examples/mvvmfx-helloworld-without-fxml/pom.xml b/examples/mvvmfx-helloworld-without-fxml/pom.xml
index 60233e1fe..256168f14 100644
--- a/examples/mvvmfx-helloworld-without-fxml/pom.xml
+++ b/examples/mvvmfx-helloworld-without-fxml/pom.xml
@@ -6,8 +6,8 @@
de.saxsys
- mvvmFX-examples
- 0.4.0
+ mvvmfx-examples
+ 1.0.0
@@ -20,7 +20,7 @@
de.saxsys
- mvvmFX
+ mvvmfx
${project.parent.version}
diff --git a/examples/mvvmfx-helloworld/pom.xml b/examples/mvvmfx-helloworld/pom.xml
index 4014f7a72..709046658 100644
--- a/examples/mvvmfx-helloworld/pom.xml
+++ b/examples/mvvmfx-helloworld/pom.xml
@@ -5,8 +5,8 @@
HelloWorld Example
de.saxsys
- mvvmFX-examples
- 0.4.0
+ mvvmfx-examples
+ 1.0.0
UTF-8
@@ -18,7 +18,7 @@
de.saxsys
- mvvmFX
+ mvvmfx
${project.parent.version}
diff --git a/examples/mvvmfx-synchronizefx/README.md b/examples/mvvmfx-synchronizefx/README.md
index 4f79fe597..bff794f51 100644
--- a/examples/mvvmfx-synchronizefx/README.md
+++ b/examples/mvvmfx-synchronizefx/README.md
@@ -1,6 +1,8 @@
# MvvmFX with SynchronizeFX
-This example shows how you can combine mvvmFX with the framework [SynchronizeFX](https://github.com/saxsys/SynchronizeFX).
+This example shows how you can combine mvvmFX with the framework [SynchronizeFX](https://github.com/saxsys/SynchronizeFX)
+to create a distributed ViewModel. This way the state of the UI of different instances of the App
+(on different JVM's, on different computers) is always synchronized between the apps.
SynchronizeFX is a library for JavaFX that enables property bindings between different JVMs over the network.
diff --git a/examples/mvvmfx-synchronizefx/pom.xml b/examples/mvvmfx-synchronizefx/pom.xml
index a9d37e904..ccf656daf 100644
--- a/examples/mvvmfx-synchronizefx/pom.xml
+++ b/examples/mvvmfx-synchronizefx/pom.xml
@@ -5,8 +5,8 @@
SynchronizeFX example
de.saxsys
- mvvmFX-examples
- 0.4.0
+ mvvmfx-examples
+ 1.0.0
UTF-8
@@ -18,7 +18,7 @@
de.saxsys
- mvvmFX
+ mvvmfx
${project.parent.version}
diff --git a/examples/pom.xml b/examples/pom.xml
index 8c25816a2..7ebbc04e0 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -4,11 +4,11 @@
de.saxsys
- mvvmFX-parent
- 0.4.0
+ mvvmfx-parent
+ 1.0.0
- mvvmFX-examples
+ mvvmfx-examples
pom
@@ -21,25 +21,7 @@
mvvmfx-helloworld-without-fxml
mvvmfx-synchronizefx
mvvmfx-contacts
+ mvvmfx-books-example
-
-
-
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
-
- default-deploy
- none
-
-
-
-
-
-
-
-
-
diff --git a/mvvmfx-archetype/README.md b/mvvmfx-archetype/README.md
index 413392251..324a3af50 100644
--- a/mvvmfx-archetype/README.md
+++ b/mvvmfx-archetype/README.md
@@ -12,4 +12,4 @@ To use this archetype:
-DartifactId=your.artifact.id
-This creates an example mvvmfx project similar to the [mvvmfx-helloworld example](/examples/mvvmfx-helloworld).
\ No newline at end of file
+This creates an example mvvmfx project similar to the [mvvmfx-helloworld example](/examples/mvvmfx-helloworld).
diff --git a/mvvmfx-archetype/pom.xml b/mvvmfx-archetype/pom.xml
index edfe7f41f..7e147dbdc 100644
--- a/mvvmfx-archetype/pom.xml
+++ b/mvvmfx-archetype/pom.xml
@@ -4,12 +4,13 @@
de.saxsys
- mvvmFX-parent
- 0.4.0
+ mvvmfx-parent
+ 1.0.0
- mvvmFX-archetype
+ mvvmfx-archetype
+ maven-archetype
mvvmFX Archetype
@@ -22,6 +23,23 @@
+
+
+ org.apache.maven.archetype
+ archetype-packaging
+ 2.2
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-archetype-plugin
+ 2.2
+
+
+
maven-resources-plugin
@@ -29,16 +47,6 @@
\
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
-
- default-deploy
- deploy
-
-
-
diff --git a/mvvmfx-archetype/src/main/resources/archetype-resources/pom.xml b/mvvmfx-archetype/src/main/resources/archetype-resources/pom.xml
index f7cbf20b4..a458118cf 100644
--- a/mvvmfx-archetype/src/main/resources/archetype-resources/pom.xml
+++ b/mvvmfx-archetype/src/main/resources/archetype-resources/pom.xml
@@ -15,7 +15,7 @@
de.saxsys
- mvvmFX
+ mvvmfx
${version}
diff --git a/mvvmfx-cdi/README.md b/mvvmfx-cdi/README.md
index 56823f42a..cccbfec03 100644
--- a/mvvmfx-cdi/README.md
+++ b/mvvmfx-cdi/README.md
@@ -1,6 +1,7 @@
# MvvmFX CDI
-This Module is an extension for the [MvvmFX](https://github.com/sialcasa/mvvmFX) framework that adds support for CDI as a dependency injection framework.
+This module is an extension for the [MvvmFX](https://github.com/sialcasa/mvvmFX) framework that adds support for
+[CDI](http://cdi-spec.org/) as dependency injection framework. It uses [JBoss Weld](http://weld.cdi-spec.org/) as implementation for CDI.
To create an application that is powered by CDI / Weld you have to extend `MvvmfxCdiApplication`:
@@ -16,6 +17,6 @@ To create an application that is powered by CDI / Weld you have to extend `Mvvmf
}
}
-A simple example for this is available at [mvvmfx-cdi-starter](/examples/mvvmfx-cdi-starter)
+A simple example for this is available at [mvvmfx-cdi-starter](/examples/mvvmfx-cdi-starter).
-If you prefer Guice as a dependency injection framework you can use [mvvnfx-guice](/mvvmfx-parent/mvvmfx-guice)
\ No newline at end of file
+If you prefer Guice as dependency injection framework you can use [mvvnfx-guice](/mvvmfx-guice).
\ No newline at end of file
diff --git a/mvvmfx-cdi/pom.xml b/mvvmfx-cdi/pom.xml
index ead57bba2..bb78758c1 100644
--- a/mvvmfx-cdi/pom.xml
+++ b/mvvmfx-cdi/pom.xml
@@ -19,11 +19,11 @@
de.saxsys
- mvvmFX-parent
- 0.4.0
+ mvvmfx-parent
+ 1.0.0
- mvvmFX-cdi
+ mvvmfx-cdi
jar
mvvmFX cdi
@@ -32,16 +32,6 @@
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
-
- default-deploy
- deploy
-
-
-
maven-surefire-plugin
@@ -57,7 +47,7 @@
de.saxsys
- mvvmFX
+ mvvmfx
${project.parent.version}
provided
@@ -95,17 +85,6 @@
mockito-all
test
-
- org.powermock
- powermock-module-junit4
- test
-
-
-
- org.powermock
- powermock-api-mockito
- test
-
diff --git a/mvvmfx-guice/README.md b/mvvmfx-guice/README.md
index 719eddc5f..2ca3eed34 100644
--- a/mvvmfx-guice/README.md
+++ b/mvvmfx-guice/README.md
@@ -1,8 +1,9 @@
# MvvmFX Guice
-This Module is an extension for the [MvvmFX](https://github.com/sialcasa/mvvmFX) framework that adds support for Guice as a dependency injection framework.
+This module is an extension for the [MvvmFX](https://github.com/sialcasa/mvvmFX) framework that adds support for
+[Guice](https://github.com/google/guice) as dependency injection framework.
-It is base on [fx-guice](https://github.com/cathive/fx-guice).
+It is based on [fx-guice](https://github.com/cathive/fx-guice).
To create an application that is powered by Guice you have to extend `MvvmfxGuiceApplication`:
@@ -19,6 +20,6 @@ To create an application that is powered by Guice you have to extend `MvvmfxGuic
}
-A simple example for this is available at [mvvmfx-guice-starter](/examples/mvvmfx-guice-starter)
+A simple example for this is available at [mvvmfx-guice-starter](/examples/mvvmfx-guice-starter).
-If you prefer CDI as a dependency injection framework you can use [mvvnfx-cdi](/mvvmfx-parent/mvvmfx-cdi)
\ No newline at end of file
+If you prefer CDI as dependency injection framework you can use [mvvnfx-cdi](/mvvmfx-cdi).
\ No newline at end of file
diff --git a/mvvmfx-guice/pom.xml b/mvvmfx-guice/pom.xml
index fff11b17f..e87d60918 100644
--- a/mvvmfx-guice/pom.xml
+++ b/mvvmfx-guice/pom.xml
@@ -19,11 +19,11 @@
de.saxsys
- mvvmFX-parent
- 0.4.0
+ mvvmfx-parent
+ 1.0.0
- mvvmFX-guice
+ mvvmfx-guice
jar
mvvmFX Guice
This module contains extensions to use mvvmFX with Guice Dependency Injection
@@ -31,16 +31,6 @@
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
-
- default-deploy
- deploy
-
-
-
maven-surefire-plugin
@@ -54,7 +44,7 @@
de.saxsys
- mvvmFX
+ mvvmfx
${project.parent.version}
provided
@@ -63,7 +53,7 @@
com.cathive.fx
fx-guice
- 2.1.3
+ 8.0.0
@@ -83,17 +73,6 @@
mockito-all
test
-
- org.powermock
- powermock-module-junit4
- test
-
-
-
- org.powermock
- powermock-api-mockito
- test
-
diff --git a/mvvmfx-guice/src/test/java/de/saxsys/mvvmfx/guice/DuplicateInjectionBugTest.java b/mvvmfx-guice/src/test/java/de/saxsys/mvvmfx/guice/DuplicateInjectionBugTest.java
new file mode 100644
index 000000000..d3192083f
--- /dev/null
+++ b/mvvmfx-guice/src/test/java/de/saxsys/mvvmfx/guice/DuplicateInjectionBugTest.java
@@ -0,0 +1,68 @@
+package de.saxsys.mvvmfx.guice;
+
+import com.google.inject.Module;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.stage.Stage;
+import org.junit.Test;
+
+import javax.inject.Inject;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * This test is used to reproduce a bug in the mvvmfx-guice module.
+ * A class that is injected into the application is instantiated twice.
+ *
+ * see: issues 124
+ */
+public class DuplicateInjectionBugTest {
+
+
+ public static class A {
+ public static int counter = 0;
+
+ public A(){
+ counter++;
+ }
+ }
+
+ public static class B {
+ public static int counter = 0;
+
+ @Inject
+ private A a;
+
+ public B() {
+ counter++;
+ }
+ }
+
+ public static class MyApplication extends MvvmfxGuiceApplication {
+
+ @Inject
+ private B b;
+
+ @Override
+ public void startMvvmfx(Stage stage) throws Exception {
+ Platform.exit();
+ }
+
+ @Override
+ public void initGuiceModules(List modules) throws Exception {
+ }
+ }
+
+
+ @Test
+ public void test(){
+ B.counter = 0;
+ A.counter = 0;
+ Application.launch(MyApplication.class);
+
+ assertThat(B.counter).isEqualTo(1);
+ assertThat(A.counter).isEqualTo(1);
+ }
+
+}
diff --git a/mvvmfx/README.md b/mvvmfx/README.md
new file mode 100644
index 000000000..c3fe572ba
--- /dev/null
+++ b/mvvmfx/README.md
@@ -0,0 +1,8 @@
+# MvvmFX Core
+
+This module is the core of [MvvmFX](https://github.com/sialcasa/mvvmFX).
+
+It contains helper classes to implement the MVVM design pattern,
+load Views based on FXML or pure Java code
+and some additional helpers for some typical problems of UI development in JavaFX.
+
diff --git a/mvvmfx/pom.xml b/mvvmfx/pom.xml
index dab412744..c1f1049ee 100644
--- a/mvvmfx/pom.xml
+++ b/mvvmfx/pom.xml
@@ -19,11 +19,11 @@
de.saxsys
- mvvmFX-parent
- 0.4.0
+ mvvmfx-parent
+ 1.0.0
- mvvmFX
+ mvvmfx
jar
mvvmFX core
@@ -31,16 +31,6 @@
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
-
- default-deploy
- deploy
-
-
-
maven-javadoc-plugin
@@ -54,10 +44,6 @@
-
- commons-lang
- commons-lang
-
org.slf4j
slf4j-api
@@ -78,17 +64,6 @@
mockito-all
test
-
- org.powermock
- powermock-module-junit4
- test
-
-
-
- org.powermock
- powermock-api-mockito
- test
-
org.assertj
@@ -106,7 +81,7 @@
de.saxsys
jfx-testrunner
- 1.0
+ 1.1
test
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/internal/viewloader/FxmlViewLoader.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/internal/viewloader/FxmlViewLoader.java
index 814cdcd67..179b52f4c 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/internal/viewloader/FxmlViewLoader.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/internal/viewloader/FxmlViewLoader.java
@@ -61,11 +61,38 @@ public class FxmlViewLoader {
public , ViewModelType extends ViewModel> ViewTuple loadFxmlViewTuple(
Class extends ViewType> viewType, ResourceBundle resourceBundle, Object controller, Object root,
ViewModelType viewModel) {
- final String pathToFXML = "/" + viewType.getPackage().getName().replaceAll("\\.", "/") + "/"
- + viewType.getSimpleName() + ".fxml";
-
+ final String pathToFXML = createFxmlPath(viewType);
return loadFxmlViewTuple(pathToFXML, resourceBundle, controller, root, viewModel);
}
+
+ /**
+ * This method is used to create a String with the path to the FXML file for a given View class.
+ *
+ * This is done by taking the package of the view class (if any) and replace "." with "/".
+ * After that the Name of the class and the file ending ".fxml" is appended.
+ *
+ * Example: de.saxsys.myapp.ui.MainView as view class will be transformed to "/de/saxsys/myapp/ui/MainView.fxml"
+ *
+ * Example 2: MainView (located in the default package) will be transformed to "/MainView.fxml"
+ *
+ * @param viewType the view class type.
+ * @return the path to the fxml file as string.
+ */
+ private String createFxmlPath(Class> viewType){
+ final StringBuilder pathBuilder = new StringBuilder();
+
+ pathBuilder.append("/");
+
+ if(viewType.getPackage() != null){
+ pathBuilder.append(viewType.getPackage().getName().replaceAll("\\.","/"));
+ pathBuilder.append("/");
+ }
+
+ pathBuilder.append(viewType.getSimpleName());
+ pathBuilder.append(".fxml");
+
+ return pathBuilder.toString();
+ }
/**
* Load the viewTuple by the path of the fxml file.
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 e344c88bc..11faa8592 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
@@ -36,26 +36,26 @@ class DefaultNotificationCenter implements NotificationCenter {
private final Map> observersForName = new HashMap>();
@Override
- public void addObserverForName(String name, NotificationObserver observer) {
- List observers = this.observersForName.get(name);
+ public void subscribe(String messageName, NotificationObserver observer) {
+ List observers = this.observersForName.get(messageName);
if (observers == null) {
- this.observersForName.put(name, new ArrayList());
+ this.observersForName.put(messageName, new ArrayList());
}
- observers = this.observersForName.get(name);
+ observers = this.observersForName.get(messageName);
observers.add(observer);
}
@Override
- public void removeObserverForName(String name, NotificationObserver observer) {
- List observers = this.observersForName.get(name);
+ public void unsubscribe(String messageName, NotificationObserver observer) {
+ List observers = this.observersForName.get(messageName);
observers.remove(observer);
if (observers.size() == 0) {
- this.observersForName.remove(name);
+ this.observersForName.remove(messageName);
}
}
@Override
- public void removeObserver(NotificationObserver observer) {
+ public void unsubscribe(NotificationObserver observer) {
Iterator iterator = this.observersForName.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
@@ -71,11 +71,11 @@ public void removeObserver(NotificationObserver observer) {
}
@Override
- public void postNotification(String name, Object... objects) {
- Collection notificationReceivers = observersForName.get(name);
+ public void publish(String messageName, Object... payload) {
+ Collection notificationReceivers = observersForName.get(messageName);
if (notificationReceivers != null) {
for (NotificationObserver observer : notificationReceivers) {
- observer.receivedNotification(name, objects);
+ observer.receivedNotification(messageName, payload);
}
}
}
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 e11a17ee9..a8ee42a86 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
@@ -30,45 +30,45 @@ public interface NotificationCenter {
/**
- * Add an observer to the @MVVMNotificationCenter which gets notifications for the given @String.
+ * Add an observer to the NotificationCenter which gets notifications for the given String.
*
- * @param name
+ * @param messageName
* key of the notification to listen
* @param observer
* which listens for the notification
*/
- public abstract void addObserverForName(String name,
- NotificationObserver observer);
+ void subscribe(String messageName,
+ NotificationObserver observer);
/**
- * Removes an observer from the @MVVMNotificationCenter.
+ * Removes an observer from the NotificationCenter.
*
- * @param name
+ * @param messageName
* key of the notification to remove
* @param observer
* which listens for the notification
*/
- public abstract void removeObserverForName(String name,
- NotificationObserver observer);
+ void unsubscribe(String messageName,
+ NotificationObserver observer);
/**
- * Remove all registrations of an @MVVMNotificationObserver.
+ * Remove all registrations of an NotificationObserver.
*
* @param observer
* for remove all notifications
*/
- public abstract void removeObserver(NotificationObserver observer);
+ void unsubscribe(NotificationObserver observer);
/**
- * Post a notification to all @MVVMNotificationObserver which are registered with the given @String. You can pass
+ * Post a notification to all NotificationObserver which are registered with the given String.
+ *
+ * You can additionally add a varying number of Objects as a payload that the observer will receive.
*
- * {@code Object[]}.
- *
- * @param name
+ * @param messageName
* of the notification which sould be send
- * @param objects
+ * @param payload
* which should be passed
*/
- public abstract void postNotification(String name, Object... objects);
+ void publish(String messageName, Object... payload);
}
diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationObserver.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationObserver.java
index 809f3e926..6aa4963ac 100644
--- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationObserver.java
+++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationObserver.java
@@ -21,14 +21,15 @@
* @author sialcasa
*
*/
+@FunctionalInterface
public interface NotificationObserver {
/**
- * Handle the Notification which is passed by the @MVVMNotificationCenter. An @Object[] could be shipped.
+ * Handle the Notification which is passed by the NotificationCenter. An @Object[] could be shipped.
*
* @param key
* notification name
- * @param objects
+ * @param payload
* which are passed
*/
- public void receivedNotification(String key, Object... objects);
+ public void receivedNotification(String key, Object... payload);
}
diff --git a/mvvmfx/src/test/java/FxmlViewInDefaultPackage.java b/mvvmfx/src/test/java/FxmlViewInDefaultPackage.java
new file mode 100644
index 000000000..872155833
--- /dev/null
+++ b/mvvmfx/src/test/java/FxmlViewInDefaultPackage.java
@@ -0,0 +1,11 @@
+import de.saxsys.mvvmfx.FxmlView;
+import de.saxsys.mvvmfx.internal.viewloader.example.TestViewModel;
+
+/**
+ * The purpose of this class is to reproduce Bug no. 154 (https://github.com/sialcasa/mvvmFX/issues/156).
+ *
+ * The problem is that FxmlView's that are located in the default package can't be loaded properly. Instead a
+ * NullPointerException was thrown.
+ */
+public class FxmlViewInDefaultPackage implements FxmlView {
+}
diff --git a/mvvmfx/src/test/java/FxmlViewinDefaultPackageTest.java b/mvvmfx/src/test/java/FxmlViewinDefaultPackageTest.java
new file mode 100644
index 000000000..0d4bb62e2
--- /dev/null
+++ b/mvvmfx/src/test/java/FxmlViewinDefaultPackageTest.java
@@ -0,0 +1,29 @@
+import de.saxsys.javafx.test.JfxRunner;
+import de.saxsys.mvvmfx.FluentViewLoader;
+import de.saxsys.mvvmfx.ViewTuple;
+import de.saxsys.mvvmfx.internal.viewloader.example.TestViewModel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * This test reproduces the bug no 154 (https://github.com/sialcasa/mvvmFX/issues/156).
+ *
+ * A FxmlView located in the default package couldn't be loaded because a NullPointerException was thrown.
+ */
+@RunWith(JfxRunner.class)
+public class FxmlViewinDefaultPackageTest {
+
+
+ @Test
+ public void test(){
+
+ ViewTuple viewTuple = FluentViewLoader
+ .fxmlView(FxmlViewInDefaultPackage.class).load();
+
+ assertThat(viewTuple).isNotNull();
+ assertThat(viewTuple.getView()).isNotNull();
+ }
+
+}
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 626d2f85c..3a352632f 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
@@ -42,35 +42,35 @@ public void init() {
@Test
public void addObserverToDefaultNotificationCenterAndPostNotification() throws Exception {
- defaultCenter.addObserverForName(TEST_NOTIFICATION, observer1);
- defaultCenter.postNotification(TEST_NOTIFICATION);
+ defaultCenter.subscribe(TEST_NOTIFICATION, observer1);
+ defaultCenter.publish(TEST_NOTIFICATION);
Mockito.verify(observer1).receivedNotification(TEST_NOTIFICATION);
}
@Test
public void addObserverToDefaultNotificationCenterAndPostObjectNotification() throws Exception {
- defaultCenter.addObserverForName(TEST_NOTIFICATION, observer1);
- defaultCenter.postNotification(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION);
+ defaultCenter.subscribe(TEST_NOTIFICATION, observer1);
+ defaultCenter.publish(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION);
Mockito.verify(observer1).receivedNotification(TEST_NOTIFICATION, OBJECT_ARRAY_FOR_NOTIFICATION);
}
@Test
public void addAndRemoveObserverToDefaultNotificationCenterAndPostNotification() throws Exception {
- defaultCenter.addObserverForName(TEST_NOTIFICATION, observer1);
- defaultCenter.addObserverForName(TEST_NOTIFICATION, observer2);
- defaultCenter.addObserverForName(TEST_NOTIFICATION, observer3);
- defaultCenter.removeObserver(observer1);
- defaultCenter.postNotification(TEST_NOTIFICATION);
+ defaultCenter.subscribe(TEST_NOTIFICATION, observer1);
+ defaultCenter.subscribe(TEST_NOTIFICATION, observer2);
+ defaultCenter.subscribe(TEST_NOTIFICATION, observer3);
+ defaultCenter.unsubscribe(observer1);
+ defaultCenter.publish(TEST_NOTIFICATION);
Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION);
}
@Test
public void addObserversToDefaultNotificationCenterAndPostNotification() throws Exception {
- defaultCenter.addObserverForName(TEST_NOTIFICATION, observer1);
- defaultCenter.addObserverForName(TEST_NOTIFICATION_2, observer2);
- defaultCenter.addObserverForName(TEST_NOTIFICATION, observer3);
+ defaultCenter.subscribe(TEST_NOTIFICATION, observer1);
+ defaultCenter.subscribe(TEST_NOTIFICATION_2, observer2);
+ defaultCenter.subscribe(TEST_NOTIFICATION, observer3);
- defaultCenter.postNotification(TEST_NOTIFICATION);
+ defaultCenter.publish(TEST_NOTIFICATION);
Mockito.verify(observer1, Mockito.only()).receivedNotification(TEST_NOTIFICATION);
Mockito.verify(observer2, Mockito.never()).receivedNotification(TEST_NOTIFICATION_2);
Mockito.verify(observer3, Mockito.only()).receivedNotification(TEST_NOTIFICATION);
@@ -78,15 +78,15 @@ public void addObserversToDefaultNotificationCenterAndPostNotification() throws
@Test
public void addAndRemoveObserverForNameToDefaultNotificationCenterAndPostNotification() throws Exception {
- defaultCenter.addObserverForName(TEST_NOTIFICATION, observer1);
- defaultCenter.removeObserverForName(TEST_NOTIFICATION, observer1);
- defaultCenter.postNotification(TEST_NOTIFICATION);
+ defaultCenter.subscribe(TEST_NOTIFICATION, observer1);
+ defaultCenter.unsubscribe(TEST_NOTIFICATION, observer1);
+ defaultCenter.publish(TEST_NOTIFICATION);
Mockito.verify(observer1, Mockito.never()).receivedNotification(TEST_NOTIFICATION);
}
private class DummyNotificationObserver implements NotificationObserver {
@Override
- public void receivedNotification(String key, Object... objects) {
+ public void receivedNotification(String key, Object... payload) {
}
}
diff --git a/mvvmfx/src/test/resources/FxmlViewInDefaultPackage.fxml b/mvvmfx/src/test/resources/FxmlViewInDefaultPackage.fxml
new file mode 100644
index 000000000..e44da6667
--- /dev/null
+++ b/mvvmfx/src/test/resources/FxmlViewInDefaultPackage.fxml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index a6c46191b..810a1bf1d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,9 +24,9 @@
de.saxsys
- mvvmFX-parent
+ mvvmfx-parent
pom
- 0.4.0
+ 1.0.0
mvvmFX parent
Application Framework for MVVM with JavaFX.
http://www.saxsys.de
@@ -84,11 +84,6 @@
-
- commons-lang
- commons-lang
- 2.6
-
org.slf4j
slf4j-api
@@ -97,57 +92,36 @@
org.slf4j
slf4j-simple
- 1.7.6
+ 1.7.9
net.jodah
typetools
- 0.3.1
+ 0.4.0
junit
junit
- 4.11
+ 4.12
org.mockito
mockito-all
- 1.9.5
-
-
- org.powermock
- powermock-module-junit4
- 1.5.1
-
-
-
- org.powermock
- powermock-api-mockito
- 1.5.1
+ 1.10.19
org.assertj
assertj-core
- 1.6.0
+ 1.7.1
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
-
- default-deploy
- deploy
-
-
-
org.apache.maven.plugins
maven-javadoc-plugin
@@ -197,7 +171,7 @@
- clean-deploy
+ deploy-release