/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.java.jdt.codeassistant;
import org.eclipse.che.ide.api.text.BadLocationException;
import org.eclipse.che.ide.api.text.Region;
import org.eclipse.che.ide.api.text.RegionImpl;
import org.eclipse.che.ide.collections.Jso;
import org.eclipse.che.ide.collections.JsonObject;
import org.eclipse.che.ide.collections.js.JsoArray;
import org.eclipse.che.ide.ext.java.jdt.core.CompletionProposal;
import org.eclipse.che.ide.ext.java.jdt.core.Signature;
import org.eclipse.che.ide.ext.java.jdt.core.util.CharUtil;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.che.ide.ext.java.jdt.text.Document;
import org.eclipse.che.ide.ext.java.worker.WorkerTypeInfoStorage;
import org.eclipse.che.ide.ext.java.worker.env.BinaryType;
import org.eclipse.che.ide.ext.java.worker.env.json.BinaryTypeJso;
/**
* Proposal for generic types.
* <p>
* Only used when compliance is set to 5.0 or higher.
* </p>
*/
public final class LazyGenericTypeProposal extends LazyJavaTypeCompletionProposal {
/** Triggers for types. Do not modify. */
private final static char[] GENERIC_TYPE_TRIGGERS = new char[]{'.', '\t', '[', '(', '<', ' '};
// /**
// * Short-lived context information object for generic types. Currently, these are only created after inserting a type proposal,
// * as core doesn't give us the correct type proposal from within SomeType<|>.
// */
// private static class ContextInformation implements org.eclipse.che.ide.editor.api.contentassist.ContextInformation
// {
// private final String fInformationDisplayString;
//
// private final String fContextDisplayString;
//
// private final Image fImage;
//
// private final int fPosition;
//
// ContextInformation(LazyGenericTypeProposal proposal)
// {
// // don't cache the proposal as content assistant
// // might hang on to the context info
// fContextDisplayString = proposal.getDisplayString();
// fInformationDisplayString = computeContextString(proposal);
// fImage = proposal.getImage();
// fPosition = proposal.getReplacementOffset() + proposal.getReplacementString().indexOf('<') + 1;
// }
//
// /*
// * @see org.eclipse.jface.text.contentassist.IContextInformation#getContextDisplayString()
// */
// public String getContextDisplayString()
// {
// return fContextDisplayString;
// }
//
// /*
// * @see org.eclipse.jface.text.contentassist.IContextInformation#getImage()
// */
// public Image getImage()
// {
// return fImage;
// }
//
// /*
// * @see org.eclipse.jface.text.contentassist.IContextInformation#getInformationDisplayString()
// */
// public String getInformationDisplayString()
// {
// return fInformationDisplayString;
// }
//
// private String computeContextString(LazyGenericTypeProposal proposal)
// {
// TypeArgumentProposal[] proposals = new TypeArgumentProposal[0];// proposal.computeTypeArgumentProposals();
// if (proposals.length == 0)
// return null;
//
// StringBuffer buf = new StringBuffer();
// for (int i = 0; i < proposals.length; i++)
// {
// buf.append(proposals[i].getDisplayName());
// if (i < proposals.length - 1)
// buf.append(", "); //$NON-NLS-1$
// }
// return buf.toString();
// }
//
// /*
// * @see org.eclipse.jface.text.contentassist.IContextInformationExtension#getContextInformationPosition()
// */
// public int getContextInformationPosition()
// {
// return fPosition;
// }
//
// /*
// * @see java.lang.Object#equals(java.lang.Object)
// */
// @Override
// public boolean equals(Object obj)
// {
// if (obj instanceof ContextInformation)
// {
// ContextInformation ci = (ContextInformation)obj;
// return getContextInformationPosition() == ci.getContextInformationPosition()
// && getInformationDisplayString().equals(ci.getInformationDisplayString());
// }
// return false;
// }
//
// /*
// * @see java.lang.Object#hashCode()
// * @since 3.1
// */
// @Override
// public int hashCode()
// {
// int low = fContextDisplayString != null ? fContextDisplayString.hashCode() : 0;
// return fPosition << 24 | fInformationDisplayString.hashCode() << 16 | low;
// }
//
// }
private Region fSelectedRegion; // initialized by apply()
private TypeArgumentProposal[] fTypeArgumentProposals;
private boolean fCanUseDiamond;
public LazyGenericTypeProposal(CompletionProposal typeProposal, JavaContentAssistInvocationContext context) {
super(typeProposal, context);
}
/*
* @see ICompletionProposalExtension#apply(IDocument, char)
*/
@Override
public void apply(Document document, char trigger, int offset) {
boolean onlyAppendArguments;
try {
onlyAppendArguments =
fProposal.getCompletion().length == 0 && offset > 0 && document.getChar(offset - 1) == '<';
} catch (BadLocationException e) {
onlyAppendArguments = false;
}
if (onlyAppendArguments || shouldAppendArguments(document, offset, trigger)) {
TypeArgumentProposal[] typeArgumentProposals = computeTypeArgumentProposals();
if (typeArgumentProposals.length > 0) {
int[] offsets = new int[typeArgumentProposals.length];
int[] lengths = new int[typeArgumentProposals.length];
StringBuffer buffer;
if (canUseDiamond()) {
buffer = new StringBuffer(getReplacementString());
buffer.append("<>"); //$NON-NLS-1$
} else {
buffer = createParameterList(typeArgumentProposals, offsets, lengths, onlyAppendArguments);
}
// set the generic type as replacement string
boolean insertClosingParenthesis = trigger == '(' && autocloseBrackets();
if (insertClosingParenthesis) {
updateReplacementWithParentheses(buffer);
}
super.setReplacementString(buffer.toString());
// add import & remove package, update replacement offset
super.apply(document, '\0', offset);
// if (hasAmbiguousProposals(typeArgumentProposals))
// {
// adaptOffsets(offsets, buffer);
// // installLinkedMode(document, offsets, lengths, typeArgumentProposals, insertClosingParenthesis);
// }
// else
// {
// if (insertClosingParenthesis)
// setUpLinkedMode(document, ')');
// else
// fSelectedRegion = new Region(getReplacementOffset() + getReplacementString().length(), 0);
// }
return;
}
}
// default is to use the super implementation
// reasons:
// - not a parameterized type,
// - already followed by <type arguments>
// - proposal type does not inherit from expected type
super.apply(document, trigger, offset);
}
/*
* @see org.eclipse.jdt.internal.ui.text.java.LazyJavaTypeCompletionProposal#computeTriggerCharacters()
*/
@Override
protected char[] computeTriggerCharacters() {
return GENERIC_TYPE_TRIGGERS;
}
/**
* Computes the type argument proposals for this type proposals. If there is an expected type binding that is a super type of
* the proposed type, the wildcard type arguments of the proposed type that can be mapped through to type the arguments of the
* expected type binding are bound accordingly.
* <p>
* For type arguments that cannot be mapped to arguments in the expected type, or if there is no expected type, the upper bound
* of the type argument is proposed.
* </p>
* <p>
* The argument proposals have their <code>isAmbiguos</code> flag set to <code>false</code> if the argument can be mapped to a
* non-wildcard type argument in the expected type, otherwise the proposal is ambiguous.
* </p>
*
* @return the type argument proposals for the proposed type
* @throws JavaModelException
* if accessing the java model fails
*/
private TypeArgumentProposal[] computeTypeArgumentProposals() {
if (fTypeArgumentProposals == null) {
// IType type = (IType)getJavaElement();
// if (type == null)
// return new TypeArgumentProposal[0];
//
// ITypeParameter[] parameters = type.getTypeParameters();
String signature = getTypeGenerycSignature(new String(Signature.toCharArray(fProposal.getSignature())));
if (signature == null) {
return new TypeArgumentProposal[0];
}
signature = signature.replaceAll("/", ".");
String[] parameters = Signature.getTypeParameters(signature);
if (parameters.length == 0) {
return new TypeArgumentProposal[0];
}
TypeArgumentProposal[] arguments = new TypeArgumentProposal[parameters.length];
// TODO use getExpectedType() method to add types names
// ITypeBinding expectedTypeBinding = getExpectedType();
// if (expectedTypeBinding != null && expectedTypeBinding.isParameterizedType())
// {
// // in this case, the type arguments we propose need to be compatible
// // with the corresponding type parameters to declared type
//
// IType expectedType = (IType)expectedTypeBinding.getJavaElement();
//
// IType[] path = computeInheritancePath(type, expectedType);
// if (path == null)
// // proposed type does not inherit from expected type
// // the user might be looking for an inner type of proposed type
// // to instantiate -> do not add any type arguments
// return new TypeArgumentProposal[0];
//
// int[] indices = new int[parameters.length];
// for (int paramIdx = 0; paramIdx < parameters.length; paramIdx++)
// {
// indices[paramIdx] = mapTypeParameterIndex(path, path.length - 1, paramIdx);
// }
//
// // for type arguments that are mapped through to the expected type's
// // parameters, take the arguments of the expected type
// ITypeBinding[] typeArguments = expectedTypeBinding.getTypeArguments();
// for (int paramIdx = 0; paramIdx < parameters.length; paramIdx++)
// {
// if (indices[paramIdx] != -1)
// {
// // type argument is mapped through
// ITypeBinding binding = typeArguments[indices[paramIdx]];
// arguments[paramIdx] = computeTypeProposal(binding, parameters[paramIdx]);
// }
// }
// }
//
// for type arguments that are not mapped through to the expected type,
// take the lower bound of the type parameter
for (int i = 0; i < arguments.length; i++) {
if (arguments[i] == null) {
arguments[i] = computeTypeProposal(parameters[i]);
}
}
fTypeArgumentProposals = arguments;
}
return fTypeArgumentProposals;
}
// /**
// * Adapt the parameter offsets to any modification of the replacement string done by <code>apply</code>. For example, applying
// * the proposal may add an import instead of inserting the fully qualified name.
// * <p>
// * This assumes that modifications happen only at the beginning of the replacement string and do not touch the type arguments
// * list.
// * </p>
// *
// * @param offsets the offsets to modify
// * @param buffer the original replacement string
// */
// private void adaptOffsets(int[] offsets, StringBuffer buffer)
// {
// String replacementString = getReplacementString();
// int delta = buffer.length() - replacementString.length(); // due to using an import instead of package
// for (int i = 0; i < offsets.length; i++)
// {
// offsets[i] -= delta;
// }
// }
private String getTypeGenerycSignature(String fqn) {
IBinaryType type = WorkerTypeInfoStorage.get().getType(fqn);
if (type == null) {
String shortTypesInfo = WorkerTypeInfoStorage.get().getShortTypesInfo();
if (shortTypesInfo == null) {
return null;
}
Jso jso = Jso.deserialize(shortTypesInfo);
if (jso.hasOwnProperty("types")) {
JsoArray<JsonObject> array = jso.getArrayField("types");
for (int i = 0; i < array.size(); i++) {
Jso obj = (Jso)array.get(i);
if (fqn.equals(obj.getStringField("name"))) {
type = new BinaryType(obj.<BinaryTypeJso>cast());
break;
}
}
}
}
if (type != null && type.getGenericSignature() != null) {
return String.valueOf(type.getGenericSignature());
}
// if (object != null && object.containsKey("signature") && object.get("signature").isNull() == null) {
// String value = object.get("signature").isString().stringValue();
// return value.isEmpty() ? null : value;
// }
return null;
}
// /**
// * Returns a type argument proposal for a given type parameter. The proposal is:
// * <ul>
// * <li>the type bound for type parameters with a single bound</li>
// * <li>the type parameter name for all other (unbounded or more than one bound) type parameters</li>
// * </ul>
// * Type argument proposals for type parameters are always ambiguous.
// *
// * @param parameter the type parameter of the inserted type
// * @return a type argument proposal for <code>parameter</code>
// * @throws JavaModelException if this element does not exist or if an exception occurs while accessing its corresponding
// * resource
// */
private TypeArgumentProposal computeTypeProposal(String parameter) {
String[] bounds = Signature.getTypeParameterBounds(parameter);
String elementName = Signature.getTypeVariable(parameter);
String displayName = computeTypeParameterDisplayName(parameter, bounds);
if (bounds.length == 1 && !"java.lang.Object".equals(Signature.toString(bounds[0]))) {
return new TypeArgumentProposal(Signature.getSignatureSimpleName(bounds[0]), true, displayName);
} else {
return new TypeArgumentProposal(elementName, true, displayName);
}
}
private String computeTypeParameterDisplayName(String parameter, String[] bounds) {
if (bounds.length == 0 || bounds.length == 1 && "java.lang.Object".equals(Signature.toString(bounds[0]))) {
return parameter;
}
StringBuffer buf = new StringBuffer(parameter);
buf.append(" extends "); //$NON-NLS-1$
for (int i = 0; i < bounds.length; i++) {
buf.append(Signature.getSimpleName(bounds[i]));
if (i < bounds.length - 1) {
buf.append(" & "); //$NON-NLS-1$
}
}
return buf.toString();
}
/**
* Returns <code>true</code> if type arguments should be appended when applying this proposal, <code>false</code> if not (for
* example if the document already contains a type argument list after the insertion point.
*
* @param document
* the document
* @param offset
* the insertion offset
* @param trigger
* the trigger character
* @return <code>true</code> if arguments should be appended
*/
private boolean shouldAppendArguments(Document document, int offset, char trigger) {
/*
* No argument list if there were any special triggers (for example a period to qualify an inner type).
*/
if (trigger != '\0' && trigger != '<' && trigger != '(') {
return false;
}
/* No argument list if the completion is empty (already within the argument list). */
char[] completion = fProposal.getCompletion();
if (completion.length == 0) {
return false;
}
/* No argument list if there already is a generic signature behind the name. */
try {
Region region = document.getLineInformationOfOffset(offset);
String line = document.get(region.getOffset(), region.getLength());
int index = offset - region.getOffset();
while (index != line.length() && CharUtil.isJavaIdentifierPart(line.charAt(index))) {
++index;
}
if (index == line.length()) {
return true;
}
char ch = line.charAt(index);
return ch != '<';
} catch (BadLocationException e) {
return true;
}
}
// /**
// * Returns a type argument proposal for a given type binding. The proposal is:
// * <ul>
// * <li>the simple type name for normal types or type variables (unambigous proposal)</li>
// * <li>for wildcard types (ambigous proposals):
// * <ul>
// * <li>the upper bound for wildcards with an upper bound</li>
// * <li>the {@linkplain #computeTypeProposal(ITypeParameter) parameter proposal} for unbounded wildcards or wildcards with a
// * lower bound</li>
// * </ul>
// * </li>
// * </ul>
// *
// * @param binding the type argument binding in the expected type
// * @param parameter the type parameter of the inserted type
// * @return a type argument proposal for <code>binding</code>
// * @throws JavaModelException if this element does not exist or if an exception occurs while accessing its corresponding
// * resource
// * @see #computeTypeProposal(ITypeParameter)
// */
// private TypeArgumentProposal computeTypeProposal(ITypeBinding binding, ITypeParameter parameter)
// throws JavaModelException
// {
// final String name = Bindings.getTypeQualifiedName(binding);
// if (binding.isWildcardType())
// {
//
// if (binding.isUpperbound())
// {
// // replace the wildcard ? with the type parameter name to get "E extends Bound" instead of "? extends Bound"
// String contextName = name.replaceFirst("\\?", parameter.getElementName()); //$NON-NLS-1$
// // upper bound - the upper bound is the bound itself
// return new TypeArgumentProposal(binding.getBound().getName(), true, contextName);
// }
//
// // no or upper bound - use the type parameter of the inserted type, as it may be more
// // restrictive (eg. List<?> list= new SerializableList<Serializable>())
// return computeTypeProposal(parameter);
// }
//
// // not a wildcard but a type or type variable - this is unambigously the right thing to insert
// return new TypeArgumentProposal(name, false, name);
// }
// /**
// * Computes one inheritance path from <code>superType</code> to <code>subType</code> or <code>null</code> if
// * <code>subType</code> does not inherit from <code>superType</code>. Note that there may be more than one inheritance path -
// * this method simply returns one.
// * <p>
// * The returned array contains <code>superType</code> at its first index, and <code>subType</code> at its last index. If
// * <code>subType</code> equals <code>superType</code> , an array of length 1 is returned containing that type.
// * </p>
// *
// * @param subType the sub type
// * @param superType the super type
// * @return an inheritance path from <code>superType</code> to <code>subType</code>, or <code>null</code> if
// * <code>subType</code> does not inherit from <code>superType</code>
// * @throws JavaModelException if this element does not exist or if an exception occurs while accessing its corresponding
// * resource
// */
// private IType[] computeInheritancePath(IType subType, IType superType) throws JavaModelException
// {
// if (superType == null)
// return null;
//
// // optimization: avoid building the type hierarchy for the identity case
// if (superType.equals(subType))
// return new IType[]{subType};
//
// ITypeHierarchy hierarchy = subType.newSupertypeHierarchy(getProgressMonitor());
// if (!hierarchy.contains(superType))
// return null; // no path
//
// List<IType> path = new LinkedList<IType>();
// path.add(superType);
// do
// {
// // any sub type must be on a hierarchy chain from superType to subType
// superType = hierarchy.getSubtypes(superType)[0];
// path.add(superType);
// }
// while (!superType.equals(subType)); // since the equality case is handled above, we can spare one check
//
// return path.toArray(new IType[path.size()]);
// }
//
// private NullProgressMonitor getProgressMonitor()
// {
// return new NullProgressMonitor();
// }
// /**
// * For the type parameter at <code>paramIndex</code> in the type at <code>path[pathIndex]</code> , this method computes the
// * corresponding type parameter index in the type at <code>path[0]</code>. If the type parameter does not map to a type
// * parameter of the super type, <code>-1</code> is returned.
// *
// * @param path the type inheritance path, a non-empty array of consecutive sub types
// * @param pathIndex an index into <code>path</code> specifying the type to start with
// * @param paramIndex the index of the type parameter to map - <code>path[pathIndex]</code> must have a type parameter at that
// * index, lest an <code>ArrayIndexOutOfBoundsException</code> is thrown
// * @return the index of the type parameter in <code>path[0]</code> corresponding to the type parameter at
// * <code>paramIndex</code> in <code>path[pathIndex]</code>, or -1 if there is no corresponding type parameter
// * @throws JavaModelException if this element does not exist or if an exception occurs while accessing its corresponding
// * resource
// * @throws ArrayIndexOutOfBoundsException if <code>path[pathIndex]</code> has <= <code>paramIndex</code> parameters
// */
// private int mapTypeParameterIndex(IType[] path, int pathIndex, int paramIndex) throws JavaModelException,
// ArrayIndexOutOfBoundsException
// {
// if (pathIndex == 0)
// // break condition: we've reached the top of the hierarchy
// return paramIndex;
//
// IType subType = path[pathIndex];
// IType superType = path[pathIndex - 1];
//
// String superSignature = findMatchingSuperTypeSignature(subType, superType);
// ITypeParameter param = subType.getTypeParameters()[paramIndex];
// int index = findMatchingTypeArgumentIndex(superSignature, param.getElementName());
// if (index == -1)
// {
// // not mapped through
// return -1;
// }
//
// return mapTypeParameterIndex(path, pathIndex - 1, index);
// }
// /**
// * Finds and returns the super type signature in the <code>extends</code> or <code>implements</code> clause of
// * <code>subType</code> that corresponds to <code>superType</code>.
// *
// * @param subType a direct and true sub type of <code>superType</code>
// * @param superType a direct super type (super class or interface) of <code>subType</code>
// * @return the super type signature of <code>subType</code> referring to <code>superType</code>
// * @throws JavaModelException if extracting the super type signatures fails, or if <code>subType</code> contains no super
// type
// * signature to <code>superType</code>
// */
// private String findMatchingSuperTypeSignature(IType subType, IType superType) throws JavaModelException
// {
// String[] signatures = getSuperTypeSignatures(subType, superType);
// for (int i = 0; i < signatures.length; i++)
// {
// String signature = signatures[i];
// String qualified = SignatureUtil.qualifySignature(signature, subType);
// String subFQN = SignatureUtil.stripSignatureToFQN(qualified);
//
// String superFQN = superType.getFullyQualifiedName();
// if (subFQN.equals(superFQN))
// {
// return signature;
// }
//
// // TODO handle local types
// }
//
// throw new JavaModelException(new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK,
// "Illegal hierarchy", null))); //$NON-NLS-1$
// }
// /**
// * Finds and returns the index of the type argument named <code>argument</code> in the given super type signature.
// * <p>
// * If <code>signature</code> does not contain a corresponding type argument, or if <code>signature</code> has no type
// * parameters (i.e. is a reference to a non-parameterized type or a raw type), -1 is returned.
// * </p>
// *
// * @param signature the super type signature from a type's <code>extends</code> or <code>implements</code> clause
// * @param argument the name of the type argument to find
// * @return the index of the given type argument, or -1 if there is none
// */
// private int findMatchingTypeArgumentIndex(String signature, String argument)
// {
// String[] typeArguments = Signature.getTypeArguments(signature);
// for (int i = 0; i < typeArguments.length; i++)
// {
// if (Signature.getSignatureSimpleName(typeArguments[i]).equals(argument))
// return i;
// }
// return -1;
// }
// /**
// * Returns the super interface signatures of <code>subType</code> if <code>superType</code> is an interface, otherwise
// returns
// * the super type signature.
// *
// * @param subType the sub type signature
// * @param superType the super type signature
// * @return the super type signatures of <code>subType</code>
// * @throws JavaModelException if any java model operation fails
// */
// private String[] getSuperTypeSignatures(IType subType, IType superType) throws JavaModelException
// {
// if (superType.isInterface())
// return subType.getSuperInterfaceTypeSignatures();
// else
// return new String[]{subType.getSuperclassTypeSignature()};
// }
// /**
// * Returns the type binding of the expected type as it is contained in the code completion context.
// *
// * @return the binding of the expected type
// */
// private ITypeBinding getExpectedType()
// {
// char[][] chKeys = fInvocationContext.getCoreContext().getExpectedTypesKeys();
// if (chKeys == null || chKeys.length == 0)
// return null;
//
// String[] keys = new String[chKeys.length];
// for (int i = 0; i < keys.length; i++)
// {
// keys[i] = String.valueOf(chKeys[0]);
// }
//
// final ASTParser parser = ASTParser.newParser(AST.JLS3);
// // parser.setProject(fCompilationUnit.getJavaProject());
// parser.setResolveBindings(true);
// parser.setStatementsRecovery(true);
//
// final Map<String, IBinding> bindings = new HashMap<String, IBinding>();
// ASTRequestor requestor = new ASTRequestor()
// {
// @Override
// public void acceptBinding(String bindingKey, IBinding binding)
// {
// bindings.put(bindingKey, binding);
// }
// };
// parser.createASTs(new ICompilationUnit[0], keys, requestor, null);
//
// if (bindings.size() > 0)
// return (ITypeBinding)bindings.get(keys[0]);
//
// return null;
// }
private StringBuffer createParameterList(TypeArgumentProposal[] typeArguments, int[] offsets, int[] lengths,
boolean onlyAppendArguments) {
StringBuffer buffer = new StringBuffer();
buffer.append(getReplacementString());
FormatterPrefs prefs = getFormatterPrefs();
final char LESS = '<';
final char GREATER = '>';
if (!onlyAppendArguments) {
if (prefs.beforeOpeningBracket) {
buffer.append(SPACE);
}
buffer.append(LESS);
}
if (prefs.afterOpeningBracket) {
buffer.append(SPACE);
}
StringBuffer separator = new StringBuffer(3);
if (prefs.beforeTypeArgumentComma) {
separator.append(SPACE);
}
separator.append(COMMA);
if (prefs.afterTypeArgumentComma) {
separator.append(SPACE);
}
for (int i = 0; i != typeArguments.length; i++) {
if (i != 0) {
buffer.append(separator);
}
offsets[i] = buffer.length();
buffer.append(typeArguments[i]);
lengths[i] = buffer.length() - offsets[i];
}
if (prefs.beforeClosingBracket) {
buffer.append(SPACE);
}
if (!onlyAppendArguments) {
buffer.append(GREATER);
}
return buffer;
}
@Override
public Region getSelection(Document document) {
if (fSelectedRegion == null) {
return super.getSelection(document);
}
return new RegionImpl(fSelectedRegion.getOffset(), fSelectedRegion.getLength());
}
// private void installLinkedMode(IDocument document, int[] offsets, int[] lengths,
// TypeArgumentProposal[] typeArgumentProposals, boolean withParentheses)
// {
// int replacementOffset = getReplacementOffset();
// String replacementString = getReplacementString();
//
// try
// {
// LinkedModeModel model = new LinkedModeModel();
// for (int i = 0; i != offsets.length; i++)
// {
// if (typeArgumentProposals[i].isAmbiguous())
// {
// LinkedPositionGroup group = new LinkedPositionGroup();
// group.addPosition(new LinkedPosition(document, replacementOffset + offsets[i], lengths[i]));
// model.addGroup(group);
// }
// }
// if (withParentheses)
// {
// LinkedPositionGroup group = new LinkedPositionGroup();
// group.addPosition(new LinkedPosition(document, replacementOffset + getCursorPosition(), 0));
// model.addGroup(group);
// }
//
// model.forceInstall();
// JavaEditor editor = getJavaEditor();
// if (editor != null)
// {
// model.addLinkingListener(new EditorHighlightingSynchronizer(editor));
// }
//
// LinkedModeUI ui = new EditorLinkedModeUI(model, getTextViewer());
// ui.setExitPolicy(new ExitPolicy(withParentheses ? ')' : '>', document));
// ui.setExitPosition(getTextViewer(), replacementOffset + replacementString.length(), 0, Integer.MAX_VALUE);
// ui.setDoContextInfo(true);
// ui.enter();
//
// fSelectedRegion = ui.getSelectedRegion();
//
// }
// catch (BadLocationException e)
// {
// JavaPlugin.log(e);
// openErrorDialog(e);
// }
// }
// private boolean hasAmbiguousProposals(TypeArgumentProposal[] typeArgumentProposals)
// {
// boolean hasAmbiguousProposals = false;
// for (int i = 0; i < typeArgumentProposals.length; i++)
// {
// if (typeArgumentProposals[i].isAmbiguous())
// {
// hasAmbiguousProposals = true;
// break;
// }
// }
// return hasAmbiguousProposals;
// }
// /**
// * Returns the currently active java editor, or <code>null</code> if it cannot be determined.
// *
// * @return the currently active java editor, or <code>null</code>
// */
// private JavaEditor getJavaEditor()
// {
// IEditorPart part = JavaPlugin.getActivePage().getActiveEditor();
// if (part instanceof JavaEditor)
// return (JavaEditor)part;
// else
// return null;
// }
@Override
protected int computeCursorPosition() {
if (fSelectedRegion != null) {
return fSelectedRegion.getOffset() - getReplacementOffset();
}
return super.computeCursorPosition();
}
//
// private void openErrorDialog(BadLocationException e)
// {
// Shell shell = getTextViewer().getTextWidget().getShell();
// MessageDialog.openError(shell, JavaTextMessages.FilledArgumentNamesMethodProposal_error_msg, e.getMessage());
// }
// /*
// * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeContextInformation()
// */
// @Override
// protected org.eclipse.che.ide.editor.api.contentassist.ContextInformation computeContextInformation()
// {
// // try
// // {
// // if (hasParameters())
// // {
// // TypeArgumentProposal[] proposals = computeTypeArgumentProposals();
// // if (hasAmbiguousProposals(proposals))
// // return new ContextInformation(this);
// // }
// // }
// // catch (JavaModelException e)
// // {
// // }
// return super.computeContextInformation();
// }
/**
* Sets whether this proposal can use the diamond.
*
* @param canUseDiamond
* <code>true</code> if a diamond can be inserted
* @see CompletionProposal#canUseDiamond(org.eclipse.jdt.core.CompletionContext)
* @since 3.7
*/
void canUseDiamond(boolean canUseDiamond) {
fCanUseDiamond = canUseDiamond;
}
// private boolean hasParameters()
// {
// // try
// // {
// // IType type = (IType)getJavaElement();
// // if (type == null)
// // return false;
// //
// // return type.getTypeParameters().length > 0;
// // }
// // catch (JavaModelException e)
// // {
// // return false;
// // }
// return false;
// }
/**
* Tells whether this proposal can use the diamond.
*
* @return <code>true</code> if a diamond can be used
* @see CompletionProposal#canUseDiamond(org.eclipse.jdt.core.CompletionContext)
* @since 3.7
*/
protected boolean canUseDiamond() {
return fCanUseDiamond;
}
private static final class TypeArgumentProposal {
private final boolean fIsAmbiguous;
private final String fProposal;
private final String fTypeDisplayName;
TypeArgumentProposal(String proposal, boolean ambiguous, String typeDisplayName) {
fIsAmbiguous = ambiguous;
fProposal = proposal;
fTypeDisplayName = typeDisplayName;
}
// public String getDisplayName()
// {
// return fTypeDisplayName;
// }
//
// boolean isAmbiguous()
// {
// return fIsAmbiguous;
// }
@Override
public String toString() {
return fProposal;
}
}
}