package ai.cogmission.fxmaps.ui; import java.util.ArrayList; import java.util.List; import javafx.geometry.Rectangle2D; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.scene.text.TextFlow; import ai.cogmission.fxmaps.model.Direction; /** * The "action" portion of a given directions route is displayed * on one of these. * * @author cogmission * */ public class DirectionsStepPane extends HBox { private static String imagePath = "http://metaware.us/images/markers/all_directions.png"; private Direction dir; private String text; private ImageView view; private TextFlow textFlow; /** * Constructs a new {@code DirectionsStepPane} * * @param d {@link Direction} enum to determine icon * @param text the actual directions */ public DirectionsStepPane(Direction d, String text) { this.dir = d == null ? Direction.HEAD : d; this.text = text; view = getImageView(dir); textFlow = parseText(); getChildren().addAll(view, textFlow); } /** * Returns an {@link ImageView} node capable of being displayed * in this {@code DirectionsStepPane} * * @param d the {@link Direction} enum indicating icon subsection * @return the constructed {@link ImageView} */ private ImageView getImageView(Direction d) { ImageView iv = new ImageView(imagePath); iv.setViewport(new Rectangle2D(0, d.index(), d.w(), d.h())); iv.fitWidthProperty().set(22); iv.fitHeightProperty().set(22); return iv; } /** * Parses the specified String to return the portion not containing * the destination statement. This is needed so that the main text * which when parsed, indicates the direction icon that will be used; * will be the only determiner of the associated directions icon. The * destination text has other directions which will confuse the parsing * which determines the icon. (i.e. The destination will be on the right). * * @param text the entire directions text returned by the Google-Maps API. * @return the String minus the destination statement (if it exists). */ private String excludeDestinationStatement(String text) { int idx = -1; if((idx = text.indexOf("Destination will be")) != -1) { text = text.substring(0, idx); } return text; } /** * Parses the text and returns a {@link TextFlow} node containing the proper * icon and the directions text which is used to display the * directions information. * * @return the constructed {@link TextFlow} */ private TextFlow parseText() { String testText = excludeDestinationStatement(text); TextFlow tf = new TextFlow(); List<Text> tList = new ArrayList<Text>(); int len = testText.length(); int start = 0; int idx = 0; boolean isBold = false; while((idx = testText.indexOf("<", start)) != len) { if(idx == -1) { idx = len; } Text segment = new Text(testText.substring(start, idx)); if(isBold) { segment.setFont(Font.font( segment.getFont().getFamily(), FontWeight.BOLD, segment.getFont().getSize())); isBold = false; } tList.add(segment); start = testText.indexOf(">", idx) + 1; if(idx < len && text.substring(idx, idx + 2).indexOf("<b") != -1) { isBold = true; } if(idx == len) break; } if(text.length() != testText.length()) { tList.add(new Text(" " + text.indexOf("Destination"))); } tf.getChildren().addAll(tList); return tf; } }