KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > text > comment > JavaDocRegion


1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.ui.text.comment;
13
14 import java.io.IOException JavaDoc;
15 import java.io.StringReader JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.Map JavaDoc;
19
20 import org.eclipse.text.edits.TextEdit;
21
22 import org.eclipse.jface.preference.IPreferenceStore;
23
24 import org.eclipse.jface.text.BadLocationException;
25 import org.eclipse.jface.text.ConfigurableLineTracker;
26 import org.eclipse.jface.text.IDocument;
27 import org.eclipse.jface.text.ILineTracker;
28 import org.eclipse.jface.text.Position;
29 import org.eclipse.jface.text.TextUtilities;
30 import org.eclipse.jface.text.TypedPosition;
31
32 import org.eclipse.jdt.core.formatter.CodeFormatter;
33
34 import org.eclipse.jdt.ui.PreferenceConstants;
35
36 import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
37
38 import org.eclipse.jdt.internal.ui.JavaPlugin;
39 import org.eclipse.jdt.internal.ui.text.javadoc.IJavaDocTagConstants;
40
41 /**
42  * Javadoc region in a source code document.
43  *
44  * @since 3.0
45  */

46 public class JavaDocRegion extends MultiCommentRegion implements IJavaDocTagConstants {
47
48     /** The positions of code ranges */
49     private final ArrayList JavaDoc fCodePositions= new ArrayList JavaDoc();
50      
51     /** Should HTML tags be formatted? */
52     private final boolean fFormatHtml;
53
54     /** Should source code regions be formatted? */
55     private final boolean fFormatSource;
56     
57     /**
58      * Creates a new Javadoc region.
59      *
60      * @param document
61      * The document which contains the comment region
62      * @param position
63      * The position of this comment region in the document
64      * @param delimiter
65      * The line delimiter of this comment region
66      * @param preferences
67      * The formatting preferences for this region
68      * @param textMeasurement
69      * The text measurement. Can be <code>null</code>.
70      */

71     protected JavaDocRegion(final IDocument document, final TypedPosition position, final String JavaDoc delimiter, final Map JavaDoc preferences, final ITextMeasurement textMeasurement) {
72         super(document, position, delimiter, preferences, textMeasurement);
73
74         fFormatSource= IPreferenceStore.TRUE.equals(preferences.get(PreferenceConstants.FORMATTER_COMMENT_FORMATSOURCE));
75         fFormatHtml= IPreferenceStore.TRUE.equals(preferences.get(PreferenceConstants.FORMATTER_COMMENT_FORMATHTML));
76     }
77
78     /**
79      * @inheritDoc
80      */

81     protected boolean canFormat(final CommentRange previous, final CommentRange next) {
82         
83         if (previous != null) {
84             
85             final boolean isCurrentCode= next.hasAttribute(COMMENT_CODE);
86             final boolean isLastCode= previous.hasAttribute(COMMENT_CODE);
87             
88             final int base= getOffset();
89             
90             if (!isLastCode && isCurrentCode)
91                 fCodePositions.add(new Position(base + previous.getOffset()));
92             else if (isLastCode && !isCurrentCode)
93                 fCodePositions.add(new Position(base + next.getOffset() + next.getLength()));
94             
95             if (previous.hasAttribute(COMMENT_IMMUTABLE) && next.hasAttribute(COMMENT_IMMUTABLE))
96                 return false;
97             
98             
99         }
100         return true;
101     }
102
103     /**
104      * @inheritDoc
105      */

106     protected final void formatRegion(final String JavaDoc indentation, final int width) {
107     
108         super.formatRegion(indentation, width);
109         
110         if (fFormatSource) {
111             
112             try {
113                 
114                 if (fCodePositions.size() > 0) {
115                     
116                     int begin= 0;
117                     int end= 0;
118                     
119                     Position position= null;
120                     
121                     final IDocument document= getDocument();
122                     
123                     for (int index= fCodePositions.size() - 1; index >= 0;) {
124                         
125                         position= (Position)fCodePositions.get(index--);
126                         begin= position.getOffset();
127                         
128                         if (index >= 0) {
129                             position= (Position)fCodePositions.get(index--);
130                             end= position.getOffset();
131                         } else {
132                             /*
133                              * Handle missing closing tag
134                              * see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=57011
135                              */

136                             position= null;
137                             end= getOffset() + getLength() - MultiCommentLine.MULTI_COMMENT_END_PREFIX.trim().length();
138                             while (end > begin && Character.isWhitespace(document.getChar(end - 1)))
139                                 end--;
140                         }
141                         
142                         String JavaDoc snippet= document.get(begin, end - begin);
143                         snippet= preprocessCodeSnippet(snippet);
144                         snippet= formatCodeSnippet(snippet);
145                         snippet= postprocessCodeSnippet(snippet, indentation);
146                         
147                         logEdit(snippet, begin - getOffset(), end - begin);
148                     }
149                 }
150             } catch (BadLocationException e) {
151                 // Can not happen
152
JavaPlugin.log(e);
153             }
154         }
155     }
156
157     /**
158      * Preprocess a given code snippet.
159      * @param snippet The code snippet
160      * @return The preprocessed code snippet
161      */

162     private String JavaDoc preprocessCodeSnippet(String JavaDoc snippet) {
163         // strip content prefix
164
StringBuffer JavaDoc buffer= new StringBuffer JavaDoc();
165         ILineTracker tracker= new ConfigurableLineTracker(new String JavaDoc[] { getDelimiter()});
166         String JavaDoc contentPrefix= MultiCommentLine.MULTI_COMMENT_CONTENT_PREFIX.trim();
167         
168         buffer.setLength(0);
169         buffer.append(snippet);
170         tracker.set(snippet);
171         for (int line= tracker.getNumberOfLines() - 1; line > 0; line--) {
172             int lineOffset;
173             try {
174                 lineOffset= tracker.getLineOffset(line);
175             } catch (BadLocationException e) {
176                 // Can not happen
177
JavaPlugin.log(e);
178                 return snippet;
179             }
180             int prefixOffset= buffer.indexOf(contentPrefix, lineOffset);
181             if (prefixOffset >= 0 && buffer.substring(lineOffset, prefixOffset).trim().length() == 0)
182                 buffer.delete(lineOffset, prefixOffset + contentPrefix.length());
183         }
184         
185         return convertHtml2Java(buffer.toString());
186     }
187
188     /**
189      * Format the given code snippet
190      * @param snippet The code snippet
191      * @return The formatted code snippet
192      */

193     private String JavaDoc formatCodeSnippet(String JavaDoc snippet) {
194         String JavaDoc lineDelimiter= TextUtilities.getDefaultLineDelimiter(getDocument());
195         TextEdit edit= CodeFormatterUtil.format2(CodeFormatter.K_UNKNOWN, snippet, 0, lineDelimiter, getPreferences());
196         if (edit != null)
197             snippet= CodeFormatterUtil.evaluateFormatterEdit(snippet, edit, null);
198         return snippet;
199     }
200
201     /**
202      * Postprocesses the given code snippet with the given indentation.
203      * @param snippet The code snippet
204      * @param indentation The indentation
205      * @return The postprocessed code snippet
206      */

207     private String JavaDoc postprocessCodeSnippet(String JavaDoc snippet, String JavaDoc indentation) {
208         // patch content prefix
209
StringBuffer JavaDoc buffer= new StringBuffer JavaDoc();
210         ILineTracker tracker= new ConfigurableLineTracker(new String JavaDoc[] { getDelimiter()});
211         String JavaDoc patch= indentation + MultiCommentLine.MULTI_COMMENT_CONTENT_PREFIX;
212
213         buffer.setLength(0);
214         buffer.append(getDelimiter());
215         buffer.append(convertJava2Html(snippet));
216         buffer.append(getDelimiter());
217         tracker.set(buffer.toString());
218         
219         for (int line= tracker.getNumberOfLines() - 1; line > 0; line--)
220             try {
221                 buffer.insert(tracker.getLineOffset(line), patch);
222             } catch (BadLocationException e) {
223                 // Can not happen
224
JavaPlugin.log(e);
225                 return snippet;
226             }
227         
228         return buffer.toString();
229     }
230
231     /**
232      * @inheritDoc
233      */

234     protected final void markHtmlRanges() {
235
236         markTagRanges(JAVADOC_IMMUTABLE_TAGS, COMMENT_IMMUTABLE, true);
237
238         if (fFormatSource)
239             markTagRanges(JAVADOC_CODE_TAGS, COMMENT_CODE, false);
240     }
241
242     /**
243      * @inheritDoc
244      */

245     protected final void markHtmlTag(final CommentRange range, final String JavaDoc token) {
246
247         if (range.hasAttribute(COMMENT_HTML)) {
248
249             range.markHtmlTag(JAVADOC_IMMUTABLE_TAGS, token, COMMENT_IMMUTABLE, true, true);
250             if (fFormatHtml) {
251
252                 range.markHtmlTag(JAVADOC_SEPARATOR_TAGS, token, COMMENT_SEPARATOR, true, true);
253                 range.markHtmlTag(JAVADOC_BREAK_TAGS, token, COMMENT_BREAK, false, true);
254                 range.markHtmlTag(JAVADOC_SINGLE_BREAK_TAG, token, COMMENT_BREAK, true, false);
255                 range.markHtmlTag(JAVADOC_NEWLINE_TAGS, token, COMMENT_NEWLINE, true, false);
256
257             } else
258                 range.markHtmlTag(JAVADOC_CODE_TAGS, token, COMMENT_SEPARATOR, true, true);
259         }
260     }
261
262     /**
263      * @inheritDoc
264      */

265     protected final void markJavadocTag(final CommentRange range, final String JavaDoc token) {
266
267         range.markPrefixTag(JAVADOC_PARAM_TAGS, COMMENT_TAG_PREFIX, token, COMMENT_PARAMETER);
268
269         if (token.charAt(0) == JAVADOC_TAG_PREFIX && !range.hasAttribute(COMMENT_PARAMETER))
270             range.setAttribute(COMMENT_ROOT);
271     }
272
273     /**
274      * Marks the comment region with the HTML range tag.
275      *
276      * @param tags the HTML tag which confines the HTML range
277      * @param attribute the attribute to set if the comment range is in the HTML range
278      * @param html <code>true</code> iff the HTML tags in this HTML range
279      * should be marked too, <code>false</code> otherwise
280      */

281     protected final void markTagRanges(final String JavaDoc[] tags, final int attribute, final boolean html) {
282         
283         int level= 0;
284         int count= 0;
285         String JavaDoc token= null;
286         CommentRange current= null;
287         
288         for (int index= 0; index < tags.length; index++) {
289             
290             level= 0;
291             for (final Iterator JavaDoc iterator= getRanges().iterator(); iterator.hasNext();) {
292                 
293                 current= (CommentRange)iterator.next();
294                 count= current.getLength();
295                 
296                 if (count > 0 || level > 0) { // PR44035: when inside a tag, mark blank lines as well to get proper snippet formatting
297

298                     token= getText(current.getOffset(), current.getLength());
299                     level= current.markTagRange(token, tags[index], level, attribute, html);
300                 }
301             }
302         }
303     }
304
305     /**
306      * @inheritDoc
307      */

308     protected boolean canAppend(CommentLine line, CommentRange previous, CommentRange next, int index, int count) {
309         // don't append code sections
310
if (next.hasAttribute(COMMENT_CODE | COMMENT_FIRST_TOKEN) && line.getSize() != 0)
311             return false;
312         return super.canAppend(line, previous, next, index, count);
313     }
314
315     /**
316      * Converts <code>formatted</code> into valid html code suitable to be
317      * put inside &lt;pre&gt;&lt;/pre&gt; tags by replacing any html symbols by
318      * the relevant entities.
319      *
320      * @param formatted the formatted java code
321      * @return html version of the formatted code
322      */

323     private String JavaDoc convertJava2Html(String JavaDoc formatted) {
324         Java2HTMLEntityReader reader= new Java2HTMLEntityReader(new StringReader JavaDoc(formatted));
325         char[] buf= new char[256];
326         StringBuffer JavaDoc buffer= new StringBuffer JavaDoc();
327         int l;
328         try {
329             do {
330                 l= reader.read(buf);
331                 if (l != -1)
332                     buffer.append(buf, 0, l);
333             } while (l > 0);
334             return buffer.toString();
335         } catch (IOException JavaDoc e) {
336             return formatted;
337         }
338     }
339
340     /**
341      * Converts <code>html</code> into java code suitable for formatting by
342      * replacing any html entities by their plain text representation.
343      *
344      * @param html html code, may contain html entities
345      * @return plain textified version of <code>html</code>
346      */

347     private String JavaDoc convertHtml2Java(String JavaDoc html) {
348         HTMLEntity2JavaReader reader= new HTMLEntity2JavaReader(new StringReader JavaDoc(html));
349         char[] buf= new char[html.length()]; // html2text never gets longer, only shorter!
350

351         try {
352             int read= reader.read(buf);
353             return new String JavaDoc(buf, 0, read);
354         } catch (IOException JavaDoc e) {
355             return html;
356         }
357     }
358 }
359
Popular Tags