blob: 71d7f2dbe68e0821a798a4cef31f199d2fa22c36 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 THALES GLOBAL SERVICES.
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.common.ui.tools.internal.interpreter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.sirius.common.tools.api.contentassist.ContentContext;
import org.eclipse.sirius.common.tools.api.contentassist.ContentInstanceContext;
import org.eclipse.sirius.common.tools.api.contentassist.ContentProposal;
import org.eclipse.sirius.common.tools.api.contentassist.IProposalProvider;
import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterContext;
import org.eclipse.sirius.common.tools.api.interpreter.TypeName;
import org.eclipse.sirius.common.tools.internal.interpreter.FeatureInterpreter;
import org.eclipse.sirius.common.ui.Messages;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* A {@link IProposalProvider} to provide completion for the feature
* interpreter.
*
* @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
*/
public class FeatureProposalProvider implements IProposalProvider {
private static final String SEPARATOR_1 = ":"; //$NON-NLS-1$
private static final String SEPARATOR_2 = " - "; //$NON-NLS-1$
private static final String SEPARATOR_3 = "[0..*]"; //$NON-NLS-1$
@Override
public ContentProposal getNewEmtpyExpression() {
return new ContentProposal(FeatureInterpreter.PREFIX, FeatureInterpreter.PREFIX, Messages.FeatureProposalProvider_newFeatureExpression, FeatureInterpreter.PREFIX.length());
}
@Override
public List<ContentProposal> getProposals(IInterpreter interpreter, ContentContext context) {
final List<ContentProposal> proposals;
if (context == null || !(interpreter instanceof FeatureInterpreter)) {
proposals = Collections.emptyList();
} else if (context.getContents() == null || context.getContents().length() == 0) {
proposals = Collections.singletonList(getNewEmtpyExpression());
} else {
Set<ContentProposal> intersectingProposals = null;
IInterpreterContext interpreterContext = context.getInterpreterContext();
for (TypeName type : interpreterContext.getTargetType().getPossibleTypes()) {
for (EClass possibleEClass : Iterables.filter(type.search(interpreterContext.getAvailableEPackages()), EClass.class)) {
Set<ContentProposal> proposalsForThisType = Sets.newLinkedHashSet(getProposals(context.getContents(), context.getPosition(), possibleEClass));
if (intersectingProposals == null) {
intersectingProposals = proposalsForThisType;
} else {
intersectingProposals = Sets.intersection(intersectingProposals, proposalsForThisType);
}
}
}
if (intersectingProposals != null) {
proposals = Lists.newArrayList(intersectingProposals);
} else {
proposals = Collections.<ContentProposal> emptyList();
}
}
return proposals;
}
@Override
public List<ContentProposal> getProposals(IInterpreter interpreter, ContentInstanceContext context) {
final List<ContentProposal> proposals;
if (context == null || !(interpreter instanceof FeatureInterpreter)) {
proposals = Collections.emptyList();
} else if (context.getCurrentSelected() == null) {
proposals = Collections.singletonList(getNewEmtpyExpression());
} else {
proposals = getProposals(context.getTextSoFar(), context.getCursorPosition(), context.getCurrentSelected().eClass());
}
return proposals;
}
/**
* Evaluates the content proposals for a given expression and returns the
* result as a list.
*
* @param writtenExpression
* The complete expression with feature: prefix.
* @param cursorPosition
* The current cursor position to consider only characters before
* it.
* @param currentElementType
* The current element type in the context.
* @return content proposal list.
*/
private List<ContentProposal> getProposals(String writtenExpression, int cursorPosition, EClass currentElementType) {
final List<ContentProposal> proposals = new ArrayList<ContentProposal>();
// Keep only characters before cursor
String featureNamePrefix = writtenExpression.substring(0, cursorPosition);
// Remove not needed space characters.
featureNamePrefix = featureNamePrefix.trim();
// Remove "feature:" prefix if the cursor position is after the prefix
// If the cursor position is before the prefix, there is no proposal
// returned.
if (featureNamePrefix.length() >= FeatureInterpreter.PREFIX.length()) {
featureNamePrefix = featureNamePrefix.trim().substring(FeatureInterpreter.PREFIX.length());
String eObjectName = EObject.class.getSimpleName();
String eContainerFeatureName = FeatureInterpreter.DEFAULT_FEATURE_NAMES[0];
if (eContainerFeatureName.startsWith(featureNamePrefix)) {
String displayedName = eContainerFeatureName + SEPARATOR_1 + eObjectName + SEPARATOR_2 + eObjectName;
proposals.add(new ContentProposal(eContainerFeatureName, displayedName, displayedName));
}
String eContentsFeatureName = FeatureInterpreter.DEFAULT_FEATURE_NAMES[1];
if (eContentsFeatureName.startsWith(featureNamePrefix)) {
String displayedName = eContentsFeatureName + SEPARATOR_1 + eObjectName + SEPARATOR_3 + SEPARATOR_2 + eObjectName;
proposals.add(new ContentProposal(eContentsFeatureName, displayedName, displayedName));
}
String eAllContentsFeatureName = FeatureInterpreter.DEFAULT_FEATURE_NAMES[2];
if (eAllContentsFeatureName.startsWith(featureNamePrefix)) {
String displayedName = eAllContentsFeatureName + SEPARATOR_1 + "TreeIterator" + SEPARATOR_2 + eObjectName; //$NON-NLS-1$
proposals.add(new ContentProposal(eAllContentsFeatureName, displayedName, displayedName));
}
String eClassFeatureName = FeatureInterpreter.DEFAULT_FEATURE_NAMES[3];
if (eClassFeatureName.startsWith(featureNamePrefix)) {
String displayedName = eClassFeatureName + SEPARATOR_1 + eObjectName + SEPARATOR_3 + SEPARATOR_2 + EClass.class.getSimpleName();
proposals.add(new ContentProposal(eClassFeatureName, displayedName, displayedName));
}
String eReferencesFeatureName = FeatureInterpreter.DEFAULT_FEATURE_NAMES[4];
if (eReferencesFeatureName.startsWith(featureNamePrefix)) {
String displayedName = eReferencesFeatureName + SEPARATOR_1 + eObjectName + SEPARATOR_3 + SEPARATOR_2 + eObjectName;
proposals.add(new ContentProposal(eReferencesFeatureName, displayedName, displayedName));
}
if (currentElementType != null) {
for (EStructuralFeature eStructuralFeature : currentElementType.getEAllStructuralFeatures()) {
if (eStructuralFeature.getName().startsWith(featureNamePrefix)) {
String displayedName = eStructuralFeature.getName()
+ (eStructuralFeature.isMany() ? "[" + eStructuralFeature.getLowerBound() + ".." //$NON-NLS-1$//$NON-NLS-2$
+ (eStructuralFeature.getUpperBound() == -1 ? "*" : eStructuralFeature.getUpperBound()) + "]" : "") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ (eStructuralFeature.getEType() != null ? SEPARATOR_1 + eStructuralFeature.getEType().getName() : "") + SEPARATOR_2 //$NON-NLS-1$
+ eStructuralFeature.getEContainingClass().getName();
proposals.add(new ContentProposal(eStructuralFeature.getName(), displayedName, displayedName));
}
}
}
}
return proposals;
}
}