All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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