KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > ext > java > JavaFormatter


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.editor.ext.java;
21
22 import javax.swing.text.JTextComponent JavaDoc;
23 import javax.swing.text.BadLocationException JavaDoc;
24 import org.netbeans.editor.TokenID;
25 import org.netbeans.editor.TokenItem;
26 import org.netbeans.editor.TokenItem;
27 import org.netbeans.editor.BaseDocument;
28 import org.netbeans.editor.Utilities;
29 import org.netbeans.editor.Syntax;
30 import org.netbeans.editor.ext.AbstractFormatLayer;
31 import org.netbeans.editor.ext.FormatTokenPosition;
32 import org.netbeans.editor.ext.ExtFormatter;
33 import org.netbeans.editor.ext.FormatLayer;
34 import org.netbeans.editor.ext.FormatSupport;
35 import org.netbeans.editor.ext.ExtFormatSupport;
36 import org.netbeans.editor.ext.FormatWriter;
37 import org.netbeans.lib.editor.util.CharSequenceUtilities;
38 import org.netbeans.lib.editor.util.swing.DocumentUtilities;
39
40 /**
41 * Java indentation services are located here
42 *
43 * @author Miloslav Metelka
44 * @version 1.00
45 */

46
47 public class JavaFormatter extends ExtFormatter {
48
49     public JavaFormatter(Class JavaDoc kitClass) {
50         super(kitClass);
51     }
52
53     protected boolean acceptSyntax(Syntax syntax) {
54         return (syntax instanceof JavaSyntax);
55     }
56
57     public int[] getReformatBlock(JTextComponent JavaDoc target, String JavaDoc typedText) {
58         int[] ret = null;
59         BaseDocument doc = Utilities.getDocument(target);
60         int dotPos = target.getCaret().getDot();
61         if (doc != null) {
62             /* Check whether the user has written the ending 'e'
63              * of the first 'else' on the line.
64              */

65             if ("e".equals(typedText)) { // NOI18N
66
try {
67                     int fnw = Utilities.getRowFirstNonWhite(doc, dotPos);
68                     if (fnw >= 0 && fnw + 4 == dotPos
69                         && CharSequenceUtilities.textEquals("else", DocumentUtilities.getText(doc, fnw, 4)) // NOI18N
70
) {
71                         ret = new int[] { fnw, fnw + 4 };
72                     }
73                 } catch (BadLocationException JavaDoc e) {
74                 }
75
76             } else if (":".equals(typedText)) { // NOI18N
77
try {
78                     int fnw = Utilities.getRowFirstNonWhite(doc, dotPos);
79                     if (fnw >= 0 && fnw + 4 <= doc.getLength()
80                         && CharSequenceUtilities.textEquals("case", DocumentUtilities.getText(doc, fnw, 4)) // NOI18N
81
) {
82                         ret = new int[] { fnw, fnw + 4 };
83                     } else {
84                         if (fnw >= 0 & fnw + 7 <= doc.getLength()
85                             && CharSequenceUtilities.textEquals("default", DocumentUtilities.getText(doc, fnw, 7)) // NOI18N
86
) {
87                             ret = new int[] {fnw, fnw + 7 };
88                         }
89                     }
90                 } catch (BadLocationException JavaDoc e) {
91                 }
92             
93             } else {
94                 ret = super.getReformatBlock(target, typedText);
95             }
96         }
97         
98         return ret;
99     }
100
101     protected void initFormatLayers() {
102         addFormatLayer(new StripEndWhitespaceLayer());
103         addFormatLayer(new JavaLayer());
104     }
105
106     public FormatSupport createFormatSupport(FormatWriter fw) {
107         return new JavaFormatSupport(fw);
108     }
109
110     public class StripEndWhitespaceLayer extends AbstractFormatLayer {
111
112         public StripEndWhitespaceLayer() {
113             super("java-strip-whitespace-at-line-end"); // NOI18N
114
}
115
116         protected FormatSupport createFormatSupport(FormatWriter fw) {
117             return new JavaFormatSupport(fw);
118         }
119
120         public void format(FormatWriter fw) {
121             JavaFormatSupport jfs = (JavaFormatSupport)createFormatSupport(fw);
122
123             FormatTokenPosition pos = jfs.getFormatStartPosition();
124             if (jfs.isIndentOnly()) { // don't do anything
125

126             } else { // remove end-line whitespace
127
while (pos.getToken() != null) {
128                     FormatTokenPosition startPos = pos;
129                     pos = jfs.removeLineEndWhitespace(pos);
130                     if (pos.getToken() != null) {
131                         pos = jfs.getNextPosition(pos);
132                     }
133                     // fix for issue 14725
134
// this is more hack than correct fix. It happens that
135
// jfs.removeLineEndWhitespace() does not move to next
136
// position. The reason is that token from which the
137
// endline whitespaces must be removed is not 'modifiable' -
138
// FormatWritter.canModifyToken() returns false in
139
// FormatWritter.remove. I don't dare to fix this problem
140
// in ExtFormatSupport and so I'm patching this
141
// loop to check whether we are still on the same position
142
// and if we are, let's do break. If similar problem reappear
143
// we will have to find better fix. Hopefully, with the planned
144
// conversion of indentation engines to new lexel module
145
// all this code will be replaced in next verison.
146
if (startPos.equals(pos)) {
147                         break;
148                     }
149                 }
150             }
151         }
152
153     }
154
155     public class JavaLayer extends AbstractFormatLayer {
156
157         public JavaLayer() {
158             super("java-layer"); // NOI18N
159
}
160
161         protected FormatSupport createFormatSupport(FormatWriter fw) {
162             return new JavaFormatSupport(fw);
163         }
164
165         public void format(FormatWriter fw) {
166             try {
167                 JavaFormatSupport jfs = (JavaFormatSupport)createFormatSupport(fw);
168
169                 FormatTokenPosition pos = jfs.getFormatStartPosition();
170
171                 if (jfs.isIndentOnly()) { // create indentation only
172
jfs.indentLine(pos);
173
174                 } else { // regular formatting
175

176                     while (pos != null) {
177
178                         // Indent the current line
179
jfs.indentLine(pos);
180
181                         // Format the line by additional rules
182
formatLine(jfs, pos);
183
184                         // Goto next line
185
FormatTokenPosition pos2 = jfs.findLineEnd(pos);
186                         if (pos2 == null || pos2.getToken() == null)
187                             break; // the last line was processed
188

189                         pos = jfs.getNextPosition(pos2, javax.swing.text.Position.Bias.Forward);
190                         if (pos == pos2)
191                             break; // in case there is no next position
192
if (pos == null || pos.getToken() == null)
193                             break; // there is nothing after the end of line
194

195                         FormatTokenPosition fnw = jfs.findLineFirstNonWhitespace(pos);
196                         if (fnw != null) {
197                           pos = fnw;
198                         } else { // no non-whitespace char on the line
199
pos = jfs.findLineStart(pos);
200                         }
201                     }
202                 }
203             } catch (IllegalStateException JavaDoc e) {
204             }
205         }
206
207
208         private void removeLineBeforeToken(TokenItem token, JavaFormatSupport jfs, boolean checkRBraceBefore){
209             FormatTokenPosition tokenPos = jfs.getPosition(token, 0);
210             // Check that nothing exists before token
211
if (jfs.findNonWhitespace(tokenPos, null, true, true) != null){
212                 return;
213             }
214
215             // Check that the backward nonWhite is }
216
if (checkRBraceBefore){
217                 FormatTokenPosition ftpos = jfs.findNonWhitespace(tokenPos, null, false, true);
218                 if (ftpos == null || ftpos.getToken().getTokenID().getNumericID() != JavaTokenContext.RBRACE_ID){
219                     return;
220                 }
221             }
222             
223             // Check that nothing exists after token, but ignore comments
224
if (jfs.getNextPosition(tokenPos) != null){
225                 FormatTokenPosition ftp = jfs.findImportant(jfs.getNextPosition(tokenPos), null, true, false);
226                 if (ftp != null){
227                     insertNewLineBeforeToken(ftp.getToken(), jfs);
228                 }
229             }
230
231             // check that on previous line is some stmt
232
FormatTokenPosition ftp = jfs.findLineStart(tokenPos); // find start of current line
233
FormatTokenPosition endOfPreviousLine = jfs.getPreviousPosition(ftp); // go one position back - means previous line
234
if (endOfPreviousLine == null || endOfPreviousLine.getToken().getTokenID() != JavaTokenContext.WHITESPACE){
235                 return;
236             }
237             ftp = jfs.findLineStart(endOfPreviousLine); // find start of the previous line - now we have limit position
238
ftp = jfs.findImportant(tokenPos, ftp, false, true); // find something important till the limit
239
if (ftp == null){
240                 return;
241             }
242
243             // check that previous line does not end with "{" or line comment
244
ftp = jfs.findNonWhitespace(endOfPreviousLine, null, true, true);
245             if (ftp.getToken().getTokenID() == JavaTokenContext.LINE_COMMENT ||
246                 ftp.getToken().getTokenID() == JavaTokenContext.LBRACE){
247                 return;
248             }
249
250             // now move the token to the end of previous line
251
boolean remove = true;
252             while (remove)
253             {
254                 if (token.getPrevious() == endOfPreviousLine.getToken()){
255                     remove = false;
256                 }
257                 if (jfs.canRemoveToken(token.getPrevious())){
258                     jfs.removeToken(token.getPrevious());
259                 }else{
260                     return; // should never get here!
261
}
262             }
263             // insert one space before token
264
if (jfs.canInsertToken(token)){
265                 jfs.insertSpaces(token, 1);
266             }
267         
268         }
269         
270         /** insertNewLineBeforeKeyword such as else, catch, finally
271          * if getFormatNewlineBeforeBrace is true
272          */

273         private void insertNewLineBeforeToken(TokenItem token, JavaFormatSupport jfs){
274             FormatTokenPosition elsePos = jfs.getPosition(token, 0);
275             FormatTokenPosition imp = jfs.findImportant(elsePos,
276                     null, true, true); // stop on line start
277
if (imp != null && imp.getToken().getTokenContextPath()
278                                     == jfs.getTokenContextPath()
279             ) {
280                 // Insert new-line
281
if (jfs.canInsertToken(token)) {
282                     jfs.insertToken(token, jfs.getValidWhitespaceTokenID(),
283                         jfs.getValidWhitespaceTokenContextPath(), "\n"); // NOI18N
284
jfs.removeLineEndWhitespace(imp);
285                     // reindent newly created line
286
jfs.indentLine(elsePos);
287                 }
288             }
289         }
290         
291         protected void formatLine(JavaFormatSupport jfs, FormatTokenPosition pos) {
292             TokenItem token = jfs.findLineStart(pos).getToken();
293             while (token != null) {
294 /* if (jfs.findLineEnd(jfs.getPosition(token, 0)).getToken() == token) {
295                     break; // at line end
296                 }
297  */

298
299                 if (token.getTokenContextPath() == jfs.getTokenContextPath()) {
300                     switch (token.getTokenID().getNumericID()) {
301                         case JavaTokenContext.ELSE_ID: //else
302
if (jfs.getFormatNewlineBeforeBrace()) {
303                                 // add a new line before else, if getFormatNewlineBeforeBrace
304
insertNewLineBeforeToken(token, jfs);
305                             } else {
306                                 removeLineBeforeToken(token, jfs, true);
307                             }
308                             break;
309                         case JavaTokenContext.CATCH_ID: //catch
310
if (jfs.getFormatNewlineBeforeBrace()) {
311                                 // add a new line before catch, if getFormatNewlineBeforeBrace
312
insertNewLineBeforeToken(token, jfs);
313                             } else {
314                                 removeLineBeforeToken(token, jfs, true);
315                             }
316                             break;
317                         case JavaTokenContext.FINALLY_ID: //finally
318
if (jfs.getFormatNewlineBeforeBrace()) {
319                                 // add a new line before finally, if getFormatNewlineBeforeBrace
320
insertNewLineBeforeToken(token, jfs);
321                             } else {
322                                 removeLineBeforeToken(token, jfs, true);
323                             }
324                             break;
325                         case JavaTokenContext.LBRACE_ID: // '{'
326
if (!jfs.isIndentOnly()) {
327                             if (jfs.getFormatNewlineBeforeBrace()) {
328                                 FormatTokenPosition lbracePos = jfs.getPosition(token, 0);
329                                 // Look for first important token in backward direction
330
FormatTokenPosition imp = jfs.findImportant(lbracePos,
331                                         null, true, true); // stop on line start
332
if (imp != null && imp.getToken().getTokenContextPath()
333                                                         == jfs.getTokenContextPath()
334                                 ) {
335                                     switch (imp.getToken().getTokenID().getNumericID()) {
336                                         case JavaTokenContext.BLOCK_COMMENT_ID:
337                                         case JavaTokenContext.LINE_COMMENT_ID:
338                                             break; // comments are ignored
339

340                                         case JavaTokenContext.RBRACKET_ID:
341                                             break; // array initializtion "ttt [] {...}"
342

343                                         case JavaTokenContext.COMMA_ID:
344                                         case JavaTokenContext.EQ_ID:
345                                         case JavaTokenContext.LBRACE_ID:
346                                             // multi array initialization
347
// static int[][] CONVERT_TABLE= { {3,5},
348
// {1,2}, {2,3}, ...
349
break;
350                                             
351
352                                         default:
353                                             // Check whether it isn't a "{ }" case
354
FormatTokenPosition next = jfs.findImportant(
355                                                     lbracePos, null, true, false);
356                                             if (next == null || next.getToken() == null
357                                                 || next.getToken().getTokenID() != JavaTokenContext.RBRACE
358                                             ) {
359                                                 // Insert new-line
360
if (jfs.canInsertToken(token)) {
361                                                     jfs.insertToken(token, jfs.getValidWhitespaceTokenID(),
362                                                         jfs.getValidWhitespaceTokenContextPath(), "\n"); // NOI18N
363
jfs.removeLineEndWhitespace(imp);
364                                                     // bug fix: 10225 - reindent newly created line
365
jfs.indentLine(lbracePos);
366                                                 }
367
368                                                 //token = imp.getToken();
369
}
370                                             break;
371                                     }
372                                 }
373
374                             } else {
375                                 //remove line before token if applicable
376
FormatTokenPosition tokenPos = jfs.getPosition(token, 0);
377                                 FormatTokenPosition ftpos = jfs.findNonWhitespace(tokenPos, null, false, true);
378                                 if (ftpos != null){
379                                     switch (ftpos.getToken().getTokenID().getNumericID()) {
380                                         case JavaTokenContext.RPAREN_ID: // ) {
381
case JavaTokenContext.IDENTIFIER_ID: // public class Hello {
382
case JavaTokenContext.ELSE_ID:
383                                         case JavaTokenContext.FINALLY_ID:
384                                         case JavaTokenContext.TRY_ID:
385                                             removeLineBeforeToken(token, jfs, false);
386                                             break;
387                                     }
388                                 }
389                             }
390                             } // !jfs.isIndentOnly()
391
break;
392
393                         case JavaTokenContext.LPAREN_ID:
394                             if (jfs.getFormatSpaceBeforeParenthesis()) {
395                                 TokenItem prevToken = token.getPrevious();
396                                 if (prevToken != null &&
397                                     (prevToken.getTokenID() == JavaTokenContext.IDENTIFIER ||
398                                     prevToken.getTokenID() == JavaTokenContext.THIS ||
399                                     prevToken.getTokenID() == JavaTokenContext.SUPER) ) {
400                                     if (jfs.canInsertToken(token)) {
401                                         jfs.insertToken(token, jfs.getWhitespaceTokenID(),
402                                             jfs.getWhitespaceTokenContextPath(), " "); // NOI18N
403
}
404                                 }
405                             } else {
406                                 // bugfix 9813: remove space before left parenthesis
407
TokenItem prevToken = token.getPrevious();
408                                 if (prevToken != null && prevToken.getTokenID() == JavaTokenContext.WHITESPACE &&
409                                         prevToken.getImage().length() == 1) {
410                                     TokenItem prevprevToken = prevToken.getPrevious();
411                                     if (prevprevToken != null &&
412                                         (prevprevToken.getTokenID() == JavaTokenContext.IDENTIFIER ||
413                                         prevprevToken.getTokenID() == JavaTokenContext.THIS ||
414                                         prevprevToken.getTokenID() == JavaTokenContext.SUPER) )
415                                     {
416                                         if (jfs.canRemoveToken(prevToken)) {
417                                             jfs.removeToken(prevToken);
418                                         }
419                                     }
420                                 }
421                                 
422                             }
423                             break;
424                     }
425                 }
426
427                 token = token.getNext();
428             }
429         }
430
431     }
432
433 }
434
Popular Tags