All Downloads are FREE. Search and download functionalities are using the official Maven repository.

impl.org.controlsfx.tableview2.NestedTableColumnHeader2 Maven / Gradle / Ivy

/**
 * Copyright (c) 2013, 2020 ControlsFX
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *     * Neither the name of ControlsFX, any associated website, nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package impl.org.controlsfx.tableview2;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumnBase;
import javafx.scene.control.skin.NestedTableColumnHeader;
import javafx.scene.control.skin.TableColumnHeader;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Rectangle;
import org.controlsfx.control.tableview2.TableView2;

/**
 * A cell column header.
 */
public class NestedTableColumnHeader2 extends NestedTableColumnHeader {

    int lastColumnResized = -1;
    private TableView2Skin skin;
    private TableView2 tableView;
    
    public NestedTableColumnHeader2(TableColumnBase tc) {
        super(tc);
    }
    
    private void init() {
        this.skin = (TableView2Skin) getTableSkin();
        this.tableView = (TableView2) skin.getSkinnable();
        /**
         * Resolve https://bitbucket.org/controlsfx/controlsfx/issue/395
         * and https://bitbucket.org/controlsfx/controlsfx/issue/434
         */
        widthProperty().addListener((Observable observable) -> {
            this.skin.hBarValue.clear();
        });
        
        getColumnHeaders().addListener((Observable o) ->
            this.skin.getTableHeaderRow2().updateVisibleLeafColumnHeaders());
        tableView.getVisibleLeafColumns().addListener((Observable o) ->
            this.skin.getTableHeaderRow2().updateVisibleLeafColumnHeaders());
    }

    
    /** {@inheritDoc} */
    @Override protected TableColumnHeader createTableColumnHeader(final TableColumnBase col) {
        if (col == null || col.getColumns().isEmpty() || col == getTableColumn())  {
            final TableColumnHeader tableColumnHeader = new TableColumnHeader(col);
            addMousePressedListener(tableColumnHeader);
            addMouseReleasedListener(tableColumnHeader);
            return tableColumnHeader;
        } else {
            final NestedTableColumnHeader2 rootHeader = new NestedTableColumnHeader2(col);
            final ObservableList rootChildren = rootHeader.getChildren();
            rootChildren.addListener(new InvalidationListener() {
                @Override
                public void invalidated(Observable o) {
                    if (rootChildren.size() > 0) {
                        final TableColumnHeader tableColumnHeader = (TableColumnHeader) rootChildren.get(0);
                        addMouseReleasedListener(tableColumnHeader);
                        rootChildren.removeListener(this);
                    }
                }
            });
            addMousePressedListener(rootHeader);
            return rootHeader;
        }
    }

    /** {@inheritDoc} */
    @Override protected void layoutChildren() {
        super.layoutChildren();
        layoutFixedColumns();
        updateDragRectangles();
    }

    /**
     * We want ColumnHeader to be fixed when we freeze some columns
     */
    public void layoutFixedColumns() {
        if (skin == null && tableView == null) {
            init();
        }
        
        if (skin == null || getChildren().isEmpty()) {
            return;
        }
        double h = getHeight() - snappedTopInset() - snappedBottomInset();
        double hbarValue = skin.getHBar().getValue();

        final int labelHeight = (int) getChildren().get(0).prefHeight(-1);
        double fixedColumnWidth = 0;
        double x = snappedLeftInset();
        int max = getColumnHeaders().size();
        max = max > tableView.getVisibleLeafColumns().size() ? tableView.getVisibleLeafColumns().size() : max;
        max = max > tableView.getColumns().size() ? tableView.getColumns().size() : max;
        for (int j = 0; j < max; j++) {
            final TableColumnHeader n = getColumnHeaders().get(j);
            if (! n.isVisible()) {
                continue;
            }
            
            final double prefWidth = snapSize(n.prefWidth(-1));
            n.resize(prefWidth, snapSize(h - labelHeight));
            //If the column is fixed
            TableColumn column = (TableColumn) n.getTableColumn();
            boolean isLeafColumn = column.getParentColumn() != null;
            while (column.getParentColumn() != null) {
                column = (TableColumn) column.getParentColumn();
            }
            if (tableView.isColumnFixingEnabled() && tableView.getFixedColumns().contains(column)) {
                double tableCellX = 0;
                //If the column is hidden we have to translate it
                if (hbarValue + fixedColumnWidth > x) {
                    
                    tableCellX = Math.abs((isLeafColumn ? 0 : hbarValue) + fixedColumnWidth - x);

                    n.toFront();
                    fixedColumnWidth += prefWidth;
                }
                n.relocate(x + tableCellX, labelHeight + snappedTopInset());
            }

            x += prefWidth;
        }
    }
    
    private void updateDragRectangles() {
        // remove drag rectangles from left border as sometimes they are placed 
        // at the origin and it doesn't make sense allowing resizing the row 
        // header or the first column from the left side
        getChildren().removeIf(r -> (r instanceof Rectangle) &&
                (r.getLayoutX() < 1 || (tableView.getParent() instanceof RowHeader)));
    }
    
    /**
     * If a dragging event to reorder the column is cancelled, when the mouse 
     * is released, the column is marked as reorderable so it can be reordered 
     * again.
     */
    private void addMouseReleasedListener(TableColumnHeader tableColumnHeader) {
        tableColumnHeader.addEventFilter(MouseEvent.MOUSE_RELEASED, e -> {
            TableColumnHeader reorderingRegion = skin.getTableHeaderRow2().getReorderingRegion();
            if (tableColumnHeader.equals(reorderingRegion)) {
                tableColumnHeader.getTableColumn().setReorderable(true);
            }
            if (e.getButton() != MouseButton.PRIMARY) {
                // consume event to avoid sorting after right-click
                e.consume();
            }
        });
    }
    
    // fix JDK-8161054
    private void addMousePressedListener(TableColumnHeader tableColumnHeader) {
        tableColumnHeader.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
            ContextMenu menu = tableColumnHeader.getTableColumn().getContextMenu();
            if (menu != null && menu.isShowing()) {
                menu.hide();
            }  
        });
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy