1 /* 2 * Copyright (c) 2011, 2017, 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 com.sun.javafx.beans.IDProperty; 29 import com.sun.javafx.scene.control.ControlAcceleratorSupport; 30 import javafx.collections.ObservableSet; 31 import javafx.css.CssMetaData; 32 import javafx.beans.property.BooleanProperty; 33 import javafx.beans.property.ObjectProperty; 34 import javafx.beans.property.ObjectPropertyBase; 35 import javafx.beans.property.SimpleBooleanProperty; 36 import javafx.beans.property.SimpleObjectProperty; 37 import javafx.beans.property.SimpleStringProperty; 38 import javafx.beans.property.StringProperty; 39 import javafx.collections.FXCollections; 40 import javafx.collections.ObservableList; 41 import javafx.css.PseudoClass; 42 import javafx.event.Event; 43 import javafx.event.EventDispatchChain; 44 import javafx.event.EventHandler; 45 import javafx.event.EventTarget; 46 import javafx.event.EventType; 47 import javafx.scene.Node; 48 49 import javafx.css.Styleable; 50 import com.sun.javafx.event.EventHandlerManager; 51 52 import java.lang.ref.WeakReference; 53 import java.util.ArrayList; 54 import java.util.Collections; 55 import java.util.HashMap; 56 import java.util.List; 57 import java.util.Set; 58 59 import javafx.beans.DefaultProperty; 60 import javafx.beans.InvalidationListener; 61 import javafx.beans.property.BooleanPropertyBase; 62 import javafx.beans.property.ReadOnlyBooleanProperty; 63 import javafx.beans.property.ReadOnlyBooleanWrapper; 64 import javafx.beans.property.ReadOnlyObjectProperty; 65 import javafx.beans.property.ReadOnlyObjectWrapper; 66 import javafx.collections.ObservableMap; 67 68 /** 69 * <p>Tabs are placed within a {@link TabPane}, where each tab represents a single 70 * 'page'.</p> 71 * <p>Tabs can contain any {@link Node} such as UI controls or groups 72 * of nodes added to a layout container.</p> 73 * <p>When the user clicks 74 * on a Tab in the TabPane the Tab content becomes visible to the user.</p> 75 * @since JavaFX 2.0 76 */ 77 @DefaultProperty("content") 78 @IDProperty("id") 79 public class Tab implements EventTarget, Styleable { 80 81 /*************************************************************************** 82 * * 83 * Constructors * 84 * * 85 **************************************************************************/ 86 87 /** 88 * Creates a tab with no title. 89 */ 90 public Tab() { 91 this(null); 92 } 93 94 /** 95 * Creates a tab with a text title. 96 * 97 * @param text The title of the tab. 98 */ 99 public Tab(String text) { 100 this(text, null); 101 } 102 103 /** 104 * Creates a tab with a text title and the specified content node. 105 * 106 * @param text The title of the tab. 107 * @param content The content of the tab. 108 * @since JavaFX 8u40 109 */ 110 public Tab(String text, Node content) { 111 setText(text); 112 setContent(content); 113 styleClass.addAll(DEFAULT_STYLE_CLASS); 114 } 115 116 117 /*************************************************************************** 118 * * 119 * Properties * 120 * * 121 **************************************************************************/ 122 123 private StringProperty id; 124 125 /** 126 * Sets the id of this tab. This simple string identifier is useful for 127 * finding a specific Tab within the {@code TabPane}. The default value is {@code null}. 128 * @param value the id of this tab 129 */ 130 public final void setId(String value) { idProperty().set(value); } 131 132 /** 133 * The id of this tab. 134 * 135 * @return The id of the tab. 136 */ 137 @Override 138 public final String getId() { return id == null ? null : id.get(); } 139 140 /** 141 * The id of this tab. 142 * @return the id property of this tab 143 */ 144 public final StringProperty idProperty() { 145 if (id == null) { 146 id = new SimpleStringProperty(this, "id"); 147 } 148 return id; 149 } 150 151 private StringProperty style; 152 153 /** 154 * A string representation of the CSS style associated with this 155 * tab. This is analogous to the "style" attribute of an 156 * HTML element. Note that, like the HTML style attribute, this 157 * variable contains style properties and values and not the 158 * selector portion of a style rule. 159 * <p> 160 * Parsing this style might not be supported on some limited 161 * platforms. It is recommended to use a standalone CSS file instead. 162 * 163 * @param value the style string 164 */ 165 public final void setStyle(String value) { styleProperty().set(value); } 166 167 /** 168 * The CSS style string associated to this tab. 169 * 170 * @return The CSS style string associated to this tab. 171 */ 172 @Override 173 public final String getStyle() { return style == null ? null : style.get(); } 174 175 /** 176 * The CSS style string associated to this tab. 177 * @return the CSS style string property associated to this tab 178 */ 179 public final StringProperty styleProperty() { 180 if (style == null) { 181 style = new SimpleStringProperty(this, "style"); 182 } 183 return style; 184 } 185 186 private ReadOnlyBooleanWrapper selected; 187 188 final void setSelected(boolean value) { 189 selectedPropertyImpl().set(value); 190 } 191 192 /** 193 * <p>Represents whether this tab is the currently selected tab, 194 * To change the selected Tab use {@code tabPane.getSelectionModel().select()} 195 * </p> 196 * @return true if selected 197 */ 198 public final boolean isSelected() { 199 return selected == null ? false : selected.get(); 200 } 201 202 /** 203 * The currently selected tab. 204 * @return the selected tab 205 */ 206 public final ReadOnlyBooleanProperty selectedProperty() { 207 return selectedPropertyImpl().getReadOnlyProperty(); 208 } 209 210 private ReadOnlyBooleanWrapper selectedPropertyImpl() { 211 if (selected == null) { 212 selected = new ReadOnlyBooleanWrapper() { 213 @Override protected void invalidated() { 214 if (getOnSelectionChanged() != null) { 215 Event.fireEvent(Tab.this, new Event(SELECTION_CHANGED_EVENT)); 216 } 217 } 218 219 @Override 220 public Object getBean() { 221 return Tab.this; 222 } 223 224 @Override 225 public String getName() { 226 return "selected"; 227 } 228 }; 229 } 230 return selected; 231 } 232 233 private ReadOnlyObjectWrapper<TabPane> tabPane; 234 235 final void setTabPane(TabPane value) { 236 tabPanePropertyImpl().set(value); 237 } 238 239 /** 240 * <p>A reference to the TabPane that contains this tab instance.</p> 241 * @return the TabPane 242 */ 243 public final TabPane getTabPane() { 244 return tabPane == null ? null : tabPane.get(); 245 } 246 247 /** 248 * The TabPane that contains this tab. 249 * @return the TabPane property 250 */ 251 public final ReadOnlyObjectProperty<TabPane> tabPaneProperty() { 252 return tabPanePropertyImpl().getReadOnlyProperty(); 253 } 254 255 private ReadOnlyObjectWrapper<TabPane> tabPanePropertyImpl() { 256 if (tabPane == null) { 257 tabPane = new ReadOnlyObjectWrapper<TabPane>(this, "tabPane") { 258 private WeakReference<TabPane> oldParent; 259 260 @Override protected void invalidated() { 261 if(oldParent != null && oldParent.get() != null) { 262 oldParent.get().disabledProperty().removeListener(parentDisabledChangedListener); 263 } 264 updateDisabled(); 265 TabPane newParent = get(); 266 if (newParent != null) { 267 newParent.disabledProperty().addListener(parentDisabledChangedListener); 268 } 269 oldParent = new WeakReference<TabPane>(newParent); 270 super.invalidated(); 271 } 272 }; 273 } 274 return tabPane; 275 } 276 277 private final InvalidationListener parentDisabledChangedListener = valueModel -> { 278 updateDisabled(); 279 }; 280 281 private StringProperty text; 282 283 /** 284 * <p>Sets the text to show in the tab to allow the user to differentiate between 285 * the function of each tab. The text is always visible 286 * </p> 287 * @param value the text string 288 */ 289 public final void setText(String value) { 290 textProperty().set(value); 291 } 292 293 /** 294 * The text shown in the tab. 295 * 296 * @return The text shown in the tab. 297 */ 298 public final String getText() { 299 return text == null ? null : text.get(); 300 } 301 302 /** 303 * The text shown in the tab. 304 * @return the text property 305 */ 306 public final StringProperty textProperty() { 307 if (text == null) { 308 text = new SimpleStringProperty(this, "text"); 309 } 310 return text; 311 } 312 313 private ObjectProperty<Node> graphic; 314 315 /** 316 * <p>Sets the graphic to show in the tab to allow the user to differentiate 317 * between the function of each tab. By default the graphic does not rotate 318 * based on the TabPane.tabPosition value, but it can be set to rotate by 319 * setting TabPane.rotateGraphic to true.</p> 320 * @param value the graphic node 321 */ 322 public final void setGraphic(Node value) { 323 graphicProperty().set(value); 324 } 325 326 /** 327 * The graphic shown in the tab. 328 * 329 * @return The graphic shown in the tab. 330 */ 331 public final Node getGraphic() { 332 return graphic == null ? null : graphic.get(); 333 } 334 335 /** 336 * The graphic in the tab. 337 * 338 * @return The graphic in the tab. 339 */ 340 public final ObjectProperty<Node> graphicProperty() { 341 if (graphic == null) { 342 graphic = new SimpleObjectProperty<Node>(this, "graphic"); 343 } 344 return graphic; 345 } 346 347 private ObjectProperty<Node> content; 348 349 /** 350 * <p>The content to show within the main TabPane area. The content 351 * can be any Node such as UI controls or groups of nodes added 352 * to a layout container.</p> 353 * @param value the content node 354 */ 355 public final void setContent(Node value) { 356 contentProperty().set(value); 357 } 358 359 /** 360 * <p>The content associated with the tab.</p> 361 * 362 * @return The content associated with the tab. 363 */ 364 public final Node getContent() { 365 return content == null ? null : content.get(); 366 } 367 368 /** 369 * <p>The content associated with the tab.</p> 370 * @return the content property 371 */ 372 public final ObjectProperty<Node> contentProperty() { 373 if (content == null) { 374 content = new SimpleObjectProperty<Node>(this, "content"); 375 } 376 return content; 377 } 378 379 380 private ObjectProperty<ContextMenu> contextMenu; 381 382 /** 383 * <p>Specifies the context menu to show when the user right-clicks on the tab. 384 * </p> 385 * @param value the context menu 386 */ 387 public final void setContextMenu(ContextMenu value) { 388 contextMenuProperty().set(value); 389 } 390 391 /** 392 * The context menu associated with the tab. 393 * @return The context menu associated with the tab. 394 */ 395 public final ContextMenu getContextMenu() { 396 return contextMenu == null ? null : contextMenu.get(); 397 } 398 399 /** 400 * The context menu associated with the tab. 401 * @return the context menu property 402 */ 403 public final ObjectProperty<ContextMenu> contextMenuProperty() { 404 if (contextMenu == null) { 405 contextMenu = new SimpleObjectProperty<ContextMenu>(this, "contextMenu") { 406 private WeakReference<ContextMenu> contextMenuRef; 407 408 @Override protected void invalidated() { 409 ContextMenu oldMenu = contextMenuRef == null ? null : contextMenuRef.get(); 410 if (oldMenu != null) { 411 ControlAcceleratorSupport.removeAcceleratorsFromScene(oldMenu.getItems(), Tab.this); 412 } 413 414 ContextMenu ctx = get(); 415 contextMenuRef = new WeakReference<>(ctx); 416 417 if (ctx != null) { 418 // if a context menu is set, we need to install any accelerators 419 // belonging to its menu items ASAP into the scene that this 420 // Control is in (if the control is not in a Scene, we will need 421 // to wait until it is and then do it). 422 ControlAcceleratorSupport.addAcceleratorsIntoScene(ctx.getItems(), Tab.this); 423 } 424 } 425 }; 426 } 427 return contextMenu; 428 } 429 430 private BooleanProperty closable; 431 432 /** 433 * <p>Sets {@code true} if the tab is closable. If this is set to {@code false}, 434 * then regardless of the TabClosingPolicy, it will not be 435 * possible for the user to close this tab. Therefore, when this 436 * property is {@code false}, no 'close' button will be shown on the tab. 437 * The default is {@code true}.</p> 438 * 439 * @param value the closable value 440 */ 441 public final void setClosable(boolean value) { 442 closableProperty().set(value); 443 } 444 445 /** 446 * Returns {@code true} if this tab is closable. 447 * 448 * @return {@code true} if the tab is closable. 449 */ 450 public final boolean isClosable() { 451 return closable == null ? true : closable.get(); 452 } 453 454 /** 455 * The closable state for this tab. 456 * @return the closable property 457 */ 458 public final BooleanProperty closableProperty() { 459 if (closable == null) { 460 closable = new SimpleBooleanProperty(this, "closable", true); 461 } 462 return closable; 463 } 464 465 466 /** 467 * <p>Called when the tab becomes selected or unselected.</p> 468 */ 469 public static final EventType<Event> SELECTION_CHANGED_EVENT = 470 new EventType<Event> (Event.ANY, "SELECTION_CHANGED_EVENT"); 471 private ObjectProperty<EventHandler<Event>> onSelectionChanged; 472 473 /** 474 * Defines a function to be called when a selection changed has occurred on the tab. 475 * @param value the on selection changed event handler 476 */ 477 public final void setOnSelectionChanged(EventHandler<Event> value) { 478 onSelectionChangedProperty().set(value); 479 } 480 481 /** 482 * The event handler that is associated with a selection on the tab. 483 * 484 * @return The event handler that is associated with a tab selection. 485 */ 486 public final EventHandler<Event> getOnSelectionChanged() { 487 return onSelectionChanged == null ? null : onSelectionChanged.get(); 488 } 489 490 /** 491 * The event handler that is associated with a selection on the tab. 492 * @return the on selection changed event handler property 493 */ 494 public final ObjectProperty<EventHandler<Event>> onSelectionChangedProperty() { 495 if (onSelectionChanged == null) { 496 onSelectionChanged = new ObjectPropertyBase<EventHandler<Event>>() { 497 @Override protected void invalidated() { 498 setEventHandler(SELECTION_CHANGED_EVENT, get()); 499 } 500 501 @Override 502 public Object getBean() { 503 return Tab.this; 504 } 505 506 @Override 507 public String getName() { 508 return "onSelectionChanged"; 509 } 510 }; 511 } 512 return onSelectionChanged; 513 } 514 515 /** 516 * <p>Called when a user closes this tab. This is useful for freeing up memory.</p> 517 */ 518 public static final EventType<Event> CLOSED_EVENT = new EventType<Event>(Event.ANY, "TAB_CLOSED"); 519 private ObjectProperty<EventHandler<Event>> onClosed; 520 521 /** 522 * Defines a function to be called when the tab is closed. 523 * @param value the on closed event handler 524 */ 525 public final void setOnClosed(EventHandler<Event> value) { 526 onClosedProperty().set(value); 527 } 528 529 /** 530 * The event handler that is associated with the tab when the tab is closed. 531 * 532 * @return The event handler that is associated with the tab when the tab is closed. 533 */ 534 public final EventHandler<Event> getOnClosed() { 535 return onClosed == null ? null : onClosed.get(); 536 } 537 538 /** 539 * The event handler that is associated with the tab when the tab is closed. 540 * @return the on closed event handler property 541 */ 542 public final ObjectProperty<EventHandler<Event>> onClosedProperty() { 543 if (onClosed == null) { 544 onClosed = new ObjectPropertyBase<EventHandler<Event>>() { 545 @Override protected void invalidated() { 546 setEventHandler(CLOSED_EVENT, get()); 547 } 548 549 @Override 550 public Object getBean() { 551 return Tab.this; 552 } 553 554 @Override 555 public String getName() { 556 return "onClosed"; 557 } 558 }; 559 } 560 return onClosed; 561 } 562 563 private ObjectProperty<Tooltip> tooltip; 564 565 /** 566 * <p>Specifies the tooltip to show when the user hovers over the tab.</p> 567 * @param value the tool tip value 568 */ 569 public final void setTooltip(Tooltip value) { tooltipProperty().setValue(value); } 570 571 /** 572 * The tooltip associated with this tab. 573 * @return The tooltip associated with this tab. 574 */ 575 public final Tooltip getTooltip() { return tooltip == null ? null : tooltip.getValue(); } 576 577 /** 578 * The tooltip associated with this tab. 579 * @return the tool tip property 580 */ 581 public final ObjectProperty<Tooltip> tooltipProperty() { 582 if (tooltip == null) { 583 tooltip = new SimpleObjectProperty<Tooltip>(this, "tooltip"); 584 } 585 return tooltip; 586 } 587 588 private final ObservableList<String> styleClass = FXCollections.observableArrayList(); 589 590 private BooleanProperty disable; 591 592 /** 593 * Sets the disabled state of this tab. 594 * 595 * @param value the state to set this tab 596 * 597 * @defaultValue false 598 * @since JavaFX 2.2 599 */ 600 public final void setDisable(boolean value) { 601 disableProperty().set(value); 602 } 603 604 /** 605 * Returns {@code true} if this tab is disable. 606 * @return true if this tab is disable 607 * @since JavaFX 2.2 608 */ 609 public final boolean isDisable() { return disable == null ? false : disable.get(); } 610 611 /** 612 * Sets the disabled state of this tab. A disable tab is no longer interactive 613 * or traversable, but the contents remain interactive. A disable tab 614 * can be selected using {@link TabPane#getSelectionModel()}. 615 * 616 * @return the disable property 617 * @defaultValue false 618 * @since JavaFX 2.2 619 */ 620 public final BooleanProperty disableProperty() { 621 if (disable == null) { 622 disable = new BooleanPropertyBase(false) { 623 @Override 624 protected void invalidated() { 625 updateDisabled(); 626 } 627 628 @Override 629 public Object getBean() { 630 return Tab.this; 631 } 632 633 @Override 634 public String getName() { 635 return "disable"; 636 } 637 }; 638 } 639 return disable; 640 } 641 642 private ReadOnlyBooleanWrapper disabled; 643 644 private final void setDisabled(boolean value) { 645 disabledPropertyImpl().set(value); 646 } 647 648 /** 649 * Returns true when the {@code Tab} {@link #disableProperty disable} is set to 650 * {@code true} or if the {@code TabPane} is disabled. 651 * @return true if the TabPane is disabled 652 * @since JavaFX 2.2 653 */ 654 public final boolean isDisabled() { 655 return disabled == null ? false : disabled.get(); 656 } 657 658 /** 659 * Indicates whether or not this {@code Tab} is disabled. A {@code Tab} 660 * will become disabled if {@link #disableProperty disable} is set to {@code true} on either 661 * itself or if the {@code TabPane} is disabled. 662 * 663 * @return the disabled property 664 * @defaultValue false 665 * @since JavaFX 2.2 666 */ 667 public final ReadOnlyBooleanProperty disabledProperty() { 668 return disabledPropertyImpl().getReadOnlyProperty(); 669 } 670 671 private ReadOnlyBooleanWrapper disabledPropertyImpl() { 672 if (disabled == null) { 673 disabled = new ReadOnlyBooleanWrapper() { 674 @Override 675 public Object getBean() { 676 return Tab.this; 677 } 678 679 @Override 680 public String getName() { 681 return "disabled"; 682 } 683 }; 684 } 685 return disabled; 686 } 687 688 private void updateDisabled() { 689 boolean disabled = isDisable() || (getTabPane() != null && getTabPane().isDisabled()); 690 setDisabled(disabled); 691 692 // Fix for RT-24658 - content should be disabled if the tab is disabled 693 Node content = getContent(); 694 if (content != null) { 695 content.setDisable(disabled); 696 } 697 } 698 699 /** 700 * Called when there is an external request to close this {@code Tab}. 701 * The installed event handler can prevent tab closing by consuming the 702 * received event. 703 * @since JavaFX 8.0 704 */ 705 public static final EventType<Event> TAB_CLOSE_REQUEST_EVENT = new EventType<Event> (Event.ANY, "TAB_CLOSE_REQUEST_EVENT"); 706 707 /** 708 * Called when there is an external request to close this {@code Tab}. 709 * The installed event handler can prevent tab closing by consuming the 710 * received event. 711 * @since JavaFX 8.0 712 */ 713 private ObjectProperty<EventHandler<Event>> onCloseRequest; 714 public final ObjectProperty<EventHandler<Event>> onCloseRequestProperty() { 715 if (onCloseRequest == null) { 716 onCloseRequest = new ObjectPropertyBase<EventHandler<Event>>() { 717 @Override protected void invalidated() { 718 setEventHandler(TAB_CLOSE_REQUEST_EVENT, get()); 719 } 720 721 @Override public Object getBean() { 722 return Tab.this; 723 } 724 725 @Override public String getName() { 726 return "onCloseRequest"; 727 } 728 }; 729 } 730 return onCloseRequest; 731 } 732 733 public EventHandler<Event> getOnCloseRequest() { 734 if( onCloseRequest == null ) { 735 return null; 736 } 737 return onCloseRequest.get(); 738 } 739 740 public void setOnCloseRequest(EventHandler<Event> value) { 741 onCloseRequestProperty().set(value); 742 } 743 744 745 // --- Properties 746 private static final Object USER_DATA_KEY = new Object(); 747 748 // A map containing a set of properties for this Tab 749 private ObservableMap<Object, Object> properties; 750 751 /** 752 * Returns an observable map of properties on this Tab for use primarily 753 * by application developers. 754 * 755 * @return an observable map of properties on this Tab for use primarily 756 * by application developers 757 * @since JavaFX 2.2 758 */ 759 public final ObservableMap<Object, Object> getProperties() { 760 if (properties == null) { 761 properties = FXCollections.observableMap(new HashMap<Object, Object>()); 762 } 763 return properties; 764 } 765 766 /** 767 * Tests if this Tab has properties. 768 * @return true if this tab has properties. 769 * @since JavaFX 2.2 770 */ 771 public boolean hasProperties() { 772 return properties != null && !properties.isEmpty(); 773 } 774 775 776 // --- UserData 777 /** 778 * Convenience method for setting a single Object property that can be 779 * retrieved at a later date. This is functionally equivalent to calling 780 * the getProperties().put(Object key, Object value) method. This can later 781 * be retrieved by calling {@link Tab#getUserData()}. 782 * 783 * @param value The value to be stored - this can later be retrieved by calling 784 * {@link Tab#getUserData()}. 785 * @since JavaFX 2.2 786 */ 787 public void setUserData(Object value) { 788 getProperties().put(USER_DATA_KEY, value); 789 } 790 791 /** 792 * Returns a previously set Object property, or null if no such property 793 * has been set using the {@link Tab#setUserData(java.lang.Object)} method. 794 * 795 * @return The Object that was previously set, or null if no property 796 * has been set or if null was set. 797 * @since JavaFX 2.2 798 */ 799 public Object getUserData() { 800 return getProperties().get(USER_DATA_KEY); 801 } 802 803 /** 804 * A list of String identifiers which can be used to logically group 805 * Nodes, specifically for an external style engine. This variable is 806 * analogous to the "class" attribute on an HTML element and, as such, 807 * each element of the list is a style class to which this Node belongs. 808 * 809 * @see <a href="http://www.w3.org/TR/css3-selectors/#class-html">CSS3 class selectors</a> 810 */ 811 @Override 812 public ObservableList<String> getStyleClass() { 813 return styleClass; 814 } 815 816 private final EventHandlerManager eventHandlerManager = 817 new EventHandlerManager(this); 818 819 /** {@inheritDoc} */ 820 @Override 821 public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) { 822 return tail.prepend(eventHandlerManager); 823 } 824 825 <E extends Event> void setEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) { 826 eventHandlerManager.setEventHandler(eventType, eventHandler); 827 } 828 829 /* 830 * See Node#lookup(String) 831 */ 832 Node lookup(String selector) { 833 if (selector == null) return null; 834 Node n = null; 835 if (getContent() != null) { 836 n = getContent().lookup(selector); 837 } 838 if (n == null && getGraphic() != null) { 839 n = getGraphic().lookup(selector); 840 } 841 return n; 842 } 843 844 /* 845 * See Node#lookupAll(String) 846 */ 847 List<Node> lookupAll(String selector) { 848 final List<Node> results = new ArrayList<>(); 849 if (getContent() != null) { 850 Set set = getContent().lookupAll(selector); 851 if (!set.isEmpty()) { 852 results.addAll(set); 853 } 854 } 855 if (getGraphic() != null) { 856 Set set = getGraphic().lookupAll(selector); 857 if (!set.isEmpty()) { 858 results.addAll(set); 859 } 860 } 861 return results; 862 } 863 864 865 /*************************************************************************** 866 * * 867 * Stylesheet Handling * 868 * * 869 **************************************************************************/ 870 871 private static final String DEFAULT_STYLE_CLASS = "tab"; 872 873 /** 874 * {@inheritDoc} 875 * @return "Tab" 876 * @since JavaFX 8.0 877 */ 878 @Override 879 public String getTypeSelector() { 880 return "Tab"; 881 } 882 883 /** 884 * {@inheritDoc} 885 * @return {@code getTabPane()} 886 * @since JavaFX 8.0 887 */ 888 @Override 889 public Styleable getStyleableParent() { 890 return getTabPane(); 891 } 892 893 /** 894 * {@inheritDoc} 895 * @since JavaFX 8.0 896 */ 897 public final ObservableSet<PseudoClass> getPseudoClassStates() { 898 return FXCollections.emptyObservableSet(); 899 } 900 901 /** 902 * {@inheritDoc} 903 * @since JavaFX 8.0 904 */ 905 @Override 906 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { 907 return getClassCssMetaData(); 908 } 909 910 /** 911 * @return The CssMetaData associated with this class, which may include the 912 * CssMetaData of its superclasses. 913 * @since JavaFX 8.0 914 */ 915 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { 916 return Collections.emptyList(); 917 } 918 }