package regexgolf2.controllers; import java.io.IOException; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.scene.Parent; import javafx.util.Duration; import javax.swing.JOptionPane; import regexgolf2.model.Word; import regexgolf2.model.containers.ContainerChangedEvent; import regexgolf2.model.containers.WordPool; import regexgolf2.services.persistence.PersistenceException; import regexgolf2.services.persistence.PersistenceService; import regexgolf2.ui.wordrepository.WordRepositoryUI; import regexgolf2.ui.wordrepository.wordcell.WordItem; import com.google.java.contract.Ensures; import com.google.java.contract.Requires; public class WordRepositoryController { private final WordRepositoryUI _ui; private final WordPool _pool; private final PersistenceService _persistenceService; private final ChangeListener<Boolean> _outOfSynchListener; public WordRepositoryController(PersistenceService ps) throws IOException { _ui = new WordRepositoryUI(); _persistenceService = ps; _pool = _persistenceService.getWordPool(); _outOfSynchListener = createOutOfSynchListener(); // Disable Remove Button if no Item is selected _ui.getRemoveButton().disableProperty() .bind(_ui.getListView().getSelectionModel().selectedItemProperty().isNull()); // Initialize Button Handlers _ui.getAddButton().setOnAction(e -> onAddButtonClicked()); _ui.getRemoveButton().setOnAction(e -> onRemoveButtonClicked()); _ui.getSaveButton().setOnAction(e -> onSaveButtonClicked()); // Refresh UI-ItemList if pool changes _pool.addListener(e -> refreshListViewItemList(e)); // Load Items _pool.forEach(word -> addItem(word)); } private ChangeListener<Boolean> createOutOfSynchListener() { return new ChangeListener<Boolean>() { private int amountOutOfSynch = 0; @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { if (newValue) amountOutOfSynch++; else amountOutOfSynch--; _ui.getSaveButton().setDisable(amountOutOfSynch != 0); } }; } private void onAddButtonClicked() { Word newWord = _pool.getEmpty(); final WordItem item = getItem(newWord); _ui.getListView().scrollTo(item); /* * Evil hack because edit mode wouldn't start without it if the item * that should be edited is not scrolled into view already. see: * https://stackoverflow * .com/questions/11997041/listview-edit-is-not-switching * -cell-to-input-state */ new Timeline(new KeyFrame(Duration.seconds(0.01), e -> _ui.getListView().edit( _ui.getListView().getItems().indexOf(item)))).play(); } private void onRemoveButtonClicked() { Word selectedWord = _ui.getListView().getSelectionModel().getSelectedItem().getWord(); _pool.remove(selectedWord); } private void onSaveButtonClicked() { try { _persistenceService.save(_pool); } catch (PersistenceException e) { // TODO use fancy dialog here JOptionPane.showMessageDialog(null, "DB Error"); } } private void refreshListViewItemList(ContainerChangedEvent<? extends Word> e) { if (e.getAddedItem() != null) addItem(e.getAddedItem()); if (e.getRemovedItem() != null) removeItemFor(e.getRemovedItem()); } /** * Creates a new Item with the given word and adds it to the UI. The created * Item is returned. */ private WordItem addItem(Word word) { WordItem item = new WordItem(word, _persistenceService.getPersistenceInformation().getPersistenceState(word)); item.isOutOfSynchPropery().addListener(_outOfSynchListener); _ui.getListView().getItems().add(item); return item; } private void removeItemFor(Word word) { _ui.getListView().getItems().stream() .filter(item -> item.getWord().equals(word)).findFirst() .ifPresent(item -> { _ui.getListView().getItems().remove(item); item.isOutOfSynchPropery().removeListener(_outOfSynchListener); item.discard(); }); } @Requires( { "word != null", "_pool.contains(word)" }) @Ensures("result != null") private WordItem getItem(Word word) { for (WordItem item : _ui.getListView().getItems()) { if (item.getWord().equals(word)) { _ui.getListView().getSelectionModel().select(item); return item; } } throw new IllegalArgumentException("An item for '" + word + "' could not be found."); } public Parent getUINode() { return _ui.getUINode(); } }