de.rpgframework.jfx.pane.AChoiceSelectorDialog Maven / Gradle / Ivy
package de.rpgframework.jfx.pane;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.prelle.javafx.CloseType;
import org.prelle.javafx.FlexibleApplication;
import org.prelle.javafx.JavaFXConstants;
import org.prelle.javafx.ManagedDialog;
import org.prelle.javafx.NavigButtonControl;
import org.prelle.javafx.OptionalNodePane;
import de.rpgframework.genericrpg.Possible;
import de.rpgframework.genericrpg.ToDoElement;
import de.rpgframework.genericrpg.ToDoElement.Severity;
import de.rpgframework.genericrpg.chargen.ComplexDataItemController;
import de.rpgframework.genericrpg.data.Choice;
import de.rpgframework.genericrpg.data.ComplexDataItem;
import de.rpgframework.genericrpg.data.ComplexDataItemValue;
import de.rpgframework.genericrpg.data.DataItemValue;
import de.rpgframework.genericrpg.data.Decision;
import de.rpgframework.genericrpg.data.Lifeform;
import de.rpgframework.genericrpg.items.CarryMode;
import de.rpgframework.genericrpg.items.Hook;
import de.rpgframework.genericrpg.items.ItemFlag;
import de.rpgframework.genericrpg.items.PieceOfGear;
import de.rpgframework.genericrpg.items.PieceOfGearVariant;
import de.rpgframework.jfx.ADescriptionPane;
import de.rpgframework.jfx.GenericDescriptionVBox;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter;
import lombok.Builder;
@Builder(setterPrefix = "set")
public class AChoiceSelectorDialog> extends ManagedDialog implements BiFunction, Decision[]> {
private final static Logger logger = System.getLogger(AChoiceSelectorDialog.class.getPackageName());
private final static Choice VARIANT_CHOICE = new Choice(PieceOfGear.VARIANT, null);
public static interface ChoiceSelectorCustomizer {
Node processChoice(T item, Choice choice, Map decisions, Consumer updateButtons);
}
protected ComplexDataItemController controller;
protected CarryMode carry;
protected T item;
protected Hook hook;
protected Lifeform,?,?> model;
protected DataItemValue> context;
protected List suggestions = new ArrayList<>();
protected List fixedDecisions = new ArrayList<>();
protected ChoiceSelectorCustomizer customizer;
protected BiFunction selectionVerifier;
protected BiFunction variantNameGetter;
protected PieceOfGearVariant suggestedVariant;
@Builder.Default
private transient Map decisions = new LinkedHashMap<>();
@Builder.Default
private transient List selectedFlasgs = new ArrayList<>();
private PieceOfGearVariant selectedVariant;
@Builder.Default
private Map> perVariantChoices = new HashMap<>();
private transient boolean canBeLeftWithOK;
private transient OptionalNodePane optional;
@Builder.Default
private transient ADescriptionPane descriptionNode = new GenericDescriptionVBox(null, null);
private transient VBox content;
private transient Label lbProblem;
private transient NavigButtonControl btnCtrl;
//-------------------------------------------------------------------
public String getTitle(T item) {
// ResourceI18N.format(RES, "title", item.getName())
return "Select for "+item.getName();
}
//-------------------------------------------------------------------
public String getExplainString(T item) {
// ResourceI18N.get(RES, "explain")
return "Configure your selection";
}
//-------------------------------------------------------------------
public String getVariantTitle(PieceOfGear item) {
// ResourceI18N.get(RES, "label.variant")
return "Variant";
}
//-------------------------------------------------------------------
public String getRegularVersionTitle(PieceOfGear item) {
// ResourceI18N.get(RES, "variant.regular")
return "Regular";
}
//-------------------------------------------------------------------
public String getForcedChoiceTitle(T item, Choice choice) {
// String forceTitle = null;
// if (choice.getUUID().equals(ItemTemplate.UUID_RATING)) forceTitle=ResourceI18N.get(RES, "label.rating");
// if (choice.getUUID().equals(ItemTemplate.UUID_CHEMICAL_CHOICE)) forceTitle=ResourceI18N.get(RES, "label.chemical");
// if (choice.getI18nKey()!=null) forceTitle=null;
return "Make some choices";
}
//-------------------------------------------------------------------
public String getForcedVariantChoiceTitle(PieceOfGearVariant> variant, Choice choice) {
// String forceTitle = null;
// if (choice.getUUID().equals(ItemTemplate.UUID_RATING)) forceTitle=ResourceI18N.get(RES, "label.rating");
// if (choice.getUUID().equals(ItemTemplate.UUID_CHEMICAL_CHOICE)) forceTitle=ResourceI18N.get(RES, "label.chemical");
return null;
}
//-------------------------------------------------------------------
/**
* @see java.util.function.BiFunction#apply(java.lang.Object, java.lang.Object)
*/
@Override
public Decision[] apply(T item, List choices) {
logger.log(Level.INFO, "ENTER apply({0}, {1})", item, choices);
this.item = item;
// decisions = new LinkedHashMap<>();
// bxDesc = new GenericDescriptionVBox<>(null, null);
content = new VBox(5);
optional= new OptionalNodePane(content, descriptionNode);
lbProblem = new Label();
lbProblem.setStyle("-fx-text-fill: -fx-accent");
this.buttons.setAll(CloseType.OK, CloseType.CANCEL);
for (CloseType type : buttons) {
buttonDisabledProperty().put(type, Boolean.FALSE);
}
setContent(new VBox(10,optional, lbProblem));
CloseType closed = null;
try {
setTitle(getTitle());
descriptionNode.setData(item);
content.getChildren().clear();
// Minimal intro text
Label explain = new Label(getExplainString(item));
explain.setWrapText(true);
content.getChildren().add(explain);
// Eventually prepare variants
if ((item instanceof PieceOfGear) && !((PieceOfGear)item).getVariants().isEmpty()) {
processVariants( (PieceOfGear)item );
}
// // Eventually prepare hardcoded rating
// if (item.hasLevel() && !(item instanceof Quality)) {
// processRating( item );
// }
for (Choice choice : choices) {
logger.log(Level.WARNING, "Found choice {0} and controller {1}", choice, controller);
String forceTitle = getForcedChoiceTitle(item, choice);
List toAdd = processChoice(item,choice, forceTitle);
if (toAdd!=null) content.getChildren().addAll(toAdd);
}
// if (item instanceof PieceOfGear) {
// for (ItemFlag flag : item.getUserSelectableFlags(SR6ItemFlag.class)) {
// processFlag((PieceOfGear) item, flag);
// }
// }
btnCtrl = new NavigButtonControl();
// btnCtrl.setCallback( (close) -> isButtonEnabled(close));
btnCtrl.initialize(FlexibleApplication.getInstance(), this);
// btnCtrl.setDisabled(CloseType.OK, true);
// this.buttonDisabledProperty().put(CloseType.OK, true);
updateButtons();
logger.log(Level.ERROR, "showAlertAndCall with btnCtrl="+btnCtrl);
closed = FlexibleApplication.getInstance().showAlertAndCall(this, btnCtrl);
logger.log(Level.ERROR, "Closed with "+closed);
if (closed==CloseType.CANCEL)
return null;
return getDecisions();
} finally {
logger.log(Level.INFO, "LEAVE apply({0}, {1} with {2})", item, choices, closed);
}
}
//-------------------------------------------------------------------
private Decision[] getDecisions() {
Decision[] ret = new Decision[decisions.size()];
// if (item.hasLevel() && selectedRating!=null)
// ret = new Decision[decisions.size()+1];
int i=0;
for (Entry entry : decisions.entrySet()) {
ret[i] = entry.getValue();
logger.log(Level.DEBUG, "Decision [{0}] = {1}", i, entry.getValue());
i++;
}
// if (item.hasLevel() && selectedRating!=null)
// ret[i] = new Decision(RATING_CHOICE, String.valueOf(selectedRating));
return ret;
}
//-------------------------------------------------------------------
private void updateButtons() {
logger.log(Level.INFO, "updateButtons");
Possible possible = null;
// Special handling for gear
if (selectionVerifier!=null) {
possible = selectionVerifier.apply(item, getDecisions());
} else {
possible = controller.canBeSelected(item, getDecisions() );
}
// Set status
ToDoElement problem = possible.getMostSevere();
if (problem==null) {
lbProblem.setText(null);
} else {
lbProblem.setText(problem.getMessage(Locale.getDefault()));
switch (problem.getSeverity()) {
case STOPPER: lbProblem.setStyle("-fx-text-fill: -fx-accent"); break;
case WARNING: lbProblem.setStyle("-fx-text-fill: primary"); break;
case INFO : lbProblem.setStyle("-fx-text-fill: -fx-text-base-color"); break;
}
}
logger.log(Level.INFO, "Item selection possible=={0} btnCtrl={1}",possible,btnCtrl);
if (btnCtrl != null) {
if (!possible.getRequireDecisions() || (problem != null && problem.getSeverity() != Severity.INFO)) {
logger.log(Level.DEBUG, " disable OK");
canBeLeftWithOK = false;
btnCtrl.setDisabled(CloseType.OK, true);
this.buttonDisabledProperty().put(CloseType.OK, true);
} else {
logger.log(Level.DEBUG, " enable OK ");
canBeLeftWithOK = true;
btnCtrl.setDisabled(CloseType.OK, false);
this.buttonDisabledProperty().put(CloseType.OK, false);
}
} else {
canBeLeftWithOK = possible.get();
if (btnCtrl!=null)
btnCtrl.setDisabled(CloseType.OK, !canBeLeftWithOK);
this.buttonDisabledProperty().put(CloseType.OK, !canBeLeftWithOK);
}
}
// -------------------------------------------------------------------
private void processVariants(PieceOfGear template) {
logger.log(Level.INFO, "variants detected");
addLabel(getVariantTitle(template));
ChoiceBox cbVariants = new ChoiceBox<>();
// If no item is required, add a "regular item"
if (!template.requiresVariant()) {
cbVariants.getItems().add(null);
}
cbVariants.getItems().addAll(template.getVariants());
cbVariants.setConverter(new StringConverter() {
public PieceOfGearVariant fromString(String value) { return null;}
public String toString(PieceOfGearVariant value) {
if (value==null) return getRegularVersionTitle(template);
String name = template.getVariantName(value, Locale.getDefault());
if (name.startsWith(template.getTypeString()) && variantNameGetter!=null) {
name = variantNameGetter.apply(item, value);
}
return name;
}
});
cbVariants.getSelectionModel().selectedItemProperty().addListener( (ov,o,n) -> {
logger.log(Level.INFO, "Chose variant {0}", n);
selectedVariant = n;
if (n==null)
decisions.remove(VARIANT_CHOICE);
else
decisions.put(VARIANT_CHOICE, new Decision(PieceOfGear.VARIANT,n.getId()));
// // Hide old variant nodes
// if (perVariantChoices.containsKey(o)) {
// logger.log(Level.DEBUG, "Hide all UI elements for old variant {0}", o);
// for (Node node : perVariantChoices.get(o)) {
// node.setVisible(false);
// node.setManaged(false);
// if (node instanceof ChoiceBox) ((ChoiceBox)node).getSelectionModel().clearSelection();
// }
// }
// // Show new variant nodes
// if (perVariantChoices.containsKey(n)) {
// logger.log(Level.DEBUG, "Show all UI elements for selected variant {0}", o);
// for (Node node : perVariantChoices.get(n)) {
// node.setVisible(true);
// node.setManaged(true);
// }
// }
updateButtons();
});
content.getChildren().add(cbVariants);
// Make a list of choices that only exists in a variant
for (PieceOfGearVariant variant : (Collection)template.getVariants()) {
if (variant.getChoices()!=null && !variant.getChoices().isEmpty()) {
List allVariantNodes = new ArrayList<>();
// Prepare UI components
for (Choice choice : variant.getChoices()) {
String forceTitle = getForcedVariantChoiceTitle(variant, choice);
List list = processChoice(item,choice, forceTitle);
logger.log(Level.INFO, "Variant choice returned "+list);
allVariantNodes.addAll(list);
}
perVariantChoices.put(variant, allVariantNodes);
// Per default hide all variant nodes
for (Node node : allVariantNodes) {
node.setVisible(false);
node.setManaged(false);
}
}
}
if (suggestedVariant!=null) {
selectedVariant = suggestedVariant;
cbVariants.getSelectionModel().select(suggestedVariant);
} else {
cbVariants.getSelectionModel().select(0);
}
updateButtons();
}
// -------------------------------------------------------------------
private void processFlag(PieceOfGear item, ItemFlag flag) {
logger.log(Level.DEBUG, "Flag "+flag);
System.err.println("ChoiceSelectorDialog: Flag "+flag);
CheckBox checkBox = new CheckBox(flag.getName());
checkBox.selectedProperty().addListener( (ov,o,n) -> {
if (n) {
logger.log(Level.DEBUG, "Selected flag {0}", n);
selectedFlasgs.add(flag);
} else {
logger.log(Level.DEBUG, "Deselected flag {0} again", n);
selectedFlasgs.remove(flag);
}
updateButtons();
});
content.getChildren().add(checkBox);
}
//-------------------------------------------------------------------
private Label addLabel(String title) {
Label lbName = new Label(title);
lbName.getStyleClass().add(JavaFXConstants.STYLE_HEADING5);
return lbName;
}
// -------------------------------------------------------------------
private List processChoice(T item, Choice choice, String forceTitle) {
logger.log(Level.DEBUG, "Choice " + choice);
List ret = new ArrayList<>();
Label label = addLabel(
(forceTitle==null)
?
item.getChoiceName(choice, Locale.getDefault())
:
forceTitle);
ret.add(label);
Node nodeToAdd = (customizer!=null)?customizer.processChoice(item, choice, decisions, (c) -> updateButtons()):null;
if (nodeToAdd!=null) {
ret.add(nodeToAdd);
} else {
logger.log(Level.ERROR, "No UI node to add for choice {0}", choice);
}
return ret;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy