/*******************************************************************************
* 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 org.eclipse.e4.ui.model.application.MContribution;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.basic.impl.PartImpl;
import org.eclipse.e4.ui.workbench.renderers.swt.ContributedPartRenderer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.riena.core.util.ReflectionUtils;
import org.eclipse.riena.e4.launcher.part.NavigationPart;
import org.eclipse.riena.e4.launcher.part.PartWrapper;
import org.eclipse.riena.e4.launcher.part.RienaPartHelper;
import org.eclipse.riena.e4.launcher.part.ViewInstanceProvider;
import org.eclipse.riena.navigation.ISubModuleNode;
import org.eclipse.riena.navigation.listener.SubModuleNodeListener;
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;
/**
* Riena specific {@link ContributedPartRenderer} honoring shared views. Shared views work by definition of a 1-n relationship between a {@link SubModuleView}
* and {@link SubModuleNode}s. Every {@link SubModuleNode} is associated to one {@link PartImpl}. Multiple {@link PartImpl}s share one {@link SubModuleView}.
*/
@SuppressWarnings("restriction")
public final class RienaPartRenderer extends ContributedPartRenderer {
@Override
public Object createWidget(final MUIElement element, final Object parent) {
final SwtViewId swtViewId = RienaPartHelper.extractRienaCompoundId(element);
// is node part?
if (isSubModuleNodePart(swtViewId)) {
Composite parentComposite = null;
final String typeId = swtViewId.getId();
final String secondayId = swtViewId.getSecondary();
final ISubModuleNode node = SwtViewProvider.getInstance().getNavigationNode(typeId, secondayId, ISubModuleNode.class);
// if the node belongs to a shared view try to lookup the view
if (RienaPartHelper.isSharedView(node)) {
parentComposite = ViewInstanceProvider.getInstance().getParentComposite(swtViewId);
if (null != parentComposite) {
// shared view found
if (null == element.getWidget()) {
// register the widget at the current element. This happens only one time for each part.
element.setWidget(parentComposite);
ViewInstanceProvider.getInstance().increaseViewCounter(swtViewId);
}
}
}
// nothing found in cache
if (null == parentComposite) {
// create new view
parentComposite = (Composite) super.createWidget(element, parent);
// initialize and build view
initializeView(swtViewId, parentComposite, node);
} else {
// Cached view found! update node in view
updateViewNode(swtViewId, node);
}
// observe nodes related to shared views
if (RienaPartHelper.isSharedView(node)) {
node.addListener(new SharedViewNodeBinder(swtViewId));
}
return parentComposite;
}
// not related to a SubModuleNode. Nothing special here. Just create composite
return super.createWidget(element, parent);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.e4.ui.workbench.renderers.swt.SWTPartRenderer#forceFocus(org.eclipse.e4.ui.model.application.ui.MUIElement)
*/
@Override
public void forceFocus(final MUIElement element) {
if (element instanceof MContribution) {
final Object object = ((MContribution) element).getObject();
if (object instanceof PartWrapper) {
((PartWrapper) object).getView().setFocus();
return;
}
if (object instanceof NavigationPart) {
((NavigationPart) object).getView().setFocus();
return;
}
}
super.forceFocus(element);
}
private boolean isSubModuleNodePart(final SwtViewId rienaCompoundId) {
return rienaCompoundId.getSecondary() != null;
}
/**
* Updates the {@link ISubModuleNode} in the {@link SubModuleView}
*/
private void updateViewNode(final SwtViewId swtViewId, final ISubModuleNode node) {
final SubModuleView viewInstance = ViewInstanceProvider.getInstance().getView(swtViewId);
viewInstance.setNavigationNode(node);
}
/**
* Initializes and builds the related {@link SubModuleView}. This involves calling {@link SubModuleView#createPartControl(Composite)}
*
*/
private void initializeView(final SwtViewId swtViewId, final Composite parentComposite, final ISubModuleNode node) {
final ViewInstanceProvider viewInstanceProvider = ViewInstanceProvider.getInstance();
final SubModuleView viewInstance = viewInstanceProvider.getView(swtViewId);
viewInstance.setE4Runtime(true);
viewInstanceProvider.registerParentComposite(swtViewId, parentComposite);
updateViewNode(swtViewId, node);
ReflectionUtils.invokeHidden(viewInstance, "setShellProvider", RienaPartHelper.toShellProvider(parentComposite.getShell())); //$NON-NLS-1$
viewInstance.createPartControl(parentComposite);
}
/**
* After activation of a {@link SubModuleNode} this listener binds the corresponding shared view to the node
*/
private final class SharedViewNodeBinder extends SubModuleNodeListener {
private final SwtViewId swtViewId;
private SharedViewNodeBinder(final SwtViewId swtViewId) {
this.swtViewId = swtViewId;
}
@Override
public void activated(final ISubModuleNode source) {
final SubModuleView viewInstance = ViewInstanceProvider.getInstance().getView(swtViewId);
viewInstance.setNavigationNode(source);
viewInstance.bind(source);
}
}
}