update copyright
[fedora-idea.git] / xml / dom-openapi / src / com / intellij / util / xml / converters / DelimitedListConverter.java
blob8f490a2d9054159d6132a612cba16926a0633a9e
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Created by IntelliJ IDEA.
19 * User: Sergey.Vasiliev
20 * Date: Nov 13, 2006
21 * Time: 4:37:22 PM
23 package com.intellij.util.xml.converters;
25 import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider;
26 import com.intellij.openapi.util.Ref;
27 import com.intellij.openapi.util.TextRange;
28 import com.intellij.openapi.util.text.StringUtil;
29 import com.intellij.psi.PsiElement;
30 import com.intellij.psi.PsiReference;
31 import com.intellij.psi.PsiReferenceBase;
32 import com.intellij.util.ArrayUtil;
33 import com.intellij.util.Function;
34 import com.intellij.util.IncorrectOperationException;
35 import com.intellij.util.xml.ConvertContext;
36 import com.intellij.util.xml.CustomReferenceConverter;
37 import com.intellij.util.xml.GenericDomValue;
38 import com.intellij.util.xml.ResolvingConverter;
39 import org.jetbrains.annotations.NonNls;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
43 import java.util.*;
45 public abstract class DelimitedListConverter<T> extends ResolvingConverter<List<T>> implements CustomReferenceConverter<List<T>> {
47 protected final static Object[] EMPTY_ARRAY = ArrayUtil.EMPTY_OBJECT_ARRAY;
49 private final String myDelimiters;
51 public DelimitedListConverter(@NonNls @NotNull String delimiters) {
53 myDelimiters = delimiters;
56 @Nullable
57 protected abstract T convertString(final @Nullable String string, final ConvertContext context);
59 @Nullable
60 protected abstract String toString(@Nullable final T t);
63 protected abstract Object[] getReferenceVariants(final ConvertContext context, GenericDomValue<List<T>> genericDomValue);
65 @Nullable
66 protected abstract PsiElement resolveReference(@Nullable final T t, final ConvertContext context);
68 protected abstract String getUnresolvedMessage(String value);
70 @NotNull
71 public Collection<? extends List<T>> getVariants(final ConvertContext context) {
72 return Collections.emptyList();
75 public static <T> void filterVariants(List<T> variants, GenericDomValue<List<T>> genericDomValue) {
76 final List<T> list = genericDomValue.getValue();
77 if (list != null) {
78 for (Iterator<T> i = variants.iterator(); i.hasNext();) {
79 final T variant = i.next();
80 for (T existing : list) {
81 if (existing.equals(variant)) {
82 i.remove();
83 break;
90 protected char getDefaultDelimiter() {
91 return myDelimiters.charAt(0);
94 public List<T> fromString(@Nullable final String str, final ConvertContext context) {
95 if (str == null) {
96 return null;
98 List<T> values = new ArrayList<T>();
100 for (String s : StringUtil.tokenize(str, myDelimiters)) {
101 final T t = convertString(s.trim(), context);
102 if (t != null) {
103 values.add(t);
106 return values;
109 public String toString(final List<T> ts, final ConvertContext context) {
110 final StringBuffer buffer = new StringBuffer();
111 final char delimiter = getDefaultDelimiter();
112 for (T t : ts) {
113 final String s = toString(t);
114 if (s != null) {
115 if (buffer.length() != 0) {
116 buffer.append(delimiter);
118 buffer.append(s);
121 return buffer.toString();
124 @NotNull
125 public PsiReference[] createReferences(final GenericDomValue<List<T>> genericDomValue,
126 final PsiElement element,
127 final ConvertContext context) {
129 final String text = genericDomValue.getStringValue();
130 if (text == null) {
131 return PsiReference.EMPTY_ARRAY;
134 final ArrayList<PsiReference> references = new ArrayList<PsiReference>();
135 new DelimitedListProcessor(myDelimiters) {
136 protected void processToken(final int start, final int end, final boolean delimitersOnly) {
137 references.add(createPsiReference(element, start + 1, end + 1, context, genericDomValue, delimitersOnly));
139 }.processText(text);
140 return references.toArray(new PsiReference[references.size()]);
143 @NotNull
144 protected PsiReference createPsiReference(final PsiElement element,
145 int start,
146 int end,
147 final ConvertContext context,
148 final GenericDomValue<List<T>> genericDomValue,
149 final boolean delimitersOnly) {
151 return new MyPsiReference(element, new TextRange(start, end), context, genericDomValue, delimitersOnly);
154 protected class MyPsiReference extends PsiReferenceBase<PsiElement> implements EmptyResolveMessageProvider {
155 protected final ConvertContext myContext;
156 protected final GenericDomValue<List<T>> myGenericDomValue;
157 private final boolean myDelimitersOnly;
159 public MyPsiReference(final PsiElement element,
160 final TextRange range,
161 final ConvertContext context,
162 final GenericDomValue<List<T>> genericDomValue,
163 final boolean delimitersOnly) {
164 this(element, range, context, genericDomValue, true, delimitersOnly);
167 public MyPsiReference(final PsiElement element,
168 final TextRange range,
169 final ConvertContext context,
170 final GenericDomValue<List<T>> genericDomValue,
171 boolean soft,
172 final boolean delimitersOnly) {
173 super(element, range, soft);
174 myContext = context;
175 myGenericDomValue = genericDomValue;
176 myDelimitersOnly = delimitersOnly;
179 @Nullable
180 public PsiElement resolve() {
181 if (myDelimitersOnly) {
182 return getElement();
184 final String value = getValue();
185 return resolveReference(convertString(value, myContext), myContext);
188 public Object[] getVariants() {
189 return getReferenceVariants(myContext, myGenericDomValue);
192 @Override
193 public PsiElement handleElementRename(final String newElementName) throws IncorrectOperationException {
194 final Ref<IncorrectOperationException> ref = new Ref<IncorrectOperationException>();
195 PsiElement element = referenceHandleElementRename(this, newElementName, getSuperElementRenameFunction(ref));
196 if (!ref.isNull()) {
197 throw ref.get();
200 return element;
203 @Override
204 public PsiElement bindToElement(@NotNull final PsiElement element) throws IncorrectOperationException {
205 final Ref<IncorrectOperationException> ref = new Ref<IncorrectOperationException>();
206 PsiElement bindElement = referenceBindToElement(this, element, getSuperBindToElementFunction(ref), getSuperElementRenameFunction(ref));
207 if (!ref.isNull()) {
208 throw ref.get();
211 return bindElement;
214 private Function<PsiElement, PsiElement> getSuperBindToElementFunction(final Ref<IncorrectOperationException> ref) {
215 return new Function<PsiElement, PsiElement>() {
216 public PsiElement fun(final PsiElement s) {
217 try {
218 return MyPsiReference.super.bindToElement(s);
220 catch (IncorrectOperationException e) {
221 ref.set(e);
223 return null;
228 private Function<String, PsiElement> getSuperElementRenameFunction(final Ref<IncorrectOperationException> ref) {
229 return new Function<String, PsiElement>() {
230 public PsiElement fun(final String s) {
231 try {
232 return MyPsiReference.super.handleElementRename(s);
234 catch (IncorrectOperationException e) {
235 ref.set(e);
237 return null;
243 public String getUnresolvedMessagePattern() {
244 return getUnresolvedMessage(getValue());
248 protected PsiElement referenceBindToElement(final PsiReference psiReference, final PsiElement element,
249 final Function<PsiElement, PsiElement> superBindToElementFunction,
250 final Function<String, PsiElement> superElementRenameFunction)
251 throws IncorrectOperationException {
252 return superBindToElementFunction.fun(element);
255 protected PsiElement referenceHandleElementRename(final PsiReference psiReference,
256 final String newName,
257 final Function<String, PsiElement> superHandleElementRename)
258 throws IncorrectOperationException {
260 return superHandleElementRename.fun(newName);