/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.e4.launcher.rendering;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.e4.ui.internal.workbench.Activator;
import org.eclipse.e4.ui.internal.workbench.E4Workbench;
import org.eclipse.e4.ui.internal.workbench.PartServiceSaveHandler;
import org.eclipse.e4.ui.internal.workbench.Policy;
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.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.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.EPartService;
import org.eclipse.e4.ui.workbench.modeling.ISaveHandler;
import org.eclipse.e4.ui.workbench.modeling.IWindowCloseHandler;
import org.eclipse.e4.ui.workbench.renderers.swt.CSSEngineHelper;
import org.eclipse.e4.ui.workbench.renderers.swt.SWTPartRenderer;
import org.eclipse.e4.ui.workbench.renderers.swt.WBWRenderer;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.databinding.swt.SWTObservables;
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.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
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.eclipse.riena.e4.launcher.E4XMIConstants;
import org.eclipse.riena.e4.launcher.part.StatusLinePart;
import org.eclipse.riena.internal.ui.swt.utils.RcpUtilities;
import org.eclipse.riena.navigation.ApplicationNodeManager;
import org.eclipse.riena.navigation.ui.swt.component.SwitcherComposite;
import org.eclipse.riena.ui.swt.layout.DpiGridLayout;
import org.eclipse.riena.ui.swt.lnf.LnfKeyConstants;
import org.eclipse.riena.ui.swt.lnf.LnfManager;
import org.eclipse.riena.ui.swt.lnf.renderer.DialogBorderRenderer;
import org.eclipse.riena.ui.swt.separator.Separator;
import org.eclipse.riena.ui.swt.utils.UIControlsFactory;
/**
* Render a Window or Workbench Window.
* <p>
* This class is a copy of {@link WBWRenderer}. All changes are collected in riena...() methods so that they can be easily identified.
* <p>
* TODO: provide a better solution when Bug 361133 is fixed
*/
public class RienaWBWRenderer extends SWTPartRenderer {
public static final String SHELL_CREATED = "shellCreated"; //$NON-NLS-1$
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>();
public void run() {
clearSizeUpdate();
while (!windowsToUpdate.isEmpty()) {
final MWindow window = windowsToUpdate.remove(0);
final 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 shellUpdater;
private EventHandler visibilityHandler;
private EventHandler sizeHandler;
private EventHandler childHandler;
/**
* manages some Riena-specific window aspects
*/
private final ApplicationView applicationView = new ApplicationView();
public RienaWBWRenderer() {
super();
}
MPart activePart = null;
private Composite header;
private Composite mainMenu;
private Composite mainToolBar;
private Composite statusLine;
private Composite perspectiveStack;
@Inject
void trackActivePart(@Optional
@Named(IServiceConstants.ACTIVE_PART)
final MPart p) {
if (activePart == p) {
return;
}
if (activePart != null) {
activePart.getTags().remove("active"); //$NON-NLS-1$
MUIElement parent = activePart.getParent();
if (parent == null && activePart.getCurSharedRef() != null) {
final MPlaceholder ph = activePart.getCurSharedRef();
parent = ph.getParent();
}
if (parent instanceof MPartStack) {
styleStack((MPartStack) parent, false);
} else {
if (activePart.getWidget() != null) {
setCSSInfo(activePart, activePart.getWidget());
}
}
}
activePart = p;
if (activePart != null) {
activePart.getTags().add("active"); //$NON-NLS-1$
MUIElement parent = activePart.getParent();
if (parent == null && activePart.getCurSharedRef() != null) {
final MPlaceholder ph = activePart.getCurSharedRef();
parent = ph.getParent();
}
if (parent instanceof MPartStack && parent.getWidget() != null) {
styleStack((MPartStack) parent, true);
} else if (activePart.getWidget() != null) {
setCSSInfo(activePart, activePart.getWidget());
}
}
}
private void styleStack(final MPartStack stack, final boolean active) {
if (!active) {
stack.getTags().remove("active"); //$NON-NLS-1$
} else {
stack.getTags().add("active"); //$NON-NLS-1$
}
if (stack.getWidget() != null) {
setCSSInfo(stack, stack.getWidget());
}
}
/**
* 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(final MWindow window) {
final EPartService partService = (EPartService) window.getContext().get(EPartService.class.getName());
final 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 (final 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 (final MPart part : parts) {
partService.hidePart(part);
}
return true;
}
@PostConstruct
public void init() {
shellUpdater = new EventHandler() {
public void handleEvent(final Event event) {
// Ensure that this event is for a MMenuItem
final Object objElement = event.getProperty(UIEvents.EventTags.ELEMENT);
if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MWindow)) {
return;
}
// Is this listener interested ?
final MWindow windowModel = (MWindow) objElement;
if (windowModel.getRenderer() != RienaWBWRenderer.this) {
return;
}
// No widget == nothing to update
final Shell theShell = (Shell) windowModel.getWidget();
if (theShell == null) {
return;
}
final String attName = (String) event.getProperty(UIEvents.EventTags.ATTNAME);
if (UIEvents.UILabel.LABEL.equals(attName)) {
final 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)) {
final String newTTip = (String) event.getProperty(UIEvents.EventTags.NEW_VALUE);
theShell.setToolTipText(newTTip);
}
}
};
eventBroker.subscribe(UIEvents.UILabel.TOPIC_ALL, shellUpdater);
visibilityHandler = new EventHandler() {
public void handleEvent(final Event event) {
// Ensure that this event is for a MMenuItem
final Object objElement = event.getProperty(UIEvents.EventTags.ELEMENT);
if (!(objElement instanceof MWindow)) {
return;
}
// Is this listener interested ?
final MWindow windowModel = (MWindow) objElement;
if (windowModel.getRenderer() != RienaWBWRenderer.this) {
return;
}
// No widget == nothing to update
final Shell theShell = (Shell) windowModel.getWidget();
if (theShell == null) {
return;
}
final String attName = (String) event.getProperty(UIEvents.EventTags.ATTNAME);
if (UIEvents.UIElement.VISIBLE.equals(attName)) {
final boolean isVisible = (Boolean) event.getProperty(UIEvents.EventTags.NEW_VALUE);
theShell.setVisible(isVisible);
}
}
};
eventBroker.subscribe(UIEvents.UIElement.TOPIC_VISIBLE, visibilityHandler);
sizeHandler = new EventHandler() {
public void handleEvent(final Event event) {
if (ignoreSizeChanges) {
return;
}
// Ensure that this event is for a MMenuItem
final Object objElement = event.getProperty(UIEvents.EventTags.ELEMENT);
if (!(objElement instanceof MWindow)) {
return;
}
// Is this listener interested ?
final MWindow windowModel = (MWindow) objElement;
if (windowModel.getRenderer() != RienaWBWRenderer.this) {
return;
}
// No widget == nothing to update
final Shell theShell = (Shell) windowModel.getWidget();
if (theShell == null) {
return;
}
final 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);
childHandler = new EventHandler() {
public void handleEvent(final Event event) {
// Track additions/removals of the active part and keep its
// stack styled correctly
final Object changedObj = event.getProperty(UIEvents.EventTags.ELEMENT);
if (!(changedObj instanceof MPartStack)) {
return;
}
final MPartStack stack = (MPartStack) changedObj;
final String eventType = (String) event.getProperty(UIEvents.EventTags.TYPE);
if (UIEvents.EventTypes.ADD.equals(eventType)) {
final MUIElement added = (MUIElement) event.getProperty(UIEvents.EventTags.NEW_VALUE);
if (added == activePart) {
styleStack(stack, true);
}
} else if (UIEvents.EventTypes.REMOVE.equals(eventType)) {
Activator.trace(Policy.DEBUG_RENDERER, "Child Removed", null); //$NON-NLS-1$
final MUIElement removed = (MUIElement) event.getProperty(UIEvents.EventTags.OLD_VALUE);
if (removed == activePart) {
styleStack(stack, false);
}
}
}
};
eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, childHandler);
}
@PreDestroy
public void contextDisposed() {
eventBroker.unsubscribe(shellUpdater);
eventBroker.unsubscribe(visibilityHandler);
eventBroker.unsubscribe(sizeHandler);
eventBroker.unsubscribe(childHandler);
}
@Override
public Object createWidget(final MUIElement element, final Object parent) {
final Widget newWidget;
if (!(element instanceof MWindow) || (parent != null && !(parent instanceof Control))) {
return null;
}
final MWindow wbwModel = (MWindow) element;
final MApplication appModel = wbwModel.getContext().get(MApplication.class);
final Boolean rtlMode = (Boolean) appModel.getTransientData().get(E4Workbench.RTL_MODE);
final int rtlStyle = (rtlMode != null && rtlMode.booleanValue()) ? SWT.RIGHT_TO_LEFT : 0;
final Shell parentShell = parent == null ? null : ((Control) parent).getShell();
final Shell wbwShell;
if (parentShell == null) {
wbwShell = rienaCreateShell(rtlStyle, wbwModel);
wbwModel.getTags().add("topLevel"); //$NON-NLS-1$
} else if (wbwModel.getTags().contains("dragHost")) { //$NON-NLS-1$
wbwShell = new Shell(parentShell, SWT.BORDER | rtlStyle);
wbwShell.setAlpha(110);
} else {
wbwShell = new Shell(parentShell, SWT.TOOL | SWT.TITLE | SWT.RESIZE | rtlStyle);
}
wbwShell.setBackgroundMode(SWT.INHERIT_DEFAULT);
final Rectangle modelBounds = wbwShell.getBounds();
if (wbwModel instanceof EObject) {
final EObject wbw = (EObject) wbwModel;
final 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
final Rectangle displayBounds = Display.getCurrent().getBounds();
if (!modelBounds.intersects(displayBounds)) {
final Rectangle clientArea = Display.getCurrent().getClientArea();
modelBounds.x = clientArea.x;
modelBounds.y = clientArea.y;
}
wbwShell.setBounds(modelBounds);
setCSSInfo(wbwModel, wbwShell);
// set up context
final IEclipseContext localContext = getContext(wbwModel);
// We need to retrieve specific CSS properties for our layout.
final CSSEngineHelper helper = new CSSEngineHelper(localContext, wbwShell);
// final 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);
rienaCreateContents(wbwShell);
// 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() {
public Shell getShell() {
return wbwShell;
}
});
localContext.set(ISaveHandler.class, new PartServiceSaveHandler() {
@Override
public Save promptToSave(final MPart dirtyPart) {
final Shell shell = (Shell) context.get(IServiceConstants.ACTIVE_SHELL);
final 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(final Collection<MPart> dirtyParts) {
final List<MPart> parts = new ArrayList<MPart>(dirtyParts);
final Shell shell = (Shell) context.get(IServiceConstants.ACTIVE_SHELL);
final Save[] response = new Save[dirtyParts.size()];
final 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;
}
});
if (wbwModel.getLabel() != null) {
wbwShell.setText(wbwModel.getLocalizedLabel());
}
wbwShell.setImage(getImage(wbwModel));
// TODO: This should be added to the model, see bug 308494
wbwShell.setImages(Window.getDefaultImages());
applicationView.doInitialBinding();
return newWidget;
}
/**
* We need a shell with the NO_TRIM style flag
*
* @param rtlStyle
* @return
*/
private Shell rienaCreateShell(final int rtlStyle, final MWindow modelElement) {
int shellStyle = rtlStyle | SWT.DOUBLE_BUFFERED;
if (isHideOSBorder()) {
shellStyle = rtlStyle | SWT.NO_TRIM;
} else {
shellStyle = rtlStyle | SWT.SHELL_TRIM;
}
final Shell shell = new Shell(Display.getCurrent(), shellStyle);
RcpUtilities.setShell(shell);
final Rectangle shellBounds = applicationView.initShell(shell);
modelElement.setX(shellBounds.x);
modelElement.setY(shellBounds.y);
modelElement.setWidth(shellBounds.width);
modelElement.setHeight(shellBounds.height);
return shell;
}
private Boolean isHideOSBorder() {
return LnfManager.getLnf().getBooleanSetting(LnfKeyConstants.SHELL_HIDE_OS_BORDER);
}
private void rienaCreateContents(final Composite clientArea) {
final DpiGridLayout layout = new DpiGridLayout();
layout.marginWidth = getShellBorderWidth();
layout.marginHeight = getShellBorderWidth();
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
clientArea.setLayout(layout);
header = new Composite(clientArea, SWT.NONE);
final GridData headerLayoutData = new GridData(GridData.FILL_HORIZONTAL);
final int headerPartHeight = SwitcherComposite.getShellPadding() + SwitcherComposite.getSwitchterHeight() + SwitcherComposite.getSwitchterTopMargin();
// headerLayoutData.heightHint = headerPartHeight;
header.setLayoutData(headerLayoutData);
header.setLayout(new FillLayout());
mainMenu = new Composite(clientArea, SWT.NONE);
final GridData mainMenuLayoutData = new GridData(GridData.FILL_HORIZONTAL);
mainMenuLayoutData.verticalIndent = LnfManager.getLnf().getIntegerSetting(LnfKeyConstants.MENUBAR_TOP_MARGIN);
mainMenu.setLayoutData(mainMenuLayoutData);
final FillLayout mainMenuLayout = new FillLayout();
final Integer shellPadding = isHideOSBorder() ? LnfManager.getLnf().getIntegerSetting(LnfKeyConstants.TITLELESS_SHELL_PADDING) : 0;
mainMenuLayout.marginWidth = shellPadding;
mainMenu.setLayout(mainMenuLayout);
final Separator separator = UIControlsFactory.createSeparator(clientArea, SWT.HORIZONTAL);
final GridData separatorLayoutData = new GridData(GridData.FILL_HORIZONTAL);
separatorLayoutData.heightHint = 2;
separator.setLayoutData(separatorLayoutData);
mainToolBar = new Composite(clientArea, SWT.NONE);
final GridData mainToolBarLayoutData = new GridData(GridData.FILL_HORIZONTAL);
mainToolBarLayoutData.verticalIndent = LnfManager.getLnf().getIntegerSetting(LnfKeyConstants.TOOLBAR_TOP_MARGIN);
mainToolBar.setLayoutData(mainToolBarLayoutData);
final FillLayout mainToolBarLayout = new FillLayout();
mainToolBarLayout.marginWidth = shellPadding;
mainToolBar.setLayout(mainToolBarLayout);
perspectiveStack = new Composite(clientArea, SWT.NONE);
perspectiveStack.setLayoutData(new GridData(GridData.FILL_BOTH));
final FillLayout perspectiveStackLayout = new FillLayout();
perspectiveStackLayout.marginWidth = shellPadding;
perspectiveStack.setLayout(perspectiveStackLayout);
applicationView.createInfoFlyout(perspectiveStack).setPositionCorrectionY(
LnfManager.getLnf().getIntegerSetting(LnfKeyConstants.TOOLBAR_WORK_AREA_VERTICAL_GAP));
statusLine = new Composite(clientArea, SWT.NONE);
final GridData statusLayoutData = new GridData(GridData.FILL_HORIZONTAL);
statusLayoutData.verticalIndent = shellPadding;
statusLayoutData.heightHint = LnfManager.getLnf().getIntegerSetting(LnfKeyConstants.STATUSLINE_HEIGHT) + StatusLinePart.BOTTOM_OFFSET;
statusLine.setLayoutData(statusLayoutData);
statusLine.setLayout(new FillLayout());
}
/**
* Returns the width of the shell border.
*
* @return border width
*/
private static int getShellBorderWidth() {
final DialogBorderRenderer borderRenderer = (DialogBorderRenderer) LnfManager.getLnf().getRenderer(LnfKeyConstants.TITLELESS_SHELL_BORDER_RENDERER);
return borderRenderer != null ? borderRenderer.getBorderWidth() : 0;
}
private void setCloseHandler(final MWindow window) {
final IEclipseContext context = window.getContext();
// no direct model parent, must be a detached window
if (window.getParent() == null) {
context.set(IWindowCloseHandler.class.getName(), new IWindowCloseHandler() {
public boolean close(final MWindow window) {
return closeDetachedWindow(window);
}
});
} else {
context.set(IWindowCloseHandler.class.getName(), new IWindowCloseHandler() {
public boolean close(final MWindow window) {
final EPartService partService = (EPartService) window.getContext().get(EPartService.class.getName());
return partService.saveAll(true);
}
});
}
}
@Override
public void hookControllerLogic(final MUIElement me) {
super.hookControllerLogic(me);
final 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() {
public void controlResized(final 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;
}
}
public void controlMoved(final 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(final ShellEvent e) {
// override the shell close event
e.doit = false;
final MWindow window = (MWindow) e.widget.getData(OWNING_ME);
final 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() {
public void handleEvent(final org.eclipse.swt.widgets.Event event) {
MUIElement parentME = w.getParent();
if (parentME instanceof MApplication) {
final 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();
}
}
}
});
}
}
private void cleanUp(final MWindow window) {
final Object parent = ((EObject) window).eContainer();
if (parent instanceof MApplication) {
final MApplication application = (MApplication) parent;
final 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(final MElementContainer me) {
if (!(me instanceof MWindow)) {
return;
}
final MWindow wbwModel = (MWindow) me;
super.processContents(me);
// Populate the main menu
final IPresentationEngine renderer = (IPresentationEngine) context.get(IPresentationEngine.class.getName());
if (wbwModel.getMainMenu() != null) {
renderer.createGui(wbwModel.getMainMenu(), me.getWidget(), null);
final Shell shell = (Shell) me.getWidget();
shell.setMenuBar((Menu) wbwModel.getMainMenu().getWidget());
}
// create Detached Windows
for (final MWindow dw : wbwModel.getWindows()) {
renderer.createGui(dw, me.getWidget(), wbwModel.getContext());
}
// Populate the trim (if any)
if (wbwModel instanceof MTrimmedWindow) {
final Shell shell = (Shell) wbwModel.getWidget();
final MTrimmedWindow tWindow = (MTrimmedWindow) wbwModel;
for (final MTrimBar trimBar : tWindow.getTrimBars()) {
renderer.createGui(trimBar, shell, wbwModel.getContext());
}
}
rienaActivateApplicationNode();
}
private void rienaActivateApplicationNode() {
final Realm realm = SWTObservables.getRealm(Display.getCurrent());
Realm.runWithDefault(realm, new Runnable() {
public void run() {
ApplicationNodeManager.getApplicationNode().activate();
}
});
}
/*
* (non-Javadoc)
*
* @see org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer#getUIContainer (org.eclipse.e4.ui.model.application.MUIElement)
*/
@Override
public Object getUIContainer(final 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();
}
final String elementId = element.getElementId();
if (E4XMIConstants.HEADER_PART_ID.equals(elementId)) {
return header;
}
if (E4XMIConstants.MAIN_MENU_PART_ID.equals(elementId)) {
return mainMenu;
}
if (E4XMIConstants.MAIN_TOOLBAR_PART_ID.equals(elementId)) {
return mainToolBar;
}
if (E4XMIConstants.STATUSLINE_PART_ID.equals(elementId)) {
return statusLine;
}
if (E4XMIConstants.PERSPECTIVE_STACK_ID.equals(elementId)) {
return perspectiveStack;
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.e4.ui.workbench.renderers.PartFactory#postProcess(org.eclipse .e4.ui.model.application.MPart)
*/
@Override
public void postProcess(final MUIElement shellME) {
super.postProcess(shellME);
final Shell shell = (Shell) shellME.getWidget();
// Capture the max/min state
final MUIElement disposeME = shellME;
shell.addDisposeListener(new DisposeListener() {
public void widgetDisposed(final DisposeEvent e) {
final 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);
if (shellME.isVisible()) {
shell.open();
} else {
shell.setVisible(false);
}
rienaPostProcess(shell);
}
/**
* notify the Riena SubApplicationBinder
*
* @param shell
* the newly created {@link Shell}
*/
private void rienaPostProcess(final Shell shell) {
eventBroker.send(SHELL_CREATED, shell);
}
private Object[] promptForSave(final Shell parentShell, final Collection<MPart> saveableParts) {
final SaveablePartPromptDialog dialog = new SaveablePartPromptDialog(parentShell, saveableParts);
if (dialog.open() == Window.CANCEL) {
return null;
}
return dialog.getCheckedElements();
}
@Inject
private IEclipseContext context;
private void applyDialogStyles(final Control control) {
final IStylingEngine engine = (IStylingEngine) context.get(IStylingEngine.SERVICE_NAME);
if (engine != null) {
final Shell shell = control.getShell();
if (shell.getBackgroundMode() == SWT.INHERIT_NONE) {
shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
}
engine.style(shell);
}
}
class SaveablePartPromptDialog extends Dialog {
private final Collection<MPart> collection;
private CheckboxTableViewer tableViewer;
private Object[] checkedElements = new Object[0];
SaveablePartPromptDialog(final Shell shell, final Collection<MPart> collection) {
super(shell);
this.collection = collection;
}
@Override
protected Control createDialogArea(Composite parent) {
parent = (Composite) super.createDialogArea(parent);
final Label label = new Label(parent, SWT.LEAD);
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
label.setText("Select the parts to save:"); //$NON-NLS-1$
tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.SINGLE | SWT.BORDER);
final 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(final 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;
}
}
}