| /******************************************************************************* |
| * Copyright (c) 2008, 2015 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| * Lars Vogel <Lars.Vogel@gmail.com> - Bug 429728 |
| * Simon Scholz <scholzsimon@arcor.de - Bug 429729 |
| *******************************************************************************/ |
| package org.eclipse.e4.ui.workbench.renderers.swt; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import javax.annotation.PostConstruct; |
| import javax.annotation.PreDestroy; |
| import javax.inject.Inject; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.core.services.events.IEventBroker; |
| import org.eclipse.e4.core.services.log.Logger; |
| import org.eclipse.e4.ui.css.core.engine.CSSEngine; |
| import org.eclipse.e4.ui.css.core.resources.IResourcesRegistry; |
| import org.eclipse.e4.ui.css.swt.dom.WidgetElement; |
| import org.eclipse.e4.ui.css.swt.resources.ResourceByDefinitionKey; |
| import org.eclipse.e4.ui.css.swt.resources.SWTResourcesRegistry; |
| import org.eclipse.e4.ui.internal.workbench.E4Workbench; |
| import org.eclipse.e4.ui.internal.workbench.PartServiceSaveHandler; |
| import org.eclipse.e4.ui.internal.workbench.renderers.swt.SWTRenderersMessages; |
| import org.eclipse.e4.ui.internal.workbench.swt.CSSConstants; |
| import org.eclipse.e4.ui.model.application.MApplication; |
| import org.eclipse.e4.ui.model.application.ui.MContext; |
| 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.advanced.MPerspective; |
| 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.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.services.IServiceConstants; |
| import org.eclipse.e4.ui.services.IStylingEngine; |
| 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.e4.ui.workbench.modeling.EPartService; |
| import org.eclipse.e4.ui.workbench.modeling.ISaveHandler; |
| import org.eclipse.e4.ui.workbench.modeling.IWindowCloseHandler; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.viewers.ArrayContentProvider; |
| import org.eclipse.jface.viewers.CheckboxTableViewer; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.window.IShellProvider; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.ControlEvent; |
| import org.eclipse.swt.events.ControlListener; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.ShellAdapter; |
| import org.eclipse.swt.events.ShellEvent; |
| import org.eclipse.swt.events.TraverseEvent; |
| import org.eclipse.swt.events.TraverseListener; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.graphics.Resource; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Widget; |
| import org.osgi.service.event.Event; |
| import org.osgi.service.event.EventHandler; |
| |
| /** |
| * Render a Window or Workbench Window. |
| */ |
| public class WBWRenderer extends SWTPartRenderer { |
| |
| private static String ShellMinimizedTag = "shellMinimized"; //$NON-NLS-1$ |
| private static String ShellMaximizedTag = "shellMaximized"; //$NON-NLS-1$ |
| |
| private class WindowSizeUpdateJob implements Runnable { |
| public List<MWindow> windowsToUpdate = new ArrayList<MWindow>(); |
| |
| @Override |
| public void run() { |
| clearSizeUpdate(); |
| while (!windowsToUpdate.isEmpty()) { |
| MWindow window = windowsToUpdate.remove(0); |
| Shell shell = (Shell) window.getWidget(); |
| if (shell == null || shell.isDisposed()) |
| continue; |
| |
| shell.setBounds(window.getX(), window.getY(), |
| window.getWidth(), window.getHeight()); |
| } |
| } |
| } |
| |
| WindowSizeUpdateJob boundsJob; |
| |
| void clearSizeUpdate() { |
| boundsJob = null; |
| } |
| |
| boolean ignoreSizeChanges = false; |
| |
| @Inject |
| Logger logger; |
| |
| @Inject |
| private IEventBroker eventBroker; |
| |
| @Inject |
| private IPresentationEngine engine; |
| |
| private EventHandler topWindowHandler; |
| private EventHandler shellUpdater; |
| private EventHandler visibilityHandler; |
| private EventHandler sizeHandler; |
| private ThemeDefinitionChangedHandler themeDefinitionChanged; |
| |
| @Inject |
| private EModelService modelService; |
| |
| public WBWRenderer() { |
| super(); |
| } |
| |
| /** |
| * Closes the provided detached window. |
| * |
| * @param window |
| * the detached window to close |
| * @return <code>true</code> if the window should be closed, |
| * <code>false</code> otherwise |
| */ |
| private boolean closeDetachedWindow(MWindow window) { |
| EPartService partService = (EPartService) window.getContext().get( |
| EPartService.class.getName()); |
| List<MPart> parts = modelService.findElements(window, null, |
| MPart.class, null); |
| // this saves one part at a time, not ideal but better than not saving |
| // at all |
| for (MPart part : parts) { |
| if (!partService.savePart(part, true)) { |
| // user cancelled the operation, return false |
| return false; |
| } |
| } |
| |
| // hide every part individually, following 3.x behaviour |
| for (MPart part : parts) { |
| partService.hidePart(part); |
| } |
| return true; |
| } |
| |
| @PostConstruct |
| public void init() { |
| |
| topWindowHandler = new EventHandler() { |
| |
| @Override |
| public void handleEvent(Event event) { |
| // Ensure that this event is for a MApplication |
| if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MApplication)) |
| return; |
| MWindow win = (MWindow) event |
| .getProperty(UIEvents.EventTags.NEW_VALUE); |
| if ((win == null) || !win.getTags().contains("topLevel")) //$NON-NLS-1$ |
| return; |
| win.setToBeRendered(true); |
| if (!(win.getRenderer() == WBWRenderer.this)) |
| return; |
| Shell shell = (Shell) win.getWidget(); |
| if (shell.getMinimized()) { |
| shell.setMinimized(false); |
| } |
| shell.setActive(); |
| shell.moveAbove(null); |
| |
| } |
| }; |
| |
| eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, |
| topWindowHandler); |
| |
| shellUpdater = new EventHandler() { |
| @Override |
| public void handleEvent(Event event) { |
| // Ensure that this event is for a MMenuItem |
| Object objElement = event |
| .getProperty(UIEvents.EventTags.ELEMENT); |
| if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MWindow)) |
| return; |
| |
| // Is this listener interested ? |
| MWindow windowModel = (MWindow) objElement; |
| if (windowModel.getRenderer() != WBWRenderer.this) |
| return; |
| |
| // No widget == nothing to update |
| Shell theShell = (Shell) windowModel.getWidget(); |
| if (theShell == null) |
| return; |
| |
| String attName = (String) event |
| .getProperty(UIEvents.EventTags.ATTNAME); |
| |
| if (UIEvents.UILabel.LABEL.equals(attName) |
| || UIEvents.UILabel.LOCALIZED_LABEL.equals(attName)) { |
| String newTitle = (String) event |
| .getProperty(UIEvents.EventTags.NEW_VALUE); |
| theShell.setText(newTitle); |
| } else if (UIEvents.UILabel.ICONURI.equals(attName)) { |
| theShell.setImage(getImage(windowModel)); |
| } else if (UIEvents.UILabel.TOOLTIP.equals(attName) |
| || UIEvents.UILabel.LOCALIZED_TOOLTIP.equals(attName)) { |
| String newTTip = (String) event |
| .getProperty(UIEvents.EventTags.NEW_VALUE); |
| theShell.setToolTipText(newTTip); |
| } |
| } |
| }; |
| |
| eventBroker.subscribe(UIEvents.UILabel.TOPIC_ALL, shellUpdater); |
| |
| visibilityHandler = new EventHandler() { |
| @Override |
| public void handleEvent(Event event) { |
| // Ensure that this event is for a MMenuItem |
| Object objElement = event |
| .getProperty(UIEvents.EventTags.ELEMENT); |
| if (!(objElement instanceof MWindow)) |
| return; |
| |
| // Is this listener interested ? |
| MWindow windowModel = (MWindow) objElement; |
| if (windowModel.getRenderer() != WBWRenderer.this) |
| return; |
| |
| // No widget == nothing to update |
| Shell theShell = (Shell) windowModel.getWidget(); |
| if (theShell == null) |
| return; |
| |
| String attName = (String) event |
| .getProperty(UIEvents.EventTags.ATTNAME); |
| |
| if (UIEvents.UIElement.VISIBLE.equals(attName)) { |
| boolean isVisible = (Boolean) event |
| .getProperty(UIEvents.EventTags.NEW_VALUE); |
| theShell.setVisible(isVisible); |
| } |
| } |
| }; |
| |
| eventBroker.subscribe(UIEvents.UIElement.TOPIC_VISIBLE, |
| visibilityHandler); |
| |
| sizeHandler = new EventHandler() { |
| @Override |
| public void handleEvent(Event event) { |
| if (ignoreSizeChanges) |
| return; |
| |
| // Ensure that this event is for a MMenuItem |
| Object objElement = event |
| .getProperty(UIEvents.EventTags.ELEMENT); |
| if (!(objElement instanceof MWindow)) { |
| return; |
| } |
| |
| // Is this listener interested ? |
| MWindow windowModel = (MWindow) objElement; |
| if (windowModel.getRenderer() != WBWRenderer.this) { |
| return; |
| } |
| |
| // No widget == nothing to update |
| Shell theShell = (Shell) windowModel.getWidget(); |
| if (theShell == null) { |
| return; |
| } |
| |
| String attName = (String) event |
| .getProperty(UIEvents.EventTags.ATTNAME); |
| |
| if (UIEvents.Window.X.equals(attName) |
| || UIEvents.Window.Y.equals(attName) |
| || UIEvents.Window.WIDTH.equals(attName) |
| || UIEvents.Window.HEIGHT.equals(attName)) { |
| if (boundsJob == null) { |
| boundsJob = new WindowSizeUpdateJob(); |
| boundsJob.windowsToUpdate.add(windowModel); |
| theShell.getDisplay().asyncExec(boundsJob); |
| } else { |
| if (!boundsJob.windowsToUpdate.contains(windowModel)) |
| boundsJob.windowsToUpdate.add(windowModel); |
| } |
| } |
| } |
| }; |
| |
| eventBroker.subscribe(UIEvents.Window.TOPIC_ALL, sizeHandler); |
| |
| themeDefinitionChanged = new ThemeDefinitionChangedHandler(); |
| eventBroker.subscribe(UIEvents.UILifeCycle.THEME_DEFINITION_CHANGED, |
| themeDefinitionChanged); |
| } |
| |
| @PreDestroy |
| public void contextDisposed() { |
| eventBroker.unsubscribe(topWindowHandler); |
| eventBroker.unsubscribe(shellUpdater); |
| eventBroker.unsubscribe(visibilityHandler); |
| eventBroker.unsubscribe(sizeHandler); |
| eventBroker.unsubscribe(themeDefinitionChanged); |
| |
| themeDefinitionChanged.dispose(); |
| } |
| |
| @Override |
| public Object createWidget(MUIElement element, Object parent) { |
| final Widget newWidget; |
| |
| if (!(element instanceof MWindow) |
| || (parent != null && !(parent instanceof Control))) |
| return null; |
| |
| MWindow wbwModel = (MWindow) element; |
| |
| MApplication appModel = wbwModel.getContext().get(MApplication.class); |
| Boolean rtlMode = (Boolean) appModel.getTransientData().get( |
| E4Workbench.RTL_MODE); |
| int rtlStyle = (rtlMode != null && rtlMode.booleanValue()) ? SWT.RIGHT_TO_LEFT |
| : 0; |
| |
| Shell parentShell = parent == null ? null : ((Control) parent) |
| .getShell(); |
| |
| final Shell wbwShell; |
| |
| int styleOverride = getStyleOverride(wbwModel) | rtlStyle; |
| if (parentShell == null) { |
| int style = styleOverride == -1 ? SWT.SHELL_TRIM | rtlStyle |
| : styleOverride; |
| wbwShell = new Shell(Display.getCurrent(), style); |
| wbwModel.getTags().add("topLevel"); //$NON-NLS-1$ |
| } else { |
| int style = SWT.TITLE | SWT.RESIZE | SWT.MAX | SWT.CLOSE | rtlStyle; |
| style = styleOverride == -1 ? style : styleOverride; |
| wbwShell = new Shell(parentShell, style); |
| |
| // Prevent ESC from closing the DW |
| wbwShell.addTraverseListener(new TraverseListener() { |
| @Override |
| public void keyTraversed(TraverseEvent e) { |
| if (e.detail == SWT.TRAVERSE_ESCAPE) { |
| e.doit = false; |
| } |
| } |
| }); |
| } |
| |
| wbwShell.setBackgroundMode(SWT.INHERIT_DEFAULT); |
| |
| Rectangle modelBounds = wbwShell.getBounds(); |
| if (wbwModel instanceof EObject) { |
| EObject wbw = (EObject) wbwModel; |
| EClass wbwclass = wbw.eClass(); |
| // use eIsSet rather than embed sentinel values |
| if (wbw.eIsSet(wbwclass.getEStructuralFeature("x"))) { //$NON-NLS-1$ |
| modelBounds.x = wbwModel.getX(); |
| } |
| if (wbw.eIsSet(wbwclass.getEStructuralFeature("y"))) { //$NON-NLS-1$ |
| modelBounds.y = wbwModel.getY(); |
| } |
| if (wbw.eIsSet(wbwclass.getEStructuralFeature("height"))) { //$NON-NLS-1$ |
| modelBounds.height = wbwModel.getHeight(); |
| } |
| if (wbw.eIsSet(wbwclass.getEStructuralFeature("width"))) { //$NON-NLS-1$ |
| modelBounds.width = wbwModel.getWidth(); |
| } |
| } |
| // Force the shell onto the display if it would be invisible otherwise |
| Rectangle displayBounds = Display.getCurrent().getBounds(); |
| if (!modelBounds.intersects(displayBounds)) { |
| Rectangle clientArea = Display.getCurrent().getClientArea(); |
| modelBounds.x = clientArea.x; |
| modelBounds.y = clientArea.y; |
| } |
| wbwShell.setBounds(modelBounds); |
| |
| setCSSInfo(wbwModel, wbwShell); |
| |
| // set up context |
| IEclipseContext localContext = getContext(wbwModel); |
| |
| // We need to retrieve specific CSS properties for our layout. |
| CSSEngineHelper helper = new CSSEngineHelper(localContext, wbwShell); |
| TrimmedPartLayout tl = new TrimmedPartLayout(wbwShell); |
| tl.gutterTop = helper.getMarginTop(0); |
| tl.gutterBottom = helper.getMarginBottom(0); |
| tl.gutterLeft = helper.getMarginLeft(0); |
| tl.gutterRight = helper.getMarginRight(0); |
| |
| wbwShell.setLayout(tl); |
| newWidget = wbwShell; |
| bindWidget(element, newWidget); |
| |
| // Add the shell into the WBW's context |
| localContext.set(Shell.class.getName(), wbwShell); |
| localContext.set(E4Workbench.LOCAL_ACTIVE_SHELL, wbwShell); |
| setCloseHandler(wbwModel); |
| localContext.set(IShellProvider.class.getName(), new IShellProvider() { |
| @Override |
| public Shell getShell() { |
| return wbwShell; |
| } |
| }); |
| final PartServiceSaveHandler saveHandler = new PartServiceSaveHandler() { |
| @Override |
| public Save promptToSave(MPart dirtyPart) { |
| Shell shell = (Shell) context |
| .get(IServiceConstants.ACTIVE_SHELL); |
| Object[] elements = promptForSave(shell, |
| Collections.singleton(dirtyPart)); |
| if (elements == null) { |
| return Save.CANCEL; |
| } |
| return elements.length == 0 ? Save.NO : Save.YES; |
| } |
| |
| @Override |
| public Save[] promptToSave(Collection<MPart> dirtyParts) { |
| List<MPart> parts = new ArrayList<MPart>(dirtyParts); |
| Shell shell = (Shell) context |
| .get(IServiceConstants.ACTIVE_SHELL); |
| Save[] response = new Save[dirtyParts.size()]; |
| Object[] elements = promptForSave(shell, parts); |
| if (elements == null) { |
| Arrays.fill(response, Save.CANCEL); |
| } else { |
| Arrays.fill(response, Save.NO); |
| for (int i = 0; i < elements.length; i++) { |
| response[parts.indexOf(elements[i])] = Save.YES; |
| } |
| } |
| return response; |
| } |
| }; |
| saveHandler.logger = logger; |
| localContext.set(ISaveHandler.class, saveHandler); |
| |
| if (wbwModel.getLabel() != null) |
| wbwShell.setText(wbwModel.getLocalizedLabel()); |
| |
| if (wbwModel.getIconURI() != null && wbwModel.getIconURI().length() > 0) { |
| wbwShell.setImage(getImage(wbwModel)); |
| } else { |
| // TODO: This should be added to the model, see bug 308494 |
| // it allows for a range of icon sizes that the platform gets to |
| // choose from |
| wbwShell.setImages(Window.getDefaultImages()); |
| } |
| |
| return newWidget; |
| } |
| |
| private void setCloseHandler(MWindow window) { |
| IEclipseContext context = window.getContext(); |
| // no direct model parent, must be a detached window |
| if (window.getParent() == null) { |
| context.set(IWindowCloseHandler.class.getName(), |
| new IWindowCloseHandler() { |
| @Override |
| public boolean close(MWindow window) { |
| return closeDetachedWindow(window); |
| } |
| }); |
| } else { |
| context.set(IWindowCloseHandler.class.getName(), |
| new IWindowCloseHandler() { |
| @Override |
| public boolean close(MWindow window) { |
| EPartService partService = (EPartService) window |
| .getContext().get( |
| EPartService.class.getName()); |
| return partService.saveAll(true); |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void hookControllerLogic(MUIElement me) { |
| super.hookControllerLogic(me); |
| |
| Widget widget = (Widget) me.getWidget(); |
| |
| if (widget instanceof Shell && me instanceof MWindow) { |
| final Shell shell = (Shell) widget; |
| final MWindow w = (MWindow) me; |
| shell.addControlListener(new ControlListener() { |
| @Override |
| public void controlResized(ControlEvent e) { |
| // Don't store the maximized size in the model |
| if (shell.getMaximized()) |
| return; |
| |
| try { |
| ignoreSizeChanges = true; |
| w.setWidth(shell.getSize().x); |
| w.setHeight(shell.getSize().y); |
| } finally { |
| ignoreSizeChanges = false; |
| } |
| } |
| |
| @Override |
| public void controlMoved(ControlEvent e) { |
| // Don't store the maximized size in the model |
| if (shell.getMaximized()) |
| return; |
| |
| try { |
| ignoreSizeChanges = true; |
| w.setX(shell.getLocation().x); |
| w.setY(shell.getLocation().y); |
| } finally { |
| ignoreSizeChanges = false; |
| } |
| } |
| }); |
| |
| shell.addShellListener(new ShellAdapter() { |
| @Override |
| public void shellClosed(ShellEvent e) { |
| // override the shell close event |
| e.doit = false; |
| MWindow window = (MWindow) e.widget.getData(OWNING_ME); |
| IWindowCloseHandler closeHandler = (IWindowCloseHandler) window |
| .getContext().get( |
| IWindowCloseHandler.class.getName()); |
| // if there's no handler or the handler permits the close |
| // request, clean-up as necessary |
| if (closeHandler == null || closeHandler.close(window)) { |
| cleanUp(window); |
| } |
| } |
| }); |
| shell.addListener(SWT.Activate, new Listener() { |
| @Override |
| public void handleEvent(org.eclipse.swt.widgets.Event event) { |
| MUIElement parentME = w.getParent(); |
| if (parentME instanceof MApplication) { |
| MApplication app = (MApplication) parentME; |
| app.setSelectedElement(w); |
| w.getContext().activate(); |
| } else if (parentME == null) { |
| parentME = (MUIElement) ((EObject) w).eContainer(); |
| if (parentME instanceof MContext) { |
| w.getContext().activate(); |
| } |
| } |
| updateNonFocusState(SWT.Activate, w); |
| } |
| }); |
| |
| shell.addListener(SWT.Deactivate, new Listener() { |
| @Override |
| public void handleEvent(org.eclipse.swt.widgets.Event event) { |
| updateNonFocusState(SWT.Deactivate, w); |
| } |
| }); |
| } |
| } |
| |
| private void updateNonFocusState(int event, MWindow win) { |
| MPerspective perspective = modelService.getActivePerspective(win); |
| if (perspective == null) { |
| return; |
| } |
| |
| List<MPartStack> stacks = modelService.findElements(perspective, null, |
| MPartStack.class, Arrays.asList(CSSConstants.CSS_ACTIVE_CLASS)); |
| if (stacks.isEmpty()) { |
| return; |
| } |
| |
| MPartStack stack = stacks.get(0); |
| int tagsCount = stack.getTags().size(); |
| boolean hasNonFocusTag = stack.getTags().contains( |
| CSSConstants.CSS_NO_FOCUS_CLASS); |
| |
| if (event == SWT.Activate && hasNonFocusTag) { |
| stack.getTags().remove(CSSConstants.CSS_NO_FOCUS_CLASS); |
| } else if (event == SWT.Deactivate && !hasNonFocusTag) { |
| stack.getTags().add(CSSConstants.CSS_NO_FOCUS_CLASS); |
| } |
| if (tagsCount != stack.getTags().size()) { |
| setCSSInfo(stack, stack.getWidget()); |
| } |
| } |
| |
| private void cleanUp(MWindow window) { |
| Object parent = ((EObject) window).eContainer(); |
| if (parent instanceof MApplication) { |
| MApplication application = (MApplication) parent; |
| List<MWindow> children = application.getChildren(); |
| if (children.size() > 1) { |
| // not the last window, destroy and remove |
| window.setToBeRendered(false); |
| children.remove(window); |
| } else { |
| // last window, just destroy without changing the model |
| engine.removeGui(window); |
| } |
| } else if (parent != null) { |
| window.setToBeRendered(false); |
| // this is a detached window, check for parts |
| if (modelService.findElements(window, null, MPart.class, null) |
| .isEmpty()) { |
| // if no parts, remove it |
| if (parent instanceof MWindow) { |
| ((MWindow) parent).getWindows().remove(window); |
| } else if (parent instanceof MPerspective) { |
| ((MPerspective) parent).getWindows().remove(window); |
| } |
| } |
| } |
| } |
| |
| /* |
| * Processing the contents of a Workbench window has to take into account |
| * that there may be trim elements contained in its child list. Since the |
| * |
| * @see |
| * org.eclipse.e4.ui.workbench.renderers.swt.SWTPartFactory#processContents |
| * (org.eclipse.e4.ui.model.application.MPart) |
| */ |
| @Override |
| public void processContents(MElementContainer<MUIElement> me) { |
| if (!(((MUIElement) me) instanceof MWindow)) |
| return; |
| MWindow wbwModel = (MWindow) ((MUIElement) me); |
| super.processContents(me); |
| |
| // Populate the main menu |
| IPresentationEngine renderer = (IPresentationEngine) context |
| .get(IPresentationEngine.class.getName()); |
| if (wbwModel.getMainMenu() != null) { |
| renderer.createGui(wbwModel.getMainMenu(), me.getWidget(), null); |
| Shell shell = (Shell) me.getWidget(); |
| shell.setMenuBar((Menu) wbwModel.getMainMenu().getWidget()); |
| } |
| |
| // create Detached Windows |
| for (MWindow dw : wbwModel.getWindows()) { |
| renderer.createGui(dw, me.getWidget(), wbwModel.getContext()); |
| } |
| |
| // Populate the trim (if any) |
| if (wbwModel instanceof MTrimmedWindow) { |
| Shell shell = (Shell) wbwModel.getWidget(); |
| MTrimmedWindow tWindow = (MTrimmedWindow) wbwModel; |
| List<MTrimBar> trimBars = new ArrayList<MTrimBar>( |
| tWindow.getTrimBars()); |
| for (MTrimBar trimBar : trimBars) { |
| renderer.createGui(trimBar, shell, wbwModel.getContext()); |
| // bug 387161: hack around that createGui(e, parent, context) |
| // does not reparent the element widget to the |
| // limbo shell wheb visible=false |
| if (!trimBar.isVisible()) { |
| trimBar.setVisible(true); |
| trimBar.setVisible(false); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public Object getUIContainer(MUIElement element) { |
| MUIElement parent = element.getParent(); |
| if (parent == null) { |
| // might be a detached window |
| parent = (MUIElement) ((EObject) element).eContainer(); |
| return parent == null ? null : parent.getWidget(); |
| } |
| |
| Composite shellComp = (Composite) element.getParent().getWidget(); |
| TrimmedPartLayout tpl = (TrimmedPartLayout) shellComp.getLayout(); |
| return tpl.clientArea; |
| } |
| |
| @Override |
| public void postProcess(MUIElement shellME) { |
| super.postProcess(shellME); |
| |
| Shell shell = (Shell) shellME.getWidget(); |
| |
| // Capture the max/min state |
| final MUIElement disposeME = shellME; |
| shell.addDisposeListener(new DisposeListener() { |
| @Override |
| public void widgetDisposed(DisposeEvent e) { |
| Shell shell = (Shell) e.widget; |
| if (disposeME != null) { |
| disposeME.getTags().remove(ShellMinimizedTag); |
| disposeME.getTags().remove(ShellMaximizedTag); |
| if (shell.getMinimized()) |
| disposeME.getTags().add(ShellMinimizedTag); |
| if (shell.getMaximized()) |
| disposeME.getTags().add(ShellMaximizedTag); |
| } |
| } |
| }); |
| |
| // Apply the correct shell state |
| if (shellME.getTags().contains(ShellMaximizedTag)) |
| shell.setMaximized(true); |
| else if (shellME.getTags().contains(ShellMinimizedTag)) |
| shell.setMinimized(true); |
| |
| shell.layout(true); |
| forceLayout(shell); |
| if (shellME.isVisible()) { |
| shell.open(); |
| } else { |
| shell.setVisible(false); |
| } |
| } |
| |
| private Object[] promptForSave(Shell parentShell, |
| Collection<MPart> saveableParts) { |
| SaveablePartPromptDialog dialog = new SaveablePartPromptDialog( |
| parentShell, saveableParts); |
| if (dialog.open() == Window.CANCEL) { |
| return null; |
| } |
| |
| return dialog.getCheckedElements(); |
| } |
| |
| @Inject |
| private IEclipseContext context; |
| |
| private void applyDialogStyles(Control control) { |
| IStylingEngine engine = (IStylingEngine) context |
| .get(IStylingEngine.SERVICE_NAME); |
| if (engine != null) { |
| Shell shell = control.getShell(); |
| if (shell.getBackgroundMode() == SWT.INHERIT_NONE) { |
| shell.setBackgroundMode(SWT.INHERIT_DEFAULT); |
| } |
| |
| engine.style(shell); |
| } |
| } |
| |
| class SaveablePartPromptDialog extends Dialog { |
| |
| private Collection<MPart> collection; |
| |
| private CheckboxTableViewer tableViewer; |
| |
| private Object[] checkedElements = new Object[0]; |
| |
| SaveablePartPromptDialog(Shell shell, Collection<MPart> collection) { |
| super(shell); |
| this.collection = collection; |
| } |
| |
| @Override |
| protected void configureShell(Shell newShell) { |
| super.configureShell(newShell); |
| newShell.setText(SWTRenderersMessages.choosePartsToSaveTitle); |
| } |
| |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| parent = (Composite) super.createDialogArea(parent); |
| |
| Label label = new Label(parent, SWT.LEAD); |
| label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| label.setText(SWTRenderersMessages.choosePartsToSave); |
| |
| tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.SINGLE |
| | SWT.BORDER); |
| GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); |
| data.heightHint = 250; |
| data.widthHint = 300; |
| tableViewer.getControl().setLayoutData(data); |
| tableViewer.setLabelProvider(new LabelProvider() { |
| @Override |
| public String getText(Object element) { |
| return ((MPart) element).getLocalizedLabel(); |
| } |
| }); |
| tableViewer.setContentProvider(ArrayContentProvider.getInstance()); |
| tableViewer.setInput(collection); |
| tableViewer.setAllChecked(true); |
| |
| return parent; |
| } |
| |
| @Override |
| public void create() { |
| super.create(); |
| applyDialogStyles(getShell()); |
| } |
| |
| @Override |
| protected void okPressed() { |
| checkedElements = tableViewer.getCheckedElements(); |
| super.okPressed(); |
| } |
| |
| public Object[] getCheckedElements() { |
| return checkedElements; |
| } |
| |
| @Override |
| protected boolean isResizable() { |
| return true; |
| } |
| |
| } |
| |
| @SuppressWarnings("restriction") |
| protected static class ThemeDefinitionChangedHandler implements |
| EventHandler { |
| protected Set<Resource> unusedResources = new HashSet<Resource>(); |
| |
| @Override |
| public void handleEvent(Event event) { |
| Object element = event.getProperty(IEventBroker.DATA); |
| |
| if (!(element instanceof MApplication)) { |
| return; |
| } |
| |
| Set<CSSEngine> engines = new HashSet<CSSEngine>(); |
| |
| // In theory we can have multiple engines since API allows it. |
| // It doesn't hurt to be prepared for such case |
| for (MWindow window : ((MApplication) element).getChildren()) { |
| CSSEngine engine = getEngine(window); |
| if (engine != null) { |
| engines.add(engine); |
| } |
| } |
| |
| for (CSSEngine engine : engines) { |
| for (Object resource : removeResources(engine |
| .getResourcesRegistry())) { |
| if (resource instanceof Resource |
| && !((Resource) resource).isDisposed()) { |
| unusedResources.add((Resource) resource); |
| } |
| } |
| engine.reapply(); |
| } |
| } |
| |
| protected CSSEngine getEngine(MWindow window) { |
| return WidgetElement.getEngine((Widget) window.getWidget()); |
| } |
| |
| protected List<Object> removeResources(IResourcesRegistry registry) { |
| if (registry instanceof SWTResourcesRegistry) { |
| return ((SWTResourcesRegistry) registry) |
| .removeResourcesByKeyTypeAndType( |
| ResourceByDefinitionKey.class, Font.class, |
| Color.class); |
| } |
| return Collections.emptyList(); |
| } |
| |
| public void dispose() { |
| for (Resource resource : unusedResources) { |
| if (!resource.isDisposed()) { |
| resource.dispose(); |
| } |
| } |
| unusedResources.clear(); |
| } |
| } |
| |
| private void forceLayout(Shell shell) { |
| int i = 0; |
| while(shell.isLayoutDeferred()) { |
| shell.setLayoutDeferred(false); |
| i++; |
| } |
| while(i > 0) { |
| shell.setLayoutDeferred(true); |
| i--; |
| } |
| } |
| } |