Bug 550107 - [13] Text Block: Return after """ should align below """

Handle indenting of Text Block if Ctrl+I is clicked.

Change-Id: I700c31ff9a1f1bfd267005fa0e5ba631aaf1adc0
Signed-off-by: Kalyan Prasad Tatavarthi <kalyan_prasad@in.ibm.com>
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/actions/IndentAction.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/actions/IndentAction.java
index 6d4b252..6d9d0b7 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/actions/IndentAction.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/actions/IndentAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -8,6 +8,10 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Tom Eicher (Avaloq Evolution AG) - block selection mode
@@ -54,6 +58,10 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
+import org.eclipse.jdt.core.formatter.IndentManipulation;
+
+import org.eclipse.jdt.internal.core.manipulation.util.Strings;
+import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
 
 import org.eclipse.jdt.ui.text.IJavaPartitions;
 
@@ -118,6 +126,10 @@
 	 */
 	private final boolean fIsTabAction;
 
+	private static String TEXT_BLOCK_STR= "\"\"\""; //$NON-NLS-1$
+	private static String SPACE_STR= " "; //$NON-NLS-1$
+	private static String EMPTY_STR= ""; //$NON-NLS-1$
+
 	/**
 	 * Creates a new instance.
 	 *
@@ -345,6 +357,43 @@
 					removeIndentations(slashes, getTabSize(project), computed);
 					indent= document.get(offset, wsStart - offset) + computed;
 				}
+			} else if (IJavaPartitions.JAVA_MULTI_LINE_STRING.equals(type)) {
+				String fullStrNoTrim= document.get(currentLine.getOffset(), currentLine.getLength());
+				String fullStr= document.get(currentLine.getOffset(), currentLine.getLength()).trim();
+				int length= IndentManipulation.measureIndentInSpaces(fullStrNoTrim, CodeFormatterUtil.getTabWidth(project));
+				int partitionOffset= partition.getOffset();
+				IRegion PartitionStartline= document.getLineInformationOfOffset(partitionOffset);
+				String PartitionStartStrNoTrim= document.get(PartitionStartline.getOffset(), PartitionStartline.getLength());
+				int startIndex= PartitionStartStrNoTrim.lastIndexOf(TEXT_BLOCK_STR);
+				if (!fullStrNoTrim.equals(PartitionStartStrNoTrim) && startIndex != -1) {
+					int partitionStartLength= measureLengthInSpaces(PartitionStartStrNoTrim.substring(0, startIndex), CodeFormatterUtil.getTabWidth(project));
+					boolean calculateIndent= false;
+					String str= EMPTY_STR;
+					int strLength= 0;
+					if (partitionStartLength > length) {
+						calculateIndent= true;
+						strLength= length;
+					} else if (fullStr.startsWith(TEXT_BLOCK_STR) && partitionStartLength != length) {
+						calculateIndent= true;
+						strLength= partitionStartLength;
+					} else {
+						indent= getLineIndentation(document, currentLine.getOffset());
+					}
+					if (calculateIndent) {
+						for (int i= 0; i < strLength; i++) {
+							str+= SPACE_STR;
+						}
+						int units= Strings.computeIndentUnits(str, project);
+						String newStr= CodeFormatterUtil.createIndentString(units, project);
+						int newLength= IndentManipulation.measureIndentInSpaces(newStr, CodeFormatterUtil.getTabWidth(project));
+						if (newLength < partitionStartLength) {
+							for (int i= newLength; i < partitionStartLength; i++) {
+								newStr+= SPACE_STR;
+							}
+						}
+						indent= newStr;
+					}
+				}
 			}
 		}
 
@@ -371,6 +420,56 @@
 		return new ReplaceData(offset, end, indent);
 	}
 
+	private static String getLineIndentation(IDocument document, int offset) throws BadLocationException {
+		// find start of line
+		int adjustedOffset= (offset == document.getLength() ? offset - 1 : offset);
+		IRegion line= document.getLineInformationOfOffset(adjustedOffset);
+		int start= line.getOffset();
+
+		// find white spaces
+		int end= findEndOfWhiteSpace(document, start, offset + line.getLength());
+
+		return document.get(start, end - start);
+	}
+
+	private static int findEndOfWhiteSpace(IDocument document, int offset, int end) throws BadLocationException {
+		while (offset < end) {
+			char c= document.getChar(offset);
+			if (c != ' ' && c != '\t') {
+				return offset;
+			}
+			offset++;
+		}
+		return end;
+	}
+
+	private static int measureLengthInSpaces(CharSequence line, int tabWidth) {
+		if (tabWidth < 0 || line == null) {
+			throw new IllegalArgumentException();
+		}
+
+		int length= 0;
+		int max= line.length();
+		for (int i= 0; i < max; i++) {
+			char ch= line.charAt(i);
+			if (ch == '\t') {
+				length= calculateSpaceEquivalents(tabWidth, length);
+			} else {
+				length++;
+			}
+		}
+		return length;
+	}
+
+	private static int calculateSpaceEquivalents(int tabWidth, int spaceEquivalents) {
+		if (tabWidth == 0) {
+			return spaceEquivalents;
+		}
+		int remainder= spaceEquivalents % tabWidth;
+		spaceEquivalents+= tabWidth - remainder;
+		return spaceEquivalents;
+	}
+
 	/**
 	 * Removes <code>count</code> indentations from start
 	 * of <code>buffer</code>. The size of a space character