Source Code Cross Referenced for IndentAction.java in  » IDE-Eclipse » jdt » org » eclipse » jdt » internal » ui » actions » 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.actions 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*******************************************************************************
002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
003:         * All rights reserved. This program and the accompanying materials
004:         * are made available under the terms of the Eclipse Public License v1.0
005:         * which accompanies this distribution, and is available at
006:         * http://www.eclipse.org/legal/epl-v10.html
007:         *
008:         * Contributors:
009:         *     IBM Corporation - initial API and implementation
010:         *******************************************************************************/package org.eclipse.jdt.internal.ui.actions;
011:
012:        import java.util.ArrayList;
013:        import java.util.Iterator;
014:        import java.util.ResourceBundle;
015:
016:        import org.eclipse.text.edits.MultiTextEdit;
017:        import org.eclipse.text.edits.ReplaceEdit;
018:        import org.eclipse.text.edits.TextEdit;
019:
020:        import org.eclipse.core.runtime.Assert;
021:        import org.eclipse.core.runtime.IStatus;
022:        import org.eclipse.core.runtime.Status;
023:
024:        import org.eclipse.swt.custom.BusyIndicator;
025:        import org.eclipse.swt.widgets.Display;
026:
027:        import org.eclipse.jface.viewers.ISelection;
028:        import org.eclipse.jface.viewers.ISelectionProvider;
029:
030:        import org.eclipse.jface.text.BadLocationException;
031:        import org.eclipse.jface.text.IDocument;
032:        import org.eclipse.jface.text.IRegion;
033:        import org.eclipse.jface.text.IRewriteTarget;
034:        import org.eclipse.jface.text.ITextSelection;
035:        import org.eclipse.jface.text.ITypedRegion;
036:        import org.eclipse.jface.text.Position;
037:        import org.eclipse.jface.text.TextSelection;
038:        import org.eclipse.jface.text.TextUtilities;
039:        import org.eclipse.jface.text.source.ISourceViewer;
040:
041:        import org.eclipse.ui.IEditorInput;
042:        import org.eclipse.ui.texteditor.IDocumentProvider;
043:        import org.eclipse.ui.texteditor.ITextEditor;
044:        import org.eclipse.ui.texteditor.ITextEditorExtension3;
045:        import org.eclipse.ui.texteditor.TextEditorAction;
046:
047:        import org.eclipse.jdt.core.ICompilationUnit;
048:        import org.eclipse.jdt.core.IJavaProject;
049:        import org.eclipse.jdt.core.JavaCore;
050:        import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
051:
052:        import org.eclipse.jdt.ui.text.IJavaPartitions;
053:
054:        import org.eclipse.jdt.internal.ui.JavaPlugin;
055:        import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
056:        import org.eclipse.jdt.internal.ui.text.JavaHeuristicScanner;
057:        import org.eclipse.jdt.internal.ui.text.JavaIndenter;
058:
059:        /**
060:         * Indents a line or range of lines in a Java document to its correct position. No complete
061:         * AST must be present, the indentation is computed using heuristics. The algorithm used is fast for
062:         * single lines, but does not store any information and therefore not so efficient for large line
063:         * ranges.
064:         * 
065:         * @see org.eclipse.jdt.internal.ui.text.JavaHeuristicScanner
066:         * @see org.eclipse.jdt.internal.ui.text.JavaIndenter
067:         * @since 3.0
068:         */
069:        public class IndentAction extends TextEditorAction {
070:
071:            /**
072:             * @since 3.4
073:             */
074:            private static final class ReplaceData {
075:
076:                /**
077:                 * The replacement
078:                 */
079:                public final String indent;
080:
081:                /**
082:                 * The start of the replacement
083:                 */
084:                public final int offset;
085:
086:                /**
087:                 * The end of the replacement
088:                 */
089:                public final int end;
090:
091:                /**
092:                 * Replace string in document from offset to end with indent
093:                 * @param offset the start of the replacement
094:                 * @param end the end of the replacement
095:                 * @param indent the replacement
096:                 */
097:                public ReplaceData(int offset, int end, String indent) {
098:                    this .indent = indent;
099:                    this .end = end;
100:                    this .offset = offset;
101:                }
102:
103:            }
104:
105:            /** The caret offset after an indent operation. */
106:            private int fCaretOffset;
107:
108:            /** 
109:             * Whether this is the action invoked by TAB. When <code>true</code>, indentation behaves 
110:             * differently to accommodate normal TAB operation.
111:             */
112:            private final boolean fIsTabAction;
113:
114:            /**
115:             * Creates a new instance.
116:             * 
117:             * @param bundle the resource bundle
118:             * @param prefix the prefix to use for keys in <code>bundle</code>
119:             * @param editor the text editor
120:             * @param isTabAction whether the action should insert tabs if over the indentation
121:             */
122:            public IndentAction(ResourceBundle bundle, String prefix,
123:                    ITextEditor editor, boolean isTabAction) {
124:                super (bundle, prefix, editor);
125:                fIsTabAction = isTabAction;
126:            }
127:
128:            /*
129:             * @see org.eclipse.jface.action.Action#run()
130:             */
131:            public void run() {
132:                // update has been called by the framework
133:                if (!isEnabled() || !validateEditorInputState())
134:                    return;
135:
136:                ITextSelection selection = getSelection();
137:                final IDocument document = getDocument();
138:
139:                if (document != null) {
140:
141:                    final int offset = selection.getOffset();
142:                    final int length = selection.getLength();
143:                    final Position end = new Position(offset + length);
144:                    final int firstLine, nLines;
145:                    fCaretOffset = -1;
146:
147:                    try {
148:                        document.addPosition(end);
149:                        firstLine = document.getLineOfOffset(offset);
150:                        // check for marginal (zero-length) lines
151:                        int minusOne = length == 0 ? 0 : 1;
152:                        nLines = document.getLineOfOffset(offset + length
153:                                - minusOne)
154:                                - firstLine + 1;
155:                    } catch (BadLocationException e) {
156:                        // will only happen on concurrent modification
157:                        JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin
158:                                .getPluginId(), IStatus.OK, "", e)); //$NON-NLS-1$
159:                        return;
160:                    }
161:
162:                    Runnable runnable = new Runnable() {
163:                        public void run() {
164:                            IRewriteTarget target = (IRewriteTarget) getTextEditor()
165:                                    .getAdapter(IRewriteTarget.class);
166:                            if (target != null)
167:                                target.beginCompoundChange();
168:
169:                            try {
170:                                JavaHeuristicScanner scanner = new JavaHeuristicScanner(
171:                                        document);
172:                                JavaIndenter indenter = new JavaIndenter(
173:                                        document, scanner, getJavaProject());
174:                                final boolean multiLine = nLines > 1;
175:                                boolean hasChanged = false;
176:                                for (int i = 0; i < nLines; i++) {
177:                                    hasChanged |= indentLine(document,
178:                                            firstLine + i, offset, indenter,
179:                                            scanner, multiLine);
180:                                }
181:
182:                                // update caret position: move to new position when indenting just one line
183:                                // keep selection when indenting multiple
184:                                int newOffset, newLength;
185:                                if (!fIsTabAction && multiLine) {
186:                                    newOffset = offset;
187:                                    newLength = end.getOffset() - offset;
188:                                } else {
189:                                    newOffset = fCaretOffset;
190:                                    newLength = 0;
191:                                }
192:
193:                                // always reset the selection if anything was replaced
194:                                // but not when we had a single line non-tab invocation
195:                                if (newOffset != -1
196:                                        && (hasChanged || newOffset != offset || newLength != length))
197:                                    selectAndReveal(newOffset, newLength);
198:
199:                                document.removePosition(end);
200:                            } catch (BadLocationException e) {
201:                                // will only happen on concurrent modification
202:                                JavaPlugin
203:                                        .log(new Status(
204:                                                IStatus.ERROR,
205:                                                JavaPlugin.getPluginId(),
206:                                                IStatus.OK,
207:                                                "ConcurrentModification in IndentAction", e)); //$NON-NLS-1$
208:
209:                            } finally {
210:                                if (target != null)
211:                                    target.endCompoundChange();
212:                            }
213:                        }
214:                    };
215:
216:                    if (nLines > 50) {
217:                        Display display = getTextEditor().getEditorSite()
218:                                .getWorkbenchWindow().getShell().getDisplay();
219:                        BusyIndicator.showWhile(display, runnable);
220:                    } else
221:                        runnable.run();
222:
223:                }
224:            }
225:
226:            /**
227:             * Selects the given range on the editor.
228:             * 
229:             * @param newOffset the selection offset
230:             * @param newLength the selection range
231:             */
232:            private void selectAndReveal(int newOffset, int newLength) {
233:                Assert.isTrue(newOffset >= 0);
234:                Assert.isTrue(newLength >= 0);
235:                ITextEditor editor = getTextEditor();
236:                if (editor instanceof  JavaEditor) {
237:                    ISourceViewer viewer = ((JavaEditor) editor).getViewer();
238:                    if (viewer != null)
239:                        viewer.setSelectedRange(newOffset, newLength);
240:                } else
241:                    // this is too intrusive, but will never get called anyway
242:                    getTextEditor().selectAndReveal(newOffset, newLength);
243:
244:            }
245:
246:            /**
247:             * Indent the given <code>document</code> based on the <code>project</code> settings and
248:             * return a text edit describing the changes applied to the document. Returns <b>null</b>
249:             * if no changes have been applied.
250:             * <p>
251:             * WARNING: This method does change the content of the given document.
252:             * </p>
253:             * <p>
254:             * This method is for internal use only, it should not be called.
255:             * </p>
256:             * 
257:             * @param document the document to indent
258:             * @param project the project to retrieve the indentation settings from, <b>null</b> for workspace settings
259:             * @return a text edit describing the changes or <b>null</b> if no changes required
260:             * @throws BadLocationException if the document got modified concurrently
261:             * 
262:             * @since 3.4
263:             */
264:            public static TextEdit indent(IDocument document,
265:                    IJavaProject project) throws BadLocationException {
266:                JavaPlugin.getDefault().getJavaTextTools()
267:                        .setupJavaDocumentPartitioner(document,
268:                                IJavaPartitions.JAVA_PARTITIONING);
269:
270:                int offset = 0;
271:                int length = document.getLength();
272:
273:                JavaHeuristicScanner scanner = new JavaHeuristicScanner(
274:                        document);
275:                JavaIndenter indenter = new JavaIndenter(document, scanner,
276:                        project);
277:
278:                ArrayList edits = new ArrayList();
279:
280:                int firstLine = document.getLineOfOffset(offset);
281:                // check for marginal (zero-length) lines
282:                int minusOne = length == 0 ? 0 : 1;
283:                int numberOfLines = document.getLineOfOffset(offset + length
284:                        - minusOne)
285:                        - firstLine + 1;
286:
287:                int shift = 0;
288:                for (int i = 0; i < numberOfLines; i++) {
289:                    ReplaceData data = computeReplaceData(document, firstLine
290:                            + i, indenter, scanner, numberOfLines > 1, false,
291:                            project);
292:
293:                    int replaceLength = data.end - data.offset;
294:                    String currentIndent = document.get(data.offset,
295:                            replaceLength);
296:
297:                    // only change the document if it is a real change
298:                    if (!data.indent.equals(currentIndent)) {
299:                        edits.add(new ReplaceEdit(data.offset + shift,
300:                                replaceLength, data.indent));
301:                        //We need to change the document, the indenter depends on it.
302:                        document.replace(data.offset, replaceLength,
303:                                data.indent);
304:                        shift -= data.indent.length() - replaceLength;
305:                    }
306:                }
307:
308:                if (edits.size() == 0)
309:                    return null;
310:
311:                if (edits.size() == 1)
312:                    return (TextEdit) edits.get(0);
313:
314:                MultiTextEdit result = new MultiTextEdit();
315:                for (Iterator iterator = edits.iterator(); iterator.hasNext();) {
316:                    TextEdit edit = (TextEdit) iterator.next();
317:                    result.addChild(edit);
318:                }
319:
320:                return result;
321:            }
322:
323:            /**
324:             * Indents a single line using the java heuristic scanner. Javadoc and multiline comments are 
325:             * indented as specified by the <code>JavaDocAutoIndentStrategy</code>.
326:             * 
327:             * @param document the document
328:             * @param line the line to be indented
329:             * @param indenter the java indenter
330:             * @param scanner the heuristic scanner
331:             * @param multiLine <code>true</code> if more than one line is being indented
332:             * @param isTabAction <code>true</code> if this action has been invoked by TAB
333:             * @param project the project to retrieve the indentation settings from, <b>null</b> for workspace settings 
334:             * @return <code>true</code> if <code>document</code> was modified, <code>false</code> otherwise
335:             * @throws BadLocationException if the document got changed concurrently 
336:             */
337:            private static ReplaceData computeReplaceData(IDocument document,
338:                    int line, JavaIndenter indenter,
339:                    JavaHeuristicScanner scanner, boolean multiLine,
340:                    boolean isTabAction, IJavaProject project)
341:                    throws BadLocationException {
342:                IRegion currentLine = document.getLineInformation(line);
343:                int offset = currentLine.getOffset();
344:                int wsStart = offset; // where we start searching for non-WS; after the "//" in single line comments
345:
346:                String indent = null;
347:                if (offset < document.getLength()) {
348:                    ITypedRegion partition = TextUtilities.getPartition(
349:                            document, IJavaPartitions.JAVA_PARTITIONING,
350:                            offset, true);
351:                    ITypedRegion startingPartition = TextUtilities
352:                            .getPartition(document,
353:                                    IJavaPartitions.JAVA_PARTITIONING, offset,
354:                                    false);
355:                    String type = partition.getType();
356:                    if (type.equals(IJavaPartitions.JAVA_DOC)
357:                            || type
358:                                    .equals(IJavaPartitions.JAVA_MULTI_LINE_COMMENT)) {
359:                        indent = computeJavadocIndent(document, line, scanner,
360:                                startingPartition);
361:                    } else if (!isTabAction
362:                            && startingPartition.getOffset() == offset
363:                            && startingPartition.getType().equals(
364:                                    IJavaPartitions.JAVA_SINGLE_LINE_COMMENT)) {
365:
366:                        // line comment starting at position 0 -> indent inside
367:                        int max = document.getLength() - offset;
368:                        int slashes = 2;
369:                        while (slashes < max - 1
370:                                && document.get(offset + slashes, 2).equals(
371:                                        "//")) //$NON-NLS-1$
372:                            slashes += 2;
373:
374:                        wsStart = offset + slashes;
375:
376:                        StringBuffer computed = indenter
377:                                .computeIndentation(offset);
378:                        if (computed == null)
379:                            computed = new StringBuffer(0);
380:                        int tabSize = getTabSize(project);
381:                        while (slashes > 0 && computed.length() > 0) {
382:                            char c = computed.charAt(0);
383:                            if (c == '\t')
384:                                if (slashes > tabSize)
385:                                    slashes -= tabSize;
386:                                else
387:                                    break;
388:                            else if (c == ' ')
389:                                slashes--;
390:                            else
391:                                break;
392:
393:                            computed.deleteCharAt(0);
394:                        }
395:
396:                        indent = document.get(offset, wsStart - offset)
397:                                + computed;
398:
399:                    }
400:                }
401:
402:                // standard java indentation
403:                if (indent == null) {
404:                    StringBuffer computed = indenter.computeIndentation(offset);
405:                    if (computed != null)
406:                        indent = computed.toString();
407:                    else
408:                        indent = ""; //$NON-NLS-1$
409:                }
410:
411:                // change document:
412:                // get current white space
413:                int lineLength = currentLine.getLength();
414:                int end = scanner.findNonWhitespaceForwardInAnyPartition(
415:                        wsStart, offset + lineLength);
416:                if (end == JavaHeuristicScanner.NOT_FOUND) {
417:                    // an empty line
418:                    end = offset + lineLength;
419:                    if (multiLine && !indentEmptyLines(project))
420:                        indent = ""; //$NON-NLS-1$
421:                }
422:
423:                return new ReplaceData(offset, end, indent);
424:            }
425:
426:            /**
427:             * Indents a single line using the java heuristic scanner. Javadoc and multiline comments are 
428:             * indented as specified by the <code>JavaDocAutoIndentStrategy</code>.
429:             * 
430:             * @param document the document
431:             * @param line the line to be indented
432:             * @param caret the caret position
433:             * @param indenter the java indenter
434:             * @param scanner the heuristic scanner
435:             * @param multiLine <code>true</code> if more than one line is being indented 
436:             * @return <code>true</code> if <code>document</code> was modified, <code>false</code> otherwise
437:             * @throws BadLocationException if the document got changed concurrently 
438:             */
439:            private boolean indentLine(IDocument document, int line, int caret,
440:                    JavaIndenter indenter, JavaHeuristicScanner scanner,
441:                    boolean multiLine) throws BadLocationException {
442:                IJavaProject project = getJavaProject();
443:                ReplaceData data = computeReplaceData(document, line, indenter,
444:                        scanner, multiLine, fIsTabAction, project);
445:
446:                String indent = data.indent;
447:                int end = data.end;
448:                int offset = data.offset;
449:
450:                int length = end - offset;
451:                String currentIndent = document.get(offset, length);
452:
453:                // if we are right before the text start / line end, and already after the insertion point
454:                // then just insert a tab.
455:                if (fIsTabAction
456:                        && caret == end
457:                        && whiteSpaceLength(currentIndent, project) >= whiteSpaceLength(
458:                                indent, project)) {
459:                    String tab = getTabEquivalent(project);
460:                    document.replace(caret, 0, tab);
461:                    fCaretOffset = caret + tab.length();
462:                    return true;
463:                }
464:
465:                // set the caret offset so it can be used when setting the selection
466:                if (caret >= offset && caret <= end)
467:                    fCaretOffset = offset + indent.length();
468:                else
469:                    fCaretOffset = -1;
470:
471:                // only change the document if it is a real change
472:                if (!indent.equals(currentIndent)) {
473:                    document.replace(offset, length, indent);
474:                    return true;
475:                } else
476:                    return false;
477:            }
478:
479:            /**
480:             * Computes and returns the indentation for a javadoc line. The line
481:             * must be inside a javadoc comment.
482:             * 
483:             * @param document the document
484:             * @param line the line in document
485:             * @param scanner the scanner
486:             * @param partition the javadoc partition
487:             * @return the indent, or <code>null</code> if not computable
488:             * @throws BadLocationException
489:             * @since 3.1
490:             */
491:            private static String computeJavadocIndent(IDocument document,
492:                    int line, JavaHeuristicScanner scanner,
493:                    ITypedRegion partition) throws BadLocationException {
494:                if (line == 0) // impossible - the first line is never inside a javadoc comment
495:                    return null;
496:
497:                // don't make any assumptions if the line does not start with \s*\* - it might be
498:                // commented out code, for which we don't want to change the indent
499:                final IRegion lineInfo = document.getLineInformation(line);
500:                final int lineStart = lineInfo.getOffset();
501:                final int lineLength = lineInfo.getLength();
502:                final int lineEnd = lineStart + lineLength;
503:                int nonWS = scanner.findNonWhitespaceForwardInAnyPartition(
504:                        lineStart, lineEnd);
505:                if (nonWS == JavaHeuristicScanner.NOT_FOUND
506:                        || document.getChar(nonWS) != '*') {
507:                    if (nonWS == JavaHeuristicScanner.NOT_FOUND)
508:                        return document.get(lineStart, lineLength);
509:                    return document.get(lineStart, nonWS - lineStart);
510:                }
511:
512:                // take the indent from the previous line and reuse
513:                IRegion previousLine = document.getLineInformation(line - 1);
514:                int previousLineStart = previousLine.getOffset();
515:                int previousLineLength = previousLine.getLength();
516:                int previousLineEnd = previousLineStart + previousLineLength;
517:
518:                StringBuffer buf = new StringBuffer();
519:                int previousLineNonWS = scanner
520:                        .findNonWhitespaceForwardInAnyPartition(
521:                                previousLineStart, previousLineEnd);
522:                if (previousLineNonWS == JavaHeuristicScanner.NOT_FOUND
523:                        || document.getChar(previousLineNonWS) != '*') {
524:                    // align with the comment start if the previous line is not an asterisked line
525:                    previousLine = document
526:                            .getLineInformationOfOffset(partition.getOffset());
527:                    previousLineStart = previousLine.getOffset();
528:                    previousLineLength = previousLine.getLength();
529:                    previousLineEnd = previousLineStart + previousLineLength;
530:                    previousLineNonWS = scanner
531:                            .findNonWhitespaceForwardInAnyPartition(
532:                                    previousLineStart, previousLineEnd);
533:                    if (previousLineNonWS == JavaHeuristicScanner.NOT_FOUND)
534:                        previousLineNonWS = previousLineEnd;
535:
536:                    // add the initial space 
537:                    // TODO this may be controlled by a formatter preference in the future
538:                    buf.append(' ');
539:                }
540:
541:                String indentation = document.get(previousLineStart,
542:                        previousLineNonWS - previousLineStart);
543:                buf.insert(0, indentation);
544:                return buf.toString();
545:            }
546:
547:            /**
548:             * Returns the size in characters of a string. All characters count one, tabs count the editor's
549:             * preference for the tab display 
550:             * 
551:             * @param indent the string to be measured.
552:             * @param project the project to retrieve the indentation settings from, <b>null</b> for workspace settings
553:             * @return the size in characters of a string
554:             */
555:            private static int whiteSpaceLength(String indent,
556:                    IJavaProject project) {
557:                if (indent == null)
558:                    return 0;
559:                else {
560:                    int size = 0;
561:                    int l = indent.length();
562:                    int tabSize = getTabSize(project);
563:
564:                    for (int i = 0; i < l; i++)
565:                        size += indent.charAt(i) == '\t' ? tabSize : 1;
566:                    return size;
567:                }
568:            }
569:
570:            /**
571:             * Returns a tab equivalent, either as a tab character or as spaces, depending on the editor and
572:             * formatter preferences.
573:             * 
574:             * @param project the project to retrieve the indentation settings from, <b>null</b> for workspace settings
575:             * @return a string representing one tab in the editor, never <code>null</code>
576:             */
577:            private static String getTabEquivalent(IJavaProject project) {
578:                String tab;
579:                if (JavaCore.SPACE.equals(getCoreFormatterOption(
580:                        DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR,
581:                        project))) {
582:                    int size = getTabSize(project);
583:                    StringBuffer buf = new StringBuffer();
584:                    for (int i = 0; i < size; i++)
585:                        buf.append(' ');
586:                    tab = buf.toString();
587:                } else
588:                    tab = "\t"; //$NON-NLS-1$
589:
590:                return tab;
591:            }
592:
593:            /**
594:             * Returns the tab size used by the java editor, which is deduced from the
595:             * formatter preferences.
596:             * 
597:             * @param project the project to retrieve the indentation settings from, <b>null</b> for workspace settings
598:             * @return the tab size as defined in the current formatter preferences
599:             */
600:            private static int getTabSize(IJavaProject project) {
601:                return getCoreFormatterOption(
602:                        DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, 4,
603:                        project);
604:            }
605:
606:            /**
607:             * Returns <code>true</code> if empty lines should be indented, false otherwise.
608:             * 
609:             * @param project the project to retrieve the indentation settings from, <b>null</b> for workspace settings
610:             * @return <code>true</code> if empty lines should be indented, false otherwise
611:             * @since 3.2
612:             */
613:            private static boolean indentEmptyLines(IJavaProject project) {
614:                return DefaultCodeFormatterConstants.TRUE
615:                        .equals(getCoreFormatterOption(
616:                                DefaultCodeFormatterConstants.FORMATTER_INDENT_EMPTY_LINES,
617:                                project));
618:            }
619:
620:            /**
621:             * Returns the possibly project-specific core preference defined under <code>key</code>.
622:             * 
623:             * @param key the key of the preference
624:             * @param project the project to retrieve the indentation settings from, <b>null</b> for workspace settings
625:             * @return the value of the preference
626:             * @since 3.1
627:             */
628:            private static String getCoreFormatterOption(String key,
629:                    IJavaProject project) {
630:                if (project == null)
631:                    return JavaCore.getOption(key);
632:                return project.getOption(key, true);
633:            }
634:
635:            /**
636:             * Returns the possibly project-specific core preference defined under <code>key</code>, or
637:             * <code>def</code> if the value is not a integer.
638:             * 
639:             * @param key the key of the preference
640:             * @param def the default value
641:             * @param project the project to retrieve the indentation settings from, <b>null</b> for workspace settings
642:             * @return the value of the preference
643:             * @since 3.1
644:             */
645:            private static int getCoreFormatterOption(String key, int def,
646:                    IJavaProject project) {
647:                try {
648:                    return Integer
649:                            .parseInt(getCoreFormatterOption(key, project));
650:                } catch (NumberFormatException e) {
651:                    return def;
652:                }
653:            }
654:
655:            /**
656:             * Returns the <code>IJavaProject</code> of the current editor input, or
657:             * <code>null</code> if it cannot be found.
658:             * 
659:             * @return the <code>IJavaProject</code> of the current editor input, or
660:             *         <code>null</code> if it cannot be found
661:             * @since 3.1
662:             */
663:            private IJavaProject getJavaProject() {
664:                ITextEditor editor = getTextEditor();
665:                if (editor == null)
666:                    return null;
667:
668:                ICompilationUnit cu = JavaPlugin.getDefault()
669:                        .getWorkingCopyManager().getWorkingCopy(
670:                                editor.getEditorInput());
671:                if (cu == null)
672:                    return null;
673:                return cu.getJavaProject();
674:            }
675:
676:            /**
677:             * Returns the editor's selection provider.
678:             * 
679:             * @return the editor's selection provider or <code>null</code>
680:             */
681:            private ISelectionProvider getSelectionProvider() {
682:                ITextEditor editor = getTextEditor();
683:                if (editor != null) {
684:                    return editor.getSelectionProvider();
685:                }
686:                return null;
687:            }
688:
689:            /*
690:             * @see org.eclipse.ui.texteditor.IUpdate#update()
691:             */
692:            public void update() {
693:                super .update();
694:
695:                if (isEnabled())
696:                    if (fIsTabAction)
697:                        setEnabled(canModifyEditor() && isSmartMode()
698:                                && isValidSelection());
699:                    else
700:                        setEnabled(canModifyEditor()
701:                                && !getSelection().isEmpty());
702:            }
703:
704:            /**
705:             * Returns if the current selection is valid, i.e. whether it is empty and the caret in the 
706:             * whitespace at the start of a line, or covers multiple lines.
707:             * 
708:             * @return <code>true</code> if the selection is valid for an indent operation
709:             */
710:            private boolean isValidSelection() {
711:                ITextSelection selection = getSelection();
712:                if (selection.isEmpty())
713:                    return false;
714:
715:                int offset = selection.getOffset();
716:                int length = selection.getLength();
717:
718:                IDocument document = getDocument();
719:                if (document == null)
720:                    return false;
721:
722:                try {
723:                    IRegion firstLine = document
724:                            .getLineInformationOfOffset(offset);
725:                    int lineOffset = firstLine.getOffset();
726:
727:                    // either the selection has to be empty and the caret in the WS at the line start
728:                    // or the selection has to extend over multiple lines
729:                    if (length == 0)
730:                        return document.get(lineOffset, offset - lineOffset)
731:                                .trim().length() == 0;
732:                    else
733:                        //				return lineOffset + firstLine.getLength() < offset + length;
734:                        return false; // only enable for empty selections for now
735:
736:                } catch (BadLocationException e) {
737:                }
738:
739:                return false;
740:            }
741:
742:            /**
743:             * Returns the smart preference state.
744:             * 
745:             * @return <code>true</code> if smart mode is on, <code>false</code> otherwise
746:             */
747:            private boolean isSmartMode() {
748:                ITextEditor editor = getTextEditor();
749:
750:                if (editor instanceof  ITextEditorExtension3)
751:                    return ((ITextEditorExtension3) editor).getInsertMode() == ITextEditorExtension3.SMART_INSERT;
752:
753:                return false;
754:            }
755:
756:            /**
757:             * Returns the document currently displayed in the editor, or <code>null</code> if none can be 
758:             * obtained.
759:             * 
760:             * @return the current document or <code>null</code>
761:             */
762:            private IDocument getDocument() {
763:
764:                ITextEditor editor = getTextEditor();
765:                if (editor != null) {
766:
767:                    IDocumentProvider provider = editor.getDocumentProvider();
768:                    IEditorInput input = editor.getEditorInput();
769:                    if (provider != null && input != null)
770:                        return provider.getDocument(input);
771:
772:                }
773:                return null;
774:            }
775:
776:            /**
777:             * Returns the selection on the editor or an invalid selection if none can be obtained. Returns
778:             * never <code>null</code>.
779:             * 
780:             * @return the current selection, never <code>null</code>
781:             */
782:            private ITextSelection getSelection() {
783:                ISelectionProvider provider = getSelectionProvider();
784:                if (provider != null) {
785:
786:                    ISelection selection = provider.getSelection();
787:                    if (selection instanceof  ITextSelection)
788:                        return (ITextSelection) selection;
789:                }
790:
791:                // null object
792:                return TextSelection.emptySelection();
793:            }
794:
795:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.