blob: d8e53cf15730136b2969860a7623c96376ea3d6b [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.lookup;
import com.intellij.codeInsight.CharTailType;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.impl.ElementLookupRenderer;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.ClassConditionKey;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* This class represents an item of a lookup list.
*/
public class LookupItem<T> extends MutableLookupElement<T> implements Comparable {
public static final ClassConditionKey<LookupItem> CLASS_CONDITION_KEY = ClassConditionKey.create(LookupItem.class);
public static final Object HIGHLIGHTED_ATTR = Key.create("highlighted");
public static final Object ICON_ATTR = Key.create("icon");
public static final Object TYPE_TEXT_ATTR = Key.create("typeText");
public static final Object TAIL_TEXT_ATTR = Key.create("tailText");
public static final Object TAIL_TEXT_SMALL_ATTR = Key.create("tailTextSmall");
public static final Key<Object> FORCE_SHOW_SIGNATURE_ATTR = Key.create("forceShowSignature");
public static final Object FORCE_QUALIFY = Key.create("FORCE_QUALIFY");
public static final Object SUBSTITUTOR = Key.create("SUBSTITUTOR");
public static final Object TYPE = Key.create("TYPE");
public static final Key<Object> DEPRECATED_ATTR = Key.create("DEPRECATED");
public static final Object CASE_INSENSITIVE = Key.create("CASE_INSENSITIVE");
public static final Key<TailType> TAIL_TYPE_ATTR = Key.create("myTailType"); // one of constants defined in SimpleTailType interface
private Object myObject;
private String myLookupString;
private InsertHandler myInsertHandler;
private double myPriority;
private Map<Object,Object> myAttributes = null;
public static final LookupItem[] EMPTY_ARRAY = new LookupItem[0];
private final Set<String> myAllLookupStrings = new HashSet<String>();
private String myPresentable;
private AutoCompletionPolicy myAutoCompletionPolicy = AutoCompletionPolicy.SETTINGS_DEPENDENT;
/**
* @deprecated use {@link LookupElementBuilder}
*/
public LookupItem(T o, @NotNull @NonNls String lookupString) {
setObject(o);
setLookupString(lookupString);
}
public static LookupItem fromString(String s) {
return new LookupItem<String>(s, s);
}
public void setObject(@NotNull T o) {
myObject = o;
if (o instanceof LookupValueWithPriority) {
setPriority(((LookupValueWithPriority)o).getPriority());
}
}
public boolean equals(Object o){
if (o == this) return true;
if (o instanceof LookupItem){
LookupItem item = (LookupItem)o;
return Comparing.equal(myObject, item.myObject)
&& Comparing.equal(myLookupString, item.myLookupString)
&& Comparing.equal(myAllLookupStrings, item.myAllLookupStrings)
&& Comparing.equal(myAttributes, item.myAttributes);
}
return false;
}
public int hashCode() {
final Object object = getObject();
assert object != this: getClass().getName();
return myAllLookupStrings.hashCode() * 239 + object.hashCode();
}
public String toString() {
return getLookupString();
}
/**
* Returns a data object. This object is used e.g. for rendering the node.
*/
@Override
@NotNull
public T getObject() {
return (T)myObject;
}
/**
* Returns a string which will be inserted to the editor when this item is
* choosen.
*/
@Override
@NotNull
public String getLookupString() {
return myLookupString;
}
public void setLookupString(@NotNull String lookupString) {
if (myAllLookupStrings.contains("")) myAllLookupStrings.remove("");
myLookupString = lookupString;
myAllLookupStrings.add(lookupString);
}
public Object getAttribute(Object key){
if (myAttributes != null){
return myAttributes.get(key);
}
else{
return null;
}
}
public <T> T getAttribute(Key<T> key) {
if (myAttributes != null){
//noinspection unchecked
return (T)myAttributes.get(key);
}
else{
return null;
}
}
public void setAttribute(Object key, Object value){
if (myAttributes == null){
myAttributes = new HashMap<Object, Object>(5);
}
myAttributes.put(key, value);
}
public <T> void setAttribute(Key<T> key, T value){
if (value == null && myAttributes != null) {
myAttributes.remove(key);
return;
}
if (myAttributes == null){
myAttributes = new HashMap<Object, Object>(5);
}
myAttributes.put(key, value);
}
@Override
public InsertHandler<? extends LookupItem> getInsertHandler(){
return myInsertHandler;
}
@Override
public boolean isBold() {
return getAttribute(HIGHLIGHTED_ATTR) != null;
}
@Override
public void handleInsert(final InsertionContext context) {
final InsertHandler<? extends LookupElement> handler = getInsertHandler();
if (handler != null) {
//noinspection unchecked
((InsertHandler)handler).handleInsert(context, this);
}
if (getTailType() != TailType.UNKNOWN && myInsertHandler == null) {
context.setAddCompletionChar(false);
final TailType type = handleCompletionChar(context.getEditor(), this, context.getCompletionChar());
type.processTail(context.getEditor(), context.getTailOffset());
}
}
@Nullable
public static TailType getDefaultTailType(final char completionChar) {
switch(completionChar){
case '.': return new CharTailType('.', false);
case ',': return TailType.COMMA;
case ';': return TailType.SEMICOLON;
case '=': return TailType.EQ;
case ' ': return TailType.SPACE;
case ':': return TailType.CASE_COLON; //?
}
return null;
}
@NotNull
public static TailType handleCompletionChar(@NotNull final Editor editor, @NotNull final LookupElement lookupElement, final char completionChar) {
final TailType type = getDefaultTailType(completionChar);
if (type != null) {
return type;
}
if (lookupElement instanceof LookupItem) {
final LookupItem<?> item = (LookupItem)lookupElement;
final TailType attr = item.getAttribute(CompletionUtil.TAIL_TYPE_ATTR);
if (attr != null) {
return attr;
}
}
return TailType.NONE;
}
@NotNull
public TailType getTailType(){
final TailType tailType = getAttribute(TAIL_TYPE_ATTR);
return tailType != null ? tailType : TailType.UNKNOWN;
}
@Override
@NotNull
public LookupItem<T> setTailType(@NotNull TailType type) {
setAttribute(TAIL_TYPE_ATTR, type);
return this;
}
@Override
public int compareTo(@NotNull Object o){
if(o instanceof String){
return getLookupString().compareTo((String)o);
}
if(!(o instanceof LookupItem)){
throw new RuntimeException("Trying to compare LookupItem with " + o.getClass() + "!!!");
}
return getLookupString().compareTo(((LookupItem)o).getLookupString());
}
@Override
public LookupItem<T> setInsertHandler(@NotNull final InsertHandler<? extends LookupElement> handler) {
myInsertHandler = handler;
return this;
}
@Override
public void renderElement(LookupElementPresentation presentation) {
for (final ElementLookupRenderer renderer : Extensions.getExtensions(ElementLookupRenderer.EP_NAME)) {
if (renderer.handlesItem(getObject())) {
renderer.renderElement(this, getObject(), presentation);
return;
}
}
DefaultLookupItemRenderer.INSTANCE.renderElement(this, presentation);
}
@Override
public LookupItem<T> setBold() {
setAttribute(HIGHLIGHTED_ATTR, "");
return this;
}
public LookupItem<T> forceQualify() {
setAttribute(FORCE_QUALIFY, "");
return this;
}
public LookupItem<T> setDeprecated(boolean deprecated) {
setAttribute(DEPRECATED_ATTR, deprecated ? "" : null);
return this;
}
@Override
public LookupItem<T> setAutoCompletionPolicy(final AutoCompletionPolicy policy) {
myAutoCompletionPolicy = policy;
return this;
}
public AutoCompletionPolicy getAutoCompletionPolicy() {
return myAutoCompletionPolicy;
}
@Override
@NotNull
public LookupItem<T> setIcon(Icon icon) {
setAttribute(ICON_ATTR, icon);
return this;
}
@Override
@NotNull
public LookupItem<T> setPriority(double priority) {
myPriority = priority;
return this;
}
public final double getPriority() {
return myPriority;
}
@Override
@NotNull
public LookupItem<T> setPresentableText(@NotNull final String displayText) {
myPresentable = displayText;
return this;
}
@Nullable
public String getPresentableText() {
return myPresentable;
}
@Override
@NotNull
public LookupItem<T> setTypeText(final String text) {
setAttribute(TYPE_TEXT_ATTR, text);
return this;
}
@NotNull
@Override
public MutableLookupElement<T> setTailText(final String text, final boolean grayed) {
setAttribute(TAIL_TEXT_ATTR, text);
setAttribute(TAIL_TEXT_SMALL_ATTR, Boolean.TRUE);
return this;
}
@Override
@NotNull
public LookupItem<T> setCaseSensitive(final boolean caseSensitive) {
setAttribute(CASE_INSENSITIVE, !caseSensitive);
return this;
}
@Override
public LookupItem<T> addLookupStrings(@NonNls final String... additionalLookupStrings) {
ContainerUtil.addAll(myAllLookupStrings, additionalLookupStrings);
return this;
}
@Override
public Set<String> getAllLookupStrings() {
return myAllLookupStrings;
}
@Override
public boolean isCaseSensitive() {
return !Boolean.TRUE.equals(getAttribute(CASE_INSENSITIVE));
}
}