/*******************************************************************************
* 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.navigation.ui.swt.presentation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.riena.core.singleton.SessionSingletonProvider;
import org.eclipse.riena.core.singleton.SingletonProvider;
import org.eclipse.riena.navigation.ApplicationModelFailure;
import org.eclipse.riena.navigation.IModuleGroupNode;
import org.eclipse.riena.navigation.IModuleNode;
import org.eclipse.riena.navigation.INavigationNode;
import org.eclipse.riena.navigation.ISubModuleNode;
import org.eclipse.riena.navigation.NavigationNodeId;
import org.eclipse.riena.navigation.ui.swt.views.SubModuleView;
import org.eclipse.riena.ui.workarea.IWorkareaDefinition;
import org.eclipse.riena.ui.workarea.WorkareaManager;
/**
* Manages the reference between the navigation nodes and the view id's
*/
public class SwtViewProvider {
private final Map<INavigationNode<?>, SwtViewId> views;
private final Map<String, Integer> viewCounter;
private final HashMap<String, Boolean> viewShared;
private INavigationNode<?> currentPrepared = null;
private static final SingletonProvider<SwtViewProvider> SVP = new SessionSingletonProvider<SwtViewProvider>(SwtViewProvider.class);
/**
* Gets the singleton SwtViewProvider.
*
* @return
* @since 1.2
*/
public static SwtViewProvider getInstance() {
return SVP.getInstance();
}
/**
* Create new instance and initialize
*/
protected SwtViewProvider() {
super();
viewCounter = new LinkedHashMap<String, Integer>();
views = new LinkedHashMap<INavigationNode<?>, SwtViewId>();
viewShared = new HashMap<String, Boolean>();
}
public SwtViewId getSwtViewId(final INavigationNode<?> node) {
SwtViewId swtViewId = views.get(node);
if (swtViewId == null) {
final ISubModuleNode submodule = node.getTypecastedAdapter(ISubModuleNode.class);
// submodules need special treatment as they may be shared
if (submodule != null && submodule.getNodeId() != null) {
swtViewId = createAndRegisterSwtViewId(submodule);
} else {
swtViewId = createAndRegisterSwtViewId(node);
}
}
boolean found = false;
for (final Entry<INavigationNode<?>, SwtViewId> entry : views.entrySet()) {
if (entry.getKey() == node) {
found = true;
}
}
Assert.isLegal(found, "Cannot register node " + node //$NON-NLS-1$
+ " because a different node with the same id is already registered."); //$NON-NLS-1$
return swtViewId;
}
public void unregisterSwtViewId(final INavigationNode<?> node) {
views.remove(node);
}
/**
* @since 3.0
*/
public void replaceNavigationNodeId(final INavigationNode<?> node, final NavigationNodeId oldId, final NavigationNodeId newId) {
node.setNodeId(oldId);
final SwtViewId swtViewId = views.remove(node);
if (swtViewId != null) {
node.setNodeId(newId);
views.put(node, swtViewId);
}
}
private SwtViewId createAndRegisterSwtViewId(final INavigationNode<?> node) {
final IWorkareaDefinition def = WorkareaManager.getInstance().getDefinition(node);
final String viewId = getViewId(node, def);
final SwtViewId swtViewId = new SwtViewId(viewId, getNextSecondaryId(viewId));
views.put(node, swtViewId);
return swtViewId;
}
private SwtViewId createAndRegisterSwtViewId(final ISubModuleNode submodule) {
final IWorkareaDefinition def = WorkareaManager.getInstance().getDefinition(submodule);
final String viewId = getViewId(submodule, def);
if (viewShared.get(viewId) != null) {
if (def.isViewShared() != viewShared.get(viewId)) {
throw new ApplicationModelFailure(
"Inconsistent view usage. The view with the id \"" //$NON-NLS-1$
+ viewId
+ "\" is already used with a different 'shared' state. A view must be defined in all workarea definitions as either shared or not shared."); //$NON-NLS-1$
}
} else {
viewShared.put(viewId, def.isViewShared());
}
SwtViewId swtViewId = null;
if (def.isViewShared()) {
if (views.get(submodule) == null) {
viewCounter.put(viewId, 0);
}
if (viewCounter.get(viewId) == 0) {
String secondary = SubModuleView.SHARED_ID;
// if the shared view should be a Group/Module Shared View, then a secondary
// id must be set to the parent IModuleGroupNode/IModuleNode,
// otherwise the secondary id remains "shared" and the view is globally shared
boolean found = false;
// first try the module parent
final IModuleNode module = submodule.getParentOfType(IModuleNode.class);
if (module != null && module.getContext(ISubModuleNode.SHARED_VIEWS_CONTEXT_KEY) instanceof String) {
secondary = secondary + "."; //$NON-NLS-1$
secondary = secondary + (String) module.getContext(ISubModuleNode.SHARED_VIEWS_CONTEXT_KEY);
found = true;
}
if (!found) {
// try the group parent
final IModuleGroupNode group = submodule.getParentOfType(IModuleGroupNode.class);
if (group != null && group.getContext(ISubModuleNode.SHARED_VIEWS_CONTEXT_KEY) instanceof String) {
secondary = secondary + "."; //$NON-NLS-1$
secondary = secondary + (String) group.getContext(ISubModuleNode.SHARED_VIEWS_CONTEXT_KEY);
}
}
// first node with this view
swtViewId = new SwtViewId(viewId, secondary);
views.put(submodule, swtViewId);
viewCounter.put(viewId, 1);
} else {
// view has been referenced already
swtViewId = views.get(getNavigationNode(viewId, null, ISubModuleNode.class, true));
views.put(submodule, swtViewId);
}
} else {
swtViewId = new SwtViewId(viewId, getNextSecondaryId(viewId));
views.put(submodule, swtViewId);
}
return swtViewId;
}
private String getViewId(final INavigationNode<?> node, final IWorkareaDefinition def) {
if (def == null) {
throw new ApplicationModelFailure("no work area definition for node " + node.getNodeId()); //$NON-NLS-1$
}
final Object viewId = def.getViewId();
if (viewId == null) {
throw new ApplicationModelFailure("viewId is null for nodeId " + node.getNodeId()); //$NON-NLS-1$
}
if (!(viewId instanceof String)) {
throw new ApplicationModelFailure("viewId is not a String for nodeId " + node.getNodeId()); //$NON-NLS-1$
}
return (String) viewId;
}
private String getNextSecondaryId(final String pViewId) {
if (viewCounter.get(pViewId) == null) {
viewCounter.put(pViewId, 0);
}
viewCounter.put(pViewId, viewCounter.get(pViewId) + 1);
return String.valueOf(viewCounter.get(pViewId));
}
private boolean isViewShared(final String viewId) {
final Boolean result = this.viewShared.get(viewId);
return result == null ? false : result;
}
public <N extends INavigationNode<?>> N getNavigationNode(final String pId, final Class<N> pClass) {
return getNavigationNode(pId, null, pClass);
}
public <N extends INavigationNode<?>> N getNavigationNode(final String pId, final String secondary, final Class<N> pClass) {
return getNavigationNode(pId, secondary, pClass, false);
}
@SuppressWarnings("unchecked")
public <N extends INavigationNode<?>> N getNavigationNode(final String pId, final String secondary, final Class<N> pClass, final boolean ignoreSharedState) {
for (final Entry<INavigationNode<?>, SwtViewId> entry : views.entrySet()) {
if (entry.getValue() == null) {
continue;
}
if (entry.getValue().getId().equals(pId) && //
(secondary == null || secondary.equals(entry.getValue().getSecondary()))) {
if (ignoreSharedState || !isViewShared(pId) || entry.getKey().isActivated()) {
return entry.getKey().getTypecastedAdapter(pClass);
} else if (isViewShared(pId)) {
if (entry.getKey().getTypecastedAdapter(pClass).equals(currentPrepared)) {
return (N) currentPrepared;
}
}
}
}
return null;
}
/**
* Locates all {@link INavigationNode} instances in the application navigation model which reference the given {@link SwtViewId}. Disposed nodes are not
* considered.
*
* @param id
* the {@link SwtViewId}
* @return a list of {@link INavigationNode}s as "users" of the given {@link SwtViewId}
* @since 3.0
*/
public List<INavigationNode<?>> getViewUsers(final SwtViewId id) {
final List<INavigationNode<?>> result = new ArrayList<INavigationNode<?>>();
final Set<INavigationNode<?>> nodes = views.keySet();
for (final INavigationNode<?> regNode : nodes) {
final SwtViewId swtViewId = views.get(regNode);
if (!regNode.isDisposed() && swtViewId != null && swtViewId.getCompoundId().equals(id.getCompoundId())) {
result.add(regNode);
}
}
return result;
}
/**
* @since 3.0
*/
public void setCurrentPrepared(final INavigationNode<?> node) {
this.currentPrepared = node;
}
/**
* @since 3.0
*/
public INavigationNode<?> getCurrentPrepared() {
return currentPrepared;
}
private final Map<SwtViewId, SubModuleView> registerdViewInstances = new HashMap<SwtViewId, SubModuleView>();
/**
* Registers the given view as being created
*
* @param id
* the id of the view
* @param subModuleView
* the {@link SubModuleView} instance
* @since 6.0
*/
public void registerView(final String id, final String secondaryId, final SubModuleView subModuleView) {
registerdViewInstances.put(new SwtViewId(id, secondaryId), subModuleView);
}
/**
* Returns the {@link SubModuleView} associated with the given id
*
* @param secondary
*
* @since 6.0
*/
public SubModuleView getRegisteredView(final String id, final String secondaryId) {
return registerdViewInstances.get(new SwtViewId(id, secondaryId));
}
/**
* Unregisters the {@link SubModuleView} associated with the given id
*
* @since 6.0
*/
public void unregisterView(final String id, final String secondaryId) {
registerdViewInstances.remove(new SwtViewId(id, secondaryId));
}
}