1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.oracle.javafx.scenebuilder.app.selectionbar; 33 34 import java.net.URL; 35 36 import javafx.event.ActionEvent; 37 import javafx.event.EventHandler; 38 import javafx.fxml.FXML; 39 import javafx.scene.Node; 40 import javafx.scene.control.Hyperlink; 41 import javafx.scene.control.Label; 42 import javafx.scene.image.Image; 43 import javafx.scene.image.ImageView; 44 import javafx.scene.layout.HBox; 45 import javafx.scene.layout.Priority; 46 import javafx.scene.layout.Region; 47 import javafx.scene.layout.StackPane; 48 49 import com.oracle.javafx.scenebuilder.app.i18n.I18N; 50 import com.oracle.javafx.scenebuilder.kit.editor.EditorController; 51 import com.oracle.javafx.scenebuilder.kit.editor.panel.util.AbstractFxmlPanelController; 52 import com.oracle.javafx.scenebuilder.kit.editor.selection.ObjectSelectionGroup; 53 import com.oracle.javafx.scenebuilder.kit.editor.selection.Selection; 54 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; 55 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject; 56 import com.oracle.javafx.scenebuilder.kit.metadata.util.DesignHierarchyMask; 57 58 /** 59 * 60 */ 61 public class SelectionBarController extends AbstractFxmlPanelController { 62 63 @FXML 64 private HBox pathBox; 65 66 private final Image selectionChevronImage; 67 68 public SelectionBarController(EditorController editorController) { 69 super(SelectionBarController.class.getResource("SelectionBar.fxml"), I18N.getBundle(), editorController); //NOI18N 70 71 // Initialize selection chevron image 72 final URL selectionChevronURL = SelectionBarController.class.getResource("selection-chevron.png"); //NOI18N 73 assert selectionChevronURL != null; 74 selectionChevronImage = new Image(selectionChevronURL.toExternalForm()); 75 } 76 77 /* 78 * AbstractPanelController 79 */ 80 @Override 81 protected void fxomDocumentDidChange(FXOMDocument oldDocument) { 82 if (pathBox != null) { 83 updateSelectionBar(); 84 } 85 } 86 87 @Override 88 protected void sceneGraphRevisionDidChange() { 89 if (pathBox != null) { 90 updateSelectionBar(); 91 } 92 } 93 94 @Override 95 protected void cssRevisionDidChange() { 96 // Nothing to do here 97 } 98 99 @Override 100 protected void jobManagerRevisionDidChange() { 101 sceneGraphRevisionDidChange(); 102 } 103 104 @Override 105 protected void editorSelectionDidChange() { 106 if (pathBox != null) { 107 updateSelectionBar(); 108 } 109 } 110 111 /* 112 * AbstractFxmlPanelController 113 */ 114 @Override 115 protected void controllerDidLoadFxml() { 116 117 // Sanity checks 118 assert pathBox != null; 119 120 // Update 121 updateSelectionBar(); 122 } 123 124 /* 125 * Private 126 */ 127 private void updateSelectionBar() { 128 final Selection selection = getEditorController().getSelection(); 129 130 pathBox.getChildren().clear(); 131 132 if (selection.isEmpty()) { 133 pathBox.getChildren().add(new Label(I18N.getString("selectionbar.no.selected"))); 134 } else { 135 if (selection.getGroup() instanceof ObjectSelectionGroup) { 136 final ObjectSelectionGroup osg = (ObjectSelectionGroup) selection.getGroup(); 137 assert osg.getItems().isEmpty() == false; 138 139 FXOMObject fxomObject = osg.getItems().iterator().next(); 140 // Recursive error report for the leaf object only 141 // boolean recursive = true; 142 while (fxomObject != null) { 143 final DesignHierarchyMask mask = new DesignHierarchyMask(fxomObject); 144 final String entryText = makeEntryText(mask); 145 final Hyperlink boxItem = new Hyperlink(); 146 boxItem.setText(entryText); 147 final Node graphic; 148 // Do not display warning icon anymore : 149 // See DTL-6535 : Should we show warnings in the selection bar ? 150 // final List<ErrorReportEntry> entries = getErrorReportEntries(fxomObject, recursive); 151 // if (entries != null) { 152 // assert !entries.isEmpty(); 153 // final ImageView classNameImageView 154 // = new ImageView(mask.getClassNameIcon()); 155 // final ImageView warningBadgeImageView 156 // = new ImageView(warningBadgeImage); 157 // final StackPane iconsStack = new StackPane(); 158 // iconsStack.getChildren().setAll(classNameImageView, warningBadgeImageView); 159 // // Update tooltip with the first entry 160 // final Tooltip iconsTooltip = new Tooltip(entries.get(0).toString()); 161 // 162 // // We use a label to set a tooltip over the node icon 163 // // (StackPane does not allow to set tooltips) 164 // graphic = new Label(); 165 // ((Label) graphic).setGraphic(iconsStack); 166 // ((Label) graphic).setTooltip(iconsTooltip); 167 // } else { 168 graphic = new ImageView(mask.getClassNameIcon()); 169 // } 170 boxItem.setGraphic(graphic); 171 boxItem.setFocusTraversable(false); 172 boxItem.setUserData(fxomObject); 173 boxItem.setOnAction(hyperlinkHandler); 174 pathBox.getChildren().add(0, boxItem); 175 176 // The last 2 box item should never show ellipsis 177 if (pathBox.getChildren().size() <= 3) { 178 boxItem.setMinWidth(Region.USE_PREF_SIZE); 179 HBox.setHgrow(boxItem, Priority.ALWAYS); 180 } else { 181 boxItem.setMinWidth(graphic.getBoundsInLocal().getWidth()); 182 } 183 184 fxomObject = mask.getParentFXOMObject(); 185 // Add selection chevron if needed 186 if (fxomObject != null) { 187 // We cannot share the image view to avoid 188 // Children: duplicate children added 189 ImageView img = new ImageView(selectionChevronImage); 190 StackPane sp = new StackPane(); 191 sp.getChildren().add(img); 192 sp.setMinWidth(selectionChevronImage.getWidth()); 193 pathBox.getChildren().add(0, sp); 194 } 195 // Non recursive error report for the parent 196 // recursive = false; 197 } 198 199 } else { 200 pathBox.getChildren().add(new Label(I18N.getString("selectionbar.not.object"))); 201 } 202 } 203 } 204 205 private String makeEntryText(DesignHierarchyMask mask) { 206 final StringBuilder result = new StringBuilder(); 207 208 result.append(mask.getClassNameInfo()); 209 final String description = mask.getSingleLineDescription(); 210 if (description != null) { 211 result.append(" : "); //NOI18N 212 result.append(description); 213 } 214 return result.toString(); 215 } 216 217 private final EventHandler<ActionEvent> hyperlinkHandler = t -> { 218 assert t.getSource() instanceof Hyperlink; 219 final Hyperlink hyperlink = (Hyperlink) t.getSource(); 220 assert hyperlink.getUserData() instanceof FXOMObject; 221 handleSelect((FXOMObject) hyperlink.getUserData()); 222 hyperlink.setVisited(false); 223 }; 224 225 private void handleSelect(FXOMObject fxomObject) { 226 final Selection selection = getEditorController().getSelection(); 227 228 assert fxomObject.getFxomDocument() == getEditorController().getFxomDocument(); 229 230 selection.select(fxomObject); 231 } 232 233 // private List<ErrorReportEntry> getErrorReportEntries(FXOMObject fxomObject, boolean recursive) { 234 // assert fxomObject != null; 235 // final ErrorReport errorReport = getEditorController().getErrorReport(); 236 // return errorReport.query(fxomObject, recursive); 237 // } 238 }