1 /* 2 * Copyright (c) 2008, 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 modena; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 import javafx.application.Platform; 38 import javafx.collections.FXCollections; 39 import javafx.collections.ObservableList; 40 import javafx.css.PseudoClass; 41 import javafx.geometry.Insets; 42 import javafx.geometry.Orientation; 43 import javafx.geometry.Pos; 44 import javafx.geometry.Side; 45 import javafx.scene.GroupBuilder; 46 import javafx.scene.Node; 47 import javafx.scene.control.Accordion; 48 import javafx.scene.control.Button; 49 import javafx.scene.control.ButtonBuilder; 50 import javafx.scene.control.CheckMenuItem; 51 import javafx.scene.control.CheckMenuItemBuilder; 52 import javafx.scene.control.ContextMenu; 53 import javafx.scene.control.Label; 54 import javafx.scene.control.ListView; 55 import javafx.scene.control.Menu; 56 import javafx.scene.control.MenuBar; 57 import javafx.scene.control.MenuItem; 58 import javafx.scene.control.Pagination; 59 import javafx.scene.control.RadioMenuItemBuilder; 60 import javafx.scene.control.SelectionMode; 61 import javafx.scene.control.Separator; 62 import javafx.scene.control.SeparatorMenuItem; 63 import javafx.scene.control.SplitPane; 64 import javafx.scene.control.TabBuilder; 65 import javafx.scene.control.TabPane; 66 import javafx.scene.control.TextField; 67 import javafx.scene.control.TitledPaneBuilder; 68 import javafx.scene.control.ToolBar; 69 import javafx.scene.image.Image; 70 import javafx.scene.image.ImageView; 71 import javafx.scene.input.KeyCharacterCombination; 72 import javafx.scene.input.KeyCombination; 73 import javafx.scene.layout.HBox; 74 import javafx.scene.layout.StackPane; 75 import javafx.scene.layout.StackPaneBuilder; 76 import javafx.scene.paint.Color; 77 import javafx.scene.shape.LineBuilder; 78 import javafx.scene.shape.RectangleBuilder; 79 80 /** 81 * Helper static methods for Sample Page 82 */ 83 public class SamplePageHelpers { 84 85 static <T extends Node> T withState(T node, String state) { 86 if (node != null && state != null) { 87 // stop user from being able to change state 88 node.setMouseTransparent(true); 89 node.setFocusTraversable(false); 90 // set state to chosen state 91 final String[] pseudoClasses = (state).split("[\\s,]+"); 92 for (String pseudoClass : pseudoClasses) { 93 node.pseudoClassStateChanged(PseudoClass.getPseudoClass(pseudoClass), true); 94 } 95 } 96 return node; 97 } 98 99 static <T extends Node> T withState(final T node, final String state, final String subNodeStyleClass, final String subNodeState) { 100 withState(node, state); 101 Platform.runLater(() -> withState(node.lookup(subNodeStyleClass), subNodeState)); 102 return node; 103 } 104 105 private static final String[] LETTERS = new String[]{"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}; 106 107 static ObservableList<String> sampleItems() { 108 return sampleItems(7); 109 } 110 111 static ObservableList<String> sampleItems(int numberOfItems) { 112 ArrayList<String> items = new ArrayList<String>(); 113 if (numberOfItems < 26) { 114 for(int i=0; i<numberOfItems; i++) { 115 items.add("Item "+LETTERS[i]); 116 } 117 } else { 118 for(int i=0; i<numberOfItems; i++) { 119 items.add("Item "+i); 120 } 121 } 122 return FXCollections.observableArrayList(items); 123 } 124 125 static Node scrollPaneContent() { 126 return GroupBuilder.create().children( 127 RectangleBuilder.create().width(200).height(200).fill(Color.PALETURQUOISE).build(), 128 LineBuilder.create().endX(200).endY(200).stroke(Color.DODGERBLUE).build(), 129 LineBuilder.create().startX(200).endX(0).endY(200).stroke(Color.DODGERBLUE).build() 130 ).build(); 131 } 132 133 static Node createTabPane(int numOfTabs, int prefWidth, int prefHeight, String firstTabText, boolean floating, boolean disableFirst, Side side) { 134 TabPane tabPane = new TabPane(); 135 tabPane.setSide(side); 136 if (floating) tabPane.getStyleClass().add("floating"); 137 for (int i=1; i<=numOfTabs; i++) { 138 tabPane.getTabs().add( 139 TabBuilder.create() 140 .text("Tab "+i) 141 .disable(i==1 && disableFirst) 142 .content(new Label((i==1 && firstTabText!=null)? firstTabText :"Tab "+i+" Content")) 143 .build() 144 ); 145 } 146 if (disableFirst) tabPane.getSelectionModel().select(1); 147 tabPane.setPrefWidth(prefWidth); 148 tabPane.setPrefHeight(prefHeight); 149 return tabPane; 150 } 151 152 static Node wrapBdr(Node node) { 153 return StackPaneBuilder.create().children(node) 154 .style("-fx-border-color: black; -fx-border-width: 3;").build(); 155 } 156 157 static ToolBar createToolBar(Side side, boolean overFlow, boolean disabled) { 158 final boolean vertical = side == Side.LEFT || side == Side.RIGHT; 159 ToolBar toolBar = new ToolBar(); 160 if (vertical) toolBar.setOrientation(Orientation.VERTICAL); 161 if (side == Side.BOTTOM) toolBar.getStyleClass().add("bottom"); 162 if (side == Side.RIGHT) toolBar.getStyleClass().add("right"); 163 if (disabled) toolBar.setDisable(true); 164 toolBar.getItems().addAll( 165 new Button("A"), 166 new Button("B"), 167 new Separator() 168 ); 169 if (vertical) { 170 toolBar.getItems().addAll( 171 new Button("C"), 172 new Button("D") 173 ); 174 } else { 175 Label searchLabel = new Label("Search:"); 176 HBox searchBox = new HBox(10, searchLabel, new TextField()); 177 searchBox.setAlignment(Pos.BASELINE_LEFT); 178 toolBar.getItems().addAll(searchBox); 179 } 180 if (overFlow) { 181 if (vertical) { 182 toolBar.setPrefHeight(80); 183 } else { 184 toolBar.setPrefWidth(80); 185 } 186 } 187 return toolBar; 188 } 189 190 static Accordion createAccordion() { 191 Accordion accordian = new Accordion(); 192 accordian.getPanes().addAll( 193 TitledPaneBuilder.create().text("Title 1").content(new Label("Content\nLine2.")).build(), 194 TitledPaneBuilder.create().text("Title 2").content(new Label("Content\nLine2.")).build(), 195 TitledPaneBuilder.create().text("Title 3").content(new Label("Content\nLine2.")).build() 196 ); 197 return accordian; 198 } 199 200 static SplitPane createSplitPane(int numOfItems, boolean vertical, Node firstItem) { 201 SplitPane splitPane = new SplitPane(); 202 if(vertical) splitPane.setOrientation(Orientation.VERTICAL); 203 if (firstItem != null) splitPane.getItems().add(firstItem); 204 for (int i=1; i<=numOfItems; i++) { 205 splitPane.getItems().add(new Label("Item "+i)); 206 } 207 splitPane.setPrefSize(150, 150); 208 return splitPane; 209 } 210 211 static Pagination createPagination(int numOfPages, boolean bullet, boolean arrows) { 212 Pagination pagination = new Pagination(numOfPages); 213 if (bullet) pagination.getStyleClass().add("bullet"); 214 if (!arrows) pagination.setStyle("-fx-arrows-visible:false;"); 215 pagination.setPageFactory(param -> new Label("Page Label "+param)); 216 return pagination; 217 } 218 219 static ListView<String> createListView(int numOfItems, boolean multipleSelection, boolean disable, boolean horiz) { 220 ListView<String> listView = new ListView<String>(); 221 if (horiz) listView.setOrientation(Orientation.HORIZONTAL); 222 listView.setPrefHeight((24*7)+4); 223 listView.setPrefWidth(horiz ? 200 : 140); 224 listView.getItems().addAll(sampleItems(numOfItems)); 225 listView.setDisable(disable); 226 if (multipleSelection) { 227 listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 228 listView.getSelectionModel().selectRange(1, 5); 229 } else { 230 listView.getSelectionModel().select(1); 231 } 232 return listView; 233 } 234 235 static MenuItem[] createMenuItems(int numberOfItems) { 236 ArrayList<MenuItem> items = new ArrayList<MenuItem>(); 237 if (numberOfItems < 26) { 238 for(int i=0; i<numberOfItems; i++) { 239 items.add(new MenuItem("Item "+LETTERS[i])); 240 } 241 } else { 242 for(int i=0; i<numberOfItems; i++) { 243 items.add(new MenuItem("Item "+i)); 244 } 245 } 246 return items.toArray(new MenuItem[items.size()]); 247 } 248 249 static MenuBar createMenuBar() { 250 final MenuBar mb = new MenuBar(); 251 mb.getMenus().addAll( 252 createMenu("File"), 253 createMenu("Edit"), 254 createMenu("View"), 255 createMenu("Help") 256 ); 257 Platform.runLater(() -> new ArrayList<Node>(mb.lookupAll(".menu")).get(1).pseudoClassStateChanged(PseudoClass.getPseudoClass("hover"), true)); 258 return mb; 259 } 260 261 static Menu createMenu(String name) { 262 Menu m = new Menu(name); 263 m.getStyleClass().add(name); 264 m.getItems().addAll(createMenuContents()); 265 return m; 266 } 267 268 static Node createContextMenu() { 269 Button b = new Button("ContextMenu Right Click Me"); 270 b.setContextMenu(new ContextMenu(createMenuContents())); 271 return b; 272 } 273 274 static Node createInlineMenu(final boolean selectAll) { 275 // create a context menu so we can put it inline in our test page 276 final ContextMenu menu = new ContextMenu(createMenuContents()); 277 // create a place holder container 278 final StackPane contextMenu = new StackPane(); 279 // show context menu then steal and place inline 280 Platform.runLater(() -> { 281 menu.show(contextMenu,-1000,-1000); 282 menu.hide(); 283 Platform.runLater(() -> { 284 final Node menuContent = menu.getSkin().getNode(); 285 contextMenu.getChildren().add(menuContent); 286 menuContent.setMouseTransparent(true); 287 // System.out.println("menuContent = " + menuContent); 288 // System.out.println("menuContent.lookupAll(\".menu-item\") = " + menuContent.lookupAll(".menu-item")); 289 290 // Platform.runLater(new Runnable() { 291 // @Override public void run() { 292 //// if (selectAll) { 293 //// for (Node n: menuContent.lookupAll(".menu-item")) { 294 //// n.pseudoClassStateChanged(PseudoClass.getPseudoClass("hover"), true); 295 //// } 296 //// } else { 297 // new ArrayList<Node>(menuContent.lookupAll(".menu-item")).get(2) 298 // .pseudoClassStateChanged(PseudoClass.getPseudoClass("hover"), true); 299 //// } 300 // } 301 // }); 302 }); 303 }); 304 return contextMenu; 305 } 306 307 static MenuItem[] createMenuContents() { 308 List<MenuItem> menuItems = new ArrayList<>(); 309 final Menu menu11 = new Menu("_New"); 310 MenuItem menu12 = new MenuItem("_Open"); 311 menu12.getStyleClass().add("OpenMenuItem"); 312 menu12.setAccelerator(new KeyCharacterCombination("]", 313 KeyCombination.SHIFT_DOWN, KeyCombination.META_DOWN)); 314 Menu menu13 = new Menu("_Submenu"); 315 MenuItem menu15 = new MenuItem("E_xit"); 316 final String change[] = {"Change Text", "Change Back"}; 317 final MenuItem menu16 = new MenuItem(change[0]); 318 menu16.setAccelerator(KeyCombination.keyCombination("Shortcut+C")); 319 menuItems.add(menu11); 320 menuItems.add(menu12); 321 menuItems.add(menu13); 322 menuItems.add(menu16); 323 menuItems.add(new SeparatorMenuItem()); 324 menuItems.add(CheckMenuItemBuilder.create().text("Check").build()); 325 menuItems.add(CheckMenuItemBuilder.create().text("Check Selected").selected(true).build()); 326 menuItems.add(new SeparatorMenuItem()); 327 menuItems.add(RadioMenuItemBuilder.create().text("Radio").build()); 328 menuItems.add(RadioMenuItemBuilder.create().text("Radio Selected").selected(true).build()); 329 menuItems.add(new SeparatorMenuItem()); 330 menuItems.add(menu15); 331 332 // --- Menu 11 submenu 333 final MenuItem menu111 = new MenuItem("blah"); 334 final MenuItem menu112 = new MenuItem("foo"); 335 final CheckMenuItem menu113 = new CheckMenuItem("Show \"foo\" item"); 336 menu113.setSelected(true); 337 menu113.selectedProperty().addListener(valueModel -> { 338 menu112.setVisible(menu113.isSelected()); 339 System.err.println("MenuItem \"foo\" is now " + (menu112.isVisible() ? "" : "not") + " visible."); 340 }); 341 menu11.getItems().addAll(menu111, menu112, menu113); 342 343 // --- Menu 13 submenu 344 MenuItem menu131 = new MenuItem("Item _1"); 345 MenuItem menu132 = new MenuItem("Item _2"); 346 menu13.getItems().addAll(menu131, menu132); 347 348 return menuItems.toArray(new MenuItem[menuItems.size()]); 349 } 350 351 static final Image recorder48 = new Image(SamplePageHelpers.class.getResource("recorder-icon-48.png").toExternalForm()); 352 353 static ImageView createGraphic() { 354 return new ImageView(recorder48); 355 } 356 357 static Node createGreyButton(double percentageGrey) { 358 int grey = (int)(percentageGrey*255); 359 int percentage = (int)(percentageGrey * 100); 360 StackPane sp = new StackPane(); 361 sp.setStyle("-fx-base: rgba("+grey+","+grey+","+grey+",1); -fx-background-color: -fx-background;"); 362 sp.setPadding(new Insets(8)); 363 sp.getChildren().add(ButtonBuilder.create().text(percentage+"%").build()); 364 return sp; 365 } 366 }