Skip to content

Commit

Permalink
8307960: Create Table Column PopupMenu lazily
Browse files Browse the repository at this point in the history
Reviewed-by: angorya
  • Loading branch information
Marius Hanl committed May 12, 2023
1 parent 7095364 commit 8aff525
Show file tree
Hide file tree
Showing 4 changed files with 443 additions and 9 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2023, 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
Expand Down Expand Up @@ -88,7 +88,7 @@ public class TableHeaderRow extends StackPane {

private final VirtualFlow flow;
final TableViewSkinBase<?,?,?,?,?> tableSkin;
private Map<TableColumnBase, CheckMenuItem> columnMenuItems = new HashMap<>();
private Map<TableColumnBase, CheckMenuItem> columnMenuItems;
private double scrollX;
private double tableWidth;
private Rectangle clip;
Expand Down Expand Up @@ -210,12 +210,6 @@ public TableHeaderRow(final TableViewSkinBase skin) {
tableSkin.getSkinnable().paddingProperty().addListener(weakTablePaddingListener);
TableSkinUtils.getVisibleLeafColumns(skin).addListener(weakVisibleLeafColumnsListener);

// popup menu for hiding/showing columns
columnPopupMenu = new ContextMenu();
updateTableColumnListeners(TableSkinUtils.getColumns(tableSkin), Collections.<TableColumnBase<?,?>>emptyList());
TableSkinUtils.getVisibleLeafColumns(skin).addListener(weakTableColumnsListener);
TableSkinUtils.getColumns(tableSkin).addListener(weakTableColumnsListener);

// drag header region. Used to indicate the current column being reordered
dragHeader = new StackPane();
dragHeader.setVisible(false);
Expand Down Expand Up @@ -264,6 +258,14 @@ public TableHeaderRow(final TableViewSkinBase skin) {
}

cornerRegion.setOnMousePressed(me -> {
if (columnPopupMenu == null) {
columnPopupMenu = new ContextMenu();
columnMenuItems = new HashMap<>();

TableSkinUtils.getVisibleLeafColumns(skin).addListener(weakTableColumnsListener);
TableSkinUtils.getColumns(tableSkin).addListener(weakTableColumnsListener);
updateTableColumnListeners(TableSkinUtils.getColumns(tableSkin), List.of());
}
// show a popupMenu which lists all columns
columnPopupMenu.show(cornerRegion, Side.BOTTOM, 0, 0);
me.consume();
Expand Down Expand Up @@ -696,4 +698,12 @@ private void updateCornerPadding() {
cornerPadding.set(padding);
}

// testing only
Pane getCornerRegion() {
return cornerRegion;
}

ContextMenu getColumnPopupMenu() {
return columnPopupMenu;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2023 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
Expand All @@ -24,6 +24,8 @@
*/
package javafx.scene.control.skin;

import javafx.scene.control.ContextMenu;
import javafx.scene.layout.Pane;
import javafx.scene.control.TableColumnBase;

public class TableHeaderRowShim {
Expand All @@ -32,4 +34,11 @@ public static TableColumnHeader getColumnHeaderFor(TableHeaderRow tr, final Tabl
return tr.getColumnHeaderFor(col);
}

public static ContextMenu getColumnPopupMenu(TableHeaderRow tableHeaderRow) {
return tableHeaderRow.getColumnPopupMenu();
}

public static Pane getCornerRegion(TableHeaderRow tableHeaderRow) {
return tableHeaderRow.getCornerRegion();
}
}
@@ -0,0 +1,207 @@
/*
* Copyright (c) 2023 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 test.javafx.scene.control.skin;

import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.skin.TableHeaderRow;
import javafx.scene.control.skin.TableHeaderRowShim;
import javafx.scene.layout.Pane;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import test.com.sun.javafx.scene.control.infrastructure.MouseEventFirer;
import test.com.sun.javafx.scene.control.infrastructure.StageLoader;
import test.com.sun.javafx.scene.control.infrastructure.VirtualFlowTestUtils;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* Tests for the {@link TableHeaderRow} of a {@link TableView}.
*/
public class TableViewTableHeaderRowTest {

private TableView<String> tableView;
private TableHeaderRow tableHeaderRow;
private Pane cornerRegion;

private StageLoader stageLoader;

@BeforeEach
void setup() {
tableView = new TableView<>();
tableView.setTableMenuButtonVisible(true);

for (int index = 0; index < 10; index++) {
tableView.getColumns().addAll(new TableColumn<String, String>("Column" + index));
}

stageLoader = new StageLoader(tableView);

tableHeaderRow = VirtualFlowTestUtils.getTableHeaderRow(tableView);
cornerRegion = TableHeaderRowShim.getCornerRegion(tableHeaderRow);
}

@AfterEach
void cleanup() {
if (stageLoader != null) {
stageLoader.dispose();
}
}

@Test
void testTableMenuButtonVisibility() {
assertTrue(cornerRegion.isVisible());

tableView.setTableMenuButtonVisible(false);

assertFalse(cornerRegion.isVisible());
}

@Test
void testColumnPopupMenuInitializing() {
ContextMenu columnPopupMenu = TableHeaderRowShim.getColumnPopupMenu(tableHeaderRow);
assertNull(columnPopupMenu);

MouseEventFirer mouseEventFirer = new MouseEventFirer(cornerRegion);
mouseEventFirer.fireMousePressed();

columnPopupMenu = TableHeaderRowShim.getColumnPopupMenu(tableHeaderRow);
assertNotNull(columnPopupMenu);

assertEquals(tableView.getColumns().size(), columnPopupMenu.getItems().size());

for (int index = 0; index < 10; index++) {
String columnText = tableView.getColumns().get(index).getText();
String columnPopupItemText = columnPopupMenu.getItems().get(index).getText();
assertEquals(columnText, columnPopupItemText);
}
}

@Test
void testColumnPopupMenuColumnTextChanged() {
MouseEventFirer mouseEventFirer = new MouseEventFirer(cornerRegion);
mouseEventFirer.fireMousePressed();

ContextMenu columnPopupMenu = TableHeaderRowShim.getColumnPopupMenu(tableHeaderRow);

TableColumn<String, ?> firstColumn = tableView.getColumns().get(0);
MenuItem firstMenuItem = columnPopupMenu.getItems().get(0);
assertEquals(firstColumn.getText(), firstMenuItem.getText());

String newColumnText = "MyNewColumnText";
assertNotEquals(newColumnText, firstMenuItem.getText());

firstColumn.setText(newColumnText);
assertEquals(newColumnText, firstMenuItem.getText());
}

@Test
void testColumnPopupMenuColumnVisibility() {
MouseEventFirer mouseEventFirer = new MouseEventFirer(cornerRegion);
mouseEventFirer.fireMousePressed();

ContextMenu columnPopupMenu = TableHeaderRowShim.getColumnPopupMenu(tableHeaderRow);

TableColumn<String, ?> firstColumn = tableView.getColumns().get(0);
CheckMenuItem firstMenuItem = (CheckMenuItem) columnPopupMenu.getItems().get(0);
assertEquals(firstColumn.isVisible(), firstMenuItem.isSelected());
assertTrue(firstMenuItem.isSelected());

firstColumn.setVisible(false);

assertEquals(firstColumn.isVisible(), firstMenuItem.isSelected());
assertFalse(firstMenuItem.isSelected());

firstMenuItem.setSelected(true);

assertEquals(firstColumn.isVisible(), firstMenuItem.isSelected());
assertTrue(firstColumn.isVisible());
}

@Test
void testColumnPopupMenuColumnVisibilityBound() {
MouseEventFirer mouseEventFirer = new MouseEventFirer(cornerRegion);
mouseEventFirer.fireMousePressed();

ContextMenu columnPopupMenu = TableHeaderRowShim.getColumnPopupMenu(tableHeaderRow);

TableColumn<String, ?> firstColumn = tableView.getColumns().get(0);
MenuItem firstMenuItem = columnPopupMenu.getItems().get(0);
assertFalse(firstMenuItem.isDisable());

SimpleBooleanProperty visibilityBinding = new SimpleBooleanProperty(false);
firstColumn.visibleProperty().bind(visibilityBinding);

// Add a column to trigger the column popup menu rebuild.
tableView.getColumns().add(new TableColumn<>("new"));

firstMenuItem = columnPopupMenu.getItems().get(0);
assertTrue(firstMenuItem.isDisable());
}

@Test
void testColumnPopupMenuColumnsAdded() {
MouseEventFirer mouseEventFirer = new MouseEventFirer(cornerRegion);
mouseEventFirer.fireMousePressed();

ContextMenu columnPopupMenu = TableHeaderRowShim.getColumnPopupMenu(tableHeaderRow);

int itemSize = columnPopupMenu.getItems().size();
assertEquals(tableView.getColumns().size(), columnPopupMenu.getItems().size());

tableView.getColumns().addAll(new TableColumn<>("new1"), new TableColumn<>("new2"), new TableColumn<>("new3"));

assertEquals(tableView.getColumns().size(), columnPopupMenu.getItems().size());
assertTrue(columnPopupMenu.getItems().size() > itemSize);
}

@Test
void testColumnPopupMenuColumnsRemoved() {
MouseEventFirer mouseEventFirer = new MouseEventFirer(cornerRegion);
mouseEventFirer.fireMousePressed();

ContextMenu columnPopupMenu = TableHeaderRowShim.getColumnPopupMenu(tableHeaderRow);

int itemSize = columnPopupMenu.getItems().size();
assertEquals(tableView.getColumns().size(), columnPopupMenu.getItems().size());

tableView.getColumns().remove(tableView.getColumns().size() - 3, tableView.getColumns().size());

assertEquals(tableView.getColumns().size(), columnPopupMenu.getItems().size());
assertTrue(columnPopupMenu.getItems().size() < itemSize);
}

}

1 comment on commit 8aff525

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.