/***************************************************************************** * Copyright (c) 2010 CEA LIST. * * 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: * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation *****************************************************************************/ package org.eclipse.papyrus.views.properties.modelelement; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.papyrus.infra.tools.util.ClassLoaderHelper; import org.eclipse.papyrus.infra.widgets.Activator; import org.eclipse.papyrus.views.properties.contexts.Context; import org.eclipse.papyrus.views.properties.contexts.DataContextElement; import org.eclipse.papyrus.views.properties.contexts.DataContextRoot; import org.eclipse.papyrus.views.properties.contexts.View; import org.eclipse.papyrus.views.properties.environment.ModelElementFactoryDescriptor; import org.eclipse.papyrus.views.properties.util.PropertiesUtil; import org.eclipse.papyrus.views.properties.xwt.XWTSection; /** * A Factory to build and populate DataSource with the right ModelElements * * @author Camille Letavernier */ public class DataSourceFactory { /** * Singleton instance for DataSourceFactory */ public static DataSourceFactory instance = new DataSourceFactory(); /** * Creates a new DataSource from a selection and a view. * * @param selection * The selection of Objects * @param view * The view to display * @return The DataSource that can be passed to the DisplayEngine to display * the view */ public DataSource createDataSourceFromSelection(IStructuredSelection selection, View view) { SelectionEntry selectionEntry = new SelectionEntry(selection, view); if(!sources.containsKey(selectionEntry)) { DataSource source = new DataSource(view, selection); sources.put(selectionEntry, source); } return sources.get(selectionEntry); } public void removeFromCache(IStructuredSelection selection, View view) { if(selection == null || view == null) { return; } SelectionEntry entry = new SelectionEntry(selection, view); sources.remove(entry); } /** * Returns the ModelElement corresponding to the given propertyPath and * DataSource * * @param source * The DataSource used to retrieved informations such as the View * and the Selection * @param propertyPath * The path describing the property for which we want a * ModelElement * @return The matching modelElement */ public ModelElement getModelElementFromPropertyPath(DataSource source, String propertyPath) { String key = propertyPath.substring(0, propertyPath.lastIndexOf(":")); //$NON-NLS-1$ for(Context context : PropertiesUtil.getDependencies(source.getView().getContext())) { DataContextElement element = PropertiesUtil.getContextElementByQualifiedName(key, context.getDataContexts()); if(element != null) { ModelElement modelElement = DataSourceFactory.instance.createModelElement(element, source.getSelection()); if(modelElement != null) { modelElement.setDataSource(source); } return modelElement; } } return null; } /** * Creates a ModelElement from the given DataContextElement and Selection. * * @param contextElement * The contextElement for which we are creating a ModelElement * @param selection * The list of objects currently selected * @return The model element corresponding to the given contextElement and * selection */ private ModelElement createModelElement(DataContextElement contextElement, IStructuredSelection selection) { if(selection.size() == 1) { // Single Selection ModelElement modelElement = createFromSource(selection.getFirstElement(), contextElement); return modelElement; } else { // MultiSelection CompositeModelElement composite = new CompositeModelElement(); Iterator<?> it = selection.iterator(); while(it.hasNext()) { ModelElement element = createFromSource(it.next(), contextElement); if(element != null) { composite.addModelElement(element); } } return composite; } } /** * Retrieves the ModelElementFactory for the given DataContextElement. The * ModelElementFactory is declared by the DataContextRoot owning the given * DataContextElement * * @param context * The DataContextElement for which we want to retrieve the * ModelElementFactory * @return The ModelElementFactory corresponding to the given * DataContextElement */ private ModelElementFactory getFactory(DataContextElement context) { DataContextRoot rootPackage = getRootPackage(context); ModelElementFactoryDescriptor factoryDescriptor = rootPackage.getModelElementFactory(); if(factoryDescriptor == null) { Activator.log.warn("No ModelElementFactory is attached to DataContextElement " + getQualifiedName(context)); //$NON-NLS-1$ return null; } String factoryName = factoryDescriptor.getFactoryClass(); ModelElementFactory factory = ClassLoaderHelper.newInstance(factoryName, ModelElementFactory.class); return factory; } private ModelElement createFromSource(Object source, DataContextElement context) { ModelElementFactory factory = getFactory(context); if(factory == null) { return null; } return factory.createFromSource(source, context); } private DataContextRoot getRootPackage(DataContextElement context) { if(context.getPackage() == null) { return (DataContextRoot)context; } return getRootPackage(context.getPackage()); } private String getQualifiedName(DataContextElement context) { if(context.getPackage() == null) { return context.getName(); } return getQualifiedName(context.getPackage()) + ":" + context.getName(); //$NON-NLS-1$ } /** * Singleton Constructor. */ private DataSourceFactory() { } private class SelectionEntry { private IStructuredSelection selection; private View view; public SelectionEntry(IStructuredSelection selection, View view) { if(selection == null) { throw new IllegalArgumentException("The selection must not be null"); } if(view == null) { throw new IllegalArgumentException("The view must not be null"); } this.selection = selection; this.view = view; } @Override public boolean equals(Object obj) { if(!(obj instanceof SelectionEntry)) { return false; } SelectionEntry other = (SelectionEntry)obj; return other.view.equals(view) && selection.equals(other.selection); } @Override public int hashCode() { return selection.hashCode() + view.hashCode(); } } /** * More than one {@link XWTSection} may share the same DataSource. * They all need to listen on the same source, so that they can correctly * refresh themselves. We maintain a cache for each Selection/View pair. * * The cache is cleaned when the sections are disposed. */ //TODO : More than one view can be displayed at the same time. The cache should only //rely on a selection ; not on a selection-view pair. //We may use a (ISelection, Context) key : the DataSource must be associated to a single context private Map<SelectionEntry, DataSource> sources = new HashMap<SelectionEntry, DataSource>(); }