Source Code Cross Referenced for SmartSemicolonAutoEditStrategy.java in  » IDE-Eclipse » jdt » org » eclipse » jdt » internal » ui » text » java » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » jdt » org.eclipse.jdt.internal.ui.text.java 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2006 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *******************************************************************************/package org.eclipse.jdt.internal.ui.text.java;
0011:
0012:        import java.util.Arrays;
0013:
0014:        import org.eclipse.text.edits.DeleteEdit;
0015:        import org.eclipse.text.edits.MalformedTreeException;
0016:        import org.eclipse.text.edits.ReplaceEdit;
0017:        import org.eclipse.text.edits.TextEdit;
0018:
0019:        import org.eclipse.core.runtime.Assert;
0020:
0021:        import org.eclipse.jface.preference.IPreferenceStore;
0022:
0023:        import org.eclipse.jface.text.BadLocationException;
0024:        import org.eclipse.jface.text.DocumentCommand;
0025:        import org.eclipse.jface.text.IAutoEditStrategy;
0026:        import org.eclipse.jface.text.IDocument;
0027:        import org.eclipse.jface.text.IRegion;
0028:        import org.eclipse.jface.text.ITextSelection;
0029:        import org.eclipse.jface.text.ITypedRegion;
0030:        import org.eclipse.jface.text.Region;
0031:        import org.eclipse.jface.text.TextSelection;
0032:        import org.eclipse.jface.text.TextUtilities;
0033:
0034:        import org.eclipse.ui.IEditorPart;
0035:        import org.eclipse.ui.IWorkbenchPage;
0036:        import org.eclipse.ui.texteditor.ITextEditorExtension2;
0037:        import org.eclipse.ui.texteditor.ITextEditorExtension3;
0038:
0039:        import org.eclipse.jdt.ui.PreferenceConstants;
0040:        import org.eclipse.jdt.ui.text.IJavaPartitions;
0041:
0042:        import org.eclipse.jdt.internal.ui.JavaPlugin;
0043:        import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
0044:        import org.eclipse.jdt.internal.ui.text.SmartBackspaceManager;
0045:        import org.eclipse.jdt.internal.ui.text.SmartBackspaceManager.UndoSpec;
0046:
0047:        /**
0048:         * Modifies <code>DocumentCommand</code>s inserting semicolons and opening braces to place them
0049:         * smartly, i.e. moving them to the end of a line if that is what the user expects.
0050:         *
0051:         * <p>In practice,  semicolons and braces (and the caret) are moved to the end of the line if they are typed
0052:         * anywhere except for semicolons in a <code>for</code> statements definition. If the line contains a semicolon
0053:         * or brace after the current caret position, the cursor is moved after it.</p>
0054:         *
0055:         * @see org.eclipse.jface.text.DocumentCommand
0056:         * @since 3.0
0057:         */
0058:        public class SmartSemicolonAutoEditStrategy implements 
0059:                IAutoEditStrategy {
0060:
0061:            /** String representation of a semicolon. */
0062:            private static final String SEMICOLON = ";"; //$NON-NLS-1$
0063:            /** Char representation of a semicolon. */
0064:            private static final char SEMICHAR = ';';
0065:            /** String represenattion of a opening brace. */
0066:            private static final String BRACE = "{"; //$NON-NLS-1$
0067:            /** Char representation of a opening brace */
0068:            private static final char BRACECHAR = '{';
0069:
0070:            private char fCharacter;
0071:            private String fPartitioning;
0072:
0073:            /**
0074:             * Creates a new SmartSemicolonAutoEditStrategy.
0075:             *
0076:             * @param partitioning the document partitioning
0077:             */
0078:            public SmartSemicolonAutoEditStrategy(String partitioning) {
0079:                fPartitioning = partitioning;
0080:            }
0081:
0082:            /*
0083:             * @see org.eclipse.jface.text.IAutoEditStrategy#customizeDocumentCommand(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.DocumentCommand)
0084:             */
0085:            public void customizeDocumentCommand(IDocument document,
0086:                    DocumentCommand command) {
0087:                // 0: early pruning
0088:                // also customize if <code>doit</code> is false (so it works in code completion situations)
0089:                //		if (!command.doit)
0090:                //			return;
0091:
0092:                if (command.text == null)
0093:                    return;
0094:
0095:                if (command.text.equals(SEMICOLON))
0096:                    fCharacter = SEMICHAR;
0097:                else if (command.text.equals(BRACE))
0098:                    fCharacter = BRACECHAR;
0099:                else
0100:                    return;
0101:
0102:                IPreferenceStore store = JavaPlugin.getDefault()
0103:                        .getPreferenceStore();
0104:                if (fCharacter == SEMICHAR
0105:                        && !store
0106:                                .getBoolean(PreferenceConstants.EDITOR_SMART_SEMICOLON))
0107:                    return;
0108:                if (fCharacter == BRACECHAR
0109:                        && !store
0110:                                .getBoolean(PreferenceConstants.EDITOR_SMART_OPENING_BRACE))
0111:                    return;
0112:
0113:                IWorkbenchPage page = JavaPlugin.getActivePage();
0114:                if (page == null)
0115:                    return;
0116:                IEditorPart part = page.getActiveEditor();
0117:                if (!(part instanceof  CompilationUnitEditor))
0118:                    return;
0119:                CompilationUnitEditor editor = (CompilationUnitEditor) part;
0120:                if (editor.getInsertMode() != ITextEditorExtension3.SMART_INSERT
0121:                        || !editor.isEditable())
0122:                    return;
0123:                ITextEditorExtension2 extension = (ITextEditorExtension2) editor
0124:                        .getAdapter(ITextEditorExtension2.class);
0125:                if (extension != null && !extension.validateEditorInputState())
0126:                    return;
0127:                if (isMultilineSelection(document, command))
0128:                    return;
0129:
0130:                // 1: find concerned line / position in java code, location in statement
0131:                int pos = command.offset;
0132:                ITextSelection line;
0133:                try {
0134:                    IRegion l = document.getLineInformationOfOffset(pos);
0135:                    line = new TextSelection(document, l.getOffset(), l
0136:                            .getLength());
0137:                } catch (BadLocationException e) {
0138:                    return;
0139:                }
0140:
0141:                // 2: choose action based on findings (is for-Statement?)
0142:                // for now: compute the best position to insert the new character
0143:                int positionInLine = computeCharacterPosition(document, line,
0144:                        pos - line.getOffset(), fCharacter, fPartitioning);
0145:                int position = positionInLine + line.getOffset();
0146:
0147:                // never position before the current position!
0148:                if (position < pos)
0149:                    return;
0150:
0151:                // never double already existing content
0152:                if (alreadyPresent(document, fCharacter, position))
0153:                    return;
0154:
0155:                // don't do special processing if what we do is actually the normal behaviour
0156:                String insertion = adjustSpacing(document, position, fCharacter);
0157:                if (command.offset == position
0158:                        && insertion.equals(command.text))
0159:                    return;
0160:
0161:                try {
0162:
0163:                    final SmartBackspaceManager manager = (SmartBackspaceManager) editor
0164:                            .getAdapter(SmartBackspaceManager.class);
0165:                    if (manager != null
0166:                            && JavaPlugin
0167:                                    .getDefault()
0168:                                    .getPreferenceStore()
0169:                                    .getBoolean(
0170:                                            PreferenceConstants.EDITOR_SMART_BACKSPACE)) {
0171:                        TextEdit e1 = new ReplaceEdit(command.offset,
0172:                                command.text.length(), document.get(
0173:                                        command.offset, command.length));
0174:                        UndoSpec s1 = new UndoSpec(command.offset
0175:                                + command.text.length(), new Region(
0176:                                command.offset, 0), new TextEdit[] { e1 }, 0,
0177:                                null);
0178:
0179:                        DeleteEdit smart = new DeleteEdit(position, insertion
0180:                                .length());
0181:                        ReplaceEdit raw = new ReplaceEdit(command.offset,
0182:                                command.length, command.text);
0183:                        UndoSpec s2 = new UndoSpec(position
0184:                                + insertion.length(), new Region(command.offset
0185:                                + command.text.length(), 0), new TextEdit[] {
0186:                                smart, raw }, 2, s1);
0187:                        manager.register(s2);
0188:                    }
0189:
0190:                    // 3: modify command
0191:                    command.offset = position;
0192:                    command.length = 0;
0193:                    command.caretOffset = position;
0194:                    command.text = insertion;
0195:                    command.doit = true;
0196:                    command.owner = null;
0197:                } catch (MalformedTreeException e) {
0198:                    JavaPlugin.log(e);
0199:                } catch (BadLocationException e) {
0200:                    JavaPlugin.log(e);
0201:                }
0202:
0203:            }
0204:
0205:            /**
0206:             * Returns <code>true</code> if the document command is applied on a multi
0207:             * line selection, <code>false</code> otherwise.
0208:             *
0209:             * @param document the document
0210:             * @param command the command
0211:             * @return <code>true</code> if <code>command</code> is a multiline command
0212:             */
0213:            private boolean isMultilineSelection(IDocument document,
0214:                    DocumentCommand command) {
0215:                try {
0216:                    return document.getNumberOfLines(command.offset,
0217:                            command.length) > 1;
0218:                } catch (BadLocationException e) {
0219:                    // ignore
0220:                    return false;
0221:                }
0222:            }
0223:
0224:            /**
0225:             * Adds a space before a brace if it is inserted after a parenthesis, equal sign, or one
0226:             * of the keywords <code>try, else, do</code>.
0227:             *
0228:             * @param doc the document we are working on
0229:             * @param position the insert position of <code>character</code>
0230:             * @param character the character to be inserted
0231:             * @return a <code>String</code> consisting of <code>character</code> plus any additional spacing
0232:             */
0233:            private String adjustSpacing(IDocument doc, int position,
0234:                    char character) {
0235:                if (character == BRACECHAR) {
0236:                    if (position > 0 && position <= doc.getLength()) {
0237:                        int pos = position - 1;
0238:                        if (looksLike(doc, pos, ")") //$NON-NLS-1$
0239:                                || looksLike(doc, pos, "=") //$NON-NLS-1$
0240:                                || looksLike(doc, pos, "]") //$NON-NLS-1$
0241:                                || looksLike(doc, pos, "try") //$NON-NLS-1$
0242:                                || looksLike(doc, pos, "else") //$NON-NLS-1$
0243:                                || looksLike(doc, pos, "synchronized") //$NON-NLS-1$
0244:                                || looksLike(doc, pos, "static") //$NON-NLS-1$
0245:                                || looksLike(doc, pos, "finally") //$NON-NLS-1$
0246:                                || looksLike(doc, pos, "do")) //$NON-NLS-1$
0247:                            return new String(new char[] { ' ', character });
0248:                    }
0249:                }
0250:
0251:                return new String(new char[] { character });
0252:            }
0253:
0254:            /**
0255:             * Checks whether a character to be inserted is already present at the insert location (perhaps
0256:             * separated by some whitespace from <code>position</code>.
0257:             *
0258:             * @param document the document we are working on
0259:             * @param position the insert position of <code>ch</code>
0260:             * @param ch the character to be inserted
0261:             * @return <code>true</code> if <code>ch</code> is already present at <code>location</code>, <code>false</code> otherwise
0262:             */
0263:            private boolean alreadyPresent(IDocument document, char ch,
0264:                    int position) {
0265:                int pos = firstNonWhitespaceForward(document, position,
0266:                        fPartitioning, document.getLength());
0267:                try {
0268:                    if (pos != -1 && document.getChar(pos) == ch)
0269:                        return true;
0270:                } catch (BadLocationException e) {
0271:                }
0272:
0273:                return false;
0274:            }
0275:
0276:            /**
0277:             * Computes the next insert position of the given character in the current line.
0278:             *
0279:             * @param document the document we are working on
0280:             * @param line the line where the change is being made
0281:             * @param offset the position of the caret in the line when <code>character</code> was typed
0282:             * @param character the character to look for
0283:             * @param partitioning the document partitioning
0284:             * @return the position where <code>character</code> should be inserted / replaced
0285:             */
0286:            protected static int computeCharacterPosition(IDocument document,
0287:                    ITextSelection line, int offset, char character,
0288:                    String partitioning) {
0289:                String text = line.getText();
0290:                if (text == null)
0291:                    return 0;
0292:
0293:                int insertPos;
0294:                if (character == BRACECHAR) {
0295:
0296:                    insertPos = computeArrayInitializationPos(document, line,
0297:                            offset, partitioning);
0298:
0299:                    if (insertPos == -1) {
0300:                        insertPos = computeAfterTryDoElse(document, line,
0301:                                offset);
0302:                    }
0303:
0304:                    if (insertPos == -1) {
0305:                        insertPos = computeAfterParenthesis(document, line,
0306:                                offset, partitioning);
0307:                    }
0308:
0309:                } else if (character == SEMICHAR) {
0310:
0311:                    if (isForStatement(text, offset)) {
0312:                        insertPos = -1; // don't do anything in for statements, as semis are vital part of these
0313:                    } else {
0314:                        int nextPartitionPos = nextPartitionOrLineEnd(document,
0315:                                line, offset, partitioning);
0316:                        insertPos = startOfWhitespaceBeforeOffset(text,
0317:                                nextPartitionPos);
0318:                        // if there is a semi present, return its location as alreadyPresent() will take it out this way.
0319:                        if (insertPos > 0
0320:                                && text.charAt(insertPos - 1) == character)
0321:                            insertPos = insertPos - 1;
0322:                        else if (insertPos > 0
0323:                                && text.charAt(insertPos - 1) == '}') {
0324:                            int opening = scanBackward(document, insertPos - 1
0325:                                    + line.getOffset(), partitioning, -1,
0326:                                    new char[] { '{' });
0327:                            if (opening > -1
0328:                                    && opening < offset + line.getOffset()) {
0329:                                if (computeArrayInitializationPos(document,
0330:                                        line, opening - line.getOffset(),
0331:                                        partitioning) == -1) {
0332:                                    insertPos = offset;
0333:                                }
0334:                            }
0335:                        }
0336:                    }
0337:
0338:                } else {
0339:                    Assert.isTrue(false);
0340:                    return -1;
0341:                }
0342:
0343:                return insertPos;
0344:            }
0345:
0346:            /**
0347:             * Computes an insert position for an opening brace if <code>offset</code> maps to a position in
0348:             * <code>document</code> that looks like being the RHS of an assignment or like an array definition.
0349:             *
0350:             * @param document the document being modified
0351:             * @param line the current line under investigation
0352:             * @param offset the offset of the caret position, relative to the line start.
0353:             * @param partitioning the document partitioning
0354:             * @return an insert position  relative to the line start if <code>line</code> looks like being an array initialization at <code>offset</code>, -1 otherwise
0355:             */
0356:            private static int computeArrayInitializationPos(
0357:                    IDocument document, ITextSelection line, int offset,
0358:                    String partitioning) {
0359:                // search backward while WS, find = (not != <= >= ==) in default partition
0360:                int pos = offset + line.getOffset();
0361:
0362:                if (pos == 0)
0363:                    return -1;
0364:
0365:                int p = firstNonWhitespaceBackward(document, pos - 1,
0366:                        partitioning, -1);
0367:
0368:                if (p == -1)
0369:                    return -1;
0370:
0371:                try {
0372:
0373:                    char ch = document.getChar(p);
0374:                    if (ch != '=' && ch != ']')
0375:                        return -1;
0376:
0377:                    if (p == 0)
0378:                        return offset;
0379:
0380:                    p = firstNonWhitespaceBackward(document, p - 1,
0381:                            partitioning, -1);
0382:                    if (p == -1)
0383:                        return -1;
0384:
0385:                    ch = document.getChar(p);
0386:                    if (Character.isJavaIdentifierPart(ch) || ch == ']'
0387:                            || ch == '[')
0388:                        return offset;
0389:
0390:                } catch (BadLocationException e) {
0391:                }
0392:                return -1;
0393:            }
0394:
0395:            /**
0396:             * Computes an insert position for an opening brace if <code>offset</code> maps to a position in
0397:             * <code>doc</code> involving a keyword taking a block after it. These are: <code>try</code>,
0398:             * <code>do</code>, <code>synchronized</code>, <code>static</code>, <code>finally</code>, or <code>else</code>.
0399:             *
0400:             * @param doc the document being modified
0401:             * @param line the current line under investigation
0402:             * @param offset the offset of the caret position, relative to the line start.
0403:             * @return an insert position  relative to the line start if <code>line</code> contains one of the above keywords at or before <code>offset</code>, -1 otherwise
0404:             */
0405:            private static int computeAfterTryDoElse(IDocument doc,
0406:                    ITextSelection line, int offset) {
0407:                // search backward while WS, find 'try', 'do', 'else' in default partition
0408:                int p = offset + line.getOffset();
0409:                p = firstWhitespaceToRight(doc, p);
0410:                if (p == -1)
0411:                    return -1;
0412:                p--;
0413:
0414:                if (looksLike(doc, p, "try") //$NON-NLS-1$
0415:                        || looksLike(doc, p, "do") //$NON-NLS-1$
0416:                        || looksLike(doc, p, "synchronized") //$NON-NLS-1$
0417:                        || looksLike(doc, p, "static") //$NON-NLS-1$
0418:                        || looksLike(doc, p, "finally") //$NON-NLS-1$
0419:                        || looksLike(doc, p, "else")) //$NON-NLS-1$
0420:                    return p + 1 - line.getOffset();
0421:
0422:                return -1;
0423:            }
0424:
0425:            /**
0426:             * Computes an insert position for an opening brace if <code>offset</code> maps to a position in
0427:             * <code>document</code> with a expression in parenthesis that will take a block after the closing parenthesis.
0428:             *
0429:             * @param document the document being modified
0430:             * @param line the current line under investigation
0431:             * @param offset the offset of the caret position, relative to the line start.
0432:             * @param partitioning the document partitioning
0433:             * @return an insert position relative to the line start if <code>line</code> contains a parenthesized expression that can be followed by a block, -1 otherwise
0434:             */
0435:            private static int computeAfterParenthesis(IDocument document,
0436:                    ITextSelection line, int offset, String partitioning) {
0437:                // find the opening parenthesis for every closing parenthesis on the current line after offset
0438:                // return the position behind the closing parenthesis if it looks like a method declaration
0439:                // or an expression for an if, while, for, catch statement
0440:                int pos = offset + line.getOffset();
0441:                int length = line.getOffset() + line.getLength();
0442:                int scanTo = scanForward(document, pos, partitioning, length,
0443:                        '}');
0444:                if (scanTo == -1)
0445:                    scanTo = length;
0446:
0447:                int closingParen = findClosingParenToLeft(document, pos,
0448:                        partitioning) - 1;
0449:
0450:                while (true) {
0451:                    int startScan = closingParen + 1;
0452:                    closingParen = scanForward(document, startScan,
0453:                            partitioning, scanTo, ')');
0454:                    if (closingParen == -1)
0455:                        break;
0456:
0457:                    int openingParen = findOpeningParenMatch(document,
0458:                            closingParen, partitioning);
0459:
0460:                    // no way an expression at the beginning of the document can mean anything
0461:                    if (openingParen < 1)
0462:                        break;
0463:
0464:                    // only select insert positions for parenthesis currently embracing the caret
0465:                    if (openingParen > pos)
0466:                        continue;
0467:
0468:                    if (looksLikeAnonymousClassDef(document, openingParen - 1,
0469:                            partitioning))
0470:                        return closingParen + 1 - line.getOffset();
0471:
0472:                    if (looksLikeIfWhileForCatch(document, openingParen - 1,
0473:                            partitioning))
0474:                        return closingParen + 1 - line.getOffset();
0475:
0476:                    if (looksLikeMethodDecl(document, openingParen - 1,
0477:                            partitioning))
0478:                        return closingParen + 1 - line.getOffset();
0479:
0480:                }
0481:
0482:                return -1;
0483:            }
0484:
0485:            /**
0486:             * Finds a closing parenthesis to the left of <code>position</code> in document, where that parenthesis is only
0487:             * separated by whitespace from <code>position</code>. If no such parenthesis can be found, <code>position</code> is returned.
0488:             *
0489:             * @param document the document being modified
0490:             * @param position the first character position in <code>document</code> to be considered
0491:             * @param partitioning the document partitioning
0492:             * @return the position of a closing parenthesis left to <code>position</code> separated only by whitespace, or <code>position</code> if no parenthesis can be found
0493:             */
0494:            private static int findClosingParenToLeft(IDocument document,
0495:                    int position, String partitioning) {
0496:                final char CLOSING_PAREN = ')';
0497:                try {
0498:                    if (position < 1)
0499:                        return position;
0500:
0501:                    int nonWS = firstNonWhitespaceBackward(document,
0502:                            position - 1, partitioning, -1);
0503:                    if (nonWS != -1 && document.getChar(nonWS) == CLOSING_PAREN)
0504:                        return nonWS;
0505:                } catch (BadLocationException e1) {
0506:                }
0507:                return position;
0508:            }
0509:
0510:            /**
0511:             * Finds the first whitespace character position to the right of (and including) <code>position</code>.
0512:             *
0513:             * @param document the document being modified
0514:             * @param position the first character position in <code>document</code> to be considered
0515:             * @return the position of a whitespace character greater or equal than <code>position</code> separated only by whitespace, or -1 if none found
0516:             */
0517:            private static int firstWhitespaceToRight(IDocument document,
0518:                    int position) {
0519:                int length = document.getLength();
0520:                Assert.isTrue(position >= 0);
0521:                Assert.isTrue(position <= length);
0522:
0523:                try {
0524:                    while (position < length) {
0525:                        char ch = document.getChar(position);
0526:                        if (Character.isWhitespace(ch))
0527:                            return position;
0528:                        position++;
0529:                    }
0530:                    return position;
0531:                } catch (BadLocationException e) {
0532:                }
0533:                return -1;
0534:            }
0535:
0536:            /**
0537:             * Finds the highest position in <code>document</code> such that the position is &lt;= <code>position</code>
0538:             * and &gt; <code>bound</code> and <code>Character.isWhitespace(document.getChar(pos))</code> evaluates to <code>false</code>
0539:             * and the position is in the default partition.
0540:             *
0541:             * @param document the document being modified
0542:             * @param position the first character position in <code>document</code> to be considered
0543:             * @param partitioning the document partitioning
0544:             * @param bound the first position in <code>document</code> to not consider any more, with <code>bound</code> &lt; <code>position</code>
0545:             * @return the highest position of one element in <code>chars</code> in [<code>position</code>, <code>scanTo</code>) that resides in a Java partition, or <code>-1</code> if none can be found
0546:             */
0547:            private static int firstNonWhitespaceBackward(IDocument document,
0548:                    int position, String partitioning, int bound) {
0549:                Assert.isTrue(position < document.getLength());
0550:                Assert.isTrue(bound >= -1);
0551:
0552:                try {
0553:                    while (position > bound) {
0554:                        char ch = document.getChar(position);
0555:                        if (!Character.isWhitespace(ch)
0556:                                && isDefaultPartition(document, position,
0557:                                        partitioning))
0558:                            return position;
0559:                        position--;
0560:                    }
0561:                } catch (BadLocationException e) {
0562:                }
0563:                return -1;
0564:            }
0565:
0566:            /**
0567:             * Finds the smallest position in <code>document</code> such that the position is &gt;= <code>position</code>
0568:             * and &lt; <code>bound</code> and <code>Character.isWhitespace(document.getChar(pos))</code> evaluates to <code>false</code>
0569:             * and the position is in the default partition.
0570:             *
0571:             * @param document the document being modified
0572:             * @param position the first character position in <code>document</code> to be considered
0573:             * @param partitioning the document partitioning
0574:             * @param bound the first position in <code>document</code> to not consider any more, with <code>bound</code> &gt; <code>position</code>
0575:             * @return the smallest position of one element in <code>chars</code> in [<code>position</code>, <code>scanTo</code>) that resides in a Java partition, or <code>-1</code> if none can be found
0576:             */
0577:            private static int firstNonWhitespaceForward(IDocument document,
0578:                    int position, String partitioning, int bound) {
0579:                Assert.isTrue(position >= 0);
0580:                Assert.isTrue(bound <= document.getLength());
0581:
0582:                try {
0583:                    while (position < bound) {
0584:                        char ch = document.getChar(position);
0585:                        if (!Character.isWhitespace(ch)
0586:                                && isDefaultPartition(document, position,
0587:                                        partitioning))
0588:                            return position;
0589:                        position++;
0590:                    }
0591:                } catch (BadLocationException e) {
0592:                }
0593:                return -1;
0594:            }
0595:
0596:            /**
0597:             * Finds the highest position in <code>document</code> such that the position is &lt;= <code>position</code>
0598:             * and &gt; <code>bound</code> and <code>document.getChar(position) == ch</code> evaluates to <code>true</code> for at least one
0599:             * ch in <code>chars</code> and the position is in the default partition.
0600:             *
0601:             * @param document the document being modified
0602:             * @param position the first character position in <code>document</code> to be considered
0603:             * @param partitioning the document partitioning
0604:             * @param bound the first position in <code>document</code> to not consider any more, with <code>scanTo</code> &gt; <code>position</code>
0605:             * @param chars an array of <code>char</code> to search for
0606:             * @return the highest position of one element in <code>chars</code> in (<code>bound</code>, <code>position</code>] that resides in a Java partition, or <code>-1</code> if none can be found
0607:             */
0608:            private static int scanBackward(IDocument document, int position,
0609:                    String partitioning, int bound, char[] chars) {
0610:                Assert.isTrue(bound >= -1);
0611:                Assert.isTrue(position < document.getLength());
0612:
0613:                Arrays.sort(chars);
0614:
0615:                try {
0616:                    while (position > bound) {
0617:
0618:                        if (Arrays.binarySearch(chars, document
0619:                                .getChar(position)) >= 0
0620:                                && isDefaultPartition(document, position,
0621:                                        partitioning))
0622:                            return position;
0623:
0624:                        position--;
0625:                    }
0626:                } catch (BadLocationException e) {
0627:                }
0628:                return -1;
0629:            }
0630:
0631:            //	/**
0632:            //	 * Finds the highest position in <code>document</code> such that the position is &lt;= <code>position</code>
0633:            //	 * and &gt; <code>bound</code> and <code>document.getChar(position) == ch</code> evaluates to <code>true</code>
0634:            //	 * and the position is in the default partition.
0635:            //	 *
0636:            //	 * @param document the document being modified
0637:            //	 * @param position the first character position in <code>document</code> to be considered
0638:            //	 * @param bound the first position in <code>document</code> to not consider any more, with <code>scanTo</code> &gt; <code>position</code>
0639:            //	 * @param chars an array of <code>char</code> to search for
0640:            //	 * @return the highest position of one element in <code>chars</code> in [<code>position</code>, <code>scanTo</code>) that resides in a Java partition, or <code>-1</code> if none can be found
0641:            //	 */
0642:            //	private static int scanBackward(IDocument document, int position, int bound, char ch) {
0643:            //		return scanBackward(document, position, bound, new char[] {ch});
0644:            //	}
0645:            //
0646:            /**
0647:             * Finds the lowest position in <code>document</code> such that the position is &gt;= <code>position</code>
0648:             * and &lt; <code>bound</code> and <code>document.getChar(position) == ch</code> evaluates to <code>true</code> for at least one
0649:             * ch in <code>chars</code> and the position is in the default partition.
0650:             *
0651:             * @param document the document being modified
0652:             * @param position the first character position in <code>document</code> to be considered
0653:             * @param partitioning the document partitioning
0654:             * @param bound the first position in <code>document</code> to not consider any more, with <code>scanTo</code> &gt; <code>position</code>
0655:             * @param chars an array of <code>char</code> to search for
0656:             * @return the lowest position of one element in <code>chars</code> in [<code>position</code>, <code>bound</code>) that resides in a Java partition, or <code>-1</code> if none can be found
0657:             */
0658:            private static int scanForward(IDocument document, int position,
0659:                    String partitioning, int bound, char[] chars) {
0660:                Assert.isTrue(position >= 0);
0661:                Assert.isTrue(bound <= document.getLength());
0662:
0663:                Arrays.sort(chars);
0664:
0665:                try {
0666:                    while (position < bound) {
0667:
0668:                        if (Arrays.binarySearch(chars, document
0669:                                .getChar(position)) >= 0
0670:                                && isDefaultPartition(document, position,
0671:                                        partitioning))
0672:                            return position;
0673:
0674:                        position++;
0675:                    }
0676:                } catch (BadLocationException e) {
0677:                }
0678:                return -1;
0679:            }
0680:
0681:            /**
0682:             * Finds the lowest position in <code>document</code> such that the position is &gt;= <code>position</code>
0683:             * and &lt; <code>bound</code> and <code>document.getChar(position) == ch</code> evaluates to <code>true</code>
0684:             * and the position is in the default partition.
0685:             *
0686:             * @param document the document being modified
0687:             * @param position the first character position in <code>document</code> to be considered
0688:             * @param partitioning the document partitioning
0689:             * @param bound the first position in <code>document</code> to not consider any more, with <code>scanTo</code> &gt; <code>position</code>
0690:             * @param ch a <code>char</code> to search for
0691:             * @return the lowest position of one element in <code>chars</code> in [<code>position</code>, <code>bound</code>) that resides in a Java partition, or <code>-1</code> if none can be found
0692:             */
0693:            private static int scanForward(IDocument document, int position,
0694:                    String partitioning, int bound, char ch) {
0695:                return scanForward(document, position, partitioning, bound,
0696:                        new char[] { ch });
0697:            }
0698:
0699:            /**
0700:             * Checks whether the content of <code>document</code> in the range (<code>offset</code>, <code>length</code>)
0701:             * contains the <code>new</code> keyword.
0702:             *
0703:             * @param document the document being modified
0704:             * @param offset the first character position in <code>document</code> to be considered
0705:             * @param length the length of the character range to be considered
0706:             * @param partitioning the document partitioning
0707:             * @return <code>true</code> if the specified character range contains a <code>new</code> keyword, <code>false</code> otherwise.
0708:             */
0709:            private static boolean isNewMatch(IDocument document, int offset,
0710:                    int length, String partitioning) {
0711:                Assert.isTrue(length >= 0);
0712:                Assert.isTrue(offset >= 0);
0713:                Assert.isTrue(offset + length < document.getLength() + 1);
0714:
0715:                try {
0716:                    String text = document.get(offset, length);
0717:                    int pos = text.indexOf("new"); //$NON-NLS-1$
0718:
0719:                    while (pos != -1
0720:                            && !isDefaultPartition(document, pos + offset,
0721:                                    partitioning))
0722:                        pos = text.indexOf("new", pos + 2); //$NON-NLS-1$
0723:
0724:                    if (pos < 0)
0725:                        return false;
0726:
0727:                    if (pos != 0
0728:                            && Character.isJavaIdentifierPart(text
0729:                                    .charAt(pos - 1)))
0730:                        return false;
0731:
0732:                    if (pos + 3 < length
0733:                            && Character.isJavaIdentifierPart(text
0734:                                    .charAt(pos + 3)))
0735:                        return false;
0736:
0737:                    return true;
0738:
0739:                } catch (BadLocationException e) {
0740:                }
0741:                return false;
0742:            }
0743:
0744:            /**
0745:             * Checks whether the content of <code>document</code> at <code>position</code> looks like an
0746:             * anonymous class definition. <code>position</code> must be to the left of the opening
0747:             * parenthesis of the definition's parameter list.
0748:             *
0749:             * @param document the document being modified
0750:             * @param position the first character position in <code>document</code> to be considered
0751:             * @param partitioning the document partitioning
0752:             * @return <code>true</code> if the content of <code>document</code> looks like an anonymous class definition, <code>false</code> otherwise
0753:             */
0754:            private static boolean looksLikeAnonymousClassDef(
0755:                    IDocument document, int position, String partitioning) {
0756:                int previousCommaParenEqual = scanBackward(document,
0757:                        position - 1, partitioning, -1, new char[] { ',', '(',
0758:                                '=' });
0759:                if (previousCommaParenEqual == -1
0760:                        || position < previousCommaParenEqual + 5) // 2 for borders, 3 for "new"
0761:                    return false;
0762:
0763:                if (isNewMatch(document, previousCommaParenEqual + 1, position
0764:                        - previousCommaParenEqual - 2, partitioning))
0765:                    return true;
0766:
0767:                return false;
0768:            }
0769:
0770:            /**
0771:             * Checks whether <code>position</code> resides in a default (Java) partition of <code>document</code>.
0772:             *
0773:             * @param document the document being modified
0774:             * @param position the position to be checked
0775:             * @param partitioning the document partitioning
0776:             * @return <code>true</code> if <code>position</code> is in the default partition of <code>document</code>, <code>false</code> otherwise
0777:             */
0778:            private static boolean isDefaultPartition(IDocument document,
0779:                    int position, String partitioning) {
0780:                Assert.isTrue(position >= 0);
0781:                Assert.isTrue(position <= document.getLength());
0782:
0783:                try {
0784:                    // don't use getPartition2 since we're interested in the scanned character's partition
0785:                    ITypedRegion region = TextUtilities.getPartition(document,
0786:                            partitioning, position, false);
0787:                    return region.getType().equals(
0788:                            IDocument.DEFAULT_CONTENT_TYPE);
0789:
0790:                } catch (BadLocationException e) {
0791:                }
0792:
0793:                return false;
0794:            }
0795:
0796:            /**
0797:             * Finds the position of the parenthesis matching the closing parenthesis at <code>position</code>.
0798:             *
0799:             * @param document the document being modified
0800:             * @param position the position in <code>document</code> of a closing parenthesis
0801:             * @param partitioning the document partitioning
0802:             * @return the position in <code>document</code> of the matching parenthesis, or -1 if none can be found
0803:             */
0804:            private static int findOpeningParenMatch(IDocument document,
0805:                    int position, String partitioning) {
0806:                final char CLOSING_PAREN = ')';
0807:                final char OPENING_PAREN = '(';
0808:
0809:                Assert.isTrue(position < document.getLength());
0810:                Assert.isTrue(position >= 0);
0811:                Assert.isTrue(isDefaultPartition(document, position,
0812:                        partitioning));
0813:
0814:                try {
0815:
0816:                    Assert.isTrue(document.getChar(position) == CLOSING_PAREN);
0817:
0818:                    int depth = 1;
0819:                    while (true) {
0820:                        position = scanBackward(document, position - 1,
0821:                                partitioning, -1, new char[] { CLOSING_PAREN,
0822:                                        OPENING_PAREN });
0823:                        if (position == -1)
0824:                            return -1;
0825:
0826:                        if (document.getChar(position) == CLOSING_PAREN)
0827:                            depth++;
0828:                        else
0829:                            depth--;
0830:
0831:                        if (depth == 0)
0832:                            return position;
0833:                    }
0834:
0835:                } catch (BadLocationException e) {
0836:                    return -1;
0837:                }
0838:            }
0839:
0840:            /**
0841:             * Checks whether, to the left of <code>position</code> and separated only by whitespace,
0842:             * <code>document</code> contains a keyword taking a parameter list and a block after it.
0843:             * These are: <code>if</code>, <code>while</code>, <code>catch</code>, <code>for</code>, <code>synchronized</code>, <code>switch</code>.
0844:             *
0845:             * @param document the document being modified
0846:             * @param position the first character position in <code>document</code> to be considered
0847:             * @param partitioning the document partitioning
0848:             * @return <code>true</code> if <code>document</code> contains any of the above keywords to the left of <code>position</code>, <code>false</code> otherwise
0849:             */
0850:            private static boolean looksLikeIfWhileForCatch(IDocument document,
0851:                    int position, String partitioning) {
0852:                position = firstNonWhitespaceBackward(document, position,
0853:                        partitioning, -1);
0854:                if (position == -1)
0855:                    return false;
0856:
0857:                return looksLike(document, position, "if") //$NON-NLS-1$
0858:                        || looksLike(document, position, "while") //$NON-NLS-1$
0859:                        || looksLike(document, position, "catch") //$NON-NLS-1$
0860:                        || looksLike(document, position, "synchronized") //$NON-NLS-1$
0861:                        || looksLike(document, position, "switch") //$NON-NLS-1$
0862:                        || looksLike(document, position, "for"); //$NON-NLS-1$
0863:            }
0864:
0865:            /**
0866:             * Checks whether code>document</code> contains the <code>String</code> <code>like</code> such
0867:             * that its last character is at <code>position</code>. If <code>like</code> starts with a
0868:             * identifier part (as determined by {@link Character#isJavaIdentifierPart(char)}), it is also made
0869:             * sure that <code>like</code> is preceded by some non-identifier character or stands at the
0870:             * document start.
0871:             *
0872:             * @param document the document being modified
0873:             * @param position the first character position in <code>document</code> to be considered
0874:             * @param like the <code>String</code> to look for.
0875:             * @return <code>true</code> if  <code>document</code> contains <code>like</code> such that it ends at <code>position</code>, <code>false</code> otherwise
0876:             */
0877:            private static boolean looksLike(IDocument document, int position,
0878:                    String like) {
0879:                int length = like.length();
0880:                if (position < length - 1)
0881:                    return false;
0882:
0883:                try {
0884:                    if (!like.equals(document
0885:                            .get(position - length + 1, length)))
0886:                        return false;
0887:
0888:                    if (position >= length
0889:                            && Character.isJavaIdentifierPart(like.charAt(0))
0890:                            && Character.isJavaIdentifierPart(document
0891:                                    .getChar(position - length)))
0892:                        return false;
0893:
0894:                } catch (BadLocationException e) {
0895:                    return false;
0896:                }
0897:
0898:                return true;
0899:            }
0900:
0901:            /**
0902:             * Checks whether the content of <code>document</code> at <code>position</code> looks like a
0903:             * method declaration header (i.e. only the return type and method name). <code>position</code>
0904:             * must be just left of the opening parenthesis of the parameter list.
0905:             *
0906:             * @param document the document being modified
0907:             * @param position the first character position in <code>document</code> to be considered
0908:             * @param partitioning the document partitioning
0909:             * @return <code>true</code> if the content of <code>document</code> looks like a method definition, <code>false</code> otherwise
0910:             */
0911:            private static boolean looksLikeMethodDecl(IDocument document,
0912:                    int position, String partitioning) {
0913:
0914:                // method name
0915:                position = eatIdentToLeft(document, position, partitioning);
0916:                if (position < 1)
0917:                    return false;
0918:
0919:                position = eatBrackets(document, position - 1, partitioning);
0920:                if (position < 1)
0921:                    return false;
0922:
0923:                position = eatIdentToLeft(document, position - 1, partitioning);
0924:
0925:                return position != -1;
0926:            }
0927:
0928:            /**
0929:             * From <code>position</code> to the left, eats any whitespace and then a pair of brackets
0930:             * as used to declare an array return type like <pre>String [ ]</pre>.
0931:             * The return value is either the position of the opening bracket or <code>position</code> if no
0932:             * pair of brackets can be parsed.
0933:             *
0934:             * @param document the document being modified
0935:             * @param position the first character position in <code>document</code> to be considered
0936:             * @param partitioning the document partitioning
0937:             * @return the smallest character position of bracket pair or <code>position</code>
0938:             */
0939:            private static int eatBrackets(IDocument document, int position,
0940:                    String partitioning) {
0941:                // accept array return type
0942:                int pos = firstNonWhitespaceBackward(document, position,
0943:                        partitioning, -1);
0944:                try {
0945:                    if (pos > 1 && document.getChar(pos) == ']') {
0946:                        pos = firstNonWhitespaceBackward(document, pos - 1,
0947:                                partitioning, -1);
0948:                        if (pos > 0 && document.getChar(pos) == '[')
0949:                            return pos;
0950:                    }
0951:                } catch (BadLocationException e) {
0952:                    // won't happen
0953:                }
0954:                return position;
0955:            }
0956:
0957:            /**
0958:             * From <code>position</code> to the left, eats any whitespace and the first identifier, returning
0959:             * the position of the first identifier character (in normal read order).
0960:             * <p>When called on a document with content <code>" some string  "</code> and positionition 13, the
0961:             * return value will be 6 (the first letter in <code>string</code>).
0962:             * </p>
0963:             *
0964:             * @param document the document being modified
0965:             * @param position the first character position in <code>document</code> to be considered
0966:             * @param partitioning the document partitioning
0967:             * @return the smallest character position of an identifier or -1 if none can be found; always &lt;= <code>position</code>
0968:             */
0969:            private static int eatIdentToLeft(IDocument document, int position,
0970:                    String partitioning) {
0971:                if (position < 0)
0972:                    return -1;
0973:                Assert.isTrue(position < document.getLength());
0974:
0975:                int p = firstNonWhitespaceBackward(document, position,
0976:                        partitioning, -1);
0977:                if (p == -1)
0978:                    return -1;
0979:
0980:                try {
0981:                    while (p >= 0) {
0982:
0983:                        char ch = document.getChar(p);
0984:                        if (Character.isJavaIdentifierPart(ch)) {
0985:                            p--;
0986:                            continue;
0987:                        }
0988:
0989:                        // length must be > 0
0990:                        if (Character.isWhitespace(ch) && p != position)
0991:                            return p + 1;
0992:                        else
0993:                            return -1;
0994:
0995:                    }
0996:
0997:                    // start of document reached
0998:                    return 0;
0999:
1000:                } catch (BadLocationException e) {
1001:                }
1002:                return -1;
1003:            }
1004:
1005:            /**
1006:             * Returns a position in the first java partition after the last non-empty and non-comment partition.
1007:             * There is no non-whitespace from the returned position to the end of the partition it is contained in.
1008:             *
1009:             * @param document the document being modified
1010:             * @param line the line under investigation
1011:             * @param offset the caret offset into <code>line</code>
1012:             * @param partitioning the document partitioning
1013:             * @return the position of the next Java partition, or the end of <code>line</code>
1014:             */
1015:            private static int nextPartitionOrLineEnd(IDocument document,
1016:                    ITextSelection line, int offset, String partitioning) {
1017:                // run relative to document
1018:                final int docOffset = offset + line.getOffset();
1019:                final int eol = line.getOffset() + line.getLength();
1020:                int nextPartitionPos = eol; // init with line end
1021:                int validPosition = docOffset;
1022:
1023:                try {
1024:                    ITypedRegion partition = TextUtilities.getPartition(
1025:                            document, partitioning, nextPartitionPos, true);
1026:                    validPosition = getValidPositionForPartition(document,
1027:                            partition, eol);
1028:                    while (validPosition == -1) {
1029:                        nextPartitionPos = partition.getOffset() - 1;
1030:                        if (nextPartitionPos < docOffset) {
1031:                            validPosition = docOffset;
1032:                            break;
1033:                        }
1034:                        partition = TextUtilities.getPartition(document,
1035:                                partitioning, nextPartitionPos, false);
1036:                        validPosition = getValidPositionForPartition(document,
1037:                                partition, eol);
1038:                    }
1039:                } catch (BadLocationException e) {
1040:                }
1041:
1042:                validPosition = Math.max(validPosition, docOffset);
1043:                // make relative to line
1044:                validPosition -= line.getOffset();
1045:                return validPosition;
1046:            }
1047:
1048:            /**
1049:             * Returns a valid insert location (except for whitespace) in <code>partition</code> or -1 if
1050:             * there is no valid insert location.
1051:             * An valid insert location is right after any java string or character partition, or at the end
1052:             * of a java default partition, but never behind <code>maxOffset</code>. Comment partitions or
1053:             * empty java partitions do never yield valid insert positions.
1054:             *
1055:             * @param doc the document being modified
1056:             * @param partition the current partition
1057:             * @param maxOffset the maximum offset to consider
1058:             * @return a valid insert location in <code>partition</code>, or -1 if there is no valid insert location
1059:             */
1060:            private static int getValidPositionForPartition(IDocument doc,
1061:                    ITypedRegion partition, int maxOffset) {
1062:                final int INVALID = -1;
1063:
1064:                if (IJavaPartitions.JAVA_DOC.equals(partition.getType()))
1065:                    return INVALID;
1066:                if (IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(partition
1067:                        .getType()))
1068:                    return INVALID;
1069:                if (IJavaPartitions.JAVA_SINGLE_LINE_COMMENT.equals(partition
1070:                        .getType()))
1071:                    return INVALID;
1072:
1073:                int endOffset = Math.min(maxOffset, partition.getOffset()
1074:                        + partition.getLength());
1075:
1076:                if (IJavaPartitions.JAVA_CHARACTER.equals(partition.getType()))
1077:                    return endOffset;
1078:                if (IJavaPartitions.JAVA_STRING.equals(partition.getType()))
1079:                    return endOffset;
1080:                if (IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())) {
1081:                    try {
1082:                        if (doc.get(partition.getOffset(),
1083:                                endOffset - partition.getOffset()).trim()
1084:                                .length() == 0)
1085:                            return INVALID;
1086:                        else
1087:                            return endOffset;
1088:                    } catch (BadLocationException e) {
1089:                        return INVALID;
1090:                    }
1091:                }
1092:                // default: we don't know anything about the partition - assume valid
1093:                return endOffset;
1094:            }
1095:
1096:            /**
1097:             * Determines whether the current line contains a for statement.
1098:             * Algorithm: any "for" word in the line is a positive, "for" contained in a string literal will
1099:             * produce a false positive.
1100:             *
1101:             * @param line the line where the change is being made
1102:             * @param offset the position of the caret
1103:             * @return <code>true</code> if <code>line</code> contains <code>for</code>, <code>false</code> otherwise
1104:             */
1105:            private static boolean isForStatement(String line, int offset) {
1106:                /* searching for (^|\s)for(\s|$) */
1107:                int forPos = line.indexOf("for"); //$NON-NLS-1$
1108:                if (forPos != -1) {
1109:                    if ((forPos == 0 || !Character.isJavaIdentifierPart(line
1110:                            .charAt(forPos - 1)))
1111:                            && (line.length() == forPos + 3 || !Character
1112:                                    .isJavaIdentifierPart(line
1113:                                            .charAt(forPos + 3))))
1114:                        return true;
1115:                }
1116:                return false;
1117:            }
1118:
1119:            /**
1120:             * Returns the position in <code>text</code> after which there comes only whitespace, up to
1121:             * <code>offset</code>.
1122:             *
1123:             * @param text the text being searched
1124:             * @param offset the maximum offset to search for
1125:             * @return the smallest value <code>v</code> such that <code>text.substring(v, offset).trim() == 0</code>
1126:             */
1127:            private static int startOfWhitespaceBeforeOffset(String text,
1128:                    int offset) {
1129:                int i = Math.min(offset, text.length());
1130:                for (; i >= 1; i--) {
1131:                    if (!Character.isWhitespace(text.charAt(i - 1)))
1132:                        break;
1133:                }
1134:                return i;
1135:            }
1136:        }
ww__w___._ja___v__a2__s_.___c___om__ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.