ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / xml / impl / src / com / intellij / codeInsight / completion / HtmlCompletionData.java
blobed4e1ff4719ff75e23ef5be3ea002f1172dca6cf
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.
16 package com.intellij.codeInsight.completion;
18 import com.intellij.lang.Language;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.util.Computable;
21 import com.intellij.psi.PsiElement;
22 import com.intellij.psi.PsiFile;
23 import com.intellij.psi.filters.AndFilter;
24 import com.intellij.psi.filters.ElementFilter;
25 import com.intellij.psi.filters.OrFilter;
26 import com.intellij.psi.filters.TextContainFilter;
27 import com.intellij.psi.filters.getters.HtmlAttributeValueGetter;
28 import com.intellij.psi.filters.getters.XmlAttributeValueGetter;
29 import com.intellij.psi.filters.position.XmlTokenTypeFilter;
30 import com.intellij.psi.util.PsiTreeUtil;
31 import com.intellij.psi.xml.*;
32 import com.intellij.util.ArrayUtil;
33 import org.jetbrains.annotations.NonNls;
35 import java.util.Set;
37 /**
38 * @author Maxim.Mossienko
40 @SuppressWarnings({"RefusedBequest"})
41 public class HtmlCompletionData extends XmlCompletionData {
42 private static CompletionData ourStyleCompletionData;
43 private boolean myCaseInsensitive;
44 private static CompletionData ourScriptCompletionData;
45 private static final @NonNls String JAVASCRIPT_LANGUAGE_ID = "JavaScript";
46 private static final @NonNls String STYLE_TAG = "style";
47 private static final @NonNls String SCRIPT_TAG = "script";
49 public HtmlCompletionData() {
50 this(true);
53 protected HtmlCompletionData(boolean _caseInsensitive) {
54 myCaseInsensitive = _caseInsensitive;
57 protected ElementFilter createXmlEntityCompletionFilter() {
58 if (isCaseInsensitive()) {
59 return new AndFilter(
60 new OrFilter (
61 new XmlTokenTypeFilter(XmlTokenType.XML_DATA_CHARACTERS),
62 new XmlTokenTypeFilter(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
64 new TextContainFilter("&")
68 return super.createXmlEntityCompletionFilter();
71 private boolean equalNames(String str,String str2) {
72 if (!myCaseInsensitive) return str.equals(str2);
73 return str.equalsIgnoreCase(str2);
76 protected boolean isCaseInsensitive() {
77 return true;
80 protected void setCaseInsensitive(final boolean caseInsensitive) {
81 myCaseInsensitive = caseInsensitive;
84 protected XmlAttributeValueGetter getAttributeValueGetter() {
85 return new HtmlAttributeValueGetter(!isCaseInsensitive());
88 protected ElementFilter createTagCompletionFilter() {
89 return new ElementFilter() {
90 public boolean isAcceptable(Object element, PsiElement context) {
91 String name = ((XmlTag)context).getName();
92 if (name == null) return true;
94 if (element instanceof PsiElement &&
95 ((PsiElement)element).getParent() == context) {
96 return true;
99 if (equalNames(name, STYLE_TAG) ||
100 equalNames(name,SCRIPT_TAG)) {
101 return false;
104 if ( isStyleAttributeContext((PsiElement)element) ) return false;
105 return true;
108 public boolean isClassAcceptable(Class hintClass) {
109 return true;
114 protected ElementFilter createAttributeCompletionFilter() {
115 return new ElementFilter() {
116 public boolean isAcceptable(Object element, PsiElement context) {
117 if (isStyleAttributeContext(context)) return false;
118 return true;
121 public boolean isClassAcceptable(Class hintClass) {
122 return true;
127 protected ElementFilter createAttributeValueCompletionFilter() {
128 return new ElementFilter() {
129 public boolean isAcceptable(Object element, PsiElement context) {
130 if (isStyleAttributeContext(context)) return false;
131 if ( isScriptContext((PsiElement)element) ) return false;
132 return true;
135 public boolean isClassAcceptable(Class hintClass) {
136 return true;
141 private boolean isScriptContext(PsiElement element) {
142 final Language language = element.getLanguage();
144 return language.getID().equals(JAVASCRIPT_LANGUAGE_ID);
147 private boolean isScriptTag(XmlTag tag) {
148 if (tag!=null) {
149 String tagName = tag.getName();
150 if (tagName == null) return false;
151 if (myCaseInsensitive) return tagName.equalsIgnoreCase(SCRIPT_TAG);
153 return tagName.equals(SCRIPT_TAG);
156 return false;
159 private boolean isStyleTag(XmlTag tag) {
160 if (tag!=null) {
161 String tagName = tag.getName();
162 if (tagName == null) return false;
163 if (myCaseInsensitive) return tagName.equalsIgnoreCase(STYLE_TAG);
165 return tagName.equals(STYLE_TAG);
168 return false;
171 public CompletionVariant[] findVariants(final PsiElement position, final PsiFile file) {
172 return ApplicationManager.getApplication().runReadAction(new Computable<CompletionVariant[]>() {
173 public CompletionVariant[] compute() {
174 CompletionVariant[] variants = HtmlCompletionData.super.findVariants(position, file);
176 if (ourStyleCompletionData!=null && isStyleContext(position)) {
177 final CompletionVariant[] styleVariants = ourStyleCompletionData.findVariants(position, file);
179 variants = ArrayUtil.mergeArrays(variants,styleVariants, CompletionVariant.class);
182 if (ourScriptCompletionData!=null && isScriptContext(position)) {
183 final CompletionVariant[] scriptVariants = ourScriptCompletionData.findVariants(position, file);
185 variants = ArrayUtil.mergeArrays(variants,scriptVariants, CompletionVariant.class);
187 return variants;
192 private boolean isStyleAttributeContext(PsiElement position) {
193 XmlAttribute parentOfType = PsiTreeUtil.getParentOfType(position, XmlAttribute.class, false);
195 if (parentOfType != null) {
196 String name = parentOfType.getName();
197 if (name != null) {
198 if (myCaseInsensitive) return STYLE_TAG.equalsIgnoreCase(name);
199 return STYLE_TAG.equals(name); //name.endsWith("style");
203 return false;
205 private boolean isStyleContext(PsiElement position) {
206 if (isStyleAttributeContext(position)) return true;
208 return isStyleTag(PsiTreeUtil.getParentOfType(position, XmlTag.class, false));
211 public void addKeywordVariants(final Set<CompletionVariant> set, final PsiElement position, final PsiFile file) {
212 super.addKeywordVariants(set, position, file);
214 ApplicationManager.getApplication().runReadAction(new Runnable() {
215 public void run() {
216 if (ourStyleCompletionData != null && isStyleContext(position)) {
217 ourStyleCompletionData.addKeywordVariants(set, position, file);
219 else if (ourScriptCompletionData != null && isScriptContext(position)) {
220 ourScriptCompletionData.addKeywordVariants(set, position, file);
226 public static void setStyleCompletionData(CompletionData cssCompletionData) {
227 ourStyleCompletionData = cssCompletionData;
230 public void registerVariant(CompletionVariant variant) {
231 super.registerVariant(variant);
232 if (isCaseInsensitive()) variant.setCaseInsensitive(true);
235 public String findPrefix(PsiElement insertedElement, int offset) {
236 XmlTag tag = PsiTreeUtil.getParentOfType(insertedElement, XmlTag.class, false);
237 String prefix = null;
239 if (isScriptTag(tag) &&
240 ourScriptCompletionData != null &&
241 !(insertedElement.getParent() instanceof XmlAttributeValue)) {
242 prefix = ourScriptCompletionData.findPrefix(insertedElement, offset);
243 } else if (isStyleTag(tag) && ourStyleCompletionData!=null) {
244 prefix = ourStyleCompletionData.findPrefix(insertedElement, offset);
247 if (prefix == null) {
248 prefix = super.findPrefix(insertedElement, offset);
250 boolean searchForEntities =
251 insertedElement instanceof XmlToken &&
252 ( ((XmlToken)insertedElement).getTokenType() == XmlTokenType.XML_DATA_CHARACTERS ||
253 ((XmlToken)insertedElement).getTokenType() == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN
256 if (searchForEntities && prefix != null) {
257 if (prefix.startsWith("&")) {
258 prefix = prefix.substring(1);
259 } else if (prefix.contains("&")) {
260 prefix = prefix.substring(prefix.indexOf("&") + 1);
265 return prefix;
268 public static void setScriptCompletionData(CompletionData scriptCompletionData) {
269 ourScriptCompletionData = scriptCompletionData;