update copyright
[fedora-idea.git] / xml / impl / src / com / intellij / psi / impl / source / resolve / reference / impl / providers / DtdReferencesProvider.java
blob7924a6a0854f60472582ee1339abaf2c882a84cf
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.psi.impl.source.resolve.reference.impl.providers;
18 import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider;
19 import com.intellij.codeInspection.LocalQuickFix;
20 import com.intellij.codeInspection.LocalQuickFixProvider;
21 import com.intellij.lang.html.HTMLLanguage;
22 import com.intellij.lang.xhtml.XHTMLLanguage;
23 import com.intellij.openapi.util.TextRange;
24 import com.intellij.psi.*;
25 import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
26 import com.intellij.psi.filters.ElementFilter;
27 import com.intellij.psi.impl.source.xml.XmlEntityRefImpl;
28 import com.intellij.psi.meta.PsiMetaData;
29 import com.intellij.psi.util.PsiTreeUtil;
30 import com.intellij.psi.util.PsiUtilBase;
31 import com.intellij.psi.xml.*;
32 import com.intellij.util.ArrayUtil;
33 import com.intellij.util.IncorrectOperationException;
34 import com.intellij.util.ProcessingContext;
35 import com.intellij.xml.XmlBundle;
36 import com.intellij.xml.XmlElementDescriptor;
37 import com.intellij.xml.XmlNSDescriptor;
38 import com.intellij.xml.impl.dtd.XmlNSDescriptorImpl;
39 import com.intellij.xml.util.CheckDtdReferencesInspection;
40 import com.intellij.xml.util.XmlUtil;
41 import org.jetbrains.annotations.NonNls;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
45 import java.util.ArrayList;
46 import java.util.List;
48 /**
49 * Created by IntelliJ IDEA.
50 * User: Maxim.Mossienko
51 * Date: Jul 4, 2005
52 * Time: 3:58:53 PM
53 * To change this template use File | Settings | File Templates.
55 public class DtdReferencesProvider extends PsiReferenceProvider {
56 static class ElementReference implements PsiReference, LocalQuickFixProvider, EmptyResolveMessageProvider {
57 private final XmlElement myElement;
58 private XmlElement myNameElement;
59 private final TextRange myRange;
60 @NonNls private static final String ELEMENT_DECLARATION_NAME = "ELEMENT";
62 public ElementReference(final XmlElement element, final XmlElement nameElement) {
63 myElement = element;
64 myNameElement = nameElement;
66 final int textOffset = element.getTextRange().getStartOffset();
67 final int nameTextOffset = nameElement.getTextOffset();
69 myRange = new TextRange(
70 nameTextOffset - textOffset,
71 nameTextOffset + nameElement.getTextLength() - textOffset
76 public PsiElement getElement() {
77 return myElement;
80 public TextRange getRangeInElement() {
81 return myRange;
84 @Nullable
85 public PsiElement resolve() {
86 XmlNSDescriptor rootTagNSDescriptor = getNsDescriptor();
88 if (rootTagNSDescriptor instanceof XmlNSDescriptorImpl) {
89 final XmlElementDescriptor elementDescriptor = ((XmlNSDescriptorImpl)rootTagNSDescriptor).getElementDescriptor(getCanonicalText());
91 if (elementDescriptor != null) return elementDescriptor.getDeclaration();
93 return null;
96 private XmlNSDescriptor getNsDescriptor() {
97 final XmlElement parentThatProvidesMetaData = PsiTreeUtil.getParentOfType(
98 PsiUtilBase.getOriginalElement(myElement,(Class<XmlElement>)myElement.getClass()),
99 XmlDocument.class,
100 XmlMarkupDecl.class
103 if (parentThatProvidesMetaData instanceof XmlDocument) {
104 final XmlDocument document = (XmlDocument)parentThatProvidesMetaData;
105 XmlNSDescriptor rootTagNSDescriptor = document.getRootTagNSDescriptor();
106 if (rootTagNSDescriptor == null) rootTagNSDescriptor = (XmlNSDescriptor)document.getMetaData();
107 return rootTagNSDescriptor;
108 } else if (parentThatProvidesMetaData instanceof XmlMarkupDecl) {
109 final XmlMarkupDecl markupDecl = (XmlMarkupDecl)parentThatProvidesMetaData;
110 final PsiMetaData psiMetaData = markupDecl.getMetaData();
112 if (psiMetaData instanceof XmlNSDescriptor) {
113 return (XmlNSDescriptor)psiMetaData;
117 return null;
120 public String getCanonicalText() {
121 final XmlElement nameElement = myNameElement;
122 return nameElement != null ? nameElement.getText() : "";
125 public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
126 myNameElement = ElementManipulators.getManipulator(myNameElement).handleContentChange(
127 myNameElement,
128 new TextRange(0,myNameElement.getTextLength()),
129 newElementName
132 return null;
135 public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
136 return null;
139 public boolean isReferenceTo(PsiElement element) {
140 return myElement.getManager().areElementsEquivalent(element, resolve());
143 public Object[] getVariants() {
144 final XmlNSDescriptor rootTagNSDescriptor = getNsDescriptor();
145 return rootTagNSDescriptor != null ?
146 rootTagNSDescriptor.getRootElementsDescriptors(((XmlFile)getRealFile()).getDocument()):
147 ArrayUtil.EMPTY_OBJECT_ARRAY;
150 private PsiFile getRealFile() {
151 PsiFile psiFile = myElement.getContainingFile();
152 if (psiFile != null) psiFile = psiFile.getOriginalFile();
153 return psiFile;
156 public boolean isSoft() {
157 return true;
160 public LocalQuickFix[] getQuickFixes() {
161 if (!canHaveAdequateFix(getElement())) return LocalQuickFix.EMPTY_ARRAY;
163 return new LocalQuickFix[] {
164 new CheckDtdReferencesInspection.AddDtdDeclarationFix(
165 "xml.dtd.create.dtd.element.intention.name",
166 ELEMENT_DECLARATION_NAME,
167 this
172 public String getUnresolvedMessagePattern() {
173 return XmlBundle.message("xml.dtd.unresolved.element.reference", getCanonicalText());
177 static class EntityReference implements PsiReference,LocalQuickFixProvider, EmptyResolveMessageProvider {
178 private final PsiElement myElement;
179 private final TextRange myRange;
180 @NonNls private static final String ENTITY_DECLARATION_NAME = "ENTITY";
182 EntityReference(PsiElement element) {
183 myElement = element;
184 if (element instanceof XmlEntityRef) {
185 final PsiElement child = element.getLastChild();
186 final int startOffsetInParent = child.getStartOffsetInParent();
187 myRange = new TextRange(startOffsetInParent + 1, startOffsetInParent + child.getTextLength() - 1);
188 } else {
189 myRange = new TextRange(1,myElement.getTextLength()-1);
193 public PsiElement getElement() {
194 return myElement;
197 public TextRange getRangeInElement() {
198 return myRange;
201 @Nullable
202 public PsiElement resolve() {
203 XmlEntityDecl xmlEntityDecl = XmlEntityRefImpl.resolveEntity(
204 (XmlElement)myElement,
205 (myElement instanceof XmlEntityRef ? myElement.getLastChild():myElement).getText(),
206 myElement.getContainingFile()
209 if (xmlEntityDecl != null && !xmlEntityDecl.isPhysical()) {
210 PsiNamedElement element = XmlUtil.findRealNamedElement(xmlEntityDecl);
211 if (element != null) xmlEntityDecl = (XmlEntityDecl)element;
213 return xmlEntityDecl;
216 public String getCanonicalText() {
217 return myRange.substring(myElement.getText());
220 public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
221 final PsiElement elementAt = myElement.findElementAt(myRange.getStartOffset());
222 return ElementManipulators.getManipulator(elementAt).handleContentChange(elementAt, getRangeInElement(), newElementName);
225 public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
226 return null;
229 public boolean isReferenceTo(PsiElement element) {
230 return myElement.getManager().areElementsEquivalent(resolve(), element);
233 public Object[] getVariants() {
234 return ArrayUtil.EMPTY_OBJECT_ARRAY;
237 public boolean isSoft() {
238 return false;
241 public LocalQuickFix[] getQuickFixes() {
242 if (!canHaveAdequateFix(getElement())) return LocalQuickFix.EMPTY_ARRAY;
244 return new LocalQuickFix[] {
245 new CheckDtdReferencesInspection.AddDtdDeclarationFix(
246 "xml.dtd.create.entity.intention.name",
247 myElement.getText().charAt(myRange.getStartOffset() - 1) == '%' ?
248 ENTITY_DECLARATION_NAME + " %":
249 ENTITY_DECLARATION_NAME,
250 this
255 public String getUnresolvedMessagePattern() {
256 return XmlBundle.message("xml.dtd.unresolved.entity.reference", getCanonicalText());
260 private static boolean canHaveAdequateFix(PsiElement element) {
261 final PsiFile containingFile = element.getContainingFile();
263 if (containingFile.getLanguage() == HTMLLanguage.INSTANCE ||
264 containingFile.getLanguage() == XHTMLLanguage.INSTANCE ||
265 containingFile.getViewProvider() instanceof TemplateLanguageFileViewProvider
267 return false;
269 return true;
272 @NotNull
273 public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) {
274 XmlElement nameElement = null;
276 if (element instanceof XmlDoctype) {
277 nameElement = ((XmlDoctype)element).getNameElement();
278 } else if (element instanceof XmlElementDecl) {
279 nameElement = ((XmlElementDecl)element).getNameElement();
280 } else if (element instanceof XmlAttlistDecl) {
281 nameElement = ((XmlAttlistDecl)element).getNameElement();
282 } else if (element instanceof XmlElementContentSpec) {
283 final PsiElement[] children = element.getChildren();
284 final List<PsiReference> psiRefs = new ArrayList<PsiReference>(children.length);
286 for (final PsiElement child : children) {
287 if (child instanceof XmlToken && ((XmlToken)child).getTokenType() == XmlTokenType.XML_NAME) {
288 psiRefs.add(new ElementReference((XmlElement)element, (XmlElement)child));
292 return psiRefs.toArray(new PsiReference[psiRefs.size()]);
295 if (nameElement != null) {
296 return new PsiReference[] { new ElementReference((XmlElement)element, nameElement) };
299 if (element instanceof XmlEntityRef ||
300 (element instanceof XmlToken && ((XmlToken)element).getTokenType() == XmlTokenType.XML_CHAR_ENTITY_REF)) {
301 return new PsiReference[] { new EntityReference(element) };
304 return PsiReference.EMPTY_ARRAY;
307 public ElementFilter getSystemReferenceFilter() {
308 return new ElementFilter() {
309 public boolean isAcceptable(Object element, PsiElement context) {
310 final PsiElement parent = context.getParent();
312 if((parent instanceof XmlEntityDecl &&
313 !((XmlEntityDecl)parent).isInternalReference()
316 PsiElement prevSibling = context.getPrevSibling();
317 if (prevSibling instanceof PsiWhiteSpace) {
318 prevSibling = prevSibling.getPrevSibling();
321 if (prevSibling instanceof XmlToken &&
322 ((XmlToken)prevSibling).getTokenType() == XmlTokenType.XML_DOCTYPE_SYSTEM ||
323 prevSibling instanceof XmlAttributeValue
325 return true;
329 return false;
332 public boolean isClassAcceptable(Class hintClass) {
333 return true;