/*******************************************************************************
* Copyright (c) 2011 Kai Toedter 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:
* Kai Toedter - initial API and implementation
******************************************************************************/
package com.toedter.e4.ui.workbench.addons.generic.minmax;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.eclipse.e4.core.commands.EHandlerService;
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.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.SideValue;
import org.eclipse.e4.ui.model.application.ui.advanced.MArea;
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.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.model.application.ui.menu.MDirectToolItem;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
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.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import com.toedter.e4.ui.workbench.generic.GenericRenderer;
import com.toedter.e4.ui.workbench.generic.PresentationEngine;
@SuppressWarnings("restriction")
public class GenericMinMaxAddon {
public static final String ADDONS_MINMAX_TRIM_STACK_ID = "com.toedter.e4.ui.workbench.addons.generic.minmax.trimStackId";
static String ID_SUFFIX = "(minimized)"; //$NON-NLS-1$
// tags representing the min/max state
public static String MINIMIZED = IPresentationEngine.MINIMIZED;
public static String MAXIMIZED = IPresentationEngine.MAXIMIZED;
public static String MINIMIZED_BY_ZOOM = IPresentationEngine.MINIMIZED_BY_ZOOM;
private final IMinMaxAddon uiMinMaxAddon;
private final IEventBroker eventBroker;
private final EModelService modelService;
protected boolean ignoreTagChanges;
@Inject
private IEclipseContext context;
@Inject
private EHandlerService handlerService;
private final MApplication application;
@Inject
public GenericMinMaxAddon(IMinMaxAddon uiMinMaxAddon, IEventBroker eventBroker, EModelService modelService,
MApplication application) {
this.application = application;
System.out.println("Generic GenericMinMaxAddon()");
this.uiMinMaxAddon = uiMinMaxAddon;
this.eventBroker = eventBroker;
this.uiMinMaxAddon.setGenericMinMaxAddon(this);
this.modelService = modelService;
}
@PostConstruct
void hookListeners() {
System.out.println("GenericMinMaxAddon.hookListeners()");
System.out.println("EventBroker: " + eventBroker);
eventBroker.subscribe(UIEvents.UIElement.TOPIC_WIDGET, widgetListener);
eventBroker.subscribe(UIEvents.ApplicationElement.TOPIC_TAGS, tagListener);
}
private final EventHandler tagListener = new EventHandler() {
@Override
public void handleEvent(Event event) {
if (ignoreTagChanges) {
return;
}
Object changedObj = event.getProperty(EventTags.ELEMENT);
String eventType = (String) event.getProperty(UIEvents.EventTags.TYPE);
String tag = (String) event.getProperty(UIEvents.EventTags.NEW_VALUE);
String oldVal = (String) event.getProperty(UIEvents.EventTags.OLD_VALUE);
if (!(changedObj instanceof MUIElement)) {
return;
}
final MUIElement changedElement = (MUIElement) changedObj;
if (UIEvents.EventTypes.ADD.equals(eventType)) {
if (MINIMIZED.equals(tag)) {
minimize(changedElement);
} else if (MAXIMIZED.equals(tag)) {
maximize(changedElement);
}
} else if (UIEvents.EventTypes.REMOVE.equals(eventType)) {
if (MINIMIZED.equals(oldVal)) {
restore(changedElement);
} else if (MAXIMIZED.equals(oldVal)) {
unzoom(changedElement);
}
}
}
};
private final EventHandler widgetListener = new EventHandler() {
@Override
public void handleEvent(Event event) {
final MUIElement element = (MUIElement) event.getProperty(EventTags.ELEMENT);
if (!(element instanceof MPartStack) && !(element instanceof MArea)) {
return;
}
final Runnable maximizeRunnable = new Runnable() {
@Override
public void run() {
maximize(element);
}
};
uiMinMaxAddon.setMaximizeHandler(element, maximizeRunnable);
final Runnable minimizeRunnable = new Runnable() {
@Override
public void run() {
minimize(element);
}
};
uiMinMaxAddon.setMinimizeHandler(element, minimizeRunnable);
final Runnable restoreRunnable = new Runnable() {
@Override
public void run() {
restore(element);
}
};
uiMinMaxAddon.setRestoreHandler(element, restoreRunnable);
}
private void maximize(MUIElement element) {
setState(element, MAXIMIZED);
}
private void minimize(MUIElement element) {
setState(element, MINIMIZED);
}
public void restore(MUIElement element) {
setState(element, null);
}
};
private void setState(MUIElement element, String state) {
element.getTags().remove(MINIMIZED_BY_ZOOM);
if (MINIMIZED.equals(state)) {
element.getTags().remove(MAXIMIZED);
element.getTags().add(MINIMIZED);
} else if (MAXIMIZED.equals(state)) {
element.getTags().remove(MINIMIZED);
element.getTags().add(MAXIMIZED);
} else {
element.getTags().remove(MINIMIZED);
element.getTags().remove(MAXIMIZED);
}
}
protected void minimize(MUIElement element) {
if (!element.isToBeRendered()) {
return;
}
createTrim(element);
element.setVisible(false);
}
protected void unzoom(MUIElement element) {
MWindow win = modelService.getTopLevelWindowFor(element);
List<MPartStack> stacks = modelService.findElements(win, null, MPartStack.class, null,
EModelService.PRESENTATION);
for (MPartStack theStack : stacks) {
if (theStack.getWidget() != null && theStack.getTags().contains(MINIMIZED)
&& theStack.getTags().contains(MINIMIZED_BY_ZOOM)) {
theStack.getTags().remove(MINIMIZED);
}
}
}
public void resetWindows(MUIElement element) {
ignoreTagChanges = true;
MWindow window = modelService.getTopLevelWindowFor(element);
List<MPartStack> stacks = modelService.findElements(window, null, MPartStack.class, null,
EModelService.PRESENTATION);
for (MPartStack partStack : stacks) {
if (partStack.getWidget() != null) {
if (partStack.getTags().contains(MINIMIZED)) {
partStack.getTags().remove(MINIMIZED);
}
if (partStack.getTags().contains(MAXIMIZED)) {
partStack.getTags().remove(MAXIMIZED);
}
if (partStack.getTags().contains(MINIMIZED_BY_ZOOM)) {
partStack.getTags().remove(MINIMIZED_BY_ZOOM);
}
}
partStack.setVisible(true);
}
ignoreTagChanges = false;
PresentationEngine presentationEngine = (PresentationEngine) context.get(IPresentationEngine.class);
if (window instanceof MTrimmedWindow) {
MTrimmedWindow trimmedWindow = (MTrimmedWindow) window;
List<MTrimBar> trimBars = trimmedWindow.getTrimBars();
for (MTrimBar trimBar : trimBars) {
if (trimBar.getSide() == SideValue.LEFT || trimBar.getSide() == SideValue.RIGHT) {
trimBar.getChildren().clear();
trimBar.setVisible(false);
presentationEngine.refreshGui(trimBar);
}
}
}
presentationEngine.refreshGui(window);
}
protected void restore(MUIElement element) {
element.getTags().remove(MINIMIZED_BY_ZOOM);
element.getTags().remove(MINIMIZED);
element.setVisible(true);
}
protected void maximize(MUIElement element) {
if (!element.isToBeRendered()) {
return;
}
MWindow mWindow = getWindowFor(element);
MPerspective persp = null; // TODO handle perspectives?
List<String> maxTag = new ArrayList<String>();
maxTag.add(MAXIMIZED);
List<MUIElement> curMax = modelService.findElements(persp == null ? mWindow : persp, null, MUIElement.class,
maxTag);
if (curMax.size() > 0) {
for (MUIElement maxElement : curMax) {
if (maxElement == element) {
continue;
}
ignoreTagChanges = true;
try {
maxElement.getTags().remove(MAXIMIZED);
} finally {
ignoreTagChanges = false;
}
}
}
List<MPartStack> stacks = modelService.findElements(persp == null ? mWindow : persp, null, MPartStack.class,
null, EModelService.PRESENTATION);
for (MPartStack theStack : stacks) {
if (theStack == element || !theStack.isToBeRendered()) {
continue;
}
// Exclude stacks in DW's
if (getWindowFor(theStack) != mWindow) {
continue;
}
int location = modelService.getElementLocation(theStack);
if (location != EModelService.IN_SHARED_AREA && theStack.getWidget() != null
&& !theStack.getTags().contains(MINIMIZED)) {
theStack.getTags().add(MINIMIZED_BY_ZOOM);
theStack.getTags().add(MINIMIZED);
}
}
// now let the parent check if the children are visible
GenericRenderer parentRenderer = (GenericRenderer) element.getParent().getRenderer();
if (parentRenderer != null) {
parentRenderer.doLayout(element.getParent());
}
}
private MWindow getWindowFor(MUIElement element) {
MUIElement parent = element.getParent();
// We rely here on the fact that a DW's 'getParent' will return
// null since it's not in the 'children' hierarchy
while (parent != null && !(parent instanceof MWindow)) {
parent = parent.getParent();
}
// A detached window will end up with getParent() == null
return (MWindow) parent;
}
private void createTrim(MUIElement element) {
MTrimmedWindow window = (MTrimmedWindow) getWindowFor(element);
// Is there already a TrimControl there ?
String trimId = element.getElementId() + getMinimizedElementSuffix(element);
System.out.println("Trim Id: " + trimId);
MToolBar trimStack = (MToolBar) modelService.find(trimId, window);
if (trimStack == null) {
trimStack = MenuFactoryImpl.eINSTANCE.createToolBar();
trimStack.setElementId(trimId);
// MCommand command = MCommandsFactory.INSTANCE.createCommand();
// command.setElementId("com.toedter.e4.ui.workbench.addons.generic.minmax.restore");
// command.setCommandName("Restore Stack");
// command.setDescription("xxx");
// command.setContributorURI("kai");
//
// MHandler handler = MCommandsFactory.INSTANCE.createHandler();
// handler.setContributionURI("bundleclass://com.toedter.e4.ui.workbench.addons.generic/com.toedter.e4.ui.workbench.addons.generic.minmax.RestoreHandler");
// handler.setCommand(command);
//
// MHandledToolItem toolItem =
// MMenuFactory.INSTANCE.createHandledToolItem();
// // command.getParameters().add(mCommandParameter);
// MParameter parameter =
// MCommandsFactory.INSTANCE.createParameter();
// parameter.setName(ADDONS_MINMAX_TRIM_STACK_ID);
// parameter.setValue(element.getElementId());
// toolItem.getParameters().add(parameter);
// toolItem.setIconURI("platform:/plugin/com.toedter.e4.ui.workbench.addons.generic/icons/fastview_restore.gif");
// toolItem.setCommand(command);
//
// application.getHandlers().add(handler);
// // window.getHandlers().add(handler);
// application.getCommands().add(command);
// handlerService.activateHandler(command.getElementId(), handler);
// MCommandParameter mCommandParameter =
// MCommandsFactory.INSTANCE.createCommandParameter();
MDirectToolItem toolItem = MenuFactoryImpl.eINSTANCE.createDirectToolItem();
toolItem.setIconURI("platform:/plugin/com.toedter.e4.ui.workbench.addons.generic/icons/fastview_restore.gif");
toolItem.setContributionURI("bundleclass://com.toedter.e4.ui.workbench.addons.generic/com.toedter.e4.ui.workbench.addons.generic.minmax.RestoreHandler");
toolItem.setContainerData(element.getElementId());
trimStack.getChildren().add(toolItem);
// Check if we have a cached location
MTrimBar bar = getBarForElement(element, window);
bar.getChildren().add(trimStack);
bar.setVisible(true);
// get the parent trim bar, see bug 320756
PresentationEngine presentationEngine = (PresentationEngine) context.get(IPresentationEngine.class);
@SuppressWarnings("unchecked")
MElementContainer<MUIElement> partStack = (MElementContainer<MUIElement>) element;
for (MUIElement stackElement : partStack.getChildren()) {
if (!stackElement.isToBeRendered()) {
continue;
}
MDirectToolItem partItem = MenuFactoryImpl.eINSTANCE.createDirectToolItem();
partItem.setContributionURI("bundleclass://com.toedter.e4.ui.workbench.addons.generic/com.toedter.e4.ui.workbench.addons.generic.minmax.FastViewHandler");
MUILabel labelElement = getLabelElement(stackElement);
partItem.setIconURI(labelElement.getIconURI());
trimStack.getChildren().add(partItem);
}
if (bar.getWidget() == null) {
// ask it to be rendered
bar.setToBeRendered(true);
// create the widget
presentationEngine.createGui(bar);
} else {
trimStack.setToBeRendered(true);
presentationEngine.createGui(trimStack);
presentationEngine.refreshGui(bar);
}
presentationEngine.refreshGui(window);
} else {
// get the parent trim bar, see bug 320756
MUIElement parent = trimStack.getParent();
parent.setVisible(true);
if (parent.getWidget() == null) {
// ask it to be rendered
parent.setToBeRendered(true);
// create the widget
PresentationEngine presentationEngine = (PresentationEngine) context.get(IPresentationEngine.class);
presentationEngine.createGui(parent);
}
trimStack.setToBeRendered(true);
}
}
private MUILabel getLabelElement(MUIElement element) {
if (element instanceof MPlaceholder) {
element = ((MPlaceholder) element).getRef();
}
return (MUILabel) (element instanceof MUILabel ? element : null);
}
private MTrimBar getBarForElement(MUIElement element, MTrimmedWindow window) {
SideValue side = SideValue.LEFT;
MTrimBar bar = modelService.getTrim(window, side);
return bar;
}
private String getMinimizedElementSuffix(MUIElement element) {
String id = ID_SUFFIX;
MPerspective persp = modelService.getPerspectiveFor(element);
if (persp != null) {
id = '(' + persp.getElementId() + ')';
}
return id;
}
}