/******************************************************************************* * Copyright 2012 Geoscience Australia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package au.gov.ga.earthsci.application; import java.util.ArrayList; import java.util.List; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.internal.contexts.EclipseContext; import org.eclipse.e4.ui.model.application.MApplication; import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor; 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.basic.MPart; import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow; import org.eclipse.e4.ui.model.internal.Position; import org.eclipse.e4.ui.model.internal.PositionInfo; import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.e4.ui.workbench.modeling.EPartService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Helper class which instantiates parts for any placeholders with the same * element id as the part. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class PartInstantiator { private final static Logger logger = LoggerFactory.getLogger(PartInstantiator.class); public static final String PARENT_ID = "parent"; //$NON-NLS-1$ public static final String POSITION_ID = "position"; //$NON-NLS-1$ public static final String VISIBLE_ID = "visible"; //$NON-NLS-1$ public static final String ONTOP_ID = "ontop"; //$NON-NLS-1$ public static void createParts(MApplication application, EModelService service, EPartService partService) { //Sometimes, when switching windows at startup, the active context //is null or doesn't have a window, and the part instantiation fails. //Ensure that a child context with a window is activated: IEclipseContext activeChild = application.getContext().getActiveChild(); if (activeChild == null || activeChild.get(MTrimmedWindow.class) == null) { boolean activated = false; if (application.getContext() instanceof EclipseContext) { for (IEclipseContext child : ((EclipseContext) application.getContext()).getChildren()) { MTrimmedWindow window = child.get(MTrimmedWindow.class); if (window != null) { child.activate(); activated = true; break; } } } if (!activated) { logger.error("Could not activate window for part instantiation"); //$NON-NLS-1$ return; } } List<MPart> ontops = new ArrayList<MPart>(); for (MPartDescriptor descriptor : application.getDescriptors()) { if (!(descriptor.getPersistedState().containsKey(VISIBLE_ID) && Boolean.toString(true).equalsIgnoreCase( descriptor.getPersistedState().get(VISIBLE_ID)))) { continue; } List<MPart> existingParts = service.findElements(application, descriptor.getElementId(), MPart.class, null); if (!existingParts.isEmpty()) { //part is already instantiated continue; } MPart part = partService.createPart(descriptor.getElementId()); if (part == null) { continue; } addPartToAppropriateContainer(part, descriptor, application, service); partService.activate(part); if (descriptor.getPersistedState().containsKey(ONTOP_ID) && Boolean.toString(true).equalsIgnoreCase(descriptor.getPersistedState().get(ONTOP_ID))) { ontops.add(part); } } //reactivate ontop parts to ensure they are on-top for (MPart ontop : ontops) { partService.activate(ontop); } } public static void addPartToAppropriateContainer(MPart part, MPartDescriptor descriptor, MApplication application, EModelService service) { //first try and find the container specified by the id in the "parent" persisted state MElementContainer<MUIElement> container = null; String parentId = descriptor.getPersistedState().get(PARENT_ID); if (parentId != null) { @SuppressWarnings("rawtypes") List<MElementContainer> containers = service.findElements(application, parentId, MElementContainer.class, null); if (!containers.isEmpty()) { @SuppressWarnings("unchecked") MElementContainer<MUIElement> uncheckedContainer = containers.get(0); container = uncheckedContainer; } } //next try and find a sibling, and use the sibling's container if (container == null) { List<MPart> siblings = service.findElements(application, descriptor.getElementId(), MPart.class, null); for (MPart sibling : siblings) { if (sibling == part) { continue; } container = sibling.getParent(); if (sibling.isToBeRendered()) { //prefer visible siblings break; } } } if (container != null) { String position = descriptor.getPersistedState().get(POSITION_ID); int index = getPositionIndex(position, container); if (index < 0 || index > container.getChildren().size()) { container.getChildren().add(part); } else { container.getChildren().add(index, part); } } } public static int getPositionIndex(String positionInList, MElementContainer<MUIElement> container) { if (positionInList == null || positionInList.trim().length() == 0) { return -1; } PositionInfo posInfo = PositionInfo.parse(positionInList); if (posInfo == null) { return -1; } switch (posInfo.getPosition()) { case FIRST: return 0; case INDEX: return posInfo.getPositionReferenceAsInteger(); case BEFORE: case AFTER: String elementId = posInfo.getPositionReference(); List<MUIElement> siblings = container.getChildren(); for (int i = 0; i < siblings.size(); i++) { MUIElement sibling = siblings.get(i); if (elementId.equals(sibling.getElementId())) { return posInfo.getPosition() == Position.BEFORE ? i : i + 1; } } case LAST: default: return -1; } } }