1 /*
   2  * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.control;
  27 
  28 import javafx.css.converter.BooleanConverter;
  29 
  30 import java.util.ArrayList;
  31 import java.util.Collections;
  32 import java.util.List;
  33 
  34 import javafx.beans.DefaultProperty;
  35 import javafx.beans.property.BooleanProperty;
  36 import javafx.beans.value.ObservableValue;
  37 import javafx.beans.value.WritableValue;
  38 import javafx.collections.FXCollections;
  39 import javafx.collections.ObservableList;
  40 import javafx.css.CssMetaData;
  41 import javafx.css.StyleableBooleanProperty;
  42 
  43 import javafx.scene.control.skin.MenuBarSkin;
  44 
  45 import javafx.css.Styleable;
  46 import javafx.css.StyleableProperty;
  47 import javafx.scene.AccessibleRole;
  48 
  49 /**
  50  * <p>
  51  * A MenuBar control traditionally is placed at the very top of the user
  52  * interface, and embedded within it are {@link Menu Menus}. To add a menu to
  53  * a menubar, you add it to the {@link #getMenus() menus} ObservableList.
  54  * By default, for each menu added to the menubar, it will be
  55  * represented as a button with the Menu {@link MenuItem#textProperty() text} value displayed.
  56  * <p>
  57  * MenuBar sets focusTraversable to false.
  58  * </p>
  59  *
  60  * To create and populate a {@code MenuBar}, you may do what is shown below.
  61  * Please refer to the {@link Menu} API page for more information on how to
  62  * configure it.
  63  * <pre><code>
  64  * final Menu menu1 = new Menu("File");
  65  * final Menu menu2 = new Menu("Options");
  66  * final Menu menu3 = new Menu("Help");
  67  *
  68  * MenuBar menuBar = new MenuBar();
  69  * menuBar.getMenus().addAll(menu1, menu2, menu3);
  70  * </code></pre>
  71  *
  72  * @see Menu
  73  * @see MenuItem
  74  * @since JavaFX 2.0
  75  */
  76 @DefaultProperty("menus")
  77 public class MenuBar extends Control {
  78 
  79     /***************************************************************************
  80      *                                                                         *
  81      * Constructors                                                            *
  82      *                                                                         *
  83      **************************************************************************/
  84 
  85     /**
  86      * Creates a new empty MenuBar.
  87      */
  88     public MenuBar() {
  89         this((Menu[])null);
  90     }
  91 
  92     /**
  93      * Creates a new MenuBar populated with the given menus.
  94      *
  95      * @param menus The menus to place inside the MenuBar
  96      * @since JavaFX 8u40
  97      */
  98     public MenuBar(Menu... menus) {
  99         getStyleClass().setAll(DEFAULT_STYLE_CLASS);
 100         setAccessibleRole(AccessibleRole.MENU_BAR);
 101 
 102         if (menus != null) {
 103             getMenus().addAll(menus);
 104         }
 105 
 106         // focusTraversable is styleable through css. Calling setFocusTraversable
 107         // makes it look to css like the user set the value and css will not
 108         // override. Initializing focusTraversable by calling applyStyle with null
 109         // StyleOrigin ensures that css will be able to override the value.
 110         ((StyleableProperty<Boolean>)(WritableValue<Boolean>)focusTraversableProperty()).applyStyle(null, Boolean.FALSE);
 111     }
 112 
 113 
 114 
 115     /***************************************************************************
 116      *                                                                         *
 117      * Instance variables                                                      *
 118      *                                                                         *
 119      **************************************************************************/
 120     private ObservableList<Menu> menus = FXCollections.<Menu>observableArrayList();
 121 
 122 
 123     /***************************************************************************
 124      *                                                                         *
 125      * Properties                                                              *
 126      *                                                                         *
 127      **************************************************************************/
 128 
 129     /**
 130      * Use the system menu bar if the current platform supports it.
 131      *
 132      * This should not be set on more than one MenuBar instance per
 133      * Stage. If this property is set to true on more than one
 134      * MenuBar in the same Stage, then the last menu set is allowed
 135      * to modify the system menu bar, and if there is an existing installed
 136      * system menu it is unset and removed from the system menu bar.
 137      *
 138      * Note that trying to uni-directionally bind to this property
 139      * will throw a RuntimeException.  Please use
 140      * bi-directional binding to this property instead.
 141      *
 142      * @return the use system menu bar property
 143      * @since JavaFX 2.1
 144      */
 145     public final BooleanProperty useSystemMenuBarProperty() {
 146         if (useSystemMenuBar == null) {
 147             useSystemMenuBar = new StyleableBooleanProperty() {
 148 
 149                 @Override
 150                 public CssMetaData<MenuBar,Boolean> getCssMetaData() {
 151                     return StyleableProperties.USE_SYSTEM_MENU_BAR;
 152                 }
 153 
 154                 @Override
 155                 public Object getBean() {
 156                     return MenuBar.this;
 157                 }
 158 
 159                 @Override
 160                 public String getName() {
 161                     return "useSystemMenuBar";
 162                 }
 163 
 164                 @Override
 165                 public void bind(final ObservableValue<? extends Boolean> rawObservable) {
 166                     throw new RuntimeException(BIND_MSG);
 167                 }
 168 
 169             };
 170         }
 171         return useSystemMenuBar;
 172     }
 173     private String BIND_MSG =
 174         "cannot uni-directionally bind to the system menu bar - use bindBidrectional instead";
 175 
 176     private BooleanProperty useSystemMenuBar;
 177     public final void setUseSystemMenuBar(boolean value) {
 178         useSystemMenuBarProperty().setValue(value);
 179     }
 180     public final boolean isUseSystemMenuBar() {
 181         return useSystemMenuBar == null ? false : useSystemMenuBar.getValue();
 182     }
 183 
 184 
 185     /***************************************************************************
 186      *                                                                         *
 187      * Public API                                                              *
 188      *                                                                         *
 189      **************************************************************************/
 190 
 191     /**
 192      * The menus to show within this MenuBar. If this ObservableList is modified at
 193      * runtime, the MenuBar will update as expected.
 194      * @return the list of menus to show within this MenuBar
 195      * @see Menu
 196      */
 197     public final ObservableList<Menu> getMenus() {
 198         return menus;
 199     }
 200 
 201     /** {@inheritDoc} */
 202     @Override protected Skin<?> createDefaultSkin() {
 203         return new MenuBarSkin(this);
 204     }
 205 
 206     /***************************************************************************
 207      *                                                                         *
 208      * Stylesheet Handling                                                     *
 209      *                                                                         *
 210      **************************************************************************/
 211 
 212     private static final String DEFAULT_STYLE_CLASS = "menu-bar";
 213 
 214     private static class StyleableProperties {
 215         private static final CssMetaData<MenuBar, Boolean> USE_SYSTEM_MENU_BAR =
 216                 new CssMetaData<MenuBar, Boolean>("-fx-use-system-menu-bar",
 217                                                         BooleanConverter.getInstance(),
 218                                                         false) {
 219             @Override public boolean isSettable(MenuBar n) {
 220                 return n.useSystemMenuBar == null || !n.useSystemMenuBar.isBound();
 221             }
 222 
 223             @Override public StyleableProperty<Boolean> getStyleableProperty(MenuBar n) {
 224                 return (StyleableProperty<Boolean>)(WritableValue<Boolean>)n.useSystemMenuBarProperty();
 225             }
 226         };
 227 
 228         private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
 229         static {
 230             final List<CssMetaData<? extends Styleable, ?>> styleables =
 231                 new ArrayList<CssMetaData<? extends Styleable, ?>>(Control.getClassCssMetaData());
 232             styleables.add(USE_SYSTEM_MENU_BAR);
 233             STYLEABLES = Collections.unmodifiableList(styleables);
 234         }
 235     }
 236 
 237     /**
 238      * @return The CssMetaData associated with this class, which may include the
 239      * CssMetaData of its superclasses.
 240      * @since JavaFX 8.0
 241      */
 242     public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
 243         return StyleableProperties.STYLEABLES;
 244     }
 245 
 246     /**
 247      * {@inheritDoc}
 248      * @since JavaFX 8.0
 249      */
 250     @Override
 251     public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
 252         return getClassCssMetaData();
 253     }
 254 
 255     /**
 256      * Returns the initial focus traversable state of this control, for use
 257      * by the JavaFX CSS engine to correctly set its initial value. This method
 258      * is overridden as by default UI controls have focus traversable set to true,
 259      * but that is not appropriate for this control.
 260      *
 261      * @since 9
 262      */
 263     @Override protected Boolean getInitialFocusTraversable() {
 264         return Boolean.FALSE;
 265     }
 266 
 267 }
 268