refactory: added UI removed from core plugin.
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpdt / internal / ui / text / phpdoc / JavaDocAutoIndentStrategy.java
diff --git a/net.sourceforge.phpeclipse.ui/src/net/sourceforge/phpdt/internal/ui/text/phpdoc/JavaDocAutoIndentStrategy.java b/net.sourceforge.phpeclipse.ui/src/net/sourceforge/phpdt/internal/ui/text/phpdoc/JavaDocAutoIndentStrategy.java
new file mode 100644 (file)
index 0000000..708a7b6
--- /dev/null
@@ -0,0 +1,938 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package net.sourceforge.phpdt.internal.ui.text.phpdoc;
+
+import java.text.BreakIterator;
+
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IMethod;
+import net.sourceforge.phpdt.core.ISourceRange;
+import net.sourceforge.phpdt.core.IType;
+import net.sourceforge.phpdt.internal.corext.util.Strings;
+import net.sourceforge.phpdt.ui.CodeGeneration;
+import net.sourceforge.phpdt.ui.IWorkingCopyManager;
+import net.sourceforge.phpdt.ui.PreferenceConstants;
+//import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.ui.WebUI;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DefaultIndentLineAutoEditStrategy;
+import org.eclipse.jface.text.DocumentCommand;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
+import org.eclipse.ui.texteditor.ITextEditorExtension3;
+
+/**
+ * Auto indent strategy for java doc comments
+ */
+public class JavaDocAutoIndentStrategy extends
+               DefaultIndentLineAutoEditStrategy {
+
+       private String fPartitioning;
+
+       /**
+        * Creates a new Javadoc auto indent strategy for the given document
+        * partitioning.
+        * 
+        * @param partitioning
+        *            the document partitioning
+        */
+       public JavaDocAutoIndentStrategy(String partitioning) {
+               fPartitioning = partitioning;
+       }
+
+       private static String getLineDelimiter(IDocument document) {
+               try {
+                       if (document.getNumberOfLines() > 1)
+                               return document.getLineDelimiter(0);
+               } catch (BadLocationException e) {
+                       WebUI.log(e);
+               }
+
+               return System.getProperty("line.separator"); //$NON-NLS-1$
+       }
+
+       /**
+        * Copies the indentation of the previous line and add a star. If the
+        * javadoc just started on this line add standard method tags and close the
+        * javadoc.
+        * 
+        * @param d
+        *            the document to work on
+        * @param c
+        *            the command to deal with
+        */
+       private void jdocIndentAfterNewLine(IDocument d, DocumentCommand c) {
+
+               if (c.offset == -1 || d.getLength() == 0)
+                       return;
+
+               try {
+                       // find start of line
+                       int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset);
+                       IRegion info = d.getLineInformationOfOffset(p);
+                       int start = info.getOffset();
+
+                       // find white spaces
+                       int end = findEndOfWhiteSpace(d, start, c.offset);
+
+                       StringBuffer buf = new StringBuffer(c.text);
+                       if (end >= start) { // 1GEYL1R: ITPJUI:ALL - java doc edit smartness
+                                                               // not work for class comments
+                               // append to input
+                               String indentation = jdocExtractLinePrefix(d, d
+                                               .getLineOfOffset(c.offset));
+                               buf.append(indentation);
+                               if (end < c.offset) {
+                                       if (d.getChar(end) == '/') {
+                                               // javadoc started on this line
+                                               buf.append(" * "); //$NON-NLS-1$
+
+                                               if (WebUI
+                                                               .getDefault()
+                                                               .getPreferenceStore()
+                                                               .getBoolean(
+                                                                               PreferenceConstants.EDITOR_CLOSE_JAVADOCS)
+                                                               && isNewComment(d, c.offset, fPartitioning)) {
+                                                       String lineDelimiter = getLineDelimiter(d);
+
+                                                       String endTag = lineDelimiter + indentation + " */"; //$NON-NLS-1$
+                                                       d.replace(c.offset, 0, endTag); //$NON-NLS-1$
+                                                       // evaluate method signature
+                                                       ICompilationUnit unit = getCompilationUnit();
+
+                                                       // if
+                                                       // (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ADD_JAVADOC_TAGS)
+                                                       // &&
+                                                       // unit != null)
+                                                       // {
+                                                       // try {
+                                                       // JavaModelUtil.reconcile(unit);
+                                                       // String string= createJavaDocTags(d, c,
+                                                       // indentation, lineDelimiter, unit);
+                                                       // if (string != null) {
+                                                       // d.replace(c.offset, 0, string);
+                                                       // }
+                                                       // } catch (CoreException e) {
+                                                       // // ignore
+                                                       // }
+                                                       // }
+                                               }
+
+                                       }
+                               }
+                       }
+
+                       c.text = buf.toString();
+
+               } catch (BadLocationException excp) {
+                       // stop work
+               }
+       }
+
+       private String createJavaDocTags(IDocument document,
+                       DocumentCommand command, String indentation, String lineDelimiter,
+                       ICompilationUnit unit) throws CoreException, BadLocationException {
+               IJavaElement element = unit.getElementAt(command.offset);
+               if (element == null)
+                       return null;
+
+               switch (element.getElementType()) {
+               case IJavaElement.TYPE:
+                       return createTypeTags(document, command, indentation,
+                                       lineDelimiter, (IType) element);
+
+               case IJavaElement.METHOD:
+                       return createMethodTags(document, command, indentation,
+                                       lineDelimiter, (IMethod) element);
+
+               default:
+                       return null;
+               }
+       }
+
+       /*
+        * Removes start and end of a comment and corrects indentation and line
+        * delimiters.
+        */
+       private String prepareTemplateComment(String comment, String indentation,
+                       String lineDelimiter) {
+               // trim comment start and end if any
+               if (comment.endsWith("*/")) //$NON-NLS-1$
+                       comment = comment.substring(0, comment.length() - 2);
+               comment = comment.trim();
+               if (comment.startsWith("/*")) { //$NON-NLS-1$
+                       if (comment.length() > 2 && comment.charAt(2) == '*') {
+                               comment = comment.substring(3); // remove '/**'
+                       } else {
+                               comment = comment.substring(2); // remove '/*'
+                       }
+               }
+               // return Strings.changeIndent(comment, 0,
+               // CodeFormatterUtil.getTabWidth(), indentation, lineDelimiter);
+               return Strings.changeIndent(comment, 0, getTabWidth(), indentation,
+                               lineDelimiter);
+       }
+
+       public static int getTabWidth() {
+               Preferences preferences = WebUI.getDefault()
+                               .getPluginPreferences();
+               return preferences
+                               .getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
+       }
+
+       private String createTypeTags(IDocument document, DocumentCommand command,
+                       String indentation, String lineDelimiter, IType type)
+                       throws CoreException {
+               String comment = CodeGeneration.getTypeComment(type
+                               .getCompilationUnit(), type.getTypeQualifiedName('.'),
+                               lineDelimiter);
+               if (comment != null) {
+                       return prepareTemplateComment(comment.trim(), indentation,
+                                       lineDelimiter);
+               }
+               return null;
+       }
+
+       private String createMethodTags(IDocument document,
+                       DocumentCommand command, String indentation, String lineDelimiter,
+                       IMethod method) throws CoreException, BadLocationException {
+               IRegion partition = TextUtilities.getPartition(document, fPartitioning,
+                               command.offset, false);
+               ISourceRange sourceRange = method.getSourceRange();
+               if (sourceRange == null
+                               || sourceRange.getOffset() != partition.getOffset())
+                       return null;
+
+               // IMethod inheritedMethod= getInheritedMethod(method);
+               // String comment= CodeGeneration.getMethodComment(method,
+               // inheritedMethod, lineDelimiter);
+               // if (comment != null) {
+               // comment= comment.trim();
+               // boolean javadocComment= comment.startsWith("/**"); //$NON-NLS-1$
+               // boolean isJavaDoc= partition.getLength() >= 3 &&
+               // document.get(partition.getOffset(), 3).equals("/**"); //$NON-NLS-1$
+               // if (javadocComment == isJavaDoc) {
+               // return prepareTemplateComment(comment, indentation, lineDelimiter);
+               // }
+               // }
+               return null;
+       }
+
+       /**
+        * Returns the method inherited from, <code>null</code> if method is newly
+        * defined.
+        */
+       // private static IMethod getInheritedMethod(IMethod method) throws
+       // JavaModelException {
+       // IType declaringType= method.getDeclaringType();
+       // ITypeHierarchy typeHierarchy=
+       // SuperTypeHierarchyCache.getTypeHierarchy(declaringType);
+       // return JavaModelUtil.findMethodDeclarationInHierarchy(typeHierarchy,
+       // declaringType,
+       // method.getElementName(), method.getParameterTypes(),
+       // method.isConstructor());
+       // }
+       protected void jdocIndentForCommentEnd(IDocument d, DocumentCommand c) {
+               if (c.offset < 2 || d.getLength() == 0) {
+                       return;
+               }
+               try {
+                       if ("* ".equals(d.get(c.offset - 2, 2))) { //$NON-NLS-1$
+                               // modify document command
+                               c.length++;
+                               c.offset--;
+                       }
+               } catch (BadLocationException excp) {
+                       // stop work
+               }
+       }
+
+       /**
+        * Guesses if the command operates within a newly created javadoc comment or
+        * not. If in doubt, it will assume that the javadoc is new.
+        */
+       private static boolean isNewComment(IDocument document, int commandOffset,
+                       String partitioning) {
+
+               try {
+                       int lineIndex = document.getLineOfOffset(commandOffset) + 1;
+                       if (lineIndex >= document.getNumberOfLines())
+                               return true;
+
+                       IRegion line = document.getLineInformation(lineIndex);
+                       ITypedRegion partition = TextUtilities.getPartition(document,
+                                       partitioning, commandOffset, false);
+                       int partitionEnd = partition.getOffset() + partition.getLength();
+                       if (line.getOffset() >= partitionEnd)
+                               return false;
+
+                       if (document.getLength() == partitionEnd)
+                               return true; // partition goes to end of document - probably
+                                                               // a new comment
+
+                       String comment = document.get(partition.getOffset(), partition
+                                       .getLength());
+                       if (comment.indexOf("/*", 2) != -1) //$NON-NLS-1$
+                               return true; // enclosed another comment -> probably a new
+                                                               // comment
+
+                       return false;
+
+               } catch (BadLocationException e) {
+                       return false;
+               }
+       }
+
+       private boolean isSmartMode() {
+               IWorkbenchPage page = WebUI.getActivePage();
+               if (page != null) {
+                       IEditorPart part = page.getActiveEditor();
+                       if (part instanceof ITextEditorExtension3) {
+                               ITextEditorExtension3 extension = (ITextEditorExtension3) part;
+                               return extension.getInsertMode() == ITextEditorExtension3.SMART_INSERT;
+                       }
+               }
+               return false;
+       }
+
+       /*
+        * @see IAutoIndentStrategy#customizeDocumentCommand
+        */
+       public void customizeDocumentCommand(IDocument document,
+                       DocumentCommand command) {
+
+               if (!isSmartMode())
+                       return;
+
+               try {
+
+                       if (command.text != null && command.length == 0) {
+                               String[] lineDelimiters = document.getLegalLineDelimiters();
+                               int index = TextUtilities
+                                               .endsWith(lineDelimiters, command.text);
+                               if (index > -1) {
+                                       // ends with line delimiter
+                                       if (lineDelimiters[index].equals(command.text))
+                                               // just the line delimiter
+                                               jdocIndentAfterNewLine(document, command);
+                                       return;
+                               }
+                       }
+
+                       if (command.text != null && command.text.equals("/")) { //$NON-NLS-1$
+                               jdocIndentForCommentEnd(document, command);
+                               return;
+                       }
+
+                       ITypedRegion partition = TextUtilities.getPartition(document,
+                                       fPartitioning, command.offset, true);
+                       int partitionStart = partition.getOffset();
+                       int partitionEnd = partition.getLength() + partitionStart;
+
+                       String text = command.text;
+                       int offset = command.offset;
+                       int length = command.length;
+
+                       // partition change
+                       final int PREFIX_LENGTH = "/*".length(); //$NON-NLS-1$
+                       final int POSTFIX_LENGTH = "*/".length(); //$NON-NLS-1$
+                       if ((offset < partitionStart + PREFIX_LENGTH || offset + length > partitionEnd
+                                       - POSTFIX_LENGTH)
+                                       || text != null
+                                       && text.length() >= 2
+                                       && ((text.indexOf("*/") != -1) || (document.getChar(offset) == '*' && text.startsWith("/")))) //$NON-NLS-1$ //$NON-NLS-2$
+                               return;
+
+                       if (command.text == null || command.text.length() == 0)
+                               jdocHandleBackspaceDelete(document, command);
+
+                       else if (command.text != null && command.length == 0
+                                       && command.text.length() > 0)
+                               jdocWrapParagraphOnInsert(document, command);
+
+               } catch (BadLocationException e) {
+                       WebUI.log(e);
+               }
+       }
+
+       private void flushCommand(IDocument document, DocumentCommand command)
+                       throws BadLocationException {
+
+               if (!command.doit)
+                       return;
+
+               document.replace(command.offset, command.length, command.text);
+
+               command.doit = false;
+               if (command.text != null)
+                       command.offset += command.text.length();
+               command.length = 0;
+               command.text = null;
+       }
+
+       protected void jdocWrapParagraphOnInsert(IDocument document,
+                       DocumentCommand command) throws BadLocationException {
+
+               // Assert.isTrue(command.length == 0);
+               // Assert.isTrue(command.text != null && command.text.length() == 1);
+
+               if (!getPreferenceStore().getBoolean(
+                               PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
+                       return;
+
+               int line = document.getLineOfOffset(command.offset);
+               IRegion region = document.getLineInformation(line);
+               int lineOffset = region.getOffset();
+               int lineLength = region.getLength();
+
+               String lineContents = document.get(lineOffset, lineLength);
+               StringBuffer buffer = new StringBuffer(lineContents);
+               int start = command.offset - lineOffset;
+               int end = command.length + start;
+               buffer.replace(start, end, command.text);
+
+               // handle whitespace
+               if (command.text != null && command.text.length() != 0
+                               && command.text.trim().length() == 0) {
+
+                       String endOfLine = document.get(command.offset, lineOffset
+                                       + lineLength - command.offset);
+
+                       // end of line
+                       if (endOfLine.length() == 0) {
+                               // move caret to next line
+                               flushCommand(document, command);
+
+                               if (isLineTooShort(document, line)) {
+                                       int[] caretOffset = { command.offset };
+                                       jdocWrapParagraphFromLine(document, line, caretOffset,
+                                                       false);
+                                       command.offset = caretOffset[0];
+                                       return;
+                               }
+
+                               // move caret to next line if possible
+                               if (line < document.getNumberOfLines() - 1
+                                               && isJavaDocLine(document, line + 1)) {
+                                       String lineDelimiter = document.getLineDelimiter(line);
+                                       String nextLinePrefix = jdocExtractLinePrefix(document,
+                                                       line + 1);
+                                       command.offset += lineDelimiter.length()
+                                                       + nextLinePrefix.length();
+                               }
+                               return;
+
+                               // inside whitespace at end of line
+                       } else if (endOfLine.trim().length() == 0) {
+                               // simply insert space
+                               return;
+                       }
+               }
+
+               // change in prefix region
+               String prefix = jdocExtractLinePrefix(document, line);
+               boolean wrapAlways = command.offset >= lineOffset
+                               && command.offset <= lineOffset + prefix.length();
+
+               // must insert the text now because it may include whitepace
+               flushCommand(document, command);
+
+               if (wrapAlways
+                               || calculateDisplayedWidth(buffer.toString()) > getMargin()
+                               || isLineTooShort(document, line)) {
+                       int[] caretOffset = { command.offset };
+                       jdocWrapParagraphFromLine(document, line, caretOffset, wrapAlways);
+
+                       if (!wrapAlways)
+                               command.offset = caretOffset[0];
+               }
+       }
+
+       /**
+        * Method jdocWrapParagraphFromLine.
+        * 
+        * @param document
+        * @param line
+        * @param always
+        */
+       private void jdocWrapParagraphFromLine(IDocument document, int line,
+                       int[] caretOffset, boolean always) throws BadLocationException {
+
+               String indent = jdocExtractLinePrefix(document, line);
+               if (!always) {
+                       if (!indent.trim().startsWith("*")) //$NON-NLS-1$
+                               return;
+
+                       if (indent.trim().startsWith("*/")) //$NON-NLS-1$
+                               return;
+
+                       if (!isLineTooLong(document, line)
+                                       && !isLineTooShort(document, line))
+                               return;
+               }
+
+               boolean caretRelativeToParagraphOffset = false;
+               int caret = caretOffset[0];
+
+               int caretLine = document.getLineOfOffset(caret);
+               int lineOffset = document.getLineOffset(line);
+               int paragraphOffset = lineOffset + indent.length();
+               if (paragraphOffset < caret) {
+                       caret -= paragraphOffset;
+                       caretRelativeToParagraphOffset = true;
+               } else {
+                       caret -= lineOffset;
+               }
+
+               StringBuffer buffer = new StringBuffer();
+               int currentLine = line;
+               while (line == currentLine || isJavaDocLine(document, currentLine)) {
+
+                       if (buffer.length() != 0
+                                       && !Character.isWhitespace(buffer
+                                                       .charAt(buffer.length() - 1))) {
+                               buffer.append(' ');
+                               if (currentLine <= caretLine) {
+                                       // in this case caretRelativeToParagraphOffset is always
+                                       // true
+                                       ++caret;
+                               }
+                       }
+
+                       String string = getLineContents(document, currentLine);
+                       buffer.append(string);
+                       currentLine++;
+               }
+               String paragraph = buffer.toString();
+
+               if (paragraph.trim().length() == 0)
+                       return;
+
+               caretOffset[0] = caretRelativeToParagraphOffset ? caret : 0;
+               String delimiter = document.getLineDelimiter(0);
+               String wrapped = formatParagraph(paragraph, caretOffset, indent,
+                               delimiter, getMargin());
+
+               int beginning = document.getLineOffset(line);
+               int end = document.getLineOffset(currentLine);
+               document.replace(beginning, end - beginning, wrapped.toString());
+
+               caretOffset[0] = caretRelativeToParagraphOffset ? caretOffset[0]
+                               + beginning : caret + beginning;
+       }
+
+       /**
+        * Line break iterator to handle whitespaces as first class citizens.
+        */
+       private static class LineBreakIterator {
+
+               private final String fString;
+
+               private final BreakIterator fIterator = BreakIterator.getLineInstance();
+
+               private int fStart;
+
+               private int fEnd;
+
+               private int fBufferedEnd;
+
+               public LineBreakIterator(String string) {
+                       fString = string;
+                       fIterator.setText(string);
+               }
+
+               public int first() {
+                       fBufferedEnd = -1;
+                       fStart = fIterator.first();
+                       return fStart;
+               }
+
+               public int next() {
+
+                       if (fBufferedEnd != -1) {
+                               fStart = fEnd;
+                               fEnd = fBufferedEnd;
+                               fBufferedEnd = -1;
+                               return fEnd;
+                       }
+
+                       fStart = fEnd;
+                       fEnd = fIterator.next();
+
+                       if (fEnd == BreakIterator.DONE)
+                               return fEnd;
+
+                       final String string = fString.substring(fStart, fEnd);
+
+                       // whitespace
+                       if (string.trim().length() == 0)
+                               return fEnd;
+
+                       final String word = string.trim();
+                       if (word.length() == string.length())
+                               return fEnd;
+
+                       // suspected whitespace
+                       fBufferedEnd = fEnd;
+                       return fStart + word.length();
+               }
+       }
+
+       /**
+        * Formats a paragraph, using break iterator.
+        * 
+        * @param offset
+        *            an offset within the paragraph, which will be updated with
+        *            respect to formatting.
+        */
+       private static String formatParagraph(String paragraph, int[] offset,
+                       String prefix, String lineDelimiter, int margin) {
+
+               LineBreakIterator iterator = new LineBreakIterator(paragraph);
+
+               StringBuffer paragraphBuffer = new StringBuffer();
+               StringBuffer lineBuffer = new StringBuffer();
+               StringBuffer whiteSpaceBuffer = new StringBuffer();
+
+               int index = offset[0];
+               int indexBuffer = -1;
+
+               // line delimiter could be null
+               if (lineDelimiter == null)
+                       lineDelimiter = ""; //$NON-NLS-1$
+
+               for (int start = iterator.first(), end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator
+                               .next()) {
+
+                       String word = paragraph.substring(start, end);
+
+                       // word is whitespace
+                       if (word.trim().length() == 0) {
+                               whiteSpaceBuffer.append(word);
+
+                               // first word of line is always appended
+                       } else if (lineBuffer.length() == 0) {
+                               lineBuffer.append(prefix);
+                               lineBuffer.append(whiteSpaceBuffer.toString());
+                               lineBuffer.append(word);
+
+                       } else {
+                               String line = lineBuffer.toString()
+                                               + whiteSpaceBuffer.toString() + word.toString();
+
+                               // margin exceeded
+                               if (calculateDisplayedWidth(line) > margin) {
+                                       // flush line buffer and wrap paragraph
+                                       paragraphBuffer.append(lineBuffer.toString());
+                                       paragraphBuffer.append(lineDelimiter);
+                                       lineBuffer.setLength(0);
+                                       lineBuffer.append(prefix);
+                                       lineBuffer.append(word);
+
+                                       // flush index buffer
+                                       if (indexBuffer != -1) {
+                                               offset[0] = indexBuffer;
+                                               // correct for caret in whitespace at the end of line
+                                               if (whiteSpaceBuffer.length() != 0 && index < start
+                                                               && index >= start - whiteSpaceBuffer.length())
+                                                       offset[0] -= (index - (start - whiteSpaceBuffer
+                                                                       .length()));
+                                               indexBuffer = -1;
+                                       }
+
+                                       whiteSpaceBuffer.setLength(0);
+
+                                       // margin not exceeded
+                               } else {
+                                       lineBuffer.append(whiteSpaceBuffer.toString());
+                                       lineBuffer.append(word);
+                                       whiteSpaceBuffer.setLength(0);
+                               }
+                       }
+
+                       if (index >= start && index < end) {
+                               indexBuffer = paragraphBuffer.length() + lineBuffer.length()
+                                               + (index - start);
+                               if (word.trim().length() != 0)
+                                       indexBuffer -= word.length();
+                       }
+               }
+
+               // flush line buffer
+               paragraphBuffer.append(lineBuffer.toString());
+               paragraphBuffer.append(lineDelimiter);
+
+               // flush index buffer
+               if (indexBuffer != -1)
+                       offset[0] = indexBuffer;
+
+               // last position is not returned by break iterator
+               else if (offset[0] == paragraph.length())
+                       offset[0] = paragraphBuffer.length() - lineDelimiter.length();
+
+               return paragraphBuffer.toString();
+       }
+
+       private static IPreferenceStore getPreferenceStore() {
+               return WebUI.getDefault().getPreferenceStore();
+       }
+
+       /**
+        * Returns the displayed width of a string, taking in account the displayed
+        * tab width. The result can be compared against the print margin.
+        */
+       private static int calculateDisplayedWidth(String string) {
+
+               int tabWidth = getPreferenceStore()
+                               .getInt(
+                                               AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
+               if (tabWidth <= 0) {
+                       tabWidth = 2;
+               }
+               int column = 0;
+               for (int i = 0; i < string.length(); i++)
+                       if ('\t' == string.charAt(i))
+                               column += tabWidth - (column % tabWidth);
+                       else
+                               column++;
+
+               return column;
+       }
+
+       private String jdocExtractLinePrefix(IDocument d, int line)
+                       throws BadLocationException {
+
+               IRegion region = d.getLineInformation(line);
+               int lineOffset = region.getOffset();
+               int index = findEndOfWhiteSpace(d, lineOffset, lineOffset
+                               + d.getLineLength(line));
+               if (d.getChar(index) == '*') {
+                       index++;
+                       if (index != lineOffset + region.getLength()
+                                       && d.getChar(index) == ' ')
+                               index++;
+               }
+               return d.get(lineOffset, index - lineOffset);
+       }
+
+       private String getLineContents(IDocument d, int line)
+                       throws BadLocationException {
+               int offset = d.getLineOffset(line);
+               int length = d.getLineLength(line);
+               String lineDelimiter = d.getLineDelimiter(line);
+               if (lineDelimiter != null)
+                       length = length - lineDelimiter.length();
+               String lineContents = d.get(offset, length);
+               int trim = jdocExtractLinePrefix(d, line).length();
+               return lineContents.substring(trim);
+       }
+
+       private static String getLine(IDocument document, int line)
+                       throws BadLocationException {
+               IRegion region = document.getLineInformation(line);
+               return document.get(region.getOffset(), region.getLength());
+       }
+
+       /**
+        * Returns <code>true</code> if the javadoc line is too short,
+        * <code>false</code> otherwise.
+        */
+       private boolean isLineTooShort(IDocument document, int line)
+                       throws BadLocationException {
+
+               if (!isJavaDocLine(document, line + 1))
+                       return false;
+
+               String nextLine = getLineContents(document, line + 1);
+               if (nextLine.trim().length() == 0)
+                       return false;
+
+               return true;
+       }
+
+       /**
+        * Returns <code>true</code> if the line is too long, <code>false</code>
+        * otherwise.
+        */
+       private boolean isLineTooLong(IDocument document, int line)
+                       throws BadLocationException {
+               String lineContents = getLine(document, line);
+               return calculateDisplayedWidth(lineContents) > getMargin();
+       }
+
+       private static int getMargin() {
+               return getPreferenceStore()
+                               .getInt(
+                                               AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN);
+       }
+
+       private static final String[] fgInlineTags = {
+                       "<b>", "<i>", "<em>", "<strong>", "<code>" //$NON-NLS-1$  //$NON-NLS-2$  //$NON-NLS-3$  //$NON-NLS-4$ //$NON-NLS-5$
+       };
+
+       private boolean isInlineTag(String string) {
+               for (int i = 0; i < fgInlineTags.length; i++)
+                       if (string.startsWith(fgInlineTags[i]))
+                               return true;
+               return false;
+       }
+
+       /**
+        * returns true if the specified line is part of a paragraph and should be
+        * merged with the previous line.
+        */
+       private boolean isJavaDocLine(IDocument document, int line)
+                       throws BadLocationException {
+
+               if (document.getNumberOfLines() < line)
+                       return false;
+
+               int offset = document.getLineOffset(line);
+               int length = document.getLineLength(line);
+               int firstChar = findEndOfWhiteSpace(document, offset, offset + length);
+               length -= firstChar - offset;
+               String lineContents = document.get(firstChar, length);
+
+               String prefix = lineContents.trim();
+               if (!prefix.startsWith("*") || prefix.startsWith("*/")) //$NON-NLS-1$ //$NON-NLS-2$
+                       return false;
+
+               lineContents = lineContents.substring(1).trim().toLowerCase();
+
+               // preserve empty lines
+               if (lineContents.length() == 0)
+                       return false;
+
+               // preserve @TAGS
+               if (lineContents.startsWith("@")) //$NON-NLS-1$
+                       return false;
+
+               // preserve HTML tags which are not inline
+               if (lineContents.startsWith("<") && !isInlineTag(lineContents)) //$NON-NLS-1$
+                       return false;
+
+               return true;
+       }
+
+       protected void jdocHandleBackspaceDelete(IDocument document,
+                       DocumentCommand c) {
+
+               if (!getPreferenceStore().getBoolean(
+                               PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
+                       return;
+
+               try {
+                       String text = document.get(c.offset, c.length);
+                       int line = document.getLineOfOffset(c.offset);
+                       int lineOffset = document.getLineOffset(line);
+
+                       // erase line delimiter
+                       String lineDelimiter = document.getLineDelimiter(line);
+                       if (lineDelimiter != null && lineDelimiter.equals(text)) {
+
+                               String prefix = jdocExtractLinePrefix(document, line + 1);
+
+                               // strip prefix if any
+                               if (prefix.length() > 0) {
+                                       int length = document.getLineDelimiter(line).length()
+                                                       + prefix.length();
+                                       document.replace(c.offset, length, null);
+
+                                       c.doit = false;
+                                       c.length = 0;
+                                       return;
+                               }
+
+                               // backspace: beginning of a javadoc line
+                       } else if (document.getChar(c.offset - 1) == '*'
+                                       && jdocExtractLinePrefix(document, line).length() - 1 >= c.offset
+                                                       - lineOffset) {
+
+                               lineDelimiter = document.getLineDelimiter(line - 1);
+                               String prefix = jdocExtractLinePrefix(document, line);
+                               int length = (lineDelimiter != null ? lineDelimiter.length()
+                                               : 0)
+                                               + prefix.length();
+                               document.replace(c.offset - length + 1, length, null);
+
+                               c.doit = false;
+                               c.offset -= length - 1;
+                               c.length = 0;
+                               return;
+
+                       } else {
+                               document.replace(c.offset, c.length, null);
+                               c.doit = false;
+                               c.length = 0;
+                       }
+
+               } catch (BadLocationException e) {
+                       WebUI.log(e);
+               }
+
+               try {
+                       int line = document.getLineOfOffset(c.offset);
+                       int lineOffset = document.getLineOffset(line);
+                       String prefix = jdocExtractLinePrefix(document, line);
+                       boolean always = c.offset > lineOffset
+                                       && c.offset <= lineOffset + prefix.length();
+                       int[] caretOffset = { c.offset };
+                       jdocWrapParagraphFromLine(document, document
+                                       .getLineOfOffset(c.offset), caretOffset, always);
+                       c.offset = caretOffset[0];
+
+               } catch (BadLocationException e) {
+                       WebUI.log(e);
+               }
+       }
+
+       /**
+        * Returns the compilation unit of the CompilationUnitEditor invoking the
+        * AutoIndentStrategy, might return <code>null</code> on error.
+        */
+       private static ICompilationUnit getCompilationUnit() {
+
+               IWorkbenchWindow window = PlatformUI.getWorkbench()
+                               .getActiveWorkbenchWindow();
+               if (window == null)
+                       return null;
+
+               IWorkbenchPage page = window.getActivePage();
+               if (page == null)
+                       return null;
+
+               IEditorPart editor = page.getActiveEditor();
+               if (editor == null)
+                       return null;
+
+               IWorkingCopyManager manager = WebUI.getDefault()
+                               .getWorkingCopyManager();
+               ICompilationUnit unit = manager.getWorkingCopy(editor.getEditorInput());
+               if (unit == null)
+                       return null;
+
+               return unit;
+       }
+
+}