Skip to content
Snippets Groups Projects
Commit a9bd4661 authored by Alexander Diewald's avatar Alexander Diewald
Browse files

Merge branch '3437' into 'master'

3437

See merge request !82
parents 3d43baff cad4fb20
No related branches found
No related tags found
1 merge request!823437
Showing
with 261 additions and 157 deletions
......@@ -100,6 +100,7 @@ Export-Package: aerofx,
org.fortiss.tooling.common.ui,
org.fortiss.tooling.common.ui.javafx,
org.fortiss.tooling.common.ui.javafx.control.treetableview,
org.fortiss.tooling.common.ui.javafx.layout,
org.fortiss.tooling.common.ui.javafx.util
Bundle-Vendor: fortiss GmbH
Bundle-Activator: org.fortiss.tooling.common.ui.ToolingCommonUIActivator
......
......@@ -595,10 +595,6 @@
* TextBox (and PasswordBox) *
* *
******************************************************************************/
.text-field{
-fx-skin: "jfxtras.styles.jmetro8.MetroTextFieldSkin";
}
.text-input{
-fx-background-radius: 0, 0;
......@@ -666,11 +662,6 @@
* PasswordBox *
* *
******************************************************************************/
.password-field {
-fx-skin: "jfxtras.styles.jmetro8.MetroPasswordFieldSkin";
}
.password-field > .right-button > .right-button-graphic {
-fx-shape : "M307.688,399.564c0,1.484-1.203,2.688-2.688,2.688c-1.484,0-2.688-1.203-2.688-2.688s1.203-2.688,2.688-2.688C306.484,396.876,307.688,398.08,307.688,399.564z M297.5,399h2.5c0,0,1.063-4,5-4c3.688,0,5,4,5,4h2.5c0,0-2.063-6.5-7.5-6.5C299,392.5,297.5,399,297.5,399z";
-fx-scale-shape: false;
......@@ -699,11 +690,6 @@
* Slider *
* *
******************************************************************************/
.slider {
-fx-skin: "jfxtras.styles.jmetro8.FilledSliderSkin";
}
.slider .thumb {
-fx-background-color: black;
-fx-background-insets: 0;
......@@ -785,7 +771,6 @@
******************************************************************************/
.ListSpinner {
-fx-skin: "jfxtras.labs.internal.scene.control.skin.ListSpinnerCaspianSkin";
-fx-background-color: #f0f0f0;
-fx-background-insets: 0 0 0 0;
-fx-background-radius: 0;
......@@ -843,10 +828,6 @@
-fx-background-radius: 0;
}
.spinner > .text-field{
-fx-skin: "com.sun.javafx.scene.control.skin.TextFieldSkin";
}
.spinner > .text-field {
-fx-background-color: #f0f0f0;
-fx-background-insets: 0;
......@@ -903,10 +884,6 @@
-fx-scale-shape: true;
}
.date-picker .text-field{
-fx-skin: "com.sun.javafx.scene.control.skin.TextFieldSkin";
}
.date-picker .text-input{
-fx-background-radius: 0, 0;
......
AF3FXViewPart.java 865b996b5eb092bb30c161d026163a0f8fc66c41 GREEN
AF3FXViewPart.java 3e4510f9e9f86ecf5ba29432342acd50e030aaaa GREEN
......@@ -15,76 +15,48 @@
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.common.ui.javafx;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import static javafx.scene.layout.AnchorPane.setBottomAnchor;
import static javafx.scene.layout.AnchorPane.setLeftAnchor;
import static javafx.scene.layout.AnchorPane.setRightAnchor;
import static javafx.scene.layout.AnchorPane.setTopAnchor;
import java.net.URL;
import java.util.ResourceBundle;
import org.apache.commons.lang3.SystemUtils;
import org.eclipse.fx.ui.workbench3.FXViewPart;
import org.eclipse.ui.part.ViewPart;
import org.fortiss.tooling.common.ui.javafx.layout.ICompositeFXController;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
/**
* Base class to create eclipse (SWT-based) views using JavaFX GUI elements. This class requires
* FXML file that defines the GUI elements of the view.
* Base class to create eclipse (SWT-based) views using JavaFX GUI elements.
*
* @author diewald
* @author munaro
*/
public abstract class AF3FXViewPart extends FXViewPart implements Initializable {
public abstract class AF3FXViewPart extends FXViewPart {
/** For later use, if we need to define different styles. */
private String cssLocation;
/** Flag that indicates if a custom style sheet has been applied. */
private boolean isCustomStyleSheetApplied;
/**
* Holds the relative location of the FXML JavaXML files. Roots are the source folders of the
* (plugin) project.
*/
private final String fXMLLocation;
/** 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 that is intended for {@link ViewPart}s which host a single view/node/control.
*
* @param viewerClass
* 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 cssLocation)
throws Exception {
// Initializing the base constructor with "null" for the FXML file indicates a
// single-view/node/control usecase.
this(viewerClass, null, cssLocation);
}
/** Specifies the view part's layout and logic. */
private ICompositeFXController<? extends Node, ? extends Node> controller;
/**
* Constructor. Allows to pass the view's FXML definition file.
*
* @param viewerClass
* 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 controller
* {@link ICompositeFXController} specifying the layout of the view part as well as
* its logic.
* @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.
......@@ -92,51 +64,31 @@ public abstract class AF3FXViewPart extends FXViewPart implements Initializable
* 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(ICompositeFXController<? extends Node, ? extends Node> controller,
String cssLocation) throws Exception {
Platform.setImplicitExit(false);
this.viewerClass = viewerClass;
this.fXMLLocation = fXMLLocation;
this.cssLocation = cssLocation;
this.controller = controller;
}
/** {@inheritDoc} */
@Override
protected Scene createFxScene() {
FXMLLoader loader = new FXMLLoader();
loader.setClassLoader(viewerClass.getClassLoader());
loader.setController(this);
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", URL.class, ResourceBundle.class).invoke(this,
null, null);
} 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);
}
}
controller.loadLayout();
Node layout = controller.getLayout();
setTopAnchor(layout, 0.0);
setRightAnchor(layout, 0.0);
setBottomAnchor(layout, 0.0);
setLeftAnchor(layout, 0.0);
root = new AnchorPane(layout);
if(cssLocation != null) {
isCustomStyleSheetApplied = applyStyleSheet(root, getClass(), cssLocation);
}
if(!isCustomStyleSheetApplied) {
setNativeLook(root);
}
Scene scene = new Scene(root);
return scene;
}
......@@ -147,36 +99,6 @@ public abstract class AF3FXViewPart extends FXViewPart implements Initializable
// 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 not break the UI experience. Most of the UI
* code is based on SWT which uses a platform native look. Currently, Windows 8&10, Windows 7,
......
DynamicTreeContentProviderBase.java dff437afeaf7486af05460fa54eca4fa61d7eae6 GREEN
DynamicTreeItem.java afc105cf5acf3d2506d89e0892555100c234ce5b GREEN
DynamicTreeTableUIProviderBase.java fd9fce19a65eb1006ceacb0d869bbe90a8c578b3 GREEN
DynamicTreeTableViewer.java e474f3a890fd6525db7de8e299d7fbe67f932a15 GREEN
DynamicTreeTableViewer.java 4f278387dd90542adc07bf0da12e92d4eaad79c4 GREEN
DynamicTreeUIProviderBase.java 56fe4df4577b35f1e5e6e4c4be189b706c852d52 GREEN
DynamicTreeViewer.java da5e24ae57777a482d8e12c8262513d8143bfa93 GREEN
DynamicTreeViewerBase.java 47124c847de322a0ae26eb7a114f85ce4bd02d7e GREEN
......
......@@ -15,13 +15,17 @@
*******************************************************************************/
package org.fortiss.tooling.common.ui.javafx.control.treetableview;
import javafx.beans.property.ReadOnlyStringWrapper;
import static javafx.scene.control.cell.TextFieldTreeTableCell.forTreeTableColumn;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.util.Callback;
/**
* A JavaFX {@link TreeTableView} based on an {@link DynamicTreeContentProviderBase} and
......@@ -51,6 +55,8 @@ public final class DynamicTreeTableViewer<T> extends DynamicTreeViewerBase<T> {
DynamicTreeItem<T> rootItem = new DynamicTreeItem<T>(root, this);
view.setRoot(rootItem);
view.setShowRoot(showRoot);
view.setEditable(true);
view.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
rootItem.update();
// expand to reveal (+1 if root node is not shown
expandItem(rootItem, showRoot ? revealLevel : revealLevel + 1);
......@@ -82,35 +88,53 @@ public final class DynamicTreeTableViewer<T> extends DynamicTreeViewerBase<T> {
}
}
/** Adds a column to the table part of the view. */
public void addColumn(String headerLabel, int prefWidth) {
final int num = view.getColumns().size();
TreeTableColumn<T, String> col = new TreeTableColumn<>(headerLabel);
col.setPrefWidth(prefWidth);
col.setCellValueFactory(param -> {
/**
* Adds a column to the table part of the view. The labels, context menus and icons are shown as
* defined in the {@link DynamicTreeTableUIProviderBase}.
*/
public TreeTableColumn<T, String> addColumn(String headerLabel, int prefWidth,
boolean readOnly) {
int num = view.getColumns().size();
TreeTableColumn<T, String> column = new TreeTableColumn<>(headerLabel);
column.setPrefWidth(prefWidth);
column.setCellValueFactory(param -> {
Object data = param.getValue().getValue();
return new ReadOnlyStringWrapper(uiProvider.getLabel(data, num));
return new SimpleObjectProperty<String>(uiProvider.getLabel(data, num));
});
col.setCellFactory(param -> {
TreeTableCell<T, String> cell = new TreeTableCell<T, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
ContextMenu menu = null;
Node icon = null;
if(!empty && item != null) {
T data = this.getTreeTableRow().getItem();
menu = uiProvider.createContextMenu(data, num);
icon = uiProvider.getIconNode(data, num);
Callback<TreeTableColumn<T, String>, TreeTableCell<T, String>> cellFactory;
if(readOnly) {
// Read only cell with the icon and context menu as specified in the UI provider
cellFactory = param -> {
TreeTableCell<T, String> cell = new TreeTableCell<T, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
ContextMenu menu = null;
Node icon = null;
int index = view.getColumns().size() - 1;
if(!empty && item != null) {
T data = this.getTreeTableRow().getItem();
menu = uiProvider.createContextMenu(data, index);
icon = uiProvider.getIconNode(data, index);
}
this.setContextMenu(menu);
this.setGraphic(icon);
}
this.setContextMenu(menu);
this.setGraphic(icon);
}
};
cell.textProperty().bind(cell.itemProperty());
return cell;
};
cell.textProperty().bind(cell.itemProperty());
return cell;
});
view.getColumns().add(col);
} else {
// Editable text field
cellFactory = forTreeTableColumn();
}
column.setCellFactory(cellFactory);
view.getColumns().add(column);
return column;
}
/** Returns the underlying {@link TreeTableView}. */
......
CompositeFXControllerBase.java 3c411746e6d3733d66194506effcc276ad9b5613 GREEN
ICompositeFXController.java 8476557dedab914c87c2931a09aad8e628463f30 GREEN
/*-------------------------------------------------------------------------+
| Copyright 2019 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.common.ui.javafx.layout;
import static java.util.Arrays.asList;
import static javafx.scene.layout.AnchorPane.setBottomAnchor;
import static javafx.scene.layout.AnchorPane.setLeftAnchor;
import static javafx.scene.layout.AnchorPane.setRightAnchor;
import static javafx.scene.layout.AnchorPane.setTopAnchor;
import static org.fortiss.tooling.common.ui.javafx.util.JavaFXUtils.loadFXML;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.layout.AnchorPane;
/**
* JavaFX node which can be hierarchically composed. It can be included within another
* {@link CompositeFXControllerBase} and might contain other {@link CompositeFXControllerBase}s.
*
* @param <T>
* Type of the controlled element itself.
* @param <S>
* Type of the layout elements which can be contained.
*
* @author munaro
*/
public abstract class CompositeFXControllerBase<T extends Node, S extends Node>
implements ICompositeFXController<T, S> {
/**
* JavaFX {@link Node} with the layout specified in the {@link FXML} resource and
* associated with a controller of type {@code T}.
*/
private T layout;
/**
* {@link ICompositeFXController}s to be added to the {@link Node} by the
* {@code addContainments} method.
*/
private ICompositeFXController<? extends S, ?>[] containments;
/** Constructor. */
@SuppressWarnings("unchecked")
public CompositeFXControllerBase(ICompositeFXController<? extends S, ?>... containments) {
this.containments = containments;
}
/** {@inheritDoc} */
@Override
public T getLayout() {
return layout;
}
/** {@inheritDoc} */
@Override
public List<ICompositeFXController<? extends S, ?>> getContainments() {
return asList(containments);
}
/** {@inheritDoc} */
@Override
public void loadLayout() {
getContainments().forEach(containment -> containment.loadLayout());
if(layout == null) {
URL fxmlResource = getClass().getResource(getFXMLLocation());
try {
layout = loadFXML(fxmlResource, this);
} catch(IOException e) {
throw new RuntimeException(
"Cannot load the resource located at " + getFXMLLocation(), e);
}
}
}
/**
* If the container is an {@link AnchorPane}, all margins are removed so as to fit the child to
* the anchor pane's size.
*/
protected void fitToParent(Node child) {
if(child.getParent() instanceof AnchorPane) {
setBottomAnchor(child, 0.0);
setTopAnchor(child, 0.0);
setLeftAnchor(child, 0.0);
setRightAnchor(child, 0.0);
}
}
}
/*-------------------------------------------------------------------------+
| Copyright 2019 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.common.ui.javafx.layout;
import java.util.List;
import javafx.fxml.FXML;
import javafx.scene.Node;
/**
* Generic interface for JavaFX controllers which can be hierarchically composed.
*
* @param <T>
* Type of the controlled element itself.
* @param <S>
* Type of the layout elements which can be contained.
*
* @author munaro
*/
public interface ICompositeFXController<T extends Node, S extends Node> {
/** Loads the the JavaFX layout from the specified {@link FXML} resource. */
public void loadLayout();
/** Returns a {@link Node} with the layout. */
public T getLayout();
/** Returns the location of the {@link FXML} resource with the layout. */
public String getFXMLLocation();
/** Initializes the {@link ICompositeFXController}. */
public void initialize();
/** Returns the {@link ICompositeFXController} containments. */
public List<ICompositeFXController<? extends S, ?>> getContainments();
}
GraphicUtils.java 4d471a310a52bda1c090f956dcdbe90775b12cb8 GREEN
SceneGraphUtils.java f54304c2eb604934de9afdf9d2a8ca88a762398a GREEN
JavaFXUtils.java db3cf28289109ffec64c8f96c7b2de779a977b3b GREEN
......@@ -15,10 +15,14 @@
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.common.ui.javafx.util;
import java.io.IOException;
import java.net.URL;
import java.util.LinkedList;
import java.util.Queue;
import java.util.function.Predicate;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
......@@ -28,14 +32,35 @@ import javafx.scene.Scene;
*
* @author hoelzl
* @author diewald
* @author munaro
*/
public final class SceneGraphUtils {
public final class JavaFXUtils {
/** Prevent instantiation. */
private SceneGraphUtils() {
private JavaFXUtils() {
// Nothing to do
}
/**
* Loads a JavaFX layout from an {@link FXML} resource and associates it with the given
* controller.
*
* @param fxmlResource
* {@link URL} of the {@link FXML} resource to load.
* @param controller
* Controller to be added to associated with the returned scene.
* @return The loaded object hierarchy. See {@link FXMLLoader} for more information.
* @throws IOException
*/
public static <T> T loadFXML(URL fxmlResource, Object controller) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setClassLoader(controller.getClass().getClassLoader());
fxmlLoader.setController(controller);
fxmlLoader.setLocation(fxmlResource);
return fxmlLoader.load();
}
/**
* Searches the scene graph hierarchy for the nearest parent node of the given class.
*
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment