1 /*
   2  * Copyright (c) 2010, 2014, 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      * @since JavaFX 2.1
 143      */
 144     public final BooleanProperty useSystemMenuBarProperty() {
 145         if (useSystemMenuBar == null) {
 146             useSystemMenuBar = new StyleableBooleanProperty() {
 147 
 148                 @Override
 149                 public CssMetaData<MenuBar,Boolean> getCssMetaData() {
 150                     return StyleableProperties.USE_SYSTEM_MENU_BAR;
 151                 }
 152 
 153                 @Override
 154                 public Object getBean() {
 155                     return MenuBar.this;
 156                 }
 157 
 158                 @Override
 159                 public String getName() {
 160                     return "useSystemMenuBar";
 161                 }
 162                 
 163                 @Override
 164                 public void bind(final ObservableValue<? extends Boolean> rawObservable) {
 165                     throw new RuntimeException(BIND_MSG);
 166                 }
 167 
 168             };
 169         }
 170         return useSystemMenuBar;
 171     }
 172     private String BIND_MSG =
 173         "cannot uni-directionally bind to the system menu bar - use bindBidrectional instead";
 174                                                
 175     private BooleanProperty useSystemMenuBar;
 176     public final void setUseSystemMenuBar(boolean value) {
 177         useSystemMenuBarProperty().setValue(value);
 178     }
 179     public final boolean isUseSystemMenuBar() {
 180         return useSystemMenuBar == null ? false : useSystemMenuBar.getValue();
 181     }
 182 
 183 
 184     /***************************************************************************
 185      *                                                                         *
 186      * Public API                                                              *
 187      *                                                                         *
 188      **************************************************************************/
 189 
 190     /**
 191      * The menus to show within this MenuBar. If this ObservableList is modified at
 192      * runtime, the MenuBar will update as expected.
 193      * @see Menu
 194      */
 195     public final ObservableList<Menu> getMenus() {
 196         return menus;
 197     }
 198 
 199     /** {@inheritDoc} */
 200     @Override protected Skin<?> createDefaultSkin() {
 201         return new MenuBarSkin(this);
 202     }
 203     
 204     /***************************************************************************
 205      *                                                                         *
 206      * Stylesheet Handling                                                     *
 207      *                                                                         *
 208      **************************************************************************/
 209 
 210     private static final String DEFAULT_STYLE_CLASS = "menu-bar";
 211 
 212     private static class StyleableProperties {
 213         private static final CssMetaData<MenuBar, Boolean> USE_SYSTEM_MENU_BAR =
 214                 new CssMetaData<MenuBar, Boolean>("-fx-use-system-menu-bar",
 215                                                         BooleanConverter.getInstance(),
 216                                                         false) {
 217             @Override public boolean isSettable(MenuBar n) {
 218                 return n.useSystemMenuBar == null || !n.useSystemMenuBar.isBound();
 219             }
 220 
 221             @Override public StyleableProperty<Boolean> getStyleableProperty(MenuBar n) {
 222                 return (StyleableProperty<Boolean>)(WritableValue<Boolean>)n.useSystemMenuBarProperty();
 223             }
 224         };
 225 
 226         private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
 227         static {
 228             final List<CssMetaData<? extends Styleable, ?>> styleables =
 229                 new ArrayList<CssMetaData<? extends Styleable, ?>>(Control.getClassCssMetaData());
 230             styleables.add(USE_SYSTEM_MENU_BAR);
 231             STYLEABLES = Collections.unmodifiableList(styleables);
 232         }
 233     }
 234 
 235     /**
 236      * @return The CssMetaData associated with this class, which may include the
 237      * CssMetaData of its super classes.
 238      * @since JavaFX 8.0
 239      */
 240     public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
 241         return StyleableProperties.STYLEABLES;
 242     }
 243 
 244     /**
 245      * {@inheritDoc}
 246      * @since JavaFX 8.0
 247      */
 248     @Override
 249     public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
 250         return getClassCssMetaData();
 251     }
 252 
 253     /**
 254       * Most Controls return true for focusTraversable, so Control overrides
 255       * this method to return true, but MenuBar returns false for
 256       * focusTraversable's initial value; hence the override of the override. 
 257       * This method is called from CSS code to get the correct initial value.
 258       * @treatAsPrivate implementation detail
 259       */
 260     @Deprecated @Override
 261     protected /*do not make final*/ Boolean impl_cssGetFocusTraversableInitialValue() {
 262         return Boolean.FALSE;
 263     }
 264 
 265 }
 266