Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.scene.control.skin;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.property.ObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.collections.WeakListChangeListener;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.AccessibleAttribute;
import javafx.scene.Node;
import javafx.scene.control.Control;
import javafx.scene.control.FocusModel;
import javafx.scene.control.IndexedCell;
import javafx.scene.control.Label;
import javafx.scene.control.ResizeFeaturesBase;
import javafx.scene.control.ScrollToEvent;
import javafx.scene.control.SelectionModel;
import javafx.scene.control.TableColumnBase;
import javafx.scene.control.TableFocusModel;
import javafx.scene.control.TablePositionBase;
import javafx.scene.control.TableSelectionModel;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.util.Callback;
import com.sun.javafx.scene.control.ListenerHelper;
import com.sun.javafx.scene.control.Properties;
import com.sun.javafx.scene.control.skin.resources.ControlResources;
/**
* TableViewSkinBase is the base skin class used by controls such as
* {@link javafx.scene.control.TableView} and {@link javafx.scene.control.TreeTableView}
* (the concrete classes are {@link TableViewSkin} and {@link TreeTableViewSkin},
* respectively).
*
* @param The type of the item stored in each row (for TableView, this is the type
* of the items list, and for TreeTableView, this is the type of the
* TreeItem).
* @param The type of the item, as represented by the selection model (for
* TableView, this is, again, the type of the items list, and for
* TreeTableView, this is TreeItem typed to the same type as M).
* @param The type of the virtualised control (e.g TableView, TreeTableView)
* @param The type of cell used by this virtualised control (e.g. TableRow, TreeTableRow)
* @param The type of TableColumnBase used by this virtualised control (e.g. TableColumn, TreeTableColumn)
*
* @since 9
* @see TableView
* @see TreeTableView
* @see TableViewSkin
* @see TreeTableViewSkin
*/
public abstract class TableViewSkinBase, TC extends TableColumnBase> extends VirtualContainerBase {
/* *************************************************************************
* *
* Static Fields *
* *
**************************************************************************/
private static final double GOLDEN_RATIO_MULTIPLIER = 0.618033987;
// RT-34744 : IS_PANNABLE will be false unless
// javafx.scene.control.skin.TableViewSkin.pannable
// is set to true. This is done in order to make TableView functional
// on embedded systems with touch screens which do not generate scroll
// events for touch drag gestures.
@SuppressWarnings("removal")
private static final boolean IS_PANNABLE =
AccessController.doPrivileged((PrivilegedAction) () -> Boolean.getBoolean("javafx.scene.control.skin.TableViewSkin.pannable"));
/* *************************************************************************
* *
* Internal Fields *
* *
**************************************************************************/
// JDK-8090129: These constants should not be static, because the
// Locale may change between instances.
private final String EMPTY_TABLE_TEXT = ControlResources.getString("TableView.noContent");
private final String NO_COLUMNS_TEXT = ControlResources.getString("TableView.noColumns");
VirtualFlow flow;
private boolean contentWidthDirty = true;
/**
* This region is used to overlay atop the table when the user is performing
* a column resize operation or a column reordering operation. It is a line
* that runs the height of the table to indicate either the final width of
* of the selected column, or the position the column will be 'dropped' into
* when the reordering operation completes.
*/
private Region columnReorderLine;
/**
* A region which is resized and positioned such that it perfectly matches
* the dimensions of any TableColumn that is being reordered by the user.
* This is useful, for example, as a semi-transparent overlay to give
* feedback to the user as to which column is currently being moved.
*/
private Region columnReorderOverlay;
/**
* The entire header region for all columns. This header region handles
* column reordering and resizing. It also handles the positioning and
* resizing of thte columnReorderLine and columnReorderOverlay.
*/
private TableHeaderRow tableHeaderRow;
private Callback rowFactory;
/**
* Region placed over the top of the flow (and possibly the header row) if
* there is no data and/or there are no columns specified.
*/
private StackPane placeholderRegion;
private Label placeholderLabel;
private int visibleColCount;
boolean needCellsRecreated = true;
boolean needCellsReconfigured = false;
private int itemCount = -1;
/* *************************************************************************
* *
* Listeners *
* *
**************************************************************************/
private ListChangeListener rowCountListener = c -> {
while (c.next()) {
if (c.wasReplaced()) {
// RT-28397: Support for when an item is replaced with itself (but
// updated internal values that should be shown visually).
// The ListViewSkin equivalent code here was updated to use the
// flow.setDirtyCell(int) API, but it was left alone here, otherwise
// our unit test for RT-36220 fails as we do not handle the case
// where the TableCell gets updated (only the TableRow does).
// Ideally we would use the dirtyCell API:
//
// for (int i = c.getFrom(); i < c.getTo(); i++) {
// flow.setCellDirty(i);
// }
itemCount = 0;
break;
} else if (c.getRemovedSize() == itemCount) {
// RT-22463: If the user clears out an items list then we
// should reset all cells (in particular their contained
// items) such that a subsequent addition to the list of
// an item which equals the old item (but is rendered
// differently) still displays as expected (i.e. with the
// updated display, not the old display).
itemCount = 0;
break;
}
}
// fix for RT-37853
if (getSkinnable() instanceof TableView) {
((TableView)getSkinnable()).edit(-1, null);
}
markItemCountDirty();
getSkinnable().requestLayout();
};
private InvalidationListener widthListener = observable -> {
// This forces the horizontal scrollbar to show when the column
// resizing occurs. It is not ideal, but will work for now.
// using 'needCellsReconfigured' here rather than 'needCellsRebuilt'
// as otherwise performance suffers massively (RT-27831)
needCellsReconfigured = true;
if (getSkinnable() != null) {
getSkinnable().requestLayout();
}
};
private WeakListChangeListener weakRowCountListener =
new WeakListChangeListener<>(rowCountListener);
private WeakInvalidationListener weakWidthListener =
new WeakInvalidationListener(widthListener);
/* *************************************************************************
* *
* Constructors *
* *
**************************************************************************/
/**
* Constructs a {@code TableViewSkinBase} for the given control.
* @param control the control
*/
public TableViewSkinBase(final C control) {
super(control);
// init the VirtualFlow
flow = getVirtualFlow();
flow.setPannable(IS_PANNABLE);
ListenerHelper lh = ListenerHelper.get(this);
/*
* Listening for scrolling along the X axis, but we need to be careful
* to handle the situation appropriately when the hbar is invisible.
*/
lh.addInvalidationListener(flow.getHbar().valueProperty(), (o) -> {
horizontalScroll();
});
// RT-37152
flow.getHbar().setUnitIncrement(15);
flow.getHbar().setBlockIncrement(TableColumnHeader.DEFAULT_COLUMN_WIDTH);
columnReorderLine = new Region();
columnReorderLine.getStyleClass().setAll("column-resize-line");
columnReorderLine.setManaged(false);
columnReorderLine.setVisible(false);
columnReorderOverlay = new Region();
columnReorderOverlay.getStyleClass().setAll("column-overlay");
columnReorderOverlay.setVisible(false);
columnReorderOverlay.setManaged(false);
tableHeaderRow = createTableHeaderRow();
// tableHeaderRow.setColumnReorderLine(columnReorderLine);
tableHeaderRow.setFocusTraversable(false);
getChildren().addAll(tableHeaderRow, flow, columnReorderOverlay, columnReorderLine);
updateVisibleColumnCount();
updateVisibleLeafColumnWidthListeners(getVisibleLeafColumns(), FXCollections.emptyObservableList());
lh.addInvalidationListener(tableHeaderRow.reorderingProperty(), (ob) -> {
getSkinnable().requestLayout();
});
lh.addListChangeListener(getVisibleLeafColumns(), (c) -> {
updateVisibleColumnCount();
while (c.next()) {
updateVisibleLeafColumnWidthListeners(c.getAddedSubList(), c.getRemoved());
}
});
final ObjectProperty> itemsProperty = TableSkinUtils.itemsProperty(this);
updateTableItems(null, itemsProperty.get());
lh.addInvalidationListener(itemsProperty, new InvalidationListener() {
private WeakReference> weakItemsRef = new WeakReference<>(itemsProperty.get());
@Override public void invalidated(Observable observable) {
ObservableList oldItems = weakItemsRef.get();
weakItemsRef = new WeakReference<>(itemsProperty.get());
updateTableItems(oldItems, itemsProperty.get());
}
});
final ObservableMap