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
;
40 * Created by IntelliJ IDEA.
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
;
60 public String
getQuickNavigateInfo(PsiElement element
) {
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();
84 private EntityDescriptor
findDocumentationDescriptor(PsiElement element
, XmlTag context
) {
86 PsiElement nameElement
= null;
89 if (element
instanceof XmlElementDecl
) {
90 nameElement
= ((XmlElementDecl
)element
).getNameElement();
91 } else if (element
instanceof XmlAttributeDecl
) {
92 nameElement
= ((XmlAttributeDecl
)element
).getNameElement();
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
) {
101 key
= ((XmlAttribute
)element
.getParent().getParent()).getName();
102 } else if (element
instanceof XmlAttributeValue
) {
104 final XmlAttribute xmlAttribute
= (XmlAttribute
)element
.getParent();
105 key
= xmlAttribute
.getName();
106 } else if (element
instanceof XmlAttribute
) {
107 final XmlAttribute xmlAttribute
= (XmlAttribute
)element
;
109 key
= xmlAttribute
.getName();
111 nameElement
= element
;
112 isTag
= !(element
.getParent() instanceof XmlAttribute
);
115 if (nameElement
!=null) {
116 key
= nameElement
.getText();
119 key
= (key
!= null)?key
.toLowerCase():"";
122 return HtmlDescriptorsTable
.getTagDescriptor(key
);
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
);
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());
175 private static String
generateJavaDoc(EntityDescriptor descriptor
, boolean ommitHtmlSpecifics
, PsiElement element
) {
176 StringBuilder buf
= new StringBuilder();
177 final boolean istag
= descriptor
instanceof HtmlTagDescriptor
;
180 DocumentationUtil
.formatEntityName(XmlBundle
.message("xml.javadoc.tag.name.message"),descriptor
.getName(),buf
);
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
);
188 final HtmlTagDescriptor tagDescriptor
= (HtmlTagDescriptor
)descriptor
;
190 if (!ommitHtmlSpecifics
) {
191 boolean hasStartTag
= tagDescriptor
.isHasStartTag();
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
);
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
;
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"));
224 buf
.append(XmlBundle
.message("xml.javadoc.defined.in.any.dtd.message"));
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
);
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
);
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
) ) {
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
) {}
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;
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
)
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
;