1 /*
   2  * Copyright (c) 2008, 2015, 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.Group;
  46 import javafx.scene.Node;
  47 import javafx.scene.control.Accordion;
  48 import javafx.scene.control.Button;
  49 import javafx.scene.control.CheckMenuItem;
  50 import javafx.scene.control.ContextMenu;
  51 import javafx.scene.control.Label;
  52 import javafx.scene.control.ListView;
  53 import javafx.scene.control.Menu;
  54 import javafx.scene.control.MenuBar;
  55 import javafx.scene.control.MenuItem;
  56 import javafx.scene.control.RadioMenuItem;
  57 import javafx.scene.control.Pagination;
  58 import javafx.scene.control.SelectionMode;
  59 import javafx.scene.control.Separator;
  60 import javafx.scene.control.SeparatorMenuItem;
  61 import javafx.scene.control.SplitPane;
  62 import javafx.scene.control.TabPane;
  63 import javafx.scene.control.Tab;
  64 import javafx.scene.control.TitledPane;
  65 import javafx.scene.control.TextField;
  66 import javafx.scene.control.ToolBar;
  67 import javafx.scene.image.Image;
  68 import javafx.scene.image.ImageView;
  69 import javafx.scene.input.KeyCharacterCombination;
  70 import javafx.scene.input.KeyCombination;
  71 import javafx.scene.layout.HBox;
  72 import javafx.scene.layout.StackPane;
  73 import javafx.scene.paint.Color;
  74 import javafx.scene.shape.Line;
  75 import javafx.scene.shape.Rectangle;
  76 
  77 /**
  78  * Helper static methods for Sample Page
  79  */
  80 public class SamplePageHelpers {
  81     
  82     static <T extends Node> T withState(T node, String state) {
  83         if (node != null && state != null) {
  84             // stop user from being able to change state
  85             node.setMouseTransparent(true);
  86             node.setFocusTraversable(false);
  87             // set state to chosen state
  88             final String[] pseudoClasses = (state).split("[\\s,]+");
  89             for (String pseudoClass : pseudoClasses) {
  90                 node.pseudoClassStateChanged(PseudoClass.getPseudoClass(pseudoClass), true);
  91             }
  92         }
  93         return node;
  94     }
  95     
  96     static <T extends Node> T withState(final T node, final String state, final String subNodeStyleClass, final String subNodeState) {
  97         withState(node, state);
  98         Platform.runLater(() -> withState(node.lookup(subNodeStyleClass), subNodeState));
  99         return node;
 100     }
 101     
 102     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"};
 103     
 104     static ObservableList<String> sampleItems() {
 105         return sampleItems(7);
 106     }
 107     
 108     static ObservableList<String> sampleItems(int numberOfItems) {
 109         ArrayList<String> items = new ArrayList<String>();
 110         if (numberOfItems < 26) {
 111             for(int i=0; i<numberOfItems; i++) {
 112                 items.add("Item "+LETTERS[i]);
 113             }
 114         } else {
 115             for(int i=0; i<numberOfItems; i++) {
 116                 items.add("Item "+i);
 117             }
 118         }
 119         return FXCollections.observableArrayList(items);
 120     }
 121     
 122     static Node scrollPaneContent() {
 123         Line l1 = new Line();
 124         l1.setEndX(200);
 125         l1.setEndY(200);
 126         l1.setStroke(Color.DODGERBLUE);
 127         Line l2 = new Line();
 128         l2.setStartX(200);
 129         l2.setStartY(0);
 130         l2.setEndY(200);
 131         l2.setStroke(Color.DODGERBLUE);
 132         return new Group(new Rectangle(200, 200, Color.PALETURQUOISE), l1, l2);
 133     }
 134     
 135     static Node createTabPane(int numOfTabs, int prefWidth, int prefHeight, String firstTabText, boolean floating, boolean disableFirst, Side side) {
 136         TabPane tabPane = new TabPane();
 137         tabPane.setSide(side);
 138         if (floating) tabPane.getStyleClass().add("floating");
 139         for (int i=1; i<=numOfTabs; i++) {
 140             Tab tab = new Tab("Tab "+i);
 141             tab.setDisable(i==1 && disableFirst);
 142             tab.setContent(new Label((i==1 && firstTabText!=null)? firstTabText :"Tab "+i+" Content"));
 143             tabPane.getTabs().add(tab);
 144         }
 145         if (disableFirst) tabPane.getSelectionModel().select(1);
 146         tabPane.setPrefWidth(prefWidth);
 147         tabPane.setPrefHeight(prefHeight);
 148         return tabPane;
 149     }
 150     
 151     static Node wrapBdr(Node node) {
 152         StackPane sp = new StackPane(node);
 153         sp.setStyle("-fx-border-color: black; -fx-border-width: 3;");
 154         return sp;
 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                 new TitledPane("Title 1", new Label("Content\nLine2.")),
 194                 new TitledPane("Title 2", new Label("Content\nLine2.")),
 195                 new TitledPane("Title 3", new Label("Content\nLine2."))
 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 
 325         menuItems.add(new CheckMenuItem("Check"));
 326         CheckMenuItem checkMenuItem = new CheckMenuItem("Check Selected");
 327         checkMenuItem.setSelected(true);
 328         menuItems.add(checkMenuItem);
 329         menuItems.add(new SeparatorMenuItem());
 330         menuItems.add(new RadioMenuItem("Radio"));
 331         RadioMenuItem radioMenuItem = new RadioMenuItem("Radio Selected");
 332         radioMenuItem.setSelected(true);
 333         menuItems.add(radioMenuItem);
 334         menuItems.add(new SeparatorMenuItem());
 335         menuItems.add(menu15);
 336 
 337         // --- Menu 11 submenu
 338         final MenuItem menu111 = new MenuItem("blah");
 339         final MenuItem menu112 = new MenuItem("foo");
 340         final CheckMenuItem menu113 = new CheckMenuItem("Show \"foo\" item");
 341         menu113.setSelected(true);
 342         menu113.selectedProperty().addListener(valueModel -> {
 343             menu112.setVisible(menu113.isSelected());
 344             System.err.println("MenuItem \"foo\" is now " + (menu112.isVisible() ? "" : "not") + " visible.");
 345         });
 346         menu11.getItems().addAll(menu111, menu112, menu113);
 347 
 348         // --- Menu 13 submenu
 349         MenuItem menu131 = new MenuItem("Item _1");
 350         MenuItem menu132 = new MenuItem("Item _2");
 351         menu13.getItems().addAll(menu131, menu132);
 352         
 353         return menuItems.toArray(new MenuItem[menuItems.size()]);
 354     }
 355     
 356     static final Image recorder48 = new Image(SamplePageHelpers.class.getResource("recorder-icon-48.png").toExternalForm());
 357     
 358     static ImageView createGraphic() {
 359         return new ImageView(recorder48);
 360     }
 361     
 362     static Node createGreyButton(double percentageGrey) {
 363         int grey = (int)(percentageGrey*255);
 364         int percentage = (int)(percentageGrey * 100);
 365         StackPane sp = new StackPane();
 366         sp.setStyle("-fx-base: rgba("+grey+","+grey+","+grey+",1); -fx-background-color: -fx-background;");
 367         sp.setPadding(new Insets(8));
 368         sp.getChildren().add(new Button(percentage+"%"));
 369         return sp;
 370     }
 371 }