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

de.rpgframework.jfx.RPGFrameworkJavaFX Maven / Gradle / Ivy

package de.rpgframework.jfx;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

import org.prelle.javafx.CloseType;
import org.prelle.javafx.FlexibleApplication;
import org.prelle.javafx.JavaFXConstants;

import de.rpgframework.ResourceI18N;
import de.rpgframework.genericrpg.chargen.PartialController;
import de.rpgframework.genericrpg.data.Choice;
import de.rpgframework.genericrpg.data.ChoiceOrigin;
import de.rpgframework.genericrpg.data.ComplexDataItem;
import de.rpgframework.genericrpg.data.ComplexDataItemValue;
import de.rpgframework.genericrpg.data.DataItem;
import de.rpgframework.genericrpg.data.Decision;
import de.rpgframework.genericrpg.data.DecisionContainer;
import de.rpgframework.genericrpg.data.GenericRPGTools;
import de.rpgframework.genericrpg.data.PageReference;
import de.rpgframework.genericrpg.modification.DataItemModification;
import de.rpgframework.genericrpg.modification.Modification;
import de.rpgframework.genericrpg.modification.ModificationChoice;
import de.rpgframework.genericrpg.requirements.Requirement;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;

public class RPGFrameworkJavaFX {

	public final static Logger logger = System.getLogger(RPGFrameworkJFXConstants.BASE_LOGGER_NAME);

	private final static URL STYLE_URL = RPGFrameworkJavaFX.class.getResource("css/rpgframework.css");
	private final static String STYLE  = STYLE_URL.toString();

	//-------------------------------------------------------------------
	public static void assignStylesheet(Scene scene) {
		if (!scene.getStylesheets().contains(STYLE)) {
			scene.getStylesheets().add(STYLE);
		}
	}

	//-------------------------------------------------------------------
	public static void parseMarkupAndFillTextFlow(TextFlow flow, String text) {
		flow.getChildren().clear();
		String toParse = ""+text+"";

		try {
			InputStream  in = new ByteArrayInputStream(toParse.getBytes("UTF-8"));
			XMLInputFactory factory = XMLInputFactory.newInstance();
			XMLStreamReader parser  = factory.createXMLStreamReader( in );

			StringBuffer buf = new StringBuffer();
			boolean em = false;
			boolean i = false;
			boolean b = false;
			while ( parser.hasNext() ) {
				switch ( parser.getEventType() )
				{
				case XMLStreamConstants.START_DOCUMENT:
					break;

				case XMLStreamConstants.END_DOCUMENT:
					parser.close();
					break;

				case XMLStreamConstants.NAMESPACE:
					System.out.println( "NAMESPACE: " + parser.getNamespaceURI() );
					break;

				case XMLStreamConstants.START_ELEMENT:
					if (buf.length()>0) {
						Text textblk = new Text(buf.toString());
						if (!buf.toString().endsWith("\n")) textblk.setText(buf.toString()+" ");
						flow.getChildren().add(textblk);
						StringBuffer style = new StringBuffer("-fx-fill: -fx-text-background-color; -fx-text-alignment: justify;");
						if (b && !em) {
							textblk.setFont(Font.font("Segoe UI Bold", FontWeight.NORMAL, -1));
							textblk.getStyleClass().add(JavaFXConstants.STYLE_HEADING5);
						} else if (em && !b) {
							textblk.setFont(Font.font("Segoe UI Italic", FontWeight.NORMAL, -1));
							textblk.getStyleClass().add("emphasize");
						} else if (em && b) {
							textblk.getStyleClass().addAll("emphasize",JavaFXConstants.STYLE_HEADING5);
//							style.append(" -fx-font-family: 'Segoe UI Bold Italic';");
							textblk.setFont(Font.font("Segoe UI Bold Italic", FontWeight.NORMAL, -1));
						}
						textblk.setStyle(style.toString());
					}
					buf = new StringBuffer();
					switch (parser.getLocalName()) {
					case "text": break;
					case "br":
						buf.append("\n");
						break;
					case "em":
						em = true;break;
					case "i":
						i = true;break;
					case "b":
						b = true;break;
					default:
						logger.log(Level.WARNING, "Unsupported START markup: "+parser.getLocalName());
					}
					break;

				case XMLStreamConstants.CHARACTERS:
					if ( ! parser.isWhiteSpace() )
						buf.append(parser.getText().trim());
					break;

				case XMLStreamConstants.END_ELEMENT:
					if (buf.length()>0) {
						Text textblk = new Text(buf.toString());
						if (!buf.toString().endsWith("\n")) textblk.setText(buf.toString()+" ");
						flow.getChildren().add(textblk);
						StringBuffer style = new StringBuffer("-fx-fill: -fx-text-background-color; -fx-text-alignment: justify;");
						if (b && !(em||i)) {
							textblk.setFont(Font.font("Segoe UI Bold", FontWeight.NORMAL, -1));
							textblk.getStyleClass().add(JavaFXConstants.STYLE_HEADING5);
						} else if ((em||i) && !b) {
							textblk.setFont(Font.font("Segoe UI Italic", FontWeight.NORMAL, -1));
							textblk.getStyleClass().add("emphasize");
						} else if ((em||i) && b) {
							textblk.getStyleClass().addAll("emphasize",JavaFXConstants.STYLE_HEADING5);
//							style.append(" -fx-font-family: 'Segoe UI Bold Italic';");
							textblk.setFont(Font.font("Segoe UI Bold Italic", FontWeight.NORMAL, -1));
						}
						textblk.setStyle(style.toString());
						buf = new StringBuffer();
					}
					switch (parser.getLocalName()) {
					case "text": break;
					case "br": break;
					case "em":
						em = false;break;
					case "b":
						b = false;break;
					case "i":
						i = false;break;
					default:
						logger.log(Level.WARNING, "Unsupported END markup: "+parser.getLocalName());
					}
					break;

				default:
					break;
				}
				parser.next();
			}
		} catch (Exception e) {
			logger.log(Level.ERROR, "Failed parsing markup",e);
			logger.log(Level.ERROR, text);
		}
	}

	//-------------------------------------------------------------------
	public static String createSourceText(DataItem item) {
		List elements = new ArrayList<>();
		boolean shorted = item.getPageReferences().size()>2;
		String language = Locale.getDefault().getLanguage();
		for (PageReference ref : item.getPageReferences()) {
			if (!ref.getLanguage().equals(language))
				continue;
			if (ref.getOverwrittenProductName()!=null) {
				elements.add( ref.getOverwrittenProductName()+" "+ref.getPage() );
			} else if (shorted) {
				elements.add( ref.getProduct().getShortName(Locale.getDefault())+" "+ref.getPage() );
			} else {
				elements.add( ref.getProduct().getName(Locale.getDefault())+" "+ref.getPage() );
			}
		}

		return String.join(", ", elements);
	}

	//-------------------------------------------------------------------
	public static  Decision requestDecision(DataItem decideFor, Choice choice, String modText, PartialController control) {
		logger.log(Level.DEBUG, "ENTER: requestDecision from {0}",choice);
		List options = GenericRPGTools.convertChoiceToOptions(choice);
		logger.log(Level.WARNING, "requestDecision from {0}",options);
		if (choice.getDistribute()!=null) {
			logger.log(Level.WARNING, "Distribute "+Arrays.toString(choice.getDistribute())+" on");
		} else {
			int count = (choice.getCount()>0)?choice.getCount():1;
			if (count>1) {
				modText = count+"x "+modText;
			}
			logger.log(Level.WARNING, "Chose "+count+"x from "+options);
			if (count==1 && options.size()<=3) {
				ChoiceFewDialog dialog = new ChoiceFewDialog(decideFor, choice.getUUID(), modText, options, control);
				CloseType closed = FlexibleApplication.getInstance().showAndWait(dialog);
				logger.log(Level.INFO, "Closed with "+closed);
			} else {
				ChoiceManyDialog dialog = new ChoiceManyDialog(decideFor, choice, modText, options, control);
				CloseType closed = FlexibleApplication.getInstance().showAndWait(dialog);
				logger.log(Level.INFO, "Closed with "+closed);
			}
		}

		logger.log(Level.DEBUG, "LEAVE: requestDecision from {0}");
		return null;
	}

	//-------------------------------------------------------------------
	public static  Decision requestDecision(DataItem decideFor, ModificationChoice choice, String modText, PartialController control) {
		logger.log(Level.WARNING, "requestDecision from "+choice.getUUID()+" with ChoiceFewDialog");
		List options = GenericRPGTools.convertChoiceToOptions(choice);
		logger.log(Level.WARNING, "requestDecision: options = {0}", options);
		ChoiceFewDialog dialog = new ChoiceFewDialog(decideFor, choice.getUUID(), modText, options, control);
		CloseType closed = FlexibleApplication.getInstance().showAndWait(dialog);
		logger.log(Level.INFO, "Closed with "+closed);

		return dialog.getDecision();
	}

	//-------------------------------------------------------------------
	public static > VBox getRequirementsBox(
			D item,
			Function reqMetResolver,
			Function reqNameResolver) {
		VBox ret = new VBox(5);
		if (item.getRequirements().isEmpty())
			return ret;

		Label heading = new Label(ResourceI18N.get(RPGFrameworkJFXConstants.UI, "label.requires"));
		heading.getStyleClass().add(JavaFXConstants.STYLE_HEADING5);
		heading.setStyle("    -fx-border-width: 0 0 1 0;\r\n"
				+ "    -fx-underline: true;");
		ret.getChildren().add(heading);

		for (Requirement req : item.getRequirements()) {
			String name = reqNameResolver.apply(req);
			Label reqLabel = new Label(name);
			ret.getChildren().add(reqLabel);
			// Check if requirement is met
			if (reqMetResolver!=null) {
				boolean met = reqMetResolver.apply(req);
				reqLabel.setStyle(met?"":"-fx-text-fill: highlight");
			}
		}
		return ret;
	}

	//-------------------------------------------------------------------
	public static > VBox getModificationsBox(
			D item,
			Function modNameResolver) {
		VBox ret = new VBox(5);
		if (item.getOutgoingModifications().isEmpty())
			return ret;

		Label heading = new Label(ResourceI18N.get(RPGFrameworkJFXConstants.UI, "label.grants"));
		heading.getStyleClass().add(JavaFXConstants.STYLE_HEADING5);
		heading.setStyle("    -fx-border-width: 0 0 1 0;\r\n"
				+ "    -fx-underline: true;");
		ret.getChildren().add(heading);

		for (Modification mod : item.getOutgoingModifications()) {
			String name = modNameResolver.apply(mod);
			Label reqLabel = new Label(name);
			ret.getChildren().add(reqLabel);
		}
		return ret;
	}

	//-------------------------------------------------------------------
	public static void updateChoice(DecisionContainer container, ChoiceOrigin origin, Function modConv, DataItemModification mod, Text decText) {
		Decision dec = container.getDecision(mod.getConnectedChoice());
		if (dec == null) {
			decText.setText("");
		} else {
			List modList = GenericRPGTools.decisionToModifications(mod,
					origin.getChoice(mod.getConnectedChoice()), dec);
			List modListS = modList.stream().map(mb -> modConv.apply(mb))
					.collect(Collectors.toList());
			decText.setText(" (" + String.join(", ", modListS) + ")");
		}
	}

}