Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.control; 027 028import java.util.ArrayList; 029import java.util.Collections; 030import java.util.List; 031import javafx.beans.property.BooleanProperty; 032import javafx.beans.property.DoubleProperty; 033import javafx.beans.property.ObjectProperty; 034import javafx.beans.property.ObjectPropertyBase; 035import javafx.beans.property.SimpleBooleanProperty; 036import javafx.beans.property.SimpleObjectProperty; 037import javafx.collections.FXCollections; 038import javafx.collections.ListChangeListener; 039import javafx.collections.ObservableList; 040import javafx.geometry.Side; 041 042import javafx.css.StyleableDoubleProperty; 043import javafx.css.CssMetaData; 044import javafx.css.PseudoClass; 045import com.sun.javafx.css.converters.SizeConverter; 046import com.sun.javafx.scene.control.skin.TabPaneSkin; 047import javafx.beans.DefaultProperty; 048import javafx.css.Styleable; 049import javafx.css.StyleableProperty; 050 051/** 052 * <p>A control that allows switching between a group of {@link Tab Tabs}. Only one tab 053 * is visible at a time. Tabs are added to the TabPane by using the {@link #getTabs}.</p> 054 * 055 * <p>Tabs in a TabPane can be positioned at any of the four sides by specifying the 056 * {@link Side}. </p> 057 * 058 * <p>A TabPane has two modes floating or recessed. Applying the styleclass STYLE_CLASS_FLOATING 059 * will change the TabPane mode to floating.</p> 060 * 061 * <p>The tabs width and height can be set to a specific size by 062 * setting the min and max for height and width. TabPane default width will be 063 * determined by the largest content width in the TabPane. This is the same for the height. 064 * If a different size is desired the width and height of the TabPane can 065 * be overridden by setting the min, pref and max size.</p> 066 * 067 * <p>When the number of tabs do not fit the TabPane a menu button will appear on the right. 068 * The menu button is used to select the tabs that are currently not visible. 069 * </p> 070 * 071 * <p>Example:</p> 072 * <pre><code> 073 * TabPane tabPane = new TabPane(); 074 * Tab tab = new Tab(); 075 * tab.setText("new tab"); 076 * tab.setContent(new Rectangle(200,200, Color.LIGHTSTEELBLUE)); 077 * tabPane.getTabs().add(tab); 078 * </code></pre> 079 * 080 * @see Tab 081 */ 082@DefaultProperty("tabs") 083public class TabPane extends Control { 084 private static final double DEFAULT_TAB_MIN_WIDTH = 0; 085 086 private static final double DEFAULT_TAB_MAX_WIDTH = Double.MAX_VALUE; 087 088 private static final double DEFAULT_TAB_MIN_HEIGHT = 0; 089 090 private static final double DEFAULT_TAB_MAX_HEIGHT = Double.MAX_VALUE; 091 092 /** 093 * TabPane mode will be changed to floating allowing the TabPane 094 * to be placed alongside other control. 095 */ 096 public static final String STYLE_CLASS_FLOATING = "floating"; 097 098 /** 099 * Constructs a new TabPane. 100 */ 101 public TabPane() { 102 getStyleClass().setAll("tab-pane"); 103 setSelectionModel(new TabPaneSelectionModel(this)); 104 105 tabs.addListener(new ListChangeListener<Tab>() { 106 @Override public void onChanged(Change<? extends Tab> c) { 107 while (c.next()) { 108 for (Tab tab : c.getRemoved()) { 109 if (tab != null && !getTabs().contains(tab)) { 110 tab.setTabPane(null); 111 } 112 } 113 114 for (Tab tab : c.getAddedSubList()) { 115 if (tab != null) { 116 tab.setTabPane(TabPane.this); 117 } 118 } 119 } 120 } 121 }); 122 123 // initialize pseudo-class state 124 Side edge = getSide(); 125 pseudoClassStateChanged(TOP_PSEUDOCLASS_STATE, (edge == Side.TOP)); 126 pseudoClassStateChanged(RIGHT_PSEUDOCLASS_STATE, (edge == Side.RIGHT)); 127 pseudoClassStateChanged(BOTTOM_PSEUDOCLASS_STATE, (edge == Side.BOTTOM)); 128 pseudoClassStateChanged(LEFT_PSEUDOCLASS_STATE, (edge == Side.LEFT)); 129 130 } 131 132 private ObservableList<Tab> tabs = FXCollections.observableArrayList(); 133 134 /** 135 * <p>The tabs to display in this TabPane. Changing this ObservableList will 136 * immediately result in the TabPane updating to display the new contents 137 * of this ObservableList.</p> 138 * 139 * <p>If the tabs ObservableList changes, the selected tab will remain the previously 140 * selected tab, if it remains within this ObservableList. If the previously 141 * selected tab is no longer in the tabs ObservableList, the selected tab will 142 * become the first tab in the ObservableList.</p> 143 */ 144 public final ObservableList<Tab> getTabs() { 145 return tabs; 146 } 147 148 private ObjectProperty<SingleSelectionModel<Tab>> selectionModel = new SimpleObjectProperty<SingleSelectionModel<Tab>>(this, "selectionModel"); 149 150 /** 151 * <p>Sets the model used for tab selection. By changing the model you can alter 152 * how the tabs are selected and which tabs are first or last.</p> 153 */ 154 public final void setSelectionModel(SingleSelectionModel<Tab> value) { selectionModel.set(value); } 155 156 /** 157 * <p>Gets the model used for tab selection.</p> 158 */ 159 public final SingleSelectionModel<Tab> getSelectionModel() { return selectionModel.get(); } 160 161 /** 162 * The selection model used for selecting tabs. 163 */ 164 public final ObjectProperty<SingleSelectionModel<Tab>> selectionModelProperty() { return selectionModel; } 165 166 private ObjectProperty<Side> side; 167 168 /** 169 * <p>The position to place the tabs in this TabPane. Whenever this changes 170 * the TabPane will immediately update the location of the tabs to reflect 171 * this.</p> 172 * 173 */ 174 public final void setSide(Side value) { 175 sideProperty().set(value); 176 } 177 178 /** 179 * The current position of the tabs in the TabPane. The default position 180 * for the tabs is Side.Top. 181 * 182 * @return The current position of the tabs in the TabPane. 183 */ 184 public final Side getSide() { 185 return side == null ? Side.TOP : side.get(); 186 } 187 188 /** 189 * The position of the tabs in the TabPane. 190 */ 191 public final ObjectProperty<Side> sideProperty() { 192 if (side == null) { 193 side = new ObjectPropertyBase<Side>(Side.TOP) { 194 private Side oldSide; 195 @Override protected void invalidated() { 196 197 oldSide = get(); 198 199 pseudoClassStateChanged(TOP_PSEUDOCLASS_STATE, (oldSide == Side.TOP || oldSide == null)); 200 pseudoClassStateChanged(RIGHT_PSEUDOCLASS_STATE, (oldSide == Side.RIGHT)); 201 pseudoClassStateChanged(BOTTOM_PSEUDOCLASS_STATE, (oldSide == Side.BOTTOM)); 202 pseudoClassStateChanged(LEFT_PSEUDOCLASS_STATE, (oldSide == Side.LEFT)); 203 } 204 205 @Override 206 public Object getBean() { 207 return TabPane.this; 208 } 209 210 @Override 211 public String getName() { 212 return "side"; 213 } 214 }; 215 } 216 return side; 217 } 218 219 private ObjectProperty<TabClosingPolicy> tabClosingPolicy; 220 221 /** 222 * <p>Specifies how the TabPane handles tab closing from an end-users 223 * perspective. The options are:</p> 224 * 225 * <ul> 226 * <li> TabClosingPolicy.UNAVAILABLE: Tabs can not be closed by the user 227 * <li> TabClosingPolicy.SELECTED_TAB: Only the currently selected tab will 228 * have the option to be closed, with a graphic next to the tab 229 * text being shown. The graphic will disappear when a tab is no 230 * longer selected. 231 * <li> TabClosingPolicy.ALL_TABS: All tabs will have the option to be 232 * closed. 233 * </ul> 234 * 235 * <p>Refer to the {@link TabClosingPolicy} enumeration for further details.</p> 236 * 237 * The default closing policy is TabClosingPolicy.SELECTED_TAB 238 */ 239 public final void setTabClosingPolicy(TabClosingPolicy value) { 240 tabClosingPolicyProperty().set(value); 241 } 242 243 /** 244 * The closing policy for the tabs. 245 * 246 * @return The closing policy for the tabs. 247 */ 248 public final TabClosingPolicy getTabClosingPolicy() { 249 return tabClosingPolicy == null ? TabClosingPolicy.SELECTED_TAB : tabClosingPolicy.get(); 250 } 251 252 /** 253 * The closing policy for the tabs. 254 */ 255 public final ObjectProperty<TabClosingPolicy> tabClosingPolicyProperty() { 256 if (tabClosingPolicy == null) { 257 tabClosingPolicy = new SimpleObjectProperty<TabClosingPolicy>(this, "tabClosingPolicy", TabClosingPolicy.SELECTED_TAB); 258 } 259 return tabClosingPolicy; 260 } 261 262 private BooleanProperty rotateGraphic; 263 264 /** 265 * <p>Specifies whether the graphic inside a Tab is rotated or not, such 266 * that it is always upright, or rotated in the same way as the Tab text is.</p> 267 * 268 * <p>By default rotateGraphic is set to false, to represent the fact that 269 * the graphic isn't rotated, resulting in it always appearing upright. If 270 * rotateGraphic is set to {@code true}, the graphic will rotate such that it 271 * rotates with the tab text.</p> 272 * 273 */ 274 public final void setRotateGraphic(boolean value) { 275 rotateGraphicProperty().set(value); 276 } 277 278 /** 279 * Returns {@code true} if the graphic inside a Tab is rotated. The 280 * default is {@code false} 281 * 282 * @return the rotatedGraphic state. 283 */ 284 public final boolean isRotateGraphic() { 285 return rotateGraphic == null ? false : rotateGraphic.get(); 286 } 287 288 /** 289 * The rotatedGraphic state of the tabs in the TabPane. 290 */ 291 public final BooleanProperty rotateGraphicProperty() { 292 if (rotateGraphic == null) { 293 rotateGraphic = new SimpleBooleanProperty(this, "rotateGraphic", false); 294 } 295 return rotateGraphic; 296 } 297 298 private DoubleProperty tabMinWidth; 299 300 /** 301 * <p>The minimum width of the tabs in the TabPane. This can be used to limit 302 * the length of text in tabs to prevent truncation. Setting the min equal 303 * to the max will fix the width of the tab. By default the min equals to the max. 304 * 305 * This value can also be set via CSS using {@code -fx-tab-min-width} 306 * 307 * </p> 308 */ 309 public final void setTabMinWidth(double value) { 310 tabMinWidthProperty().setValue(value); 311 } 312 313 /** 314 * The minimum width of the tabs in the TabPane. 315 * 316 * @return The minimum width of the tabs. 317 */ 318 public final double getTabMinWidth() { 319 return tabMinWidth == null ? DEFAULT_TAB_MIN_WIDTH : tabMinWidth.getValue(); 320 } 321 322 /** 323 * The minimum width of the tabs in the TabPane. 324 */ 325 public final DoubleProperty tabMinWidthProperty() { 326 if (tabMinWidth == null) { 327 tabMinWidth = new StyleableDoubleProperty(DEFAULT_TAB_MIN_WIDTH) { 328 329 @Override 330 public CssMetaData<TabPane,Number> getCssMetaData() { 331 return StyleableProperties.TAB_MIN_WIDTH; 332 } 333 334 @Override 335 public Object getBean() { 336 return TabPane.this; 337 } 338 339 @Override 340 public String getName() { 341 return "tabMinWidth"; 342 } 343 }; 344 } 345 return tabMinWidth; 346 } 347 348 /** 349 * <p>Specifies the maximum width of a tab. This can be used to limit 350 * the length of text in tabs. If the tab text is longer than the maximum 351 * width the text will be truncated. Setting the max equal 352 * to the min will fix the width of the tab. By default the min equals to the max 353 * 354 * This value can also be set via CSS using {@code -fx-tab-max-width}.</p> 355 */ 356 private DoubleProperty tabMaxWidth; 357 public final void setTabMaxWidth(double value) { 358 tabMaxWidthProperty().setValue(value); 359 } 360 361 /** 362 * The maximum width of the tabs in the TabPane. 363 * 364 * @return The maximum width of the tabs. 365 */ 366 public final double getTabMaxWidth() { 367 return tabMaxWidth == null ? DEFAULT_TAB_MAX_WIDTH : tabMaxWidth.getValue(); 368 } 369 370 /** 371 * The maximum width of the tabs in the TabPane. 372 */ 373 public final DoubleProperty tabMaxWidthProperty() { 374 if (tabMaxWidth == null) { 375 tabMaxWidth = new StyleableDoubleProperty(DEFAULT_TAB_MAX_WIDTH) { 376 377 @Override 378 public CssMetaData<TabPane,Number> getCssMetaData() { 379 return StyleableProperties.TAB_MAX_WIDTH; 380 } 381 382 @Override 383 public Object getBean() { 384 return TabPane.this; 385 } 386 387 @Override 388 public String getName() { 389 return "tabMaxWidth"; 390 } 391 }; 392 } 393 return tabMaxWidth; 394 } 395 396 private DoubleProperty tabMinHeight; 397 398 /** 399 * <p>The minimum height of the tabs in the TabPane. This can be used to limit 400 * the height in tabs. Setting the min equal to the max will fix the height 401 * of the tab. By default the min equals to the max. 402 * 403 * This value can also be set via CSS using {@code -fx-tab-min-height} 404 * </p> 405 */ 406 public final void setTabMinHeight(double value) { 407 tabMinHeightProperty().setValue(value); 408 } 409 410 /** 411 * The minimum height of the tabs in the TabPane. 412 * 413 * @return The minimum height of the tabs. 414 */ 415 public final double getTabMinHeight() { 416 return tabMinHeight == null ? DEFAULT_TAB_MIN_HEIGHT : tabMinHeight.getValue(); 417 } 418 419 /** 420 * The minimum height of the tab. 421 */ 422 public final DoubleProperty tabMinHeightProperty() { 423 if (tabMinHeight == null) { 424 tabMinHeight = new StyleableDoubleProperty(DEFAULT_TAB_MIN_HEIGHT) { 425 426 @Override 427 public CssMetaData<TabPane,Number> getCssMetaData() { 428 return StyleableProperties.TAB_MIN_HEIGHT; 429 } 430 431 @Override 432 public Object getBean() { 433 return TabPane.this; 434 } 435 436 @Override 437 public String getName() { 438 return "tabMinHeight"; 439 } 440 }; 441 } 442 return tabMinHeight; 443 } 444 445 /** 446 * <p>The maximum height if the tabs in the TabPane. This can be used to limit 447 * the height in tabs. Setting the max equal to the min will fix the height 448 * of the tab. By default the min equals to the max. 449 * 450 * This value can also be set via CSS using -fx-tab-max-height 451 * </p> 452 */ 453 private DoubleProperty tabMaxHeight; 454 public final void setTabMaxHeight(double value) { 455 tabMaxHeightProperty().setValue(value); 456 } 457 458 /** 459 * The maximum height of the tabs in the TabPane. 460 * 461 * @return The maximum height of the tabs. 462 */ 463 public final double getTabMaxHeight() { 464 return tabMaxHeight == null ? DEFAULT_TAB_MAX_HEIGHT : tabMaxHeight.getValue(); 465 } 466 467 /** 468 * <p>The maximum height of the tabs in the TabPane.</p> 469 */ 470 public final DoubleProperty tabMaxHeightProperty() { 471 if (tabMaxHeight == null) { 472 tabMaxHeight = new StyleableDoubleProperty(DEFAULT_TAB_MAX_HEIGHT) { 473 474 @Override 475 public CssMetaData<TabPane,Number> getCssMetaData() { 476 return StyleableProperties.TAB_MAX_HEIGHT; 477 } 478 479 @Override 480 public Object getBean() { 481 return TabPane.this; 482 } 483 484 @Override 485 public String getName() { 486 return "tabMaxHeight"; 487 } 488 }; 489 } 490 return tabMaxHeight; 491 } 492 493 /** {@inheritDoc} */ 494 @Override protected Skin<?> createDefaultSkin() { 495 return new TabPaneSkin(this); 496 } 497 498 /*************************************************************************** 499 * * 500 * Stylesheet Handling * 501 * * 502 **************************************************************************/ 503 504 private static class StyleableProperties { 505 private static final CssMetaData<TabPane,Number> TAB_MIN_WIDTH = 506 new CssMetaData<TabPane,Number>("-fx-tab-min-width", 507 SizeConverter.getInstance(), DEFAULT_TAB_MIN_WIDTH) { 508 509 @Override 510 public boolean isSettable(TabPane n) { 511 return n.tabMinWidth == null || !n.tabMinWidth.isBound(); 512 } 513 514 @Override 515 public StyleableProperty<Number> getStyleableProperty(TabPane n) { 516 return (StyleableProperty<Number>)n.tabMinWidthProperty(); 517 } 518 }; 519 520 private static final CssMetaData<TabPane,Number> TAB_MAX_WIDTH = 521 new CssMetaData<TabPane,Number>("-fx-tab-max-width", 522 SizeConverter.getInstance(), DEFAULT_TAB_MAX_WIDTH) { 523 524 @Override 525 public boolean isSettable(TabPane n) { 526 return n.tabMaxWidth == null || !n.tabMaxWidth.isBound(); 527 } 528 529 @Override 530 public StyleableProperty<Number> getStyleableProperty(TabPane n) { 531 return (StyleableProperty<Number>)n.tabMaxWidthProperty(); 532 } 533 }; 534 535 private static final CssMetaData<TabPane,Number> TAB_MIN_HEIGHT = 536 new CssMetaData<TabPane,Number>("-fx-tab-min-height", 537 SizeConverter.getInstance(), DEFAULT_TAB_MIN_HEIGHT) { 538 539 @Override 540 public boolean isSettable(TabPane n) { 541 return n.tabMinHeight == null || !n.tabMinHeight.isBound(); 542 } 543 544 @Override 545 public StyleableProperty<Number> getStyleableProperty(TabPane n) { 546 return (StyleableProperty<Number>)n.tabMinHeightProperty(); 547 } 548 }; 549 550 private static final CssMetaData<TabPane,Number> TAB_MAX_HEIGHT = 551 new CssMetaData<TabPane,Number>("-fx-tab-max-height", 552 SizeConverter.getInstance(), DEFAULT_TAB_MAX_HEIGHT) { 553 554 @Override 555 public boolean isSettable(TabPane n) { 556 return n.tabMaxHeight == null || !n.tabMaxHeight.isBound(); 557 } 558 559 @Override 560 public StyleableProperty<Number> getStyleableProperty(TabPane n) { 561 return (StyleableProperty<Number>)n.tabMaxHeightProperty(); 562 } 563 }; 564 565 private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; 566 static { 567 final List<CssMetaData<? extends Styleable, ?>> styleables = 568 new ArrayList<CssMetaData<? extends Styleable, ?>>(Control.getClassCssMetaData()); 569 styleables.add(TAB_MIN_WIDTH); 570 styleables.add(TAB_MAX_WIDTH); 571 styleables.add(TAB_MIN_HEIGHT); 572 styleables.add(TAB_MAX_HEIGHT); 573 STYLEABLES = Collections.unmodifiableList(styleables); 574 } 575 } 576 577 /** 578 * @return The CssMetaData associated with this class, which may include the 579 * CssMetaData of its super classes. 580 */ 581 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { 582 return StyleableProperties.STYLEABLES; 583 } 584 585 /** 586 * {@inheritDoc} 587 */ 588 @Override 589 public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() { 590 return getClassCssMetaData(); 591 } 592 593 private static final PseudoClass TOP_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("top"); 594 private static final PseudoClass BOTTOM_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("bottom"); 595 private static final PseudoClass LEFT_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("left"); 596 private static final PseudoClass RIGHT_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("right"); 597 598 599 static class TabPaneSelectionModel extends SingleSelectionModel<Tab> { 600 private final TabPane tabPane; 601 602 public TabPaneSelectionModel(final TabPane t) { 603 if (t == null) { 604 throw new NullPointerException("TabPane can not be null"); 605 } 606 this.tabPane = t; 607 608 // watching for changes to the items list content 609 final ListChangeListener<Tab> itemsContentObserver = new ListChangeListener<Tab>() { 610 @Override public void onChanged(Change<? extends Tab> c) { 611 while (c.next()) { 612 for (Tab tab : c.getRemoved()) { 613 if (tab != null && !tabPane.getTabs().contains(tab)) { 614 if (getSelectedIndex() == 0 && tabPane.getTabs().size() > 0) { 615 clearAndSelect(0); 616 tab.setSelected(false); 617 } 618 if (tab.isSelected()) { 619 tab.setSelected(false); 620 if (c.getFrom() == 0) { 621 if (tabPane.getTabs().size() > 1) { 622 clearSelection(); 623 } 624 } else { 625 selectPrevious(); 626 } 627 } 628 } 629 } 630 if (c.wasAdded() || c.wasRemoved()) { 631 // The selected tab index can be out of sync with the list of tab if 632 // we add or remove tabs before the selected tab. 633 if (getSelectedIndex() != tabPane.getTabs().indexOf(getSelectedItem())) { 634 clearAndSelect(tabPane.getTabs().indexOf(getSelectedItem())); 635 } 636 } 637 } 638 if (getSelectedIndex() == -1 && getSelectedItem() == null && tabPane.getTabs().size() > 0) { 639 selectFirst(); 640 } else if (tabPane.getTabs().isEmpty()) { 641 clearSelection(); 642 } 643 } 644 }; 645 if (this.tabPane.getTabs() != null) { 646 this.tabPane.getTabs().addListener(itemsContentObserver); 647 } 648 } 649 650 // API Implementation 651 @Override public void select(int index) { 652 if (index < 0 || (getItemCount() > 0 && index >= getItemCount()) || 653 (index == getSelectedIndex() && getModelItem(index).isSelected())) { 654 return; 655 } 656 657 // Unselect the old tab 658 if (getSelectedIndex() >= 0 && getSelectedIndex() < tabPane.getTabs().size()) { 659 tabPane.getTabs().get(getSelectedIndex()).setSelected(false); 660 } 661 662 setSelectedIndex(index); 663 664 Tab tab = getModelItem(index); 665 if (tab != null) { 666 setSelectedItem(tab); 667 } 668 669 // Select the new tab 670 if (getSelectedIndex() >= 0 && getSelectedIndex() < tabPane.getTabs().size()) { 671 tabPane.getTabs().get(getSelectedIndex()).setSelected(true); 672 } 673 } 674 675 @Override public void select(Tab tab) { 676 final int itemCount = getItemCount(); 677 678 for (int i = 0; i < itemCount; i++) { 679 final Tab value = getModelItem(i); 680 if (value != null && value.equals(tab)) { 681 select(i); 682 return; 683 } 684 } 685 if (tab != null) { 686 setSelectedItem(tab); 687 } 688 } 689 690 @Override protected Tab getModelItem(int index) { 691 final ObservableList<Tab> items = tabPane.getTabs(); 692 if (items == null) return null; 693 if (index < 0 || index >= items.size()) return null; 694 return items.get(index); 695 } 696 697 @Override protected int getItemCount() { 698 final ObservableList<Tab> items = tabPane.getTabs(); 699 return items == null ? 0 : items.size(); 700 } 701 } 702 703 /** 704 * <p>This specifies how the TabPane handles tab closing from an end-users 705 * perspective. The options are:</p> 706 * 707 * <ul> 708 * <li> TabClosingPolicy.UNAVAILABLE: Tabs can not be closed by the user 709 * <li> TabClosingPolicy.SELECTED_TAB: Only the currently selected tab will 710 * have the option to be closed, with a graphic next to the tab 711 * text being shown. The graphic will disappear when a tab is no 712 * longer selected. 713 * <li> TabClosingPolicy.ALL_TABS: All tabs will have the option to be 714 * closed. 715 * </ul> 716 */ 717 public enum TabClosingPolicy { 718 719 /** 720 * Only the currently selected tab will have the option to be closed, with a 721 * graphic next to the tab text being shown. The graphic will disappear when 722 * a tab is no longer selected. 723 */ 724 SELECTED_TAB, 725 726 /** 727 * All tabs will have the option to be closed. 728 */ 729 ALL_TABS, 730 731 /** 732 * Tabs can not be closed by the user. 733 */ 734 UNAVAILABLE 735 } 736}