/******************************************************************************* * 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.part; import java.util.List; import javax.inject.Inject; import org.eclipse.e4.core.contexts.IEclipseContext; 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.MPerspective; import org.eclipse.e4.ui.model.application.ui.basic.MBasicFactory; 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.impl.PartImpl; import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.jface.window.IShellProvider; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.riena.e4.launcher.Activator; import org.eclipse.riena.e4.launcher.E4XMIConstants; import org.eclipse.riena.navigation.ISubApplicationNode; import org.eclipse.riena.navigation.ISubModuleNode; import org.eclipse.riena.navigation.model.SubModuleNode; import org.eclipse.riena.navigation.ui.swt.presentation.SwtViewId; import org.eclipse.riena.navigation.ui.swt.presentation.SwtViewProvider; import org.eclipse.riena.navigation.ui.swt.views.SubModuleView; import org.eclipse.riena.ui.workarea.WorkareaManager; /** * Utility class for the connection of {@link PartImpl} to {@link SubModuleNode}s */ @SuppressWarnings("restriction") public class RienaPartHelper { public static final String COMPOUND_ID_DELIMITER = ":"; //$NON-NLS-1$ public static final String COUNTER_DELIMITER = "#"; //$NON-NLS-1$ private static final String KEY_E4_PART_ID = "E4PartId"; //$NON-NLS-1$ @Inject private IEclipseContext context; @Inject private EModelService modelService; private static int secondaryIdCounter = 0; public void showPart(final ISubModuleNode source) { final String partId = (String) source.getContext(KEY_E4_PART_ID); MPart partToActivate = null; if (null == partId) { // not registered yet --> create new part partToActivate = createPart(source); } else { // search for part partToActivate = findPart(source); /** handle shared views **/ final Object viewInstance = partToActivate.getTransientData().get(PartWrapper.VIEW_KEY); if (viewInstance instanceof SubModuleView) { ((SubModuleView) viewInstance).setNavigationNode(source); ((SubModuleView) viewInstance).prepareNode(source); } } if (partToActivate == null) { throw new IllegalStateException("Part not found, partId: " + partId); //$NON-NLS-1$ } partToActivate.getParent().setSelectedElement(partToActivate); } private MPart findPart(final ISubModuleNode node) { final String partId = (String) node.getContext(KEY_E4_PART_ID); if (null == partId) { return null; } final List<MPart> parts = modelService.findElements(context.get(MApplication.class), partId, MPart.class, null, EModelService.IN_ANY_PERSPECTIVE); return parts.get(0); } private MPart createPart(final ISubModuleNode source) { final ISubApplicationNode subApplicationNode = source.getParentOfType(ISubApplicationNode.class); final MElementContainer parent = findStackPart(subApplicationNode); // everything ok until here. Now create part instance final MPart partToActivate = MBasicFactory.INSTANCE.createPart(); final String partId = createPartId(source); partToActivate.setElementId(partId); source.setContext(KEY_E4_PART_ID, partId); // construct the String as in Application.e4xmi final String pluginId = Activator.getDefault().getBundleContext().getBundle().getSymbolicName(); partToActivate.setContributionURI("bundleclass://" + pluginId + "/" + PartWrapper.class.getName()); //$NON-NLS-1$ //$NON-NLS-2$ // set parent and add as child parent.getChildren().add(partToActivate); partToActivate.setParent(parent); return partToActivate; } /** * Returns the stack part of the Riena working area for the given sub-application. * * @param subApplicationNode * node of the sub-application * @return stack part */ private MPartStack findStackPart(final ISubApplicationNode subApplicationNode) { final String perspectiveId = SwtViewProvider.getInstance().getSwtViewId(subApplicationNode).getId(); // find perspective to add part to final List<MPerspective> perspectives = modelService.findElements(context.get(MApplication.class), perspectiveId, MPerspective.class, null); if (perspectives.isEmpty()) { // nothing found throw new IllegalStateException("Parent perspective not found. perspectiveId: " + perspectiveId); //$NON-NLS-1$ } // find stack to add part to final MPerspective subApplicationPerspective = perspectives.get(0); final List<MPartStack> stacks = modelService.findElements(subApplicationPerspective, E4XMIConstants.CONTENT_PART_STACK_ID, MPartStack.class, null); if (stacks.isEmpty()) { // nothing found throw new IllegalStateException("Part stack not found on parent perspective. perspectiveId: " + perspectiveId); //$NON-NLS-1$ } // we only use one stack per perspective final MPartStack parent = stacks.get(0); return parent; } private String createPartId(final ISubModuleNode node) { final String basicId = SwtViewProvider.getInstance().getSwtViewId(node).getCompoundId(); final String fqId = basicId + COUNTER_DELIMITER + increasePartCounter(); // TODO rename fqId ? return fqId; } private String increasePartCounter() { return String.valueOf(secondaryIdCounter++); } public void disposeNode(final ISubModuleNode source) { final MPart part = findPart(source); if (part != null) { final SwtViewId swtViewId = extractRienaCompoundId(part); final Composite widget = (Composite) part.getWidget(); unregisterPart(part); final int remainingCount = ViewInstanceProvider.getInstance().decreaseViewCounter(swtViewId); // honor reference counter (important for shared views) if (remainingCount == 0) { // kill zombie widget widget.dispose(); ViewInstanceProvider.getInstance().unregisterParentComposite(swtViewId); } } } /** * Unregisters the given {@link MPart} from the e4 application model */ private void unregisterPart(final MPart part) { part.setWidget(null); part.getParent().getChildren().remove(part); } public static SwtViewId extractRienaCompoundId(final MUIElement part) { final String[] split = part.getElementId().split(COUNTER_DELIMITER)[0].split(COMPOUND_ID_DELIMITER); return new SwtViewId(split[0], split.length > 1 ? split[1] : null); } /** * * @return true if the given {@link ISubModuleNode} related to a shared view */ public static boolean isSharedView(final ISubModuleNode source) { return WorkareaManager.getInstance().getDefinition(source).isViewShared(); } /** * * @return a new instance of {@link IShellProvider} for the give {@link Shell} */ public static IShellProvider toShellProvider(final Shell shell) { return new IShellProvider() { public Shell getShell() { return shell; } }; } }