blob: 43e57f5daded52b36c895a2d2b6800fc9427d454 [file] [log] [blame]
/*******************************************************************************
* 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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Rushan R. Gilmullin - initial API and implementation
*******************************************************************************/
package org.eclipse.osbp.vaaclipse.behaviour.cleanup;
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.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.advanced.MArea;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
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 org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.eclipse.osbp.vaaclipse.api.VaadinExecutorService;
public class CleanupAddon {
@Inject
IEventBroker eventBroker;
@Inject
EModelService modelService;
@Inject
MApplication app;
@Inject
VaadinExecutorService communicationManager;
private EventHandler childrenHandler = new EventHandler() {
private boolean ignoreChildrenChanges = false;
public void handleEvent(Event event) {
if (ignoreChildrenChanges)
return;
Object changedObj = event.getProperty(UIEvents.EventTags.ELEMENT);
String eventType = (String) event
.getProperty(UIEvents.EventTags.TYPE);
if (UIEvents.EventTypes.REMOVE.equals(eventType)) {
final MElementContainer<?> container = (MElementContainer<?>) changedObj;
MUIElement containerParent = container.getParent();
// Determine the elements that should *not* ever be
// auto-destroyed
if (container instanceof MApplication
|| container instanceof MPerspectiveStack
|| container instanceof MMenuElement
|| container instanceof MTrimBar
|| container instanceof MToolBar
|| container instanceof MArea
|| container.getTags().contains(
IPresentationEngine.NO_AUTO_COLLAPSE)) {
return;
}
if (container instanceof MWindow
&& containerParent instanceof MApplication) {
return;
}
// Stall the removal to handle cases where the container is only
// transiently empty
communicationManager.invokeLater(new Runnable() {
@Override
public void run() {
// Remove it from the display if no visible children
int tbrCount = modelService
.toBeRenderedCount(container);
// Cache the value since setting the TBR may change the
// result
boolean lastStack = isLastEditorStack(container);
if (tbrCount == 0 && !lastStack) {
container.setToBeRendered(false);
}
// Remove it from the model if it has no children at all
MElementContainer<?> lclContainer = container;
if (lclContainer.getChildren().size() == 0) {
MElementContainer<MUIElement> parent = container
.getParent();
if (parent != null && !lastStack) {
container.setToBeRendered(false);
parent.getChildren().remove(container);
} else if (container instanceof MWindow) {
// Must be a Detached Window
MUIElement eParent = (MUIElement) ((EObject) container)
.eContainer();
if (eParent instanceof MPerspective) {
((MPerspective) eParent).getWindows()
.remove(container);
} else if (eParent instanceof MWindow) {
((MWindow) eParent).getWindows().remove(
container);
}
}
} else if (container.getChildren().size() == 1
&& container instanceof MPartSashContainer) {
// if a sash container has only one element then
// remove it and move
// its child up to where it used to be
MUIElement theChild = container.getChildren()
.get(0);
MElementContainer<MUIElement> parentContainer = container
.getParent();
if (parentContainer != null) {
ignoreChildrenChanges = true;
int index = parentContainer.getChildren()
.indexOf(container);
theChild.setContainerData(container
.getContainerData());
container.getChildren().remove(theChild);
parentContainer.getChildren().remove(container);
parentContainer.getChildren().add(index,
theChild);
container.setToBeRendered(false);
ignoreChildrenChanges = false;
}
}
}
});
}
}
};
private EventHandler renderingChangeHandler = new EventHandler() {
public void handleEvent(Event event) {
MUIElement changedObj = (MUIElement) event
.getProperty(UIEvents.EventTags.ELEMENT);
MElementContainer<MUIElement> container = null;
if (changedObj.getCurSharedRef() != null)
container = changedObj.getCurSharedRef().getParent();
else
container = changedObj.getParent();
// this can happen for shared parts that aren't attached to any
// placeholders
if (container == null) {
return;
}
// never hide top-level windows
MUIElement containerElement = container;
if (containerElement instanceof MWindow
&& containerElement.getParent() != null) {
return;
}
// These elements should neither be shown nor hidden based on their
// containment state
if (isLastEditorStack(containerElement)
|| containerElement instanceof MPerspective
|| containerElement instanceof MPerspectiveStack
|| containerElement instanceof MTrimBar)
return;
Boolean toBeRendered = (Boolean) event
.getProperty(UIEvents.EventTags.NEW_VALUE);
if (toBeRendered) {
// Bring the container back if one of its children goes visible
if (!container.isToBeRendered())
container.setToBeRendered(true);
} else {
// Never hide the container marked as no_close
if (container.getTags().contains(
IPresentationEngine.NO_AUTO_COLLAPSE)) {
return;
}
int visCount = modelService.countRenderableChildren(container);
// Remove stacks with no visible children from the display (but
// not the
// model)
final MElementContainer<MUIElement> theContainer = container;
if (visCount == 0) {
communicationManager.invokeLater(new Runnable() {
@Override
public void run() {
if (!isLastEditorStack(theContainer))
theContainer.setToBeRendered(false);
}
});
} else {
// if there are rendered elements but none are 'visible' we
// should
// make the container invisible as well
boolean makeInvisible = true;
// OK, we have rendered children, are they 'visible' ?
for (MUIElement kid : container.getChildren()) {
if (!kid.isToBeRendered())
continue;
if (kid.isVisible()) {
makeInvisible = false;
break;
}
}
if (makeInvisible) {
container.setVisible(false);
}
}
}
}
};
@PostConstruct
void init(IEclipseContext context) {
eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN,
childrenHandler);
eventBroker.subscribe(UIEvents.UIElement.TOPIC_TOBERENDERED,
renderingChangeHandler);
}
@PreDestroy
void removeListeners() {
eventBroker.unsubscribe(childrenHandler);
eventBroker.unsubscribe(renderingChangeHandler);
}
boolean isLastEditorStack(MUIElement element) {
return modelService.isLastEditorStack(element);
}
}