package at.bestsolution.efxclipse.runtime.workbench.renderers; import java.util.ArrayList; import java.util.List; import javax.annotation.PostConstruct; import javax.inject.Inject; import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.Event; import javafx.event.EventHandler; import javafx.scene.Node; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.image.ImageView; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.ui.model.application.MApplication; import org.eclipse.e4.ui.model.application.ui.MDirtyable; import org.eclipse.e4.ui.model.application.ui.MElementContainer; import org.eclipse.e4.ui.model.application.ui.MGenericStack; import org.eclipse.e4.ui.model.application.ui.MUIElement; import org.eclipse.e4.ui.model.application.ui.MUILabel; import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder; import org.eclipse.e4.ui.model.application.ui.basic.MPart; import org.eclipse.e4.ui.model.application.ui.basic.MPartStack; import org.eclipse.e4.ui.model.application.ui.basic.MWindow; import org.eclipse.e4.ui.model.application.ui.menu.MToolBar; import org.eclipse.e4.ui.workbench.IPresentationEngine; import org.eclipse.e4.ui.workbench.UIEvents; import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.emf.ecore.EObject; import at.bestsolution.efxclipse.runtime.workbench.renderers.internal.ExtendedTab; @SuppressWarnings("restriction") public class StackRenderer extends JFXRenderer { private org.osgi.service.event.EventHandler selectedItemHandler = new org.osgi.service.event.EventHandler() { @Override public void handleEvent(org.osgi.service.event.Event event) { Object element = event.getProperty(UIEvents.EventTags.ELEMENT); if (!(element instanceof MGenericStack<?>)) return; MGenericStack<MUIElement> stack = (MGenericStack<MUIElement>) element; if( stack.getRenderer() != StackRenderer.this ) { return; } StackRenderer lsr = (StackRenderer) stack.getRenderer(); // Gather up the elements that are being 'hidden' by this change MUIElement oldSel = (MUIElement) event .getProperty(UIEvents.EventTags.OLD_VALUE); if (oldSel != null) { List<MUIElement> goingHidden = new ArrayList<MUIElement>(); hideElementRecursive(oldSel, goingHidden); } if (stack.getSelectedElement() != null) lsr.showTab(stack.getSelectedElement()); } }; private org.osgi.service.event.EventHandler focusPartHandler = new org.osgi.service.event.EventHandler() { @Override public void handleEvent(org.osgi.service.event.Event event) { Object element = event.getProperty(IEventBroker.DATA); if( ! ( element instanceof MGenericStack<?>) ) { return; } MGenericStack<MUIElement> stack = (MGenericStack<MUIElement>) element; if( stack.getRenderer() != StackRenderer.this ) { return; } System.err.println("Stack is activated"); activateStack(stack); } }; @Inject IEventBroker eventBroker; @Inject IPresentationEngine renderer; private boolean ignoreTabSelChanges = false; @Inject private MApplication application; private ActivationJob activationJob = null; private class ActivationJob implements Runnable { /** * Returns whether it is acceptable for a stack to be activated. As the * activation occurs asynchronously, the original activation request may * have been invalidated since the request was originally enqueued. * <p> * For example, an activation request that was enqueued no longer should * be honoured if a dialog window gets opened in the interim. * </p> * * @return <code>true</code> if the requested stack should be activated, * <code>false</code> otherwise */ private boolean shouldActivate() { if (application != null) { IEclipseContext applicationContext = application.getContext(); IEclipseContext activeChild = applicationContext .getActiveChild(); System.err.println(activeChild); if (activeChild == null || activeChild.get(MWindow.class) != application .getSelectedElement() || application.getSelectedElement() != modelService .getTopLevelWindowFor(stackToActivate)) { return false; } } return true; } public MElementContainer<MUIElement> stackToActivate = null; public void run() { // System.err.println("Running job"); activationJob = null; if (stackToActivate != null && stackToActivate.getSelectedElement() != null // && shouldActivate() ) { // System.err.println("Activation in process"); // // Ensure we're activating a stack in the current perspective, // // when using a dialog to open a perspective // // we end up in the situation where this stack is in the // // previously active perspective // int location = modelService.getElementLocation(stackToActivate); // if ((location & EModelService.IN_ACTIVE_PERSPECTIVE) == 0 // && (location & EModelService.OUTSIDE_PERSPECTIVE) == 0 // && (location & EModelService.IN_SHARED_AREA) == 0) // return; MUIElement selElement = stackToActivate.getSelectedElement(); // System.err.println("checking validness"); // if (!isValid(selElement)) // return; // // if (selElement instanceof MPlaceholder) // selElement = ((MPlaceholder) selElement).getRef(); System.err.println("calling activation: " + selElement); activate((MPart) selElement); } } } private boolean isValid(MUIElement element) { if (element == null || !element.isToBeRendered()) { return false; } if (element instanceof MApplication) { return true; } MUIElement parent = element.getParent(); if (parent == null && element instanceof MWindow) { // might be a detached window parent = (MUIElement) ((EObject) element).eContainer(); } if (parent == null) { // might be a shared part, try to find the placeholder MWindow window = modelService.getTopLevelWindowFor(element); return window == null ? false : isValid(modelService .findPlaceholderFor(window, element)); } return isValid(parent); } @PostConstruct void init() { eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, selectedItemHandler); eventBroker.subscribe(FX_FOCUS_TOPIC, focusPartHandler); } @Override public Object createWidget(MUIElement element, Object parent) { TabPane tabPane = new TabPane(); tabPane.getStyleClass().add("MPartStack"); return tabPane; } @Override public void processContents(MElementContainer<MUIElement> container) { for (MUIElement e : container.getChildren()) { createTab(container, e); } } @Override protected Object getParentWidget(MUIElement element) { return (Node) element.getParent().getWidget(); } @Override public void postProcess(MUIElement childElement) { if (!(childElement instanceof MGenericStack<?>)) return; MGenericStack<MUIElement> stack = (MGenericStack<MUIElement>) childElement; MUIElement selPart = stack.getSelectedElement(); if (selPart != null) { showTab(selPart); } else if (stack.getChildren().size() > 0) { // Set the selection to the first renderable element for (MUIElement kid : stack.getChildren()) { if (kid.isToBeRendered() && kid.isVisible()) { stack.setSelectedElement(kid); break; } } } } @Override public void disposeWidget(MUIElement part) { // TODO Auto-generated method stub } @Override public void hookControllerLogic(MUIElement me) { super.hookControllerLogic(me); // if (!(me instanceof MElementContainer<?>)) // return; // // final MElementContainer<MUIElement> stack = (MElementContainer<MUIElement>) me; // TabPane control = (TabPane) stack.getWidget(); // control.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() { // // @Override // public void changed(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue) { // System.err.println("Hello world"); // // prevent recursions // if (ignoreTabSelChanges || newValue == null) // return; // // MUIElement ele = (MUIElement) ((ExtendedTab)newValue).getData(); // ele.getParent().setSelectedElement(ele); // activateStack(stack); // } // }); } @Override public void childRendered(final MElementContainer<MUIElement> parentElement, final MUIElement element) { // Platform.runLater(new Runnable() { // // @Override // public void run() { createTab(parentElement, element); // } // }); } private void createTab(final MElementContainer<MUIElement> stack, MUIElement element) { final MPart part; if (element instanceof MPart) part = (MPart) element; else if (element instanceof MPlaceholder) { part = (MPart) ((MPlaceholder) element).getRef(); part.setCurSharedRef((MPlaceholder) element); } else { part = null; } TabPane parentPane = (TabPane) stack.getWidget(); Tab cti = findItemForPart(element, stack); if (cti != null) { if (element.getWidget() != null) cti.setContent((Node) element.getWidget()); return; } final ExtendedTab tab = new ExtendedTab(getLabel(part, part.getLocalizedLabel())); if( part.getIconURI() != null ) { tab.setGraphic(new ImageView(part.getIconURI())); } tab.setData(element); tab.setClosable(isClosable(part)); tab.setOnSelectionChanged(new EventHandler<Event>() { @Override public void handle(Event event) { if( tab.isSelected() && tab.getContent() == null && ((MUIElement)tab.getData()).getParent() != null ) { IPresentationEngine renderer = (IPresentationEngine) context.get(IPresentationEngine.class .getName()); Node node = (Node) renderer.createGui(part); tab.setContent(node); } if( tab.isSelected() ) { MUIElement ele = (MUIElement) tab.getData(); if( ele.isToBeRendered() ) { ele.getParent().setSelectedElement(ele); activateStack(stack); } } } }); parentPane.getTabs().add(tab); } synchronized private void activateStack(MElementContainer<MUIElement> stack) { TabPane w = (TabPane) stack.getWidget(); if( w == null || w.getParent() == null ) { return; } if (activationJob == null) { activationJob = new ActivationJob(); activationJob.stackToActivate = stack; // Platform.runLater(activationJob); activationJob.run(); } else { activationJob.stackToActivate = stack; } } @Override public void hideChild(final MElementContainer<MUIElement> parentElement, final MUIElement child) { super.hideChild(parentElement, child); System.err.println("Hiding"); // Platform.runLater(new Runnable() { // // @Override // public void run() { doHideChild(parentElement, child); // } // }); } private void doHideChild(MElementContainer<MUIElement> parentElement, MUIElement child) { TabPane ctf = (TabPane) parentElement.getWidget(); if (ctf == null) return; // find the 'stale' tab for this element and dispose it Tab cti = findItemForPart(child, parentElement); if (cti != null ) { System.err.println("Removing children"); cti.setContent(null); ctf.getTabs().remove(cti); } // Check if we have to reset the currently active child for the stack if (parentElement.getSelectedElement() == child) { clearTR(ctf); } else { if (child instanceof MPlaceholder) { MPlaceholder placeholder = (MPlaceholder) child; child = placeholder.getRef(); if (child.getCurSharedRef() != placeholder) { // if this placeholder isn't currently managing this // element, no need to do anything about its toolbar, just // return here return; } } if (child instanceof MPart) { MToolBar toolbar = ((MPart) child).getToolbar(); if (toolbar != null) { toolbar.setVisible(false); } } } } public void clearTR(TabPane ctf) { // ToolBar vmTB = getViewMenuTB(ctf); // if (vmTB != null && !vmTB.isDisposed()) // vmTB.dispose(); // // MToolBar viewTBModel = getViewTB(ctf); // if (viewTBModel != null && viewTBModel.getWidget() != null) // viewTBModel.setVisible(false); // // ctf.setTopRight(null); // getTRComposite(ctf).setVisible(false); } private String getLabel(MUILabel itemPart, String newName) { if (newName == null) { newName = ""; //$NON-NLS-1$ } if (itemPart instanceof MDirtyable && ((MDirtyable) itemPart).isDirty()) { newName = '*' + newName; } return newName; } private boolean isClosable(MPart part) { // if it's a shared part check its current ref if (part.getCurSharedRef() != null) { return !(part.getCurSharedRef().getTags() .contains(IPresentationEngine.NO_CLOSE)); } return part.isCloseable(); } private Tab findItemForPart(MUIElement element, MElementContainer<MUIElement> stack) { if (stack == null) stack = element.getParent(); TabPane ctf = (TabPane) stack.getWidget(); if (ctf == null) return null; ExtendedTab[] items = ctf.getTabs().toArray(new ExtendedTab[0]); for (int i = 0; i < items.length; i++) { if (items[i].getData() == element) return items[i]; } return null; } @Override protected Object getImage(MUILabel element) { // TODO Auto-generated method stub return null; } private void hideElementRecursive(MUIElement element, List<MUIElement> goingHidden) { //TODO Port from SWT } protected void showTab(MUIElement element) { //TODO Port from SWT // Now process any newly visible elements // List<MUIElement> becomingVisible = new ArrayList<MUIElement>(); // MUIElement curSel = element.getParent().getSelectedElement(); // if (curSel != null) { // showElementRecursive(curSel, becomingVisible); // } // an invisible element won't have the correct widget hierarchy if (!element.isVisible()) { return; } final TabPane ctf = (TabPane) getParentWidget(element); Tab cti = findItemForPart(element, null); if (cti == null) { createTab(element.getParent(), element); cti = findItemForPart(element, element.getParent()); } Node ctrl = (Node) element.getWidget(); if (ctrl != null && ctrl.getParent() != ctf) { // ctrl.setParent(ctf); cti.setContent(ctrl); } else if (element.getWidget() == null) { Node tabCtrl = (Node) renderer.createGui(element); cti.setContent(tabCtrl); } ignoreTabSelChanges = true; ctf.getSelectionModel().select(cti); ignoreTabSelChanges = false; // Clear out the current Top Right info MPart part = (MPart) ((element instanceof MPart) ? element : ((MPlaceholder) element).getRef()); // adjustTR(ctf, part); } }