From e9c61192cc532b4a75612b6181b8b50cee1c9cc5 Mon Sep 17 00:00:00 2001 From: Nir Lisker Date: Tue, 24 Mar 2020 00:08:09 +0000 Subject: [PATCH 01/10] 8240692: Cleanup of the javafx property objects Reviewed-by: kcr --- .../javafx/binding/BidirectionalBinding.java | 19 +++++++------------ .../beans/property/BooleanProperty.java | 8 ++++---- .../javafx/beans/property/DoubleProperty.java | 19 ++++++------------- .../javafx/beans/property/FloatProperty.java | 11 +++++------ .../beans/property/IntegerProperty.java | 10 +++++----- .../javafx/beans/property/LongProperty.java | 10 +++++----- 6 files changed, 32 insertions(+), 45 deletions(-) diff --git a/modules/javafx.base/src/main/java/com/sun/javafx/binding/BidirectionalBinding.java b/modules/javafx.base/src/main/java/com/sun/javafx/binding/BidirectionalBinding.java index 4868e01d488..b3fe6266abb 100644 --- a/modules/javafx.base/src/main/java/com/sun/javafx/binding/BidirectionalBinding.java +++ b/modules/javafx.base/src/main/java/com/sun/javafx/binding/BidirectionalBinding.java @@ -25,7 +25,6 @@ package com.sun.javafx.binding; -import javafx.beans.Observable; import javafx.beans.WeakListener; import javafx.beans.property.*; import javafx.beans.value.ChangeListener; @@ -35,13 +34,13 @@ import java.lang.ref.WeakReference; import java.text.Format; import java.text.ParseException; +import java.util.Objects; public abstract class BidirectionalBinding implements ChangeListener, WeakListener { private static void checkParameters(Object property1, Object property2) { - if ((property1 == null) || (property2 == null)) { - throw new NullPointerException("Both properties must be specified."); - } + Objects.requireNonNull(property1, "Both properties must be specified."); + Objects.requireNonNull(property2, "Both properties must be specified."); if (property1 == property2) { throw new IllegalArgumentException("Cannot bind property to itself"); } @@ -69,10 +68,8 @@ public static BidirectionalBinding bind(Property property1, Property p public static Object bind(Property stringProperty, Property otherProperty, Format format) { checkParameters(stringProperty, otherProperty); - if (format == null) { - throw new NullPointerException("Format cannot be null"); - } - final StringConversionBidirectionalBinding binding = new StringFormatBidirectionalBinding(stringProperty, otherProperty, format); + Objects.requireNonNull(format, "Format cannot be null"); + final var binding = new StringFormatBidirectionalBinding(stringProperty, otherProperty, format); stringProperty.setValue(format.format(otherProperty.getValue())); stringProperty.addListener(binding); otherProperty.addListener(binding); @@ -81,10 +78,8 @@ public static Object bind(Property stringProperty, Property otherProp public static Object bind(Property stringProperty, Property otherProperty, StringConverter converter) { checkParameters(stringProperty, otherProperty); - if (converter == null) { - throw new NullPointerException("Converter cannot be null"); - } - final StringConversionBidirectionalBinding binding = new StringConverterBidirectionalBinding(stringProperty, otherProperty, converter); + Objects.requireNonNull(converter, "Converter cannot be null"); + final var binding = new StringConverterBidirectionalBinding<>(stringProperty, otherProperty, converter); stringProperty.setValue(converter.toString(otherProperty.getValue())); stringProperty.addListener(binding); otherProperty.addListener(binding); diff --git a/modules/javafx.base/src/main/java/javafx/beans/property/BooleanProperty.java b/modules/javafx.base/src/main/java/javafx/beans/property/BooleanProperty.java index ceca98463dc..25acf463b24 100644 --- a/modules/javafx.base/src/main/java/javafx/beans/property/BooleanProperty.java +++ b/modules/javafx.base/src/main/java/javafx/beans/property/BooleanProperty.java @@ -25,6 +25,8 @@ package javafx.beans.property; +import java.util.Objects; + import com.sun.javafx.binding.BidirectionalBinding; import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; @@ -133,9 +135,7 @@ public String toString() { * @since JavaFX 8.0 */ public static BooleanProperty booleanProperty(final Property property) { - if (property == null) { - throw new NullPointerException("Property cannot be null"); - } + Objects.requireNonNull(property, "Property cannot be null"); return property instanceof BooleanProperty ? (BooleanProperty)property : new BooleanPropertyBase() { { BidirectionalBinding.bind(this, property); @@ -164,7 +164,7 @@ public String getName() { */ @Override public ObjectProperty asObject() { - return new ObjectPropertyBase () { + return new ObjectPropertyBase<> () { { BidirectionalBinding.bind(this, BooleanProperty.this); } diff --git a/modules/javafx.base/src/main/java/javafx/beans/property/DoubleProperty.java b/modules/javafx.base/src/main/java/javafx/beans/property/DoubleProperty.java index fd46236c860..2aedf417eb1 100644 --- a/modules/javafx.base/src/main/java/javafx/beans/property/DoubleProperty.java +++ b/modules/javafx.base/src/main/java/javafx/beans/property/DoubleProperty.java @@ -25,17 +25,14 @@ package javafx.beans.property; +import java.util.Objects; + import com.sun.javafx.binding.BidirectionalBinding; -import com.sun.javafx.binding.ExpressionHelper; +import com.sun.javafx.binding.Logging; + import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; import javafx.beans.value.WritableDoubleValue; -import com.sun.javafx.binding.Logging; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.WeakInvalidationListener; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableDoubleValue; /** * This class defines a {@link Property} wrapping a {@code double} value. @@ -148,9 +145,7 @@ public String toString() { * @since JavaFX 8.0 */ public static DoubleProperty doubleProperty(final Property property) { - if (property == null) { - throw new NullPointerException("Property cannot be null"); - } + Objects.requireNonNull(property, "Property cannot be null"); return new DoublePropertyBase() { { BidirectionalBinding.bindNumber(this, property); @@ -189,7 +184,7 @@ public String getName() { */ @Override public ObjectProperty asObject() { - return new ObjectPropertyBase () { + return new ObjectPropertyBase<> () { { BidirectionalBinding.bindNumber(this, DoubleProperty.this); } @@ -205,6 +200,4 @@ public String getName() { } }; } - - } diff --git a/modules/javafx.base/src/main/java/javafx/beans/property/FloatProperty.java b/modules/javafx.base/src/main/java/javafx/beans/property/FloatProperty.java index 2cec8f08790..b56277a8601 100644 --- a/modules/javafx.base/src/main/java/javafx/beans/property/FloatProperty.java +++ b/modules/javafx.base/src/main/java/javafx/beans/property/FloatProperty.java @@ -25,6 +25,8 @@ package javafx.beans.property; +import java.util.Objects; + import com.sun.javafx.binding.BidirectionalBinding; import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; @@ -142,10 +144,8 @@ public String toString() { * @see #asObject() * @since JavaFX 8.0 */ - public static FloatProperty floatProperty(final Property property) { - if (property == null) { - throw new NullPointerException("Property cannot be null"); - } + public static FloatProperty floatProperty(final Property property) { + Objects.requireNonNull(property, "Property cannot be null"); return new FloatPropertyBase() { { BidirectionalBinding.bindNumber(this, property); @@ -184,7 +184,7 @@ public String getName() { */ @Override public ObjectProperty asObject() { - return new ObjectPropertyBase () { + return new ObjectPropertyBase<> () { { BidirectionalBinding.bindNumber(this, FloatProperty.this); } @@ -200,5 +200,4 @@ public String getName() { } }; } - } diff --git a/modules/javafx.base/src/main/java/javafx/beans/property/IntegerProperty.java b/modules/javafx.base/src/main/java/javafx/beans/property/IntegerProperty.java index d085de4ea2c..81211a9232b 100644 --- a/modules/javafx.base/src/main/java/javafx/beans/property/IntegerProperty.java +++ b/modules/javafx.base/src/main/java/javafx/beans/property/IntegerProperty.java @@ -25,6 +25,8 @@ package javafx.beans.property; +import java.util.Objects; + import com.sun.javafx.binding.BidirectionalBinding; import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; @@ -142,10 +144,8 @@ public String toString() { * @see #asObject() * @since JavaFX 8.0 */ - public static IntegerProperty integerProperty(final Property property) { - if (property == null) { - throw new NullPointerException("Property cannot be null"); - } + public static IntegerProperty integerProperty(final Property property) { + Objects.requireNonNull(property, "Property cannot be null"); return new IntegerPropertyBase() { { BidirectionalBinding.bindNumber(this, property); @@ -184,7 +184,7 @@ public String getName() { */ @Override public ObjectProperty asObject() { - return new ObjectPropertyBase () { + return new ObjectPropertyBase<> () { { BidirectionalBinding.bindNumber(this, IntegerProperty.this); } diff --git a/modules/javafx.base/src/main/java/javafx/beans/property/LongProperty.java b/modules/javafx.base/src/main/java/javafx/beans/property/LongProperty.java index e004aa4f9f2..e8fdeadb0df 100644 --- a/modules/javafx.base/src/main/java/javafx/beans/property/LongProperty.java +++ b/modules/javafx.base/src/main/java/javafx/beans/property/LongProperty.java @@ -25,6 +25,8 @@ package javafx.beans.property; +import java.util.Objects; + import com.sun.javafx.binding.BidirectionalBinding; import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; @@ -140,10 +142,8 @@ public String toString() { * @see #asObject() * @since JavaFX 8.0 */ - public static LongProperty longProperty(final Property property) { - if (property == null) { - throw new NullPointerException("Property cannot be null"); - } + public static LongProperty longProperty(final Property property) { + Objects.requireNonNull(property, "Property cannot be null"); return new LongPropertyBase() { { BidirectionalBinding.bindNumber(this, property); @@ -182,7 +182,7 @@ public String getName() { */ @Override public ObjectProperty asObject() { - return new ObjectPropertyBase () { + return new ObjectPropertyBase<> () { { BidirectionalBinding.bindNumber(this, LongProperty.this); } From 2aa821855e031a2fa193c2de1515c627dbc78ef3 Mon Sep 17 00:00:00 2001 From: Ajit Ghaisas Date: Tue, 24 Mar 2020 05:14:24 +0000 Subject: [PATCH 02/10] 8235480: Regression: [RTL] Arrow keys navigation doesn't respect TableView orientation Reviewed-by: kcr, fastegal --- .../behavior/TableViewBehaviorBase.java | 46 +- .../TableViewHorizontalArrowsTest.java | 401 ++++++++++++++++++ 2 files changed, 428 insertions(+), 19 deletions(-) create mode 100644 modules/javafx.controls/src/test/java/test/javafx/scene/control/TableViewHorizontalArrowsTest.java diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableViewBehaviorBase.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableViewBehaviorBase.java index 887228662bb..000999fb2ff 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableViewBehaviorBase.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableViewBehaviorBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, 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 @@ -146,20 +146,20 @@ public TableViewBehaviorBase(C control) { new KeyMapping(PAGE_UP, e -> scrollUp()), new KeyMapping(PAGE_DOWN, e -> scrollDown()), - new KeyMapping(LEFT, e -> selectLeftCell()), - new KeyMapping(KP_LEFT, e -> selectLeftCell()), - new KeyMapping(RIGHT, e -> selectRightCell()), - new KeyMapping(KP_RIGHT, e -> selectRightCell()), + new KeyMapping(LEFT, e -> { if(isRTL()) selectRightCell(); else selectLeftCell(); }), + new KeyMapping(KP_LEFT,e -> { if(isRTL()) selectRightCell(); else selectLeftCell(); }), + new KeyMapping(RIGHT, e -> { if(isRTL()) selectLeftCell(); else selectRightCell(); }), + new KeyMapping(KP_RIGHT, e -> { if(isRTL()) selectLeftCell(); else selectRightCell(); }), new KeyMapping(UP, e -> selectPreviousRow()), new KeyMapping(KP_UP, e -> selectPreviousRow()), new KeyMapping(DOWN, e -> selectNextRow()), new KeyMapping(KP_DOWN, e -> selectNextRow()), - new KeyMapping(LEFT, FocusTraversalInputMap::traverseLeft), - new KeyMapping(KP_LEFT, FocusTraversalInputMap::traverseLeft), - new KeyMapping(RIGHT, FocusTraversalInputMap::traverseRight), - new KeyMapping(KP_RIGHT, FocusTraversalInputMap::traverseRight), + new KeyMapping(LEFT, e -> { if(isRTL()) focusTraverseRight(); else focusTraverseLeft(); }), + new KeyMapping(KP_LEFT, e -> { if(isRTL()) focusTraverseRight(); else focusTraverseLeft(); }), + new KeyMapping(RIGHT, e -> { if(isRTL()) focusTraverseLeft(); else focusTraverseRight(); }), + new KeyMapping(KP_RIGHT, e -> { if(isRTL()) focusTraverseLeft(); else focusTraverseRight(); }), new KeyMapping(UP, FocusTraversalInputMap::traverseUp), new KeyMapping(KP_UP, FocusTraversalInputMap::traverseUp), new KeyMapping(DOWN, FocusTraversalInputMap::traverseDown), @@ -178,17 +178,17 @@ public TableViewBehaviorBase(C control) { new KeyMapping(new KeyBinding(SPACE).shift(), e -> selectAllToFocus(false)), new KeyMapping(new KeyBinding(SPACE).shortcut().shift(), e -> selectAllToFocus(true)), - new KeyMapping(new KeyBinding(LEFT).shift(), e -> alsoSelectLeftCell()), - new KeyMapping(new KeyBinding(KP_LEFT).shift(), e -> alsoSelectLeftCell()), - new KeyMapping(new KeyBinding(RIGHT).shift(), e -> alsoSelectRightCell()), - new KeyMapping(new KeyBinding(KP_RIGHT).shift(), e -> alsoSelectRightCell()), + new KeyMapping(new KeyBinding(LEFT).shift(), e -> { if(isRTL()) alsoSelectRightCell(); else alsoSelectLeftCell(); }), + new KeyMapping(new KeyBinding(KP_LEFT).shift(), e -> { if(isRTL()) alsoSelectRightCell(); else alsoSelectLeftCell(); }), + new KeyMapping(new KeyBinding(RIGHT).shift(), e -> { if(isRTL()) alsoSelectLeftCell(); else alsoSelectRightCell(); }), + new KeyMapping(new KeyBinding(KP_RIGHT).shift(), e -> { if(isRTL()) alsoSelectLeftCell(); else alsoSelectRightCell(); }), new KeyMapping(new KeyBinding(UP).shortcut(), e -> focusPreviousRow()), new KeyMapping(new KeyBinding(DOWN).shortcut(), e -> focusNextRow()), - new KeyMapping(new KeyBinding(RIGHT).shortcut(), e -> focusRightCell()), - new KeyMapping(new KeyBinding(KP_RIGHT).shortcut(), e -> focusRightCell()), - new KeyMapping(new KeyBinding(LEFT).shortcut(), e -> focusLeftCell()), - new KeyMapping(new KeyBinding(KP_LEFT).shortcut(), e -> focusLeftCell()), + new KeyMapping(new KeyBinding(RIGHT).shortcut(), e -> { if(isRTL()) focusLeftCell(); else focusRightCell(); }), + new KeyMapping(new KeyBinding(KP_RIGHT).shortcut(), e -> { if(isRTL()) focusLeftCell(); else focusRightCell(); }), + new KeyMapping(new KeyBinding(LEFT).shortcut(), e -> { if(isRTL()) focusRightCell(); else focusLeftCell(); }), + new KeyMapping(new KeyBinding(KP_LEFT).shortcut(), e -> { if(isRTL()) focusRightCell(); else focusLeftCell(); }), new KeyMapping(new KeyBinding(A).shortcut(), e -> selectAll()), new KeyMapping(new KeyBinding(HOME).shortcut(), e -> focusFirstRow()), @@ -198,8 +198,8 @@ public TableViewBehaviorBase(C control) { new KeyMapping(new KeyBinding(UP).shortcut().shift(), e -> discontinuousSelectPreviousRow()), new KeyMapping(new KeyBinding(DOWN).shortcut().shift(), e -> discontinuousSelectNextRow()), - new KeyMapping(new KeyBinding(LEFT).shortcut().shift(), e -> discontinuousSelectPreviousColumn()), - new KeyMapping(new KeyBinding(RIGHT).shortcut().shift(), e -> discontinuousSelectNextColumn()), + new KeyMapping(new KeyBinding(LEFT).shortcut().shift(), e -> { if(isRTL()) discontinuousSelectNextColumn(); else discontinuousSelectPreviousColumn(); }), + new KeyMapping(new KeyBinding(RIGHT).shortcut().shift(), e -> { if(isRTL()) discontinuousSelectPreviousColumn(); else discontinuousSelectNextColumn(); }), new KeyMapping(new KeyBinding(PAGE_UP).shortcut().shift(), e -> discontinuousSelectPageUp()), new KeyMapping(new KeyBinding(PAGE_DOWN).shortcut().shift(), e -> discontinuousSelectPageDown()), new KeyMapping(new KeyBinding(HOME).shortcut().shift(), e -> discontinuousSelectAllToFirstRow()), @@ -1309,4 +1309,12 @@ protected void discontinuousSelectAllToLastRow() { if (onMoveToLastCell != null) onMoveToLastCell.run(); } + + private EventHandler focusTraverseLeft() { + return FocusTraversalInputMap::traverseLeft; + } + + private EventHandler focusTraverseRight() { + return FocusTraversalInputMap::traverseRight; + } } diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableViewHorizontalArrowsTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableViewHorizontalArrowsTest.java new file mode 100644 index 00000000000..aa96f8c70ee --- /dev/null +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableViewHorizontalArrowsTest.java @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2020, 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; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.junit.Assert.*; +import static test.com.sun.javafx.scene.control.infrastructure.KeyModifier.*; + +import com.sun.javafx.util.Utils; +import javafx.geometry.NodeOrientation; +import javafx.scene.input.KeyCode; +import javafx.scene.control.SelectionMode; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TablePosition; +import javafx.scene.control.TableView; +import test.com.sun.javafx.scene.control.behavior.TableViewAnchorRetriever; +import test.com.sun.javafx.scene.control.infrastructure.KeyEventFirer; +import test.com.sun.javafx.scene.control.infrastructure.KeyModifier; +import test.com.sun.javafx.scene.control.infrastructure.StageLoader; + + +/** + * Test basic horizontal navigation mappings for TableView. + * It is parameterized on NodeOrientation + */ +@RunWith(Parameterized.class) +public class TableViewHorizontalArrowsTest { + @Parameterized.Parameters + public static Collection implementations() { + return Arrays.asList(new Object[][] { + {NodeOrientation.LEFT_TO_RIGHT}, + {NodeOrientation.RIGHT_TO_LEFT} + }); + } + + private TableView tableView; + private TableView.TableViewSelectionModel sm; + private TableView.TableViewFocusModel fm; + + private TableColumn col0; + private TableColumn col1; + private TableColumn col2; + private TableColumn col3; + private TableColumn col4; + + private KeyEventFirer keyboard; + private StageLoader stageLoader; + private NodeOrientation orientation; + + public TableViewHorizontalArrowsTest(NodeOrientation val) { + orientation = val; + } + + @Before + public void setup() { + tableView = new TableView(); + tableView.setNodeOrientation(orientation); + sm = tableView.getSelectionModel(); + fm = tableView.getFocusModel(); + + sm.setSelectionMode(SelectionMode.MULTIPLE); + sm.setCellSelectionEnabled(true); + + tableView.getItems().setAll("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"); + + col0 = new TableColumn("col0"); + col1 = new TableColumn("col1"); + col2 = new TableColumn("col2"); + col3 = new TableColumn("col3"); + col4 = new TableColumn("col4"); + tableView.getColumns().setAll(col0, col1, col2, col3, col4); + + keyboard = new KeyEventFirer(tableView); + + stageLoader = new StageLoader(tableView); + stageLoader.getStage().show(); + } + + @After + public void tearDown() { + tableView.getSkin().dispose(); + stageLoader.dispose(); + } + + // ---------------- Helper methods ------------------------- + /** + * Toggles the parameter nodeOrientation and + * sets the tableView's orientation to the new toggled value + */ + private void toggleNodeOrientation() { + orientation = (orientation == NodeOrientation.LEFT_TO_RIGHT? + NodeOrientation.RIGHT_TO_LEFT : NodeOrientation.LEFT_TO_RIGHT); + tableView.setNodeOrientation(orientation); + } + + /** + * Orientation-aware forward horizontal navigation with arrow keys. + * @param modifiers the modifiers to use on keyboard + */ + private void forward(KeyModifier... modifiers) { + if (orientation == NodeOrientation.LEFT_TO_RIGHT) { + keyboard.doRightArrowPress(modifiers); + } else if (orientation == NodeOrientation.RIGHT_TO_LEFT) { + keyboard.doLeftArrowPress(modifiers); + } + } + + /** + * Orientation-aware backward horizontal navigation with arrow keys. + * @param modifiers the modifiers to use on keyboard + */ + private void backward(KeyModifier... modifiers) { + if (orientation == NodeOrientation.LEFT_TO_RIGHT) { + keyboard.doLeftArrowPress(modifiers); + } else if (orientation == NodeOrientation.RIGHT_TO_LEFT) { + keyboard.doRightArrowPress(modifiers); + } + } + + private TablePosition getAnchor() { + return TableViewAnchorRetriever.getAnchor(tableView); + } + + private boolean isAnchor(int row) { + TablePosition tp = new TablePosition(tableView, row, null); + return getAnchor() != null && getAnchor().equals(tp); + } + + private boolean isAnchor(int row, int col) { + TablePosition tp = new TablePosition(tableView, row, tableView.getColumns().get(col)); + return getAnchor() != null && getAnchor().equals(tp); + } + + + // ----------------------- Tests ---------------------------- + + @Test + public void testForwardSelect() { + sm.select(0, col0); + forward(); + assertTrue("next cell must be selected", sm.isSelected(0, col1)); + assertFalse("old cell not be selected", sm.isSelected(0, col0)); + } + + @Test + public void testBackwardSelect() { + sm.select(0, col4); + backward(); + assertTrue("next cell must be selected", sm.isSelected(0, col3)); + assertFalse("old cell not be selected", sm.isSelected(0, col4)); + } + + @Test + public void testForwardFocus() { + sm.select(0, col0); + forward(getShortcutKey()); + assertTrue("selected cell must still be selected", sm.isSelected(0, col0)); + assertFalse("next cell must not be selected", sm.isSelected(0, col1)); + TablePosition focusedCell = fm.getFocusedCell(); + assertEquals("focused cell must moved to next", col1, focusedCell.getTableColumn()); + } + + @Test + public void testBackwardFocus() { + sm.select(0, col4); + backward(getShortcutKey()); + assertTrue("selected cell must still be selected", sm.isSelected(0, col4)); + assertFalse("previous cell must not be selected", sm.isSelected(0, col3)); + TablePosition focusedCell = fm.getFocusedCell(); + assertEquals("focused cell must moved to prev", col3, focusedCell.getTableColumn()); + } + + @Test + public void testChangeOrientationSimpleForwardSelect() { + sm.select(0, col0); + forward(); + assertTrue(sm.isSelected(0, col1)); + assertFalse(sm.isSelected(0, col0)); + + toggleNodeOrientation(); + + // Now, test that the forward select respects change in NodeOrientation + forward(); + + assertFalse(sm.isSelected(0, col1)); + assertTrue(sm.isSelected(0, col2)); + } + + @Test + public void testChangeOrientationSimpleBackwardSelect() { + sm.select(0, col4); + backward(); + assertTrue(sm.isSelected(0, col3)); + assertFalse(sm.isSelected(0, col4)); + + toggleNodeOrientation(); + + // Now, test that the backward select respects change in NodeOrientation + backward(); + assertFalse(sm.isSelected(0, col3)); + assertTrue(sm.isSelected(0, col2)); + } + + @Test public void testShiftBackwardWhenAtFirstCol() { + sm.select(0, col0); + backward(KeyModifier.SHIFT); + + assertTrue("Selected cell remains selected", sm.isSelected(0, col0)); + + // We are at the first colum, there is no backward cell + assertFalse("sanity - forward cell must not be selected", sm.isSelected(0, col1)); + } + + @Test public void testShiftForwardWhenAtFirstCol() { + sm.select(0, col0); + forward(KeyModifier.SHIFT); + + assertTrue("Selected cell remains selected", sm.isSelected(0, col0)); + assertTrue("forward cell must also be selected", sm.isSelected(0, col1)); + } + + @Test public void testShiftBackwardWhenAtLastCol() { + sm.select(0, col4); + backward(KeyModifier.SHIFT); + assertTrue("Selected cell remains selected", sm.isSelected(0, col4)); + assertTrue("backward cell must also be selected", sm.isSelected(0, col3)); + } + + @Test public void testShiftForwardWhenAtLastCol() { + sm.select(0, col4); + forward(KeyModifier.SHIFT); + assertTrue("Selected cell remains selected", sm.isSelected(0, col4)); + + // We are at the last colum, there is no forward cell + assertFalse("sanity - backward cell must not be selected", sm.isSelected(0, col3)); + } + + @Test public void testCtrlBackwardDoesNotMoveRowFocus() { + // Select first row + sm.clearAndSelect(0); + assertTrue(fm.isFocused(0)); + + backward(KeyModifier.getShortcutKey()); + + assertTrue("Focus should not change", fm.isFocused(0)); + assertTrue("Selection should not change", sm.isSelected(0)); + } + + @Test public void testCtrlForwardDoesNotMoveRowFocus() { + // Select first row + sm.clearAndSelect(0); + assertTrue(fm.isFocused(0)); + + forward(KeyModifier.getShortcutKey()); + + assertTrue("Focus should not change", fm.isFocused(0)); + assertTrue("Selection should not change", sm.isSelected(0)); + } + + // Tests for discontinuous multiple cell selection (RT-18951) + @Test public void test_rt18591_select_forward_then_backward() { + sm.select(0, col0); + + forward(KeyModifier.getShortcutKey()); + forward(KeyModifier.getShortcutKey()); + keyboard.doKeyPress(KeyCode.SPACE, + KeyModifier.getShortcutKey(), + (Utils.isMac()? KeyModifier.CTRL : null)); + assertTrue(sm.isSelected(0, col0)); + assertFalse(sm.isSelected(0, col1)); + assertTrue(sm.isSelected(0, col2)); + assertTrue(isAnchor(0, 2)); + + forward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + forward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + + assertTrue(sm.isSelected(0, col0)); + assertFalse(sm.isSelected(0, col1)); + assertTrue(sm.isSelected(0, col2)); + assertTrue(sm.isSelected(0, col3)); + assertTrue(sm.isSelected(0, col4)); + assertTrue(isAnchor(0,2)); + + + backward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + backward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + backward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + + assertTrue(sm.isSelected(0, col0)); + assertTrue(sm.isSelected(0, col1)); + assertTrue(sm.isSelected(0, col2)); + assertTrue(sm.isSelected(0, col3)); + assertTrue(sm.isSelected(0, col4)); + } + + @Test public void test_rt18591_select_backward_then_forward() { + sm.select(0, col4); + + backward(KeyModifier.getShortcutKey()); + backward(KeyModifier.getShortcutKey()); + keyboard.doKeyPress(KeyCode.SPACE, + KeyModifier.getShortcutKey(), + (Utils.isMac()? KeyModifier.CTRL : null)); + + assertTrue(sm.isSelected(0, col4)); + assertFalse(sm.isSelected(0, col3)); + assertTrue(sm.isSelected(0, col2)); + assertTrue(isAnchor(0, 2)); + + backward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + backward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + + assertTrue(sm.isSelected(0, col4)); + assertFalse(sm.isSelected(0, col3)); + assertTrue(sm.isSelected(0, col2)); + assertTrue(sm.isSelected(0, col1)); + assertTrue(sm.isSelected(0, col0)); + assertTrue(isAnchor(0,2)); + + forward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + forward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + forward(KeyModifier.SHIFT, KeyModifier.getShortcutKey()); + + assertTrue(sm.isSelected(0, col4)); + assertTrue(sm.isSelected(0, col3)); + assertTrue(sm.isSelected(0, col2)); + assertTrue(sm.isSelected(0, col1)); + assertTrue(sm.isSelected(0, col0)); + } + + @Test public void test_rt18536_forward_focus_and_selectAll() { + // Test shift selection when focus is elsewhere (so as to select a range) + sm.clearAndSelect(1, col0); + + // move focus by holding down ctrl button + forward(KeyModifier.getShortcutKey()); // move focus to (1, col1) + forward(KeyModifier.getShortcutKey()); // move focus to (1, col2) + forward(KeyModifier.getShortcutKey()); // move focus to (1, col3) + forward(KeyModifier.getShortcutKey()); // move focus to (1, col4) + assertTrue(fm.isFocused(1, col4)); + + // press shift + space to select all cells between (1, col0) and (1, col4) + keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT); + assertTrue(sm.isSelected(1, col0)); + assertTrue(sm.isSelected(1, col1)); + assertTrue(sm.isSelected(1, col2)); + assertTrue(sm.isSelected(1, col3)); + assertTrue(sm.isSelected(1, col4)); + } + + @Test public void test_rt18536_backward_focus_and_selectAll() { + // Test shift selection when focus is elsewhere (so as to select a range) + sm.clearAndSelect(1, col4); + + // move focus by holding down ctrl button + backward(KeyModifier.getShortcutKey()); // move focus to (1, col3) + backward(KeyModifier.getShortcutKey()); // move focus to (1, col2) + backward(KeyModifier.getShortcutKey()); // move focus to (1, col1) + backward(KeyModifier.getShortcutKey()); // move focus to (1, col0) + assertTrue(fm.isFocused(1, col0)); + + // press shift + space to select all cells between (1, col0) and (1, col4) + keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT); + assertTrue(sm.isSelected(1, col0)); + assertTrue(sm.isSelected(1, col1)); + assertTrue(sm.isSelected(1, col2)); + assertTrue(sm.isSelected(1, col3)); + assertTrue(sm.isSelected(1, col4)); + } +} From 2a7ab367329525636e677979bfa6b9b09e3d1136 Mon Sep 17 00:00:00 2001 From: Ajit Ghaisas Date: Tue, 24 Mar 2020 05:18:19 +0000 Subject: [PATCH 03/10] 8089134: [2D traversal, RTL] TraversalEngine only handles left/right key traversal correctly in RTL for top-level engine in ToolBar Reviewed-by: kcr --- .../scene/control/skin/ToolBarSkin.java | 3 + .../control/ToolBarHorizontalArrowsTest.java | 345 ++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100644 modules/javafx.controls/src/test/java/test/javafx/scene/control/ToolBarHorizontalArrowsTest.java diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ToolBarSkin.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ToolBarSkin.java index 7f61baaf35c..e95b48c2eca 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ToolBarSkin.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ToolBarSkin.java @@ -165,6 +165,9 @@ private Node selectNext(int from, TraversalContext context) { @Override public Node select(Node owner, Direction dir, TraversalContext context) { + + dir = dir.getDirectionForNodeOrientation(control.getEffectiveNodeOrientation()); + final ObservableList boxChildren = box.getChildren(); if (owner == overflowMenu) { if (dir.isForward()) { diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ToolBarHorizontalArrowsTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ToolBarHorizontalArrowsTest.java new file mode 100644 index 00000000000..0f1e03ec03a --- /dev/null +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ToolBarHorizontalArrowsTest.java @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2020, 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; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.junit.Assert.*; + +import com.sun.javafx.tk.Toolkit; + +import javafx.geometry.NodeOrientation; +import javafx.scene.control.Button; +import javafx.scene.control.ToolBar; +import javafx.scene.control.skin.ToolBarSkin; +import javafx.scene.input.KeyCode; + +import test.com.sun.javafx.pgstub.StubToolkit; +import test.com.sun.javafx.scene.control.infrastructure.KeyEventFirer; +import test.com.sun.javafx.scene.control.infrastructure.KeyModifier; +import test.com.sun.javafx.scene.control.infrastructure.StageLoader; + + +/** + * Test basic horizontal navigation mappings for ToolBar. + * It is parameterized on NodeOrientation + */ +@RunWith(Parameterized.class) +public class ToolBarHorizontalArrowsTest { + @Parameterized.Parameters + public static Collection implementations() { + return Arrays.asList(new Object[][] { + {NodeOrientation.LEFT_TO_RIGHT}, + {NodeOrientation.RIGHT_TO_LEFT} + }); + } + + private ToolBar toolBar; + private Button btn1; + private Button btn2; + private Button btn3; + private Button btn4; + private Button btn5; + + private KeyEventFirer keyboard; + private StageLoader stageLoader; + private NodeOrientation orientation; + + public ToolBarHorizontalArrowsTest(NodeOrientation val) { + orientation = val; + } + + @Before public void setup() { + toolBar = new ToolBar(); + toolBar.setNodeOrientation(orientation); + + // Create 5 buttons and add them in order to the toolBar + btn1 = new Button("Btn1"); + btn2 = new Button("Btn2"); + btn3 = new Button("Btn3"); + btn4 = new Button("Btn4"); + btn5 = new Button("Btn5"); + + toolBar.getItems().addAll(btn1, btn2, btn3, btn4, btn5); + + ToolBarSkin toolbarSkin = new ToolBarSkin(toolBar); + toolBar.setSkin(toolbarSkin); + + stageLoader = new StageLoader(toolBar); + stageLoader.getStage().show(); + ((StubToolkit)Toolkit.getToolkit()).firePulse(); + + toolBar.setFocusTraversable(true); + + keyboard = new KeyEventFirer(toolBar, toolBar.getScene()); + } + + @After + public void tearDown() { + toolBar.getSkin().dispose(); + stageLoader.dispose(); + } + + // ---------------- Helper methods ------------------------- + /** + * Toggles the parameter nodeOrientation and + * sets the toolBar's orientation to the new toggled value + */ + private void toggleNodeOrientation() { + orientation = (orientation == NodeOrientation.LEFT_TO_RIGHT? + NodeOrientation.RIGHT_TO_LEFT : NodeOrientation.LEFT_TO_RIGHT); + toolBar.setNodeOrientation(orientation); + } + + /** + * Orientation-aware forward horizontal navigation with arrow keys. + * @param modifiers the modifiers to use on keyboard + */ + private void forward(KeyModifier... modifiers) { + if (orientation == NodeOrientation.LEFT_TO_RIGHT) { + keyboard.doRightArrowPress(modifiers); + } else if (orientation == NodeOrientation.RIGHT_TO_LEFT) { + keyboard.doLeftArrowPress(modifiers); + } + } + + /** + * Orientation-aware backward horizontal navigation with arrow keys. + * @param modifiers the modifiers to use on keyboard + */ + private void backward(KeyModifier... modifiers) { + if (orientation == NodeOrientation.LEFT_TO_RIGHT) { + keyboard.doLeftArrowPress(modifiers); + } else if (orientation == NodeOrientation.RIGHT_TO_LEFT) { + keyboard.doRightArrowPress(modifiers); + } + } + + + // ----------------------- Tests ---------------------------- + + /** + * Test forward focus movements with TAB key + */ + @Test + public void testForwardFocus() { + assertTrue(toolBar.isFocusTraversable()); + + toolBar.getScene().getWindow().requestFocus(); + assertTrue(btn1.isFocused()); + + keyboard.doKeyPress(KeyCode.TAB); + assertTrue(btn2.isFocused()); + + keyboard.doKeyPress(KeyCode.TAB); + assertTrue(btn3.isFocused()); + + keyboard.doKeyPress(KeyCode.TAB); + assertTrue(btn4.isFocused()); + + keyboard.doKeyPress(KeyCode.TAB); + assertTrue(btn5.isFocused()); + } + + /** + * Test backward focus movements with SHIFT+TAB keys + */ + @Test + public void testBackwardFocus() { + assertTrue(toolBar.isFocusTraversable()); + + toolBar.getScene().getWindow().requestFocus(); + btn5.requestFocus(); + assertTrue(btn5.isFocused()); + + keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT); + assertTrue(btn4.isFocused()); + + keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT); + assertTrue(btn3.isFocused()); + + keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT); + assertTrue(btn2.isFocused()); + + keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT); + assertTrue(btn1.isFocused()); + } + + @Test + public void testForwardFocusArrows() { + assertTrue(toolBar.isFocusTraversable()); + + toolBar.getScene().getWindow().requestFocus(); + assertTrue(btn1.isFocused()); + + forward(); + assertTrue(btn2.isFocused()); + + forward(); + assertTrue(btn3.isFocused()); + + forward(); + assertTrue(btn4.isFocused()); + + forward(); + assertTrue(btn5.isFocused()); + } + + @Test + public void testBackwardFocusArrows() { + assertTrue(toolBar.isFocusTraversable()); + + toolBar.getScene().getWindow().requestFocus(); + btn5.requestFocus(); + assertTrue(btn5.isFocused()); + + backward(); + assertTrue(btn4.isFocused()); + + backward(); + assertTrue(btn3.isFocused()); + + backward(); + assertTrue(btn2.isFocused()); + + backward(); + assertTrue(btn1.isFocused()); + } + + /** + * Test forward focus movement when ToolBar's NodeOrientation + * is changed dynamically. + */ + @Test + public void testForwardFocusArrows_toggleOrientation() { + assertTrue(toolBar.isFocusTraversable()); + + toolBar.getScene().getWindow().requestFocus(); + assertTrue(btn1.isFocused()); + + forward(); + assertTrue(btn2.isFocused()); + + toggleNodeOrientation(); + + forward(); + assertTrue(btn3.isFocused()); + + forward(); + assertTrue(btn4.isFocused()); + + toggleNodeOrientation(); + + forward(); + assertTrue(btn5.isFocused()); + } + + /** + * Test backward focus movement when ToolBar's NodeOrientation + * is changed dynamically. + */ + @Test + public void testBackwardFocusArrows_toggleOrientation() { + assertTrue(toolBar.isFocusTraversable()); + + toolBar.getScene().getWindow().requestFocus(); + btn5.requestFocus(); + assertTrue(btn5.isFocused()); + + backward(); + assertTrue(btn4.isFocused()); + + toggleNodeOrientation(); + + backward(); + assertTrue(btn3.isFocused()); + + backward(); + assertTrue(btn2.isFocused()); + + toggleNodeOrientation(); + + backward(); + assertTrue(btn1.isFocused()); + } + + /** + * Test forward/backward focus movements when ToolBar's NodeOrientation + * is changed dynamically. + */ + @Test + public void testMixedFocusArrows_toggleOrientation() { + assertTrue(toolBar.isFocusTraversable()); + + toolBar.getScene().getWindow().requestFocus(); + assertTrue(btn1.isFocused()); + + forward(); + assertTrue(btn2.isFocused()); + + toggleNodeOrientation(); + + forward(); + assertTrue(btn3.isFocused()); + + backward(); + assertTrue(btn2.isFocused()); + + toggleNodeOrientation(); + + backward(); + assertTrue(btn1.isFocused()); + } + + /** + * Test focus movements when focus is at extreme child Nodes of the ToolBar + */ + @Test + public void testFocusExtremeNodesOfToolBar() { + assertTrue(toolBar.isFocusTraversable()); + + // Test backward movement when focus is at the first Button in the toolBar + toolBar.getScene().getWindow().requestFocus(); + assertTrue(btn1.isFocused()); + + backward(); + assertTrue(btn1.isFocused()); // focus should not change + + // Test forward movement when focus is at the last Button in the toolBar + btn5.requestFocus(); + assertTrue(btn5.isFocused()); + + forward(); + assertTrue(btn5.isFocused()); // focus should not change + } +} From d12e71c1d75312eddc7cf21b40d5068904f0ae8a Mon Sep 17 00:00:00 2001 From: Thiago Milczarek Sayao Date: Tue, 24 Mar 2020 14:42:26 +0000 Subject: [PATCH 04/10] 8241474: Build failing on Ubuntu 20.04 Reviewed-by: kcr --- buildSrc/linux.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/linux.gradle b/buildSrc/linux.gradle index df03d41ac88..0a61954305c 100644 --- a/buildSrc/linux.gradle +++ b/buildSrc/linux.gradle @@ -79,7 +79,7 @@ if (hasProperty('toolchainDir')) { toolchainDir = "" } -def gtk2CCFlags = [ ]; +def gtk2CCFlags = [ "-Wno-deprecated-declarations" ]; def gtk3CCFlags = [ "-Wno-deprecated-declarations" ]; def gtk2LinkFlags = [ ]; def gtk3LinkFlags = [ ]; From f3a3ea0134c438731addbbeea9667930a168b8d8 Mon Sep 17 00:00:00 2001 From: Arun Joseph Date: Thu, 26 Mar 2020 11:26:06 +0000 Subject: [PATCH 05/10] 8234471: Canvas in webview displayed with wrong scale on Windows Reviewed-by: kcr, ghb --- .../webkit/prism/PrismGraphicsManager.java | 2 +- .../test/javafx/scene/web/CanvasTest.java | 136 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tests/system/src/test/java/test/javafx/scene/web/CanvasTest.java diff --git a/modules/javafx.web/src/main/java/com/sun/javafx/webkit/prism/PrismGraphicsManager.java b/modules/javafx.web/src/main/java/com/sun/javafx/webkit/prism/PrismGraphicsManager.java index a2f83b9e12d..cf4463cd589 100644 --- a/modules/javafx.web/src/main/java/com/sun/javafx/webkit/prism/PrismGraphicsManager.java +++ b/modules/javafx.web/src/main/java/com/sun/javafx/webkit/prism/PrismGraphicsManager.java @@ -49,7 +49,7 @@ public final class PrismGraphicsManager extends WCGraphicsManager { ps = Math.max(s.getRecommendedOutputScaleY(), ps); } highestPixelScale = (float) Math.ceil(ps); - pixelScaleTransform = BaseTransform.getScaleInstance(ps, ps); + pixelScaleTransform = BaseTransform.getScaleInstance(highestPixelScale, highestPixelScale); } static BaseTransform getPixelScaleTransform() { diff --git a/tests/system/src/test/java/test/javafx/scene/web/CanvasTest.java b/tests/system/src/test/java/test/javafx/scene/web/CanvasTest.java new file mode 100644 index 00000000000..d3dc5759d23 --- /dev/null +++ b/tests/system/src/test/java/test/javafx/scene/web/CanvasTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2020, 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.web; + +import java.util.concurrent.CountDownLatch; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.scene.Scene; +import javafx.scene.web.WebView; +import javafx.stage.Stage; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import test.util.Util; + +import static javafx.concurrent.Worker.State.SUCCEEDED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class CanvasTest { + private static final CountDownLatch launchLatch = new CountDownLatch(1); + + // Maintain one application instance + static CanvasTestApp canvasTestApp; + + private WebView webView; + + public static class CanvasTestApp extends Application { + Stage primaryStage = null; + + @Override + public void init() { + CanvasTest.canvasTestApp = this; + } + + @Override + public void start(Stage primaryStage) throws Exception { + Platform.setImplicitExit(false); + this.primaryStage = primaryStage; + launchLatch.countDown(); + } + } + + @BeforeClass + public static void setupOnce() { + // Start the Test Application + new Thread(() -> Application.launch(CanvasTestApp.class, (String[])null)).start(); + + assertTrue("Timeout waiting for FX runtime to start", Util.await(launchLatch)); + } + + @AfterClass + public static void tearDownOnce() { + Platform.exit(); + } + + @Before + public void setupTestObjects() { + Platform.runLater(() -> { + webView = new WebView(); + canvasTestApp.primaryStage.setScene(new Scene(webView)); + canvasTestApp.primaryStage.show(); + }); + } + + /** + * @test + * @bug 8234471 + * Summary Check if canvas displays the whole rectangle + */ + @Test + public void testCanvasRect() throws Exception { + final CountDownLatch webViewStateLatch = new CountDownLatch(1); + final String htmlCanvasContent = "\n" + + "\n" + + "\n"; + + Util.runAndWait(() -> { + webView.getEngine().getLoadWorker().stateProperty(). + addListener((observable, oldValue, newValue) -> { + if (newValue == SUCCEEDED) { + webView.requestFocus(); + } + }); + + assertNotNull(webView); + webView.getEngine().loadContent(htmlCanvasContent); + + webView.focusedProperty(). + addListener((observable, oldValue, newValue) -> { + if (newValue) { + webViewStateLatch.countDown(); + } + }); + }); + + assertTrue("Timeout when waiting for focus change ", Util.await(webViewStateLatch)); + + Util.runAndWait(() -> { + int redColor = 255; + assertEquals("Rect top-left corner", redColor, (int) webView.getEngine().executeScript( + "document.getElementById('canvas').getContext('2d').getImageData(1, 1, 1, 1).data[0]")); + assertEquals("Rect bottom-right corner", redColor, (int) webView.getEngine().executeScript( + "document.getElementById('canvas').getContext('2d').getImageData(99, 99, 1, 1).data[0]")); + }); + } +} From 9ecc10793d0e8b6fdba4e169166389f99334f820 Mon Sep 17 00:00:00 2001 From: Kevin Rushforth Date: Thu, 26 Mar 2020 13:00:19 +0000 Subject: [PATCH 06/10] 8240539: Upgrade gradle to version 6.3 Reviewed-by: jvos, arapte --- build.properties | 2 +- gradle/legal/gradle.md | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.properties b/build.properties index 506be226e9f..99349d74236 100644 --- a/build.properties +++ b/build.properties @@ -84,7 +84,7 @@ jfx.build.jdk.buildnum.min=28 # gradle/legal/gradle.md. # The jfx.gradle.version.min property defines the minimum version of gradle # that is supported. It must be <= jfx.gradle.version. -jfx.gradle.version=6.0 +jfx.gradle.version=6.3 jfx.gradle.version.min=5.3 # Toolchains diff --git a/gradle/legal/gradle.md b/gradle/legal/gradle.md index c77cb57a0b3..ad270f34fd5 100644 --- a/gradle/legal/gradle.md +++ b/gradle/legal/gradle.md @@ -1,4 +1,4 @@ -## Gradle v6.0 +## Gradle v6.3 ### Apache 2.0 License ``` diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6ce793f21e8..a4b4429748d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From d7f13f457ebbf8608dc5169737b34b8cc9c9d242 Mon Sep 17 00:00:00 2001 From: Ajit Ghaisas Date: Fri, 27 Mar 2020 04:36:58 +0000 Subject: [PATCH 07/10] 8089828: RTL Orientation, the flag of a mnemonic is not placed under the mnemonic letter. Reviewed-by: kcr, arapte --- .../sun/javafx/scene/control/skin/Utils.java | 11 ++++-- .../scene/control/skin/LabeledSkinBase.java | 5 ++- .../manual/UI/ButtonMnemonicPositionTest.java | 39 +++++++++++++++++-- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java index f53b66b8868..f0c3bd6b0e2 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, 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 @@ -148,7 +148,7 @@ public static double computeTextHeight(Font font, String text, double wrappingWi } public static Point2D computeMnemonicPosition(Font font, String text, int mnemonicIndex, double wrappingWidth, - double lineSpacing) { + double lineSpacing, boolean isRTL) { // Input validation if ((font == null) || (text == null) || (mnemonicIndex < 0) || (mnemonicIndex > text.length())) { @@ -165,8 +165,9 @@ public static Point2D computeMnemonicPosition(Font font, String text, int mnemon int start = 0; int i = 0; int totalLines = layout.getLines().length; + int lineLength = 0; while (i < totalLines) { - int lineLength = layout.getLines()[i].getLength(); + lineLength = layout.getLines()[i].getLength(); if ((mnemonicIndex >= start) && (mnemonicIndex < (start + lineLength))) { @@ -182,6 +183,10 @@ public static Point2D computeMnemonicPosition(Font font, String text, int mnemon // in line numbered 'i' double lineHeight = layout.getBounds().getHeight() / totalLines; double x = Utils.computeTextWidth(font, text.substring(start, mnemonicIndex), 0); + if (isRTL) { + double lineWidth = Utils.computeTextWidth(font, text.substring(start, (start + lineLength - 1)), 0); + x = lineWidth - x; + } double y = (lineHeight * (i+1)); // Adjust y offset for linespacing except for the last line. diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java index e3f439a1a80..119df7dabcf 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2020, 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 @@ -580,7 +580,8 @@ protected void layoutLabelInArea(double x, double y, double w, double h, Pos ali if (containsMnemonic) { final Font font = text.getFont(); String preSt = bindings.getText(); - mnemonicPos = Utils.computeMnemonicPosition(font, preSt, bindings.getMnemonicIndex(), this.wrapWidth, labeled.getLineSpacing()); + boolean isRTL = (labeledNode.getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT); + mnemonicPos = Utils.computeMnemonicPosition(font, preSt, bindings.getMnemonicIndex(), this.wrapWidth, labeled.getLineSpacing(), isRTL); mnemonicWidth = Utils.computeTextWidth(font, preSt.substring(bindings.getMnemonicIndex(), bindings.getMnemonicIndex() + 1), 0); mnemonicHeight = Utils.computeTextHeight(font, "_", 0, text.getBoundsType()); } diff --git a/tests/manual/UI/ButtonMnemonicPositionTest.java b/tests/manual/UI/ButtonMnemonicPositionTest.java index 2319ce25c74..488a1bb65eb 100644 --- a/tests/manual/UI/ButtonMnemonicPositionTest.java +++ b/tests/manual/UI/ButtonMnemonicPositionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, 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 @@ -25,6 +25,7 @@ import javafx.application.Application; import javafx.application.Platform; +import javafx.geometry.NodeOrientation; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -40,7 +41,7 @@ public void start(Stage primaryStage) throws Exception { String str = "This test is to check mnemonic position is correctly shown " + "in a single and multi-line button.\n" + - "Test shows 4 buttons of varying widths one below another - " + + "Test shows 8 buttons of varying widths stacked in 2 groups of 4 buttons each - " + "The buttons are made up of a string consisting of A to Z English" + " characters\n"+ "------------------------------------------------------\n"+ @@ -70,7 +71,7 @@ public void start(Stage primaryStage) throws Exception { new Label("------------------------------------------------------"); - // Test buttons --------------------------------------- + // LTR Test buttons --------------------------------------- Button b1 = new Button("ABCDEFGHIJKLMNOPQRST_UVWXYZ"); Button b2 = new Button("ABCDEFGHIJKLMNOPQRST_UVWXYZ"); Button b3 = new Button("ABCDEFGHIJKLMNOPQRST_UVWXYZ"); @@ -85,12 +86,42 @@ public void start(Stage primaryStage) throws Exception { b4.setMaxWidth(60); b4.wrapTextProperty().setValue(true); + VBox LTRBox = new VBox(); + LTRBox.setSpacing(10.0); + LTRBox.getChildren().addAll(b1, b2, b3, b4); + + // RTL Test buttons --------------------------------------- + Button b5 = new Button("ABCDEFGHIJKLMNOPQRST_UVWXYZ"); + Button b6 = new Button("ABCDEFGHIJKLMNOPQRST_UVWXYZ"); + Button b7 = new Button("ABCDEFGHIJKLMNOPQRST_UVWXYZ"); + Button b8 = new Button("ABCDEFGHIJKLMNOPQRST_UVWXYZ"); + + b5.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); + b6.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); + b6.setMaxWidth(130); + b6.wrapTextProperty().setValue(true); + + b7.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); + b7.setMaxWidth(85); + b7.wrapTextProperty().setValue(true); + + b8.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); + b8.setMaxWidth(60); + b8.wrapTextProperty().setValue(true); + + VBox RTLBox = new VBox(); + RTLBox.setSpacing(10.0); + RTLBox.getChildren().addAll(b5, b6, b7, b8); + + HBox btnBox = new HBox(); + btnBox.getChildren().addAll(LTRBox, RTLBox); + VBox box = new VBox(); box.setSpacing(10.0); Scene s = new Scene(box); box.getChildren().addAll(testInstructions, testBtnBox, lbl, - b1, b2, b3, b4); + btnBox); primaryStage.setScene(s); primaryStage.show(); } From 6d098fe5786c22854f1e42b2b120b9dd8279683e Mon Sep 17 00:00:00 2001 From: "Rony G. Flatscher" Date: Tue, 31 Mar 2020 12:17:13 +0000 Subject: [PATCH 08/10] 8234959: FXMLLoader does not populate ENGINE_SCOPE Bindings with FILENAME and ARGV Reviewed-by: kcr, aghaisas --- build.gradle | 6 +- .../src/main/java/javafx/fxml/FXMLLoader.java | 24 +- .../test/launchertest/ModuleLauncherTest.java | 9 +- .../java/mymod/module-info.java | 34 +++ .../java/mymod/myapp1/Constants.java | 37 +++ .../mymod/myapp1/FXMLScriptDeployment.java | 286 ++++++++++++++++++ .../java/mymod/myapp1/Util.java | 114 +++++++ .../pseudoScriptEngine/InvocationInfos.java | 77 +++++ .../RgfPseudoScriptEngine.java | 124 ++++++++ .../RgfPseudoScriptEngineFactory.java | 140 +++++++++ .../services/javax.script.ScriptEngineFactory | 2 + .../resources/mymod/myapp1/demo_01.fxml | 69 +++++ .../mymod/myapp1/demo_01_bottomscript.rpsl | 1 + .../mymod/myapp1/demo_01_middlescript.rpsl | 1 + .../mymod/myapp1/demo_01_topscript.rpsl | 1 + 15 files changed, 912 insertions(+), 13 deletions(-) create mode 100644 tests/system/src/testscriptapp1/java/mymod/module-info.java create mode 100644 tests/system/src/testscriptapp1/java/mymod/myapp1/Constants.java create mode 100644 tests/system/src/testscriptapp1/java/mymod/myapp1/FXMLScriptDeployment.java create mode 100644 tests/system/src/testscriptapp1/java/mymod/myapp1/Util.java create mode 100644 tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/InvocationInfos.java create mode 100644 tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/RgfPseudoScriptEngine.java create mode 100644 tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/RgfPseudoScriptEngineFactory.java create mode 100644 tests/system/src/testscriptapp1/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory create mode 100644 tests/system/src/testscriptapp1/resources/mymod/myapp1/demo_01.fxml create mode 100644 tests/system/src/testscriptapp1/resources/mymod/myapp1/demo_01_bottomscript.rpsl create mode 100644 tests/system/src/testscriptapp1/resources/mymod/myapp1/demo_01_middlescript.rpsl create mode 100644 tests/system/src/testscriptapp1/resources/mymod/myapp1/demo_01_topscript.rpsl diff --git a/build.gradle b/build.gradle index 99ce4e76073..f7899ae8224 100644 --- a/build.gradle +++ b/build.gradle @@ -3571,6 +3571,7 @@ project(":systemTests") { testapp4 testapp5 testapp6 + testscriptapp1 } def nonModSrcSets = [ @@ -3583,7 +3584,8 @@ project(":systemTests") { sourceSets.testapp3, sourceSets.testapp4, sourceSets.testapp5, - sourceSets.testapp6 + sourceSets.testapp6, + sourceSets.testscriptapp1 ] project.ext.buildModule = false @@ -3683,7 +3685,7 @@ project(":systemTests") { } test.dependsOn(createTestApps); - def modtestapps = [ "testapp2", "testapp3", "testapp4", "testapp5", "testapp6" ] + def modtestapps = [ "testapp2", "testapp3", "testapp4", "testapp5", "testapp6", "testscriptapp1" ] modtestapps.each { testapp -> def testappCapital = testapp.capitalize() def copyTestAppTask = task("copy${testappCapital}", type: Copy) { diff --git a/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java b/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java index 7f3d2f30837..313f1580955 100644 --- a/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java +++ b/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java @@ -618,8 +618,8 @@ public void processEventHandlerAttributes() throws LoadException { throw constructLoadException("Error resolving " + attribute.name + "='" + attribute.value + "', either the event handler is not in the Namespace or there is an error in the script."); } - - eventHandler = new ScriptEventHandler(handlerName, scriptEngine); + eventHandler = new ScriptEventHandler(handlerName, scriptEngine, location.getPath() + + "-" + attribute.name + "_attribute_in_element_ending_at_line_" + getLineNumber()); } // Add the handler @@ -1557,6 +1557,8 @@ public void processStartElement() throws IOException { location = new URL(FXMLLoader.this.location, source); } + Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); + engineBindings.put(engine.FILENAME, location.getPath()); InputStreamReader scriptReader = null; try { @@ -1582,6 +1584,9 @@ public void processEndElement() throws IOException { if (value != null && !staticLoad) { // Evaluate the script try { + Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE); + engineBindings.put(scriptEngine.FILENAME, location.getPath() + "-script_starting_at_line_" + + (getLineNumber() - (int) ((String) value).codePoints().filter(c -> c == '\n').count())); scriptEngine.eval((String)value); } catch (ScriptException exception) { System.err.println(exception.getMessage()); @@ -1675,10 +1680,12 @@ public void handle(T event) { private static class ScriptEventHandler implements EventHandler { public final String script; public final ScriptEngine scriptEngine; + public final String filename; - public ScriptEventHandler(String script, ScriptEngine scriptEngine) { + public ScriptEventHandler(String script, ScriptEngine scriptEngine, String filename) { this.script = script; this.scriptEngine = scriptEngine; + this.filename = filename; } @Override @@ -1686,19 +1693,16 @@ public void handle(Event event) { // Don't pollute the page namespace with values defined in the script Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE); Bindings localBindings = scriptEngine.createBindings(); - localBindings.put(EVENT_KEY, event); localBindings.putAll(engineBindings); - scriptEngine.setBindings(localBindings, ScriptContext.ENGINE_SCOPE); - + localBindings.put(EVENT_KEY, event); + localBindings.put(scriptEngine.ARGV, new Object[]{event}); + localBindings.put(scriptEngine.FILENAME, filename); // Execute the script try { - scriptEngine.eval(script); + scriptEngine.eval(script, localBindings); } catch (ScriptException exception){ throw new RuntimeException(exception); } - - // Restore the original bindings - scriptEngine.setBindings(engineBindings, ScriptContext.ENGINE_SCOPE); } } diff --git a/tests/system/src/test/java/test/launchertest/ModuleLauncherTest.java b/tests/system/src/test/java/test/launchertest/ModuleLauncherTest.java index 7d38bb8aa68..346bf78c4e2 100644 --- a/tests/system/src/test/java/test/launchertest/ModuleLauncherTest.java +++ b/tests/system/src/test/java/test/launchertest/ModuleLauncherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, 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 @@ -43,6 +43,8 @@ public class ModuleLauncherTest { private static final String modulePath4 = System.getProperty("launchertest.testapp4.module.path"); private static final String modulePath5 = System.getProperty("launchertest.testapp5.module.path"); private static final String modulePath6 = System.getProperty("launchertest.testapp6.module.path"); + private static final String modulePathScript1 = System.getProperty("launchertest.testscriptapp1.module.path"); + private static final String moduleName = "mymod"; private final int testExitCode = ERROR_NONE; @@ -274,4 +276,9 @@ public void testModuleFXMLQualOpened() throws Exception { doTestLaunchModule(modulePath6, "myapp6.AppFXMLQualOpened"); } + @Test (timeout = 15000) + public void testFXMLScriptDeployment() throws Exception { + doTestLaunchModule(modulePathScript1, "myapp1.FXMLScriptDeployment"); + } + } diff --git a/tests/system/src/testscriptapp1/java/mymod/module-info.java b/tests/system/src/testscriptapp1/java/mymod/module-info.java new file mode 100644 index 00000000000..8196c861e13 --- /dev/null +++ b/tests/system/src/testscriptapp1/java/mymod/module-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020, 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. + */ + +module mymod { + requires javafx.controls; + requires javafx.fxml; + + requires java.scripting; + provides javax.script.ScriptEngineFactory with pseudoScriptEngine.RgfPseudoScriptEngineFactory; + exports pseudoScriptEngine; + exports myapp1; +} diff --git a/tests/system/src/testscriptapp1/java/mymod/myapp1/Constants.java b/tests/system/src/testscriptapp1/java/mymod/myapp1/Constants.java new file mode 100644 index 00000000000..4379f319667 --- /dev/null +++ b/tests/system/src/testscriptapp1/java/mymod/myapp1/Constants.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017, 2020, 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 myapp1; // verbatim from myapp6 + +public class Constants { + + public static final int SHOWTIME = 2500; + + // NOTE: these constants must match those in test.launchertest.Constants + public static final int ERROR_NONE = 2; + public static final int ERROR_UNEXPECTED_EXCEPTION = 4; + + public static final int ERROR_ASSERTION_FAILURE = 28; +} diff --git a/tests/system/src/testscriptapp1/java/mymod/myapp1/FXMLScriptDeployment.java b/tests/system/src/testscriptapp1/java/mymod/myapp1/FXMLScriptDeployment.java new file mode 100644 index 00000000000..41119cfe72b --- /dev/null +++ b/tests/system/src/testscriptapp1/java/mymod/myapp1/FXMLScriptDeployment.java @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2020, 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 myapp1; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +import javax.script.Bindings; +import javax.script.ScriptContext; + +import static myapp1.Constants.*; +import pseudoScriptEngine.InvocationInfos; +import pseudoScriptEngine.RgfPseudoScriptEngine; + +/** + * Modular test application for testing FXML. + * This is launched by ModuleLauncherTest. + */ +public class FXMLScriptDeployment extends Application { + + static boolean bDebug = false; // true; // display invocation list + + /** Runs the application and invokes the tests. + * @param args the command line arguments, if any given the RgfPseudoScriptEngine invocation logs get displayed + * which are used in the asserCorrectInvocations() method + */ + public static void main(String[] args) { + try { + // any argument will cause the bDebug flag to be set to true + if (args.length > 0) { + bDebug = true; + } + new FXMLScriptDeployment().launch(); + // for debugging, allows to study invocation logs in detail + if (bDebug) { dumpEvalInformation(); } + assertCorrectInvocations(); + } catch (AssertionError ex) { + System.err.println("ASSERTION ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_ASSERTION_FAILURE); + } catch (Error | Exception ex) { + System.err.println("ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + System.exit(ERROR_NONE); // not in stop() method as we need to run the assertions first + } + + @Override + public void start(Stage mainStage) { + URL fxmlUrl = null; + Parent rootNode = null; + Scene scene = null; + Button btn = null; + try { + fxmlUrl = Util.getURL(FXMLScriptDeployment.class, "demo_01"); + rootNode = FXMLLoader.load(fxmlUrl); + scene = new Scene(rootNode); + btn = (Button) scene.lookup("#idButton"); + } + catch (Exception ioe) { + ioe.printStackTrace(); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + // fire three events on the button + btn.fire(); + btn.fireEvent(new ActionEvent()); + btn.fireEvent(new MouseEvent(MouseEvent.MOUSE_CLICKED, + 0, // double x, + 0, // double y, + 0, // double screenX, + 0, // double screenY, + MouseButton.PRIMARY, // MouseButton button, + 0, // int clickCount, + false, // boolean shiftDown, + false, // boolean controlDown, + false, // boolean altDown, + false, // boolean metaDown, + true, // boolean primaryButtonDown, + false, // boolean middleButtonDown, + false, // boolean secondaryButtonDown, + false, // boolean synthesized, + false, // boolean popupTrigger, + false, // boolean stillSincePress, + null // PickResult pickResult + ) + ); + + // mainStage.setScene(scene); + // mainStage.show(); + Platform.exit(); + } + + // show engine invocations with script text and their Bindings + static void dumpEvalInformation() { + System.err.println("\nListing eval() invocation information (invocationList):"); + + Iterator it = RgfPseudoScriptEngine.getEnginesUsed().iterator(); + while (it.hasNext()) { + RgfPseudoScriptEngine rpse = it.next(); + ArrayList invocationList = rpse.getInvocationList(); + System.err.println("ScriptEngine: [" + rpse + "]"); + + Iterator itEval = invocationList.iterator(); + int count = 1; + while (itEval.hasNext()) { + System.err.println("\teval() invocation # " + count + ": "); + InvocationInfos entry = itEval.next(); + System.err.println(entry.toDebugFormat("\t\t")); // indentation + count++; + System.err.println(); + } + } + } + + static void assertCorrectInvocations() { + // test only creates one engine for a script controller + Util.assertTrue("exactly one pseudo script engine instance", + RgfPseudoScriptEngine.getEnginesUsed().size() == 1); + RgfPseudoScriptEngine rpse = RgfPseudoScriptEngine.getEnginesUsed().get(0); + + ArrayList invocationList = rpse.getInvocationList(); + Util.assertTrue("exactly nine script engine invocations", invocationList.size() == 9); + + final String FILENAME = "javax.script.filename"; + final String ARGV = "javax.script.argv"; + final String EVENT = "event"; + final String IDBUTTON = "idButton"; + final String IDROOT = "idRoot"; + final String LOCATION = "location"; // always FXML File hosting script controller code + final String RESOURCES = "resources"; // always null in this test + + for (Integer invocation = 1; invocation <= invocationList.size(); invocation++) { + InvocationInfos entry = (InvocationInfos) invocationList.get(invocation - 1); + String script = entry.script; + TreeMap scopes = (TreeMap) entry.bindings; + + TreeMap engineBindings = scopes.get(100); + TreeMap globalBindings = scopes.get(200); + + Object obj = null; + Button btn = null; + + // global Bindings + Util.assertExists(IDROOT + " in global scope Bindings", globalBindings.containsKey(IDROOT)); + obj = globalBindings.get(IDROOT); + Util.assertType(IDROOT, AnchorPane.class, obj); + + Util.assertExists(LOCATION + " in global scope Bindings", globalBindings.containsKey(LOCATION)); + obj = globalBindings.get(LOCATION); + Util.assertType(LOCATION, URL.class, obj); + + Util.assertExists(RESOURCES + " in global scope Bindings", globalBindings.containsKey(RESOURCES)); + obj = globalBindings.get(RESOURCES); + Util.assertNull(RESOURCES,obj); + + if (invocation == 1) { + Util.assertNotExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + } + else { + Util.assertExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + obj = globalBindings.get(IDBUTTON); + Util.assertType(IDBUTTON, Button.class, obj); + btn = (Button) obj; + } + + // engine Bindings + Util.assertExists(FILENAME + " in engine scope Bindings", engineBindings.containsKey(FILENAME)); + if (invocation < 7) { // no event objects, no arguments + Util.assertNotExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Util.assertNotExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + } + else { // this has events on the Button + Util.assertExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Object[] argv = (Object[]) engineBindings.get(ARGV); + + Util.assertExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + obj = engineBindings.get(EVENT); + + Util.assertSame("argv[0] == event", argv[0], obj); + + if (invocation == 9) { + Util.assertType(EVENT, MouseEvent.class, obj); + MouseEvent ev = (MouseEvent) obj; + Util.assertSame("MouseEvent.getSource() == btn", ev.getSource(), btn); + Util.assertSame("MouseEvent.MOUSE_CLICKED", MouseEvent.MOUSE_CLICKED, ev.getEventType()); + } else { + Util.assertType(EVENT, ActionEvent.class, obj); + ActionEvent ev = (ActionEvent) obj; + Util.assertSame("ActionEvent.getSource() == btn", ev.getSource(), btn); + } + } + + // check filename and script + String filename = (String) engineBindings.get(FILENAME); + boolean ok = false; + switch (invocation) { + case 1: + Util.assertEndsWith ("demo_01_topscript.rpsl", filename); + Util.assertStartsWith("demo_01_topscript.rpsl file - pseudo script", script); + break; + + case 2: + Util.assertEndsWith ("demo_01_middlescript.rpsl", filename); + Util.assertStartsWith("demo_01_middlescript.rpsl file - pseudo script", script); + break; + + case 3: + Util.assertEndsWith("demo_01.fxml-script_starting_at_line_52", filename); + Util.assertStartsWith("demo_01.fxml embedded script rpsl - line # 52", script); + break; + + case 4: + Util.assertEndsWith ("demo_01_bottomscript.rpsl", filename); + Util.assertStartsWith("demo_01_bottomscript.rpsl file - pseudo script", script); + break; + + case 5: + Util.assertEndsWith("demo_01.fxml-script_starting_at_line_56", filename); + Util.assertStartsWith("something (line # 56)", script); + break; + + case 6: + Util.assertEndsWith("demo_01.fxml-script_starting_at_line_59", filename); + Util.assertStartsWith("demo_01.fxml (line # 59):", script); + break; + + case 7: // same as case 8 (same button clicked) + Util.assertEndsWith("demo_01.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_01.fxml embedded event - ActionEvent - line # 45 -", script); + break; + + case 8: // same as case 7 (same button clicked) + Util.assertEndsWith("demo_01.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_01.fxml embedded event - ActionEvent - line # 45 -", script); + break; + + case 9: + Util.assertEndsWith("demo_01.fxml-onMouseClicked_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_01.fxml embedded event - MouseClicked - line # 44", script); + break; + } + } + } +} diff --git a/tests/system/src/testscriptapp1/java/mymod/myapp1/Util.java b/tests/system/src/testscriptapp1/java/mymod/myapp1/Util.java new file mode 100644 index 00000000000..991e718a5ed --- /dev/null +++ b/tests/system/src/testscriptapp1/java/mymod/myapp1/Util.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017, 2020, 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 myapp1; // from myapp6 + +import java.net.URL; + +public class Util { + + public static final URL getURL(Class clazz, String name) { + final String theName = name + ".fxml"; + final URL fxmlFile = clazz.getResource(theName); + if (fxmlFile == null) { + throw new AssertionError("(getURL()) unable to open: " + theName); + } + return fxmlFile; + } + + public static void assertNull(String message, Object o) { + if (o != null) { + throw new AssertionError("(assertNull) " + message + ", expected null object, but was non-null"); + } + } + + public static void assertNotNull(Object o) { + if (o == null) { + throw new AssertionError("(assertNotNull) expected non-null object, but was null"); + } + } + + public static void assertEndsWith(String expected, String observed) { + if ((expected == null && observed != null) || !observed.endsWith(expected)) { + throw new AssertionError("(assertEndsWith) " + "expected: <" + expected + "> but was: <" + observed + ">"); + } + } + + public static void assertStartsWith(String expected, String observed) { + if ((expected == null && observed != null) || !observed.startsWith(expected)) { + throw new AssertionError("(assertStartsWith) " + "expected: <" + expected + "> but was: <" + observed + ">"); + } + } + + + public static void assertSame(String message, Object expected, Object observed) { + if (expected != observed) { + throw new AssertionError("(assertSame) "+ message + ", expected: <" + expected + "> but was: <" + observed + ">"); + } + } + + public static void assertTrue(String message, boolean cond) { + if (!cond) { + throw new AssertionError("(assertTrue): " + message); + } + } + + public static void assertFalse(String message, boolean cond) { + if (cond) { + throw new AssertionError("(assertFalse): " + message); + } + } + + public static void assertExists(String message, boolean cond) { + if (!cond) { + throw new AssertionError("(assertExists): " + message); + } + } + + public static void assertNotExists(String message, boolean cond) { + if (cond) { + throw new AssertionError("(assertNotExists): " + message); + } + } + + public static void assertType(String message, Class clz, Object obj) { + if (obj == null) { + throw new AssertionError("(assertType): " + message+": \"obj\" is null"); + } + else if (clz == null) { + throw new AssertionError("(assertType): " + message+": \"clz\" is null"); + } + + if (! clz.isInstance(obj)) { + throw new AssertionError("(assertType): " + message + + ", object " + obj + + " is not an instance of class " + + clz + " -> " + clz.getName() + "]"); + } + } + + private Util() { + } +} diff --git a/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/InvocationInfos.java b/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/InvocationInfos.java new file mode 100644 index 00000000000..b7d0378a84a --- /dev/null +++ b/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/InvocationInfos.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020, 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 pseudoScriptEngine; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Set; +import java.util.TreeMap; + + +/** Stores PseudoScriptEngine related invocation information for asserting and debugging. */ +public class InvocationInfos { + public String script; + public TreeMap> bindings; + public Instant dateTime; + + InvocationInfos(String script, ScriptContext context) { + this.dateTime = Instant.now(); + this.script = script; + this.bindings = new TreeMap(); + // get and save each Bindings + for (Integer scope : context.getScopes()) { + Bindings binding = context.getBindings(scope); + bindings.put(scope, binding == null ? new TreeMap() : new TreeMap(binding)); + } + } + + /** + * Creates and returns a string having all information formatted to ease debugging. + * @return string formatted to ease debugging + */ + public String toDebugFormat(String indentation) { + StringBuilder sb = new StringBuilder(); + String indent = (indentation == null ? "\t\t" : indentation); + sb.append(indent).append("at: [").append(dateTime.toString()).append("]\n"); + sb.append(indent).append("script: [").append(script) .append("]\n"); + + for (Integer scope : (Set) bindings.keySet()) { + sb.append(indent).append("Bindings for scope # ").append(scope); + if (scope == 100) sb.append(" (ENGINE_SCOPE):"); + else if (scope == 200) sb.append(" (GLOBAL_SCOPE):"); + else sb.append(':'); + sb.append('\n'); + + TreeMap treeMap = bindings.get(scope); + for (String k : (Set) treeMap.keySet()) { + sb.append(indent).append("\t[").append(k).append("]:\t[").append(treeMap.get(k)).append("]\n"); + } + } + return sb.toString(); + } +} diff --git a/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/RgfPseudoScriptEngine.java b/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/RgfPseudoScriptEngine.java new file mode 100644 index 00000000000..3f99d2138ea --- /dev/null +++ b/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/RgfPseudoScriptEngine.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2020, 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 pseudoScriptEngine; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +import javax.script.AbstractScriptEngine; +import javax.script.SimpleScriptContext; +import javax.script.SimpleBindings; + +import java.util.ArrayList; +import java.util.Set; +import java.util.TreeMap; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.IOException; + +import java.time.Instant; + +public class RgfPseudoScriptEngine extends AbstractScriptEngine { + static final boolean bDebug = false; // true; + + /** Allows to log and access the ScriptEngine instances with their evalDataList. */ + static final ArrayList enginesUsed = new ArrayList(); + public static ArrayList getEnginesUsed() { + return enginesUsed; + } + + public RgfPseudoScriptEngine() { + enginesUsed.add(this); + } + + public ScriptEngineFactory getFactory() { + return new RgfPseudoScriptEngineFactory(); + } + + /** ArrayList of eval() (invocation) information. */ + final ArrayList invocationList = new ArrayList(); + + /** Returns ArrayList of eval() (invocation) information. + * @return invocationList + */ + public ArrayList getInvocationList() { + return invocationList; + } + + public Bindings createBindings() { + return new SimpleBindings(); + } + + public Object eval(Reader reader, ScriptContext context) { + if (bDebug) System.err.println("[debug: " + this + ".eval(Reader,ScriptContext), ScriptContext=" + context + "]"); + + return eval(readReader(reader), context); + } + + + public Object eval(String script, ScriptContext context) { + if (bDebug) System.err.print("[debug: " + this + ".eval(String,ScriptContext), ScriptContext=" + context + "]"); + + // create copies of the Bindings for later inspection as they may + // get reused and changed on each eval() invocation + TreeMap bindings = new TreeMap(); + for (Integer scope : context.getScopes()) { + Bindings binding = context.getBindings(scope); + bindings.put(scope, binding == null ? new TreeMap() : new TreeMap(binding)); + } + invocationList.add(new InvocationInfos(script,context)); + if (bDebug) System.err.println(" | invocationList.size()=" + invocationList.size()); + return invocationList; + } + + + String readReader(Reader reader) { + if (reader == null) { + return ""; + } + + BufferedReader bufferedReader = new BufferedReader(reader); + StringBuilder sb = new StringBuilder(); + // caters for possible IOException in read() and close() + try { + try { + char[] charBuffer = new char[1024]; + int r = 0; + + while ((r = bufferedReader.read(charBuffer)) != -1) { + sb.append(charBuffer, 0, r); + } + } finally { + bufferedReader.close(); + } + } catch (IOException ioe) { + throw new RuntimeException(ioe.getMessage(), ioe); + } + return sb.toString(); + } +} diff --git a/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/RgfPseudoScriptEngineFactory.java b/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/RgfPseudoScriptEngineFactory.java new file mode 100644 index 00000000000..dc591447112 --- /dev/null +++ b/tests/system/src/testscriptapp1/java/mymod/pseudoScriptEngine/RgfPseudoScriptEngineFactory.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2020, 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 pseudoScriptEngine; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +import java.lang.StringBuilder; +import java.util.Arrays; +import java.util.List; + + +public class RgfPseudoScriptEngineFactory implements ScriptEngineFactory { + static final String ENGINE_NAME = "RgfPseudoScriptLanguage (RPSL) 1.0.0"; + static final String SHORT_ENGINE_NAME = "rpsl"; + static final String ENGINE_VERSION = "100.20200228"; + static final List EXTENSIONS = Arrays.asList("rpsl", "RPSL"); + static final String LANGUAGE_NAME = "RgfPseudoScriptLanguage"; + static final String LANGUAGE_VERSION = "1.0.0.100.20200228"; + static final List MIME_TYPES = Arrays.asList("text/rpsl", "application/x-rpsl"); + static final String THREADING = "MULTITHREADED"; + static final List ENGINE_NAMES = Arrays.asList(SHORT_ENGINE_NAME, "RgfPseudoSL"); + + public String getEngineName() { + return ENGINE_NAME; + } + + public String getEngineVersion() { + return ENGINE_VERSION; + } + + public List getExtensions() { + return EXTENSIONS; + } + + public String getLanguageName() { + return LANGUAGE_NAME; + } + + public String getLanguageVersion() { + return LANGUAGE_VERSION; + } + + public String getName() { + return ENGINE_NAME; + } + + public String getMethodCallSyntax(String obj, String m, String... args) { + return "obj~(m, ...) /* ooRexx style */ "; + } + + public List getMimeTypes() { + return MIME_TYPES; + } + + public List getNames() { + return ENGINE_NAMES; + } + + public String getOutputStatement(String toDisplay) { + String tmpDisplay = toStringLiteral(toDisplay); + return "say " + tmpDisplay + " /* Rexx style (duplicate quotes within string) */ "; + } + + String toStringLiteral(String toDisplay) { + if (toDisplay == null) { + return "\"\""; + } + return '"' + toDisplay.replace("\"","\"\"") + '"'; + } + + public Object getParameter(final String key) { + switch (key) { + case "THREADING": + return THREADING; + + case ScriptEngine.NAME: + return SHORT_ENGINE_NAME; + + case ScriptEngine.ENGINE: + return ENGINE_NAME; + + case ScriptEngine.ENGINE_VERSION: + return ENGINE_VERSION; + + case ScriptEngine.LANGUAGE: + return LANGUAGE_NAME; + + case ScriptEngine.LANGUAGE_VERSION: + return LANGUAGE_VERSION; + + default: + return null; + } + } + + public String getProgram(String... statements) { + if (statements == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < statements.length; i++) { + if (statements[i] == null) { + sb.append("\tsay 'null'; /* Rexx style */ \n"); + } + else { + sb.append("\t" + statements[i] + ";\n"); + } + } + return sb.toString(); + } + + public ScriptEngine getScriptEngine() { + return new RgfPseudoScriptEngine(); + } +} diff --git a/tests/system/src/testscriptapp1/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory b/tests/system/src/testscriptapp1/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 00000000000..b2ef7c5bac0 --- /dev/null +++ b/tests/system/src/testscriptapp1/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1,2 @@ +pseudoScriptEngine.RgfPseudoScriptEngineFactory + diff --git a/tests/system/src/testscriptapp1/resources/mymod/myapp1/demo_01.fxml b/tests/system/src/testscriptapp1/resources/mymod/myapp1/demo_01.fxml new file mode 100644 index 00000000000..23a899eb041 --- /dev/null +++ b/tests/system/src/testscriptapp1/resources/mymod/myapp1/demo_01.fxml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + +