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
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
;
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
;
57 protected abstract T
convertString(final @Nullable String string
, final ConvertContext context
);
60 protected abstract String
toString(@Nullable final T t
);
63 protected abstract Object
[] getReferenceVariants(final ConvertContext context
, GenericDomValue
<List
<T
>> genericDomValue
);
66 protected abstract PsiElement
resolveReference(@Nullable final T t
, final ConvertContext context
);
68 protected abstract String
getUnresolvedMessage(String value
);
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();
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
)) {
90 protected char getDefaultDelimiter() {
91 return myDelimiters
.charAt(0);
94 public List
<T
> fromString(@Nullable final String str
, final ConvertContext context
) {
98 List
<T
> values
= new ArrayList
<T
>();
100 for (String s
: StringUtil
.tokenize(str
, myDelimiters
)) {
101 final T t
= convertString(s
.trim(), context
);
109 public String
toString(final List
<T
> ts
, final ConvertContext context
) {
110 final StringBuffer buffer
= new StringBuffer();
111 final char delimiter
= getDefaultDelimiter();
113 final String s
= toString(t
);
115 if (buffer
.length() != 0) {
116 buffer
.append(delimiter
);
121 return buffer
.toString();
125 public PsiReference
[] createReferences(final GenericDomValue
<List
<T
>> genericDomValue
,
126 final PsiElement element
,
127 final ConvertContext context
) {
129 final String text
= genericDomValue
.getStringValue();
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
));
140 return references
.toArray(new PsiReference
[references
.size()]);
144 protected PsiReference
createPsiReference(final PsiElement element
,
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
,
172 final boolean delimitersOnly
) {
173 super(element
, range
, soft
);
175 myGenericDomValue
= genericDomValue
;
176 myDelimitersOnly
= delimitersOnly
;
180 public PsiElement
resolve() {
181 if (myDelimitersOnly
) {
184 final String value
= getValue();
185 return resolveReference(convertString(value
, myContext
), myContext
);
188 public Object
[] getVariants() {
189 return getReferenceVariants(myContext
, myGenericDomValue
);
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
));
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
));
214 private Function
<PsiElement
, PsiElement
> getSuperBindToElementFunction(final Ref
<IncorrectOperationException
> ref
) {
215 return new Function
<PsiElement
, PsiElement
>() {
216 public PsiElement
fun(final PsiElement s
) {
218 return MyPsiReference
.super.bindToElement(s
);
220 catch (IncorrectOperationException e
) {
228 private Function
<String
, PsiElement
> getSuperElementRenameFunction(final Ref
<IncorrectOperationException
> ref
) {
229 return new Function
<String
, PsiElement
>() {
230 public PsiElement
fun(final String s
) {
232 return MyPsiReference
.super.handleElementRename(s
);
234 catch (IncorrectOperationException e
) {
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
);