diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/.ratings b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/.ratings index 86b47393dc290e086696323a5f07d0be07adb0bb..2e06d6b862828e55a9b03d90a05c2f428f29b04c 100644 --- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/.ratings +++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/.ratings @@ -1 +1 @@ -AF3FXViewPart.java 9e119a36de6ab9e1a07cd416de0126a89514bd38 GREEN +AF3FXViewPart.java 10100de78c542858792cb51a7c3cfe7e55ec95d7 YELLOW diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/AF3FXViewPart.java b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/AF3FXViewPart.java index 9e119a36de6ab9e1a07cd416de0126a89514bd38..10100de78c542858792cb51a7c3cfe7e55ec95d7 100644 --- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/AF3FXViewPart.java +++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/AF3FXViewPart.java @@ -16,11 +16,14 @@ package org.fortiss.tooling.common.ui.javafx; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.net.URL; import javafx.application.Platform; import javafx.fxml.FXMLLoader; +import javafx.scene.Node; import javafx.scene.Scene; +import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import org.apache.commons.lang3.SystemUtils; @@ -54,48 +57,47 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD /** References the stub that defines the FXML file defining the layout and controller. */ private Class<? extends AF3FXViewPart> viewerClass; + /** References the root {@link Pane} to which GUI elements must be added to be displayed. */ + private Pane root; + /** * Constructor. Allows to pass the view's FXML definition file along with style. * * @param viewerClass - * Stub class that defines the FXML file defining the layout and controller - * @param fXMLLocation - * location of the fXML file relative to the source (resource) folders. + * Class implementing the {@link AF3FXViewPart} to load resources from its containing + * bundle. + * @param cssLocation + * style sheet file path for the appearance settings relative to the source + * (resource) folders. Pass {@code null} if the OS-native look shall be used. * @throws Exception * if the given FXML file path is not given or if it cannot be found in any of the * source (resource) folders. */ - public AF3FXViewPart(Class<? extends AF3FXViewPart> viewerClass, String fXMLLocation) + public AF3FXViewPart(Class<? extends AF3FXViewPart> viewerClass, String cssLocation) throws Exception { - if(fXMLLocation == null) { - throw new Exception( - "The location of the FXML file defining the gui elements was not given," + - "or it cannot be found at the given location (" + fXMLLocation + ") " + - "The view will NOT be created."); - } - - Platform.setImplicitExit(false); - this.viewerClass = viewerClass; - this.fXMLLocation = fXMLLocation; + this(viewerClass, null, cssLocation); } /** * Constructor. Allows to pass the view's FXML definition file. * * @param viewerClass - * Stub class that defines the FXML file defining the layout and controller + * Class implementing the {@link AF3FXViewPart} to load resources from its containing + * bundle. * @param fXMLLocation * location of the fXML file relative to the source (resource) folders. * @param cssLocation * style sheet file path for the appearance settings relative to the source - * (resource) folders. + * (resource) folders. Pass {@code null} if the OS-native look shall be used. * @throws Exception * if the given FXML file path is not given or if it cannot be found in any of the * source (resource) folders. */ public AF3FXViewPart(Class<? extends AF3FXViewPart> viewerClass, String fXMLLocation, String cssLocation) throws Exception { - this(viewerClass, fXMLLocation); + Platform.setImplicitExit(false); + this.viewerClass = viewerClass; + this.fXMLLocation = fXMLLocation; this.cssLocation = cssLocation; } @@ -118,14 +120,28 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD /** {@inheritDoc} */ @Override protected Scene createFxScene() { - Pane root = null; FXMLLoader loader = new FXMLLoader(); loader.setClassLoader(viewerClass.getClassLoader()); - loader.setLocation(viewerClass.getResource(fXMLLocation)); - try { - root = (Pane)loader.load(); - } catch(IOException e) { - throw new RuntimeException("Cannot load the resource located at " + fXMLLocation, e); + if(fXMLLocation != null) { + loader.setLocation(viewerClass.getResource(fXMLLocation)); + try { + root = (Pane)loader.load(); + } catch(IOException e) { + throw new RuntimeException("Cannot load the resource located at " + fXMLLocation, e); + } + } else { + root = new AnchorPane(); + try { + viewerClass.getMethod("initialize").invoke(this); + } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | + SecurityException e) { + throw new RuntimeException("The initialize method of the View " + + viewerClass.getSimpleName() + " threw an exception!", e); + } catch(NoSuchMethodException e) { + throw new RuntimeException("For single Controller views, an initialize method is " + + "required that creates the control! This cannot be done in constructors " + + "since the JavaFX toolkit is not initialized in that stage.", e); + } } if(cssLocation != null) { @@ -134,6 +150,7 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD if(!isCustomStyleSheetApplied) { setNativeLook(root); } + Scene scene = new Scene(root); return scene; } @@ -144,6 +161,36 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD // Not needed. } + /** + * Adds a single {@link Node} to this view. It embeds the given {@link Node} to the + * {@link AnchorPane} of this view and stretches it to the borders of the view. + * <p> + * NOTE: This method may only be used for single-control views, not FXML-based ones. + * + * @param fxNode + * {@link Node} to be added to the view. + */ + protected void setChildNodeFinal(Node fxNode) { + if(fXMLLocation != null) { + throw new RuntimeException("This method is intended for single-control views. It may" + + " not be used for FXML-based views."); + } + if(!root.getChildren().isEmpty()) { + throw new RuntimeException("The method setChildNodeFinal was invoked more than once." + + " This method is intended for single-control views. If more controls" + + "shall be added, please define an FXML layout file and call the appropriate" + + " constructors."); + } + + root.getChildren().add(fxNode); + // Stretch the node to the borders of the view. In the createScene method, we a create a + // root pane that is an AnchorPane, so we can safely use these calls here. + AnchorPane.setTopAnchor(fxNode, 0.0); + AnchorPane.setRightAnchor(fxNode, 0.0); + AnchorPane.setBottomAnchor(fxNode, 0.0); + AnchorPane.setLeftAnchor(fxNode, 0.0); + } + /** * Sets the native look of the target platform to break the UI. Most of the UI code is based on * SWT which uses a platform native look. Currently, Windows 8&10, Windows 7, and MacOS X native