Java tutorial
/******************************************************************************* * Copyright (c) 2012 Rushan R. Gilmullin and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Rushan R. Gilmullin - initial API and implementation *******************************************************************************/ package org.semanticsoft.vaaclipse.presentation.renderers; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; 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.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.MStackElement; import org.eclipse.e4.ui.model.application.ui.basic.MWindow; import org.eclipse.e4.ui.services.internal.events.EventBroker; import org.eclipse.e4.ui.workbench.IPresentationEngine; import org.eclipse.e4.ui.workbench.UIEvents; import org.eclipse.e4.ui.workbench.UIEvents.EventTags; import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.e4.ui.workbench.modeling.EPartService; import org.eclipse.emf.ecore.EObject; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.semanticsoft.vaaclipse.api.VaadinExecutorService; import org.semanticsoft.vaaclipse.presentation.dnd.VaadinDropHandler; import org.semanticsoft.vaaclipse.publicapi.resources.ResourceHelper; import org.semanticsoft.vaaclipse.widgets.StackWidget; import org.semanticsoft.vaaclipse.widgets.StackWidget.StateListener; import com.vaadin.server.Resource; import com.vaadin.ui.Component; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.CloseHandler; import com.vaadin.ui.TabSheet.SelectedTabChangeEvent; import com.vaadin.ui.TabSheet.SelectedTabChangeListener; import com.vaadin.ui.TabSheet.Tab; import fi.jasoft.dragdroplayouts.client.ui.LayoutDragMode; @SuppressWarnings("restriction") public class StackRenderer extends VaadinRenderer { @Inject private EventBroker eventBroker; @Inject private EModelService modelService; @Inject private EPartService partService; private Map<Component, MStackElement> vaatab2Element = new HashMap<Component, MStackElement>(); private boolean ignoreTabSelChanges = false; @Inject VaadinExecutorService communicationManager; private EventHandler tagListener = new EventHandler() { @Override public void handleEvent(Event event) { Object changedObj = event.getProperty(EventTags.ELEMENT); String eventType = (String) event.getProperty(UIEvents.EventTags.TYPE); String tag = (String) event.getProperty(UIEvents.EventTags.NEW_VALUE); int location = modelService.getElementLocation((MUIElement) changedObj); if (!(changedObj instanceof MPartStack) || location == EModelService.IN_SHARED_AREA) { return; } final MPartStack stack = (MPartStack) changedObj; StackWidget stackWidget = (StackWidget) stack.getWidget(); if (UIEvents.EventTypes.ADD.equals(eventType)) { if (IPresentationEngine.MINIMIZED.equals(tag)) { stackWidget.setState(-1); } else if (IPresentationEngine.MAXIMIZED.equals(tag)) { stackWidget.setState(1); } } else if (UIEvents.EventTypes.REMOVE.equals(eventType)) { stackWidget.setState(0); } } }; private EventHandler selectElementHandler = new EventHandler() { public void handleEvent(Event event) { Object element = event.getProperty(UIEvents.EventTags.ELEMENT); if (!(element instanceof MPartStack)) return; MPartStack stack = (MPartStack) element; if (stack.getRenderer() != StackRenderer.this) return; if (stack.getSelectedElement() != null) { if (stack.getSelectedElement().getWidget() == null) { IPresentationEngine engine = (IPresentationEngine) context .get(IPresentationEngine.class.getName()); engine.createGui(stack.getSelectedElement()); int i = 0; for (MStackElement e : stack.getChildren()) { if (e == stack.getSelectedElement()) break; if (e.getWidget() != null) i++; } addTab((TabSheet) stack.getWidget(), stack.getSelectedElement(), i); } ignoreTabSelChanges = true; ((TabSheet) stack.getWidget()).setSelectedTab((Component) stack.getSelectedElement().getWidget()); ignoreTabSelChanges = false; } } }; EventHandler itemUpdater = new EventHandler() { public void handleEvent(Event event) { MUIElement element = (MUIElement) event.getProperty(UIEvents.EventTags.ELEMENT); if (!(element instanceof MPart)) return; MPart part = (MPart) element; String attName = (String) event.getProperty(UIEvents.EventTags.ATTNAME); Object newValue = event.getProperty(UIEvents.EventTags.NEW_VALUE); MPartStack stack = null; // is this a direct child of the stack? MPlaceholder placeholder = null; if (element.getParent() != null && element.getParent().getRenderer() == StackRenderer.this) { stack = (MPartStack) (MElementContainer<?>) element.getParent(); } else { // Do we have any stacks with place holders for the element // that's changed? MWindow win = modelService.getTopLevelWindowFor(part); List<MPlaceholder> refs = modelService.findElements(win, null, MPlaceholder.class, null); if (refs != null) { for (MPlaceholder ref : refs) { if (ref.getRef() != part) continue; MElementContainer<?> refParent = ref.getParent(); // can be null, see bug 328296 if (refParent != null && refParent.getRenderer() instanceof StackRenderer) { placeholder = ref; stack = (MPartStack) refParent; } } } } if (stack != null) { Tab tab = ((StackWidget) stack.getWidget()) .getTab((Component) (placeholder == null ? part.getWidget() : placeholder.getWidget())); updateTab(tab, part, attName, newValue); } } }; private void updateTab(Tab tab, MPart part, String attName, Object newValue) { if (UIEvents.UILabel.LABEL.equals(attName)) { String newName = (String) newValue; tab.setCaption(getLabel(part, newName)); } else if (UIEvents.UILabel.ICONURI.equals(attName)) { Resource icon = part.getIconURI() != null ? ResourceHelper.createResource(part.getIconURI()) : null; tab.setIcon(icon); } else if (UIEvents.UILabel.TOOLTIP.equals(attName)) { String newTTip = (String) newValue; tab.setDescription(newTTip); } else if (UIEvents.Dirtyable.DIRTY.equals(attName)) { Boolean dirtyState = (Boolean) newValue; String text = tab.getCaption(); boolean hasAsterisk = text.length() > 0 && text.charAt(0) == '*'; if (dirtyState.booleanValue()) { if (!hasAsterisk) { tab.setCaption('*' + text); } } else if (hasAsterisk) { tab.setCaption(text.substring(1)); } } } 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; } @PostConstruct public void postConstruct() { eventBroker.subscribe(UIEvents.ApplicationElement.TOPIC_TAGS, tagListener); eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, selectElementHandler); eventBroker.subscribe(UIEvents.UILabel.TOPIC_ALL, itemUpdater); eventBroker.subscribe(UIEvents.Dirtyable.TOPIC_DIRTY, itemUpdater); } @PreDestroy public void preDestroy() { eventBroker.unsubscribe(tagListener); eventBroker.unsubscribe(selectElementHandler); eventBroker.unsubscribe(itemUpdater); } @Override public void createWidget(MUIElement element, MElementContainer<MUIElement> parent) { if (!(element instanceof MPartStack)) return; MPartStack stack = (MPartStack) element; StackWidget stackWidget = new StackWidget(); stackWidget.setDragMode(LayoutDragMode.CLONE); stackWidget.setSizeFull(); element.setWidget(stackWidget); IEclipseContext context = modelService.getContainingContext(stack).createChild(); context.set(MPartStack.class, stack); VaadinDropHandler dropHandler = ContextInjectionFactory.make(VaadinDropHandler.class, context); stackWidget.setDropHandler(dropHandler); } @Override public void processContents(final MElementContainer<MUIElement> container) { MPartStack stack = (MPartStack) (MElementContainer<?>) container; StackWidget stackWidget = (StackWidget) stack.getWidget(); for (MStackElement element : stack.getChildren()) { if (element.isToBeRendered()) addTab(stackWidget, (MStackElement) element, stackWidget.getComponentCount()); } // if there are childs in stack and the selected element is not // specified for stack, set the first child as selected if (stack.getChildren().size() > 0 && stack.getSelectedElement() == null) { stack.setSelectedElement(stack.getChildren().get(0)); } if (stack.getSelectedElement() != null) { Component stackSelectedComponent = (Component) stack.getSelectedElement().getWidget(); stackWidget.setSelectedTab(stackSelectedComponent); } } private void addTab(TabSheet parentPane, MStackElement element, int pos) { MUILabel mLabel; if (element instanceof MPlaceholder) mLabel = (MUILabel) ((MPlaceholder) element).getRef(); else mLabel = (MUILabel) element; boolean closable = false; if (mLabel instanceof MPart) closable = ((MPart) mLabel).isCloseable(); Resource icon = mLabel.getIconURI() != null ? ResourceHelper.createResource(mLabel.getIconURI()) : null; //Tab tab = parentPane.addTab((com.vaadin.ui.Component) element.getWidget(), mLabel.getLocalizedLabel(), icon, pos); Tab tab = parentPane.addTab((com.vaadin.ui.Component) element.getWidget(), pos); tab.setCaption(mLabel.getLocalizedLabel()); tab.setIcon(icon); tab.setClosable(closable); tab.setDescription(mLabel.getLocalizedTooltip()); vaatab2Element.put((Component) element.getWidget(), element); } @Override public void hookControllerLogic(final MUIElement element) { final StackWidget sw = (StackWidget) element.getWidget(); int location = modelService.getElementLocation(element); if (location != EModelService.IN_SHARED_AREA) //if the stack not in shared area { sw.addStateListener(new StateListener() { @Override public void stateChanged(int newState, int oldState) { if (oldState == 0 && newState == 1) setState(element, IPresentationEngine.MAXIMIZED); else if (oldState == 1 && newState == 0) setState(element, null); else if (oldState == 1 && newState == -1) { element.getTags().remove(IPresentationEngine.MINIMIZED); element.getTags().remove(IPresentationEngine.MAXIMIZED); element.getTags().add(IPresentationEngine.MINIMIZED); } else if (oldState == -1 && newState == 0) { element.getTags().remove(IPresentationEngine.MINIMIZED_BY_ZOOM); element.getTags().remove(IPresentationEngine.MINIMIZED); } else if (oldState == 0 && newState == -1) setState(element, IPresentationEngine.MINIMIZED); } private void setState(MUIElement element, String state) { element.getTags().remove(IPresentationEngine.MINIMIZED_BY_ZOOM); if (IPresentationEngine.MINIMIZED.equals(state)) { element.getTags().remove(IPresentationEngine.MAXIMIZED); element.getTags().add(IPresentationEngine.MINIMIZED); } else if (IPresentationEngine.MAXIMIZED.equals(state)) { element.getTags().remove(IPresentationEngine.MINIMIZED); element.getTags().add(IPresentationEngine.MAXIMIZED); } else { element.getTags().remove(IPresentationEngine.MINIMIZED); element.getTags().remove(IPresentationEngine.MAXIMIZED); } } }); } sw.addListener(new SelectedTabChangeListener() { public void selectedTabChange(SelectedTabChangeEvent event) { MStackElement stackElement = vaatab2Element.get(sw.getSelectedTab()); if (stackElement != null) { if (ignoreTabSelChanges) return; MPartStack stack = (MPartStack) (MElementContainer<?>) stackElement.getParent(); if (stack != null && stack.getSelectedElement() != stackElement) { stack.setSelectedElement(stackElement); activateStack(stack); } } } }); sw.setCloseHandler(new CloseHandler() { public void onTabClose(TabSheet tabsheet, Component tabContent) { MStackElement stackElement = vaatab2Element.get(tabContent); closePart(stackElement); } }); } private void activateStack(MPartStack stack) { communicationManager.invokeLater(new ActivationRunnable(stack)); } private class ActivationRunnable implements Runnable { private MPartStack stack; public ActivationRunnable(MPartStack stack) { this.stack = stack; } @Override public void run() { MStackElement stackElement = stack.getSelectedElement(); // 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(stack); if ((location & EModelService.IN_ACTIVE_PERSPECTIVE) == 0 && (location & EModelService.OUTSIDE_PERSPECTIVE) == 0 && (location & EModelService.IN_SHARED_AREA) == 0) return; if (!isValid(stackElement)) return; if (stackElement instanceof MPlaceholder) stackElement = (MStackElement) ((MPlaceholder) stackElement).getRef(); IEclipseContext curContext = getContext(stackElement); if (curContext != null) { EPartService ps = (EPartService) curContext.get(EPartService.class.getName()); if (ps != null) ps.activate((MPart) stackElement, true); } } } 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); } 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 boolean closePart(MStackElement stackElement) { MPart part = (MPart) ((stackElement instanceof MPart) ? stackElement : ((MPlaceholder) stackElement).getRef()); if (!isClosable(part)) { return false; } IEclipseContext partContext = part.getContext(); IEclipseContext parentContext = getContextForParent(part); // a part may not have a context if it hasn't been rendered IEclipseContext context = partContext == null ? parentContext : partContext; // Allow closes to be 'canceled' EPartService partService = (EPartService) context.get(EPartService.class.getName()); if (partService.savePart(part, true)) { partService.hidePart(part); return true; } // the user has canceled out of the save operation, so don't close the // part return false; } @Override public void setVisible(MUIElement changedElement, boolean visible) { TabSheet tabPane = (TabSheet) changedElement.getWidget(); tabPane.setVisible(visible); } @Override public void addChildGui(MUIElement child, MElementContainer<MUIElement> element) { if (!(child instanceof MStackElement)) return; StackWidget sw = (StackWidget) element.getWidget(); int index = indexOf(child, element); addTab(sw, (MStackElement) child, index); } }