Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8115386

New lines / unnecessary Ellipsis in Labels with setWrapText(true)

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P4
    • Resolution: Fixed
    • Affects Version/s: 8
    • Fix Version/s: None
    • Component/s: javafx
    • Labels:
    • Environment:

      Windows 7 64-bit, JavaFX 8.0.0-ea-b92

      Description

      Run the included source, and look at the bottom left row of "images" with their name and role descriptions. These were properly formatted in JavaFX 2.2, without any extra spacing or ellipses between the two labels (CastingImage.label and CastingImage.characterNameLabel).

      The first bottom-left image shows spacing between "Some Name" and the text below it, and the text below it is cut off with an ellipsis. Expected: no spacing, no ellipsis.

      The second bottom-left image shows spacing between the Image button ("?") and the first label, and more unnecessary spacings and cut-offs with ellipses in the two labels.

      The third bottom-left image shows a correct result -- it turns out it is correct as long as none of the labels need wrapping.

      package hs.mediasystem;

      import java.util.Map;
      import java.util.WeakHashMap;

      import javafx.application.Application;
      import javafx.beans.binding.BooleanBinding;
      import javafx.beans.binding.BooleanExpression;
      import javafx.beans.binding.StringBinding;
      import javafx.beans.property.SimpleStringProperty;
      import javafx.beans.property.StringProperty;
      import javafx.collections.ObservableList;
      import javafx.geometry.Pos;
      import javafx.scene.Node;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.Label;
      import javafx.scene.control.ListView;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.layout.ColumnConstraints;
      import javafx.scene.layout.GridPane;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.Pane;
      import javafx.scene.layout.Priority;
      import javafx.scene.layout.RowConstraints;
      import javafx.scene.layout.VBox;
      import javafx.stage.Stage;

      public class TextFlowSample extends Application {
        private StringProperty plot = new SimpleStringProperty("When the coach of the France soccer team is killed by a poisoned dart in the stadium in the end of a game, and his expensive and huge ring with the diamond Pink Panther disappears, the ambitious Chief Inspector Dreyfus assigns the worst police inspector Jacques Clouseau to the case.");

        public static void main(String[] args) {
          Application.launch(args);
        }

        @Override
        public void start(Stage stage) throws Exception {
          HBox hbox = new HBox();

          hbox.setStyle(" -fx-font-family: \"Arial\"; -fx-font-size: 16px; -fx-font-weight: normal;");

          BorderPane borderPane = new BorderPane() {{
            setTop(new VBox() {{
              setId("title-area");
            }});

            setCenter(new GridPane() {{
              GridPaneUtil.configure(this, new double[] {60, 40}, new double[] {100});

              setHgap(20);

              add(new VBox() {{
                setId("description-area");
              }}, 0, 0);

              add(new VBox() {{
                setId("title-image-area");
              }}, 1, 0);
            }});

            setBottom(new HBox() {{
              setId("link-area");
              setStyle(" -fx-font-size: 12px; -fx-font-weight: bold;");
            }});
          }};

          add(borderPane, "description-area", 6, createPlotBlock());


          add(borderPane, "link-area", 0, createCastingImage("Some name", "Some Character / Some Other Character"));
          add(borderPane, "link-area", 0, createCastingImage("Some longer name", "Some Character"));
          add(borderPane, "link-area", 0, createCastingImage("Joe Normal", "Ace"));

          ListView<String> listView = new ListView<>();

          listView.setMinWidth(100);
          listView.getItems().add("Some title");

          hbox.getChildren().addAll(borderPane, listView);

          stage.setScene(new Scene(hbox));

          stage.setWidth(1024);
          stage.setHeight(600);
          stage.show();
        }

        protected Node createCastingImage(String name, String character) {
          return new CastingImage() {{
            this.title.set(name);
            this.characterName.set(character);
          }};
        }

        protected Pane createPlotBlock() {
          Node plotField = createPlotField();
          VBox.setVgrow(plotField, Priority.ALWAYS);

          return createTitledBlock("PLOT", plotField, plot.isNotEqualTo(""));
        }

        protected Node createPlotField() {
          return new Label() {{
            getStyleClass().addAll("field", "plot");
            wrapTextProperty().set(true);
            textProperty().bind(plot);
            managedProperty().bind(plot.isNotEqualTo(""));
            visibleProperty().bind(plot.isNotEqualTo(""));
          }};
        }

        protected Pane createTitledBlock(final String title, final Node content, final BooleanExpression visibleCondition) {
          return new VBox() {{
            setFillWidth(true);
            getChildren().add(new Label(title) {{
              getStyleClass().add("header");
            }});
            getChildren().add(content);

            if(visibleCondition != null) {
              managedProperty().bind(visibleCondition);
              visibleProperty().bind(visibleCondition);
            }
            setStyle("-fx-border-color: red; -fx-border-width: 2px");
          }};
        }

        private final Map<Node, Double> orderMap = new WeakHashMap<>();

        public boolean add(Pane mainPane, String areaName, double order, Node node) {
          Pane pane = (Pane)mainPane.lookup("#" + areaName);

          if(pane == null) {
            return false;
          }

          ObservableList<Node> children = pane.getChildren();
          int insertPosition = 0;

          for(; insertPosition < children.size(); insertPosition++) {
            Node child = children.get(insertPosition);

            if(orderMap.get(child) > order) {
              break;
            }
          }

          children.add(insertPosition, node);
          orderMap.put(node, order);

          return true;
        }

        public static class GridPaneUtil {
          public static void configure(GridPane gridPane, double[] columns, double[] rows) {
            for(double column : columns) {
              ColumnConstraints constraints = new ColumnConstraints();

              constraints.setPercentWidth(column);

              gridPane.getColumnConstraints().add(constraints);
            }

            for(double row : rows) {
              RowConstraints constraints = new RowConstraints();

              constraints.setPercentHeight(row);

              gridPane.getRowConstraints().add(constraints);
            }
          }

          public static GridPane create(double[] columns, double[] rows) {
            GridPane gridPane = new GridPane();

            configure(gridPane, columns, rows);

            return gridPane;
          }
        }

        public class CastingImage extends Button {
          public final StringProperty title = new SimpleStringProperty();
          public final StringProperty characterName = new SimpleStringProperty();

          private final StringBinding formattedCharacterName = new StringBinding() {
            {
              bind(characterName);
            }

            @Override
            protected String computeValue() {
              return characterName.get() == null ? null : "as " + formatCharacterName(characterName.get(), 40);
            }
          };

          public CastingImage() {
            getStyleClass().add("cast-item");

            VBox vbox = new VBox();
            Button imageView = new Button("?");

            Label label = new Label();

            imageView.getStyleClass().add("cast-photo");
            imageView.setMinHeight(122);
            imageView.setAlignment(Pos.CENTER);

            label.getStyleClass().add("cast-name");
            label.setWrapText(true);
            label.textProperty().bind(title);
            label.setMinWidth(100);
            label.setMaxWidth(100);

            vbox.getChildren().addAll(imageView, label);

            Label characterNameLabel = new Label();

            characterNameLabel.getStyleClass().add("cast-character-name");
            characterNameLabel.setWrapText(true);
            characterNameLabel.textProperty().bind(formattedCharacterName);
            characterNameLabel.setMinWidth(100);
            characterNameLabel.setMaxWidth(100);

            vbox.getChildren().add(characterNameLabel);

            BooleanBinding visibleBinding = characterName.isNotNull().and(characterName.isNotEqualTo(""));

            characterNameLabel.managedProperty().bind(visibleBinding);
            characterNameLabel.visibleProperty().bind(visibleBinding);

            setGraphic(vbox);
          }

          private String formatCharacterName(String rawCharacterName, int cutOffLength) {
            String characterName = rawCharacterName.replaceAll(" / ", "|");
            int more = 0;

            for(;;) {
              int index = characterName.lastIndexOf('|');

              if(index == -1) {
                return characterName;
              }

              if(index > cutOffLength) { // too long, cut it off
                characterName = characterName.substring(0, index).trim();
                more++;
              }
              else {
                if(more == 0) {
                  characterName = characterName.substring(0, index).trim() + " & " + characterName.substring(index + 1).trim();
                }
                else {
                  characterName = characterName.substring(0, index).trim() + " (" + (more + 1) + "\u00a0more)";
                }
                return characterName.replaceAll(" *\\| *", ", ");
              }
            }
          }
        }
      }

        Attachments

        1. RT-30960.png
          76 kB
          Felipe Heidrich

          Issue Links

            Activity

              People

              • Assignee:
                fheidric Felipe Heidrich (Inactive)
                Reporter:
                jhendrikx John Hendrikx
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Imported: