update copyright
[fedora-idea.git] / xml / impl / src / com / intellij / xml / util / documentation / HtmlDocumentationProvider.java
blobd687fa5bbb074d58e72ccf527419428df8cf5fdb
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.xml.util.documentation;
18 import com.intellij.lang.documentation.DocumentationProvider;
19 import com.intellij.lang.documentation.DocumentationUtil;
20 import com.intellij.psi.PsiElement;
21 import com.intellij.psi.PsiManager;
22 import com.intellij.psi.PsiWhiteSpace;
23 import com.intellij.psi.XmlElementFactory;
24 import com.intellij.psi.meta.PsiMetaData;
25 import com.intellij.psi.util.PsiTreeUtil;
26 import com.intellij.psi.xml.*;
27 import com.intellij.util.IncorrectOperationException;
28 import com.intellij.xml.XmlAttributeDescriptor;
29 import com.intellij.xml.XmlBundle;
30 import com.intellij.xml.XmlElementDescriptor;
31 import com.intellij.xml.util.ColorSampleLookupValue;
32 import com.intellij.xml.util.XmlUtil;
33 import org.jetbrains.annotations.NonNls;
34 import org.jetbrains.annotations.Nullable;
36 import java.util.Collections;
37 import java.util.List;
39 /**
40 * Created by IntelliJ IDEA.
41 * User: maxim
42 * Date: 24.12.2004
43 * Time: 23:55:08
44 * To change this template use File | Settings | File Templates.
46 public class HtmlDocumentationProvider implements DocumentationProvider {
47 private static String ourBaseHtmlExtDocUrl;
48 private static DocumentationProvider ourStyleProvider;
49 private static DocumentationProvider ourScriptProvider;
51 @NonNls public static final String ELEMENT_ELEMENT_NAME = "element";
52 @NonNls public static final String NBSP = ": ";
53 @NonNls public static final String BR = "<br>";
55 public static void registerStyleDocumentationProvider(DocumentationProvider documentationProvider) {
56 ourStyleProvider = documentationProvider;
59 @Nullable
60 public String getQuickNavigateInfo(PsiElement element) {
61 return null;
64 public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
65 String result = getUrlForHtml(element, PsiTreeUtil.getParentOfType(originalElement,XmlTag.class,false));
67 if (result == null && ourStyleProvider !=null) {
68 return ourStyleProvider.getUrlFor(element, originalElement);
71 return result != null ? Collections.singletonList(result) : null;
74 public String getUrlForHtml(PsiElement element, XmlTag context) {
75 final EntityDescriptor descriptor = findDocumentationDescriptor(element, context);
77 if (descriptor!=null) {
78 return ourBaseHtmlExtDocUrl + descriptor.getHelpRef();
79 } else {
80 return null;
84 private EntityDescriptor findDocumentationDescriptor(PsiElement element, XmlTag context) {
85 boolean isTag = true;
86 PsiElement nameElement = null;
87 String key = null;
89 if (element instanceof XmlElementDecl) {
90 nameElement = ((XmlElementDecl)element).getNameElement();
91 } else if (element instanceof XmlAttributeDecl) {
92 nameElement = ((XmlAttributeDecl)element).getNameElement();
93 isTag = false;
94 } else if (element instanceof XmlTag) {
95 final XmlTag xmlTag = ((XmlTag)element);
96 final PsiMetaData metaData = xmlTag.getMetaData();
97 key = (metaData!=null)?metaData.getName():null;
98 isTag = xmlTag.getLocalName().equals(ELEMENT_ELEMENT_NAME);
99 } else if (element.getParent() instanceof XmlAttributeValue) {
100 isTag = false;
101 key = ((XmlAttribute)element.getParent().getParent()).getName();
102 } else if (element instanceof XmlAttributeValue) {
103 isTag = false;
104 final XmlAttribute xmlAttribute = (XmlAttribute)element.getParent();
105 key = xmlAttribute.getName();
106 } else if (element instanceof XmlAttribute) {
107 final XmlAttribute xmlAttribute = (XmlAttribute)element;
108 isTag = false;
109 key = xmlAttribute.getName();
110 } else {
111 nameElement = element;
112 isTag = !(element.getParent() instanceof XmlAttribute);
115 if (nameElement!=null) {
116 key = nameElement.getText();
119 key = (key != null)?key.toLowerCase():"";
121 if (isTag) {
122 return HtmlDescriptorsTable.getTagDescriptor(key);
123 } else {
124 return getDescriptor(key, context);
128 private static HtmlAttributeDescriptor getDescriptor(String name, XmlTag context) {
130 HtmlAttributeDescriptor attributeDescriptor = HtmlDescriptorsTable.getAttributeDescriptor(name);
131 if (attributeDescriptor instanceof CompositeAttributeTagDescriptor) {
132 return ((CompositeAttributeTagDescriptor)attributeDescriptor).findHtmlAttributeInContext(context);
135 return attributeDescriptor;
138 public String generateDoc(PsiElement element, PsiElement originalElement) {
139 final XmlTag tag = PsiTreeUtil.getParentOfType(originalElement, XmlTag.class, false);
140 String result = generateDocForHtml(element, false, tag, originalElement);
142 if (result == null && ourStyleProvider !=null) {
143 result = ourStyleProvider.generateDoc(element, originalElement);
146 if (result == null && ourScriptProvider !=null) {
147 result = ourScriptProvider.generateDoc(element, originalElement);
150 if (result == null && element instanceof XmlAttributeValue) {
151 result = generateDocForHtml(element.getParent(), false, tag, originalElement);
154 return result;
157 public String generateDocForHtml(PsiElement element) {
158 return generateDocForHtml(element,true, null, null);
161 protected String generateDocForHtml(PsiElement element, boolean ommitHtmlSpecifics, XmlTag context, PsiElement originalElement) {
162 final EntityDescriptor descriptor = findDocumentationDescriptor(element,context);
164 if (descriptor!=null) {
165 return generateJavaDoc(descriptor, ommitHtmlSpecifics, originalElement);
167 if (element instanceof XmlEntityDecl) {
168 final XmlEntityDecl entityDecl = (XmlEntityDecl)element;
170 return XmlDocumentationProvider.findDocRightAfterElement(element, entityDecl.getName());
172 return null;
175 private static String generateJavaDoc(EntityDescriptor descriptor, boolean ommitHtmlSpecifics, PsiElement element) {
176 StringBuilder buf = new StringBuilder();
177 final boolean istag = descriptor instanceof HtmlTagDescriptor;
179 if (istag) {
180 DocumentationUtil.formatEntityName(XmlBundle.message("xml.javadoc.tag.name.message"),descriptor.getName(),buf);
181 } else {
182 DocumentationUtil.formatEntityName(XmlBundle.message("xml.javadoc.attribute.name.message"),descriptor.getName(),buf);
185 buf.append(XmlBundle.message("xml.javadoc.description.message")).append(NBSP).append(descriptor.getDescription()).append(BR);
187 if (istag) {
188 final HtmlTagDescriptor tagDescriptor = (HtmlTagDescriptor)descriptor;
190 if (!ommitHtmlSpecifics) {
191 boolean hasStartTag = tagDescriptor.isHasStartTag();
192 if (!hasStartTag) {
193 buf.append(XmlBundle.message("xml.javadoc.start.tag.could.be.omitted.message")).append(BR);
195 if (!tagDescriptor.isEmpty() && !tagDescriptor.isHasEndTag()) {
196 buf.append(XmlBundle.message("xml.javadoc.end.tag.could.be.omitted.message")).append(BR);
200 if (tagDescriptor.isEmpty()) {
201 buf.append(XmlBundle.message("xml.javadoc.is.empty.message")).append(BR);
203 } else {
204 final HtmlAttributeDescriptor attributeDescriptor = (HtmlAttributeDescriptor)descriptor;
206 buf.append(XmlBundle.message("xml.javadoc.attr.type.message", attributeDescriptor.getType())).append(BR);
207 if (!attributeDescriptor.isHasDefaultValue())
208 buf.append(XmlBundle.message("xml.javadoc.attr.default.required.message")).append(BR);
211 char dtdId = descriptor.getDtd();
212 boolean deprecated = dtdId == HtmlTagDescriptor.LOOSE_DTD;
213 if (deprecated) {
214 buf.append(XmlBundle.message("xml.javadoc.deprecated.message", deprecated)).append(BR);
217 if (dtdId == HtmlTagDescriptor.LOOSE_DTD) {
218 buf.append(XmlBundle.message("xml.javadoc.defined.in.loose.dtd.message"));
220 else if (dtdId == HtmlTagDescriptor.FRAME_DTD) {
221 buf.append(XmlBundle.message("xml.javadoc.defined.in.frameset.dtd.message"));
223 else {
224 buf.append(XmlBundle.message("xml.javadoc.defined.in.any.dtd.message"));
227 if (!istag) {
228 ColorSampleLookupValue.addColorPreviewAndCodeToLookup(element,buf);
231 if (element != null) {
232 buf.append(XmlDocumentationProvider.generateHtmlAdditionalDocTemplate(element));
235 return buf.toString();
238 public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) {
239 PsiElement result = createNavigationElementHTML(psiManager, object.toString(),element);
241 if (result== null && ourStyleProvider !=null) {
242 result = ourStyleProvider.getDocumentationElementForLookupItem(psiManager, object, element);
244 if (result== null && ourScriptProvider !=null) {
245 result = ourScriptProvider.getDocumentationElementForLookupItem(psiManager, object, element);
247 if (result == null && object instanceof String && element != null) {
248 result = XmlDocumentationProvider.findDeclWithName((String)object, element);
250 return result;
253 public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) {
254 PsiElement result = createNavigationElementHTML(psiManager, link, context);
256 if (result== null && ourStyleProvider !=null) {
257 result = ourStyleProvider.getDocumentationElementForLink(psiManager, link,context);
259 if (result== null && ourScriptProvider !=null) {
260 result = ourScriptProvider.getDocumentationElementForLink(psiManager, link,context);
262 return result;
265 public PsiElement createNavigationElementHTML(PsiManager psiManager, String text, PsiElement context) {
266 String key = text.toLowerCase();
267 final HtmlTagDescriptor descriptor = HtmlDescriptorsTable.getTagDescriptor(key);
269 if (descriptor != null && !isAttributeContext(context) ) {
270 try {
271 final XmlTag tagFromText = XmlElementFactory.getInstance(psiManager.getProject()).createTagFromText("<"+ key + " xmlns=\"" + XmlUtil.XHTML_URI + "\"/>");
272 final XmlElementDescriptor tagDescriptor = tagFromText.getDescriptor();
273 return tagDescriptor != null ? tagDescriptor.getDeclaration() : null;
275 catch(IncorrectOperationException ex) {}
277 else {
278 XmlTag tagContext = findTagContext(context);
279 HtmlAttributeDescriptor myAttributeDescriptor = getDescriptor(key,tagContext);
281 if (myAttributeDescriptor != null && tagContext != null) {
282 XmlElementDescriptor tagDescriptor = tagContext.getDescriptor();
283 XmlAttributeDescriptor attributeDescriptor = tagDescriptor != null ? tagDescriptor.getAttributeDescriptor(text, tagContext): null;
285 return (attributeDescriptor != null)?attributeDescriptor.getDeclaration():null;
288 return null;
291 protected boolean isAttributeContext(PsiElement context) {
292 if(context instanceof XmlAttribute) return true;
294 if (context instanceof PsiWhiteSpace) {
295 PsiElement prevSibling = context.getPrevSibling();
296 if (prevSibling instanceof XmlAttribute)
297 return true;
300 return false;
303 protected XmlTag findTagContext(PsiElement context) {
304 if (context instanceof PsiWhiteSpace) {
305 PsiElement prevSibling = context.getPrevSibling();
306 if (prevSibling instanceof XmlTag)
307 return (XmlTag)prevSibling;
310 return PsiTreeUtil.getParentOfType(context,XmlTag.class,false);
313 public static void setBaseHtmlExtDocUrl(String baseHtmlExtDocUrl) {
314 HtmlDocumentationProvider.ourBaseHtmlExtDocUrl = baseHtmlExtDocUrl;
317 static String getBaseHtmlExtDocUrl() {
318 return ourBaseHtmlExtDocUrl;
321 public static void registerScriptDocumentationProvider(final DocumentationProvider provider) {
322 ourScriptProvider = provider;