package at.bestsolution.efxclipse.runtime.workbench.renderers;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javafx.application.ConditionalFeature;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javax.inject.Inject;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.model.application.ui.MElementContainer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.workbench.IPresentationEngine;
import org.eclipse.emf.common.util.URI;
import org.osgi.framework.Bundle;
import at.bestsolution.efxclipse.runtime.di.InjectingFXMLLoader;
import at.bestsolution.efxclipse.runtime.panels.FillLayoutPane;
import at.bestsolution.efxclipse.runtime.services.theme.Theme;
import at.bestsolution.efxclipse.runtime.services.theme.ThemeManager;
import at.bestsolution.efxclipse.runtime.services.theme.ThemeManager.Registration;
import at.bestsolution.efxclipse.runtime.workbench.renderers.internal.WindowResizeButton;
@SuppressWarnings("restriction")
public class WorkbenchWindowRenderer extends JFXRenderer {
@Inject
@Optional
ThemeManager themeManager;
private Registration sceneRegistration;
@Inject
IEventBroker broker;
private WindowResizeButton windowResizeButton;
@SuppressWarnings("deprecation")
@Override
public Object createWidget(MUIElement element, Object parent) {
if (element instanceof MWindow) {
final MWindow e = (MWindow) element;
Stage stage = new Stage();
stage.setX(e.getX());
stage.setY(e.getY());
stage.setWidth(e.getWidth());
stage.setHeight(e.getHeight());
stage.setTitle(((MWindow) element).getLocalizedLabel());
BorderPane root = new BorderPane() {
@Override
protected void layoutChildren() {
super.layoutChildren();
if( windowResizeButton != null ) {
windowResizeButton.autosize();
windowResizeButton.setLayoutX(getWidth() - windowResizeButton.getLayoutBounds().getWidth());
windowResizeButton.setLayoutY(getHeight() - windowResizeButton.getLayoutBounds().getHeight());
}
}
};
root.getStyleClass().add("MWindow");
VBox topAreaBox = new VBox();
root.setTop(topAreaBox);
//root.setStyle("-fx-background-color: #999;");
Scene scene = new Scene(root,-1,-1, Platform.isSupported(ConditionalFeature.SCENE3D));
if( Platform.isSupported(ConditionalFeature.SCENE3D) ) {
scene.setCamera(new PerspectiveCamera());
}
scene.focusOwnerProperty().addListener(new ChangeListener<Node>() {
private Object lastFocusElement;
@Override
public void changed(ObservableValue<? extends Node> observable, Node oldValue, Node newValue) {
if( newValue != null ) {
Object element = null;
do {
if( newValue.getUserData() instanceof MUIElement ) {
MUIElement e = (MUIElement) newValue.getUserData();
if( e instanceof MPartStack ) {
element = e;
} else if( (MUIElement)e.getParent() instanceof MPartStack ) {
element = e.getParent();
} else {
element = e;
}
break;
}
} while( (newValue = newValue.getParent()) != null );
if( element != lastFocusElement ) {
lastFocusElement = element;
broker.send(FX_FOCUS_TOPIC, element);
}
}
}
});
scene.getStylesheets().add(getClass().getClassLoader().getResource("/css/default.css").toExternalForm());
if (themeManager != null) {
Theme theme = themeManager.getCurrentTheme();
if (theme != null) {
List<String> sUrls = new ArrayList<String>();
for (URL url : theme.getStylesheetURL()) {
sUrls.add(url.toExternalForm());
}
scene.getStylesheets().addAll(sUrls);
}
sceneRegistration = themeManager.registerScene(scene);
}
stage.setScene(scene);
ChangeListener<Number> resizeListener = new PosAndSizeListener(stage, e);
stage.widthProperty().addListener(resizeListener);
stage.heightProperty().addListener(resizeListener);
stage.xProperty().addListener(resizeListener);
stage.yProperty().addListener(resizeListener);
context.set(Stage.class, stage);
context.set(Scene.class, scene);
return stage;
}
return null;
}
@Override
public void postProcess(MUIElement childElement) {
super.postProcess(childElement);
Stage stage = (Stage) childElement.getWidget();
stage.toFront();
stage.show();
}
@Override
public Object getUIContainer(MUIElement element) {
// Stage stage = (Stage) element.getParent().getWidget();
// return stage.getScene().getRoot();
return null;
}
@Override
public void processContents(MElementContainer<MUIElement> container) {
if ((MUIElement) container instanceof MWindow) {
Stage stage = (Stage) container.getWidget();
BorderPane rootPane = (BorderPane) stage.getScene().getRoot();
VBox topAreaBox = (VBox) rootPane.getTop();
IPresentationEngine renderer = (IPresentationEngine) context.get(IPresentationEngine.class.getName());
MWindow window = (MWindow) (MUIElement) container;
Node topDecoration = createTopDecoration(stage, window);
if (topDecoration != null) {
topAreaBox.getChildren().add(topDecoration);
windowResizeButton = new WindowResizeButton(stage, 30, 30);
}
if (window.getMainMenu() != null) {
Node n = (Node) renderer.createGui(window.getMainMenu());
if (n != null) {
topAreaBox.getChildren().add(n);
}
}
if (window instanceof MTrimmedWindow) {
MTrimmedWindow tWindow = (MTrimmedWindow) window;
for (MTrimBar trim : tWindow.getTrimBars()) {
Node n = (Node) renderer.createGui(trim);
if (n != null) {
switch (trim.getSide()) {
case BOTTOM:
rootPane.setBottom(n);
break;
case LEFT:
rootPane.setLeft(n);
break;
case RIGHT:
rootPane.setRight(n);
break;
case TOP:
topAreaBox.getChildren().add(n);
break;
}
}
}
}
FillLayoutPane filllayout = new FillLayoutPane();
rootPane.setCenter(filllayout);
// Process any contents of the newly created ME
List<MUIElement> parts = container.getChildren();
if (parts != null) {
// loading a legacy app will add children to the window while it
// is
// being rendered.
// this is *not* the correct place for this
// hope that the ADD event will pick up the new part.
MUIElement[] plist = parts.toArray(new MUIElement[parts.size()]);
for (int i = 0; i < plist.length; i++) {
MUIElement childME = plist[i];
Object element = renderer.createGui(childME);
if (element instanceof Node) {
filllayout.getChildren().add((Node) element);
}
}
}
if( windowResizeButton != null ) {
rootPane.getChildren().add(windowResizeButton);
}
}
}
protected Node createTopDecoration(final Stage stage, MWindow window) {
String fxml = null;
URI uri = null;
for (String t : window.getTags()) {
if (t.startsWith("decoration#")) {
uri = URI.createURI(window.getContributorURI());
fxml = t.substring("decoration#".length());
}
}
if (fxml != null && uri != null) {
stage.initStyle(StageStyle.UNDECORATED);
Bundle b = org.eclipse.core.runtime.Platform.getBundle(uri.segment(1));
if (b != null) {
try {
return (Node) InjectingFXMLLoader.create(context, b, fxml).load();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
public static class PosAndSizeListener implements ChangeListener<Number> {
private final Stage stage;
private final MWindow mWindow;
public PosAndSizeListener(Stage stage, MWindow mWindow) {
super();
this.stage = stage;
this.mWindow = mWindow;
}
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
mWindow.setX(((Double) stage.getX()).intValue());
mWindow.setY(((Double) stage.getY()).intValue());
mWindow.setWidth(((Double) stage.getWidth()).intValue());
mWindow.setHeight(((Double) stage.getHeight()).intValue());
}
}
}