
org.testfx.util.NodeQueryUtils Maven / Gradle / Ivy
/*
* Copyright 2013-2014 SmartBear Software
* Copyright 2014-2019 The TestFX Contributors
*
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the
* European Commission - subsequent versions of the EUPL (the "Licence"); You may
* not use this work except in compliance with the Licence.
*
* You may obtain a copy of the Licence at:
* http://ec.europa.eu/idabc/eupl.html
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the Licence for the
* specific language governing permissions and limitations under the Licence.
*/
package org.testfx.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Labeled;
import javafx.scene.control.PopupControl;
import javafx.scene.control.TextInputControl;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.Window;
import org.hamcrest.Matcher;
import static org.testfx.internal.JavaVersionAdapter.isNotVisible;
public final class NodeQueryUtils {
private NodeQueryUtils() {}
/**
* Returns a set of the given windows' scenes' root nodes.
*/
public static Set rootsOfWindows(Collection windows) {
return windows.stream()
.map(NodeQueryUtils::fromWindow)
.collect(Collectors.toSet());
}
/**
* Returns a set of the given windows' scenes' root nodes.
*/
public static Set rootOfWindow(Window... windows) {
// TODO: is this set (toSet()) in order?
return Arrays.stream(windows)
.map(NodeQueryUtils::fromWindow)
.collect(Collectors.toSet());
}
/**
* Returns a set of the given stages' scenes' root nodes.
*/
public static Set rootOfStage(Stage... stages) {
return Arrays.stream(stages)
.map(NodeQueryUtils::fromStage)
.collect(Collectors.toSet());
}
/**
* Returns a set of the given scenes' root nodes.
*/
public static Set rootOfScene(Scene... scenes) {
return Arrays.stream(scenes)
.map(NodeQueryUtils::fromScene)
.collect(Collectors.toSet());
}
/**
* Returns a set of the given popup controls' scenes' root nodes.
*/
public static Set rootOfPopupControl(PopupControl... popupControls) {
return Arrays.stream(popupControls)
.map(NodeQueryUtils::fromPopupControl)
.collect(Collectors.toSet());
}
/**
* Returns a function that calls {@link Node#lookup(String)} on each given node.
*/
public static Function> bySelector(String selector) {
return parentNode -> lookupWithSelector(parentNode, selector);
}
/**
* Returns a function that returns a {@code Set} of all {@code Node}s that pass the given {@code predicate}.
*/
public static Function> byPredicate(Predicate predicate) {
return parentNode -> lookupWithPredicate(parentNode, predicate);
}
/**
* Returns a function that returns a {@code Set} of all {@code Node}s that match the given {@code matcher}.
*/
public static Function> byMatcher(Matcher matcher) {
return byPredicate(matchesMatcher(matcher));
}
/**
* Returns a function that returns a {@code Set} of all {@link javafx.scene.control.Label}s,
* {@link TextInputControl}s, or any of their subclasses that have the given {@code text}.
*/
public static Function> byText(String text) {
return byPredicate(hasText(text));
}
/**
* Returns a predicate that returns true if the node's id equals the given {@code id}.
*/
public static Predicate hasId(String id) {
return node -> Objects.equals(node.getId(), id);
}
/**
* Returns a predicate that returns true if the node is a {@link javafx.scene.control.Label},
* {@link TextInputControl}, or any of their subclasses whose text equals the given {@code text}.
*/
public static Predicate hasText(String text) {
return node -> hasNodeText(node, text);
}
/**
* Returns a predicate that returns true if the given node matches the given {@code matcher}.
*/
public static Predicate matchesMatcher(Matcher matcher) {
return node -> matchesNodeMatcher(node, matcher);
}
/**
* Returns a predicate that returns true if the given node is visible, the given tree is visible, or the
* node's local bounds are within its scene's bounds
*/
public static Predicate isVisible() {
return NodeQueryUtils::isNodeVisible;
}
/**
* Returns a function that returns a {@code Set} of all {@code Node}s that maps the given node by {@code function0}
* and then by {@code function1)}.
*/
public static Function> combine(Function> function0,
Function> function1) {
List>> functions = new ArrayList<>();
functions.add(function0);
functions.add(function1);
return input -> combine(input, functions);
}
private static Parent fromWindow(Window window) {
return window.getScene().getRoot();
}
private static Parent fromStage(Stage stage) {
return stage.getScene().getRoot();
}
private static Parent fromScene(Scene scene) {
return scene.getRoot();
}
private static Parent fromPopupControl(PopupControl popupControl) {
return popupControl.getScene().getRoot();
}
private static Set lookupWithSelector(Node parentNode, String selector) {
return parentNode.lookupAll(selector);
}
private static Set lookupWithPredicate(Node parentNode, Predicate predicate) {
Set resultNodes = new LinkedHashSet<>();
if (applyPredicateSafely(predicate, parentNode)) {
resultNodes.add(parentNode);
}
if (parentNode instanceof Parent) {
List childNodes = ((Parent) parentNode).getChildrenUnmodifiable();
for (Node childNode : childNodes) {
resultNodes.addAll(lookupWithPredicate(childNode, predicate));
}
}
return Collections.unmodifiableSet(resultNodes);
}
private static boolean applyPredicateSafely(Predicate predicate, T input) {
// TODO: Test cases with ClassCastException.
try {
return predicate.test(input);
}
catch (ClassCastException ignore) {
return false;
}
}
private static boolean hasNodeText(Node node, String text) {
// TODO: Test cases with node.getText() == null.
if (node instanceof Labeled) {
return Objects.equals(((Labeled) node).getText(), text);
}
else if (node instanceof TextInputControl) {
return Objects.equals(((TextInputControl) node).getText(), text);
}
else if (node instanceof Text) {
return Objects.equals(((Text) node).getText(), text);
}
return false;
}
private static boolean matchesNodeMatcher(Node node, Matcher matcher) {
// TODO: Test cases with ClassCastException.
return matcher.matches(node);
}
@SuppressWarnings("deprecation")
private static boolean isNodeVisible(Node node) {
return !isNotVisible(node) && isNodeWithinSceneBounds(node);
}
private static boolean isNodeWithinSceneBounds(Node node) {
Scene scene = node.getScene();
Bounds nodeBounds = node.localToScene(node.getBoundsInLocal());
return nodeBounds.intersects(0, 0, scene.getWidth(), scene.getHeight());
}
private static Set combine(T input, Collection>> functions) {
return functions.stream()
.map(f -> f.apply(input))
.flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy