package de.saring.sportstracker.gui.dialogs;
import java.time.LocalTime;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Control;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.stage.Window;
import javafx.util.converter.NumberStringConverter;
import javax.inject.Inject;
import org.controlsfx.validation.ValidationResult;
import org.controlsfx.validation.Validator;
import de.saring.sportstracker.data.Weight;
import de.saring.sportstracker.gui.STContext;
import de.saring.sportstracker.gui.STDocument;
import de.saring.util.ValidationUtils;
import de.saring.util.gui.javafx.TimeToStringConverter;
/**
* Controller (MVC) class of the Weight dialog for editing / adding Weight entries.
*
* @author Stefan Saring
*/
public class WeightDialogController extends AbstractDialogController {
private final STDocument document;
@FXML
private DatePicker dpDate;
@FXML
private TextField tfTime;
@FXML
private TextField tfValue;
@FXML
private Label laWeightUnit;
@FXML
private TextArea taComment;
/** ViewModel of the edited Weight. */
private WeightViewModel weightViewModel;
/**
* Standard c'tor for dependency injection.
*
* @param context the SportsTracker UI context
* @param document the SportsTracker model/document
*/
@Inject
public WeightDialogController(final STContext context, final STDocument document) {
super(context);
this.document = document;
}
/**
* Displays the Weight dialog for the passed Weight instance.
*
* @param parent parent window of the dialog
* @param weight Weight to be edited
*/
public void show(final Window parent, final Weight weight) {
this.weightViewModel = new WeightViewModel(weight, document.getOptions().getUnitSystem());
final boolean newWeight = document.getWeightList().getByID(weight.getId()) == null;
final String dlgTitleKey = newWeight ? "st.dlg.weight.title.add" : "st.dlg.weight.title";
final String dlgTitle = context.getResources().getString(dlgTitleKey);
showEditDialog("/fxml/dialogs/WeightDialog.fxml", parent, dlgTitle);
}
@Override
protected void setupDialogControls() {
laWeightUnit.setText(context.getFormatUtils().getWeightUnitName());
// setup binding between view model and the UI controls
dpDate.valueProperty().bindBidirectional(weightViewModel.date);
// use text formatter for time values => makes sure that the value is also valid
final TextFormatter<LocalTime> timeTextFormatter = new TextFormatter<>(new TimeToStringConverter());
timeTextFormatter.valueProperty().bindBidirectional(weightViewModel.time);
tfTime.setTextFormatter(timeTextFormatter);
tfValue.textProperty().bindBidirectional(weightViewModel.value, new NumberStringConverter());
taComment.textProperty().bindBidirectional(weightViewModel.comment);
// setup validation of the UI controls
// => due to a ControlsFX bug the validation setup must be executed after the dialog has been shown
// (see https://bitbucket.org/controlsfx/controlsfx/issues/539/multiple-dialog-fields-with-validation )
Platform.runLater(() -> {
validationSupport.registerValidator(dpDate,
Validator.createEmptyValidator(context.getResources().getString("st.dlg.weight.error.date")));
validationSupport.registerValidator(tfTime, //
Validator.createEmptyValidator(context.getResources().getString("st.dlg.weight.error.time")));
validationSupport.registerValidator(tfValue, true, (Control control, String newValue) -> ValidationResult
.fromErrorIf(tfValue, context.getResources().getString("st.dlg.weight.error.weight"),
!ValidationUtils.isValueDoubleBetween(newValue, 0.1d, 1000)));
});
}
@Override
protected boolean validateAndStore() {
// store the new Weight, no further validation needed
final Weight newWeight = weightViewModel.getWeight();
document.getWeightList().set(newWeight);
return true;
}
}